Skip to content

Commit

Permalink
feat: update art (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
simplyoptimistic authored Mar 2, 2024
1 parent e75c08c commit 4f92328
Show file tree
Hide file tree
Showing 11 changed files with 291 additions and 608 deletions.
88 changes: 66 additions & 22 deletions contracts/periphery/NonfungibleTokenPositionDescriptor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma abicoder v2;

import "contracts/core/interfaces/ICLPool.sol";
import "@uniswap/contracts/libraries/SafeERC20Namer.sol";
import "base64-sol/base64.sol";

import "./libraries/ChainId.sol";
import "./interfaces/INonfungiblePositionManager.sol";
Expand All @@ -12,6 +13,7 @@ import "./interfaces/IERC20Metadata.sol";
import "./libraries/PoolAddress.sol";
import "./libraries/NFTDescriptor.sol";
import "./libraries/TokenRatioSortOrder.sol";
import "./libraries/NFTSVG.sol";

/// @title Describes NFT token positions
/// @notice Produces a string containing the data URI for a JSON metadata string
Expand Down Expand Up @@ -64,31 +66,73 @@ contract NonfungibleTokenPositionDescriptor is INonfungibleTokenPositionDescript
bool _flipRatio = flipRatio(token0, token1, ChainId.get());
address quoteTokenAddress = !_flipRatio ? token1 : token0;
address baseTokenAddress = !_flipRatio ? token0 : token1;
(, int24 tick,,,,) = pool.slot0();

return NFTDescriptor.constructTokenURI(
NFTDescriptor.ConstructTokenURIParams({
tokenId: tokenId,
quoteTokenAddress: quoteTokenAddress,
baseTokenAddress: baseTokenAddress,
quoteTokenSymbol: quoteTokenAddress == WETH9
? nativeCurrencyLabel()
: SafeERC20Namer.tokenSymbol(quoteTokenAddress),
baseTokenSymbol: baseTokenAddress == WETH9
? nativeCurrencyLabel()
: SafeERC20Namer.tokenSymbol(baseTokenAddress),
quoteTokenDecimals: IERC20Metadata(quoteTokenAddress).decimals(),
baseTokenDecimals: IERC20Metadata(baseTokenAddress).decimals(),
flipRatio: _flipRatio,
tickLower: tickLower,
tickUpper: tickUpper,
tickCurrent: tick,
tickSpacing: tickSpacing,
poolAddress: address(pool)
})
NFTDescriptor.ConstructTokenURIParams memory params = NFTDescriptor.ConstructTokenURIParams({
tokenId: tokenId,
quoteTokenAddress: quoteTokenAddress,
baseTokenAddress: baseTokenAddress,
quoteTokenSymbol: quoteTokenAddress == WETH9
? nativeCurrencyLabel()
: SafeERC20Namer.tokenSymbol(quoteTokenAddress),
baseTokenSymbol: baseTokenAddress == WETH9
? nativeCurrencyLabel()
: SafeERC20Namer.tokenSymbol(baseTokenAddress),
quoteTokenDecimals: IERC20Metadata(quoteTokenAddress).decimals(),
baseTokenDecimals: IERC20Metadata(baseTokenAddress).decimals(),
flipRatio: _flipRatio,
tickLower: tickLower,
tickUpper: tickUpper,
tickSpacing: tickSpacing,
poolAddress: address(pool)
});

string memory image = Base64.encode(bytes(generateSVG(positionManager, params)));

string memory nameAndDescription = NFTDescriptor.constructTokenURI(params);

return string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
bytes(
abi.encodePacked(
"{", nameAndDescription, ', "image": "', "data:image/svg+xml;base64,", image, '"}'
)
)
)
)
);
}

function generateSVG(
INonfungiblePositionManager positionManager,
NFTDescriptor.ConstructTokenURIParams memory params
) internal view returns (string memory) {
(uint256 quoteTokensOwed, uint256 baseTokensOwed) =
tokensOwed({positionManager: positionManager, tokenId: params.tokenId, flipRatio: params.flipRatio});
return NFTSVG.generateSVG({
quoteTokenSymbol: params.quoteTokenSymbol,
baseTokenSymbol: params.baseTokenSymbol,
quoteTokensOwed: quoteTokensOwed,
baseTokensOwed: baseTokensOwed,
tokenId: params.tokenId,
tickLower: params.tickLower,
tickUpper: params.tickUpper,
tickSpacing: params.tickSpacing,
quoteTokenDecimals: params.quoteTokenDecimals,
baseTokenDecimals: params.baseTokenDecimals
});
}

