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 proxy tests #427

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions script/DeployPosm.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ contract DeployPosmTest is Script {
address permit2,
uint256 unsubscribeGasLimit,
address wrappedNative,
string memory nativeCurrencyLabel
bytes32 nativeCurrencyLabelBytes
) public returns (IPositionDescriptor positionDescriptor, IPositionManager posm) {
vm.startBroadcast();

positionDescriptor = Deploy.positionDescriptor(poolManager, wrappedNative, nativeCurrencyLabel, hex"00");
positionDescriptor = Deploy.positionDescriptor(poolManager, wrappedNative, nativeCurrencyLabelBytes, hex"00");
console2.log("PositionDescriptor", address(positionDescriptor));

posm = Deploy.positionManager(
Expand Down
4 changes: 2 additions & 2 deletions snapshots/PosMGasTest.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
"PositionManager_mint_withSettlePair": "420939",
"PositionManager_multicall_initialize_mint": "458237",
"PositionManager_permit": "79175",
"PositionManager_permit_secondPosition": "62063",
"PositionManager_permit_twice": "44975",
"PositionManager_permit_secondPosition": "62075",
"PositionManager_permit_twice": "44963",
"PositionManager_subscribe": "87968",
"PositionManager_unsubscribe": "62697",
"position manager initcode hash (without constructor params, as uint256)": "81827502601055975118808937107769364319765058198432540518516360048852193272922",
Expand Down
5 changes: 3 additions & 2 deletions snapshots/PositionDescriptorTest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"position descriptor initcode hash (without constructor params, as uint256)": "88482580191959945449130293370700011665153263709859488839371600440410373093991",
"positionDescriptor bytecode size": "24110"
"position descriptor initcode hash (without constructor params, as uint256)": "90002686278379416913385532438840669828848441637921711710845035729125835578244",
"positionDescriptor bytecode size": "24138",
"proxy bytecode size": "1488"
}
23 changes: 18 additions & 5 deletions src/PositionDescriptor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,27 @@ contract PositionDescriptor is IPositionDescriptor {
address private constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;

address public immutable wrappedNative;
string public nativeCurrencyLabel;
bytes32 public immutable nativeCurrencyLabelBytes;

IPoolManager public immutable poolManager;

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

/// @notice Returns the native currency label as a string
function nativeCurrencyLabel() public view returns (string memory) {
Copy link
Contributor

Choose a reason for hiding this comment

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

would love to see unit tests for this function

uint256 len = 0;
while (len < 32 && nativeCurrencyLabelBytes[len] != 0) {
len++;
}
bytes memory b = new bytes(len);
for (uint256 i = 0; i < len; i++) {
b[i] = nativeCurrencyLabelBytes[i];
}
return string(b);
}

/// @inheritdoc IPositionDescriptor
Expand Down Expand Up @@ -66,8 +79,8 @@ contract PositionDescriptor is IPositionDescriptor {
tokenId: tokenId,
quoteCurrency: quoteCurrency,
baseCurrency: baseCurrency,
quoteCurrencySymbol: SafeCurrencyMetadata.currencySymbol(quoteCurrency, nativeCurrencyLabel),
baseCurrencySymbol: SafeCurrencyMetadata.currencySymbol(baseCurrency, nativeCurrencyLabel),
quoteCurrencySymbol: SafeCurrencyMetadata.currencySymbol(quoteCurrency, nativeCurrencyLabel()),
baseCurrencySymbol: SafeCurrencyMetadata.currencySymbol(baseCurrency, nativeCurrencyLabel()),
quoteCurrencyDecimals: SafeCurrencyMetadata.currencyDecimals(quoteCurrency),
baseCurrencyDecimals: SafeCurrencyMetadata.currencyDecimals(baseCurrency),
flipRatio: _flipRatio,
Expand Down
3 changes: 3 additions & 0 deletions src/interfaces/IPositionDescriptor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ interface IPositionDescriptor {
/// @return The wrapped native token for this descriptor
function wrappedNative() external view returns (address);

/// @return The native currency label bytes for this descriptor
function nativeCurrencyLabelBytes() external view returns (bytes32);

/// @return The native currency label for this descriptor
function nativeCurrencyLabel() external view returns (string memory);

Expand Down
67 changes: 38 additions & 29 deletions test/PositionDescriptor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup {
address public TBTC = 0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa;
address public WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
string public nativeCurrencyLabel = "ETH";
bytes32 public nativeCurrencyLabelBytes = "ETH";

struct Token {
string description;
Expand All @@ -51,43 +52,51 @@ contract PositionDescriptorTest is Test, PosmTestSetup {
vm.snapshotValue("positionDescriptor bytecode size", address(positionDescriptor).code.length);
}

function test_bytecodeSize_proxy() public {
vm.snapshotValue("proxy bytecode size", address(proxyAsImplementation).code.length);
}

function test_setup_succeeds() public view {
assertEq(address(positionDescriptor.poolManager()), address(manager));
assertEq(positionDescriptor.wrappedNative(), WETH9);
assertEq(positionDescriptor.nativeCurrencyLabel(), nativeCurrencyLabel);
assertEq(address(proxyAsImplementation.poolManager()), address(manager));
assertEq(proxyAsImplementation.wrappedNative(), WETH9);
assertEq(proxyAsImplementation.nativeCurrencyLabelBytes(), nativeCurrencyLabelBytes);
}

function test_nativeCurrencyLabel_succeeds() public view {
assertEq(proxyAsImplementation.nativeCurrencyLabel(), nativeCurrencyLabel);
}

function test_currencyRatioPriority_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(proxyAsImplementation.currencyRatioPriority(WETH9), CurrencyRatioSortOrder.DENOMINATOR);
assertEq(proxyAsImplementation.currencyRatioPriority(address(0)), CurrencyRatioSortOrder.DENOMINATOR);
assertEq(proxyAsImplementation.currencyRatioPriority(USDC), CurrencyRatioSortOrder.NUMERATOR_MOST);
assertEq(proxyAsImplementation.currencyRatioPriority(USDT), CurrencyRatioSortOrder.NUMERATOR_MORE);
assertEq(proxyAsImplementation.currencyRatioPriority(DAI), CurrencyRatioSortOrder.NUMERATOR);
assertEq(proxyAsImplementation.currencyRatioPriority(TBTC), CurrencyRatioSortOrder.DENOMINATOR_MORE);
assertEq(proxyAsImplementation.currencyRatioPriority(WBTC), CurrencyRatioSortOrder.DENOMINATOR_MOST);
assertEq(proxyAsImplementation.currencyRatioPriority(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);
assertEq(proxyAsImplementation.currencyRatioPriority(WETH9), CurrencyRatioSortOrder.DENOMINATOR);
assertEq(proxyAsImplementation.currencyRatioPriority(address(0)), CurrencyRatioSortOrder.DENOMINATOR);
assertEq(proxyAsImplementation.currencyRatioPriority(USDC), 0);
assertEq(proxyAsImplementation.currencyRatioPriority(USDT), 0);
assertEq(proxyAsImplementation.currencyRatioPriority(DAI), 0);
assertEq(proxyAsImplementation.currencyRatioPriority(TBTC), 0);
assertEq(proxyAsImplementation.currencyRatioPriority(WBTC), 0);
assertEq(proxyAsImplementation.currencyRatioPriority(makeAddr("ALICE")), 0);
}

function test_flipRatio_succeeds() public {
vm.chainId(1);
// bc price = token1/token0
assertTrue(positionDescriptor.flipRatio(USDC, WETH9));
assertFalse(positionDescriptor.flipRatio(DAI, USDC));
assertFalse(positionDescriptor.flipRatio(WBTC, WETH9));
assertFalse(positionDescriptor.flipRatio(WBTC, USDC));
assertFalse(positionDescriptor.flipRatio(WBTC, DAI));
assertTrue(proxyAsImplementation.flipRatio(USDC, WETH9));
assertFalse(proxyAsImplementation.flipRatio(DAI, USDC));
assertFalse(proxyAsImplementation.flipRatio(WBTC, WETH9));
assertFalse(proxyAsImplementation.flipRatio(WBTC, USDC));
assertFalse(proxyAsImplementation.flipRatio(WBTC, DAI));
}

function test_tokenURI_succeeds() public {
Expand All @@ -112,7 +121,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup {
// The prefix length is calculated by converting the string to bytes and finding its length
uint256 prefixLength = bytes("data:application/json;base64,").length;

string memory uri = positionDescriptor.tokenURI(lpm, tokenId);
string memory uri = proxyAsImplementation.tokenURI(lpm, tokenId);
// Convert the uri to bytes
bytes memory uriBytes = bytes(uri);

Expand All @@ -133,7 +142,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup {
}

// quote is currency1, base is currency0
assertFalse(positionDescriptor.flipRatio(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1)));
assertFalse(proxyAsImplementation.flipRatio(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1)));

string memory symbol0 = SafeCurrencyMetadata.currencySymbol(Currency.unwrap(currency0), nativeCurrencyLabel);
string memory symbol1 = SafeCurrencyMetadata.currencySymbol(Currency.unwrap(currency1), nativeCurrencyLabel);
Expand Down Expand Up @@ -231,7 +240,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup {
// The prefix length is calculated by converting the string to bytes and finding its length
uint256 prefixLength = bytes("data:application/json;base64,").length;

string memory uri = positionDescriptor.tokenURI(lpm, tokenId);
string memory uri = proxyAsImplementation.tokenURI(lpm, tokenId);
// Convert the uri to bytes
bytes memory uriBytes = bytes(uri);

Expand All @@ -253,7 +262,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup {

// quote is currency1, base is currency0
assertFalse(
positionDescriptor.flipRatio(Currency.unwrap(nativeKey.currency0), Currency.unwrap(nativeKey.currency1))
proxyAsImplementation.flipRatio(Currency.unwrap(nativeKey.currency0), Currency.unwrap(nativeKey.currency1))
);

string memory symbol0 =
Expand Down Expand Up @@ -354,7 +363,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup {

vm.expectRevert(abi.encodeWithSelector(IPositionDescriptor.InvalidTokenId.selector, tokenId + 1));

positionDescriptor.tokenURI(lpm, tokenId + 1);
proxyAsImplementation.tokenURI(lpm, tokenId + 1);
}

// Helper functions for testing purposes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF

// Set the fee on transfer amount 1% higher.
(uint256 amount0, uint256 amount1) =
fotKey.currency0 == Currency.wrap(address(fotToken)) ? (100e18, 99e18) : (99e19, 100e18);
fotKey.currency0 == Currency.wrap(address(fotToken)) ? (100e18, 99e18) : (99e18, 100e18);

Plan memory planner = Planner.init();
planner.add(Actions.SETTLE, abi.encode(fotKey.currency0, amount0, true));
Expand All @@ -821,7 +821,7 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF
lpm.modifyLiquidities(actions, _deadline);

(uint256 amount0AfterTransfer, uint256 amount1AfterTransfer) =
fotKey.currency0 == Currency.wrap(address(fotToken)) ? (99e18, 100e18) : (100e18, 99e19);
fotKey.currency0 == Currency.wrap(address(fotToken)) ? (99e18, 100e18) : (100e18, 99e18);

uint128 newLiquidity = LiquidityAmounts.getLiquidityForAmounts(
SQRT_PRICE_1_1,
Expand Down Expand Up @@ -919,14 +919,14 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF
// bool currency0IsFOT = fotKey.currency0 == Currency.wrap(address(fotToken));
// bool positionIsEntirelyInOtherToken = currency0IsFOT
// ? tickUpper <= TickMath.getTickAtSqrtPrice(sqrtPriceX96)
// : tickLower > TickMath.getTickAtSqrtPrice(sqrtPriceX96);
// : tickLower >= TickMath.getTickAtSqrtPrice(sqrtPriceX96);
// if (bips == 10000 && !positionIsEntirelyInOtherToken) {
if (
bips == 10000
&& !(
fotKey.currency0 == Currency.wrap(address(fotToken))
? tickUpper <= TickMath.getTickAtSqrtPrice(sqrtPriceX96)
: tickLower > TickMath.getTickAtSqrtPrice(sqrtPriceX96)
: tickLower >= TickMath.getTickAtSqrtPrice(sqrtPriceX96)
)
) {
vm.expectRevert(Position.CannotUpdateEmptyPosition.selector);
Expand Down
17 changes: 15 additions & 2 deletions test/shared/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {IPositionDescriptor} from "../../src/interfaces/IPositionDescriptor.sol"
import {IPositionManager} from "../../src/interfaces/IPositionManager.sol";
import {IV4Quoter} from "../../src/interfaces/IV4Quoter.sol";
import {IStateView} from "../../src/interfaces/IStateView.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

library Deploy {
Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
Expand Down Expand Up @@ -41,13 +42,25 @@ library Deploy {
}
}

function transparentUpgradeableProxy(address implementation, address admin, bytes memory data, bytes memory salt)
internal
returns (TransparentUpgradeableProxy proxy)
{
bytes memory args = abi.encode(implementation, admin, data);
bytes memory initcode =
abi.encodePacked(vm.getCode("TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy"), args);
assembly {
proxy := create2(0, add(initcode, 0x20), mload(initcode), salt)
}
}

function positionDescriptor(
address poolManager,
address wrappedNative,
string memory nativeCurrencyLabel,
bytes32 nativeCurrencyLabelBytes,
bytes memory salt
) internal returns (IPositionDescriptor descriptor) {
bytes memory args = abi.encode(poolManager, wrappedNative, nativeCurrencyLabel);
bytes memory args = abi.encode(poolManager, wrappedNative, nativeCurrencyLabelBytes);
bytes memory initcode = abi.encodePacked(vm.getCode("PositionDescriptor.sol:PositionDescriptor"), args);
assembly {
descriptor := create2(0, add(initcode, 0x20), mload(initcode), salt)
Expand Down
8 changes: 7 additions & 1 deletion test/shared/PosmTestSetup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,20 @@ import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol";
import {SortTokens} from "@uniswap/v4-core/test/utils/SortTokens.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {PositionConfig} from "../shared/PositionConfig.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

/// @notice A shared test contract that wraps the v4-core deployers contract and exposes basic liquidity operations on posm.
contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations {
uint256 constant STARTING_USER_BALANCE = 10_000_000 ether;

IAllowanceTransfer permit2;
IPositionDescriptor public positionDescriptor;
TransparentUpgradeableProxy proxy;
IPositionDescriptor proxyAsImplementation;
HookSavesDelta hook;
address hookAddr = address(uint160(Hooks.AFTER_ADD_LIQUIDITY_FLAG | Hooks.AFTER_REMOVE_LIQUIDITY_FLAG));
IWETH9 public _WETH9 = IWETH9(address(new WETH()));
address governance = address(0xABCD);

HookModifyLiquidities hookModifyLiquidities;
address hookModifyLiquiditiesAddr = address(
Expand Down Expand Up @@ -69,9 +73,11 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations {
permit2 = IAllowanceTransfer(deployPermit2());
positionDescriptor =
Deploy.positionDescriptor(address(poolManager), 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, "ETH", hex"00");
proxy = Deploy.transparentUpgradeableProxy(address(positionDescriptor), governance, "", hex"03");
lpm = Deploy.positionManager(
address(poolManager), address(permit2), 100_000, address(positionDescriptor), address(_WETH9), hex"03"
address(poolManager), address(permit2), 100_000, address(proxy), address(_WETH9), hex"03"
);
proxyAsImplementation = IPositionDescriptor(address(proxy));
}

function seedBalance(address to) internal {
Expand Down
Loading