Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Position descriptor #353

Merged
merged 53 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
2434576
position descriptor stuff
dianakocsis Aug 20, 2024
c423b33
messy checkpoint
snreynolds Aug 28, 2024
e497389
update subscribers
snreynolds Aug 28, 2024
830fdf5
stack too deep, permit error
snreynolds Aug 28, 2024
8eb66b3
use packed, no via-ir, but stack too deep concerning for tests
snreynolds Aug 29, 2024
7e8fc42
use external
snreynolds Aug 29, 2024
f94823f
review comments
snreynolds Aug 29, 2024
a77fb26
merge confs
snreynolds Aug 29, 2024
547c893
clear lower 8 bits on unsubscribe
snreynolds Aug 29, 2024
e695f43
move _pay, minimize diff
snreynolds Aug 29, 2024
df58a26
pr comments
snreynolds Aug 29, 2024
d6d1353
fix: test_fuzz_erc721Permit_SignatureDeadlineExpired
snreynolds Aug 29, 2024
7fd6b5b
naming
snreynolds Aug 29, 2024
84cc704
fix
snreynolds Aug 29, 2024
ec4ebdd
natspec
snreynolds Aug 29, 2024
5a88042
fix: stack too deep in tests
snreynolds Aug 29, 2024
fe1d709
remove console
snreynolds Aug 29, 2024
31a22de
merge main
snreynolds Aug 29, 2024
ca37b8c
move PositionConfig to shared testing infra
snreynolds Aug 29, 2024
ec14729
remove pool key checker lib
snreynolds Aug 29, 2024
21ae901
pr commmeeennnnttsss
snreynolds Aug 29, 2024
b29c5fe
fmt
snreynolds Aug 29, 2024
a2bc1b2
Merge branch 'main' into position-descriptor
dianakocsis Sep 3, 2024
e6315a3
pass in pd to posm
dianakocsis Sep 4, 2024
e7eb9f0
descriptooooor
dianakocsis Sep 18, 2024
69208ec
new files
dianakocsis Sep 18, 2024
e6dfb70
commentsss
dianakocsis Sep 18, 2024
9b723c3
Merge branch 'main' into position-descriptor
dianakocsis Sep 18, 2024
7d69f53
format
dianakocsis Sep 18, 2024
0ba4e38
fix comment
dianakocsis Sep 18, 2024
2b518bf
warnings
dianakocsis Sep 19, 2024
04b719a
more fixes
dianakocsis Sep 19, 2024
7e110cc
priority
dianakocsis Sep 19, 2024
924d12e
update core to fix snapshots
dianakocsis Sep 19, 2024
a6af3b7
re-add files
dianakocsis Sep 19, 2024
69af352
deploy script
dianakocsis Sep 20, 2024
04b458e
does this work
dianakocsis Sep 20, 2024
9ff5137
format
dianakocsis Sep 20, 2024
8506989
merge main
dianakocsis Sep 23, 2024
4542c59
pass in string directly
dianakocsis Sep 23, 2024
d0b81fe
remove extra check
dianakocsis Sep 23, 2024
4d53d2a
comments, selector, and reference
dianakocsis Sep 24, 2024
e4ccd57
Merge branch 'main' into position-descriptor
dianakocsis Sep 24, 2024
a4892e3
some changes
dianakocsis Sep 26, 2024
c08ccd9
more fixes
dianakocsis Sep 26, 2024
40904b0
format
dianakocsis Sep 26, 2024
8a6033e
more review changes
dianakocsis Oct 1, 2024
6ff9887
add safeerc20metadata file
dianakocsis Oct 1, 2024
8ea6b67
updates
dianakocsis Oct 2, 2024
072102f
format
dianakocsis Oct 2, 2024
bd90cee
currency name plus more tests
dianakocsis Oct 4, 2024
f72f195
invalid token id
dianakocsis Oct 7, 2024
c10da46
re-add comments
dianakocsis Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_burn_empty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
50413
50481
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_burn_empty_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
50413
50481
Original file line number Diff line number Diff line change
@@ -1 +1 @@
125541
125609
Original file line number Diff line number Diff line change
@@ -1 +1 @@
124988
125056
Original file line number Diff line number Diff line change
@@ -1 +1 @@
132394
132462
Original file line number Diff line number Diff line change
@@ -1 +1 @@
131841
131909
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
146241
146326
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_sameRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
154807
154892
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_withClose.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
154807
154892
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_withTakePair.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
154128
154213
Original file line number Diff line number Diff line change
@@ -1 +1 @@
111938
112006
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119688
119773
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119009
119094
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_decrease_burnEmpty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135191
135259
Original file line number Diff line number Diff line change
@@ -1 +1 @@
128338
128406
Original file line number Diff line number Diff line change
@@ -1 +1 @@
132375
132460
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_decrease_take_take.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
120264
120349
Original file line number Diff line number Diff line change
@@ -1 +1 @@
158992
159077
Original file line number Diff line number Diff line change
@@ -1 +1 @@
157932
158017
Original file line number Diff line number Diff line change
@@ -1 +1 @@
140819
140904
Original file line number Diff line number Diff line change
@@ -1 +1 @@
136318
136403
Original file line number Diff line number Diff line change
@@ -1 +1 @@
177299
177384
Original file line number Diff line number Diff line change
@@ -1 +1 @@
147975
148060
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
364680
364765
Original file line number Diff line number Diff line change
@@ -1 +1 @@
373203
373288
Original file line number Diff line number Diff line change
@@ -1 +1 @@
372426
372511
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickLower.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
317528
317613
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickUpper.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
318198
318283
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_sameRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
243767
243852
Original file line number Diff line number Diff line change
@@ -1 +1 @@
418947
419032
Original file line number Diff line number Diff line change
@@ -1 +1 @@
323559
323644
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_withClose.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
420081
420166
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_withSettlePair.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
419139
419224
Original file line number Diff line number Diff line change
@@ -1 +1 @@
464241
464348
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_unsubscribe.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
59238
59260
21 changes: 16 additions & 5 deletions script/DeployPosm.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,29 @@ import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
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)
public
returns (PositionManager posm)
{
function run(
address poolManager,
address permit2,
uint256 unsubscribeGasLimit,
address wrappedNative,
string memory nativeCurrencyLabel
) public returns (PositionDescriptor positionDescriptor, PositionManager posm) {
vm.startBroadcast();

positionDescriptor = new PositionDescriptor(IPoolManager(poolManager), wrappedNative, nativeCurrencyLabel);
console2.log("PositionDescriptor", address(positionDescriptor));

posm = new PositionManager{salt: hex"03"}(
IPoolManager(poolManager), IAllowanceTransfer(permit2), unsubscribeGasLimit
IPoolManager(poolManager),
IAllowanceTransfer(permit2),
unsubscribeGasLimit,
IPositionDescriptor(address(positionDescriptor))
);
console2.log("PositionManager", address(posm));

Expand Down
124 changes: 124 additions & 0 deletions src/PositionDescriptor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.26;

import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol";
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";

/// @title Describes NFT token positions
/// @notice Produces a string containing the data URI for a JSON metadata string
contract PositionDescriptor is IPositionDescriptor {
using StateLibrary for IPoolManager;
using PoolIdLibrary for PoolKey;
using CurrencyLibrary for Currency;
using PositionInfoLibrary for PositionInfo;

error InvalidTokenId(uint256 tokenId);

// mainnet addresses
address private constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address private constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address private constant TBTC = 0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa;
address private constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;

address public immutable wrappedNative;
string public nativeCurrencyLabel;

IPoolManager public immutable poolManager;

constructor(IPoolManager _poolManager, address _wrappedNative, string memory _nativeCurrencyLabel) {
poolManager = _poolManager;
wrappedNative = _wrappedNative;
nativeCurrencyLabel = _nativeCurrencyLabel;
}

/// @inheritdoc IPositionDescriptor
function tokenURI(IPositionManager positionManager, uint256 tokenId)
external
view
override
returns (string memory)
{
(PoolKey memory poolKey, PositionInfo positionInfo) = positionManager.getPoolAndPositionInfo(tokenId);
if (positionInfo.poolId() == 0) {
revert InvalidTokenId(tokenId);
}
(, 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));
dianakocsis marked this conversation as resolved.
Show resolved Hide resolved

// 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;

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),
flipRatio: _flipRatio,
tickLower: positionInfo.tickLower(),
tickUpper: positionInfo.tickUpper(),
tickCurrent: tick,
tickSpacing: poolKey.tickSpacing,
fee: poolKey.fee,
poolManager: address(poolManager),
hooks: address(poolKey.hooks)
})
);
}

