diff --git a/assets/logos/hyperliquid.svg b/assets/logos/hyperliquid.svg new file mode 100644 index 0000000..0b7b721 --- /dev/null +++ b/assets/logos/hyperliquid.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/abis/aerodrome_v3_pool.abi.json b/lib/abis/aerodrome_v3_pool.abi.json new file mode 100644 index 0000000..731bdaf --- /dev/null +++ b/lib/abis/aerodrome_v3_pool.abi.json @@ -0,0 +1,1309 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "name": "Collect", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "name": "CollectFees", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "paid0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "paid1", + "type": "uint256" + } + ], + "name": "Flash", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "observationCardinalityNextOld", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "observationCardinalityNextNew", + "type": "uint16" + } + ], + "name": "IncreaseObservationCardinalityNext", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "int24", + "name": "tick", + "type": "int24" + } + ], + "name": "Initialize", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "feeProtocol0Old", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "feeProtocol1Old", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "feeProtocol0New", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "feeProtocol1New", + "type": "uint8" + } + ], + "name": "SetFeeProtocol", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "int256", + "name": "amount0", + "type": "int256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "amount1", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "int24", + "name": "tick", + "type": "int24" + } + ], + "name": "Swap", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "burn", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + } + ], + "name": "burn", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount0Requested", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1Requested", + "type": "uint128" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "collect", + "outputs": [ + { + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount0Requested", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1Requested", + "type": "uint128" + } + ], + "name": "collect", + "outputs": [ + { + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "collectFees", + "outputs": [ + { + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "factoryRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fee", + "outputs": [ + { + "internalType": "uint24", + "name": "", + "type": "uint24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeGrowthGlobal0X128", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeGrowthGlobal1X128", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "flash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "gauge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gaugeFees", + "outputs": [ + { + "internalType": "uint128", + "name": "token0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "token1", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint256", + "name": "_rewardGrowthGlobalX128", + "type": "uint256" + } + ], + "name": "getRewardGrowthInside", + "outputs": [ + { + "internalType": "uint256", + "name": "rewardGrowthInside", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "observationCardinalityNext", + "type": "uint16" + } + ], + "name": "increaseObservationCardinalityNext", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }, + { + "internalType": "address", + "name": "_token0", + "type": "address" + }, + { + "internalType": "address", + "name": "_token1", + "type": "address" + }, + { + "internalType": "int24", + "name": "_tickSpacing", + "type": "int24" + }, + { + "internalType": "address", + "name": "_factoryRegistry", + "type": "address" + }, + { + "internalType": "uint160", + "name": "_sqrtPriceX96", + "type": "uint160" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastUpdated", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquidity", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLiquidityPerTick", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "nft", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "observations", + "outputs": [ + { + "internalType": "uint32", + "name": "blockTimestamp", + "type": "uint32" + }, + { + "internalType": "int56", + "name": "tickCumulative", + "type": "int56" + }, + { + "internalType": "uint160", + "name": "secondsPerLiquidityCumulativeX128", + "type": "uint160" + }, + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32[]", + "name": "secondsAgos", + "type": "uint32[]" + } + ], + "name": "observe", + "outputs": [ + { + "internalType": "int56[]", + "name": "tickCumulatives", + "type": "int56[]" + }, + { + "internalType": "uint160[]", + "name": "secondsPerLiquidityCumulativeX128s", + "type": "uint160[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "periodFinish", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "positions", + "outputs": [ + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "feeGrowthInside0LastX128", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "feeGrowthInside1LastX128", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "tokensOwed0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "tokensOwed1", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardGrowthGlobalX128", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardReserve", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollover", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gauge", + "type": "address" + }, + { + "internalType": "address", + "name": "_nft", + "type": "address" + } + ], + "name": "setGaugeAndPositionManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slot0", + "outputs": [ + { + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + }, + { + "internalType": "int24", + "name": "tick", + "type": "int24" + }, + { + "internalType": "uint16", + "name": "observationIndex", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "observationCardinality", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "observationCardinalityNext", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "unlocked", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + } + ], + "name": "snapshotCumulativesInside", + "outputs": [ + { + "internalType": "int56", + "name": "tickCumulativeInside", + "type": "int56" + }, + { + "internalType": "uint160", + "name": "secondsPerLiquidityInsideX128", + "type": "uint160" + }, + { + "internalType": "uint32", + "name": "secondsInside", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int128", + "name": "stakedLiquidityDelta", + "type": "int128" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "bool", + "name": "positionUpdate", + "type": "bool" + } + ], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stakedLiquidity", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "zeroForOne", + "type": "bool" + }, + { + "internalType": "int256", + "name": "amountSpecified", + "type": "int256" + }, + { + "internalType": "uint160", + "name": "sqrtPriceLimitX96", + "type": "uint160" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "int256", + "name": "amount0", + "type": "int256" + }, + { + "internalType": "int256", + "name": "amount1", + "type": "int256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rewardRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_rewardReserve", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_periodFinish", + "type": "uint256" + } + ], + "name": "syncReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int16", + "name": "", + "type": "int16" + } + ], + "name": "tickBitmap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tickSpacing", + "outputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "name": "ticks", + "outputs": [ + { + "internalType": "uint128", + "name": "liquidityGross", + "type": "uint128" + }, + { + "internalType": "int128", + "name": "liquidityNet", + "type": "int128" + }, + { + "internalType": "int128", + "name": "stakedLiquidityNet", + "type": "int128" + }, + { + "internalType": "uint256", + "name": "feeGrowthOutside0X128", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "feeGrowthOutside1X128", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardGrowthOutsideX128", + "type": "uint256" + }, + { + "internalType": "int56", + "name": "tickCumulativeOutside", + "type": "int56" + }, + { + "internalType": "uint160", + "name": "secondsPerLiquidityOutsideX128", + "type": "uint160" + }, + { + "internalType": "uint32", + "name": "secondsOutside", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token0", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token1", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unstakedFee", + "outputs": [ + { + "internalType": "uint24", + "name": "", + "type": "uint24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "updateRewardsGrowthGlobal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/lib/abis/aerodrome_v3_position_manager.abi.json b/lib/abis/aerodrome_v3_position_manager.abi.json new file mode 100644 index 0000000..ca21600 --- /dev/null +++ b/lib/abis/aerodrome_v3_position_manager.abi.json @@ -0,0 +1,1312 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }, + { + "internalType": "address", + "name": "_WETH9", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenDescriptor", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_fromTokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_toTokenId", + "type": "uint256" + } + ], + "name": "BatchMetadataUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Collect", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "DecreaseLiquidity", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "IncreaseLiquidity", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "MetadataUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "tokenDescriptor", + "type": "address" + } + ], + "name": "TokenDescriptorChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "TransferOwnership", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH9", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint128", + "name": "amount0Max", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1Max", + "type": "uint128" + } + ], + "internalType": "struct INonfungiblePositionManager.CollectParams", + "name": "params", + "type": "tuple" + } + ], + "name": "collect", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "amount0Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct INonfungiblePositionManager.DecreaseLiquidityParams", + "name": "params", + "type": "tuple" + } + ], + "name": "decreaseLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount0Desired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Desired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount0Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct INonfungiblePositionManager.IncreaseLiquidityParams", + "name": "params", + "type": "tuple" + } + ], + "name": "increaseLiquidity", + "outputs": [ + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint256", + "name": "amount0Desired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Desired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount0Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Min", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + } + ], + "internalType": "struct INonfungiblePositionManager.MintParams", + "name": "params", + "type": "tuple" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "positions", + "outputs": [ + { + "internalType": "uint96", + "name": "nonce", + "type": "uint96" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "feeGrowthInside0LastX128", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "feeGrowthInside1LastX128", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "tokensOwed0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "tokensOwed1", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "refundETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitAllowed", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitAllowedIfNecessary", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitIfNecessary", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenDescriptor", + "type": "address" + } + ], + "name": "setTokenDescriptor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountMinimum", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tokenDescriptor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount0Owed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Owed", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "uniswapV3MintCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountMinimum", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "unwrapWETH9", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] \ No newline at end of file diff --git a/lib/abis/algebra/v1.2.1/pool.abi.json b/lib/abis/algebra/v1.2.1/pool.abi.json new file mode 100644 index 0000000..db1e74c --- /dev/null +++ b/lib/abis/algebra/v1.2.1/pool.abi.json @@ -0,0 +1,1381 @@ +[ + { + "inputs": [], + "name": "alreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "arithmeticError", + "type": "error" + }, + { + "inputs": [], + "name": "bottomTickLowerThanMIN", + "type": "error" + }, + { + "inputs": [], + "name": "dynamicFeeActive", + "type": "error" + }, + { + "inputs": [], + "name": "dynamicFeeDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "flashInsufficientPaid0", + "type": "error" + }, + { + "inputs": [], + "name": "flashInsufficientPaid1", + "type": "error" + }, + { + "inputs": [], + "name": "incorrectPluginFee", + "type": "error" + }, + { + "inputs": [], + "name": "insufficientInputAmount", + "type": "error" + }, + { + "inputs": [], + "name": "invalidAmountRequired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "expectedSelector", + "type": "bytes4" + } + ], + "name": "invalidHookResponse", + "type": "error" + }, + { + "inputs": [], + "name": "invalidLimitSqrtPrice", + "type": "error" + }, + { + "inputs": [], + "name": "invalidNewCommunityFee", + "type": "error" + }, + { + "inputs": [], + "name": "invalidNewTickSpacing", + "type": "error" + }, + { + "inputs": [], + "name": "liquidityAdd", + "type": "error" + }, + { + "inputs": [], + "name": "liquidityOverflow", + "type": "error" + }, + { + "inputs": [], + "name": "liquiditySub", + "type": "error" + }, + { + "inputs": [], + "name": "locked", + "type": "error" + }, + { + "inputs": [], + "name": "notAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "notInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "pluginIsNotConnected", + "type": "error" + }, + { + "inputs": [], + "name": "priceOutOfRange", + "type": "error" + }, + { + "inputs": [], + "name": "tickInvalidLinks", + "type": "error" + }, + { + "inputs": [], + "name": "tickIsNotInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "tickIsNotSpaced", + "type": "error" + }, + { + "inputs": [], + "name": "tickOutOfRange", + "type": "error" + }, + { + "inputs": [], + "name": "topTickAboveMAX", + "type": "error" + }, + { + "inputs": [], + "name": "topTickLowerOrEqBottomTick", + "type": "error" + }, + { + "inputs": [], + "name": "transferFailed", + "type": "error" + }, + { + "inputs": [], + "name": "zeroAmountRequired", + "type": "error" + }, + { + "inputs": [], + "name": "zeroLiquidityActual", + "type": "error" + }, + { + "inputs": [], + "name": "zeroLiquidityDesired", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "bottomTick", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "topTick", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidityAmount", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint24", + "name": "pluginFee", + "type": "uint24" + } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "bottomTick", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "topTick", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "name": "Collect", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "communityFeeNew", + "type": "uint16" + } + ], + "name": "CommunityFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newCommunityVault", + "type": "address" + } + ], + "name": "CommunityVault", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "ExcessTokens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "fee", + "type": "uint16" + } + ], + "name": "Fee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "paid0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "paid1", + "type": "uint256" + } + ], + "name": "Flash", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint160", + "name": "price", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "int24", + "name": "tick", + "type": "int24" + } + ], + "name": "Initialize", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "int24", + "name": "bottomTick", + "type": "int24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "topTick", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidityAmount", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newPluginAddress", + "type": "address" + } + ], + "name": "Plugin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "newPluginConfig", + "type": "uint8" + } + ], + "name": "PluginConfig", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Skim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "int256", + "name": "amount0", + "type": "int256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "amount1", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "price", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "int24", + "name": "tick", + "type": "int24" + }, + { + "indexed": false, + "internalType": "uint24", + "name": "overrideFee", + "type": "uint24" + }, + { + "indexed": false, + "internalType": "uint24", + "name": "pluginFee", + "type": "uint24" + } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "int24", + "name": "newTickSpacing", + "type": "int24" + } + ], + "name": "TickSpacing", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "bottomTick", + "type": "int24" + }, + { + "internalType": "int24", + "name": "topTick", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "burn", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "int24", + "name": "bottomTick", + "type": "int24" + }, + { + "internalType": "int24", + "name": "topTick", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "amount0Requested", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1Requested", + "type": "uint128" + } + ], + "name": "collect", + "outputs": [ + { + "internalType": "uint128", + "name": "amount0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "communityVault", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fee", + "outputs": [ + { + "internalType": "uint16", + "name": "currentFee", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "flash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCommunityFeePending", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPluginFeePending", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getReserves", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "globalState", + "outputs": [ + { + "internalType": "uint160", + "name": "price", + "type": "uint160" + }, + { + "internalType": "int24", + "name": "tick", + "type": "int24" + }, + { + "internalType": "uint16", + "name": "lastFee", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "pluginConfig", + "type": "uint8" + }, + { + "internalType": "uint16", + "name": "communityFee", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "unlocked", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint160", + "name": "initialPrice", + "type": "uint160" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isUnlocked", + "outputs": [ + { + "internalType": "bool", + "name": "unlocked", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFeeTransferTimestamp", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquidity", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLiquidityPerTick", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "leftoversRecipient", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "int24", + "name": "bottomTick", + "type": "int24" + }, + { + "internalType": "int24", + "name": "topTick", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "liquidityDesired", + "type": "uint128" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "liquidityActual", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "nextTickGlobal", + "outputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "plugin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "positions", + "outputs": [ + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "innerFeeGrowth0Token", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "innerFeeGrowth1Token", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "fees0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "fees1", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prevTickGlobal", + "outputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "safelyGetStateOfAMM", + "outputs": [ + { + "internalType": "uint160", + "name": "sqrtPrice", + "type": "uint160" + }, + { + "internalType": "int24", + "name": "tick", + "type": "int24" + }, + { + "internalType": "uint16", + "name": "lastFee", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "pluginConfig", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "activeLiquidity", + "type": "uint128" + }, + { + "internalType": "int24", + "name": "nextTick", + "type": "int24" + }, + { + "internalType": "int24", + "name": "previousTick", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "newCommunityFee", + "type": "uint16" + } + ], + "name": "setCommunityFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newCommunityVault", + "type": "address" + } + ], + "name": "setCommunityVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "newFee", + "type": "uint16" + } + ], + "name": "setFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newPluginAddress", + "type": "address" + } + ], + "name": "setPlugin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "newConfig", + "type": "uint8" + } + ], + "name": "setPluginConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "newTickSpacing", + "type": "int24" + } + ], + "name": "setTickSpacing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "skim", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "zeroToOne", + "type": "bool" + }, + { + "internalType": "int256", + "name": "amountRequired", + "type": "int256" + }, + { + "internalType": "uint160", + "name": "limitSqrtPrice", + "type": "uint160" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "int256", + "name": "amount0", + "type": "int256" + }, + { + "internalType": "int256", + "name": "amount1", + "type": "int256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "leftoversRecipient", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "zeroToOne", + "type": "bool" + }, + { + "internalType": "int256", + "name": "amountToSell", + "type": "int256" + }, + { + "internalType": "uint160", + "name": "limitSqrtPrice", + "type": "uint160" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "swapWithPaymentInAdvance", + "outputs": [ + { + "internalType": "int256", + "name": "amount0", + "type": "int256" + }, + { + "internalType": "int256", + "name": "amount1", + "type": "int256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sync", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "tickSpacing", + "outputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int16", + "name": "", + "type": "int16" + } + ], + "name": "tickTable", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tickTreeRoot", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int16", + "name": "", + "type": "int16" + } + ], + "name": "tickTreeSecondLayer", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "name": "ticks", + "outputs": [ + { + "internalType": "uint256", + "name": "liquidityTotal", + "type": "uint256" + }, + { + "internalType": "int128", + "name": "liquidityDelta", + "type": "int128" + }, + { + "internalType": "int24", + "name": "prevTick", + "type": "int24" + }, + { + "internalType": "int24", + "name": "nextTick", + "type": "int24" + }, + { + "internalType": "uint256", + "name": "outerFeeGrowth0Token", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outerFeeGrowth1Token", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token0", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token1", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalFeeGrowth0Token", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalFeeGrowth1Token", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/lib/abis/algebra/v1.2.1/position_manager.abi.json b/lib/abis/algebra/v1.2.1/position_manager.abi.json new file mode 100644 index 0000000..b22ffc5 --- /dev/null +++ b/lib/abis/algebra/v1.2.1/position_manager.abi.json @@ -0,0 +1,1403 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }, + { + "internalType": "address", + "name": "_WNativeToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenDescriptor_", + "type": "address" + }, + { + "internalType": "address", + "name": "_poolDeployer", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "tickOutOfRange", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Collect", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "DecreaseLiquidity", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "FarmingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "liquidityDesired", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "actualLiquidity", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "IncreaseLiquidity", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NONFUNGIBLE_POSITION_MANAGER_ADMINISTRATOR_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WNativeToken", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount0Owed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Owed", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "algebraMintCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approve", + "type": "bool" + }, + { + "internalType": "address", + "name": "farmingAddress", + "type": "address" + } + ], + "name": "approveForFarming", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint128", + "name": "amount0Max", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amount1Max", + "type": "uint128" + } + ], + "internalType": "struct INonfungiblePositionManager.CollectParams", + "name": "params", + "type": "tuple" + } + ], + "name": "collect", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "internalType": "address", + "name": "deployer", + "type": "address" + }, + { + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "createAndInitializePoolIfNecessary", + "outputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "amount0Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct INonfungiblePositionManager.DecreaseLiquidityParams", + "name": "params", + "type": "tuple" + } + ], + "name": "decreaseLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "farmingApprovals", + "outputs": [ + { + "internalType": "address", + "name": "farmingCenterAddress", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "farmingCenter", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount0Desired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Desired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount0Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct INonfungiblePositionManager.IncreaseLiquidityParams", + "name": "params", + "type": "tuple" + } + ], + "name": "increaseLiquidity", + "outputs": [ + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "isApprovedOrOwner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "internalType": "address", + "name": "deployer", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint256", + "name": "amount0Desired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Desired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount0Min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Min", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct INonfungiblePositionManager.MintParams", + "name": "params", + "type": "tuple" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "poolDeployer", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "positions", + "outputs": [ + { + "internalType": "uint88", + "name": "nonce", + "type": "uint88" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "internalType": "address", + "name": "deployer", + "type": "address" + }, + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + }, + { + "internalType": "uint128", + "name": "liquidity", + "type": "uint128" + }, + { + "internalType": "uint256", + "name": "feeGrowthInside0LastX128", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "feeGrowthInside1LastX128", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "tokensOwed0", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "tokensOwed1", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "refundNativeToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitAllowed", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitAllowedIfNecessary", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitIfNecessary", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newFarmingCenter", + "type": "address" + } + ], + "name": "setFarmingCenter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountMinimum", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "toActive", + "type": "bool" + } + ], + "name": "switchFarmingStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenFarmedIn", + "outputs": [ + { + "internalType": "address", + "name": "farmingCenterAddress", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountMinimum", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "unwrapWNativeToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] \ No newline at end of file diff --git a/lib/abis/pancake_swap_infinity_cl_pool_manager.abi.json b/lib/abis/pancake_swap_infinity_cl_pool_manager.abi.json index 1117a3b..24da904 100644 --- a/lib/abis/pancake_swap_infinity_cl_pool_manager.abi.json +++ b/lib/abis/pancake_swap_infinity_cl_pool_manager.abi.json @@ -32,5 +32,49 @@ ], "stateMutability": "view", "type": "function" + }, + { + "inputs": [ + { + "internalType": "PoolId", + "name": "id", + "type": "bytes32" + } + ], + "name": "poolIdToPoolKey", + "outputs": [ + { + "internalType": "Currency", + "name": "currency0", + "type": "address" + }, + { + "internalType": "Currency", + "name": "currency1", + "type": "address" + }, + { + "internalType": "contract IHooks", + "name": "hooks", + "type": "address" + }, + { + "internalType": "contract IPoolManager", + "name": "poolManager", + "type": "address" + }, + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "internalType": "bytes32", + "name": "parameters", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" } ] \ No newline at end of file diff --git a/lib/abis/pancake_swap_infinity_cl_position_manager.abi.json b/lib/abis/pancake_swap_infinity_cl_position_manager.abi.json new file mode 100644 index 0000000..dbff6ad --- /dev/null +++ b/lib/abis/pancake_swap_infinity_cl_position_manager.abi.json @@ -0,0 +1,20 @@ +[ + { + "inputs": [ + { + "internalType": "bytes", + "name": "payload", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "modifyLiquidities", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] \ No newline at end of file diff --git a/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart b/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart index 6836217..1c96778 100644 --- a/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart +++ b/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart @@ -35,15 +35,15 @@ class PreviewDepositModalCubit extends Cubit with V3Po required UniswapPermit2 permit2, required GlobalKey navigatorKey, required ZupAnalytics zupAnalytics, - }) : _yield = currentYield, - _poolRepository = poolService, - _erc20 = erc20, - _wallet = wallet, - _latestPoolTick = initialPoolTick, - _navigatorKey = navigatorKey, - _zupAnalytics = zupAnalytics, - _permit2 = permit2, - super(const PreviewDepositModalState.loading()); + }) : _yield = currentYield, + _poolRepository = poolService, + _erc20 = erc20, + _wallet = wallet, + _latestPoolTick = initialPoolTick, + _navigatorKey = navigatorKey, + _zupAnalytics = zupAnalytics, + _permit2 = permit2, + super(const PreviewDepositModalState.loading()); final PoolService _poolRepository; final Erc20 _erc20; @@ -76,12 +76,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po await _getTokensAllowance(); - emit( - PreviewDepositModalState.initial( - token0Allowance: _token0Allowance, - token1Allowance: _token1Allowance, - ), - ); + emit(PreviewDepositModalState.initial(token0Allowance: _token0Allowance, token1Allowance: _token1Allowance)); } Future approveToken(TokenDto token, BigInt value) async { @@ -92,10 +87,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po await _maybeSwitchNetwork(); - final contract = _erc20.fromSigner( - contractAddress: tokenAddressInNetwork, - signer: _wallet.signer!, - ); + final contract = _erc20.fromSigner(contractAddress: tokenAddressInNetwork, signer: _wallet.signer!); final tx = await contract.approve(spender: spender, value: value); @@ -131,10 +123,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po if (tokenAddressInNetwork == EthereumConstants.zeroAddress) return; - final permit2Contract = _permit2.fromSigner( - contractAddress: _yield.permit2!, - signer: _wallet.signer!, - ); + final permit2Contract = _permit2.fromSigner(contractAddress: _yield.permit2!, signer: _wallet.signer!); final permit2CurrentAllowance = await permit2Contract.allowance( await _wallet.signer!.address, @@ -183,10 +172,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po ); } - return tickToClosestValidTick( - tick: convertPriceToTickLower(), - tickSpacing: _yield.tickSpacing, - ); + return tickToClosestValidTick(tick: convertPriceToTickLower(), tickSpacing: _yield.tickSpacing); } BigInt tickUpper() { @@ -202,10 +188,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po ); } - return tickToClosestValidTick( - tick: convertPriceToTickUpper(), - tickSpacing: _yield.tickSpacing, - ); + return tickToClosestValidTick(tick: convertPriceToTickUpper(), tickSpacing: _yield.tickSpacing); } final amount0Desired = token0Amount; @@ -268,10 +251,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po if (e is UserRejectedAction) { return emit( - PreviewDepositModalState.initial( - token0Allowance: _token0Allowance, - token1Allowance: _token1Allowance, - ), + PreviewDepositModalState.initial(token0Allowance: _token0Allowance, token1Allowance: _token1Allowance), ); } @@ -301,10 +281,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po rpcUrl: _yield.network.rpcUrl, ); - _token0Allowance = await token0contract.allowance( - owner: owner, - spender: spender, - ); + _token0Allowance = await token0contract.allowance(owner: owner, spender: spender); } if (!_yield.isToken1Native) { @@ -313,10 +290,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po rpcUrl: _yield.network.rpcUrl, ); - _token1Allowance = await token1contract.allowance( - owner: owner, - spender: spender, - ); + _token1Allowance = await token1contract.allowance(owner: owner, spender: spender); } } catch (e) { if (canThrow) rethrow; @@ -339,14 +313,13 @@ class PreviewDepositModalCubit extends Cubit with V3Po final stateAsWaitingTransaction = state as _WaitingTransaction; WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - ScaffoldMessenger.of(context).showSnackBar(() { - return switch (stateAsWaitingTransaction.type) { - WaitingTransactionType.deposit => ZupSnackBar( + ScaffoldMessenger.of(context).showSnackBar( + () { + return switch (stateAsWaitingTransaction.type) { + WaitingTransactionType.deposit => ZupSnackBar( context, - message: "${S.of(context).previewDepositModalCubitDepositingSnackBarMessage( - token0Symbol: _yield.token0.symbol, - token1Symbol: _yield.token1.symbol, - )} ", + message: + "${S.of(context).previewDepositModalCubitDepositingSnackBarMessage(token0Symbol: _yield.token0.symbol, token1Symbol: _yield.token1.symbol)} ", customIcon: const ZupCircularLoadingIndicator(size: 20), type: ZupSnackBarType.info, maxWidth: 500, @@ -356,20 +329,21 @@ class PreviewDepositModalCubit extends Cubit with V3Po onButtonTap: () => _yield.network.openTx(stateAsWaitingTransaction.txId), ), ), - WaitingTransactionType.approve => ZupSnackBar( + WaitingTransactionType.approve => ZupSnackBar( context, message: "${S.of(context).previewDepositModalCubitApprovingSnackBarMessage} ", type: ZupSnackBarType.info, maxWidth: 400, helperButton: ( title: S.of(context).previewDepositModalWaitingTransactionSnackBarHelperButtonTitle, - onButtonTap: () => _yield.network.openTx(stateAsWaitingTransaction.txId) + onButtonTap: () => _yield.network.openTx(stateAsWaitingTransaction.txId), ), customIcon: const ZupCircularLoadingIndicator(size: 20), snackDuration: const Duration(minutes: 10), - ) - }; - }.call()); + ), + }; + }.call(), + ); }); stream.listen((state) async { @@ -393,11 +367,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po (_) async => ScaffoldMessenger.of(context).hideCurrentSnackBar(), ); - DepositSuccessModal.show( - context, - depositedYield: _yield, - showAsBottomSheet: isMobileSize(context), - ); + DepositSuccessModal.show(context, depositedYield: _yield, showAsBottomSheet: isMobileSize(context)); }, orElse: () async { ScaffoldMessenger.of(context).hideCurrentSnackBar(); diff --git a/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card.dart b/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card.dart index 814fee2..76e5445 100644 --- a/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card.dart +++ b/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card.dart @@ -82,7 +82,7 @@ class _TokenAmountInputCardState extends State with Single return super.didUpdateWidget(oldWidget); } - if (widget.token != oldWidget.token) { + if (widget.token != oldWidget.token || widget.network != oldWidget.network) { WidgetsBinding.instance.addPostFrameCallback((_) { userBalanceCubit.updateTokenAndNetwork( widget.token.addresses[widget.network.chainId]!, diff --git a/lib/core/dtos/pool_search_settings_dto.dart b/lib/core/dtos/pool_search_settings_dto.dart index bfabbc6..6846618 100644 --- a/lib/core/dtos/pool_search_settings_dto.dart +++ b/lib/core/dtos/pool_search_settings_dto.dart @@ -5,7 +5,7 @@ part 'pool_search_settings_dto.g.dart'; @freezed sealed class PoolSearchSettingsDto with _$PoolSearchSettingsDto { - static const num defaultMinLiquidityUSD = 1000; + static const num defaultMinLiquidityUSD = 5000; @JsonSerializable(explicitToJson: true) factory PoolSearchSettingsDto({ @@ -22,7 +22,5 @@ sealed class PoolSearchSettingsDto with _$PoolSearchSettingsDto { factory PoolSearchSettingsDto.fromJson(Map json) => _$PoolSearchSettingsDtoFromJson(json); - factory PoolSearchSettingsDto.fixture() => PoolSearchSettingsDto( - minLiquidityUSD: 1200, - ); + factory PoolSearchSettingsDto.fixture() => PoolSearchSettingsDto(minLiquidityUSD: 1200); } diff --git a/lib/core/dtos/yield_dto.dart b/lib/core/dtos/yield_dto.dart index 6b149aa..62627bf 100644 --- a/lib/core/dtos/yield_dto.dart +++ b/lib/core/dtos/yield_dto.dart @@ -20,16 +20,18 @@ sealed class YieldDto with _$YieldDto { required String positionManagerAddress, required int tickSpacing, required ProtocolDto protocol, - required int feeTier, - required num yield24h, - required num yield7d, - required num yield30d, - required num yield90d, + required int initialFeeTier, + required int currentFeeTier, required int chainId, + @Default(0) num yield24h, + @Default(0) num yield7d, + @Default(0) num yield30d, + @Default(0) num yield90d, @Default(PoolType.unknown) @JsonKey(unknownEnumValue: PoolType.unknown) PoolType poolType, @Default("0") String latestTick, @Default(0) num totalValueLockedUSD, @Default(EthereumConstants.zeroAddress) @JsonKey(name: "hooksAddress") String v4Hooks, + @Default(EthereumConstants.zeroAddress) @JsonKey(name: "deployerAddress") String deployerAddress, @JsonKey(name: "poolManagerAddress") String? v4PoolManager, @JsonKey(name: "stateViewAddress") String? v4StateView, @JsonKey(name: "permit2Address") String? permit2, @@ -59,7 +61,8 @@ sealed class YieldDto with _$YieldDto { factory YieldDto.fromJson(Map json) => _$YieldDtoFromJson(json); factory YieldDto.fixture() => YieldDto( - feeTier: 0, + initialFeeTier: 0, + currentFeeTier: 0, yield24h: 32.2, yield30d: 32.2, yield90d: 32.2, diff --git a/lib/core/dtos/yields_dto.dart b/lib/core/dtos/yields_dto.dart index c77a8bd..6a2f2b6 100644 --- a/lib/core/dtos/yields_dto.dart +++ b/lib/core/dtos/yields_dto.dart @@ -86,7 +86,8 @@ sealed class YieldsDto with _$YieldsDto { yield30d: 765.61, yield90d: 2022.99, totalValueLockedUSD: 65434567890.21, - feeTier: 500, + initialFeeTier: 500, + currentFeeTier: 500, protocol: ProtocolDto( id: ProtocolId.pancakeSwapInfinityCL, rawId: ProtocolId.pancakeSwapInfinityCL.toRawJsonValue, diff --git a/lib/core/enums/networks.dart b/lib/core/enums/networks.dart index 428c45b..9ec707c 100644 --- a/lib/core/enums/networks.dart +++ b/lib/core/enums/networks.dart @@ -7,134 +7,139 @@ import 'package:zup_app/gen/assets.gen.dart'; enum AppNetworks { allNetworks, mainnet, - // base, + base, + hyperEvm, // bnb, unichain, scroll, sepolia; - static List get testnets => AppNetworks.values - .where( - (network) => !network.isAllNetworks && network.isTestnet, - ) - .toList(); + static List get testnets => + AppNetworks.values.where((network) => !network.isAllNetworks && network.isTestnet).toList(); - static List get mainnets => AppNetworks.values - .where( - (network) => network.isAllNetworks || !network.isTestnet, - ) - .toList(); + static List get mainnets => + AppNetworks.values.where((network) => network.isAllNetworks || !network.isTestnet).toList(); static AppNetworks? fromValue(String value) => AppNetworks.values.firstWhereOrNull((network) => network.name == value); - static AppNetworks? fromChainId(int chainId) => AppNetworks.values.firstWhereOrNull( - (network) { - if (network.isAllNetworks) return false; + static AppNetworks? fromChainId(int chainId) => AppNetworks.values.firstWhereOrNull((network) { + if (network.isAllNetworks) return false; - return int.parse(network.chainInfo.hexChainId) == chainId; - }, - ); + return int.parse(network.chainInfo.hexChainId) == chainId; + }); int get chainId => int.parse(chainInfo.hexChainId); bool get isAllNetworks => this == allNetworks; bool get isTestnet => switch (this) { - mainnet => false, - scroll => false, - sepolia => true, - allNetworks => false, - // base => false, - unichain => false, - // bnb => false - }; + mainnet => false, + scroll => false, + sepolia => true, + allNetworks => false, + base => false, + unichain => false, + hyperEvm => false, + // bnb => false + }; String get label => switch (this) { - sepolia => "Sepolia", - mainnet => "Ethereum", - scroll => "Scroll", - allNetworks => "All Networks", - // base => "Base", - unichain => "Unichain", - // bnb => "BNB Chain", - }; + sepolia => "Sepolia", + mainnet => "Ethereum", + scroll => "Scroll", + allNetworks => "All Networks", + base => "Base", + unichain => "Unichain", + hyperEvm => "HyperEVM", + // bnb => "BNB Chain", + }; Widget get icon => switch (this) { - sepolia => Assets.logos.ethereum.svg(), - mainnet => Assets.logos.ethereum.svg(), - scroll => Assets.logos.scroll.svg(), - // base => Assets.logos.base.svg(), - unichain => Assets.logos.unichain.svg(), - allNetworks => Assets.icons.all.svg(), - // bnb => Assets.logos.bnbChain.svg() - }; + sepolia => Assets.logos.ethereum.svg(), + mainnet => Assets.logos.ethereum.svg(), + scroll => Assets.logos.scroll.svg(), + base => Assets.logos.base.svg(), + unichain => Assets.logos.unichain.svg(), + allNetworks => Assets.icons.all.svg(), + hyperEvm => Assets.logos.hyperliquid.svg(), + // bnb => Assets.logos.bnbChain.svg() + }; ChainInfo get chainInfo => switch (this) { - allNetworks => throw UnimplementedError("allNetworks is not a valid network"), - sepolia => ChainInfo( - hexChainId: "0xaa36a7", - chainName: label, - blockExplorerUrls: const ["https://sepolia.etherscan.io"], - nativeCurrency: NativeCurrencies.eth.currencyInfo, - rpcUrls: [rpcUrl], - ), - mainnet => ChainInfo( - hexChainId: "0x1", - chainName: label, - blockExplorerUrls: const ["https://etherscan.io"], - nativeCurrency: NativeCurrencies.eth.currencyInfo, - rpcUrls: [rpcUrl], - ), - scroll => ChainInfo( - hexChainId: "0x82750", - chainName: label, - blockExplorerUrls: const ["https://scrollscan.com"], - nativeCurrency: NativeCurrencies.eth.currencyInfo, - rpcUrls: [rpcUrl], - ), - // base => ChainInfo( - // hexChainId: "0x2105", - // chainName: label, - // blockExplorerUrls: const ["https://basescan.org"], - // nativeCurrency: NativeCurrencies.eth.currencyInfo, - // rpcUrls: [rpcUrl], - // ), - unichain => ChainInfo( - hexChainId: "0x82", - chainName: label, - blockExplorerUrls: const ["https://uniscan.xyz"], - nativeCurrency: NativeCurrencies.eth.currencyInfo, - rpcUrls: [rpcUrl], - ), - // bnb => ChainInfo( - // hexChainId => "0x38", - // chainName => label, - // blockExplorerUrls => const ["https://bscscan.com"], - // nativeCurrency => NativeCurrencies.bnb.currencyInfo, - // rpcUrls => [rpcUrl], - // ), - }; + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), + sepolia => ChainInfo( + hexChainId: "0xaa36a7", + chainName: label, + blockExplorerUrls: const ["https://sepolia.etherscan.io"], + nativeCurrency: NativeCurrencies.eth.currencyInfo, + rpcUrls: [rpcUrl], + ), + mainnet => ChainInfo( + hexChainId: "0x1", + chainName: label, + blockExplorerUrls: const ["https://etherscan.io"], + nativeCurrency: NativeCurrencies.eth.currencyInfo, + rpcUrls: [rpcUrl], + ), + scroll => ChainInfo( + hexChainId: "0x82750", + chainName: label, + blockExplorerUrls: const ["https://scrollscan.com"], + nativeCurrency: NativeCurrencies.eth.currencyInfo, + rpcUrls: [rpcUrl], + ), + base => ChainInfo( + hexChainId: "0x2105", + chainName: label, + blockExplorerUrls: const ["https://basescan.org"], + nativeCurrency: NativeCurrencies.eth.currencyInfo, + rpcUrls: [rpcUrl], + ), + unichain => ChainInfo( + hexChainId: "0x82", + chainName: label, + blockExplorerUrls: const ["https://uniscan.xyz"], + nativeCurrency: NativeCurrencies.eth.currencyInfo, + rpcUrls: [rpcUrl], + ), + hyperEvm => ChainInfo( + hexChainId: "0x3e7", + chainName: label, + blockExplorerUrls: const ["https://hyperevmscan.io"], + nativeCurrency: NativeCurrencies.hype.currencyInfo, + rpcUrls: [rpcUrl], + ), + // bnb => ChainInfo( + // hexChainId => "0x38", + // chainName => label, + // blockExplorerUrls => const ["https://bscscan.com"], + // nativeCurrency => NativeCurrencies.bnb.currencyInfo, + // rpcUrls => [rpcUrl], + // ), + }; String get wrappedNativeTokenAddress => switch (this) { - allNetworks => throw UnimplementedError("allNetworks is not a valid network"), - sepolia => "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", - mainnet => "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - scroll => "0x5300000000000000000000000000000000000004", - // base => "0x4200000000000000000000000000000000000006", - unichain => "0x4200000000000000000000000000000000000006", - // bnb => "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", - }; + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), + sepolia => "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + mainnet => "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + scroll => "0x5300000000000000000000000000000000000004", + base => "0x4200000000000000000000000000000000000006", + unichain => "0x4200000000000000000000000000000000000006", + hyperEvm => "0x5555555555555555555555555555555555555555", + // bnb => "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + }; String get rpcUrl => switch (this) { - allNetworks => throw UnimplementedError("allNetworks is not a valid network"), - sepolia => "https://ethereum-sepolia-rpc.publicnode.com", - mainnet => "https://ethereum-rpc.publicnode.com", - scroll => "https://scroll-rpc.publicnode.com", - // base => "https://base-rpc.publicnode.com", - unichain => "https://unichain-rpc.publicnode.com", - // bnb => "https://bsc-rpc.publicnode.com" - }; + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), + sepolia => "https://ethereum-sepolia-rpc.publicnode.com", + mainnet => "https://ethereum-rpc.publicnode.com", + scroll => "https://scroll-rpc.publicnode.com", + base => "https://base-rpc.publicnode.com", + unichain => "https://unichain-rpc.publicnode.com", + hyperEvm => "https://rpc.hyperliquid.xyz/evm", + // bnb => "https://bsc-rpc.publicnode.com" + }; Future openTx(String txHash) async { final url = "${chainInfo.blockExplorerUrls?.first}/tx/$txHash"; diff --git a/lib/core/enums/protocol_id.dart b/lib/core/enums/protocol_id.dart index 529166a..0739bb8 100644 --- a/lib/core/enums/protocol_id.dart +++ b/lib/core/enums/protocol_id.dart @@ -4,11 +4,20 @@ part 'protocol_id.g.dart'; @JsonEnum(alwaysCreate: true) enum ProtocolId { - @JsonValue("pancake-v4-cl") + @JsonValue("pancakeswap-infinity-cl") pancakeSwapInfinityCL, + @JsonValue("aerodrome-v3") + aerodromeSlipstream, + @JsonValue("velodrome-v3") + velodromeSlipstream, + @JsonValue("gliquid-v3") + gliquidV3, unknown; bool get isPancakeSwapInfinityCL => this == ProtocolId.pancakeSwapInfinityCL; + bool get isAerodromeOrVelodromeSlipstream => + (this == ProtocolId.aerodromeSlipstream || this == ProtocolId.velodromeSlipstream); + bool get isGLiquidV3 => this == ProtocolId.gliquidV3; String get toRawJsonValue => _$ProtocolIdEnumMap[this]!; } diff --git a/lib/core/injections.dart b/lib/core/injections.dart index 1574f35..87d9b79 100644 --- a/lib/core/injections.dart +++ b/lib/core/injections.dart @@ -6,8 +6,13 @@ import 'package:get_it/get_it.dart'; import 'package:lottie/lottie.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:web3kit/web3kit.dart'; +import 'package:zup_app/abis/aerodrome_v3_pool.abi.g.dart'; +import 'package:zup_app/abis/aerodrome_v3_position_manager.abi.g.dart'; +import 'package:zup_app/abis/algebra/v1.2.1/pool.abi.g.dart' as algebra_1_2_1_pool; +import 'package:zup_app/abis/algebra/v1.2.1/position_manager.abi.g.dart' as algebra_1_2_1_position_manager; import 'package:zup_app/abis/erc_20.abi.g.dart'; import 'package:zup_app/abis/pancake_swap_infinity_cl_pool_manager.abi.g.dart'; +import 'package:zup_app/abis/pancake_swap_infinity_cl_position_manager.abi.g.dart'; import 'package:zup_app/abis/uniswap_permit2.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart'; @@ -126,6 +131,18 @@ Future setupInjections() async { inject.registerLazySingleton(() => PancakeSwapInfinityClPoolManager()); + inject.registerLazySingleton(() => AerodromeV3PositionManager()); + + inject.registerLazySingleton(() => AerodromeV3Pool()); + + inject.registerLazySingleton(() => algebra_1_2_1_pool.Pool()); + + inject.registerLazySingleton( + () => algebra_1_2_1_position_manager.PositionManager(), + ); + + inject.registerLazySingleton(() => PancakeSwapInfinityClPositionManager()); + inject.registerLazySingleton( () => PoolService( inject(), @@ -134,6 +151,11 @@ Future setupInjections() async { inject(), inject(), inject(), + inject(), + inject(), + inject(), + inject(), + inject(), ), ); diff --git a/lib/core/pool_service.dart b/lib/core/pool_service.dart index 02a0d76..0c78fa8 100644 --- a/lib/core/pool_service.dart +++ b/lib/core/pool_service.dart @@ -1,7 +1,12 @@ import 'package:clock/clock.dart'; import 'package:web3kit/core/dtos/transaction_response.dart'; import 'package:web3kit/web3kit.dart'; +import 'package:zup_app/abis/aerodrome_v3_pool.abi.g.dart'; +import 'package:zup_app/abis/aerodrome_v3_position_manager.abi.g.dart'; +import 'package:zup_app/abis/algebra/v1.2.1/pool.abi.g.dart' as algebra_1_2_1_pool; +import 'package:zup_app/abis/algebra/v1.2.1/position_manager.abi.g.dart' as algebra_1_2_1_position_manager; import 'package:zup_app/abis/pancake_swap_infinity_cl_pool_manager.abi.g.dart'; +import 'package:zup_app/abis/pancake_swap_infinity_cl_position_manager.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart'; import 'package:zup_app/abis/uniswap_v4_position_manager.abi.g.dart'; @@ -17,6 +22,11 @@ class PoolService with V4PoolLiquidityCalculationsMixin { final UniswapV4PositionManager _uniswapV4PositionManager; final EthereumAbiCoder _ethereumAbiCoder; final PancakeSwapInfinityClPoolManager _pancakeSwapInfinityClPoolManager; + final PancakeSwapInfinityClPositionManager _pancakeSwapInfinityClPositionManager; + final AerodromeV3PositionManager _aerodromeV3PositionManager; + final AerodromeV3Pool _aerodromeV3Pool; + final algebra_1_2_1_pool.Pool _algebra121Pool; + final algebra_1_2_1_position_manager.PositionManager _algebra121PositionManager; PoolService( this._uniswapV4StateView, @@ -25,9 +35,23 @@ class PoolService with V4PoolLiquidityCalculationsMixin { this._uniswapV4PositionManager, this._ethereumAbiCoder, this._pancakeSwapInfinityClPoolManager, + this._pancakeSwapInfinityClPositionManager, + this._aerodromeV3PositionManager, + this._aerodromeV3Pool, + this._algebra121Pool, + this._algebra121PositionManager, ); Future getPoolTick(YieldDto forYield) async { + if (forYield.protocol.id.isGLiquidV3) { + final algebraPool = _algebra121Pool.fromRpcProvider( + contractAddress: forYield.poolAddress, + rpcUrl: forYield.network.rpcUrl, + ); + + return (await algebraPool.globalState()).tick; + } + if (forYield.protocol.id.isPancakeSwapInfinityCL) { final pancakeSwapInfinityCLPoolManagerContract = _pancakeSwapInfinityClPoolManager.fromRpcProvider( contractAddress: forYield.v4PoolManager!, @@ -37,6 +61,15 @@ class PoolService with V4PoolLiquidityCalculationsMixin { return (await pancakeSwapInfinityCLPoolManagerContract.getSlot0(id: forYield.poolAddress)).tick; } + if (forYield.protocol.id.isAerodromeOrVelodromeSlipstream) { + final aerodromeV3Pool = _aerodromeV3Pool.fromRpcProvider( + contractAddress: forYield.poolAddress, + rpcUrl: forYield.network.rpcUrl, + ); + + return (await aerodromeV3Pool.slot0()).tick; + } + if (forYield.poolType.isV4) { final stateView = _uniswapV4StateView.fromRpcProvider( contractAddress: forYield.v4StateView!, @@ -64,6 +97,24 @@ class PoolService with V4PoolLiquidityCalculationsMixin { return (await pancakeSwapInfinityCLPoolManagerContract.getSlot0(id: forYield.poolAddress)).sqrtPriceX96; } + if (forYield.protocol.id.isGLiquidV3) { + final algebraPool = _algebra121Pool.fromRpcProvider( + contractAddress: forYield.poolAddress, + rpcUrl: forYield.network.rpcUrl, + ); + + return (await algebraPool.globalState()).price; + } + + if (forYield.protocol.id.isAerodromeOrVelodromeSlipstream) { + final aerodromeV3Pool = _aerodromeV3Pool.fromRpcProvider( + contractAddress: forYield.poolAddress, + rpcUrl: forYield.network.rpcUrl, + ); + + return (await aerodromeV3Pool.slot0()).sqrtPriceX96; + } + if (forYield.poolType.isV4) { final stateView = _uniswapV4StateView.fromRpcProvider( contractAddress: forYield.v4StateView!, @@ -97,6 +148,36 @@ class PoolService with V4PoolLiquidityCalculationsMixin { required BigInt tickLower, required BigInt tickUpper, }) async { + if (depositOnYield.protocol.id.isAerodromeOrVelodromeSlipstream) { + return _sendV3DepositTransactionForSlipstream( + depositOnYield, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + } + + if (depositOnYield.protocol.id.isGLiquidV3) { + return _sendV3DepositTransactionForAlgebra121( + depositOnYield, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + } + final v3PositionManagerContract = _uniswapV3PositionManager.fromSigner( contractAddress: depositOnYield.positionManagerAddress, signer: signer, @@ -114,28 +195,22 @@ class PoolService with V4PoolLiquidityCalculationsMixin { recipient: recipient, tickLower: tickLower, tickUpper: tickUpper, - fee: BigInt.from(depositOnYield.feeTier), - token0: depositOnYield.token0.addresses[depositOnYield.network.chainId]! == EthereumConstants.zeroAddress - ? depositOnYield.network.wrappedNativeTokenAddress - : depositOnYield.token0.addresses[depositOnYield.network.chainId]!, - token1: depositOnYield.token1.addresses[depositOnYield.network.chainId]! == EthereumConstants.zeroAddress - ? depositOnYield.network.wrappedNativeTokenAddress - : depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + fee: BigInt.from(depositOnYield.initialFeeTier), + token0: _getNativeV3PoolToken0Address(depositOnYield), + token1: _getNativeV3PoolToken1Address(depositOnYield), ), ); return await v3PositionManagerContract.multicall( - data: [ - mintCalldata, - _uniswapV3PositionManager.getRefundETHCalldata(), - ], - ethValue: () { - if (depositOnYield.isToken0Native) { - return amount0Desired; - } - - return amount1Desired; - }.call()); + data: [mintCalldata, _uniswapV3PositionManager.getRefundETHCalldata()], + ethValue: () { + if (depositOnYield.isToken0Native) { + return amount0Desired; + } + + return amount1Desired; + }.call(), + ); } return await v3PositionManagerContract.mint( @@ -148,7 +223,7 @@ class PoolService with V4PoolLiquidityCalculationsMixin { recipient: recipient, tickLower: tickLower, tickUpper: tickUpper, - fee: BigInt.from(depositOnYield.feeTier), + fee: BigInt.from(depositOnYield.initialFeeTier), token0: depositOnYield.token0.addresses[depositOnYield.network.chainId]!, token1: depositOnYield.token1.addresses[depositOnYield.network.chainId]!, ), @@ -170,6 +245,21 @@ class PoolService with V4PoolLiquidityCalculationsMixin { required BigInt maxAmount1ToDeposit, required String recipient, }) async { + if (depositOnYield.protocol.id.isPancakeSwapInfinityCL) { + return _sendV4PoolDepositTransactionForPancakeSwap( + depositOnYield, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0toDeposit, + amount1ToDeposit: amount1ToDeposit, + maxAmount0ToDeposit: maxAmount0ToDeposit, + maxAmount1ToDeposit: maxAmount1ToDeposit, + recipient: recipient, + ); + } + final isNativeDeposit = depositOnYield.isToken0Native || depositOnYield.isToken1Native; final sqrtPriceX96 = await getSqrtPriceX96(depositOnYield); final sqrtPriceAX96 = getSqrtPriceAtTick(tickLower); @@ -182,58 +272,54 @@ class PoolService with V4PoolLiquidityCalculationsMixin { amount1ToDeposit, ); - final actions = _ethereumAbiCoder.encodePacked([ - "uint8", - "uint8", - if (isNativeDeposit) "uint8", - ], [ - V4PoolConstants.mintPositionActionValue, - V4PoolConstants.settlePairActionValue, - if (isNativeDeposit) V4PoolConstants.sweepActionValue, - ]); - - final mintPositionActionParams = _ethereumAbiCoder.encode([ - "tuple(address,address,int32,int24,address)", - "int24", - "int24", - "uint256", - "uint128", - "uint128", - "address", - "bytes" - ], [ + final actions = _ethereumAbiCoder.encodePacked( + ["uint8", "uint8", if (isNativeDeposit) "uint8"], + [ + V4PoolConstants.mintPositionActionValue, + V4PoolConstants.uniswapSettlePairActionValue, + if (isNativeDeposit) V4PoolConstants.uniswapSweepActionValue, + ], + ); + + final mintPositionActionParams = _ethereumAbiCoder.encode( + [ + "tuple(address,address,int32,int24,address)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], + [ + [ + depositOnYield.token0.addresses[depositOnYield.network.chainId]!, + depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + BigInt.from(depositOnYield.initialFeeTier), + BigInt.from(depositOnYield.tickSpacing), + depositOnYield.v4Hooks, + ], + tickLower, + tickUpper, + liquidity, + depositOnYield.isToken0Native ? amount0toDeposit : maxAmount0ToDeposit, + depositOnYield.isToken1Native ? amount1ToDeposit : maxAmount1ToDeposit, + recipient, + EthereumConstants.emptyBytes, + ], + ); + + final settlePairActionParams = _ethereumAbiCoder.encode( + ["address", "address"], [ depositOnYield.token0.addresses[depositOnYield.network.chainId]!, depositOnYield.token1.addresses[depositOnYield.network.chainId]!, - BigInt.from(depositOnYield.feeTier), - BigInt.from(depositOnYield.tickSpacing), - depositOnYield.v4Hooks, ], - tickLower, - tickUpper, - liquidity, - depositOnYield.isToken0Native ? amount0toDeposit : maxAmount0ToDeposit, - depositOnYield.isToken1Native ? amount1ToDeposit : maxAmount1ToDeposit, - recipient, - EthereumConstants.emptyBytes, - ]); - - final settlePairActionParams = _ethereumAbiCoder.encode([ - "address", - "address" - ], [ - depositOnYield.token0.addresses[depositOnYield.network.chainId]!, - depositOnYield.token1.addresses[depositOnYield.network.chainId]!, - ]); + ); final sweepActionParams = isNativeDeposit - ? _ethereumAbiCoder.encode([ - "address", - "address" - ], [ - EthereumConstants.zeroAddress, - recipient, - ]) + ? _ethereumAbiCoder.encode(["address", "address"], [EthereumConstants.zeroAddress, recipient]) : null; final uniswapV4PositionManagerContract = _uniswapV4PositionManager.fromSigner( @@ -241,19 +327,9 @@ class PoolService with V4PoolLiquidityCalculationsMixin { signer: signer, ); - final params = [ - mintPositionActionParams, - settlePairActionParams, - if (isNativeDeposit) sweepActionParams, - ]; + final params = [mintPositionActionParams, settlePairActionParams, if (isNativeDeposit) sweepActionParams]; - final unlockData = _ethereumAbiCoder.encode([ - "bytes", - "bytes[]" - ], [ - actions, - params, - ]); + final unlockData = _ethereumAbiCoder.encode(["bytes", "bytes[]"], [actions, params]); return await uniswapV4PositionManagerContract.modifyLiquidities( deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), @@ -266,4 +342,246 @@ class PoolService with V4PoolLiquidityCalculationsMixin { }.call(), ); } + + Future _sendV4PoolDepositTransactionForPancakeSwap( + YieldDto depositOnYield, + Signer signer, { + required Duration deadline, + required BigInt tickLower, + required BigInt tickUpper, + required BigInt amount0toDeposit, + required BigInt amount1ToDeposit, + required BigInt maxAmount0ToDeposit, + required BigInt maxAmount1ToDeposit, + required String recipient, + }) async { + final isNativeDeposit = depositOnYield.isToken0Native || depositOnYield.isToken1Native; + final sqrtPriceX96 = await getSqrtPriceX96(depositOnYield); + final sqrtPriceAX96 = getSqrtPriceAtTick(tickLower); + final sqrtPriceBX96 = getSqrtPriceAtTick(tickUpper); + final liquidity = getLiquidityForAmounts( + sqrtPriceX96, + sqrtPriceAX96, + sqrtPriceBX96, + amount0toDeposit, + amount1ToDeposit, + ); + + final actions = _ethereumAbiCoder.encodePacked( + ["uint8", "uint8", "uint8"], + [ + V4PoolConstants.mintPositionActionValue, + V4PoolConstants.pancakeSwapCloseCurrencyActionValue, + V4PoolConstants.pancakeSwapCloseCurrencyActionValue, + ], + ); + + final mintPositionActionParams = _ethereumAbiCoder.encode( + [ + "tuple(address,address,address,address,uint24,bytes32)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], + [ + [ + depositOnYield.token0.addresses[depositOnYield.network.chainId]!, + depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + depositOnYield.v4Hooks, + depositOnYield.v4PoolManager, + depositOnYield.initialFeeTier, + await _getPancakeSwapInfinityPoolBytesParameters(depositOnYield), + ], + tickLower, + tickUpper, + liquidity, + depositOnYield.isToken0Native ? amount0toDeposit : maxAmount0ToDeposit, + depositOnYield.isToken1Native ? amount1ToDeposit : maxAmount1ToDeposit, + recipient, + EthereumConstants.emptyBytes, + ], + ); + + final closeCurrency0ActionParams = _ethereumAbiCoder.encode( + ["address"], + [depositOnYield.token0.addresses[depositOnYield.network.chainId]!], + ); + + final closeCurrency1ActionParams = _ethereumAbiCoder.encode( + ["address"], + [depositOnYield.token1.addresses[depositOnYield.network.chainId]!], + ); + + final pancakeSwapV4PositionManagerContract = _pancakeSwapInfinityClPositionManager.fromSigner( + contractAddress: depositOnYield.positionManagerAddress, + signer: signer, + ); + + final params = [mintPositionActionParams, closeCurrency0ActionParams, closeCurrency1ActionParams]; + final payloadData = _ethereumAbiCoder.encode(["bytes", "bytes[]"], [actions, params]); + + return await pancakeSwapV4PositionManagerContract.modifyLiquidities( + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + payload: payloadData, + ethValue: () { + if (!isNativeDeposit) return null; + if (depositOnYield.isToken0Native) return amount0toDeposit; + + return amount1ToDeposit; + }.call(), + ); + } + + Future _sendV3DepositTransactionForAlgebra121( + YieldDto depositOnYield, + Signer signer, { + required BigInt amount0Desired, + required BigInt amount1Desired, + required Duration deadline, + required BigInt amount0Min, + required BigInt amount1Min, + required String recipient, + required BigInt tickLower, + required BigInt tickUpper, + }) async { + final positionManagerContract = _algebra121PositionManager.fromSigner( + contractAddress: depositOnYield.positionManagerAddress, + signer: signer, + ); + final TransactionResponse tx = await () async { + if (depositOnYield.isToken1Native || depositOnYield.isToken0Native) { + final mintCalldata = _algebra121PositionManager.getMintCalldata( + params: ( + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + deployer: depositOnYield.deployerAddress, + token0: _getNativeV3PoolToken0Address(depositOnYield), + token1: _getNativeV3PoolToken1Address(depositOnYield), + ), + ); + + return await positionManagerContract.multicall( + data: [mintCalldata, _algebra121PositionManager.getRefundNativeTokenCalldata()], + ethValue: () { + if (depositOnYield.isToken0Native) return amount0Desired; + + return amount1Desired; + }.call(), + ); + } + + return await positionManagerContract.mint( + params: ( + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + deployer: depositOnYield.deployerAddress, + token0: depositOnYield.token0.addresses[depositOnYield.network.chainId]!, + token1: depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + ), + ); + }.call(); + + return tx; + } + + Future _sendV3DepositTransactionForSlipstream( + YieldDto depositOnYield, + Signer signer, { + required BigInt amount0Desired, + required BigInt amount1Desired, + required Duration deadline, + required BigInt amount0Min, + required BigInt amount1Min, + required String recipient, + required BigInt tickLower, + required BigInt tickUpper, + }) async { + final aerodromeV3PositionManager = _aerodromeV3PositionManager.fromSigner( + contractAddress: depositOnYield.positionManagerAddress, + signer: signer, + ); + + final TransactionResponse tx = await () async { + if (depositOnYield.isToken1Native || depositOnYield.isToken0Native) { + final mintCalldata = _aerodromeV3PositionManager.getMintCalldata( + params: ( + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + tickSpacing: BigInt.from(depositOnYield.tickSpacing), + sqrtPriceX96: BigInt.from(0), + token0: _getNativeV3PoolToken0Address(depositOnYield), + token1: _getNativeV3PoolToken1Address(depositOnYield), + ), + ); + + return await aerodromeV3PositionManager.multicall( + data: [mintCalldata, _aerodromeV3PositionManager.getRefundETHCalldata()], + ethValue: () { + if (depositOnYield.isToken0Native) return amount0Desired; + return amount1Desired; + }.call(), + ); + } + + return await aerodromeV3PositionManager.mint( + params: ( + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + tickSpacing: BigInt.from(depositOnYield.tickSpacing), + sqrtPriceX96: BigInt.from(0), + token0: depositOnYield.token0.addresses[depositOnYield.network.chainId]!, + token1: depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + ), + ); + }.call(); + + return tx; + } + + String _getNativeV3PoolToken0Address(YieldDto forYield) { + if (forYield.isToken0Native) return forYield.network.wrappedNativeTokenAddress; + return forYield.token0.addresses[forYield.network.chainId]!; + } + + String _getNativeV3PoolToken1Address(YieldDto forYield) { + if (forYield.isToken1Native) return forYield.network.wrappedNativeTokenAddress; + return forYield.token1.addresses[forYield.network.chainId]!; + } + + Future _getPancakeSwapInfinityPoolBytesParameters(YieldDto forYield) async { + final contract = _pancakeSwapInfinityClPoolManager.fromRpcProvider( + contractAddress: forYield.v4PoolManager!, + rpcUrl: forYield.network.rpcUrl, + ); + + return (await contract.poolIdToPoolKey(id: forYield.poolAddress)).parameters; + } } diff --git a/lib/core/v4_pool_constants.dart b/lib/core/v4_pool_constants.dart index 75ad585..22b3285 100644 --- a/lib/core/v4_pool_constants.dart +++ b/lib/core/v4_pool_constants.dart @@ -1,5 +1,6 @@ abstract class V4PoolConstants { static const mintPositionActionValue = 0x02; - static const settlePairActionValue = 0x0d; - static const sweepActionValue = 0x14; + static const uniswapSettlePairActionValue = 0x0d; + static const uniswapSweepActionValue = 0x14; + static const pancakeSwapCloseCurrencyActionValue = 0x12; } diff --git a/lib/l10n/en.arb b/lib/l10n/en.arb index 21fac94..645db5e 100644 --- a/lib/l10n/en.arb +++ b/lib/l10n/en.arb @@ -166,7 +166,7 @@ } } }, - "yieldCardAverageYieldYearly": "Average Yield (Yearly)", + "yieldCardAverageYieldYearly": "Average Yearly Yield", "previewDepositModalDepositSuccessSnackBarHelperButtonTitle": "View Transaction", "previewDepositModalApproveSuccessSnackBarHelperButtonTitle": "View Transaction", "previewDepositModalWaitingTransactionSnackBarHelperButtonTitle": "View on Explorer", diff --git a/lib/l10n/gen/app_localizations.dart b/lib/l10n/gen/app_localizations.dart index cba7dfa..70efcef 100644 --- a/lib/l10n/gen/app_localizations.dart +++ b/lib/l10n/gen/app_localizations.dart @@ -463,7 +463,7 @@ abstract class S { /// No description provided for @yieldCardAverageYieldYearly. /// /// In en, this message translates to: - /// **'Average Yield (Yearly)'** + /// **'Average Yearly Yield'** String get yieldCardAverageYieldYearly; /// No description provided for @previewDepositModalDepositSuccessSnackBarHelperButtonTitle. diff --git a/lib/l10n/gen/app_localizations_en.dart b/lib/l10n/gen/app_localizations_en.dart index b21bec5..12e0b97 100644 --- a/lib/l10n/gen/app_localizations_en.dart +++ b/lib/l10n/gen/app_localizations_en.dart @@ -237,7 +237,7 @@ class SEn extends S { } @override - String get yieldCardAverageYieldYearly => 'Average Yield (Yearly)'; + String get yieldCardAverageYieldYearly => 'Average Yearly Yield'; @override String get previewDepositModalDepositSuccessSnackBarHelperButtonTitle => diff --git a/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart b/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart index 2f21409..91fa325 100644 --- a/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart +++ b/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart @@ -13,15 +13,16 @@ part 'token_selector_modal_state.dart'; class TokenSelectorModalCubit extends Cubit { TokenSelectorModalCubit(this._tokensRepository, this._appCubit, this._wallet) - : super(const TokenSelectorModalState.initial()); + : super(const TokenSelectorModalState.initial()); final TokensRepository _tokensRepository; final AppCubit _appCubit; final Wallet _wallet; final Map> _tokenListCachedPerNetworkByAddress = {}; - Future get tokenList async => _tokenListCachedPerNetworkByAddress[_appCubit.selectedNetwork] - ?[await _wallet.signer?.address ?? EthereumConstants.zeroAddress]; + Future get tokenList async => + _tokenListCachedPerNetworkByAddress[_appCubit.selectedNetwork]?[await _wallet.signer?.address ?? + EthereumConstants.zeroAddress]; Future _emitSuccessCached() async => emit(TokenSelectorModalState.success((await tokenList)!)); bool get _shouldDiscardSearchState => state != const TokenSelectorModalState.searchLoading(); @@ -41,8 +42,8 @@ class TokenSelectorModalCubit extends Cubit { try { emit(const TokenSelectorModalState.loading()); - _tokenListCachedPerNetworkByAddress[_appCubit.selectedNetwork]![userAddress] = - await _tokensRepository.getTokenList(_appCubit.selectedNetwork); + _tokenListCachedPerNetworkByAddress[_appCubit.selectedNetwork]![userAddress] = await _tokensRepository + .getTokenList(_appCubit.selectedNetwork); if (_shouldDiscardTokenListLoadedState) return; diff --git a/lib/widgets/yield_card.dart b/lib/widgets/yield_card.dart index 8bf4742..5d33386 100644 --- a/lib/widgets/yield_card.dart +++ b/lib/widgets/yield_card.dart @@ -88,7 +88,9 @@ class _YieldCardState extends State { Padding( padding: const EdgeInsets.only(top: 10), child: Text( - S.of(context).yieldCardYearlyYield, + widget.timeFrame.isDay + ? S.of(context).yieldCardYearlyYield + : S.of(context).yieldCardAverageYieldYearly, style: TextStyle(fontSize: 14, color: ZupThemeColors.primaryText.themed(context.brightness)), ), ), diff --git a/lib/widgets/zup_cached_image.dart b/lib/widgets/zup_cached_image.dart index cb02398..d135b8f 100644 --- a/lib/widgets/zup_cached_image.dart +++ b/lib/widgets/zup_cached_image.dart @@ -39,7 +39,12 @@ class ZupCachedImage { fit: BoxFit.cover, errorBuilder: errorWidget, frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { - if (frame == null) return placeholder ?? ZupCircularLoadingIndicator(size: height ?? 20); + if (frame == null) { + return Container( + color: ZupThemeColors.background.themed(context.brightness), + child: placeholder ?? ZupCircularLoadingIndicator(size: height ?? 20), + ); + } return child; }, webHtmlElementStrategy: WebHtmlElementStrategy.fallback, diff --git a/pubspec.lock b/pubspec.lock index 8e6c9f0..209b05c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1281,7 +1281,7 @@ packages: description: path: "." ref: main - resolved-ref: "13ec43de31406f3f5195f6747474ccb50eacdf8e" + resolved-ref: "9a51f58425d80bd29886286a68571d653b4995d5" url: "https://github.com/Zup-Protocol/web3kit.git" source: git version: "0.0.1" @@ -1339,7 +1339,7 @@ packages: description: path: "." ref: main - resolved-ref: "311aa04082ab0b85f2e8dc351777176338a227ea" + resolved-ref: ce5f6541493ed80ad96b2ee3adf75ad67c9a1e59 url: "https://github.com/Zup-Protocol/zup-ui-kit.git" source: git version: "0.0.1" diff --git a/test/app/create/deposit/goldens/deposit_page_30d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_30d_timeframe.png index 4df6120..e712388 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_30d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_30d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_7d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_7d_timeframe.png index 35b7dac..8156917 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_7d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_7d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_90d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_90d_timeframe.png index ce292d7..8f2b63d 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_90d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_90d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_pools_page_1_30d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_pools_page_1_30d_timeframe.png index 229945c..a4316e3 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_pools_page_1_30d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_pools_page_1_30d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_pools_page_1_7d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_pools_page_1_7d_timeframe.png index b476194..908b7e1 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_pools_page_1_7d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_pools_page_1_7d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_pools_page_1_90d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_pools_page_1_90d_timeframe.png index 104e1e0..7aa1453 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_pools_page_1_90d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_pools_page_1_90d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_pools_page_2_30d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_pools_page_2_30d_timeframe.png index 60c5dde..61fdc95 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_pools_page_2_30d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_pools_page_2_30d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_pools_page_2_7d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_pools_page_2_7d_timeframe.png index ba99362..e7de6c4 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_pools_page_2_7d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_pools_page_2_7d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_pools_page_2_90d_timeframe.png b/test/app/create/deposit/goldens/deposit_page_pools_page_2_90d_timeframe.png index eec31e2..7b2c6bd 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_pools_page_2_90d_timeframe.png and b/test/app/create/deposit/goldens/deposit_page_pools_page_2_90d_timeframe.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_reset_scroll_position_on_timeframe_change.png b/test/app/create/deposit/goldens/deposit_page_reset_scroll_position_on_timeframe_change.png index 5f44a12..6cd6fbe 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_reset_scroll_position_on_timeframe_change.png and b/test/app/create/deposit/goldens/deposit_page_reset_scroll_position_on_timeframe_change.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_test.dart b/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_test.dart index 56ee9b9..8250d71 100644 --- a/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_test.dart +++ b/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_test.dart @@ -380,6 +380,39 @@ void main() { }, ); + zGoldenTest( + """When updating the widget from one network, for a different network, + it should update the token in the cubit and get the balance again""", + (tester) async { + await tester.runAsync(() async { + const key = Key("token-amount-card"); + + const oldTokenNetwork = AppNetworks.scroll; + const newTokenNetwork = AppNetworks.sepolia; + + final token = TokenDto.fixture().copyWith( + addresses: { + AppNetworks.scroll.chainId: AppNetworks.scroll.wrappedNativeTokenAddress, + AppNetworks.sepolia.chainId: AppNetworks.sepolia.wrappedNativeTokenAddress, + }, + symbol: "OLD_TOKEN", + ); + + await tester.pumpDeviceBuilder( + await goldenBuilder(key: key, token: token, isNative: false, network: oldTokenNetwork), + ); + await tester.pumpDeviceBuilder( + await goldenBuilder(key: key, token: token, isNative: false, network: newTokenNetwork), + ); + await tester.pumpAndSettle(); + + verify( + () => wallet.nativeOrTokenBalance(token.addresses[newTokenNetwork.chainId]!, rpcUrl: newTokenNetwork.rpcUrl), + ).called(1); + }); + }, + ); + zGoldenTest( """When there's a large number typed, it should not hard clip it in the left border, but instead do a soft clip with a gradient""", diff --git a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_open.png b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_open.png index ed02df2..48a39a6 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_open.png and b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_open.png differ diff --git a/test/app/create/widgets/goldens/create_page_setting_dropdown_min_liquidity_non_numeric.png b/test/app/create/widgets/goldens/create_page_setting_dropdown_min_liquidity_non_numeric.png index 24c1d1a..fa4de39 100644 Binary files a/test/app/create/widgets/goldens/create_page_setting_dropdown_min_liquidity_non_numeric.png and b/test/app/create/widgets/goldens/create_page_setting_dropdown_min_liquidity_non_numeric.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_low_min_tvl_warning.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_low_min_tvl_warning.png index d98d333..6ccfd89 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_low_min_tvl_warning.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_low_min_tvl_warning.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_tooltip.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_tooltip.png index 6c29457..56704c3 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_tooltip.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_tooltip.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_warning_field.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_warning_field.png index 3e24f47..083d8ad 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_warning_field.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_warning_field.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_pool_types_tooltip_hover.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_pool_types_tooltip_hover.png index 93348f0..6d1fa3c 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_pool_types_tooltip_hover.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_pool_types_tooltip_hover.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_v3_pool_type_disabled.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_v3_pool_type_disabled.png index 0cc6b41..206b51f 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_v3_pool_type_disabled.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_v3_pool_type_disabled.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_v3_pool_type_enable.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_v3_pool_type_enable.png index 30c2dd9..a083488 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_v3_pool_type_enable.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_v3_pool_type_enable.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_v4_pool_type_disabled.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_v4_pool_type_disabled.png index edcc71b..159c56a 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_v4_pool_type_disabled.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_v4_pool_type_disabled.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_v4_pool_type_enable.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_v4_pool_type_enable.png index 370abc4..ac2d228 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_v4_pool_type_enable.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_v4_pool_type_enable.png differ diff --git a/test/core/dtos/yield_dto_test.dart b/test/core/dtos/yield_dto_test.dart index 473f5de..0b96b7f 100644 --- a/test/core/dtos/yield_dto_test.dart +++ b/test/core/dtos/yield_dto_test.dart @@ -1,5 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:web3kit/core/ethereum_constants.dart'; +import 'package:zup_app/core/dtos/protocol_dto.dart'; import 'package:zup_app/core/dtos/token_dto.dart'; import 'package:zup_app/core/dtos/yield_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; @@ -85,4 +86,38 @@ void main() { expect(currentYield.yieldTimeframed(YieldTimeFrame.threeMonth), yield90d); }); + + test("When building the yield dto with default variables, the deployerAddress should be zero address by default", () { + expect( + YieldDto( + token0: TokenDto.fixture(), + token1: TokenDto.fixture(), + poolAddress: "0x1", + chainId: AppNetworks.sepolia.chainId, + positionManagerAddress: "0x2", + tickSpacing: 1, + protocol: ProtocolDto.fixture(), + initialFeeTier: 0, + currentFeeTier: 0, + ).deployerAddress, + EthereumConstants.zeroAddress, + ); + }); + + test("When building the yield dto with default variables, the hooks should be zero address by default", () { + expect( + YieldDto( + token0: TokenDto.fixture(), + token1: TokenDto.fixture(), + poolAddress: "0x1", + chainId: AppNetworks.sepolia.chainId, + positionManagerAddress: "0x2", + tickSpacing: 1, + protocol: ProtocolDto.fixture(), + initialFeeTier: 0, + currentFeeTier: 0, + ).v4Hooks, + EthereumConstants.zeroAddress, + ); + }); } diff --git a/test/core/enums/goldens/hyperEVM_network_icon.png b/test/core/enums/goldens/hyperEVM_network_icon.png new file mode 100644 index 0000000..f6614bd Binary files /dev/null and b/test/core/enums/goldens/hyperEVM_network_icon.png differ diff --git a/test/core/enums/networks_test.dart b/test/core/enums/networks_test.dart index 1e77904..968848e 100644 --- a/test/core/enums/networks_test.dart +++ b/test/core/enums/networks_test.dart @@ -1,3 +1,4 @@ +import 'package:flutter/src/widgets/basic.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:golden_toolkit/golden_toolkit.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; @@ -21,7 +22,8 @@ void main() { expect(AppNetworks.fromValue("mainnet"), AppNetworks.mainnet, reason: "Mainnet should match"); expect(AppNetworks.fromValue("scroll"), AppNetworks.scroll, reason: "Scroll should match"); expect(AppNetworks.fromValue("allNetworks"), AppNetworks.allNetworks, reason: "All networks should match"); - // expect(AppNetworks.fromValue("base"), AppNetworks.base, reason: "Base should match"); + expect(AppNetworks.fromValue("base"), AppNetworks.base, reason: "Base should match"); + expect(AppNetworks.fromValue("hyperEvm"), AppNetworks.hyperEvm, reason: "HyperEVM should match"); expect(AppNetworks.fromValue("unichain"), AppNetworks.unichain, reason: "Unichain should match"); // expect(AppNetworks.fromValue("bnb"), AppNetworks.bnb, reason: "BNB should match"); }); @@ -31,7 +33,8 @@ void main() { expect(AppNetworks.mainnet.label, "Ethereum", reason: "Ethereum Label should match"); expect(AppNetworks.scroll.label, "Scroll", reason: "Scroll Label should match"); expect(AppNetworks.allNetworks.label, "All Networks", reason: "All Networks Label should match"); - // expect(AppNetworks.base.label, "Base", reason: "Base Label should match"); + expect(AppNetworks.base.label, "Base", reason: "Base Label should match"); + expect(AppNetworks.hyperEvm.label, "HyperEVM", reason: "HyperEVM Label should match"); expect(AppNetworks.unichain.label, "Unichain", reason: "Unichain Label should match"); // expect(AppNetworks.bnb.label, "BNB Chain", reason: "BNB Chain Label should match"); }); @@ -47,7 +50,8 @@ void main() { AppNetworks.allNetworks, AppNetworks.mainnet, AppNetworks.scroll, - // AppNetworks.base, + AppNetworks.base, + AppNetworks.hyperEvm, AppNetworks.unichain, // AppNetworks.bnb ]), @@ -67,7 +71,11 @@ void main() { }); test("`isTestnet` method should return false for base", () { - // expect(AppNetworks.base.isTestnet, false); + expect(AppNetworks.base.isTestnet, false); + }); + + test("`isTestnet` method should return false for hyperEVM", () { + expect(AppNetworks.hyperEvm.isTestnet, false); }); test("`isTestnet` method should return false for unichain", () { @@ -114,17 +122,17 @@ void main() { reason: "Scroll ChainInfo should match", ); - // expect( - // AppNetworks.base.chainInfo, - // ChainInfo( - // hexChainId: "0x2105", - // chainName: "Base", - // blockExplorerUrls: const ["https://basescan.org"], - // nativeCurrency: NativeCurrencies.eth.currencyInfo, - // rpcUrls: const ["https://base-rpc.publicnode.com"], - // ), - // reason: "Base ChainInfo should match", - // ); + expect( + AppNetworks.base.chainInfo, + ChainInfo( + hexChainId: "0x2105", + chainName: "Base", + blockExplorerUrls: const ["https://basescan.org"], + nativeCurrency: NativeCurrencies.eth.currencyInfo, + rpcUrls: const ["https://base-rpc.publicnode.com"], + ), + reason: "Base ChainInfo should match", + ); expect( AppNetworks.unichain.chainInfo, @@ -138,6 +146,18 @@ void main() { reason: "Unichain ChainInfo should match", ); + expect( + AppNetworks.hyperEvm.chainInfo, + ChainInfo( + hexChainId: "0x3e7", + chainName: "HyperEVM", + blockExplorerUrls: const ["https://hyperevmscan.io"], + nativeCurrency: NativeCurrencies.hype.currencyInfo, + rpcUrls: const ["https://rpc.hyperliquid.xyz/evm"], + ), + reason: "HyperEVM ChainInfo should match", + ); + // expect( // AppNetworks.bnb.chainInfo, // ChainInfo( @@ -190,17 +210,9 @@ void main() { reason: "Sepolia rpc url should match", ); - expect( - AppNetworks.mainnet.rpcUrl, - "https://ethereum-rpc.publicnode.com", - reason: "Ethereum rpc url should match", - ); + expect(AppNetworks.mainnet.rpcUrl, "https://ethereum-rpc.publicnode.com", reason: "Ethereum rpc url should match"); - expect( - AppNetworks.scroll.rpcUrl, - "https://scroll-rpc.publicnode.com", - reason: "Scroll rpc url should match", - ); + expect(AppNetworks.scroll.rpcUrl, "https://scroll-rpc.publicnode.com", reason: "Scroll rpc url should match"); // expect( // AppNetworks.base.rpcUrl, @@ -208,11 +220,7 @@ void main() { // reason: "Base rpc url should match", // ); - expect( - AppNetworks.unichain.rpcUrl, - "https://unichain-rpc.publicnode.com", - reason: "Unichain rpc url should match", - ); + expect(AppNetworks.unichain.rpcUrl, "https://unichain-rpc.publicnode.com", reason: "Unichain rpc url should match"); // expect( // AppNetworks.bnb.rpcUrl, @@ -267,38 +275,32 @@ void main() { }); zGoldenTest("Sepolia network icon should match", goldenFileName: "sepolia_network_icon", (tester) async { - await tester.pumpDeviceBuilder(await goldenDeviceBuilder( - AppNetworks.sepolia.icon, - device: GoldenDevice.square, - )); + await tester.pumpDeviceBuilder(await goldenDeviceBuilder(AppNetworks.sepolia.icon, device: GoldenDevice.square)); + }); + + zGoldenTest("hyperEVM network icon should match", goldenFileName: "hyperEVM_network_icon", (tester) async { + await tester.pumpDeviceBuilder( + await goldenDeviceBuilder( + SizedBox(height: 100, child: Center(child: AppNetworks.hyperEvm.icon)), + device: GoldenDevice.square, + ), + ); }); zGoldenTest("Ethereum network icon should match", goldenFileName: "ethereum_network_icon", (tester) async { - await tester.pumpDeviceBuilder(await goldenDeviceBuilder( - AppNetworks.mainnet.icon, - device: GoldenDevice.square, - )); + await tester.pumpDeviceBuilder(await goldenDeviceBuilder(AppNetworks.mainnet.icon, device: GoldenDevice.square)); }); - // zGoldenTest("Base network icon should match", goldenFileName: "base_network_icon", (tester) async { - // await tester.pumpDeviceBuilder(await goldenDeviceBuilder( - // AppNetworks.base.icon, - // device: GoldenDevice.square, - // )); - // }); + zGoldenTest("Base network icon should match", goldenFileName: "base_network_icon", (tester) async { + await tester.pumpDeviceBuilder(await goldenDeviceBuilder(AppNetworks.base.icon, device: GoldenDevice.square)); + }); zGoldenTest("Scroll network icon should match", goldenFileName: "scroll_network_icon", (tester) async { - await tester.pumpDeviceBuilder(await goldenDeviceBuilder( - AppNetworks.scroll.icon, - device: GoldenDevice.square, - )); + await tester.pumpDeviceBuilder(await goldenDeviceBuilder(AppNetworks.scroll.icon, device: GoldenDevice.square)); }); zGoldenTest("Unichain network icon should match", goldenFileName: "unichain_network_icon", (tester) async { - await tester.pumpDeviceBuilder(await goldenDeviceBuilder( - AppNetworks.unichain.icon, - device: GoldenDevice.square, - )); + await tester.pumpDeviceBuilder(await goldenDeviceBuilder(AppNetworks.unichain.icon, device: GoldenDevice.square)); }); // zGoldenTest("BNB network icon should match", goldenFileName: "bnb_network_icon", (tester) async { diff --git a/test/core/enums/protocol_id_test.dart b/test/core/enums/protocol_id_test.dart index b2d22a2..5a02bd8 100644 --- a/test/core/enums/protocol_id_test.dart +++ b/test/core/enums/protocol_id_test.dart @@ -9,6 +9,27 @@ void main() { }, ); + test( + "when calling 'isAerodromeOrVelodromeSlipstream' and the protocol is indeed aerodromeSlipstream, it should return true", + () { + expect(ProtocolId.aerodromeSlipstream.isAerodromeOrVelodromeSlipstream, true); + }, + ); + + test( + "when calling 'isAerodromeOrVelodromeSlipstream' and the protocol is indeed velodromeSlipstream, it should return true", + () { + expect(ProtocolId.velodromeSlipstream.isAerodromeOrVelodromeSlipstream, true); + }, + ); + + test( + "when calling 'isAerodromeOrVelodromeSlipstream' and the protocol is not aerodromeSlipstream or velodromeSlipstream, it should return false", + () { + expect(ProtocolId.unknown.isAerodromeOrVelodromeSlipstream, false); + }, + ); + test( "When calling `isPancakeSwapInfinityCL` and the protocol is not pancakeSwapInfinityCL, it should return false", () { diff --git a/test/core/pool_service_test.dart b/test/core/pool_service_test.dart index 91bf353..22d136c 100644 --- a/test/core/pool_service_test.dart +++ b/test/core/pool_service_test.dart @@ -4,7 +4,12 @@ import 'package:mocktail/mocktail.dart'; import 'package:web3kit/core/dtos/transaction_receipt.dart'; import 'package:web3kit/core/dtos/transaction_response.dart'; import 'package:web3kit/web3kit.dart'; +import 'package:zup_app/abis/aerodrome_v3_pool.abi.g.dart'; +import 'package:zup_app/abis/aerodrome_v3_position_manager.abi.g.dart'; +import 'package:zup_app/abis/algebra/v1.2.1/pool.abi.g.dart' as algebra_1_2_1_pool; +import 'package:zup_app/abis/algebra/v1.2.1/position_manager.abi.g.dart' as algebra_1_2_1_position_manager; import 'package:zup_app/abis/pancake_swap_infinity_cl_pool_manager.abi.g.dart'; +import 'package:zup_app/abis/pancake_swap_infinity_cl_position_manager.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart'; import 'package:zup_app/abis/uniswap_v4_position_manager.abi.g.dart'; @@ -19,6 +24,7 @@ import 'package:zup_app/core/mixins/v4_pool_liquidity_calculations_mixin.dart'; import 'package:zup_app/core/pool_service.dart'; import 'package:zup_app/core/v4_pool_constants.dart'; +import '../matchers.dart'; import '../mocks.dart'; class _V4PoolLiquidityCalculationsMixinWrapper with V4PoolLiquidityCalculationsMixin {} @@ -33,13 +39,23 @@ void main() { late Signer signer; late YieldDto currentYield; late TransactionResponse transactionResponse; + late AerodromeV3PositionManager aerodromePositionManagerV3; + late AerodromeV3Pool aerodromeV3Pool; + late algebra_1_2_1_position_manager.PositionManager algebra121PositionManager; + late algebra_1_2_1_pool.Pool algebra121Pool; + late PancakeSwapInfinityClPositionManager pancakeSwapInfinityCLPositionManager; - late UniswapV4StateViewImpl stateViewImpl; + late UniswapV4StateViewImpl uniswapV4StateViewImpl; late UniswapV3PoolImpl uniswapV3PoolImpl; late UniswapV3PositionManagerImpl positionManagerV3Impl; - late UniswapV4PositionManagerImpl positionManagerV4Impl; + late UniswapV4PositionManagerImpl uniswapPositionManagerV4Impl; late PancakeSwapInfinityClPoolManagerImpl pancakeSwapInfinityCLPoolManagerImpl; late EthereumAbiCoder ethereumAbiCoder; + late AerodromeV3PositionManagerImpl aerodromePositionManagerV3Impl; + late algebra_1_2_1_position_manager.PositionManagerImpl algebra121PositionManagerImpl; + late algebra_1_2_1_pool.PoolImpl algebra121PoolImpl; + late AerodromeV3PoolImpl aerodromeV3PoolImpl; + late PancakeSwapInfinityClPositionManagerImpl pancakeSwapInfinityCLPositionManagerImpl; setUp(() { registerFallbackValue(( @@ -66,13 +82,22 @@ void main() { pancakeSwapInfinityCLPoolManager = PancakeSwapInfinityCLPoolManagerMock(); ethereumAbiCoder = EthereumAbiCoderMock(); signer = SignerMock(); + aerodromePositionManagerV3 = AerodromeV3PositionManagerMock(); + algebra121PositionManager = Algebra121PositionManagerMock(); + algebra121Pool = Algebra121PoolMock(); + aerodromeV3Pool = AerodromeV3PoolMock(); + pancakeSwapInfinityCLPositionManager = PancakeSwapInfinityCLPositionManagerMock(); pancakeSwapInfinityCLPoolManagerImpl = PancakeSwapInfinityCLPoolManagerImplMock(); - - stateViewImpl = UniswapV4StateViewImplMock(); + uniswapV4StateViewImpl = UniswapV4StateViewImplMock(); uniswapV3PoolImpl = UniswapV3PoolImplMock(); positionManagerV3Impl = UniswapV3PositionManagerImplMock(); - positionManagerV4Impl = UniswapV4PositionManagerImplMock(); + uniswapPositionManagerV4Impl = UniswapV4PositionManagerImplMock(); + aerodromePositionManagerV3Impl = AerodromeV3PositionManagerImplMock(); + algebra121PositionManagerImpl = Algebra121PositionManagerImplMock(); + algebra121PoolImpl = Algebra121PoolImplMock(); + aerodromeV3PoolImpl = AerodromeV3PoolImplMock(); + pancakeSwapInfinityCLPositionManagerImpl = PancakeSwapInfinityCLPositionManagerImplMock(); currentYield = YieldDto.fixture(); @@ -83,89 +108,142 @@ void main() { positionManagerV4, ethereumAbiCoder, pancakeSwapInfinityCLPoolManager, + pancakeSwapInfinityCLPositionManager, + aerodromePositionManagerV3, + aerodromeV3Pool, + algebra121Pool, + algebra121PositionManager, ); - when(() => uniswapV3Pool.fromRpcProvider( - contractAddress: any(named: "contractAddress"), - rpcUrl: any(named: "rpcUrl"), - )).thenReturn(uniswapV3PoolImpl); + when( + () => uniswapV3Pool.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(uniswapV3PoolImpl); + + when( + () => positionManagerV3.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(positionManagerV3Impl); + + when( + () => positionManagerV3.fromSigner( + contractAddress: any(named: "contractAddress"), + signer: any(named: "signer"), + ), + ).thenReturn(positionManagerV3Impl); + + when( + () => positionManagerV4.fromSigner( + contractAddress: any(named: "contractAddress"), + signer: any(named: "signer"), + ), + ).thenReturn(uniswapPositionManagerV4Impl); + + when( + () => stateView.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(uniswapV4StateViewImpl); - when(() => positionManagerV3.fromRpcProvider( + when( + () => positionManagerV4.fromRpcProvider( contractAddress: any(named: "contractAddress"), - rpcUrl: any(named: "rpcUrl"))).thenReturn(positionManagerV3Impl); + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(uniswapPositionManagerV4Impl); + + when(() => uniswapV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + feeProtocol: BigInt.from(0), + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + observationIndex: BigInt.from(0), + sqrtPriceX96: BigInt.from(0), + tick: BigInt.from(0), + unlocked: true, + ), + ); - when(() => - positionManagerV3.fromSigner(contractAddress: any(named: "contractAddress"), signer: any(named: "signer"))) - .thenReturn(positionManagerV3Impl); + when( + () => pancakeSwapInfinityCLPoolManager.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(pancakeSwapInfinityCLPoolManagerImpl); - when(() => - positionManagerV4.fromSigner(contractAddress: any(named: "contractAddress"), signer: any(named: "signer"))) - .thenReturn(positionManagerV4Impl); + when( + () => pancakeSwapInfinityCLPoolManager.fromSigner( + contractAddress: any(named: "contractAddress"), + signer: any(named: "signer"), + ), + ).thenReturn(pancakeSwapInfinityCLPoolManagerImpl); - when(() => stateView.fromRpcProvider(contractAddress: any(named: "contractAddress"), rpcUrl: any(named: "rpcUrl"))) - .thenReturn(stateViewImpl); + when( + () => pancakeSwapInfinityCLPositionManager.fromSigner( + contractAddress: any(named: "contractAddress"), + signer: any(named: "signer"), + ), + ).thenReturn(pancakeSwapInfinityCLPositionManagerImpl); - when(() => positionManagerV4.fromRpcProvider( + when( + () => pancakeSwapInfinityCLPositionManager.fromRpcProvider( contractAddress: any(named: "contractAddress"), - rpcUrl: any(named: "rpcUrl"))).thenReturn(positionManagerV4Impl); + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(pancakeSwapInfinityCLPositionManagerImpl); when(() => signer.address).thenAnswer((_) async => "0xS0M3_4ddr355"); when(() => transactionResponse.waitConfirmation()).thenAnswer((_) async => TransactionReceipt(hash: "0x123")); when(() => transactionResponse.hash).thenReturn("0x123"); - when(() => stateViewImpl.getSlot0(poolId: any(named: "poolId"))).thenAnswer((_) async => ( - lpFee: BigInt.from(0), - protocolFee: BigInt.from(0), - sqrtPriceX96: BigInt.from(0), - tick: BigInt.from(0), - )); + when(() => uniswapV4StateViewImpl.getSlot0(poolId: any(named: "poolId"))).thenAnswer( + (_) async => + (lpFee: BigInt.from(0), protocolFee: BigInt.from(0), sqrtPriceX96: BigInt.from(0), tick: BigInt.from(0)), + ); }); - test( - "When calling `getPoolTick` and the pool is v4, it should use the state view contract to get it", - () async { - final expectedTick = BigInt.from(87654); - when(() => stateViewImpl.getSlot0(poolId: any(named: "poolId"))).thenAnswer((_) async => ( - lpFee: BigInt.from(0), - protocolFee: BigInt.from(0), - sqrtPriceX96: BigInt.from(0), - tick: expectedTick, - )); - when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer((_) async => ( - lpFee: BigInt.from(0), - protocolFee: BigInt.from(0), - sqrtPriceX96: BigInt.from(0), - tick: expectedTick, - )); - final currentYield0 = currentYield.copyWith(poolType: PoolType.v4, v4StateView: "0x123"); - final result = await sut.getPoolTick(currentYield0); + test("When calling `getPoolTick` and the pool is v4, it should use the state view contract to get it", () async { + final expectedTick = BigInt.from(87654); + when(() => uniswapV4StateViewImpl.getSlot0(poolId: any(named: "poolId"))).thenAnswer( + (_) async => + (lpFee: BigInt.from(0), protocolFee: BigInt.from(0), sqrtPriceX96: BigInt.from(0), tick: expectedTick), + ); + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => + (lpFee: BigInt.from(0), protocolFee: BigInt.from(0), sqrtPriceX96: BigInt.from(0), tick: expectedTick), + ); + final currentYield0 = currentYield.copyWith(poolType: PoolType.v4, v4StateView: "0x123"); + final result = await sut.getPoolTick(currentYield0); - expect(result, expectedTick); - verify(() => stateViewImpl.getSlot0(poolId: currentYield0.poolAddress)).called(1); - }, - ); + expect(result, expectedTick); + verify(() => uniswapV4StateViewImpl.getSlot0(poolId: currentYield0.poolAddress)).called(1); + }); - test( - "When calling `getPoolTick` and the pool is v3, it should use the v3 pool contract to get it", - () async { - final expectedTick = BigInt.from(2127); - when(() => uniswapV3PoolImpl.slot0()).thenAnswer((_) async => ( - feeProtocol: BigInt.from(0), - observationCardinality: BigInt.from(0), - observationCardinalityNext: BigInt.from(0), - observationIndex: BigInt.from(0), - sqrtPriceX96: BigInt.from(0), - tick: expectedTick, - unlocked: true - )); + test("When calling `getPoolTick` and the pool is v3, it should use the v3 pool contract to get it", () async { + final expectedTick = BigInt.from(2127); + when(() => uniswapV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + feeProtocol: BigInt.from(0), + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + observationIndex: BigInt.from(0), + sqrtPriceX96: BigInt.from(0), + tick: expectedTick, + unlocked: true, + ), + ); - final currentYield0 = currentYield.copyWith(poolType: PoolType.v3); - final result = await sut.getPoolTick(currentYield0); + final currentYield0 = currentYield.copyWith(poolType: PoolType.v3); + final result = await sut.getPoolTick(currentYield0); - expect(result, expectedTick); - verify(() => uniswapV3PoolImpl.slot0()).called(1); - }, - ); + expect(result, expectedTick); + verify(() => uniswapV3PoolImpl.slot0()).called(1); + }); test( """when calling `sendV3PoolDepositTransaction` with token0 native, @@ -177,21 +255,20 @@ void main() { const network = AppNetworks.mainnet; final currentYield0 = currentYield.copyWith( - poolType: PoolType.v3, - chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: { - network.chainId: EthereumConstants.zeroAddress, - }), - token1: TokenDto.fixture().copyWith(addresses: { - network.chainId: "0x123", - })); + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x123"}), + ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); when(() => positionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); - when(() => positionManagerV3Impl.multicall(data: any(named: "data"), ethValue: any(named: "ethValue"))) - .thenAnswer( - (_) async => transactionResponse, - ); + when( + () => positionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); final amount0Desired = BigInt.from(100); final amount1Desired = BigInt.from(100); @@ -236,17 +313,20 @@ void main() { const network = AppNetworks.mainnet; final currentYield0 = currentYield.copyWith( - poolType: PoolType.v3, - chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address})); + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); when(() => positionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); - when(() => positionManagerV3Impl.multicall(data: any(named: "data"), ethValue: any(named: "ethValue"))) - .thenAnswer( - (_) async => transactionResponse, - ); + when( + () => positionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -271,19 +351,21 @@ void main() { ); verify( - () => positionManagerV3.getMintCalldata(params: ( - amount0Desired: amount0Desired, - amount0Min: amount0Min, - amount1Desired: amount1Desired, - amount1Min: amount1Min, - deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), - fee: BigInt.from(currentYield0.feeTier), - recipient: recipient, - tickLower: tickLower, - tickUpper: tickUpper, - token0: network.wrappedNativeTokenAddress, - token1: token1Address, - )), + () => positionManagerV3.getMintCalldata( + params: ( + amount0Desired: amount0Desired, + amount0Min: amount0Min, + amount1Desired: amount1Desired, + amount1Min: amount1Min, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + fee: BigInt.from(currentYield0.initialFeeTier), + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + token0: network.wrappedNativeTokenAddress, + token1: token1Address, + ), + ), ).called(1); }); }, @@ -301,17 +383,20 @@ void main() { const network = AppNetworks.mainnet; final currentYield0 = currentYield.copyWith( - poolType: PoolType.v3, - chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address})); + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); when(() => positionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); - when(() => positionManagerV3Impl.multicall(data: any(named: "data"), ethValue: any(named: "ethValue"))) - .thenAnswer( - (_) async => transactionResponse, - ); + when( + () => positionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); final amount0Desired = BigInt.from(100); final amount1Desired = BigInt.from(31); @@ -336,19 +421,21 @@ void main() { ); verify( - () => positionManagerV3.getMintCalldata(params: ( - amount0Desired: amount0Desired, - amount0Min: amount0Min, - amount1Desired: amount1Desired, - amount1Min: amount1Min, - deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), - fee: BigInt.from(currentYield0.feeTier), - recipient: recipient, - tickLower: tickLower, - tickUpper: tickUpper, - token0: token0Address, - token1: network.wrappedNativeTokenAddress, - )), + () => positionManagerV3.getMintCalldata( + params: ( + amount0Desired: amount0Desired, + amount0Min: amount0Min, + amount1Desired: amount1Desired, + amount1Min: amount1Min, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + fee: BigInt.from(currentYield0.initialFeeTier), + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + token0: token0Address, + token1: network.wrappedNativeTokenAddress, + ), + ), ).called(1); }); }, @@ -366,17 +453,20 @@ void main() { const network = AppNetworks.mainnet; final currentYield0 = currentYield.copyWith( - poolType: PoolType.v3, - chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address})); + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); when(() => positionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); - when(() => positionManagerV3Impl.multicall(data: any(named: "data"), ethValue: any(named: "ethValue"))) - .thenAnswer( - (_) async => transactionResponse, - ); + when( + () => positionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -401,7 +491,10 @@ void main() { ); verify( - () => positionManagerV3Impl.multicall(ethValue: amount0Desired, data: any(named: "data")), + () => positionManagerV3Impl.multicall( + ethValue: amount0Desired, + data: any(named: "data"), + ), ).called(1); }); }, @@ -419,17 +512,20 @@ void main() { const network = AppNetworks.mainnet; final currentYield0 = currentYield.copyWith( - poolType: PoolType.v3, - chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address})); + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); when(() => positionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); - when(() => positionManagerV3Impl.multicall(data: any(named: "data"), ethValue: any(named: "ethValue"))) - .thenAnswer( - (_) async => transactionResponse, - ); + when( + () => positionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -454,7 +550,10 @@ void main() { ); verify( - () => positionManagerV3Impl.multicall(ethValue: amount1Desired, data: any(named: "data")), + () => positionManagerV3Impl.multicall( + ethValue: amount1Desired, + data: any(named: "data"), + ), ).called(1); }); }, @@ -468,18 +567,21 @@ void main() { const token1Address = "0x315768"; const token0Address = "0x20172891"; - when(() => positionManagerV3Impl.mint(params: any(named: "params"), ethValue: any(named: "ethValue"))) - .thenAnswer( - (_) async => transactionResponse, - ); + when( + () => positionManagerV3Impl.mint( + params: any(named: "params"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); const network = AppNetworks.mainnet; final currentYield0 = currentYield.copyWith( - feeTier: 3982, - poolType: PoolType.v3, - chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address})); + initialFeeTier: 3982, + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -508,7 +610,7 @@ void main() { params: ( token0: token0Address, token1: token1Address, - fee: BigInt.from(currentYield0.feeTier), + fee: BigInt.from(currentYield0.initialFeeTier), tickLower: tickLower, tickUpper: tickUpper, amount0Desired: amount0Desired, @@ -526,119 +628,175 @@ void main() { ); test( - "When calling `sendV4PoolDepositTransaction` and the token0 is native, it should encode packed the correct actions including the sweep", - () async { - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); - when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), - ).thenAnswer((_) async => transactionResponse); + "When calling `sendV4PoolDepositTransaction` and the token0 is native, it should encode packed the correct actions including the sweep", + () async { + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); - const network = AppNetworks.mainnet; - final amount0Desired = BigInt.from(4311); - final amount1Desired = BigInt.from(1031900); - const deadline = Duration(days: 1); - final amount0Max = BigInt.from(4312); - final amount1Max = BigInt.from(1031901); - final recipient = await signer.address; - final tickLower = BigInt.from(321); - final tickUpper = BigInt.from(1222); + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); - final currentYield0 = currentYield.copyWith( - chainId: network.chainId, - poolType: PoolType.v4, - v4StateView: "0x1", - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), - ); + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + poolType: PoolType.v4, + v4StateView: "0x1", + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), + ); - await sut.sendV4PoolDepositTransaction( - currentYield0, - signer, - deadline: deadline, - tickLower: tickLower, - tickUpper: tickUpper, - amount0toDeposit: amount0Desired, - amount1ToDeposit: amount1Desired, - maxAmount0ToDeposit: amount0Max, - maxAmount1ToDeposit: amount1Max, - recipient: recipient, - ); + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); - verify(() => ethereumAbiCoder.encodePacked([ - "uint8", - "uint8", - "uint8" - ], [ - V4PoolConstants.mintPositionActionValue, - V4PoolConstants.settlePairActionValue, - V4PoolConstants.sweepActionValue - ])).called(1); - }); + verify( + () => ethereumAbiCoder.encodePacked( + ["uint8", "uint8", "uint8"], + [ + V4PoolConstants.mintPositionActionValue, + V4PoolConstants.uniswapSettlePairActionValue, + V4PoolConstants.uniswapSweepActionValue, + ], + ), + ).called(1); + }, + ); test( - "When calling `sendV4PoolDepositTransaction` and the token1 is native, it should encode packed the correct actions including the sweep", - () async { - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); - when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), - ).thenAnswer((_) async => transactionResponse); - - const network = AppNetworks.mainnet; - final amount0Desired = BigInt.from(4311); - final amount1Desired = BigInt.from(1031900); - const deadline = Duration(days: 1); - final amount0Max = BigInt.from(4312); - final amount1Max = BigInt.from(1031901); - final recipient = await signer.address; - final tickLower = BigInt.from(321); - final tickUpper = BigInt.from(1222); + "When calling `sendV4PoolDepositTransaction` and the token1 is native, it should encode packed the correct actions including the sweep", + () async { + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); - final currentYield0 = currentYield.copyWith( - chainId: network.chainId, - v4StateView: "0x1", - poolType: PoolType.v4, - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), - ); + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); - await sut.sendV4PoolDepositTransaction( - currentYield0, - signer, - deadline: deadline, - tickLower: tickLower, - tickUpper: tickUpper, - amount0toDeposit: amount0Desired, - amount1ToDeposit: amount1Desired, - maxAmount0ToDeposit: amount0Max, - maxAmount1ToDeposit: amount1Max, - recipient: recipient, - ); + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + v4StateView: "0x1", + poolType: PoolType.v4, + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), + ); - verify(() => ethereumAbiCoder.encodePacked([ - "uint8", - "uint8", - "uint8" - ], [ - V4PoolConstants.mintPositionActionValue, - V4PoolConstants.settlePairActionValue, - V4PoolConstants.sweepActionValue - ])).called(1); - }); + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); + + verify( + () => ethereumAbiCoder.encodePacked( + ["uint8", "uint8", "uint8"], + [ + V4PoolConstants.mintPositionActionValue, + V4PoolConstants.uniswapSettlePairActionValue, + V4PoolConstants.uniswapSweepActionValue, + ], + ), + ).called(1); + }, + ); test( - "When calling `sendV4PoolDepositTransaction` and none of the tokens are native, it should not include the sweep action", - () async { - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); - when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), - ).thenAnswer((_) async => transactionResponse); + "When calling `sendV4PoolDepositTransaction` and none of the tokens are native, it should not include the sweep action", + () async { + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + v4StateView: "0x1", + poolType: PoolType.v4, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x2"}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), + ); + + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); + verify( + () => ethereumAbiCoder.encodePacked( + ["uint8", "uint8"], + [V4PoolConstants.mintPositionActionValue, V4PoolConstants.uniswapSettlePairActionValue], + ), + ).called(1); + }, + ); + + test("When calling `sendV4PoolDepositTransaction` the mint action params should be correctly encoded", () async { + const token0Address = "0x1"; + const token1Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -648,13 +806,29 @@ void main() { final recipient = await signer.address; final tickLower = BigInt.from(321); final tickUpper = BigInt.from(1222); + final sqrtPriceX96 = BigInt.from(2167212171927187); + + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + when(() => uniswapV4StateViewImpl.getSlot0(poolId: any(named: "poolId"))).thenAnswer( + (_) async => + (lpFee: BigInt.from(0), protocolFee: BigInt.from(0), sqrtPriceX96: sqrtPriceX96, tick: BigInt.from(0)), + ); final currentYield0 = currentYield.copyWith( chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x2"}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), ); await sut.sendV4PoolDepositTransaction( @@ -670,17 +844,47 @@ void main() { recipient: recipient, ); - verify(() => ethereumAbiCoder.encodePacked([ - "uint8", - "uint8", - ], [ - V4PoolConstants.mintPositionActionValue, - V4PoolConstants.settlePairActionValue, - ])).called(1); + verify( + () => ethereumAbiCoder.encode( + [ + "tuple(address,address,int32,int24,address)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], + [ + [ + token0Address, + token1Address, + BigInt.from(currentYield0.initialFeeTier), + BigInt.from(currentYield0.tickSpacing), + currentYield0.v4Hooks, + ], + tickLower, + tickUpper, + _V4PoolLiquidityCalculationsMixinWrapper().getLiquidityForAmounts( + sqrtPriceX96, + _V4PoolLiquidityCalculationsMixinWrapper().getSqrtPriceAtTick(tickLower), + _V4PoolLiquidityCalculationsMixinWrapper().getSqrtPriceAtTick(tickUpper), + amount0Desired, + amount1Desired, + ), + amount0Max, + amount1Max, + recipient, + EthereumConstants.emptyBytes, + ], + ), + ).called(1); }); test( - "When calling `sendV4PoolDepositTransaction` the mint action params should be correctly encoded", + """When calling `sendV4PoolDepositTransaction` and the protocol is Pancake Swap + infinity the mint action params should be correctly encoded""", () async { const token0Address = "0x1"; const token1Address = "0x2"; @@ -694,25 +898,42 @@ void main() { final tickLower = BigInt.from(321); final tickUpper = BigInt.from(1222); final sqrtPriceX96 = BigInt.from(2167212171927187); + const parameters = "0x2186271217625167f2ffff"; + const hooks = "0x2111"; + const poolManager = "0xAAABbbaaa"; when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), + () => pancakeSwapInfinityCLPositionManagerImpl.modifyLiquidities( + payload: any(named: "payload"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), ).thenAnswer((_) async => transactionResponse); - when(() => stateViewImpl.getSlot0(poolId: any(named: "poolId"))).thenAnswer((_) async => ( - lpFee: BigInt.from(0), - protocolFee: BigInt.from(0), - sqrtPriceX96: sqrtPriceX96, - tick: BigInt.from(0), - )); + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => + (lpFee: BigInt.from(0), protocolFee: BigInt.from(0), sqrtPriceX96: sqrtPriceX96, tick: BigInt.from(0)), + ); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.poolIdToPoolKey(id: any(named: "id"))).thenAnswer( + (_) async => ( + currency0: token0Address, + currency1: token1Address, + fee: BigInt.from(21), + hooks: hooks, + parameters: parameters, + poolManager: poolManager, + ), + ); final currentYield0 = currentYield.copyWith( chainId: network.chainId, - v4StateView: "0x1", + v4PoolManager: poolManager, + v4Hooks: hooks, poolType: PoolType.v4, + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), ); @@ -730,23 +951,20 @@ void main() { recipient: recipient, ); - verify(() => ethereumAbiCoder.encode([ - "tuple(address,address,int32,int24,address)", + verify( + () => ethereumAbiCoder.encode( + [ + "tuple(address,address,address,address,uint24,bytes32)", "int24", "int24", "uint256", "uint128", "uint128", "address", - "bytes" - ], [ - [ - token0Address, - token1Address, - BigInt.from(currentYield0.feeTier), - BigInt.from(currentYield0.tickSpacing), - currentYield0.v4Hooks, - ], + "bytes", + ], + [ + [token0Address, token1Address, hooks, poolManager, currentYield0.initialFeeTier, parameters], tickLower, tickUpper, _V4PoolLiquidityCalculationsMixinWrapper().getLiquidityForAmounts( @@ -760,20 +978,17 @@ void main() { amount1Max, recipient, EthereumConstants.emptyBytes, - ])).called(1); + ], + ), + ).called(1); }, ); test( - "When calling `sendV4PoolDepositTransaction` the settle pair action params should be correctly encoded", + """When calling `sendV4PoolDepositTransaction` and the protocol is Pancake Swap + infinity, it should get the pool parameters from the pool manager and + encode it correctly in the mint action""", () async { - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); - when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), - ).thenAnswer((_) async => transactionResponse); - const token0Address = "0x1"; const token1Address = "0x2"; const network = AppNetworks.mainnet; @@ -785,11 +1000,43 @@ void main() { final recipient = await signer.address; final tickLower = BigInt.from(321); final tickUpper = BigInt.from(1222); + final sqrtPriceX96 = BigInt.from(2167212171927187); + const parameters = "0x2186271217625167f2ffff"; + const hooks = "0x2111"; + const poolManager = "0xAAABbbaaa"; + + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => pancakeSwapInfinityCLPositionManagerImpl.modifyLiquidities( + payload: any(named: "payload"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => + (lpFee: BigInt.from(0), protocolFee: BigInt.from(0), sqrtPriceX96: sqrtPriceX96, tick: BigInt.from(0)), + ); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.poolIdToPoolKey(id: any(named: "id"))).thenAnswer( + (_) async => ( + currency0: token0Address, + currency1: token1Address, + fee: BigInt.from(21), + hooks: hooks, + parameters: parameters, + poolManager: poolManager, + ), + ); final currentYield0 = currentYield.copyWith( chainId: network.chainId, - v4StateView: "0x1", + v4PoolManager: poolManager, + v4Hooks: hooks, poolType: PoolType.v4, + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), ); @@ -807,21 +1054,26 @@ void main() { recipient: recipient, ); - verify(() => ethereumAbiCoder.encode(["address", "address"], [token0Address, token1Address])).called(1); + verify( + () => ethereumAbiCoder.encode([ + "tuple(address,address,address,address,uint24,bytes32)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], any(that: ObjectParamMatcher((object) => object[0].last == parameters))), + ).called(1); }, ); test( - "When calling `sendV4PoolDepositTransaction` and the token0 is native the sweep action params should be correctly encoded", + """When calling `sendV4PoolDepositTransaction` and the protocol is Pancake Swap + infinity the actions should be correctly encoded""", () async { - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); - when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), - ).thenAnswer((_) async => transactionResponse); - - const token0Address = EthereumConstants.zeroAddress; + const token0Address = "0x1"; const token1Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); @@ -832,11 +1084,43 @@ void main() { final recipient = await signer.address; final tickLower = BigInt.from(321); final tickUpper = BigInt.from(1222); + final sqrtPriceX96 = BigInt.from(2167212171927187); + const parameters = "0x2186271217625167f2ffff"; + const hooks = "0x2111"; + const poolManager = "0xAAABbbaaa"; + + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => pancakeSwapInfinityCLPositionManagerImpl.modifyLiquidities( + payload: any(named: "payload"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => + (lpFee: BigInt.from(0), protocolFee: BigInt.from(0), sqrtPriceX96: sqrtPriceX96, tick: BigInt.from(0)), + ); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.poolIdToPoolKey(id: any(named: "id"))).thenAnswer( + (_) async => ( + currency0: token0Address, + currency1: token1Address, + fee: BigInt.from(21), + hooks: hooks, + parameters: parameters, + poolManager: poolManager, + ), + ); final currentYield0 = currentYield.copyWith( chainId: network.chainId, - v4StateView: "0x1", + v4PoolManager: poolManager, + v4Hooks: hooks, poolType: PoolType.v4, + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), ); @@ -855,26 +1139,24 @@ void main() { ); verify( - () => ethereumAbiCoder.encode( - ["address", "address"], - [EthereumConstants.zeroAddress, recipient], + () => ethereumAbiCoder.encodePacked( + ["uint8", "uint8", "uint8"], + [ + V4PoolConstants.mintPositionActionValue, + V4PoolConstants.pancakeSwapCloseCurrencyActionValue, + V4PoolConstants.pancakeSwapCloseCurrencyActionValue, + ], ), ).called(1); }, ); test( - "When calling `sendV4PoolDepositTransaction` and the token1 is native the sweep action params should be correctly encoded", + """When calling `sendV4PoolDepositTransaction` and the protocol is Pancake Swap + infinity the close currency action should be correctly encoded for token1 and token0""", () async { - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); - when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), - ).thenAnswer((_) async => transactionResponse); - - const token0Address = "0x2"; - const token1Address = EthereumConstants.zeroAddress; + const token0Address = "0x1"; + const token1Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -884,13 +1166,45 @@ void main() { final recipient = await signer.address; final tickLower = BigInt.from(321); final tickUpper = BigInt.from(1222); + final sqrtPriceX96 = BigInt.from(2167212171927187); + const parameters = "0x2186271217625167f2ffff"; + const hooks = "0x2111"; + const poolManager = "0xAAABbbaaa"; + + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => pancakeSwapInfinityCLPositionManagerImpl.modifyLiquidities( + payload: any(named: "payload"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => + (lpFee: BigInt.from(0), protocolFee: BigInt.from(0), sqrtPriceX96: sqrtPriceX96, tick: BigInt.from(0)), + ); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.poolIdToPoolKey(id: any(named: "id"))).thenAnswer( + (_) async => ( + currency0: token0Address, + currency1: token1Address, + fee: BigInt.from(21), + hooks: hooks, + parameters: parameters, + poolManager: poolManager, + ), + ); final currentYield0 = currentYield.copyWith( chainId: network.chainId, - v4StateView: "0x1", + v4PoolManager: poolManager, + v4Hooks: hooks, poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), ); await sut.sendV4PoolDepositTransaction( @@ -906,26 +1220,25 @@ void main() { recipient: recipient, ); - verify( - () => ethereumAbiCoder.encode( - ["address", "address"], - [EthereumConstants.zeroAddress, recipient], - ), - ).called(1); + verify(() => ethereumAbiCoder.encode(["address"], [token0Address])).called(1); + verify(() => ethereumAbiCoder.encode(["address"], [token1Address])).called(1); }, ); test( - """When calling `sendV4PoolDepositTransaction` and the token0 is native, - it should send the correct unlock data to the contract to add liquidity""", + "When calling `sendV4PoolDepositTransaction` the settle pair action params should be correctly encoded", () async { - const actionsEncoded = "0xhvaaa"; - const mintPositionActionParamsEncoded = "0xaaaa"; - const settlePairActionParamsEncoded = "0xbbbb"; - const sweepActionParamsEncoded = "0xcccc"; - const unlockData = "0xaaaaa77777AAA"; + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); - const token0Address = EthereumConstants.zeroAddress; + const token0Address = "0x1"; const token1Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); @@ -941,40 +1254,10 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), ); - when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); - when(() => ethereumAbiCoder.encode([ - "tuple(address,address,int32,int24,address)", - "int24", - "int24", - "uint256", - "uint128", - "uint128", - "address", - "bytes" - ], any())).thenReturn(mintPositionActionParamsEncoded); - when(() => ethereumAbiCoder.encode(["address", "address"], [token0Address, token1Address])) - .thenReturn(settlePairActionParamsEncoded); - - when(() => ethereumAbiCoder.encode(["address", "address"], [EthereumConstants.zeroAddress, recipient])) - .thenReturn(sweepActionParamsEncoded); - - when(() => ethereumAbiCoder.encode([ - "bytes", - "bytes[]" - ], [ - actionsEncoded, - [mintPositionActionParamsEncoded, settlePairActionParamsEncoded, sweepActionParamsEncoded] - ])).thenReturn(unlockData); - - when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), - ).thenAnswer((_) async => transactionResponse); - await sut.sendV4PoolDepositTransaction( currentYield0, signer, @@ -988,28 +1271,25 @@ void main() { recipient: recipient, ); - verify( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: unlockData, - deadline: any(named: "deadline"), - ethValue: any(named: "ethValue"), - ), - ).called(1); + verify(() => ethereumAbiCoder.encode(["address", "address"], [token0Address, token1Address])).called(1); }, ); test( - """When calling `sendV4PoolDepositTransaction` and the token1 is native, - it should send the correct unlock data to the contract to add liquidity""", + "When calling `sendV4PoolDepositTransaction` and the token0 is native the sweep action params should be correctly encoded", () async { - const actionsEncoded = "0xhvaaa"; - const mintPositionActionParamsEncoded = "0xaaaa"; - const settlePairActionParamsEncoded = "0xbbbb"; - const sweepActionParamsEncoded = "0xcccc"; - const unlockData = "0xaaaaa77777AAA"; + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); - const token1Address = EthereumConstants.zeroAddress; - const token0Address = "0x2"; + const token0Address = EthereumConstants.zeroAddress; + const token1Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -1024,40 +1304,62 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), ); - when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); - when(() => ethereumAbiCoder.encode([ - "tuple(address,address,int32,int24,address)", - "int24", - "int24", - "uint256", - "uint128", - "uint128", - "address", - "bytes" - ], any())).thenReturn(mintPositionActionParamsEncoded); - when(() => ethereumAbiCoder.encode(["address", "address"], [token0Address, token1Address])) - .thenReturn(settlePairActionParamsEncoded); - - when(() => ethereumAbiCoder.encode(["address", "address"], [EthereumConstants.zeroAddress, recipient])) - .thenReturn(sweepActionParamsEncoded); + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); - when(() => ethereumAbiCoder.encode([ - "bytes", - "bytes[]" - ], [ - actionsEncoded, - [mintPositionActionParamsEncoded, settlePairActionParamsEncoded, sweepActionParamsEncoded] - ])).thenReturn(unlockData); + verify( + () => ethereumAbiCoder.encode(["address", "address"], [EthereumConstants.zeroAddress, recipient]), + ).called(1); + }, + ); + test( + "When calling `sendV4PoolDepositTransaction` and the token1 is native the sweep action params should be correctly encoded", + () async { + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), ).thenAnswer((_) async => transactionResponse); + const token0Address = "0x2"; + const token1Address = EthereumConstants.zeroAddress; + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + v4StateView: "0x1", + poolType: PoolType.v4, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + await sut.sendV4PoolDepositTransaction( currentYield0, signer, @@ -1072,25 +1374,22 @@ void main() { ); verify( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: unlockData, - deadline: any(named: "deadline"), - ethValue: any(named: "ethValue"), - ), + () => ethereumAbiCoder.encode(["address", "address"], [EthereumConstants.zeroAddress, recipient]), ).called(1); }, ); test( - """When calling `sendV4PoolDepositTransaction` and none of the tokens are native, - it should send the correct unlock data to the contract to add liquidity (without sweep)""", + """When calling `sendV4PoolDepositTransaction` and the token0 is native, + it should send the correct unlock data to the contract to add liquidity""", () async { const actionsEncoded = "0xhvaaa"; const mintPositionActionParamsEncoded = "0xaaaa"; const settlePairActionParamsEncoded = "0xbbbb"; + const sweepActionParamsEncoded = "0xcccc"; const unlockData = "0xaaaaa77777AAA"; - const token0Address = "0x1"; + const token0Address = EthereumConstants.zeroAddress; const token1Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); @@ -1110,31 +1409,43 @@ void main() { token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), ); - when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8"], any())).thenReturn(actionsEncoded); - when(() => ethereumAbiCoder.encode([ - "tuple(address,address,int32,int24,address)", - "int24", - "int24", - "uint256", - "uint128", - "uint128", - "address", - "bytes" - ], any())).thenReturn(mintPositionActionParamsEncoded); - when(() => ethereumAbiCoder.encode(["address", "address"], [token0Address, token1Address])) - .thenReturn(settlePairActionParamsEncoded); + when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); + when( + () => ethereumAbiCoder.encode([ + "tuple(address,address,int32,int24,address)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], any()), + ).thenReturn(mintPositionActionParamsEncoded); + when( + () => ethereumAbiCoder.encode(["address", "address"], [token0Address, token1Address]), + ).thenReturn(settlePairActionParamsEncoded); - when(() => ethereumAbiCoder.encode([ - "bytes", - "bytes[]" - ], [ + when( + () => ethereumAbiCoder.encode(["address", "address"], [EthereumConstants.zeroAddress, recipient]), + ).thenReturn(sweepActionParamsEncoded); + + when( + () => ethereumAbiCoder.encode( + ["bytes", "bytes[]"], + [ actionsEncoded, - [mintPositionActionParamsEncoded, settlePairActionParamsEncoded] - ])).thenReturn(unlockData); + [mintPositionActionParamsEncoded, settlePairActionParamsEncoded, sweepActionParamsEncoded], + ], + ), + ).thenReturn(unlockData); when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), ).thenAnswer((_) async => transactionResponse); await sut.sendV4PoolDepositTransaction( @@ -1151,7 +1462,7 @@ void main() { ); verify( - () => positionManagerV4Impl.modifyLiquidities( + () => uniswapPositionManagerV4Impl.modifyLiquidities( unlockData: unlockData, deadline: any(named: "deadline"), ethValue: any(named: "ethValue"), @@ -1161,66 +1472,17 @@ void main() { ); test( - """When calling `sendV4PoolDepositTransaction` it should send the correct deadline to the contract to add liquidity - (now + deadline)""", + """When calling `sendV4PoolDepositTransaction`, the protocol is pancake swap + infinity CL and the token0 is native, + it should send the correct payload data to the contract to add liquidity""", () async { - withClock(Clock(() => DateTime(2022, 1, 1)), () async { - const token0Address = "0x1"; - const token1Address = "0x2"; - const network = AppNetworks.mainnet; - final amount0Desired = BigInt.from(4311); - final amount1Desired = BigInt.from(1031900); - const deadline = Duration(days: 1); - final amount0Max = BigInt.from(4312); - final amount1Max = BigInt.from(1031901); - final recipient = await signer.address; - final tickLower = BigInt.from(321); - final tickUpper = BigInt.from(1222); - - final currentYield0 = currentYield.copyWith( - chainId: network.chainId, - v4StateView: "0x1", - poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), - ); - - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); - - when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), - ).thenAnswer((_) async => transactionResponse); - - await sut.sendV4PoolDepositTransaction( - currentYield0, - signer, - deadline: deadline, - tickLower: tickLower, - tickUpper: tickUpper, - amount0toDeposit: amount0Desired, - amount1ToDeposit: amount1Desired, - maxAmount0ToDeposit: amount0Max, - maxAmount1ToDeposit: amount1Max, - recipient: recipient, - ); - - verify( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), - deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), - ethValue: any(named: "ethValue"), - ), - ).called(1); - }); - }, - ); + const actionsEncoded = "0xhvaaa"; + const mintPositionActionParamsEncoded = "0xaaaa"; + const closeCurrency0ActionParamsEncoded = "0xbbbb"; + const closeCurrency1ActionParamsEncoded = "0xxxx"; + const payloadData = "0xaaaaa77777AAA"; - test( - """When calling `sendV4PoolDepositTransaction` and none of the tokens are native, it should not send any eth value""", - () async { - const token0Address = "0x1"; + const token0Address = EthereumConstants.zeroAddress; const token1Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); @@ -1232,20 +1494,68 @@ void main() { final tickLower = BigInt.from(321); final tickUpper = BigInt.from(1222); + when(() => pancakeSwapInfinityCLPoolManagerImpl.poolIdToPoolKey(id: any(named: "id"))).thenAnswer( + (_) async => ( + currency0: token0Address, + currency1: token1Address, + fee: BigInt.from(21), + hooks: "", + parameters: "", + poolManager: "", + ), + ); + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => ( + lpFee: BigInt.from(21), + protocolFee: BigInt.from(21), + sqrtPriceX96: BigInt.from(21), + tick: BigInt.from(21), + ), + ); + final currentYield0 = currentYield.copyWith( chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, + v4PoolManager: "0xbvv", + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), ); - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); + when( + () => ethereumAbiCoder.encode([ + "tuple(address,address,address,address,uint24,bytes32)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], any()), + ).thenReturn(mintPositionActionParamsEncoded); + + when(() => ethereumAbiCoder.encode(["address"], [token0Address])).thenReturn(closeCurrency0ActionParamsEncoded); + when(() => ethereumAbiCoder.encode(["address"], [token1Address])).thenReturn(closeCurrency1ActionParamsEncoded); when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), + () => ethereumAbiCoder.encode( + ["bytes", "bytes[]"], + [ + actionsEncoded, + [mintPositionActionParamsEncoded, closeCurrency0ActionParamsEncoded, closeCurrency1ActionParamsEncoded], + ], + ), + ).thenReturn(payloadData); + + when( + () => pancakeSwapInfinityCLPositionManagerImpl.modifyLiquidities( + payload: any(named: "payload"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), ).thenAnswer((_) async => transactionResponse); await sut.sendV4PoolDepositTransaction( @@ -1262,21 +1572,28 @@ void main() { ); verify( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), + () => pancakeSwapInfinityCLPositionManagerImpl.modifyLiquidities( + payload: payloadData, deadline: any(named: "deadline"), - ethValue: null, + ethValue: any(named: "ethValue"), ), ).called(1); }, ); test( - """When calling `sendV4PoolDepositTransaction` and the token0 is native, it should send the eth value from the - token0amount""", + """When calling `sendV4PoolDepositTransaction`, the protocol is pancake swap + infinity CL and the token1 is native, + it should send the correct payload data to the contract to add liquidity""", () async { - const token0Address = EthereumConstants.zeroAddress; - const token1Address = "0x2"; + const actionsEncoded = "0xhvaaa"; + const mintPositionActionParamsEncoded = "0xaaaa"; + const closeCurrency0ActionParamsEncoded = "0xbbbb"; + const closeCurrency1ActionParamsEncoded = "0xxxx"; + const payloadData = "0xaaaaa77777AAA"; + + const token1Address = EthereumConstants.zeroAddress; + const token0Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -1287,20 +1604,68 @@ void main() { final tickLower = BigInt.from(321); final tickUpper = BigInt.from(1222); + when(() => pancakeSwapInfinityCLPoolManagerImpl.poolIdToPoolKey(id: any(named: "id"))).thenAnswer( + (_) async => ( + currency0: token0Address, + currency1: token1Address, + fee: BigInt.from(21), + hooks: "", + parameters: "", + poolManager: "", + ), + ); + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => ( + lpFee: BigInt.from(21), + protocolFee: BigInt.from(21), + sqrtPriceX96: BigInt.from(21), + tick: BigInt.from(21), + ), + ); + final currentYield0 = currentYield.copyWith( chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, + v4PoolManager: "0xbvv", + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), ); - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); + when( + () => ethereumAbiCoder.encode([ + "tuple(address,address,address,address,uint24,bytes32)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], any()), + ).thenReturn(mintPositionActionParamsEncoded); + + when(() => ethereumAbiCoder.encode(["address"], [token0Address])).thenReturn(closeCurrency0ActionParamsEncoded); + when(() => ethereumAbiCoder.encode(["address"], [token1Address])).thenReturn(closeCurrency1ActionParamsEncoded); + + when( + () => ethereumAbiCoder.encode( + ["bytes", "bytes[]"], + [ + actionsEncoded, + [mintPositionActionParamsEncoded, closeCurrency0ActionParamsEncoded, closeCurrency1ActionParamsEncoded], + ], + ), + ).thenReturn(payloadData); when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), + () => pancakeSwapInfinityCLPositionManagerImpl.modifyLiquidities( + payload: any(named: "payload"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), ).thenAnswer((_) async => transactionResponse); await sut.sendV4PoolDepositTransaction( @@ -1317,21 +1682,27 @@ void main() { ); verify( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), + () => pancakeSwapInfinityCLPositionManagerImpl.modifyLiquidities( + payload: payloadData, deadline: any(named: "deadline"), - ethValue: amount0Desired, + ethValue: any(named: "ethValue"), ), ).called(1); }, ); test( - """When calling `sendV4PoolDepositTransaction` and the token1 is native, it should send the eth value from the - token1amount""", + """When calling `sendV4PoolDepositTransaction` and the token1 is native, + it should send the correct unlock data to the contract to add liquidity""", () async { - const token0Address = "0x1"; + const actionsEncoded = "0xhvaaa"; + const mintPositionActionParamsEncoded = "0xaaaa"; + const settlePairActionParamsEncoded = "0xbbbb"; + const sweepActionParamsEncoded = "0xcccc"; + const unlockData = "0xaaaaa77777AAA"; + const token1Address = EthereumConstants.zeroAddress; + const token0Address = "0x2"; const network = AppNetworks.mainnet; final amount0Desired = BigInt.from(4311); final amount1Desired = BigInt.from(1031900); @@ -1350,12 +1721,43 @@ void main() { token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), ); - when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); - when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); + when( + () => ethereumAbiCoder.encode([ + "tuple(address,address,int32,int24,address)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], any()), + ).thenReturn(mintPositionActionParamsEncoded); + when( + () => ethereumAbiCoder.encode(["address", "address"], [token0Address, token1Address]), + ).thenReturn(settlePairActionParamsEncoded); + + when( + () => ethereumAbiCoder.encode(["address", "address"], [EthereumConstants.zeroAddress, recipient]), + ).thenReturn(sweepActionParamsEncoded); + + when( + () => ethereumAbiCoder.encode( + ["bytes", "bytes[]"], + [ + actionsEncoded, + [mintPositionActionParamsEncoded, settlePairActionParamsEncoded, sweepActionParamsEncoded], + ], + ), + ).thenReturn(unlockData); when( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), deadline: any(named: "deadline"), ethValue: any(named: "ethValue")), + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), ).thenAnswer((_) async => transactionResponse); await sut.sendV4PoolDepositTransaction( @@ -1372,136 +1774,1718 @@ void main() { ); verify( - () => positionManagerV4Impl.modifyLiquidities( - unlockData: any(named: "unlockData"), + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: unlockData, deadline: any(named: "deadline"), - ethValue: amount1Desired, + ethValue: any(named: "ethValue"), ), ).called(1); }, ); test( - """"When calling `getPoolTick` and the yield protocol is pancakeswap infinity cl, - it should use the pancakeswap inifity cl pool manager to get the tick""", + """When calling `sendV4PoolDepositTransaction` and none of the tokens are native, + it should send the correct unlock data to the contract to add liquidity (without sweep)""", () async { - final expectedTick = BigInt.from(318675); - - when(() => pancakeSwapInfinityCLPoolManager.fromRpcProvider( - contractAddress: any(named: "contractAddress"), rpcUrl: any(named: "rpcUrl"))).thenReturn( - pancakeSwapInfinityCLPoolManagerImpl, - ); + const actionsEncoded = "0xhvaaa"; + const mintPositionActionParamsEncoded = "0xaaaa"; + const settlePairActionParamsEncoded = "0xbbbb"; + const unlockData = "0xaaaaa77777AAA"; + + const token0Address = "0x1"; + const token1Address = "0x2"; + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + v4StateView: "0x1", + poolType: PoolType.v4, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8"], any())).thenReturn(actionsEncoded); + when( + () => ethereumAbiCoder.encode([ + "tuple(address,address,int32,int24,address)", + "int24", + "int24", + "uint256", + "uint128", + "uint128", + "address", + "bytes", + ], any()), + ).thenReturn(mintPositionActionParamsEncoded); + when( + () => ethereumAbiCoder.encode(["address", "address"], [token0Address, token1Address]), + ).thenReturn(settlePairActionParamsEncoded); + + when( + () => ethereumAbiCoder.encode( + ["bytes", "bytes[]"], + [ + actionsEncoded, + [mintPositionActionParamsEncoded, settlePairActionParamsEncoded], + ], + ), + ).thenReturn(unlockData); + + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); + + verify( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: unlockData, + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).called(1); + }, + ); + + test( + """When calling `sendV4PoolDepositTransaction` it should send the correct deadline to the contract to add liquidity + (now + deadline)""", + () async { + withClock(Clock(() => DateTime(2022, 1, 1)), () async { + const token0Address = "0x1"; + const token1Address = "0x2"; + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + v4StateView: "0x1", + poolType: PoolType.v4, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); + + verify( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + ethValue: any(named: "ethValue"), + ), + ).called(1); + }); + }, + ); + + test( + """When calling `sendV4PoolDepositTransaction` and none of the tokens are native, it should not send any eth value""", + () async { + const token0Address = "0x1"; + const token1Address = "0x2"; + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + v4StateView: "0x1", + poolType: PoolType.v4, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); + + verify( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: null, + ), + ).called(1); + }, + ); + + test( + """When calling `sendV4PoolDepositTransaction` and the token0 is native, it should send the eth value from the + token0amount""", + () async { + const token0Address = EthereumConstants.zeroAddress; + const token1Address = "0x2"; + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + v4StateView: "0x1", + poolType: PoolType.v4, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); + + verify( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: amount0Desired, + ), + ).called(1); + }, + ); + + test( + """When calling `sendV4PoolDepositTransaction` and the token1 is native, it should send the eth value from the + token1amount""", + () async { + const token0Address = "0x1"; + const token1Address = EthereumConstants.zeroAddress; + const network = AppNetworks.mainnet; + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Max = BigInt.from(4312); + final amount1Max = BigInt.from(1031901); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + final currentYield0 = currentYield.copyWith( + chainId: network.chainId, + v4StateView: "0x1", + poolType: PoolType.v4, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); + when(() => ethereumAbiCoder.encode(any(), any())).thenReturn("0x"); + + when( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + await sut.sendV4PoolDepositTransaction( + currentYield0, + signer, + deadline: deadline, + tickLower: tickLower, + tickUpper: tickUpper, + amount0toDeposit: amount0Desired, + amount1ToDeposit: amount1Desired, + maxAmount0ToDeposit: amount0Max, + maxAmount1ToDeposit: amount1Max, + recipient: recipient, + ); + + verify( + () => uniswapPositionManagerV4Impl.modifyLiquidities( + unlockData: any(named: "unlockData"), + deadline: any(named: "deadline"), + ethValue: amount1Desired, + ), + ).called(1); + }, + ); + + test( + """"When calling `getPoolTick` and the yield protocol is pancakeswap infinity cl, + it should use the pancakeswap inifity cl pool manager to get the tick""", + () async { + final expectedTick = BigInt.from(318675); + + when( + () => pancakeSwapInfinityCLPoolManager.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(pancakeSwapInfinityCLPoolManagerImpl); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => + (sqrtPriceX96: BigInt.from(0), tick: expectedTick, protocolFee: BigInt.from(0), lpFee: BigInt.from(0)), + ); + + final yield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), + v4PoolManager: "0x0000001", + ); + + final receivedPoolTick = await sut.getPoolTick(yield0); + expect(receivedPoolTick, expectedTick); + + verify(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: yield0.poolAddress)).called(1); + }, + ); + + test( + """When calling `getSqrtPriceX96` and the yield protocol is pancakeswap infinity cl, + it should use the pancakeswap inifity cl pool manager to get the sqrtPriceX96 from the + slot0""", + () async { + final expectedSqrtPriceX96 = BigInt.parse("3256723627823257362"); + + final yield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), + v4PoolManager: "0x0000001", + ); + + when( + () => pancakeSwapInfinityCLPoolManager.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(pancakeSwapInfinityCLPoolManagerImpl); + + when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer( + (_) async => ( + sqrtPriceX96: expectedSqrtPriceX96, + tick: BigInt.from(0), + protocolFee: BigInt.from(0), + lpFee: BigInt.from(0), + ), + ); + + final receivedSqrtPriceX96 = await sut.getSqrtPriceX96(yield0); + + expect(receivedSqrtPriceX96, expectedSqrtPriceX96); + }, + ); + + test( + """When calling `getSqrtPriceX96` and the yield pool is v4, + it should use the v4 state view get the sqrtPriceX96 from the + slot0""", + () async { + final expectedSqrtPriceX96 = BigInt.parse("1216426515276100"); + + final yield0 = currentYield.copyWith(poolType: PoolType.v4, v4StateView: "0x0000001"); + + when( + () => stateView.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(uniswapV4StateViewImpl); + + when(() => uniswapV4StateViewImpl.getSlot0(poolId: any(named: "poolId"))).thenAnswer( + (_) async => ( + sqrtPriceX96: expectedSqrtPriceX96, + tick: BigInt.from(0), + protocolFee: BigInt.from(0), + lpFee: BigInt.from(0), + ), + ); + + final receivedSqrtPriceX96 = await sut.getSqrtPriceX96(yield0); + + expect(receivedSqrtPriceX96, expectedSqrtPriceX96); + }, + ); + + test( + """When calling `getSqrtPriceX96` and the yield pool is v3, + it should use the pool contract get the sqrtPriceX96 from the + slot0""", + () async { + final expectedSqrtPriceX96 = BigInt.parse("907219862715267517621"); + + final yield0 = currentYield.copyWith(poolType: PoolType.v3, poolAddress: "0x0000001"); + + when( + () => uniswapV3Pool.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(uniswapV3PoolImpl); + + when(() => uniswapV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + feeProtocol: BigInt.from(0), + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + observationIndex: BigInt.from(0), + sqrtPriceX96: expectedSqrtPriceX96, + tick: BigInt.from(0), + unlocked: true, + ), + ); + + final receivedSqrtPriceX96 = await sut.getSqrtPriceX96(yield0); + + expect(receivedSqrtPriceX96, expectedSqrtPriceX96); + }, + ); + + test( + """When calling `getSqrtPriceX96` and the yield pool type + is unknown, it should throw an error""", + () async { + final yield0 = currentYield.copyWith(poolType: PoolType.unknown); + + expect(() async => await sut.getSqrtPriceX96(yield0), throwsA(isA())); + }, + ); + + group( + 'When the protocol is aerodrome v3 or velodrome v3, it should use aerodrome smart contracts to interact with pools', + () { + setUp(() { + registerFallbackValue(( + amount0Desired: BigInt.zero, + amount0Min: BigInt.zero, + amount1Desired: BigInt.zero, + amount1Min: BigInt.zero, + deadline: BigInt.zero, + recipient: "", + sqrtPriceX96: BigInt.zero, + tickLower: BigInt.zero, + tickSpacing: BigInt.zero, + tickUpper: BigInt.zero, + token0: "", + token1: "", + )); + + registerFallbackValue(YieldDto.fixture()); + + when( + () => aerodromePositionManagerV3.fromSigner( + contractAddress: any(named: "contractAddress"), + signer: any(named: "signer"), + ), + ).thenReturn(aerodromePositionManagerV3Impl); + + when( + () => aerodromeV3Pool.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(aerodromeV3PoolImpl); + + when( + () => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params")), + ).thenReturn("0x0000000000000000000000000000000000000000000000000000000000000000"); + when( + () => aerodromePositionManagerV3.getRefundETHCalldata(), + ).thenReturn("0x0000000000000000000000000000000000000000000000000000000000000000"); + + when( + () => aerodromePositionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) => Future.value(transactionResponse)); + }); + + test("When the protocol is aerodrome v3 it should use aerodrome v3 pool to get the pool tick", () async { + final expectedTick = BigInt.from(1271897); + + when(() => aerodromeV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + observationIndex: BigInt.from(0), + sqrtPriceX96: BigInt.from(0), + tick: expectedTick, + unlocked: true, + ), + ); + + final yield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + poolType: PoolType.v3, + chainId: AppNetworks.mainnet.chainId, + ); + + final receivedTick = await sut.getPoolTick(yield0); + + expect(receivedTick, expectedTick); + + verify(() => aerodromeV3PoolImpl.slot0()).called(1); + }); + + test("When the protocol is velodrome v3 it should use aerodrome v3 pool to get the pool tick", () async { + final expectedTick = BigInt.from(11111); + + when(() => aerodromeV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + observationIndex: BigInt.from(0), + sqrtPriceX96: BigInt.from(0), + tick: expectedTick, + unlocked: true, + ), + ); + + final yield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.velodromeSlipstream), + poolType: PoolType.v3, + chainId: AppNetworks.mainnet.chainId, + ); + + final receivedTick = await sut.getPoolTick(yield0); + + expect(receivedTick, expectedTick); + + verify(() => aerodromeV3PoolImpl.slot0()).called(1); + }); + + test( + "when calling with token0 native, it should send a multicall transaction with the mint calldata and a native refund calldata", + () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x123"}), + ); + + when(() => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => aerodromePositionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); + when( + () => aerodromePositionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(100); + final amount1Desired = BigInt.from(100); + const deadline = Duration.zero; + final amount0Min = BigInt.from(12); + final amount1Min = BigInt.from(12); + final recipient = await signer.address; + final tickLower = BigInt.from(0); + final tickUpper = BigInt.from(0); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => aerodromePositionManagerV3Impl.multicall( + data: [mintCalldata, refundCalldata], + ethValue: any(named: "ethValue"), + ), + ).called(1); + }, + ); + + test( + "when calling with token0 native, it should correctly pass the params to get the mint calldata, with the token0 being the wrapped native address", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token0Address = EthereumConstants.zeroAddress; + const token1Address = "0x20172891"; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when( + () => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params")), + ).thenReturn(mintCalldata); + when(() => aerodromePositionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); + when( + () => aerodromePositionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => aerodromePositionManagerV3.getMintCalldata( + params: ( + amount0Desired: amount0Desired, + amount0Min: amount0Min, + amount1Desired: amount1Desired, + amount1Min: amount1Min, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + tickSpacing: BigInt.from(currentYield0.tickSpacing), + sqrtPriceX96: BigInt.from(0), + token0: network.wrappedNativeTokenAddress, + token1: token1Address, + ), + ), + ).called(1); + }); + }, + ); + + test( + "when calling with token1 native, it should correctly pass the params to get the mint calldata, with the token1 being the wrapped native address", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token0Address = "0x20172891"; + const token1Address = EthereumConstants.zeroAddress; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when( + () => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params")), + ).thenReturn(mintCalldata); + when(() => aerodromePositionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); + when( + () => aerodromePositionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(100); + final amount1Desired = BigInt.from(31); + const deadline = Duration.zero; + final amount0Min = BigInt.from(320); + final amount1Min = BigInt.from(12); + final recipient = await signer.address; + final tickLower = BigInt.from(32); + final tickUpper = BigInt.from(14489); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => aerodromePositionManagerV3.getMintCalldata( + params: ( + amount0Desired: amount0Desired, + amount0Min: amount0Min, + amount1Desired: amount1Desired, + amount1Min: amount1Min, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + tickSpacing: BigInt.from(currentYield0.tickSpacing), + sqrtPriceX96: BigInt.from(0), + token0: token0Address, + token1: network.wrappedNativeTokenAddress, + ), + ), + ).called(1); + }); + }, + ); + + test("when calling with token0 native, it should correctly send the token0amount as ethValue", () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token0Address = EthereumConstants.zeroAddress; + const token1Address = "0x20172891"; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => aerodromePositionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); + when( + () => aerodromePositionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => aerodromePositionManagerV3Impl.multicall( + ethValue: amount0Desired, + data: any(named: "data"), + ), + ).called(1); + }); + }); + + test("when calling with token1 native, it should correctly send the token1amount as ethValue", () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token1Address = EthereumConstants.zeroAddress; + const token0Address = "0x20172891"; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => aerodromePositionManagerV3.getRefundETHCalldata()).thenReturn(refundCalldata); + when( + () => aerodromePositionManagerV3Impl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); - when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer((_) async => ( - sqrtPriceX96: BigInt.from(0), - tick: expectedTick, - protocolFee: BigInt.from(0), - lpFee: BigInt.from(0), - )); + verify( + () => aerodromePositionManagerV3Impl.multicall( + ethValue: amount1Desired, + data: any(named: "data"), + ), + ).called(1); + }); + }); - final yield0 = currentYield.copyWith( - protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), - v4PoolManager: "0x0000001", + test( + "When there is no native token, it should call mint in the aerodrome position manager passing the correct params", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const token1Address = "0x315768"; + const token0Address = "0x20172891"; + + when( + () => aerodromePositionManagerV3Impl.mint( + params: any(named: "params"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + initialFeeTier: 3982, + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => aerodromePositionManagerV3Impl.mint( + params: ( + token0: token0Address, + token1: token1Address, + tickSpacing: BigInt.from(currentYield0.tickSpacing), + tickLower: tickLower, + tickUpper: tickUpper, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + sqrtPriceX96: BigInt.from(0), + ), + ethValue: null, + ), + ).called(1); + }); + }, ); - final receivedPoolTick = await sut.getPoolTick(yield0); - expect(receivedPoolTick, expectedTick); + test( + """When the yield protocol is aerodrome v3 and the pool does not have native token, + it should set the sqrtPriceX96 as 0 for the pool and pass it correctly to the mint function""", + () { + withClock(Clock.fixed(DateTime(2028)), () async { + const token1Address = "0x315768"; + const token0Address = "0x20172891"; + final expectedSqrtPriceX96 = BigInt.from(0); + + when( + () => aerodromePositionManagerV3Impl.mint( + params: any(named: "params"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + when(() => uniswapV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + feeProtocol: BigInt.from(0), + sqrtPriceX96: expectedSqrtPriceX96, + tick: BigInt.from(0), + observationIndex: BigInt.from(0), + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + unlocked: false, + ), + ); + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + initialFeeTier: 3982, + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => aerodromePositionManagerV3Impl.mint( + params: any( + named: "params", + that: ObjectParamMatcher((object) => object.sqrtPriceX96 == expectedSqrtPriceX96), + ), + ethValue: null, + ), + ).called(1); + }); + }, + ); - verify(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: yield0.poolAddress)).called(1); + test( + """When the yield protocol is aerodrome v3 and the pool does have a native token, + it should set the sqrtPriceX96 as 0 for the pool and pass it correctly to the mint calldata""", + () { + withClock(Clock.fixed(DateTime(2028)), () async { + const token1Address = EthereumConstants.zeroAddress; + const token0Address = EthereumConstants.zeroAddress; + final expectedSqrtPriceX96 = BigInt.from(0); + + when( + () => aerodromePositionManagerV3Impl.mint( + params: any(named: "params"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + when(() => uniswapV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + feeProtocol: BigInt.from(0), + sqrtPriceX96: expectedSqrtPriceX96, + tick: BigInt.from(0), + observationIndex: BigInt.from(0), + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + unlocked: false, + ), + ); + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + initialFeeTier: 3982, + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => aerodromePositionManagerV3.getMintCalldata( + params: any( + named: "params", + that: ObjectParamMatcher((object) => object.sqrtPriceX96 == expectedSqrtPriceX96), + ), + ), + ).called(1); + }); + }, + ); + + test( + "When the protocol is aerodrome v3, it should use the aerodrome pool contract to get the sqrtPriceX96", + () async { + final expectedSqrtPriceX96 = BigInt.from(12718271); + when(() => aerodromeV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + sqrtPriceX96: expectedSqrtPriceX96, + tick: BigInt.from(0), + observationIndex: BigInt.from(0), + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + unlocked: false, + ), + ); + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), + initialFeeTier: 3982, + poolType: PoolType.v3, + chainId: network.chainId, + ); + + final actualSqrtPriceX96 = await sut.getSqrtPriceX96(currentYield0); + expect(actualSqrtPriceX96, expectedSqrtPriceX96); + + verify(() => aerodromeV3PoolImpl.slot0()).called(1); + }, + ); + + test( + "When the protocol is velodrome v3, it should use the aerodrome pool contract to get the sqrtPriceX96", + () async { + final expectedSqrtPriceX96 = BigInt.from(90876543); + when(() => aerodromeV3PoolImpl.slot0()).thenAnswer( + (_) async => ( + sqrtPriceX96: expectedSqrtPriceX96, + tick: BigInt.from(0), + observationIndex: BigInt.from(0), + observationCardinality: BigInt.from(0), + observationCardinalityNext: BigInt.from(0), + unlocked: false, + ), + ); + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.velodromeSlipstream), + initialFeeTier: 3982, + poolType: PoolType.v3, + chainId: network.chainId, + ); + + final actualSqrtPriceX96 = await sut.getSqrtPriceX96(currentYield0); + expect(actualSqrtPriceX96, expectedSqrtPriceX96); + + verify(() => aerodromeV3PoolImpl.slot0()).called(1); + }, + ); }, ); - test("""When calling `getSqrtPriceX96` and the yield protocol is pancakeswap infinity cl, - it should use the pancakeswap inifity cl pool manager to get the sqrtPriceX96 from the - slot0""", () async { - final expectedSqrtPriceX96 = BigInt.parse("3256723627823257362"); + group("When the protocol is GLiquid, it should use algebra 1.2.1 smart contracts to interact with the pool", () { + setUp(() async { + registerFallbackValue(( + amount0Desired: BigInt.from(0), + amount1Desired: BigInt.from(0), + deadline: BigInt.from(0), + amount0Min: BigInt.from(0), + amount1Min: BigInt.from(0), + recipient: "", + tickLower: BigInt.from(0), + tickUpper: BigInt.from(0), + deployer: "", + token0: "", + token1: "", + )); + + currentYield = currentYield.copyWith(protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3)); + when( + () => algebra121Pool.fromRpcProvider( + contractAddress: any(named: "contractAddress"), + rpcUrl: any(named: "rpcUrl"), + ), + ).thenReturn(algebra121PoolImpl); - final yield0 = currentYield.copyWith( - protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), - v4PoolManager: "0x0000001", - ); + when( + () => algebra121PositionManager.fromSigner( + contractAddress: any(named: "contractAddress"), + signer: any(named: "signer"), + ), + ).thenReturn(algebra121PositionManagerImpl); + }); + + test("When calling 'getPoolTick' it should return the pool tick got from algebra pool 1.2.1", () async { + final expectedTick = BigInt.from(12871); + when(() => algebra121PoolImpl.globalState()).thenAnswer( + (_) async => ( + price: BigInt.from(0), + tick: expectedTick, + lastFee: BigInt.from(0), + pluginConfig: BigInt.from(0), + communityFee: BigInt.from(0), + unlocked: false, + ), + ); - when(() => pancakeSwapInfinityCLPoolManager.fromRpcProvider( - contractAddress: any(named: "contractAddress"), rpcUrl: any(named: "rpcUrl"))).thenReturn( - pancakeSwapInfinityCLPoolManagerImpl, - ); + final actualTick = await sut.getPoolTick(currentYield); - when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer((_) async => ( - sqrtPriceX96: expectedSqrtPriceX96, + expect(actualTick, expectedTick); + + verify(() => algebra121PoolImpl.globalState()).called(1); + }); + + test("When calling 'getSqrtPriceX96' it should return the price from algebra pool 1.2.1", () async { + final expectedSqrtPriceX96 = BigInt.from(12617826517); + + when(() => algebra121PoolImpl.globalState()).thenAnswer( + (_) async => ( + price: expectedSqrtPriceX96, tick: BigInt.from(0), - protocolFee: BigInt.from(0), - lpFee: BigInt.from(0), - )); + lastFee: BigInt.from(0), + pluginConfig: BigInt.from(0), + communityFee: BigInt.from(0), + unlocked: false, + ), + ); - final receivedSqrtPriceX96 = await sut.getSqrtPriceX96(yield0); + final actualSqrtPriceX96 = await sut.getSqrtPriceX96(currentYield); - expect(receivedSqrtPriceX96, expectedSqrtPriceX96); - }); + expect(actualSqrtPriceX96, expectedSqrtPriceX96); - test("""When calling `getSqrtPriceX96` and the yield pool is v4, - it should use the v4 state view get the sqrtPriceX96 from the - slot0""", () async { - final expectedSqrtPriceX96 = BigInt.parse("1216426515276100"); + verify(() => algebra121PoolImpl.globalState()).called(1); + }); - final yield0 = currentYield.copyWith( - poolType: PoolType.v4, - v4StateView: "0x0000001", - ); + test( + "when calling with token0 native, it should send a multicall transaction with the mint calldata and a native refund calldata", + () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; - when(() => stateView.fromRpcProvider(contractAddress: any(named: "contractAddress"), rpcUrl: any(named: "rpcUrl"))) - .thenReturn( - stateViewImpl, - ); + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x123"}), + ); - when(() => stateViewImpl.getSlot0(poolId: any(named: "poolId"))).thenAnswer((_) async => ( - sqrtPriceX96: expectedSqrtPriceX96, - tick: BigInt.from(0), - protocolFee: BigInt.from(0), - lpFee: BigInt.from(0), - )); + when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => algebra121PositionManager.getRefundNativeTokenCalldata()).thenReturn(refundCalldata); + when( + () => algebra121PositionManagerImpl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); - final receivedSqrtPriceX96 = await sut.getSqrtPriceX96(yield0); + final amount0Desired = BigInt.from(100); + final amount1Desired = BigInt.from(100); + const deadline = Duration.zero; + final amount0Min = BigInt.from(12); + final amount1Min = BigInt.from(12); + final recipient = await signer.address; + final tickLower = BigInt.from(0); + final tickUpper = BigInt.from(0); - expect(receivedSqrtPriceX96, expectedSqrtPriceX96); - }); + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); - test("""When calling `getSqrtPriceX96` and the yield pool is v3, - it should use the pool contract get the sqrtPriceX96 from the - slot0""", () async { - final expectedSqrtPriceX96 = BigInt.parse("907219862715267517621"); + verify( + () => algebra121PositionManagerImpl.multicall( + data: [mintCalldata, refundCalldata], + ethValue: any(named: "ethValue"), + ), + ).called(1); + }, + ); - final yield0 = currentYield.copyWith( - poolType: PoolType.v3, - poolAddress: "0x0000001", + test( + "when calling with token0 native, it should correctly pass the params to get the mint calldata, with the token0 being the wrapped native address", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token0Address = EthereumConstants.zeroAddress; + const token1Address = "0x20172891"; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => algebra121PositionManager.getRefundNativeTokenCalldata()).thenReturn(refundCalldata); + when( + () => algebra121PositionManagerImpl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => algebra121PositionManager.getMintCalldata( + params: ( + amount0Desired: amount0Desired, + amount0Min: amount0Min, + amount1Desired: amount1Desired, + amount1Min: amount1Min, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + deployer: currentYield0.deployerAddress, + token0: network.wrappedNativeTokenAddress, + token1: token1Address, + ), + ), + ).called(1); + }); + }, ); - when(() => - uniswapV3Pool.fromRpcProvider(contractAddress: any(named: "contractAddress"), rpcUrl: any(named: "rpcUrl"))) - .thenReturn( - uniswapV3PoolImpl, + test( + "when calling with token1 native, it should correctly pass the params to get the mint calldata, with the token1 being the wrapped native address", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token0Address = "0x20172891"; + const token1Address = EthereumConstants.zeroAddress; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); + + when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => algebra121PositionManager.getRefundNativeTokenCalldata()).thenReturn(refundCalldata); + when( + () => algebra121PositionManagerImpl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(100); + final amount1Desired = BigInt.from(31); + const deadline = Duration.zero; + final amount0Min = BigInt.from(320); + final amount1Min = BigInt.from(12); + final recipient = await signer.address; + final tickLower = BigInt.from(32); + final tickUpper = BigInt.from(14489); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => algebra121PositionManager.getMintCalldata( + params: ( + amount0Desired: amount0Desired, + amount0Min: amount0Min, + amount1Desired: amount1Desired, + amount1Min: amount1Min, + deadline: BigInt.from(clock.now().add(deadline).millisecondsSinceEpoch), + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + deployer: currentYield0.deployerAddress, + token0: token0Address, + token1: network.wrappedNativeTokenAddress, + ), + ), + ).called(1); + }); + }, ); - when(() => uniswapV3PoolImpl.slot0()).thenAnswer((_) async => ( - feeProtocol: BigInt.from(0), - observationCardinality: BigInt.from(0), - observationCardinalityNext: BigInt.from(0), - observationIndex: BigInt.from(0), - sqrtPriceX96: expectedSqrtPriceX96, - tick: BigInt.from(0), - unlocked: true, - )); + test("when calling with token0 native, it should correctly send the token0amount as ethValue", () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token0Address = EthereumConstants.zeroAddress; + const token1Address = "0x20172891"; - final receivedSqrtPriceX96 = await sut.getSqrtPriceX96(yield0); + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + ); - expect(receivedSqrtPriceX96, expectedSqrtPriceX96); - }); + when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => algebra121PositionManager.getRefundNativeTokenCalldata()).thenReturn(refundCalldata); + when( + () => algebra121PositionManagerImpl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => algebra121PositionManagerImpl.multicall( + ethValue: amount0Desired, + data: any(named: "data"), + ), + ).called(1); + }); + }); + + test( + "when the yield has a deployer address set, and the deposit is it a native token, it should pass it to the mint calldata", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token0Address = EthereumConstants.zeroAddress; + const token1Address = "0x20172891"; + const expectedDeployer = "0xdale"; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + deployerAddress: expectedDeployer, + ); + + when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => algebra121PositionManager.getRefundNativeTokenCalldata()).thenReturn(refundCalldata); + when( + () => algebra121PositionManagerImpl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => algebra121PositionManager.getMintCalldata( + params: any(named: "params", that: ObjectParamMatcher((object) => object.deployer == expectedDeployer)), + ), + ).called(1); + }); + }, + ); + + test( + "when the yield has a deployer address set, and the deposit is with erc20, it should pass it to the mint function", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const token0Address = "0x123"; + const token1Address = "0x20172891"; + const expectedDeployer = "0xdalepapi"; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + deployerAddress: expectedDeployer, + ); + + when( + () => algebra121PositionManagerImpl.mint(params: any(named: "params")), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => algebra121PositionManagerImpl.mint( + params: any(named: "params", that: ObjectParamMatcher((object) => object.deployer == expectedDeployer)), + ), + ).called(1); + }); + }, + ); - test("""When calling `getSqrtPriceX96` and the yield pool type - is unknown, it should throw an error""", () async { - final yield0 = currentYield.copyWith( - poolType: PoolType.unknown, + test( + "when the yield has a deployer address as zero address, and the deposit is with erc20, it should pass it to the mint function", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const token0Address = "0x123"; + const token1Address = "0x20172891"; + const expectedDeployer = EthereumConstants.zeroAddress; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + deployerAddress: expectedDeployer, + ); + + when( + () => algebra121PositionManagerImpl.mint(params: any(named: "params")), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => algebra121PositionManagerImpl.mint( + params: any( + named: "params", + that: ObjectParamMatcher((object) => object.deployer == EthereumConstants.zeroAddress), + ), + ), + ).called(1); + }); + }, ); - expect(() async => await sut.getSqrtPriceX96(yield0), throwsA(isA())); + test( + "when the yield has a deployer address of address zero, and the deposit is it a native token, it should pass it to the mint calldata", + () async { + withClock(Clock.fixed(DateTime(2028)), () async { + const mintCalldata = "0x25"; + const refundCalldata = "0x26"; + const token0Address = EthereumConstants.zeroAddress; + const token1Address = "0x20172891"; + + const network = AppNetworks.mainnet; + final currentYield0 = currentYield.copyWith( + protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), + poolType: PoolType.v3, + chainId: network.chainId, + token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + deployerAddress: EthereumConstants.zeroAddress, + ); + + when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); + when(() => algebra121PositionManager.getRefundNativeTokenCalldata()).thenReturn(refundCalldata); + when( + () => algebra121PositionManagerImpl.multicall( + data: any(named: "data"), + ethValue: any(named: "ethValue"), + ), + ).thenAnswer((_) async => transactionResponse); + + final amount0Desired = BigInt.from(4311); + final amount1Desired = BigInt.from(1031900); + const deadline = Duration(days: 1); + final amount0Min = BigInt.from(1390); + final amount1Min = BigInt.from(432); + final recipient = await signer.address; + final tickLower = BigInt.from(321); + final tickUpper = BigInt.from(1222); + + await sut.sendV3PoolDepositTransaction( + currentYield0, + signer, + amount0Desired: amount0Desired, + amount1Desired: amount1Desired, + deadline: deadline, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: recipient, + tickLower: tickLower, + tickUpper: tickUpper, + ); + + verify( + () => algebra121PositionManager.getMintCalldata( + params: any( + named: "params", + that: ObjectParamMatcher((object) => object.deployer == EthereumConstants.zeroAddress), + ), + ), + ).called(1); + }); + }, + ); }); } diff --git a/test/core/v4_pool_constants_test.dart b/test/core/v4_pool_constants_test.dart index 09e994b..dd380c2 100644 --- a/test/core/v4_pool_constants_test.dart +++ b/test/core/v4_pool_constants_test.dart @@ -7,10 +7,14 @@ void main() { }); test('settlePairActionValue should return the correct value', () { - expect(V4PoolConstants.settlePairActionValue, 0x0d); + expect(V4PoolConstants.uniswapSettlePairActionValue, 0x0d); }); test('sweepActionValue should return the correct value', () { - expect(V4PoolConstants.sweepActionValue, 0x14); + expect(V4PoolConstants.uniswapSweepActionValue, 0x14); + }); + + test("close currency should return the correct value", () { + expect(V4PoolConstants.pancakeSwapCloseCurrencyActionValue, 0x12); }); } diff --git a/test/matchers.dart b/test/matchers.dart index f7da309..64945eb 100644 --- a/test/matchers.dart +++ b/test/matchers.dart @@ -15,3 +15,17 @@ class ExpectedMatcher extends Matcher { return true; } } + +class ObjectParamMatcher extends Matcher { + ObjectParamMatcher(this.matching); + + final bool Function(dynamic object) matching; + + @override + Description describe(Description description) => description.add("dale"); + + @override + bool matches(item, Map matchState) { + return matching(item); + } +} diff --git a/test/mocks.dart b/test/mocks.dart index 657af0d..cfe2bf1 100644 --- a/test/mocks.dart +++ b/test/mocks.dart @@ -11,8 +11,13 @@ import 'package:url_launcher_platform_interface/link.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; import 'package:web3kit/core/dtos/transaction_response.dart'; import 'package:web3kit/web3kit.dart'; +import 'package:zup_app/abis/aerodrome_v3_pool.abi.g.dart'; +import 'package:zup_app/abis/aerodrome_v3_position_manager.abi.g.dart'; +import 'package:zup_app/abis/algebra/v1.2.1/pool.abi.g.dart' as algebra_1_2_1_pool; +import 'package:zup_app/abis/algebra/v1.2.1/position_manager.abi.g.dart' as algebra_1_2_1_position_manager; import 'package:zup_app/abis/erc_20.abi.g.dart'; import 'package:zup_app/abis/pancake_swap_infinity_cl_pool_manager.abi.g.dart'; +import 'package:zup_app/abis/pancake_swap_infinity_cl_position_manager.abi.g.dart'; import 'package:zup_app/abis/uniswap_permit2.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart'; @@ -92,8 +97,20 @@ class PancakeSwapInfinityCLPoolManagerMock extends Mock implements PancakeSwapIn class PancakeSwapInfinityCLPoolManagerImplMock extends Mock implements PancakeSwapInfinityClPoolManagerImpl {} +class PancakeSwapInfinityCLPositionManagerMock extends Mock implements PancakeSwapInfinityClPositionManager {} + +class PancakeSwapInfinityCLPositionManagerImplMock extends Mock implements PancakeSwapInfinityClPositionManagerImpl {} + class UniswapV3PoolImplMock extends Mock implements UniswapV3PoolImpl {} +class Algebra121PositionManagerMock extends Mock implements algebra_1_2_1_position_manager.PositionManager {} + +class Algebra121PositionManagerImplMock extends Mock implements algebra_1_2_1_position_manager.PositionManagerImpl {} + +class Algebra121PoolMock extends Mock implements algebra_1_2_1_pool.Pool {} + +class Algebra121PoolImplMock extends Mock implements algebra_1_2_1_pool.PoolImpl {} + class UniswapV3PoolMock extends Mock implements UniswapV3Pool {} class WalletMock extends Mock implements Wallet {} @@ -120,6 +137,14 @@ class ZupHolderMock extends Mock implements ZupHolder {} class ProtocolRepositoryMock extends Mock implements ProtocolRepository {} +class AerodromeV3PositionManagerMock extends Mock implements AerodromeV3PositionManager {} + +class AerodromeV3PoolMock extends Mock implements AerodromeV3Pool {} + +class AerodromeV3PoolImplMock extends Mock implements AerodromeV3PoolImpl {} + +class AerodromeV3PositionManagerImplMock extends Mock implements AerodromeV3PositionManagerImpl {} + class ChangeNotifierMock extends Mock with ChangeNotifier { void notify() => notifyListeners(); } diff --git a/test/widgets/goldens/yield_card_30d.png b/test/widgets/goldens/yield_card_30d.png index ca9d642..c547c19 100644 Binary files a/test/widgets/goldens/yield_card_30d.png and b/test/widgets/goldens/yield_card_30d.png differ diff --git a/test/widgets/goldens/yield_card_7d.png b/test/widgets/goldens/yield_card_7d.png index b08c0fb..c35f2fe 100644 Binary files a/test/widgets/goldens/yield_card_7d.png and b/test/widgets/goldens/yield_card_7d.png differ diff --git a/test/widgets/goldens/yield_card_90d.png b/test/widgets/goldens/yield_card_90d.png index dcbb607..45c1785 100644 Binary files a/test/widgets/goldens/yield_card_90d.png and b/test/widgets/goldens/yield_card_90d.png differ diff --git a/web/index.html b/web/index.html index 293aa35..3b64da5 100644 --- a/web/index.html +++ b/web/index.html @@ -66,6 +66,6 @@ inject(); - +