diff --git a/script/DeployPositionDescriptor.s.sol b/script/DeployPositionDescriptor.s.sol deleted file mode 100644 index 9599d7ea..00000000 --- a/script/DeployPositionDescriptor.s.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.20; - -import "forge-std/console2.sol"; -import "forge-std/Script.sol"; - -import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; -import {PositionDescriptor} from "../src/PositionDescriptor.sol"; - -contract DeployPositionDescriptorTest is Script { - function setUp() public {} - - function run(address poolManager, address weth, string memory nativeCurrencyLabel) - public - returns (PositionDescriptor positionDescriptor) - { - vm.startBroadcast(); - - positionDescriptor = new PositionDescriptor(IPoolManager(poolManager), weth, nativeCurrencyLabel); - console2.log("PositionDescriptor", address(positionDescriptor)); - - vm.stopBroadcast(); - } -} diff --git a/script/DeployPosm.s.sol b/script/DeployPosm.s.sol index e3f15bf4..4233208c 100644 --- a/script/DeployPosm.s.sol +++ b/script/DeployPosm.s.sol @@ -9,21 +9,28 @@ import {StateView} from "../src/lens/StateView.sol"; import {PositionManager} from "../src/PositionManager.sol"; import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol"; import {IPositionDescriptor} from "../src/interfaces/IPositionDescriptor.sol"; +import {PositionDescriptor} from "../src/PositionDescriptor.sol"; contract DeployPosmTest is Script { function setUp() public {} - function run(address poolManager, address permit2, uint256 unsubscribeGasLimit, address positionDescriptor) - public - returns (PositionManager posm) - { + function run( + address poolManager, + address permit2, + uint256 unsubscribeGasLimit, + address weth, + string memory nativeCurrencyLabel + ) public returns (PositionDescriptor positionDescriptor, PositionManager posm) { vm.startBroadcast(); + positionDescriptor = new PositionDescriptor(IPoolManager(poolManager), weth, nativeCurrencyLabel); + console2.log("PositionDescriptor", address(positionDescriptor)); + posm = new PositionManager{salt: hex"03"}( IPoolManager(poolManager), IAllowanceTransfer(permit2), unsubscribeGasLimit, - IPositionDescriptor(positionDescriptor) + IPositionDescriptor(address(positionDescriptor)) ); console2.log("PositionManager", address(posm)); diff --git a/src/PositionDescriptor.sol b/src/PositionDescriptor.sol index b7ee4d84..c3dc3a6c 100644 --- a/src/PositionDescriptor.sol +++ b/src/PositionDescriptor.sol @@ -13,7 +13,7 @@ import {IPositionDescriptor} from "./interfaces/IPositionDescriptor.sol"; import {PositionInfo, PositionInfoLibrary} from "./libraries/PositionInfoLibrary.sol"; import {Descriptor} from "./libraries/Descriptor.sol"; import {CurrencyRatioSortOrder} from "./libraries/CurrencyRatioSortOrder.sol"; -import {SafeERC20Namer} from "./libraries/SafeERC20Namer.sol"; +import {SafeERC20Metadata} from "./libraries/SafeERC20Metadata.sol"; /// @title Describes NFT token positions /// @notice Produces a string containing the data URI for a JSON metadata string @@ -67,16 +67,16 @@ contract PositionDescriptor is IPositionDescriptor { baseCurrency: baseCurrency, quoteCurrencySymbol: quoteCurrency.isAddressZero() ? nativeCurrencyLabel - : SafeERC20Namer.tokenSymbol(Currency.unwrap(quoteCurrency)), + : SafeERC20Metadata.tokenSymbol(Currency.unwrap(quoteCurrency)), baseCurrencySymbol: baseCurrency.isAddressZero() ? nativeCurrencyLabel - : SafeERC20Namer.tokenSymbol(Currency.unwrap(baseCurrency)), + : SafeERC20Metadata.tokenSymbol(Currency.unwrap(baseCurrency)), quoteCurrencyDecimals: quoteCurrency.isAddressZero() ? 18 - : IERC20Metadata(Currency.unwrap(quoteCurrency)).decimals(), + : SafeERC20Metadata.tokenDecimals(Currency.unwrap(quoteCurrency)), baseCurrencyDecimals: baseCurrency.isAddressZero() ? 18 - : IERC20Metadata(Currency.unwrap(baseCurrency)).decimals(), + : SafeERC20Metadata.tokenDecimals(Currency.unwrap(baseCurrency)), flipRatio: _flipRatio, tickLower: positionInfo.tickLower(), tickUpper: positionInfo.tickUpper(), diff --git a/src/libraries/Descriptor.sol b/src/libraries/Descriptor.sol index 43149f51..b5da50ee 100644 --- a/src/libraries/Descriptor.sol +++ b/src/libraries/Descriptor.sol @@ -18,6 +18,7 @@ library Descriptor { using TickMath for int24; using Strings for uint256; using HexStrings for uint256; + using LPFeeLibrary for uint24; uint256 constant sqrt10X128 = 1076067327063303206878105757264492625226; @@ -403,7 +404,7 @@ library Descriptor { /// @param fee fee amount /// @return fee as a decimal string with percent sign function feeToPercentString(uint24 fee) internal pure returns (string memory) { - if (fee == LPFeeLibrary.DYNAMIC_FEE_FLAG) { + if (fee.isDynamicFee()) { return "Dynamic"; } if (fee == 0) { diff --git a/src/libraries/SafeERC20Namer.sol b/src/libraries/SafeERC20Namer.sol deleted file mode 100644 index 0e8417a7..00000000 --- a/src/libraries/SafeERC20Namer.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import "./AddressStringUtil.sol"; - -/// @title SafeERC20Namer -/// @notice produces token descriptors from inconsistent or absent ERC20 symbol implementations that can return string or bytes32 -/// this library will always produce a string symbol to represent the token -/// @dev Reference: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/SafeERC20Namer.sol -library SafeERC20Namer { - function bytes32ToString(bytes32 x) private pure returns (string memory) { - bytes memory bytesString = new bytes(32); - uint256 charCount = 0; - for (uint256 j = 0; j < 32; j++) { - bytes1 char = x[j]; - if (char != 0) { - bytesString[charCount] = char; - charCount++; - } - } - bytes memory bytesStringTrimmed = new bytes(charCount); - for (uint256 j = 0; j < charCount; j++) { - bytesStringTrimmed[j] = bytesString[j]; - } - return string(bytesStringTrimmed); - } - - /// @notice produces a token symbol from the address - the first 6 hex of the address string in upper case - /// @param token the token address - /// @return the token symbol - function addressToSymbol(address token) private pure returns (string memory) { - return AddressStringUtil.toAsciiString(token, 6); - } - - /// @notice calls an external view token contract method that returns a symbol, and parses the output into a string - /// @param token the token address - /// @param selector the selector of the symbol method - /// @return the token symbol - function callAndParseStringReturn(address token, bytes4 selector) private view returns (string memory) { - (bool success, bytes memory data) = token.staticcall(abi.encodeWithSelector(selector)); - // if not implemented, return empty string - if (!success) { - return ""; - } - // bytes32 data always has length 32 - if (data.length == 32) { - bytes32 decoded = abi.decode(data, (bytes32)); - return bytes32ToString(decoded); - } else if (data.length > 64) { - return abi.decode(data, (string)); - } - return ""; - } - - /// @notice attempts to extract the token symbol. if it does not implement symbol, returns a symbol derived from the address - /// @param token the token address - /// @return the token symbol - function tokenSymbol(address token) internal view returns (string memory) { - string memory symbol = callAndParseStringReturn(token, IERC20Metadata.symbol.selector); - if (bytes(symbol).length == 0) { - // fallback to 6 uppercase hex of address - return addressToSymbol(token); - } - return symbol; - } -}