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 43 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_permit.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
79076
79064
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
24 changes: 24 additions & 0 deletions script/DeployPositionDescriptor.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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 {
dianakocsis marked this conversation as resolved.
Show resolved Hide resolved
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();
}
}
8 changes: 6 additions & 2 deletions script/DeployPosm.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@ 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";

contract DeployPosmTest is Script {
function setUp() public {}

function run(address poolManager, address permit2, uint256 unsubscribeGasLimit)
function run(address poolManager, address permit2, uint256 unsubscribeGasLimit, address positionDescriptor)
public
returns (PositionManager posm)
{
vm.startBroadcast();

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

Expand Down
132 changes: 132 additions & 0 deletions src/PositionDescriptor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// 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 {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.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 {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.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 {SafeERC20Namer} from "./libraries/SafeERC20Namer.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;

// 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 WETH9;
string public nativeCurrencyLabel;

IPoolManager public immutable poolManager;

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

/// @inheritdoc IPositionDescriptor
function tokenURI(IPositionManager positionManager, uint256 tokenId)
external
view
override
returns (string memory)
{
(PoolKey memory poolKey, PositionInfo positionInfo) = positionManager.getPoolAndPositionInfo(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: quoteCurrency.isAddressZero()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think id rather this logic was inside the namer. Like SafeCurrencyNamer and then in there check .isAddressZero() to abstract away from this contract

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so have the isAddressZero check inside of the namer? that's not directly related to name though. Plus, the isAddressZero check is also used for decimals

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I'm wondering if SafeERC20Namer should be called like SafeCurrencyMetadata or something?
and then it can include

  • logic for checking for isAddressZero and returning information for native
  • try-catching decimals (from other comment) and returning 0 if not

? nativeCurrencyLabel
: SafeERC20Namer.tokenSymbol(Currency.unwrap(quoteCurrency)),
baseCurrencySymbol: baseCurrency.isAddressZero()
? nativeCurrencyLabel
: SafeERC20Namer.tokenSymbol(Currency.unwrap(baseCurrency)),
quoteCurrencyDecimals: quoteCurrency.isAddressZero()
? 18
: IERC20Metadata(Currency.unwrap(quoteCurrency)).decimals(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is safe decimal fetching not needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure because for name we check to see if its returned in bytes and then convert it to string.
i guess we could do something similar for uint8?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how likely that decimals will be in bytes tho

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but what if the token doesnt have a decimals function? they dont have to. I think you have to default it to 0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you look at the spec the function is optional. So you can do a try-catch and default to 0 or something

baseCurrencyDecimals: baseCurrency.isAddressZero()
? 18
: IERC20Metadata(Currency.unwrap(baseCurrency)).decimals(),
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
/// @param currency1 The second currency
/// @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
/// @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
// weth is different address on different chains. passed in constructor

// native currency
if (currency == address(0)) {
return CurrencyRatioSortOrder.DENOMINATOR;
}
if (currency == WETH9) {
return CurrencyRatioSortOrder.DENOMINATOR_2;
}
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;
}
}
Loading
Loading