function tokensOwed(INonfungiblePositionManager positionManager, uint256 tokenId, bool flipRatio)
internal
view
returns (uint256 quoteTokensOwed, uint256 baseTokensOwed)
{
(,,,,,,,,,, uint256 tokensOwed0, uint256 tokensOwed1) = positionManager.positions(tokenId);
quoteTokensOwed = flipRatio ? tokensOwed1 : tokensOwed0;
baseTokensOwed = flipRatio ? tokensOwed0 : tokensOwed1;
}

function flipRatio(address token0, address token1, uint256 chainId) public view returns (bool) {
return tokenRatioPriority(token0, chainId) > tokenRatioPriority(token1, chainId);
}
Expand Down
80 changes: 1 addition & 79 deletions contracts/periphery/libraries/NFTDescriptor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import "contracts/core/libraries/FullMath.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/math/SignedSafeMath.sol";
import "base64-sol/base64.sol";
import "./HexStrings.sol";
import "./NFTSVG.sol";

library NFTDescriptor {
using TickMath for int24;
Expand All @@ -35,7 +33,6 @@ library NFTDescriptor {
bool flipRatio;
int24 tickLower;
int24 tickUpper;
int24 tickCurrent;
int24 tickSpacing;
address poolAddress;
}
Expand All @@ -54,27 +51,9 @@ library NFTDescriptor {
addressToString(params.baseTokenAddress),
(uint256(params.tickSpacing)).toString()
);
string memory image = Base64.encode(bytes(generateSVGImage(params)));

return string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
bytes(
abi.encodePacked(
'{"name":"',
name,
'", "description":"',
descriptionPartOne,
descriptionPartTwo,
'", "image": "',
"data:image/svg+xml;base64,",
image,
'"}'
)
)
)
)
abi.encodePacked('"name":"', name, '", "description":"', descriptionPartOne, descriptionPartTwo, '"')
);
}

Expand Down Expand Up @@ -392,61 +371,4 @@ library NFTDescriptor {
function addressToString(address addr) internal pure returns (string memory) {
return (uint256(addr)).toHexString(20);
}
function generateSVGImage(ConstructTokenURIParams memory params) internal pure returns (string memory svg) {
NFTSVG.SVGParams memory svgParams = NFTSVG.SVGParams({
quoteToken: addressToString(params.quoteTokenAddress),
baseToken: addressToString(params.baseTokenAddress),
poolAddress: params.poolAddress,
quoteTokenSymbol: params.quoteTokenSymbol,
baseTokenSymbol: params.baseTokenSymbol,
tickLower: params.tickLower,
tickUpper: params.tickUpper,
tickSpacing: params.tickSpacing,
overRange: overRange(params.tickLower, params.tickUpper, params.tickCurrent),
tokenId: params.tokenId,
color0: tokenToColorHex(uint256(params.quoteTokenAddress), 136),
color1: tokenToColorHex(uint256(params.baseTokenAddress), 136),
color2: tokenToColorHex(uint256(params.quoteTokenAddress), 0),
color3: tokenToColorHex(uint256(params.baseTokenAddress), 0),
x1: scale(getCircleCoord(uint256(params.quoteTokenAddress), 16, params.tokenId), 0, 255, 16, 274),
y1: scale(getCircleCoord(uint256(params.baseTokenAddress), 16, params.tokenId), 0, 255, 100, 484),
x2: scale(getCircleCoord(uint256(params.quoteTokenAddress), 32, params.tokenId), 0, 255, 16, 274),
y2: scale(getCircleCoord(uint256(params.baseTokenAddress), 32, params.tokenId), 0, 255, 100, 484),
x3: scale(getCircleCoord(uint256(params.quoteTokenAddress), 48, params.tokenId), 0, 255, 16, 274),
y3: scale(getCircleCoord(uint256(params.baseTokenAddress), 48, params.tokenId), 0, 255, 100, 484)
});
return NFTSVG.generateSVG(svgParams);
}
function overRange(int24 tickLower, int24 tickUpper, int24 tickCurrent) private pure returns (int8) {
if (tickCurrent < tickLower) {
return -1;
} else if (tickCurrent > tickUpper) {
return 1;
} else {
return 0;
}
}
function scale(uint256 n, uint256 inMn, uint256 inMx, uint256 outMn, uint256 outMx)
private
pure
returns (string memory)
{
return (n.sub(inMn).mul(outMx.sub(outMn)).div(inMx.sub(inMn)).add(outMn)).toString();
}
function tokenToColorHex(uint256 token, uint256 offset) internal pure returns (string memory str) {
return string((token >> offset).toHexStringNoPrefix(3));
}
function getCircleCoord(uint256 tokenAddress, uint256 offset, uint256 tokenId) internal pure returns (uint256) {
return (sliceTokenHex(tokenAddress, offset) * tokenId) % 255;
}
function sliceTokenHex(uint256 token, uint256 offset) internal pure returns (uint256) {
return uint256(uint8(token >> offset));
}
}
Loading

0 comments on commit 4f92328

Please sign in to comment.