/// @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 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
// wrapped native is different address on different chains. passed in constructor

// native currency
if (currency == address(0) || currency == wrappedNative) {
return CurrencyRatioSortOrder.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;
} else {
return 0;
}
}
return 0;
}
}
20 changes: 17 additions & 3 deletions src/PositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {Position} from "@uniswap/v4-core/src/libraries/Position.sol";
import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
import {IPositionDescriptor} from "./interfaces/IPositionDescriptor.sol";

import {ERC721Permit_v4} from "./base/ERC721Permit_v4.sol";
import {ReentrancyLock} from "./base/ReentrancyLock.sol";
Expand Down Expand Up @@ -116,15 +117,24 @@ contract PositionManager is
/// @dev The ID of the next token that will be minted. Skips 0
uint256 public nextTokenId = 1;

IPositionDescriptor public immutable tokenDescriptor;

mapping(uint256 tokenId => PositionInfo info) public positionInfo;
mapping(bytes25 poolId => PoolKey poolKey) public poolKeys;

constructor(IPoolManager _poolManager, IAllowanceTransfer _permit2, uint256 _unsubscribeGasLimit)
constructor(
IPoolManager _poolManager,
IAllowanceTransfer _permit2,
uint256 _unsubscribeGasLimit,
IPositionDescriptor _tokenDescriptor
)
BaseActionsRouter(_poolManager)
Permit2Forwarder(_permit2)
ERC721Permit_v4("Uniswap V4 Positions NFT", "UNI-V4-POSM")
ERC721Permit_v4("Uniswap v4 Positions NFT", "UNI-V4-POSM")
Notifier(_unsubscribeGasLimit)
{}
{
tokenDescriptor = _tokenDescriptor;
}

/// @notice Reverts if the deadline has passed
/// @param deadline The timestamp at which the call is no longer valid, passed in by the caller
Expand All @@ -143,6 +153,10 @@ contract PositionManager is
_;
}

function tokenURI(uint256 tokenId) public view override returns (string memory) {
dianakocsis marked this conversation as resolved.
Show resolved Hide resolved
return IPositionDescriptor(tokenDescriptor).tokenURI(this, tokenId);
}

/// @inheritdoc IPositionManager
function modifyLiquidities(bytes calldata unlockData, uint256 deadline)
external
Expand Down
2 changes: 1 addition & 1 deletion src/V4Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {Actions} from "./libraries/Actions.sol";
import {ActionConstants} from "./libraries/ActionConstants.sol";

/// @title UniswapV4Router
/// @notice Abstract contract that contains all internal logic needed for routing through Uniswap V4 pools
/// @notice Abstract contract that contains all internal logic needed for routing through Uniswap v4 pools
/// @dev the entry point to executing actions in this contract is calling `BaseActionsRouter._executeActions`
/// An inheriting contract should call _executeActions at the point that they wish actions to be executed
abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
Expand Down
Loading
Loading