diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap
index ec121d73..fcd5df5e 100644
--- a/.forge-snapshots/positionDescriptor bytecode size.snap
+++ b/.forge-snapshots/positionDescriptor bytecode size.snap
@@ -1 +1 @@
-31065
\ No newline at end of file
+31144
\ No newline at end of file
diff --git a/src/PositionDescriptor.sol b/src/PositionDescriptor.sol
index 7cf39d94..716f7497 100644
--- a/src/PositionDescriptor.sol
+++ b/src/PositionDescriptor.sol
@@ -10,8 +10,8 @@ import {IPositionManager} from "./interfaces/IPositionManager.sol";
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 {SafeCurrencyMetadata} from "./libraries/SafeCurrencyMetadata.sol";
+import {AddressRatioSortOrder} from "./libraries/AddressRatioSortOrder.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
@@ -31,14 +31,14 @@ contract PositionDescriptor is IPositionDescriptor {
address private constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
address public immutable wrappedNative;
- string public nativeCurrencyLabel;
+ string public nativeAddressLabel;
IPoolManager public immutable poolManager;
- constructor(IPoolManager _poolManager, address _wrappedNative, string memory _nativeCurrencyLabel) {
+ constructor(IPoolManager _poolManager, address _wrappedNative, string memory _nativeAddressLabel) {
poolManager = _poolManager;
wrappedNative = _wrappedNative;
- nativeCurrencyLabel = _nativeCurrencyLabel;
+ nativeAddressLabel = _nativeAddressLabel;
}
/// @inheritdoc IPositionDescriptor
@@ -54,24 +54,27 @@ contract PositionDescriptor is IPositionDescriptor {
}
(, int24 tick,,) = poolManager.getSlot0(poolKey.toId());
- // If possible, flip currencies to get the larger currency as the base currency, so that the price (quote/base) is more readable
- // flip if currency0 priority is greater than currency1 priority
- bool _flipRatio = flipRatio(Currency.unwrap(poolKey.currency0), Currency.unwrap(poolKey.currency1));
+ address address0 = Currency.unwrap(poolKey.currency0);
+ address address1 = Currency.unwrap(poolKey.currency1);
- // If not flipped, quote currency is currency1, base currency is currency0
- // If flipped, quote currency is currency0, base currency is currency1
- Currency quoteCurrency = !_flipRatio ? poolKey.currency1 : poolKey.currency0;
- Currency baseCurrency = !_flipRatio ? poolKey.currency0 : poolKey.currency1;
+ // If possible, flip addresses to get the larger one as the base, so that the price (quote/base) is more readable
+ // flip if address0 priority is greater than address1 priority
+ bool _flipRatio = flipRatio(address0, address1);
+
+ // If not flipped, quote address is address1, base address is address0
+ // If flipped, quote address is address0, base address is address1
+ address quoteAddress = !_flipRatio ? address1 : address0;
+ address baseAddress = !_flipRatio ? address0 : address1;
return Descriptor.constructTokenURI(
Descriptor.ConstructTokenURIParams({
tokenId: tokenId,
- quoteCurrency: quoteCurrency,
- baseCurrency: baseCurrency,
- quoteCurrencySymbol: SafeCurrencyMetadata.currencySymbol(quoteCurrency, nativeCurrencyLabel),
- baseCurrencySymbol: SafeCurrencyMetadata.currencySymbol(baseCurrency, nativeCurrencyLabel),
- quoteCurrencyDecimals: SafeCurrencyMetadata.currencyDecimals(quoteCurrency),
- baseCurrencyDecimals: SafeCurrencyMetadata.currencyDecimals(baseCurrency),
+ quoteAddress: quoteAddress,
+ baseAddress: baseAddress,
+ quoteAddressSymbol: SafeERC20Metadata.addressSymbol(quoteAddress, nativeAddressLabel),
+ baseAddressSymbol: SafeERC20Metadata.addressSymbol(baseAddress, nativeAddressLabel),
+ quoteAddressDecimals: SafeERC20Metadata.addressDecimals(quoteAddress),
+ baseAddressDecimals: SafeERC20Metadata.addressDecimals(baseAddress),
flipRatio: _flipRatio,
tickLower: positionInfo.tickLower(),
tickUpper: positionInfo.tickUpper(),
@@ -84,37 +87,37 @@ contract PositionDescriptor is IPositionDescriptor {
);
}
- /// @notice Returns true if currency0 has higher priority than currency1
- /// @param currency0 The first currency address
- /// @param currency1 The second currency address
- /// @return flipRatio True if currency0 has higher priority than currency1
- function flipRatio(address currency0, address currency1) public view returns (bool) {
- return currencyRatioPriority(currency0) > currencyRatioPriority(currency1);
+ /// @notice Returns true if address0 has higher priority than address1
+ /// @param address0 The first address
+ /// @param address1 The second address
+ /// @return flipRatio True if address0 has higher priority than address1
+ function flipRatio(address address0, address address1) public view returns (bool) {
+ return addressRatioPriority(address0) > addressRatioPriority(address1);
}
- /// @notice Returns the priority of a currency.
- /// For certain currencies on mainnet, the smaller the currency, the higher the priority
- /// @param currency The currency address
- /// @return priority The priority of the currency
- function currencyRatioPriority(address currency) public view returns (int256) {
- // Currencies in order of priority on mainnet: USDC, USDT, DAI, (ETH, WETH), TBTC, WBTC
+ /// @notice Returns the priority of an address.
+ /// For certain addresses on mainnet, the smaller the address, the higher the priority
+ /// @param addr The address
+ /// @return priority The priority of the address
+ function addressRatioPriority(address addr) public view returns (int256) {
+ // Addresses in order of priority on mainnet: USDC, USDT, DAI, (ETH, WETH), TBTC, WBTC
// wrapped native is different address on different chains. passed in constructor
- // native currency
- if (currency == address(0) || currency == wrappedNative) {
- return CurrencyRatioSortOrder.DENOMINATOR;
+ // native address
+ if (addr == address(0) || addr == wrappedNative) {
+ return AddressRatioSortOrder.DENOMINATOR;
}
if (block.chainid == 1) {
- if (currency == USDC) {
- return CurrencyRatioSortOrder.NUMERATOR_MOST;
- } else if (currency == USDT) {
- return CurrencyRatioSortOrder.NUMERATOR_MORE;
- } else if (currency == DAI) {
- return CurrencyRatioSortOrder.NUMERATOR;
- } else if (currency == TBTC) {
- return CurrencyRatioSortOrder.DENOMINATOR_MORE;
- } else if (currency == WBTC) {
- return CurrencyRatioSortOrder.DENOMINATOR_MOST;
+ if (addr == USDC) {
+ return AddressRatioSortOrder.NUMERATOR_MOST;
+ } else if (addr == USDT) {
+ return AddressRatioSortOrder.NUMERATOR_MORE;
+ } else if (addr == DAI) {
+ return AddressRatioSortOrder.NUMERATOR;
+ } else if (addr == TBTC) {
+ return AddressRatioSortOrder.DENOMINATOR_MORE;
+ } else if (addr == WBTC) {
+ return AddressRatioSortOrder.DENOMINATOR_MOST;
} else {
return 0;
}
diff --git a/src/libraries/CurrencyRatioSortOrder.sol b/src/libraries/AddressRatioSortOrder.sol
similarity index 65%
rename from src/libraries/CurrencyRatioSortOrder.sol
rename to src/libraries/AddressRatioSortOrder.sol
index 1f3a719a..71fdfcf9 100644
--- a/src/libraries/CurrencyRatioSortOrder.sol
+++ b/src/libraries/AddressRatioSortOrder.sol
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
-/// @title CurrencyRatioSortOrder
-/// @notice Provides constants for sorting currencies when displaying price ratios
-/// Currencies given larger values will be in the numerator of the price ratio
+/// @title AddressRatioSortOrder
+/// @notice Provides constants for sorting addresses when displaying price ratios
+/// Addresses given larger values will be in the numerator of the price ratio
/// @dev Reference: https://github.com/Uniswap/v3-periphery/blob/main/contracts/libraries/TokenRatioSortOrder.sol
-library CurrencyRatioSortOrder {
+library AddressRatioSortOrder {
int256 constant NUMERATOR_MOST = 300;
int256 constant NUMERATOR_MORE = 200;
int256 constant NUMERATOR = 100;
diff --git a/src/libraries/Descriptor.sol b/src/libraries/Descriptor.sol
index 527e7bd8..56f7cb39 100644
--- a/src/libraries/Descriptor.sol
+++ b/src/libraries/Descriptor.sol
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
-import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {FullMath} from "@uniswap/v4-core/src/libraries/FullMath.sol";
import {LPFeeLibrary} from "@uniswap/v4-core/src/libraries/LPFeeLibrary.sol";
@@ -23,12 +22,12 @@ library Descriptor {
struct ConstructTokenURIParams {
uint256 tokenId;
- Currency quoteCurrency;
- Currency baseCurrency;
- string quoteCurrencySymbol;
- string baseCurrencySymbol;
- uint8 quoteCurrencyDecimals;
- uint8 baseCurrencyDecimals;
+ address quoteAddress;
+ address baseAddress;
+ string quoteAddressSymbol;
+ string baseAddressSymbol;
+ uint8 quoteAddressDecimals;
+ uint8 baseAddressDecimals;
bool flipRatio;
int24 tickLower;
int24 tickUpper;
@@ -45,15 +44,15 @@ library Descriptor {
function constructTokenURI(ConstructTokenURIParams memory params) internal pure returns (string memory) {
string memory name = generateName(params, feeToPercentString(params.fee));
string memory descriptionPartOne = generateDescriptionPartOne(
- escapeQuotes(params.quoteCurrencySymbol),
- escapeQuotes(params.baseCurrencySymbol),
+ escapeQuotes(params.quoteAddressSymbol),
+ escapeQuotes(params.baseAddressSymbol),
addressToString(params.poolManager)
);
string memory descriptionPartTwo = generateDescriptionPartTwo(
params.tokenId.toString(),
- escapeQuotes(params.baseCurrencySymbol),
- addressToString(Currency.unwrap(params.quoteCurrency)),
- addressToString(Currency.unwrap(params.baseCurrency)),
+ escapeQuotes(params.baseAddressSymbol),
+ params.quoteAddress == address(0) ? "Native" : addressToString(params.quoteAddress),
+ params.baseAddress == address(0) ? "Native" : addressToString(params.baseAddress),
addressToString(params.hooks),
feeToPercentString(params.fee)
);
@@ -109,56 +108,56 @@ library Descriptor {
}
/// @notice Generates the first part of the description for a Uniswap v4 NFT
- /// @param quoteCurrencySymbol The symbol of the quote currency
- /// @param baseCurrencySymbol The symbol of the base currency
+ /// @param quoteAddressSymbol The symbol of the quote address
+ /// @param baseAddressSymbol The symbol of the base address
/// @param poolManager The address of the pool manager
/// @return The first part of the description
function generateDescriptionPartOne(
- string memory quoteCurrencySymbol,
- string memory baseCurrencySymbol,
+ string memory quoteAddressSymbol,
+ string memory baseAddressSymbol,
string memory poolManager
) private pure returns (string memory) {
- // displays quote currency first, then base currency
+ // displays quote address first, then base address
return string(
abi.encodePacked(
"This NFT represents a liquidity position in a Uniswap v4 ",
- quoteCurrencySymbol,
+ quoteAddressSymbol,
"-",
- baseCurrencySymbol,
+ baseAddressSymbol,
" pool. ",
"The owner of this NFT can modify or redeem the position.\\n",
"\\nPool Manager Address: ",
poolManager,
"\\n",
- quoteCurrencySymbol
+ quoteAddressSymbol
)
);
}
/// @notice Generates the second part of the description for a Uniswap v4 NFTs
/// @param tokenId The token ID
- /// @param baseCurrencySymbol The symbol of the base currency
- /// @param quoteCurrency The address of the quote currency
- /// @param baseCurrency The address of the base currency
+ /// @param baseAddressSymbol The symbol of the base address
+ /// @param quoteAddress The address of the quote address
+ /// @param baseAddress The address of the base address
/// @param hooks The address of the hooks contract
/// @param feeTier The fee tier of the pool
/// @return The second part of the description
function generateDescriptionPartTwo(
string memory tokenId,
- string memory baseCurrencySymbol,
- string memory quoteCurrency,
- string memory baseCurrency,
+ string memory baseAddressSymbol,
+ string memory quoteAddress,
+ string memory baseAddress,
string memory hooks,
string memory feeTier
) private pure returns (string memory) {
return string(
abi.encodePacked(
" Address: ",
- quoteCurrency,
+ quoteAddress,
"\\n",
- baseCurrencySymbol,
+ baseAddressSymbol,
" Address: ",
- baseCurrency,
+ baseAddress,
"\\nHook Address: ",
hooks,
"\\nFee Tier: ",
@@ -166,7 +165,7 @@ library Descriptor {
"\\nToken ID: ",
tokenId,
"\\n\\n",
- unicode"⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated."
+ unicode"⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure addresses match the expected addresses, as symbols may be imitated."
)
);
}
@@ -180,29 +179,29 @@ library Descriptor {
pure
returns (string memory)
{
- // image shows in terms of price, ie quoteCurrency/baseCurrency
+ // image shows in terms of price, ie quoteAddress/baseAddress
return string(
abi.encodePacked(
"Uniswap - ",
feeTier,
" - ",
- escapeQuotes(params.quoteCurrencySymbol),
+ escapeQuotes(params.quoteAddressSymbol),
"/",
- escapeQuotes(params.baseCurrencySymbol),
+ escapeQuotes(params.baseAddressSymbol),
" - ",
tickToDecimalString(
!params.flipRatio ? params.tickLower : params.tickUpper,
params.tickSpacing,
- params.baseCurrencyDecimals,
- params.quoteCurrencyDecimals,
+ params.baseAddressDecimals,
+ params.quoteAddressDecimals,
params.flipRatio
),
"<>",
tickToDecimalString(
!params.flipRatio ? params.tickUpper : params.tickLower,
params.tickSpacing,
- params.baseCurrencyDecimals,
- params.quoteCurrencyDecimals,
+ params.baseAddressDecimals,
+ params.quoteAddressDecimals,
params.flipRatio
)
)
@@ -262,15 +261,15 @@ library Descriptor {
/// MIN or MAX are returned if tick is at the bottom or top of the price curve
/// @param tick The tick (either tickLower or tickUpper)
/// @param tickSpacing The tick spacing of the pool
- /// @param baseCurrencyDecimals The decimals of the base currency
- /// @param quoteCurrencyDecimals The decimals of the quote currency
+ /// @param baseAddressDecimals The decimals of the base address
+ /// @param quoteAddressDecimals The decimals of the quote address
/// @param flipRatio True if the ratio was flipped
/// @return The ratio value as a string
function tickToDecimalString(
int24 tick,
int24 tickSpacing,
- uint8 baseCurrencyDecimals,
- uint8 quoteCurrencyDecimals,
+ uint8 baseAddressDecimals,
+ uint8 quoteAddressDecimals,
bool flipRatio
) internal pure returns (string memory) {
if (tick == (TickMath.MIN_TICK / tickSpacing) * tickSpacing) {
@@ -282,7 +281,7 @@ library Descriptor {
if (flipRatio) {
sqrtRatioX96 = uint160(uint256(1 << 192) / sqrtRatioX96);
}
- return fixedPointToDecimalString(sqrtRatioX96, baseCurrencyDecimals, quoteCurrencyDecimals);
+ return fixedPointToDecimalString(sqrtRatioX96, baseAddressDecimals, quoteAddressDecimals);
}
}
@@ -306,17 +305,17 @@ library Descriptor {
/// @notice Adjusts the sqrt price for different currencies with different decimals
/// @param sqrtRatioX96 The sqrt price at a specific tick
- /// @param baseCurrencyDecimals The decimals of the base currency
- /// @param quoteCurrencyDecimals The decimals of the quote currency
+ /// @param baseAddressDecimals The decimals of the base address
+ /// @param quoteAddressDecimals The decimals of the quote address
/// @return adjustedSqrtRatioX96 The adjusted sqrt price
- function adjustForDecimalPrecision(uint160 sqrtRatioX96, uint8 baseCurrencyDecimals, uint8 quoteCurrencyDecimals)
+ function adjustForDecimalPrecision(uint160 sqrtRatioX96, uint8 baseAddressDecimals, uint8 quoteAddressDecimals)
private
pure
returns (uint256 adjustedSqrtRatioX96)
{
- uint256 difference = abs(int256(uint256(baseCurrencyDecimals)) - (int256(uint256(quoteCurrencyDecimals))));
+ uint256 difference = abs(int256(uint256(baseAddressDecimals)) - (int256(uint256(quoteAddressDecimals))));
if (difference > 0 && difference <= 18) {
- if (baseCurrencyDecimals > quoteCurrencyDecimals) {
+ if (baseAddressDecimals > quoteAddressDecimals) {
adjustedSqrtRatioX96 = sqrtRatioX96 * (10 ** (difference / 2));
if (difference % 2 == 1) {
adjustedSqrtRatioX96 = FullMath.mulDiv(adjustedSqrtRatioX96, sqrt10X128, 1 << 128);
@@ -339,13 +338,13 @@ library Descriptor {
return uint256(x >= 0 ? x : -x);
}
- function fixedPointToDecimalString(uint160 sqrtRatioX96, uint8 baseCurrencyDecimals, uint8 quoteCurrencyDecimals)
+ function fixedPointToDecimalString(uint160 sqrtRatioX96, uint8 baseAddressDecimals, uint8 quoteAddressDecimals)
internal
pure
returns (string memory)
{
uint256 adjustedSqrtRatioX96 =
- adjustForDecimalPrecision(sqrtRatioX96, baseCurrencyDecimals, quoteCurrencyDecimals);
+ adjustForDecimalPrecision(sqrtRatioX96, baseAddressDecimals, quoteAddressDecimals);
uint256 value = FullMath.mulDiv(adjustedSqrtRatioX96, adjustedSqrtRatioX96, 1 << 64);
bool priceBelow1 = adjustedSqrtRatioX96 < 2 ** 96;
@@ -462,27 +461,27 @@ library Descriptor {
/// @return svg The SVG image as a string
function generateSVGImage(ConstructTokenURIParams memory params) internal pure returns (string memory svg) {
SVG.SVGParams memory svgParams = SVG.SVGParams({
- quoteCurrency: addressToString(Currency.unwrap(params.quoteCurrency)),
- baseCurrency: addressToString(Currency.unwrap(params.baseCurrency)),
+ quoteAddress: addressToString(params.quoteAddress),
+ baseAddress: addressToString(params.baseAddress),
hooks: params.hooks,
- quoteCurrencySymbol: params.quoteCurrencySymbol,
- baseCurrencySymbol: params.baseCurrencySymbol,
+ quoteAddressSymbol: params.quoteAddressSymbol,
+ baseAddressSymbol: params.baseAddressSymbol,
feeTier: feeToPercentString(params.fee),
tickLower: params.tickLower,
tickUpper: params.tickUpper,
tickSpacing: params.tickSpacing,
overRange: overRange(params.tickLower, params.tickUpper, params.tickCurrent),
tokenId: params.tokenId,
- color0: currencyToColorHex(params.quoteCurrency.toId(), 136),
- color1: currencyToColorHex(params.baseCurrency.toId(), 136),
- color2: currencyToColorHex(params.quoteCurrency.toId(), 0),
- color3: currencyToColorHex(params.baseCurrency.toId(), 0),
- x1: scale(getCircleCoord(params.quoteCurrency.toId(), 16, params.tokenId), 0, 255, 16, 274),
- y1: scale(getCircleCoord(params.baseCurrency.toId(), 16, params.tokenId), 0, 255, 100, 484),
- x2: scale(getCircleCoord(params.quoteCurrency.toId(), 32, params.tokenId), 0, 255, 16, 274),
- y2: scale(getCircleCoord(params.baseCurrency.toId(), 32, params.tokenId), 0, 255, 100, 484),
- x3: scale(getCircleCoord(params.quoteCurrency.toId(), 48, params.tokenId), 0, 255, 16, 274),
- y3: scale(getCircleCoord(params.baseCurrency.toId(), 48, params.tokenId), 0, 255, 100, 484)
+ color0: addressToColorHex(uint256(uint160(params.quoteAddress)), 136),
+ color1: addressToColorHex(uint256(uint160(params.baseAddress)), 136),
+ color2: addressToColorHex(uint256(uint160(params.quoteAddress)), 0),
+ color3: addressToColorHex(uint256(uint160(params.baseAddress)), 0),
+ x1: scale(getCircleCoord(uint256(uint160(params.quoteAddress)), 16, params.tokenId), 0, 255, 16, 274),
+ y1: scale(getCircleCoord(uint256(uint160(params.baseAddress)), 16, params.tokenId), 0, 255, 100, 484),
+ x2: scale(getCircleCoord(uint256(uint160(params.quoteAddress)), 32, params.tokenId), 0, 255, 16, 274),
+ y2: scale(getCircleCoord(uint256(uint160(params.baseAddress)), 32, params.tokenId), 0, 255, 100, 484),
+ x3: scale(getCircleCoord(uint256(uint160(params.quoteAddress)), 48, params.tokenId), 0, 255, 16, 274),
+ y3: scale(getCircleCoord(uint256(uint160(params.baseAddress)), 48, params.tokenId), 0, 255, 100, 484)
});
return SVG.generateSVG(svgParams);
@@ -511,15 +510,15 @@ library Descriptor {
return ((n - inMn) * (outMx - outMn) / (inMx - inMn) + outMn).toString();
}
- function currencyToColorHex(uint256 currency, uint256 offset) internal pure returns (string memory str) {
- return string((currency >> offset).toHexStringNoPrefix(3));
+ function addressToColorHex(uint256 addr, uint256 offset) internal pure returns (string memory str) {
+ return string((addr >> offset).toHexStringNoPrefix(3));
}
- function getCircleCoord(uint256 currency, uint256 offset, uint256 tokenId) internal pure returns (uint256) {
- return (sliceCurrencyHex(currency, offset) * tokenId) % 255;
+ function getCircleCoord(uint256 addr, uint256 offset, uint256 tokenId) internal pure returns (uint256) {
+ return (sliceAddressHex(addr, offset) * tokenId) % 255;
}
- function sliceCurrencyHex(uint256 currency, uint256 offset) internal pure returns (uint256) {
- return uint256(uint8(currency >> offset));
+ function sliceAddressHex(uint256 addr, uint256 offset) internal pure returns (uint256) {
+ return uint256(uint8(addr >> offset));
}
}
diff --git a/src/libraries/SVG.sol b/src/libraries/SVG.sol
index dea00e66..0da00a50 100644
--- a/src/libraries/SVG.sol
+++ b/src/libraries/SVG.sol
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
-import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {BitMath} from "@uniswap/v4-core/src/libraries/BitMath.sol";
import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol";
@@ -26,11 +25,11 @@ library SVG {
string constant curve8 = "M1 1C1 97 49 145 145 145";
struct SVGParams {
- string quoteCurrency;
- string baseCurrency;
+ string quoteAddress;
+ string baseAddress;
address hooks;
- string quoteCurrencySymbol;
- string baseCurrencySymbol;
+ string quoteAddressSymbol;
+ string baseAddressSymbol;
string feeTier;
int24 tickLower;
int24 tickUpper;
@@ -57,9 +56,9 @@ library SVG {
abi.encodePacked(
generateSVGDefs(params),
generateSVGBorderText(
- params.quoteCurrency, params.baseCurrency, params.quoteCurrencySymbol, params.baseCurrencySymbol
+ params.quoteAddress, params.baseAddress, params.quoteAddressSymbol, params.baseAddressSymbol
),
- generateSVGCardMantle(params.quoteCurrencySymbol, params.baseCurrencySymbol, params.feeTier),
+ generateSVGCardMantle(params.quoteAddressSymbol, params.baseAddressSymbol, params.feeTier),
generageSvgCurve(params.tickLower, params.tickUpper, params.tickSpacing, params.overRange),
generateSVGPositionDataAndLocationCurve(
params.tokenId.toString(), params.hooks, params.tickLower, params.tickUpper
@@ -158,61 +157,61 @@ library SVG {
);
}
- /// @notice Generate the SVG for the moving border text displaying the quote and base currency addresses with their symbols
- /// @param quoteCurrency The quote currency
- /// @param baseCurrency The base currency
- /// @param quoteCurrencySymbol The quote currency symbol
- /// @param baseCurrencySymbol The base currency symbol
+ /// @notice Generate the SVG for the moving border text displaying the quote and base addresses with their symbols
+ /// @param quoteAddress The quote address
+ /// @param baseAddress The base address
+ /// @param quoteAddressSymbol The quote address symbol
+ /// @param baseAddressSymbol The base address symbol
/// @return svg The SVG for the border NFT's border text
function generateSVGBorderText(
- string memory quoteCurrency,
- string memory baseCurrency,
- string memory quoteCurrencySymbol,
- string memory baseCurrencySymbol
+ string memory quoteAddress,
+ string memory baseAddress,
+ string memory quoteAddressSymbol,
+ string memory baseAddressSymbol
) private pure returns (string memory svg) {
svg = string(
abi.encodePacked(
'',
'',
- baseCurrency,
+ baseAddress,
unicode" • ",
- baseCurrencySymbol,
+ baseAddressSymbol,
' ',
' ',
- baseCurrency,
+ baseAddress,
unicode" • ",
- baseCurrencySymbol,
+ baseAddressSymbol,
' ',
'',
- quoteCurrency,
+ quoteAddress,
unicode" • ",
- quoteCurrencySymbol,
+ quoteAddressSymbol,
' ',
- quoteCurrency,
+ quoteAddress,
unicode" • ",
- quoteCurrencySymbol,
+ quoteAddressSymbol,
' '
)
);
}
- /// @notice Generate the SVG for the card mantle displaying the quote and base currency symbols and fee tier
- /// @param quoteCurrencySymbol The quote currency symbol
- /// @param baseCurrencySymbol The base currency symbol
+ /// @notice Generate the SVG for the card mantle displaying the quote and base address symbols and fee tier
+ /// @param quoteAddressSymbol The quote address symbol
+ /// @param baseAddressSymbol The base address symbol
/// @param feeTier The fee tier
/// @return svg The SVG for the card mantle
function generateSVGCardMantle(
- string memory quoteCurrencySymbol,
- string memory baseCurrencySymbol,
+ string memory quoteAddressSymbol,
+ string memory baseAddressSymbol,
string memory feeTier
) private pure returns (string memory svg) {
svg = string(
abi.encodePacked(
' ',
- quoteCurrencySymbol,
+ quoteAddressSymbol,
"/",
- baseCurrencySymbol,
+ baseAddressSymbol,
'',
feeTier,
"",
diff --git a/src/libraries/SafeCurrencyMetadata.sol b/src/libraries/SafeERC20Metadata.sol
similarity index 64%
rename from src/libraries/SafeCurrencyMetadata.sol
rename to src/libraries/SafeERC20Metadata.sol
index f4d7cf27..1346a3f7 100644
--- a/src/libraries/SafeCurrencyMetadata.sol
+++ b/src/libraries/SafeERC20Metadata.sol
@@ -2,41 +2,36 @@
pragma solidity ^0.8.0;
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
-import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {AddressStringUtil} from "./AddressStringUtil.sol";
-/// @title SafeCurrencyMetadata
+/// @title SafeERC20Metadata
/// @notice can produce symbols and decimals from inconsistent or absent ERC20 implementations
/// @dev Reference: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/SafeERC20Namer.sol
-library SafeCurrencyMetadata {
- using CurrencyLibrary for Currency;
-
+library SafeERC20Metadata {
/// @notice attempts to extract the token symbol. if it does not implement symbol, returns a symbol derived from the address
- /// @param currency The currency
+ /// @param addr The address
/// @param nativeLabel The native label
/// @return the token symbol
- function currencySymbol(Currency currency, string memory nativeLabel) internal view returns (string memory) {
- if (currency.isAddressZero()) {
+ function addressSymbol(address addr, string memory nativeLabel) internal view returns (string memory) {
+ if (addr == address(0)) {
return nativeLabel;
}
- address currencyAddress = Currency.unwrap(currency);
- string memory symbol = callAndParseStringReturn(currencyAddress, IERC20Metadata.symbol.selector);
+ string memory symbol = callAndParseStringReturn(addr, IERC20Metadata.symbol.selector);
if (bytes(symbol).length == 0) {
// fallback to 6 uppercase hex of address
- return addressToSymbol(currencyAddress);
+ return addressToSymbol(addr);
}
return symbol;
}
/// @notice attempts to extract the token decimals, returns 0 if not implemented or not a uint8
- /// @param currency The currency
+ /// @param addr The address
/// @return the token decimals
- function currencyDecimals(Currency currency) internal view returns (uint8) {
- if (currency.isAddressZero()) {
+ function addressDecimals(address addr) internal view returns (uint8) {
+ if (addr == address(0)) {
return 18;
}
- (bool success, bytes memory data) =
- Currency.unwrap(currency).staticcall(abi.encodeCall(IERC20Metadata.decimals, ()));
+ (bool success, bytes memory data) = addr.staticcall(abi.encodeCall(IERC20Metadata.decimals, ()));
if (!success) {
return 0;
}
@@ -64,18 +59,18 @@ library SafeCurrencyMetadata {
}
/// @notice produces a symbol from the address - the first 6 hex of the address string in upper case
- /// @param currencyAddress the address of the currency
+ /// @param addr The address
/// @return the symbol
- function addressToSymbol(address currencyAddress) private pure returns (string memory) {
- return AddressStringUtil.toAsciiString(currencyAddress, 6);
+ function addressToSymbol(address addr) private pure returns (string memory) {
+ return AddressStringUtil.toAsciiString(addr, 6);
}
/// @notice calls an external view contract method that returns a symbol, and parses the output into a string
- /// @param currencyAddress the address of the currency
+ /// @param addr The address
/// @param selector the selector of the symbol method
/// @return the symbol
- function callAndParseStringReturn(address currencyAddress, bytes4 selector) private view returns (string memory) {
- (bool success, bytes memory data) = currencyAddress.staticcall(abi.encodeWithSelector(selector));
+ function callAndParseStringReturn(address addr, bytes4 selector) private view returns (string memory) {
+ (bool success, bytes memory data) = addr.staticcall(abi.encodeWithSelector(selector));
// if not implemented, return empty string
if (!success) {
return "";
diff --git a/test/PositionDescriptor.t.sol b/test/PositionDescriptor.t.sol
index dabe8393..381a4cdb 100644
--- a/test/PositionDescriptor.t.sol
+++ b/test/PositionDescriptor.t.sol
@@ -3,7 +3,7 @@ pragma solidity ^0.8.24;
import "forge-std/Test.sol";
import {PositionDescriptor} from "../src/PositionDescriptor.sol";
-import {CurrencyRatioSortOrder} from "../src/libraries/CurrencyRatioSortOrder.sol";
+import {AddressRatioSortOrder} from "../src/libraries/AddressRatioSortOrder.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {LiquidityAmounts} from "@uniswap/v4-core/test/utils/LiquidityAmounts.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
@@ -44,30 +44,30 @@ contract PositionDescriptorTest is Test, PosmTestSetup, GasSnapshot {
function test_setup_succeeds() public view {
assertEq(address(positionDescriptor.poolManager()), address(manager));
assertEq(positionDescriptor.wrappedNative(), WETH9);
- assertEq(positionDescriptor.nativeCurrencyLabel(), nativeCurrencyLabel);
+ assertEq(positionDescriptor.nativeAddressLabel(), nativeCurrencyLabel);
}
- function test_currencyRatioPriority_mainnet_succeeds() public {
+ function test_addressRatioPriority_mainnet_succeeds() public {
vm.chainId(1);
- assertEq(positionDescriptor.currencyRatioPriority(WETH9), CurrencyRatioSortOrder.DENOMINATOR);
- assertEq(positionDescriptor.currencyRatioPriority(address(0)), CurrencyRatioSortOrder.DENOMINATOR);
- assertEq(positionDescriptor.currencyRatioPriority(USDC), CurrencyRatioSortOrder.NUMERATOR_MOST);
- assertEq(positionDescriptor.currencyRatioPriority(USDT), CurrencyRatioSortOrder.NUMERATOR_MORE);
- assertEq(positionDescriptor.currencyRatioPriority(DAI), CurrencyRatioSortOrder.NUMERATOR);
- assertEq(positionDescriptor.currencyRatioPriority(TBTC), CurrencyRatioSortOrder.DENOMINATOR_MORE);
- assertEq(positionDescriptor.currencyRatioPriority(WBTC), CurrencyRatioSortOrder.DENOMINATOR_MOST);
- assertEq(positionDescriptor.currencyRatioPriority(makeAddr("ALICE")), 0);
+ assertEq(positionDescriptor.addressRatioPriority(WETH9), AddressRatioSortOrder.DENOMINATOR);
+ assertEq(positionDescriptor.addressRatioPriority(address(0)), AddressRatioSortOrder.DENOMINATOR);
+ assertEq(positionDescriptor.addressRatioPriority(USDC), AddressRatioSortOrder.NUMERATOR_MOST);
+ assertEq(positionDescriptor.addressRatioPriority(USDT), AddressRatioSortOrder.NUMERATOR_MORE);
+ assertEq(positionDescriptor.addressRatioPriority(DAI), AddressRatioSortOrder.NUMERATOR);
+ assertEq(positionDescriptor.addressRatioPriority(TBTC), AddressRatioSortOrder.DENOMINATOR_MORE);
+ assertEq(positionDescriptor.addressRatioPriority(WBTC), AddressRatioSortOrder.DENOMINATOR_MOST);
+ assertEq(positionDescriptor.addressRatioPriority(makeAddr("ALICE")), 0);
}
- function test_currencyRatioPriority_notMainnet_succeeds() public {
- assertEq(positionDescriptor.currencyRatioPriority(WETH9), CurrencyRatioSortOrder.DENOMINATOR);
- assertEq(positionDescriptor.currencyRatioPriority(address(0)), CurrencyRatioSortOrder.DENOMINATOR);
- assertEq(positionDescriptor.currencyRatioPriority(USDC), 0);
- assertEq(positionDescriptor.currencyRatioPriority(USDT), 0);
- assertEq(positionDescriptor.currencyRatioPriority(DAI), 0);
- assertEq(positionDescriptor.currencyRatioPriority(TBTC), 0);
- assertEq(positionDescriptor.currencyRatioPriority(WBTC), 0);
- assertEq(positionDescriptor.currencyRatioPriority(makeAddr("ALICE")), 0);
+ function test_addressRatioPriority_notMainnet_succeeds() public {
+ assertEq(positionDescriptor.addressRatioPriority(WETH9), AddressRatioSortOrder.DENOMINATOR);
+ assertEq(positionDescriptor.addressRatioPriority(address(0)), AddressRatioSortOrder.DENOMINATOR);
+ assertEq(positionDescriptor.addressRatioPriority(USDC), 0);
+ assertEq(positionDescriptor.addressRatioPriority(USDT), 0);
+ assertEq(positionDescriptor.addressRatioPriority(DAI), 0);
+ assertEq(positionDescriptor.addressRatioPriority(TBTC), 0);
+ assertEq(positionDescriptor.addressRatioPriority(WBTC), 0);
+ assertEq(positionDescriptor.addressRatioPriority(makeAddr("ALICE")), 0);
}
function test_flipRatio_succeeds() public {
@@ -122,7 +122,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup, GasSnapshot {
assertEq(token.name, "Uniswap - 0.3% - TEST/TEST - 1.0060<>1.0121");
assertEq(
token.description,
- unicode"This NFT represents a liquidity position in a Uniswap v4 TEST-TEST pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: 0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f\nTEST Address: 0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9\nTEST Address: 0x2e234dae75c793f67a35089c9d99245e1c58470b\nHook Address: 0x0000000000000000000000000000000000000000\nFee Tier: 0.3%\nToken ID: 1\n\n⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated."
+ unicode"This NFT represents a liquidity position in a Uniswap v4 TEST-TEST pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: 0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f\nTEST Address: 0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9\nTEST Address: 0x2e234dae75c793f67a35089c9d99245e1c58470b\nHook Address: 0x0000000000000000000000000000000000000000\nFee Tier: 0.3%\nToken ID: 1\n\n⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure addresses match the expected addresses, as symbols may be imitated."
);
}