From 58ce241c632feb6cc2014a511de9beca3cd6e471 Mon Sep 17 00:00:00 2001 From: die-herdplatte <173669014+die-herdplatte@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:02:37 +0200 Subject: [PATCH 01/58] Add support for Ekubo MEV-resist extension --- foundry/lib/ekubo/interfaces/ICore.sol | 6 +- .../lib/ekubo/interfaces/IFlashAccountant.sol | 12 +- foundry/lib/ekubo/types/poolKey.sol | 10 +- foundry/src/executors/EkuboExecutor.sol | 153 +++++++++++++----- foundry/test/TychoRouterTestSetup.sol | 9 +- foundry/test/executors/EkuboExecutor.t.sol | 86 ++++++++-- 6 files changed, 214 insertions(+), 62 deletions(-) diff --git a/foundry/lib/ekubo/interfaces/ICore.sol b/foundry/lib/ekubo/interfaces/ICore.sol index d2388e8..cb43b8d 100644 --- a/foundry/lib/ekubo/interfaces/ICore.sol +++ b/foundry/lib/ekubo/interfaces/ICore.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.26; import {IFlashAccountant} from "./IFlashAccountant.sol"; -import {EkuboPoolKey} from "../types/poolKey.sol"; +import {PoolKey} from "../types/poolKey.sol"; import {SqrtRatio} from "../types/sqrtRatio.sol"; interface ICore is IFlashAccountant { function swap_611415377( - EkuboPoolKey memory poolKey, + PoolKey memory poolKey, int128 amount, bool isToken1, SqrtRatio sqrtRatioLimit, uint256 skipAhead ) external payable returns (int128 delta0, int128 delta1); -} \ No newline at end of file +} diff --git a/foundry/lib/ekubo/interfaces/IFlashAccountant.sol b/foundry/lib/ekubo/interfaces/IFlashAccountant.sol index 2524078..5682e25 100644 --- a/foundry/lib/ekubo/interfaces/IFlashAccountant.sol +++ b/foundry/lib/ekubo/interfaces/IFlashAccountant.sol @@ -10,7 +10,17 @@ interface IPayer { } interface IFlashAccountant { + // Forward the lock from the current locker to the given address + // Any additional calldata is also passed through to the forwardee, with no additional encoding + // In addition, any data returned from IForwardee#forwarded is also returned from this function exactly as is, i.e. with no additional encoding or decoding + // Reverts are also bubbled up + function forward(address to) external; + // Withdraws a token amount from the accountant to the given recipient. // The contract must be locked, as it tracks the withdrawn amount against the current locker's delta. - function withdraw(address token, address recipient, uint128 amount) external; + function withdraw( + address token, + address recipient, + uint128 amount + ) external; } diff --git a/foundry/lib/ekubo/types/poolKey.sol b/foundry/lib/ekubo/types/poolKey.sol index ad20db8..ad375a4 100644 --- a/foundry/lib/ekubo/types/poolKey.sol +++ b/foundry/lib/ekubo/types/poolKey.sol @@ -1,12 +1,20 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; +using {extension} for Config global; + // address (20 bytes) | fee (8 bytes) | tickSpacing (4 bytes) type Config is bytes32; // Each pool has its own state associated with this key -struct EkuboPoolKey { +struct PoolKey { address token0; address token1; Config config; } + +function extension(Config config) pure returns (address e) { + assembly ("memory-safe") { + e := shr(96, config) + } +} diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index 63a57b3..f149234 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -9,8 +9,8 @@ import {ILocker, IPayer} from "@ekubo/interfaces/IFlashAccountant.sol"; import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol"; import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol"; import {LibBytes} from "@solady/utils/LibBytes.sol"; -import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.sol"; -import {MAX_SQRT_RATIO, MIN_SQRT_RATIO} from "@ekubo/types/sqrtRatio.sol"; +import {Config, PoolKey} from "@ekubo/types/poolKey.sol"; +import {MAX_SQRT_RATIO, MIN_SQRT_RATIO, SqrtRatio} from "@ekubo/types/sqrtRatio.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; import "@openzeppelin/contracts/utils/Address.sol"; @@ -26,6 +26,7 @@ contract EkuboExecutor is error EkuboExecutor__UnknownCallback(); ICore immutable core; + address immutable mevResist; uint256 constant POOL_DATA_OFFSET = 57; uint256 constant HOP_BYTE_LEN = 52; @@ -33,30 +34,34 @@ contract EkuboExecutor is bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256) bytes4 constant PAY_CALLBACK_SELECTOR = 0x599d0714; // payCallback(uint256,address) + uint256 constant SKIP_AHEAD = 0; + using SafeERC20 for IERC20; - constructor(address _core, address _permit2) - RestrictTransferFrom(_permit2) - { + constructor( + address _core, + address _mevResist, + address _permit2 + ) RestrictTransferFrom(_permit2) { core = ICore(_core); + mevResist = _mevResist; } - function swap(uint256 amountIn, bytes calldata data) - external - payable - returns (uint256 calculatedAmount) - { + function swap( + uint256 amountIn, + bytes calldata data + ) external payable returns (uint256 calculatedAmount) { if (data.length < 92) revert EkuboExecutor__InvalidDataLength(); // amountIn must be at most type(int128).MAX - calculatedAmount = - uint256(_lock(bytes.concat(bytes16(uint128(amountIn)), data))); + calculatedAmount = uint256( + _lock(bytes.concat(bytes16(uint128(amountIn)), data)) + ); } - function handleCallback(bytes calldata raw) - external - returns (bytes memory) - { + function handleCallback( + bytes calldata raw + ) external returns (bytes memory) { verifyCallback(raw); // Without selector and locker id @@ -89,15 +94,12 @@ contract EkuboExecutor is } } - function payCallback(uint256, address /*token*/ ) external coreOnly { + function payCallback(uint256, address /*token*/) external coreOnly { // Without selector and locker id _payCallback(msg.data[36:]); } - function _lock(bytes memory data) - internal - returns (uint128 swappedAmount) - { + function _lock(bytes memory data) internal returns (uint128 swappedAmount) { address target = address(core); // slither-disable-next-line assembly @@ -131,29 +133,56 @@ contract EkuboExecutor is address nextTokenIn = tokenIn; - uint256 hopsLength = (swapData.length - POOL_DATA_OFFSET) / HOP_BYTE_LEN; + uint256 hopsLength = (swapData.length - POOL_DATA_OFFSET) / + HOP_BYTE_LEN; uint256 offset = POOL_DATA_OFFSET; for (uint256 i = 0; i < hopsLength; i++) { - address nextTokenOut = - address(bytes20(LibBytes.loadCalldata(swapData, offset))); - Config poolConfig = - Config.wrap(LibBytes.loadCalldata(swapData, offset + 20)); - - (address token0, address token1, bool isToken1) = nextTokenIn - > nextTokenOut - ? (nextTokenOut, nextTokenIn, true) - : (nextTokenIn, nextTokenOut, false); - - // slither-disable-next-line calls-loop - (int128 delta0, int128 delta1) = core.swap_611415377( - EkuboPoolKey(token0, token1, poolConfig), - nextAmountIn, - isToken1, - isToken1 ? MAX_SQRT_RATIO : MIN_SQRT_RATIO, - 0 + address nextTokenOut = address( + bytes20(LibBytes.loadCalldata(swapData, offset)) ); + Config poolConfig = Config.wrap( + LibBytes.loadCalldata(swapData, offset + 20) + ); + + ( + address token0, + address token1, + bool isToken1, + SqrtRatio sqrtRatioLimit + ) = nextTokenIn > nextTokenOut + ? (nextTokenOut, nextTokenIn, true, MAX_SQRT_RATIO) + : (nextTokenIn, nextTokenOut, false, MIN_SQRT_RATIO); + + PoolKey memory pk = PoolKey(token0, token1, poolConfig); + + int128 delta0; + int128 delta1; + + if (poolConfig.extension() == mevResist) { + (delta0, delta1) = abi.decode( + _forward( + mevResist, + abi.encode( + pk, + nextAmountIn, + isToken1, + sqrtRatioLimit, + SKIP_AHEAD + ) + ), + (int128, int128) + ); + } else { + (delta0, delta1) = core.swap_611415377( + pk, + nextAmountIn, + isToken1, + sqrtRatioLimit, + SKIP_AHEAD + ); + } nextTokenIn = nextTokenOut; nextAmountIn = -(isToken1 ? delta0 : delta1); @@ -166,9 +195,49 @@ contract EkuboExecutor is return nextAmountIn; } - function _pay(address token, uint128 amount, TransferType transferType) - internal - { + function _forward( + address to, + bytes memory data + ) internal returns (bytes memory result) { + address target = address(core); + + assembly ("memory-safe") { + // We will store result where the free memory pointer is now, ... + result := mload(0x40) + + // But first use it to store the calldata + + // Selector of forward(address) + mstore(result, shl(224, 0x101e8952)) + mstore(add(result, 4), to) + + // We only copy the data, not the length, because the length is read from the calldata size + let len := mload(data) + mcopy(add(result, 36), add(data, 32), len) + + // If the call failed, pass through the revert + if iszero(call(gas(), target, 0, result, add(36, len), 0, 0)) { + returndatacopy(result, 0, returndatasize()) + revert(result, returndatasize()) + } + + // Copy the entire return data into the space where the result is pointing + mstore(result, returndatasize()) + returndatacopy(add(result, 32), 0, returndatasize()) + + // Update the free memory pointer to be after the end of the data, aligned to the next 32 byte word + mstore( + 0x40, + and(add(add(result, add(32, returndatasize())), 31), not(31)) + ) + } + } + + function _pay( + address token, + uint128 amount, + TransferType transferType + ) internal { address target = address(core); if (token == NATIVE_TOKEN_ADDRESS) { diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index 925fafa..da1291c 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.26; import "../src/executors/BalancerV2Executor.sol"; import "../src/executors/CurveExecutor.sol"; -import "../src/executors/EkuboExecutor.sol"; +import {EkuboExecutor} from "../src/executors/EkuboExecutor.sol"; import "../src/executors/UniswapV2Executor.sol"; import "../src/executors/UniswapV3Executor.sol"; import "../src/executors/UniswapV4Executor.sol"; @@ -116,6 +116,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { bytes32 initCodePancakeV3 = PANCAKEV3_POOL_CODE_INIT_HASH; address poolManagerAddress = 0x000000000004444c5dc75cB358380D2e3dE08A90; address ekuboCore = 0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444; + address ekuboMevResist = 0x553a2EFc570c9e104942cEC6aC1c18118e54C091; IPoolManager poolManager = IPoolManager(poolManagerAddress); usv2Executor = @@ -127,7 +128,11 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { factoryPancakeV3, initCodePancakeV3, PERMIT2_ADDRESS ); balancerv2Executor = new BalancerV2Executor(PERMIT2_ADDRESS); - ekuboExecutor = new EkuboExecutor(ekuboCore, PERMIT2_ADDRESS); + ekuboExecutor = new EkuboExecutor( + ekuboCore, + ekuboMevResist, + PERMIT2_ADDRESS + ); curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS); maverickv2Executor = new MaverickV2Executor(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); diff --git a/foundry/test/executors/EkuboExecutor.t.sol b/foundry/test/executors/EkuboExecutor.t.sol index 7fa3eb1..8168016 100644 --- a/foundry/test/executors/EkuboExecutor.t.sol +++ b/foundry/test/executors/EkuboExecutor.t.sol @@ -18,22 +18,29 @@ contract EkuboExecutorTest is Constants, TestUtils { IERC20 USDT = IERC20(USDT_ADDR); address constant CORE_ADDRESS = 0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444; + address constant MEV_RESIST_ADDRESS = + 0x553a2EFc570c9e104942cEC6aC1c18118e54C091; bytes32 constant ORACLE_CONFIG = 0x51d02a5948496a67827242eabc5725531342527c000000000000000000000000; - function setUp() public { - vm.createSelectFork(vm.rpcUrl("mainnet"), 22082754); + // 0.01% fee and 0.02% tick spacing + bytes32 constant MEV_RESIST_POOL_CONFIG = + 0x553a2EFc570c9e104942cEC6aC1c18118e54C09100068db8bac710cb000000c8; + + modifier setUpFork(uint256 blockNumber) { + vm.createSelectFork(vm.rpcUrl("mainnet"), blockNumber); deployCodeTo( "executors/EkuboExecutor.sol", - abi.encode(CORE_ADDRESS, PERMIT2_ADDRESS), + abi.encode(CORE_ADDRESS, MEV_RESIST_ADDRESS, PERMIT2_ADDRESS), EXECUTOR_ADDRESS ); executor = EkuboExecutor(payable(EXECUTOR_ADDRESS)); + _; } - function testSingleSwapEth() public { + function testSingleSwapEth() public setUpFork(22722989) { uint256 amountIn = 1 ether; deal(address(executor), amountIn); @@ -59,10 +66,14 @@ contract EkuboExecutorTest is Constants, TestUtils { console.log(amountOut); assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore + amountIn); - assertEq(address(executor).balance, ethBalanceBeforeExecutor - amountIn); + assertEq( + address(executor).balance, + ethBalanceBeforeExecutor - amountIn + ); assertEq( - USDC.balanceOf(CORE_ADDRESS), usdcBalanceBeforeCore - amountOut + USDC.balanceOf(CORE_ADDRESS), + usdcBalanceBeforeCore - amountOut ); assertEq( USDC.balanceOf(address(executor)), @@ -70,7 +81,7 @@ contract EkuboExecutorTest is Constants, TestUtils { ); } - function testSingleSwapERC20() public { + function testSingleSwapERC20() public setUpFork(22722989) { uint256 amountIn = 1_000_000_000; deal(USDC_ADDR, address(executor), amountIn); @@ -95,7 +106,10 @@ contract EkuboExecutorTest is Constants, TestUtils { console.log(amountOut); - assertEq(USDC.balanceOf(CORE_ADDRESS), usdcBalanceBeforeCore + amountIn); + assertEq( + USDC.balanceOf(CORE_ADDRESS), + usdcBalanceBeforeCore + amountIn + ); assertEq( USDC.balanceOf(address(executor)), usdcBalanceBeforeExecutor - amountIn @@ -103,7 +117,49 @@ contract EkuboExecutorTest is Constants, TestUtils { assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore - amountOut); assertEq( - address(executor).balance, ethBalanceBeforeExecutor + amountOut + address(executor).balance, + ethBalanceBeforeExecutor + amountOut + ); + } + + function testMevResist() public setUpFork(22722989) { + uint256 amountIn = 1_000_000_000; + + deal(USDC_ADDR, address(executor), amountIn); + + uint256 usdcBalanceBeforeCore = USDC.balanceOf(CORE_ADDRESS); + uint256 usdcBalanceBeforeExecutor = USDC.balanceOf(address(executor)); + + uint256 ethBalanceBeforeCore = CORE_ADDRESS.balance; + uint256 ethBalanceBeforeExecutor = address(executor).balance; + + bytes memory data = abi.encodePacked( + uint8(RestrictTransferFrom.TransferType.Transfer), // transferNeeded (transfer from executor to core) + address(executor), // receiver + USDC_ADDR, // tokenIn + NATIVE_TOKEN_ADDRESS, // tokenOut + MEV_RESIST_POOL_CONFIG // config + ); + + uint256 gasBefore = gasleft(); + uint256 amountOut = executor.swap(amountIn, data); + console.log(gasBefore - gasleft()); + + console.log(amountOut); + + assertEq( + USDC.balanceOf(CORE_ADDRESS), + usdcBalanceBeforeCore + amountIn + ); + assertEq( + USDC.balanceOf(address(executor)), + usdcBalanceBeforeExecutor - amountIn + ); + + assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore - amountOut); + assertEq( + address(executor).balance, + ethBalanceBeforeExecutor + amountOut ); } @@ -126,10 +182,14 @@ contract EkuboExecutorTest is Constants, TestUtils { console.log(amountOut); assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore + amountIn); - assertEq(address(executor).balance, ethBalanceBeforeExecutor - amountIn); + assertEq( + address(executor).balance, + ethBalanceBeforeExecutor - amountIn + ); assertEq( - USDT.balanceOf(CORE_ADDRESS), usdtBalanceBeforeCore - amountOut + USDT.balanceOf(CORE_ADDRESS), + usdtBalanceBeforeCore - amountOut ); assertEq( USDT.balanceOf(address(executor)), @@ -138,7 +198,7 @@ contract EkuboExecutorTest is Constants, TestUtils { } // Same test case as in swap_encoder::tests::ekubo::test_encode_swap_multi - function testMultiHopSwap() public { + function testMultiHopSwap() public setUpFork(22082754) { bytes memory data = abi.encodePacked( uint8(RestrictTransferFrom.TransferType.Transfer), // transferNeeded (transfer from executor to core) address(executor), // receiver @@ -154,7 +214,7 @@ contract EkuboExecutorTest is Constants, TestUtils { } // Data is generated by test case in swap_encoder::tests::ekubo::test_encode_swap_multi - function testMultiHopSwapIntegration() public { + function testMultiHopSwapIntegration() public setUpFork(22082754) { multiHopSwap(loadCallDataFromFile("test_ekubo_encode_swap_multi")); } } From 72553bf98d432963851c07fba10b91f42ab7a3e6 Mon Sep 17 00:00:00 2001 From: die-herdplatte <173669014+die-herdplatte@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:34:31 +0200 Subject: [PATCH 02/58] Fix slither issues --- foundry/lib/ekubo/types/poolKey.sol | 1 + foundry/src/executors/EkuboExecutor.sol | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/foundry/lib/ekubo/types/poolKey.sol b/foundry/lib/ekubo/types/poolKey.sol index ad375a4..a3f2bc3 100644 --- a/foundry/lib/ekubo/types/poolKey.sol +++ b/foundry/lib/ekubo/types/poolKey.sol @@ -14,6 +14,7 @@ struct PoolKey { } function extension(Config config) pure returns (address e) { + // slither-disable-next-line assembly assembly ("memory-safe") { e := shr(96, config) } diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index f149234..e072810 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -21,6 +21,7 @@ contract EkuboExecutor is ICallback, RestrictTransferFrom { + error EkuboExecutor__AddressZero(); error EkuboExecutor__InvalidDataLength(); error EkuboExecutor__CoreOnly(); error EkuboExecutor__UnknownCallback(); @@ -44,6 +45,10 @@ contract EkuboExecutor is address _permit2 ) RestrictTransferFrom(_permit2) { core = ICore(_core); + + if (_mevResist == address(0)) { + revert EkuboExecutor__AddressZero(); + } mevResist = _mevResist; } @@ -175,6 +180,7 @@ contract EkuboExecutor is (int128, int128) ); } else { + // slither-disable-next-line calls-loop (delta0, delta1) = core.swap_611415377( pk, nextAmountIn, @@ -201,6 +207,7 @@ contract EkuboExecutor is ) internal returns (bytes memory result) { address target = address(core); + // slither-disable-next-line assembly assembly ("memory-safe") { // We will store result where the free memory pointer is now, ... result := mload(0x40) From b331a43392d3a55f30d3a3955b8acde24340fd27 Mon Sep 17 00:00:00 2001 From: die-herdplatte <173669014+die-herdplatte@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:22:34 +0200 Subject: [PATCH 03/58] forge fmt --- foundry/src/executors/EkuboExecutor.sol | 81 +++++++++++----------- foundry/test/TychoRouterTestSetup.sol | 7 +- foundry/test/executors/EkuboExecutor.t.sol | 32 +++------ 3 files changed, 49 insertions(+), 71 deletions(-) diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index e072810..2718841 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -10,7 +10,11 @@ import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol"; import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol"; import {LibBytes} from "@solady/utils/LibBytes.sol"; import {Config, PoolKey} from "@ekubo/types/poolKey.sol"; -import {MAX_SQRT_RATIO, MIN_SQRT_RATIO, SqrtRatio} from "@ekubo/types/sqrtRatio.sol"; +import { + MAX_SQRT_RATIO, + MIN_SQRT_RATIO, + SqrtRatio +} from "@ekubo/types/sqrtRatio.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; import "@openzeppelin/contracts/utils/Address.sol"; @@ -39,11 +43,9 @@ contract EkuboExecutor is using SafeERC20 for IERC20; - constructor( - address _core, - address _mevResist, - address _permit2 - ) RestrictTransferFrom(_permit2) { + constructor(address _core, address _mevResist, address _permit2) + RestrictTransferFrom(_permit2) + { core = ICore(_core); if (_mevResist == address(0)) { @@ -52,21 +54,22 @@ contract EkuboExecutor is mevResist = _mevResist; } - function swap( - uint256 amountIn, - bytes calldata data - ) external payable returns (uint256 calculatedAmount) { + function swap(uint256 amountIn, bytes calldata data) + external + payable + returns (uint256 calculatedAmount) + { if (data.length < 92) revert EkuboExecutor__InvalidDataLength(); // amountIn must be at most type(int128).MAX - calculatedAmount = uint256( - _lock(bytes.concat(bytes16(uint128(amountIn)), data)) - ); + calculatedAmount = + uint256(_lock(bytes.concat(bytes16(uint128(amountIn)), data))); } - function handleCallback( - bytes calldata raw - ) external returns (bytes memory) { + function handleCallback(bytes calldata raw) + external + returns (bytes memory) + { verifyCallback(raw); // Without selector and locker id @@ -99,12 +102,15 @@ contract EkuboExecutor is } } - function payCallback(uint256, address /*token*/) external coreOnly { + function payCallback(uint256, address /*token*/ ) external coreOnly { // Without selector and locker id _payCallback(msg.data[36:]); } - function _lock(bytes memory data) internal returns (uint128 swappedAmount) { + function _lock(bytes memory data) + internal + returns (uint128 swappedAmount) + { address target = address(core); // slither-disable-next-line assembly @@ -138,18 +144,15 @@ contract EkuboExecutor is address nextTokenIn = tokenIn; - uint256 hopsLength = (swapData.length - POOL_DATA_OFFSET) / - HOP_BYTE_LEN; + uint256 hopsLength = (swapData.length - POOL_DATA_OFFSET) / HOP_BYTE_LEN; uint256 offset = POOL_DATA_OFFSET; for (uint256 i = 0; i < hopsLength; i++) { - address nextTokenOut = address( - bytes20(LibBytes.loadCalldata(swapData, offset)) - ); - Config poolConfig = Config.wrap( - LibBytes.loadCalldata(swapData, offset + 20) - ); + address nextTokenOut = + address(bytes20(LibBytes.loadCalldata(swapData, offset))); + Config poolConfig = + Config.wrap(LibBytes.loadCalldata(swapData, offset + 20)); ( address token0, @@ -157,8 +160,8 @@ contract EkuboExecutor is bool isToken1, SqrtRatio sqrtRatioLimit ) = nextTokenIn > nextTokenOut - ? (nextTokenOut, nextTokenIn, true, MAX_SQRT_RATIO) - : (nextTokenIn, nextTokenOut, false, MIN_SQRT_RATIO); + ? (nextTokenOut, nextTokenIn, true, MAX_SQRT_RATIO) + : (nextTokenIn, nextTokenOut, false, MIN_SQRT_RATIO); PoolKey memory pk = PoolKey(token0, token1, poolConfig); @@ -182,11 +185,7 @@ contract EkuboExecutor is } else { // slither-disable-next-line calls-loop (delta0, delta1) = core.swap_611415377( - pk, - nextAmountIn, - isToken1, - sqrtRatioLimit, - SKIP_AHEAD + pk, nextAmountIn, isToken1, sqrtRatioLimit, SKIP_AHEAD ); } @@ -201,10 +200,10 @@ contract EkuboExecutor is return nextAmountIn; } - function _forward( - address to, - bytes memory data - ) internal returns (bytes memory result) { + function _forward(address to, bytes memory data) + internal + returns (bytes memory result) + { address target = address(core); // slither-disable-next-line assembly @@ -240,11 +239,9 @@ contract EkuboExecutor is } } - function _pay( - address token, - uint128 amount, - TransferType transferType - ) internal { + function _pay(address token, uint128 amount, TransferType transferType) + internal + { address target = address(core); if (token == NATIVE_TOKEN_ADDRESS) { diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index da1291c..8a68568 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -128,11 +128,8 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { factoryPancakeV3, initCodePancakeV3, PERMIT2_ADDRESS ); balancerv2Executor = new BalancerV2Executor(PERMIT2_ADDRESS); - ekuboExecutor = new EkuboExecutor( - ekuboCore, - ekuboMevResist, - PERMIT2_ADDRESS - ); + ekuboExecutor = + new EkuboExecutor(ekuboCore, ekuboMevResist, PERMIT2_ADDRESS); curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS); maverickv2Executor = new MaverickV2Executor(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); diff --git a/foundry/test/executors/EkuboExecutor.t.sol b/foundry/test/executors/EkuboExecutor.t.sol index 8168016..6ddd395 100644 --- a/foundry/test/executors/EkuboExecutor.t.sol +++ b/foundry/test/executors/EkuboExecutor.t.sol @@ -66,14 +66,10 @@ contract EkuboExecutorTest is Constants, TestUtils { console.log(amountOut); assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore + amountIn); - assertEq( - address(executor).balance, - ethBalanceBeforeExecutor - amountIn - ); + assertEq(address(executor).balance, ethBalanceBeforeExecutor - amountIn); assertEq( - USDC.balanceOf(CORE_ADDRESS), - usdcBalanceBeforeCore - amountOut + USDC.balanceOf(CORE_ADDRESS), usdcBalanceBeforeCore - amountOut ); assertEq( USDC.balanceOf(address(executor)), @@ -106,10 +102,7 @@ contract EkuboExecutorTest is Constants, TestUtils { console.log(amountOut); - assertEq( - USDC.balanceOf(CORE_ADDRESS), - usdcBalanceBeforeCore + amountIn - ); + assertEq(USDC.balanceOf(CORE_ADDRESS), usdcBalanceBeforeCore + amountIn); assertEq( USDC.balanceOf(address(executor)), usdcBalanceBeforeExecutor - amountIn @@ -117,8 +110,7 @@ contract EkuboExecutorTest is Constants, TestUtils { assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore - amountOut); assertEq( - address(executor).balance, - ethBalanceBeforeExecutor + amountOut + address(executor).balance, ethBalanceBeforeExecutor + amountOut ); } @@ -147,10 +139,7 @@ contract EkuboExecutorTest is Constants, TestUtils { console.log(amountOut); - assertEq( - USDC.balanceOf(CORE_ADDRESS), - usdcBalanceBeforeCore + amountIn - ); + assertEq(USDC.balanceOf(CORE_ADDRESS), usdcBalanceBeforeCore + amountIn); assertEq( USDC.balanceOf(address(executor)), usdcBalanceBeforeExecutor - amountIn @@ -158,8 +147,7 @@ contract EkuboExecutorTest is Constants, TestUtils { assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore - amountOut); assertEq( - address(executor).balance, - ethBalanceBeforeExecutor + amountOut + address(executor).balance, ethBalanceBeforeExecutor + amountOut ); } @@ -182,14 +170,10 @@ contract EkuboExecutorTest is Constants, TestUtils { console.log(amountOut); assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore + amountIn); - assertEq( - address(executor).balance, - ethBalanceBeforeExecutor - amountIn - ); + assertEq(address(executor).balance, ethBalanceBeforeExecutor - amountIn); assertEq( - USDT.balanceOf(CORE_ADDRESS), - usdtBalanceBeforeCore - amountOut + USDT.balanceOf(CORE_ADDRESS), usdtBalanceBeforeCore - amountOut ); assertEq( USDT.balanceOf(address(executor)), From 266e30d1aa49f3ad04dddeb6a3bb047ed4db90e9 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 24 Jun 2025 11:52:12 +0100 Subject: [PATCH 04/58] feat: Deploy Balancer V3 executor Took 19 minutes --- config/executor_addresses.json | 2 +- foundry/scripts/deploy-executors.js | 2 ++ foundry/src/executors/BalancerV3Executor.sol | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/executor_addresses.json b/config/executor_addresses.json index fed287c..5881fdc 100644 --- a/config/executor_addresses.json +++ b/config/executor_addresses.json @@ -10,7 +10,7 @@ "ekubo_v2": "0xcCF8e1E39e9ddfa88282fA6a7B31eBFB41a1ED7B", "vm:curve": "0x879F3008D96EBea0fc584aD684c7Df31777F3165", "vm:maverick_v2": "0xF35e3F5F205769B41508A18787b62A21bC80200B", - "vm:balancer_v3": "0x0000000000000000000000000000000000000000" + "vm:balancer_v3": "0xec5cE4bF6FbcB7bB0148652c92a4AEC8c1d474Ec" }, "base": { "uniswap_v2": "0xF744EBfaA580cF3fFc25aD046E92BD8B770a0700", diff --git a/foundry/scripts/deploy-executors.js b/foundry/scripts/deploy-executors.js index 82a9be7..ca4adb1 100644 --- a/foundry/scripts/deploy-executors.js +++ b/foundry/scripts/deploy-executors.js @@ -78,6 +78,8 @@ const executors_to_deploy = { "0x000000000022D473030F116dDEE9F6B43aC78BA3" ] }, + // Args: Permit2 + {exchange: "BalancerV3Executor", args: ["0x000000000022D473030F116dDEE9F6B43aC78BA3"]}, ], "base": [ // Args: Factory, Pool Init Code Hash, Permit2, Fee BPS diff --git a/foundry/src/executors/BalancerV3Executor.sol b/foundry/src/executors/BalancerV3Executor.sol index 82c44ef..679dca8 100644 --- a/foundry/src/executors/BalancerV3Executor.sol +++ b/foundry/src/executors/BalancerV3Executor.sol @@ -12,7 +12,7 @@ import { VaultSwapParams } from "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; -import {ICallback} from "../../interfaces/ICallback.sol"; +import {ICallback} from "@interfaces/ICallback.sol"; error BalancerV3Executor__InvalidDataLength(); error BalancerV3Executor__SenderIsNotVault(address sender); From 5aaac2855e7bb87de980450e5f05dc07f3611516 Mon Sep 17 00:00:00 2001 From: die-herdplatte <173669014+die-herdplatte@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:42:28 +0200 Subject: [PATCH 05/58] forge fmt --- foundry/test/TychoRouterTestSetup.sol | 109 +++++++++++--------------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index ddcaec1..6f1193d 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -8,7 +8,10 @@ import {CurveExecutor} from "../src/executors/CurveExecutor.sol"; import {EkuboExecutor} from "../src/executors/EkuboExecutor.sol"; import {MaverickV2Executor} from "../src/executors/MaverickV2Executor.sol"; import {UniswapV2Executor} from "../src/executors/UniswapV2Executor.sol"; -import {UniswapV3Executor, IUniswapV3Pool} from "../src/executors/UniswapV3Executor.sol"; +import { + UniswapV3Executor, + IUniswapV3Pool +} from "../src/executors/UniswapV3Executor.sol"; import {UniswapV4Executor} from "../src/executors/UniswapV4Executor.sol"; // Test utilities and mocks @@ -38,10 +41,7 @@ contract TychoRouterExposed is TychoRouter { bool transferFromNeeded ) external { _tstoreTransferFromInfo( - tokenIn, - amountIn, - isPermit2, - transferFromNeeded + tokenIn, amountIn, isPermit2, transferFromNeeded ); } @@ -53,10 +53,10 @@ contract TychoRouterExposed is TychoRouter { return _splitSwap(amountIn, nTokens, swaps); } - function exposedSequentialSwap( - uint256 amountIn, - bytes calldata swaps - ) external returns (uint256) { + function exposedSequentialSwap(uint256 amountIn, bytes calldata swaps) + external + returns (uint256) + { return _sequentialSwap(amountIn, swaps); } } @@ -100,8 +100,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { tychoRouter.grantRole(keccak256("PAUSER_ROLE"), PAUSER); tychoRouter.grantRole(keccak256("UNPAUSER_ROLE"), UNPAUSER); tychoRouter.grantRole( - keccak256("EXECUTOR_SETTER_ROLE"), - EXECUTOR_SETTER + keccak256("EXECUTOR_SETTER_ROLE"), EXECUTOR_SETTER ); return tychoRouter; } @@ -118,34 +117,20 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address ekuboMevResist = 0x553a2EFc570c9e104942cEC6aC1c18118e54C091; IPoolManager poolManager = IPoolManager(poolManagerAddress); - usv2Executor = new UniswapV2Executor( - factoryV2, - initCodeV2, - PERMIT2_ADDRESS, - 30 - ); - usv3Executor = new UniswapV3Executor( - factoryV3, - initCodeV3, - PERMIT2_ADDRESS - ); + usv2Executor = + new UniswapV2Executor(factoryV2, initCodeV2, PERMIT2_ADDRESS, 30); + usv3Executor = + new UniswapV3Executor(factoryV3, initCodeV3, PERMIT2_ADDRESS); usv4Executor = new UniswapV4Executor(poolManager, PERMIT2_ADDRESS); pancakev3Executor = new UniswapV3Executor( - factoryPancakeV3, - initCodePancakeV3, - PERMIT2_ADDRESS + factoryPancakeV3, initCodePancakeV3, PERMIT2_ADDRESS ); balancerv2Executor = new BalancerV2Executor(PERMIT2_ADDRESS); - ekuboExecutor = new EkuboExecutor( - ekuboCore, - ekuboMevResist, - PERMIT2_ADDRESS - ); + ekuboExecutor = + new EkuboExecutor(ekuboCore, ekuboMevResist, PERMIT2_ADDRESS); curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS); - maverickv2Executor = new MaverickV2Executor( - MAVERICK_V2_FACTORY, - PERMIT2_ADDRESS - ); + maverickv2Executor = + new MaverickV2Executor(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); balancerV3Executor = new BalancerV3Executor(PERMIT2_ADDRESS); address[] memory executors = new address[](9); @@ -162,9 +147,11 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { return executors; } - function pleEncode( - bytes[] memory data - ) public pure returns (bytes memory encoded) { + function pleEncode(bytes[] memory data) + public + pure + returns (bytes memory encoded) + { for (uint256 i = 0; i < data.length; i++) { encoded = bytes.concat( encoded, @@ -173,17 +160,19 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { } } - function encodeSingleSwap( - address executor, - bytes memory protocolData - ) internal pure returns (bytes memory) { + function encodeSingleSwap(address executor, bytes memory protocolData) + internal + pure + returns (bytes memory) + { return abi.encodePacked(executor, protocolData); } - function encodeSequentialSwap( - address executor, - bytes memory protocolData - ) internal pure returns (bytes memory) { + function encodeSequentialSwap(address executor, bytes memory protocolData) + internal + pure + returns (bytes memory) + { return abi.encodePacked(executor, protocolData); } @@ -194,14 +183,9 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address executor, bytes memory protocolData ) internal pure returns (bytes memory) { - return - abi.encodePacked( - tokenInIndex, - tokenOutIndex, - split, - executor, - protocolData - ); + return abi.encodePacked( + tokenInIndex, tokenOutIndex, split, executor, protocolData + ); } function encodeUniswapV2Swap( @@ -224,15 +208,14 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { RestrictTransferFrom.TransferType transferType ) internal view returns (bytes memory) { IUniswapV3Pool pool = IUniswapV3Pool(target); - return - abi.encodePacked( - tokenIn, - tokenOut, - pool.fee(), - receiver, - target, - zero2one, - transferType - ); + return abi.encodePacked( + tokenIn, + tokenOut, + pool.fee(), + receiver, + target, + zero2one, + transferType + ); } } From 312269dabba5b0d8f303f9aba47d9456e5cd5db7 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Fri, 27 Jun 2025 09:39:13 +0100 Subject: [PATCH 06/58] fix: Fix wrong log in CurveEncoder Took 5 minutes --- src/encoding/evm/swap_encoder/swap_encoders.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index cbf33e9..84ddecd 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -440,7 +440,7 @@ impl CurveSwapEncoder { .iter() .position(|&addr| addr == token_out) .ok_or(EncodingError::FatalError(format!( - "Token in address {token_in} not found in curve pool coins" + "Token in address {token_out} not found in curve pool coins" )))?; Ok((U8::from(i), U8::from(j))) } From 0458b910abc56b171920f505ca7fc1af6eb763b5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 27 Jun 2025 09:04:43 +0000 Subject: [PATCH 07/58] chore(release): 0.101.4 [skip ci] ## [0.101.4](https://github.com/propeller-heads/tycho-execution/compare/0.101.3...0.101.4) (2025-06-27) ### Bug Fixes * Fix wrong log in CurveEncoder ([312269d](https://github.com/propeller-heads/tycho-execution/commit/312269dabba5b0d8f303f9aba47d9456e5cd5db7)) --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4004d25..81825cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.101.4](https://github.com/propeller-heads/tycho-execution/compare/0.101.3...0.101.4) (2025-06-27) + + +### Bug Fixes + +* Fix wrong log in CurveEncoder ([312269d](https://github.com/propeller-heads/tycho-execution/commit/312269dabba5b0d8f303f9aba47d9456e5cd5db7)) + ## [0.101.3](https://github.com/propeller-heads/tycho-execution/compare/0.101.2...0.101.3) (2025-06-23) diff --git a/Cargo.lock b/Cargo.lock index 4d53c90..8501128 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4658,7 +4658,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.101.3" +version = "0.101.4" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 13b398d..cba6b48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.101.3" +version = "0.101.4" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From 0f679d6e0663aba881babb09319815723cdf68e5 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Fri, 27 Jun 2025 17:58:29 +0100 Subject: [PATCH 08/58] fix: Use native token curve address and not regular zero address Took 18 minutes Took 1 minute --- src/encoding/evm/swap_encoder/swap_encoders.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 84ddecd..c7e30e6 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -407,7 +407,10 @@ impl CurveSwapEncoder { // Some curve pools support both ETH and WETH as tokens. // They do the wrapping/unwrapping inside the pool fn normalize_token(&self, token: Address, coins: &[Address]) -> Result { - let native_token_address = bytes_to_address(&self.native_token_address)?; + let native_token_address = + Address::from_str(&self.native_token_curve_address).map_err(|_| { + EncodingError::FatalError("Invalid native token curve address".to_string()) + })?; let wrapped_native_token_address = bytes_to_address(&self.wrapped_native_token_address)?; if token == native_token_address && !coins.contains(&token) { Ok(wrapped_native_token_address) From 2f161231e9e69830f7ff8162046d04e419545d13 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 27 Jun 2025 17:05:44 +0000 Subject: [PATCH 09/58] chore(release): 0.101.5 [skip ci] ## [0.101.5](https://github.com/propeller-heads/tycho-execution/compare/0.101.4...0.101.5) (2025-06-27) ### Bug Fixes * Use native token curve address and not regular zero address ([0f679d6](https://github.com/propeller-heads/tycho-execution/commit/0f679d6e0663aba881babb09319815723cdf68e5)) --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81825cd..0b52b8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.101.5](https://github.com/propeller-heads/tycho-execution/compare/0.101.4...0.101.5) (2025-06-27) + + +### Bug Fixes + +* Use native token curve address and not regular zero address ([0f679d6](https://github.com/propeller-heads/tycho-execution/commit/0f679d6e0663aba881babb09319815723cdf68e5)) + ## [0.101.4](https://github.com/propeller-heads/tycho-execution/compare/0.101.3...0.101.4) (2025-06-27) diff --git a/Cargo.lock b/Cargo.lock index 8501128..76029dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4658,7 +4658,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.101.4" +version = "0.101.5" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index cba6b48..97361f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.101.4" +version = "0.101.5" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From 3fe9906e5babb4a31af45c1d48fda3a096802fe8 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 1 Jul 2025 16:00:51 +0100 Subject: [PATCH 10/58] feat: Deploy EkuboExecutor with MEV-resist Took 31 minutes --- config/executor_addresses.json | 2 +- foundry/scripts/deploy-executors.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config/executor_addresses.json b/config/executor_addresses.json index fed287c..9790be0 100644 --- a/config/executor_addresses.json +++ b/config/executor_addresses.json @@ -7,7 +7,7 @@ "pancakeswap_v3": "0x9D32e9F569B22Ae8d8C6f788037C1CD53632A059", "uniswap_v4": "0xD11496EAb53A9521f0bC1e5c1098Ecb467103Ad9", "vm:balancer_v2": "0xB5b8dc3F0a1Be99685a0DEd015Af93bFBB55C411", - "ekubo_v2": "0xcCF8e1E39e9ddfa88282fA6a7B31eBFB41a1ED7B", + "ekubo_v2": "0x263DD7AD20983b5E0392bf1F09C4493500EDb333", "vm:curve": "0x879F3008D96EBea0fc584aD684c7Df31777F3165", "vm:maverick_v2": "0xF35e3F5F205769B41508A18787b62A21bC80200B", "vm:balancer_v3": "0x0000000000000000000000000000000000000000" diff --git a/foundry/scripts/deploy-executors.js b/foundry/scripts/deploy-executors.js index 82a9be7..82dfb9e 100644 --- a/foundry/scripts/deploy-executors.js +++ b/foundry/scripts/deploy-executors.js @@ -57,10 +57,11 @@ const executors_to_deploy = { }, // Args: Permit2 {exchange: "BalancerV2Executor", args: ["0x000000000022D473030F116dDEE9F6B43aC78BA3"]}, - // Args: Ekubo core contract, Permit2 + // Args: Ekubo core contract, mev resist, Permit2 { exchange: "EkuboExecutor", args: [ "0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444", + "0x553a2EFc570c9e104942cEC6aC1c18118e54C091", "0x000000000022D473030F116dDEE9F6B43aC78BA3" ] }, From 62583e3419d9bc3f8419fa9f299f550cdedd4d12 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 1 Jul 2025 16:07:59 +0000 Subject: [PATCH 11/58] chore(release): 0.102.0 [skip ci] ## [0.102.0](https://github.com/propeller-heads/tycho-execution/compare/0.101.5...0.102.0) (2025-07-01) ### Features * Deploy EkuboExecutor with MEV-resist ([3fe9906](https://github.com/propeller-heads/tycho-execution/commit/3fe9906e5babb4a31af45c1d48fda3a096802fe8)) --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b52b8f..aa89aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.102.0](https://github.com/propeller-heads/tycho-execution/compare/0.101.5...0.102.0) (2025-07-01) + + +### Features + +* Deploy EkuboExecutor with MEV-resist ([3fe9906](https://github.com/propeller-heads/tycho-execution/commit/3fe9906e5babb4a31af45c1d48fda3a096802fe8)) + ## [0.101.5](https://github.com/propeller-heads/tycho-execution/compare/0.101.4...0.101.5) (2025-06-27) diff --git a/Cargo.lock b/Cargo.lock index 76029dc..4e65e5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4658,7 +4658,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.101.5" +version = "0.102.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 97361f1..d304d85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.101.5" +version = "0.102.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From 0c01e61d507b6c0fcc5c53dabc13fba205d03009 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Fri, 4 Jul 2025 12:15:12 +0100 Subject: [PATCH 12/58] chore: Use tycho project in tenderly Took 15 minutes --- foundry/hardhat.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foundry/hardhat.config.js b/foundry/hardhat.config.js index e0d3d82..b68cecb 100644 --- a/foundry/hardhat.config.js +++ b/foundry/hardhat.config.js @@ -44,7 +44,7 @@ module.exports = { }, tenderly: { - project: "project", + project: "tycho", username: "tvinagre", privateVerification: false, }, From 4e49b3b99ba1f752711a6e0fdb40035d6b428522 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 7 Jul 2025 11:06:10 +0000 Subject: [PATCH 13/58] chore(release): 0.103.0 [skip ci] ## [0.103.0](https://github.com/propeller-heads/tycho-execution/compare/0.102.0...0.103.0) (2025-07-07) ### Features * Deploy Balancer V3 executor ([266e30d](https://github.com/propeller-heads/tycho-execution/commit/266e30d1aa49f3ad04dddeb6a3bb047ed4db90e9)) --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa89aa4..34d27c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.103.0](https://github.com/propeller-heads/tycho-execution/compare/0.102.0...0.103.0) (2025-07-07) + + +### Features + +* Deploy Balancer V3 executor ([266e30d](https://github.com/propeller-heads/tycho-execution/commit/266e30d1aa49f3ad04dddeb6a3bb047ed4db90e9)) + ## [0.102.0](https://github.com/propeller-heads/tycho-execution/compare/0.101.5...0.102.0) (2025-07-01) diff --git a/Cargo.lock b/Cargo.lock index 4e65e5a..df435e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4658,7 +4658,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.102.0" +version = "0.103.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index d304d85..df96172 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.102.0" +version = "0.103.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From ce1fe1dd94a4cc68e4695902c80ee30d30d7fd5e Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Mon, 7 Jul 2025 18:00:53 -0400 Subject: [PATCH 14/58] feat: UniswapXFiller skeleton --- foundry/src/uniswap_x/IReactor.sol | 31 +++++ foundry/src/uniswap_x/IReactorCallback.sol | 16 +++ foundry/src/uniswap_x/IStructs.sol | 115 ++++++++++++++++++ foundry/src/uniswap_x/UniswapXFiller.sol | 109 +++++++++++++++++ foundry/test/TychoRouter.t.sol | 1 - foundry/test/uniswap_x/UniswapXFiller.t.sol | 126 ++++++++++++++++++++ 6 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 foundry/src/uniswap_x/IReactor.sol create mode 100644 foundry/src/uniswap_x/IReactorCallback.sol create mode 100644 foundry/src/uniswap_x/IStructs.sol create mode 100644 foundry/src/uniswap_x/UniswapXFiller.sol create mode 100644 foundry/test/uniswap_x/UniswapXFiller.t.sol diff --git a/foundry/src/uniswap_x/IReactor.sol b/foundry/src/uniswap_x/IReactor.sol new file mode 100644 index 0000000..5ca5414 --- /dev/null +++ b/foundry/src/uniswap_x/IReactor.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.26; + +import {SignedOrder} from "./IStructs.sol"; +import {IReactorCallback} from "./IReactorCallback.sol"; + +/// @notice Interface for order execution reactors +interface IReactor { + /// @notice Execute a single order + /// @param order The order definition and valid signature to execute + function execute(SignedOrder calldata order) external payable; + + /// @notice Execute a single order using the given callback data + /// @param order The order definition and valid signature to execute + function executeWithCallback( + SignedOrder calldata order, + bytes calldata callbackData + ) external payable; + + /// @notice Execute the given orders at once + /// @param orders The order definitions and valid signatures to execute + function executeBatch(SignedOrder[] calldata orders) external payable; + + /// @notice Execute the given orders at once using a callback with the given callback data + /// @param orders The order definitions and valid signatures to execute + /// @param callbackData The callbackData to pass to the callback + function executeBatchWithCallback( + SignedOrder[] calldata orders, + bytes calldata callbackData + ) external payable; +} diff --git a/foundry/src/uniswap_x/IReactorCallback.sol b/foundry/src/uniswap_x/IReactorCallback.sol new file mode 100644 index 0000000..12af565 --- /dev/null +++ b/foundry/src/uniswap_x/IReactorCallback.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.26; + +import "./IStructs.sol"; + +/// @notice Callback for executing orders through a reactor. +interface IReactorCallback { + /// @notice Called by the reactor during the execution of an order + /// @param resolvedOrders Has inputs and outputs + /// @param fillData The fillData specified for an order execution + /// @dev Must have approved each token and amount in outputs to the msg.sender + function reactorCallback( + ResolvedOrder[] memory resolvedOrders, + bytes memory fillData + ) external; +} diff --git a/foundry/src/uniswap_x/IStructs.sol b/foundry/src/uniswap_x/IStructs.sol new file mode 100644 index 0000000..3781266 --- /dev/null +++ b/foundry/src/uniswap_x/IStructs.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.26; + +/// @dev external struct including a generic encoded order and swapper signature +/// The order bytes will be parsed and mapped to a ResolvedOrder in the concrete reactor contract + +struct SignedOrder { + bytes order; + bytes sig; +} + +struct OrderInfo { + // The address of the reactor that this order is targeting + // Note that this must be included in every order so the swapper + // signature commits to the specific reactor that they trust to fill their order properly + address reactor; + // The address of the user which created the order + // Note that this must be included so that order hashes are unique by swapper + address swapper; + // The nonce of the order, allowing for signature replay protection and cancellation + uint256 nonce; + // The timestamp after which this order is no longer valid + uint256 deadline; + // Custom validation contract + address additionalValidationContract; + // Encoded validation params for additionalValidationContract + bytes additionalValidationData; +} + +/// @dev tokens that need to be sent from the swapper in order to satisfy an order +struct InputToken { + address token; + uint256 amount; + // Needed for dutch decaying inputs + uint256 maxAmount; +} + +/// @dev tokens that need to be received by the recipient in order to satisfy an order +struct OutputToken { + address token; + uint256 amount; + address recipient; +} +/// @dev generic concrete order that specifies exact tokens which need to be sent and received + +struct ResolvedOrder { + OrderInfo info; + InputToken input; + OutputToken[] outputs; + bytes sig; + bytes32 hash; +} + +struct DutchOutput { + address token; + uint256 startAmount; + uint256 endAmount; + address recipient; +} + +struct DutchInput { + address token; + uint256 startAmount; + uint256 endAmount; +} + +struct ExclusiveDutchOrder { + OrderInfo info; + uint256 decayStartTime; + uint256 decayEndTime; + address exclusiveFiller; + uint256 exclusivityOverrideBps; + DutchInput input; + DutchOutput[] outputs; +} + +struct DutchOrder { + OrderInfo info; + uint256 decayStartTime; + uint256 decayEndTime; + address exclusiveFiller; + uint256 exclusivityOverrideBps; + DutchInput input; + DutchOutput[] outputs; +} + +struct CosignerData { + // The time at which the DutchOutputs start decaying + uint256 decayStartTime; + // The time at which price becomes static + uint256 decayEndTime; + // The address who has exclusive rights to the order until decayStartTime + address exclusiveFiller; + // The amount in bps that a non-exclusive filler needs to improve the outputs by to be able to fill the order + uint256 exclusivityOverrideBps; + // The tokens that the swapper will provide when settling the order + uint256 inputAmount; + // The tokens that must be received to satisfy the order + uint256[] outputAmounts; +} + +struct V2DutchOrder { + // generic order information + OrderInfo info; + // The address which must cosign the full order + address cosigner; + // The tokens that the swapper will provide when settling the order + DutchInput baseInput; + // The tokens that must be received to satisfy the order + DutchOutput[] baseOutputs; + // signed over by the cosigner + CosignerData cosignerData; + // signature from the cosigner over (orderHash || cosignerData) + bytes cosignature; +} diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol new file mode 100644 index 0000000..bbb8af3 --- /dev/null +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.26; + +import "./IReactor.sol"; +import "./IReactorCallback.sol"; +import { + SafeERC20, + IERC20 +} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/access/AccessControl.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; + +error UniswapXFiller__AddressZero(); + +contract UniswapXFiller is AccessControl, IReactorCallback { + using SafeERC20 for IERC20; + + // UniswapX V2DutchOrder Reactor + IReactor public constant USXEDAReactor = + IReactor(0x00000011F84B9aa48e5f8aA8B9897600006289Be); + address public immutable tychoRouter; + + // keccak256("NAME_OF_ROLE") : save gas on deployment + bytes32 public constant REACTOR_ROLE = + 0x39dd1d7269516fc1f719706a5e9b05cdcb1644978808b171257d9a8eab55dd57; + bytes32 public constant EXECUTOR_ROLE = + 0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63; + + event Withdrawal( + address indexed token, uint256 amount, address indexed receiver + ); + + constructor(address _tychoRouter) { + if (_tychoRouter == address(0)) revert UniswapXFiller__AddressZero(); + + _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); + _grantRole(REACTOR_ROLE, address(USXEDAReactor)); + tychoRouter = _tychoRouter; + } + + function execute(SignedOrder calldata order, bytes calldata callbackData) + external + onlyRole(EXECUTOR_ROLE) + { + USXEDAReactor.executeWithCallback(order, callbackData); + } + + function reactorCallback( + ResolvedOrder[] calldata resolvedOrders, + bytes calldata callbackData + ) external onlyRole(REACTOR_ROLE) { + // TODO + } + + /** + * @dev Allows granting roles to multiple accounts in a single call. + */ + function batchGrantRole(bytes32 role, address[] memory accounts) + external + onlyRole(DEFAULT_ADMIN_ROLE) + { + for (uint256 i = 0; i < accounts.length; i++) { + _grantRole(role, accounts[i]); + } + } + + /** + * @dev Allows withdrawing any ERC20 funds if funds get stuck in case of a bug. + */ + function withdraw(IERC20[] memory tokens, address receiver) + external + onlyRole(DEFAULT_ADMIN_ROLE) + { + if (receiver == address(0)) revert UniswapXFiller__AddressZero(); + + for (uint256 i = 0; i < tokens.length; i++) { + // slither-disable-next-line calls-loop + uint256 tokenBalance = tokens[i].balanceOf(address(this)); + if (tokenBalance > 0) { + emit Withdrawal(address(tokens[i]), tokenBalance, receiver); + tokens[i].safeTransfer(receiver, tokenBalance); + } + } + } + + /** + * @dev Allows withdrawing any NATIVE funds if funds get stuck in case of a bug. + * The contract should never hold any NATIVE tokens for security reasons. + */ + function withdrawNative(address receiver) + external + onlyRole(DEFAULT_ADMIN_ROLE) + { + if (receiver == address(0)) revert UniswapXFiller__AddressZero(); + + uint256 amount = address(this).balance; + if (amount > 0) { + emit Withdrawal(address(0), amount, receiver); + Address.sendValue(payable(receiver), amount); + } + } + + /** + * @dev Allows this contract to receive native token with empty msg.data from contracts + */ + receive() external payable { + require(msg.sender.code.length != 0); + } +} diff --git a/foundry/test/TychoRouter.t.sol b/foundry/test/TychoRouter.t.sol index fb53058..651461d 100644 --- a/foundry/test/TychoRouter.t.sol +++ b/foundry/test/TychoRouter.t.sol @@ -96,7 +96,6 @@ contract TychoRouterTest is TychoRouterTestSetup { } vm.startPrank(FUND_RESCUER); - tychoRouter.withdraw(tokens, FUND_RESCUER); // Check balances after withdrawing diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol new file mode 100644 index 0000000..c267938 --- /dev/null +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.26; + +import "@src/executors/UniswapV4Executor.sol"; +import "forge-std/Test.sol"; +import "@src/uniswap_x/UniswapXFiller.sol"; +import "../TychoRouterTestSetup.sol"; + +contract UniswapXFillerTest is Test, TychoRouterTestSetup { + address EXECUTOR = makeAddr("executor"); + address REACTOR = address(0x00000011F84B9aa48e5f8aA8B9897600006289Be); + + UniswapXFiller filler; + address fillerAddr; + + bytes32 public constant EXECUTOR_ROLE = + 0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63; + + event CallbackVerifierSet(address indexed callbackVerifier); + event Withdrawal( + address indexed token, uint256 amount, address indexed receiver + ); + + function fillerSetup() public { + vm.startPrank(ADMIN); + filler = new UniswapXFiller(tychoRouterAddr); + fillerAddr = address(filler); + filler.grantRole(keccak256("EXECUTOR_ROLE"), EXECUTOR); + vm.stopPrank(); + } + + function testTychoAddressZero() public { + vm.expectRevert(UniswapXFiller__AddressZero.selector); + filler = new UniswapXFiller(address(0)); + } + + function testWithdrawNative() public { + fillerSetup(); + vm.startPrank(ADMIN); + // Send 100 ether to filler + assertEq(fillerAddr.balance, 0); + assertEq(ADMIN.balance, 0); + vm.deal(fillerAddr, 100 ether); + vm.expectEmit(); + emit Withdrawal(address(0), 100 ether, ADMIN); + filler.withdrawNative(ADMIN); + assertEq(fillerAddr.balance, 0); + assertEq(ADMIN.balance, 100 ether); + vm.stopPrank(); + } + + function testWithdrawNativeAddressZero() public { + fillerSetup(); + vm.deal(fillerAddr, 100 ether); + vm.startPrank(ADMIN); + vm.expectRevert(UniswapXFiller__AddressZero.selector); + filler.withdrawNative(address(0)); + vm.stopPrank(); + } + + function testWithdrawNativeMissingRole() public { + fillerSetup(); + vm.deal(fillerAddr, 100 ether); + // Not role ADMIN + vm.startPrank(BOB); + vm.expectRevert(); + filler.withdrawNative(ADMIN); + vm.stopPrank(); + } + + function testWithdrawERC20Tokens() public { + fillerSetup(); + + IERC20[] memory tokens = new IERC20[](2); + tokens[0] = IERC20(WETH_ADDR); + tokens[1] = IERC20(USDC_ADDR); + for (uint256 i = 0; i < tokens.length; i++) { + deal(address(tokens[i]), fillerAddr, 100 ether); + } + + vm.startPrank(ADMIN); + filler.withdraw(tokens, ADMIN); + + // Check balances after withdrawing + for (uint256 i = 0; i < tokens.length; i++) { + // slither-disable-next-line calls-loop + assertEq(tokens[i].balanceOf(fillerAddr), 0); + // slither-disable-next-line calls-loop + assertEq(tokens[i].balanceOf(ADMIN), 100 ether); + } + vm.stopPrank(); + } + + function testWithdrawERC20TokensAddressZero() public { + fillerSetup(); + + IERC20[] memory tokens = new IERC20[](2); + tokens[0] = IERC20(WETH_ADDR); + tokens[1] = IERC20(USDC_ADDR); + for (uint256 i = 0; i < tokens.length; i++) { + deal(address(tokens[i]), fillerAddr, 100 ether); + } + + vm.startPrank(ADMIN); + vm.expectRevert(UniswapXFiller__AddressZero.selector); + filler.withdraw(tokens, address(0)); + vm.stopPrank(); + } + + function testWithdrawERC20TokensAddressMissingRole() public { + fillerSetup(); + + IERC20[] memory tokens = new IERC20[](2); + tokens[0] = IERC20(WETH_ADDR); + tokens[1] = IERC20(USDC_ADDR); + for (uint256 i = 0; i < tokens.length; i++) { + deal(address(tokens[i]), fillerAddr, 100 ether); + } + + // Not role ADMIN + vm.startPrank(BOB); + vm.expectRevert(); + filler.withdraw(tokens, ADMIN); + vm.stopPrank(); + } +} From 2733bb00724fb2df8d6f8151df02826807289c9a Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 8 Jul 2025 12:23:41 +0100 Subject: [PATCH 15/58] feat: Upgrade scripts to submit to Safe wallet Also add revoke-role.js script Took 4 hours 0 minutes --- foundry/package-lock.json | 3793 +++++++++++++++++++++++++--- foundry/package.json | 4 +- foundry/scripts/README.md | 15 +- foundry/scripts/remove-executor.js | 27 +- foundry/scripts/revoke-role.js | 51 + foundry/scripts/set-executors.js | 34 +- foundry/scripts/set-roles.js | 26 +- foundry/scripts/utils.js | 55 + 8 files changed, 3619 insertions(+), 386 deletions(-) create mode 100644 foundry/scripts/revoke-role.js create mode 100644 foundry/scripts/utils.js diff --git a/foundry/package-lock.json b/foundry/package-lock.json index 48ac1a8..b6ea69b 100644 --- a/foundry/package-lock.json +++ b/foundry/package-lock.json @@ -7,7 +7,9 @@ "name": "hardhat-project", "dependencies": { "@nomicfoundation/hardhat-foundry": "^1.1.3", - "ethers": "^5.0.0", + "@safe-global/api-kit": "^1.1.0", + "@safe-global/protocol-kit": "^1.0.1", + "ethers": "^5.8.0", "prompt-sync": "^4.2.0" }, "devDependencies": { @@ -852,10 +854,119 @@ "node": ">=12" } }, + "node_modules/@ethereumjs/common": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz", + "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz", + "integrity": "sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==", + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/common": "^2.6.4", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, "node_modules/@ethersproject/abi": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", - "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", + "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", "funding": [ { "type": "individual", @@ -867,21 +978,21 @@ } ], "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@ethersproject/abstract-provider": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", - "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", + "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", "funding": [ { "type": "individual", @@ -893,19 +1004,19 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0" } }, "node_modules/@ethersproject/abstract-signer": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", - "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", + "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", "funding": [ { "type": "individual", @@ -917,17 +1028,17 @@ } ], "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0" + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0" } }, "node_modules/@ethersproject/address": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", - "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", + "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", "funding": [ { "type": "individual", @@ -939,17 +1050,17 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/rlp": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/rlp": "^5.8.0" } }, "node_modules/@ethersproject/base64": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", - "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", + "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", "funding": [ { "type": "individual", @@ -961,13 +1072,13 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0" + "@ethersproject/bytes": "^5.8.0" } }, "node_modules/@ethersproject/basex": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", - "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.8.0.tgz", + "integrity": "sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==", "funding": [ { "type": "individual", @@ -979,14 +1090,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/properties": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/properties": "^5.8.0" } }, "node_modules/@ethersproject/bignumber": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", - "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", "funding": [ { "type": "individual", @@ -998,15 +1109,15 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", "bn.js": "^5.2.1" } }, "node_modules/@ethersproject/bytes": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", - "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", "funding": [ { "type": "individual", @@ -1018,13 +1129,13 @@ } ], "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/constants": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", - "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", "funding": [ { "type": "individual", @@ -1036,13 +1147,13 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0" } }, "node_modules/@ethersproject/contracts": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", - "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.8.0.tgz", + "integrity": "sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==", "funding": [ { "type": "individual", @@ -1054,22 +1165,22 @@ } ], "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0" + "@ethersproject/abi": "^5.8.0", + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0" } }, "node_modules/@ethersproject/hash": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", - "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", + "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", "funding": [ { "type": "individual", @@ -1081,21 +1192,21 @@ } ], "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@ethersproject/hdnode": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", - "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.8.0.tgz", + "integrity": "sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==", "funding": [ { "type": "individual", @@ -1107,24 +1218,24 @@ } ], "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/basex": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/pbkdf2": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/wordlists": "^5.8.0" } }, "node_modules/@ethersproject/json-wallets": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", - "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.8.0.tgz", + "integrity": "sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==", "funding": [ { "type": "individual", @@ -1136,25 +1247,25 @@ } ], "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hdnode": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/pbkdf2": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", "aes-js": "3.0.0", "scrypt-js": "3.0.1" } }, "node_modules/@ethersproject/keccak256": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", - "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", + "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", "funding": [ { "type": "individual", @@ -1166,14 +1277,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", "js-sha3": "0.8.0" } }, "node_modules/@ethersproject/logger": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", "funding": [ { "type": "individual", @@ -1186,9 +1297,9 @@ ] }, "node_modules/@ethersproject/networks": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", - "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", + "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", "funding": [ { "type": "individual", @@ -1200,13 +1311,13 @@ } ], "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/pbkdf2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", - "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", + "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", "funding": [ { "type": "individual", @@ -1218,14 +1329,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/sha2": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/sha2": "^5.8.0" } }, "node_modules/@ethersproject/properties": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", - "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", "funding": [ { "type": "individual", @@ -1237,13 +1348,13 @@ } ], "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/providers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", - "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.8.0.tgz", + "integrity": "sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==", "funding": [ { "type": "individual", @@ -1255,32 +1366,52 @@ } ], "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0", + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/basex": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0", "bech32": "1.1.4", - "ws": "7.4.6" + "ws": "8.18.0" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/@ethersproject/random": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", - "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.8.0.tgz", + "integrity": "sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==", "funding": [ { "type": "individual", @@ -1292,14 +1423,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/rlp": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", - "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", + "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", "funding": [ { "type": "individual", @@ -1311,14 +1442,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/sha2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", - "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", + "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", "funding": [ { "type": "individual", @@ -1330,15 +1461,15 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", "hash.js": "1.1.7" } }, "node_modules/@ethersproject/signing-key": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", - "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", "funding": [ { "type": "individual", @@ -1350,18 +1481,18 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", "bn.js": "^5.2.1", - "elliptic": "6.5.4", + "elliptic": "6.6.1", "hash.js": "1.1.7" } }, "node_modules/@ethersproject/solidity": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", - "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.8.0.tgz", + "integrity": "sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==", "funding": [ { "type": "individual", @@ -1373,18 +1504,18 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@ethersproject/strings": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", - "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", + "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", "funding": [ { "type": "individual", @@ -1396,15 +1527,15 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/transactions": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", - "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", "funding": [ { "type": "individual", @@ -1416,21 +1547,21 @@ } ], "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0" + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" } }, "node_modules/@ethersproject/units": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", - "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.8.0.tgz", + "integrity": "sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==", "funding": [ { "type": "individual", @@ -1442,15 +1573,15 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/wallet": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", - "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.8.0.tgz", + "integrity": "sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==", "funding": [ { "type": "individual", @@ -1462,27 +1593,27 @@ } ], "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/json-wallets": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/hdnode": "^5.8.0", + "@ethersproject/json-wallets": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/wordlists": "^5.8.0" } }, "node_modules/@ethersproject/web": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", - "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", + "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", "funding": [ { "type": "individual", @@ -1494,17 +1625,17 @@ } ], "dependencies": { - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@ethersproject/wordlists": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", - "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.8.0.tgz", + "integrity": "sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==", "funding": [ { "type": "individual", @@ -1516,11 +1647,11 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@fastify/busboy": { @@ -2378,6 +2509,82 @@ "node": ">=14" } }, + "node_modules/@safe-global/api-kit": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@safe-global/api-kit/-/api-kit-1.3.1.tgz", + "integrity": "sha512-JKvCNs8p+42+N8pV2MIqoXlBLckTe5CKboVT7t9mTluuA66i5W8+Kr+B5j9D//EIU5vO7iSOOIYnJuA2ck4XRQ==", + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@safe-global/safe-core-sdk-types": "^2.3.0", + "node-fetch": "^2.6.6" + } + }, + "node_modules/@safe-global/protocol-kit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@safe-global/protocol-kit/-/protocol-kit-1.3.0.tgz", + "integrity": "sha512-zBhwHpaUggywmnR1Xm5RV22DpyjmVWYP3pnOl4rcf9LAc1k7IVmw6WIt2YVhHRaWGxVYMd4RitJX8Dx2+8eLZQ==", + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/solidity": "^5.7.0", + "@safe-global/safe-deployments": "^1.26.0", + "ethereumjs-util": "^7.1.5", + "semver": "^7.5.4", + "web3": "^1.8.1", + "web3-core": "^1.8.1", + "web3-utils": "^1.8.1", + "zksync-web3": "^0.14.3" + } + }, + "node_modules/@safe-global/protocol-kit/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@safe-global/safe-core-sdk-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@safe-global/safe-core-sdk-types/-/safe-core-sdk-types-2.3.0.tgz", + "integrity": "sha512-dU0KkDV1KJNf11ajbUjWiSi4ygdyWfhk1M50lTJWUdCn1/2Bsb/hICM8LoEk6DCoFumxaoCet02SmYakXsW2CA==", + "deprecated": "WARNING: This project has been renamed to @safe-global/types-kit. Please, migrate from @safe-global/safe-core-sdk-types@5.1.0 to @safe-global/types-kit@1.0.0.", + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@safe-global/safe-deployments": "^1.26.0", + "web3-core": "^1.8.1", + "web3-utils": "^1.8.1" + } + }, + "node_modules/@safe-global/safe-deployments": { + "version": "1.37.36", + "resolved": "https://registry.npmjs.org/@safe-global/safe-deployments/-/safe-deployments-1.37.36.tgz", + "integrity": "sha512-h9vuA659vvjJKf7wgoV5iPIHXWEQMoSkXAIZ2CJEoBteP9vP4LjyuPFp+wVQ6WyQSeHi22HjrlvGXxZD72Kqqw==", + "license": "MIT", + "dependencies": { + "semver": "^7.6.2" + } + }, + "node_modules/@safe-global/safe-deployments/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@scure/base": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", @@ -2481,6 +2688,18 @@ "node": ">=6" } }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, "node_modules/@smithy/abort-controller": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", @@ -3407,6 +3626,18 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/@tenderly/api-client": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@tenderly/api-client/-/api-client-1.1.0.tgz", @@ -3701,6 +3932,33 @@ "@types/node": "*" } }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3728,6 +3986,15 @@ "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", "dev": true }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/secp256k1": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", @@ -3736,6 +4003,34 @@ "@types/node": "*" } }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.8.tgz", + "integrity": "sha512-9f1iZ2uWh92VcrU9Y8x+LdM4DLj75VE0MJB8zuF1iUnroEptStw+DQ8EQPMUdfe5k+PkB1uUfDQfWbhstH8LrQ==", + "license": "MIT" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", @@ -3933,6 +4228,30 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -3942,6 +4261,12 @@ "node": ">=8" } }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT" + }, "node_modules/async-retry": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", @@ -3963,8 +4288,37 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "license": "MIT" }, "node_modules/axios": { "version": "1.7.9", @@ -3994,7 +4348,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -4010,11 +4363,35 @@ } ] }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" + }, "node_modules/bech32": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, + "node_modules/bignumber.js": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", + "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -4031,11 +4408,71 @@ "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "license": "MIT" + }, "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/bowser": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", @@ -4155,6 +4592,25 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "license": "MIT" + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -4221,11 +4677,79 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -4235,13 +4759,13 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "dev": true, + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -4261,6 +4785,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "license": "Apache-2.0" + }, "node_modules/cbor": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", @@ -4316,6 +4846,59 @@ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" }, + "node_modules/cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "deprecated": "This module has been superseded by the multiformats module", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/cids/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/cids/node_modules/multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "deprecated": "This module has been superseded by the multiformats module", + "license": "MIT", + "dependencies": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + }, "node_modules/cipher-base": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", @@ -4328,6 +4911,12 @@ "node": ">= 0.10" } }, + "node_modules/class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "license": "MIT" + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -4372,6 +4961,18 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4392,7 +4993,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4419,6 +5019,38 @@ "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", "dev": true }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "license": "ISC", + "dependencies": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", @@ -4427,6 +5059,43 @@ "node": ">= 0.6" } }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -4458,6 +5127,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "devOptional": true }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4472,6 +5150,31 @@ "node": ">= 8" } }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -4499,6 +5202,68 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -4512,7 +5277,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -4525,6 +5289,16 @@ "node": ">= 0.8" } }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -4533,6 +5307,11 @@ "node": ">=0.3.1" } }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, "node_modules/dotenv": { "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", @@ -4549,7 +5328,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -4565,10 +5343,32 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "license": "MIT", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecc-jsbn/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -4595,11 +5395,19 @@ "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", "dev": true }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -4609,7 +5417,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -4618,6 +5425,15 @@ "node": ">=0.10.0" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enquirer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", @@ -4648,7 +5464,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -4657,7 +5472,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -4666,7 +5480,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, "dependencies": { "es-errors": "^1.3.0" }, @@ -4689,6 +5502,52 @@ "node": ">= 0.4" } }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -4697,6 +5556,12 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4708,6 +5573,104 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "license": "ISC", + "dependencies": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "node_modules/eth-ens-namehash/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "license": "MIT" + }, + "node_modules/eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/eth-lib/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/eth-lib/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/eth-lib/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz", + "integrity": "sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.4.0" + } + }, + "node_modules/ethereum-bloom-filters/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -4771,7 +5734,6 @@ "version": "7.1.5", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", - "dev": true, "dependencies": { "@types/bn.js": "^5.1.0", "bn.js": "^5.1.2", @@ -4784,9 +5746,9 @@ } }, "node_modules/ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.8.0.tgz", + "integrity": "sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==", "funding": [ { "type": "individual", @@ -4798,38 +5760,58 @@ } ], "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" + "@ethersproject/abi": "5.8.0", + "@ethersproject/abstract-provider": "5.8.0", + "@ethersproject/abstract-signer": "5.8.0", + "@ethersproject/address": "5.8.0", + "@ethersproject/base64": "5.8.0", + "@ethersproject/basex": "5.8.0", + "@ethersproject/bignumber": "5.8.0", + "@ethersproject/bytes": "5.8.0", + "@ethersproject/constants": "5.8.0", + "@ethersproject/contracts": "5.8.0", + "@ethersproject/hash": "5.8.0", + "@ethersproject/hdnode": "5.8.0", + "@ethersproject/json-wallets": "5.8.0", + "@ethersproject/keccak256": "5.8.0", + "@ethersproject/logger": "5.8.0", + "@ethersproject/networks": "5.8.0", + "@ethersproject/pbkdf2": "5.8.0", + "@ethersproject/properties": "5.8.0", + "@ethersproject/providers": "5.8.0", + "@ethersproject/random": "5.8.0", + "@ethersproject/rlp": "5.8.0", + "@ethersproject/sha2": "5.8.0", + "@ethersproject/signing-key": "5.8.0", + "@ethersproject/solidity": "5.8.0", + "@ethersproject/strings": "5.8.0", + "@ethersproject/transactions": "5.8.0", + "@ethersproject/units": "5.8.0", + "@ethersproject/wallet": "5.8.0", + "@ethersproject/web": "5.8.0", + "@ethersproject/wordlists": "5.8.0" } }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "license": "MIT", + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "license": "MIT" + }, "node_modules/ethjs-util": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", @@ -4843,6 +5825,16 @@ "npm": ">=3" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -4852,6 +5844,115 @@ "safe-buffer": "^5.1.1" } }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/express/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, "node_modules/fast-base64-decode": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", @@ -4861,8 +5962,13 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" }, "node_modules/fast-uri": { "version": "3.0.6", @@ -4926,6 +6032,39 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -4977,6 +6116,21 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", @@ -5005,6 +6159,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, "node_modules/form-data": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", @@ -5020,11 +6183,35 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "license": "MIT" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fp-ts": { "version": "1.19.3", "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==" }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -5072,7 +6259,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5086,17 +6272,17 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "get-proto": "^1.0.0", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", @@ -5113,7 +6299,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -5122,6 +6307,27 @@ "node": ">= 0.4" } }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -5152,11 +6358,20 @@ "node": ">= 6" } }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "license": "MIT", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -5164,11 +6379,83 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, "node_modules/hardhat": { "version": "2.22.18", "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.18.tgz", @@ -5462,11 +6749,22 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -5478,7 +6776,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "dependencies": { "has-symbols": "^1.0.3" }, @@ -5515,7 +6812,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -5556,8 +6852,7 @@ "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, "node_modules/http-errors": { "version": "2.0.0", @@ -5574,6 +6869,12 @@ "node": ">= 0.8" } }, + "node_modules/http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "license": "ISC" + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -5596,6 +6897,34 @@ "node": ">= 14" } }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -5619,11 +6948,31 @@ "node": ">=0.10.0" } }, + "node_modules/idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "license": "MIT", + "dependencies": { + "punycode": "2.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/idna-uts46-hx/node_modules/punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -5716,6 +7065,31 @@ "node": ">= 12" } }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -5727,6 +7101,18 @@ "node": ">=8" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -5758,6 +7144,30 @@ "node": ">=8" } }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "license": "MIT" + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -5800,6 +7210,45 @@ "node": ">=8" } }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -5845,6 +7294,12 @@ "unfetch": "^4.2.0" } }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "license": "MIT" + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -5888,6 +7343,18 @@ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", "dev": true }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -5905,8 +7372,7 @@ "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, "node_modules/json5": { "version": "2.2.3", @@ -5937,6 +7403,21 @@ "node >= 0.2.0" ] }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/keccak": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", @@ -5950,6 +7431,15 @@ "node": ">=10.0.0" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -6012,6 +7502,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", @@ -6062,7 +7564,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -6077,6 +7578,15 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -6085,11 +7595,46 @@ "node": ">= 0.10.0" } }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "license": "MIT" + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -6098,7 +7643,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -6106,6 +7650,23 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -6131,7 +7692,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6275,7 +7835,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -6283,6 +7842,19 @@ "node": ">=10" } }, + "node_modules/mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", + "license": "ISC", + "dependencies": { + "mkdirp": "*" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mnemonist": { "version": "0.38.5", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", @@ -6384,11 +7956,108 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/mock-fs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "deprecated": "This module has been superseded by the multiformats module", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/multibase/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "deprecated": "This module has been superseded by the multiformats module", + "license": "MIT", + "dependencies": { + "varint": "^5.0.0" + } + }, + "node_modules/multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "node_modules/multihashes/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/multihashes/node_modules/multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "deprecated": "This module has been superseded by the multiformats module", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, "node_modules/murmur-128": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/murmur-128/-/murmur-128-0.2.1.tgz", @@ -6400,6 +8069,12 @@ "imul": "^1.0.0" } }, + "node_modules/nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "license": "MIT" + }, "node_modules/ndjson": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", @@ -6428,6 +8103,12 @@ "node": ">= 0.6" } }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "license": "ISC" + }, "node_modules/node-addon-api": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", @@ -6437,7 +8118,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -6480,6 +8160,18 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/npm-package-arg": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", @@ -6526,11 +8218,48 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "license": "MIT", + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "license": "MIT" + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -6543,6 +8272,27 @@ "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==" }, + "node_modules/oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "license": "BSD", + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -6576,6 +8326,15 @@ "node": ">=0.10.0" } }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -6624,6 +8383,21 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true }, + "node_modules/parse-headers": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz", + "integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==", + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6662,6 +8436,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, "node_modules/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -6677,6 +8457,12 @@ "node": ">=0.12" } }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -6693,6 +8479,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/proc-log": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", @@ -6702,6 +8497,15 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", @@ -6766,12 +8570,56 @@ "signal-exit": "^3.0.2" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", @@ -6787,6 +8635,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -6795,6 +8669,15 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/raw-body": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", @@ -6834,6 +8717,71 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6862,6 +8810,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/responselike/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -6915,6 +8890,23 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6939,25 +8931,6 @@ "node": ">=18.0.0" } }, - "node_modules/secp256k1/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" - }, - "node_modules/secp256k1/node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/secp256k1/node_modules/node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", @@ -6971,6 +8944,54 @@ "semver": "bin/semver.js" } }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -6979,6 +9000,54 @@ "randombytes": "^2.1.0" } }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "license": "MIT", + "dependencies": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -7026,7 +9095,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -7045,7 +9113,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -7061,7 +9128,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -7079,7 +9145,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -7100,6 +9165,49 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "license": "MIT", + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -7208,6 +9316,43 @@ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "license": "MIT" + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" + }, "node_modules/ssri": { "version": "10.0.6", "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", @@ -7247,6 +9392,15 @@ "node": ">= 0.8" } }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -7353,6 +9507,207 @@ "node": ">=8" } }, + "node_modules/swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "license": "MIT", + "dependencies": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + } + }, + "node_modules/swarm-js/node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swarm-js/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/swarm-js/node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/swarm-js/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/swarm-js/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/swarm-js/node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "license": "ISC", + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/swarm-js/node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/swarm-js/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "license": "ISC", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/swarm-js/node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "license": "MIT", + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/swarm-js/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/swarm-js/node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "license": "ISC", + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/swarm-js/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, "node_modules/table": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", @@ -7428,6 +9783,15 @@ "readable-stream": "3" } }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tinyglobby": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", @@ -7473,11 +9837,23 @@ "node": ">=0.6" } }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/ts-node": { "version": "10.9.2", @@ -7553,6 +9929,18 @@ "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -7563,6 +9951,12 @@ "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==" }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "license": "ISC" + }, "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", @@ -7574,6 +9968,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", @@ -7587,6 +10003,12 @@ "node": ">=14.17" } }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "license": "MIT" + }, "node_modules/undici": { "version": "5.28.5", "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz", @@ -7649,11 +10071,67 @@ "node": ">= 0.8" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "license": "MIT" + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "license": "MIT" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -7677,17 +10155,543 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/web3": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.4.tgz", + "integrity": "sha512-kgJvQZjkmjOEKimx/tJQsqWfRDPTTcBfYPa9XletxuHLpHcXdx67w8EFn5AW3eVxCutE9dTVHgGa9VYe8vgsEA==", + "hasInstallScript": true, + "license": "LGPL-3.0", + "dependencies": { + "web3-bzz": "1.10.4", + "web3-core": "1.10.4", + "web3-eth": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-shh": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.4.tgz", + "integrity": "sha512-ZZ/X4sJ0Uh2teU9lAGNS8EjveEppoHNQiKlOXAjedsrdWuaMErBPdLQjXfcrYvN6WM6Su9PMsAxf3FXXZ+HwQw==", + "hasInstallScript": true, + "license": "LGPL-3.0", + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/web3-core": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.4.tgz", + "integrity": "sha512-B6elffYm81MYZDTrat7aEhnhdtVE3lDBUZft16Z8awYMZYJDbnykEbJVS+l3mnA7AQTnSDr/1MjWofGDLBJPww==", + "license": "LGPL-3.0", + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-requestmanager": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "license": "LGPL-3.0", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.4.tgz", + "integrity": "sha512-uZTb7flr+Xl6LaDsyTeE2L1TylokCJwTDrIVfIfnrGmnwLc6bmTWCCrm71sSrQ0hqs6vp/MKbQYIYqUN0J8WyA==", + "license": "LGPL-3.0", + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "license": "LGPL-3.0", + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-promievent/node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "license": "MIT" + }, + "node_modules/web3-core-requestmanager": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.4.tgz", + "integrity": "sha512-vqP6pKH8RrhT/2MoaU+DY/OsYK9h7HmEBNCdoMj+4ZwujQtw/Mq2JifjwsJ7gits7Q+HWJwx8q6WmQoVZAWugg==", + "license": "LGPL-3.0", + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.4", + "web3-providers-http": "1.10.4", + "web3-providers-ipc": "1.10.4", + "web3-providers-ws": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.4.tgz", + "integrity": "sha512-o0lSQo/N/f7/L76C0HV63+S54loXiE9fUPfHFcTtpJRQNDBVsSDdWRdePbWwR206XlsBqD5VHApck1//jEafTw==", + "license": "LGPL-3.0", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "license": "MIT" + }, + "node_modules/web3-core/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/web3-eth": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.4.tgz", + "integrity": "sha512-Sql2kYKmgt+T/cgvg7b9ce24uLS7xbFrxE4kuuor1zSCGrjhTJ5rRNG8gTJUkAJGKJc7KgnWmgW+cOfMBPUDSA==", + "license": "LGPL-3.0", + "dependencies": { + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-accounts": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-eth-ens": "1.10.4", + "web3-eth-iban": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "license": "LGPL-3.0", + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.4.tgz", + "integrity": "sha512-ysy5sVTg9snYS7tJjxVoQAH6DTOTkRGR8emEVCWNGLGiB9txj+qDvSeT0izjurS/g7D5xlMAgrEHLK1Vi6I3yg==", + "license": "LGPL-3.0", + "dependencies": { + "@ethereumjs/common": "2.6.5", + "@ethereumjs/tx": "3.5.2", + "@ethereumjs/util": "^8.1.0", + "eth-lib": "0.2.8", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/web3-eth-accounts/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/web3-eth-contract": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.4.tgz", + "integrity": "sha512-Q8PfolOJ4eV9TvnTj1TGdZ4RarpSLmHnUnzVxZ/6/NiTfe4maJz99R0ISgwZkntLhLRtw0C7LRJuklzGYCNN3A==", + "license": "LGPL-3.0", + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.4.tgz", + "integrity": "sha512-LLrvxuFeVooRVZ9e5T6OWKVflHPFgrVjJ/jtisRWcmI7KN/b64+D/wJzXqgmp6CNsMQcE7rpmf4CQmJCrTdsgg==", + "license": "LGPL-3.0", + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "license": "LGPL-3.0", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.4.tgz", + "integrity": "sha512-BRa/hs6jU1hKHz+AC/YkM71RP3f0Yci1dPk4paOic53R4ZZG4MgwKRkJhgt3/GPuPliwS46f/i5A7fEGBT4F9w==", + "license": "LGPL-3.0", + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/web3-net": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.4.tgz", + "integrity": "sha512-mKINnhOOnZ4koA+yV2OT5s5ztVjIx7IY9a03w6s+yao/BUn+Luuty0/keNemZxTr1E8Ehvtn28vbOtW7Ids+Ow==", + "license": "LGPL-3.0", + "dependencies": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.4.tgz", + "integrity": "sha512-m2P5Idc8hdiO0l60O6DSCPw0kw64Zgi0pMjbEFRmxKIck2Py57RQMu4bxvkxJwkF06SlGaEQF8rFZBmuX7aagQ==", + "license": "LGPL-3.0", + "dependencies": { + "abortcontroller-polyfill": "^1.7.5", + "cross-fetch": "^4.0.0", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.4.tgz", + "integrity": "sha512-YRF/bpQk9z3WwjT+A6FI/GmWRCASgd+gC0si7f9zbBWLXjwzYAKG73bQBaFRAHex1hl4CVcM5WUMaQXf3Opeuw==", + "license": "LGPL-3.0", + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.4.tgz", + "integrity": "sha512-j3FBMifyuFFmUIPVQR4pj+t5ILhAexAui0opgcpu9R5LxQrLRUZxHSnU+YO25UycSOa/NAX8A+qkqZNpcFAlxA==", + "license": "LGPL-3.0", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "license": "MIT" + }, + "node_modules/web3-shh": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.4.tgz", + "integrity": "sha512-cOH6iFFM71lCNwSQrC3niqDXagMqrdfFW85hC9PFUrAr3PUrIem8TNstTc3xna2bwZeWG6OBy99xSIhBvyIACw==", + "hasInstallScript": true, + "license": "LGPL-3.0", + "dependencies": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-net": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", + "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", + "license": "LGPL-3.0", + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/websocket": { + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz", + "integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==", + "license": "Apache-2.0", + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.63", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -7708,6 +10712,27 @@ "node": ">= 8" } }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -7783,6 +10808,51 @@ } } }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "license": "MIT", + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "license": "MIT", + "dependencies": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "node_modules/xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "license": "MIT", + "dependencies": { + "xhr-request": "^1.1.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -7791,6 +10861,16 @@ "node": ">=10" } }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "engines": { + "node": ">=0.10.32" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -7861,7 +10941,6 @@ "resolved": "https://registry.npmjs.org/zksync-web3/-/zksync-web3-0.14.4.tgz", "integrity": "sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg==", "deprecated": "This package has been deprecated in favor of zksync-ethers@5.0.0", - "dev": true, "peerDependencies": { "ethers": "^5.7.0" } diff --git a/foundry/package.json b/foundry/package.json index 8f8f530..b08e879 100644 --- a/foundry/package.json +++ b/foundry/package.json @@ -9,7 +9,9 @@ }, "dependencies": { "@nomicfoundation/hardhat-foundry": "^1.1.3", - "ethers": "^5.0.0", + "@safe-global/api-kit": "^1.1.0", + "@safe-global/protocol-kit": "^1.0.1", + "ethers": "^5.8.0", "prompt-sync": "^4.2.0" } } diff --git a/foundry/scripts/README.md b/foundry/scripts/README.md index 302df41..ff170e4 100644 --- a/foundry/scripts/README.md +++ b/foundry/scripts/README.md @@ -53,4 +53,17 @@ For each of the following, you must select one of `tenderly_ethereum`, `tenderly 1. If you set a new executor for the same protocol, you need to remove the old one. 2. Run: `npx hardhat run scripts/remove-executor.js --network NETWORK` -3. There will be a prompt for you to insert the executor address you want to remove. \ No newline at end of file +3. There will be a prompt for you to insert the executor address you want to remove. + +### Revoke roles + +1. If you wish to revoke a role for a certain address, run: `npx hardhat run scripts/revoke-role.js --network NETWORK` +2. There will be a prompt for you to insert the role hash and the address you want to revoke it for. + +### Safe wallet + +1. If the wallet that has the role, is a Gnosis Safe, you need to set the `SAFE_ADDRESS` env var. +2. The scripts deploy-executors, remove-executor, set-roles and revoke-role all support this. + 1. If `SAFE_ADDRESS` is set, then it will propose a transaction to the safe wallet and later on it needs to be + approved in their UI to execute on chain. + 2. If it's not set, it will submit the transaction directly to the chain. \ No newline at end of file diff --git a/foundry/scripts/remove-executor.js b/foundry/scripts/remove-executor.js index f63ff22..e4e96b7 100644 --- a/foundry/scripts/remove-executor.js +++ b/foundry/scripts/remove-executor.js @@ -1,16 +1,22 @@ require('dotenv').config(); const {ethers} = require("hardhat"); const hre = require("hardhat"); +const {proposeOrSendTransaction} = require("./utils"); const prompt = require('prompt-sync')(); async function main() { const network = hre.network.name; const routerAddress = process.env.ROUTER_ADDRESS; - console.log(`Removing executors on TychoRouter at ${routerAddress} on ${network}`); + const safeAddress = process.env.SAFE_ADDRESS; + if (!routerAddress) { + throw new Error("Missing ROUTER_ADDRESS"); + } - const [deployer] = await ethers.getSigners(); - console.log(`Removing executors with account: ${deployer.address}`); - console.log(`Account balance: ${ethers.utils.formatEther(await deployer.getBalance())} ETH`); + console.log(`Removing executor on TychoRouter at ${routerAddress} on ${network}`); + + const [signer] = await ethers.getSigners(); + console.log(`Removing executors with account: ${signer.address}`); + console.log(`Account balance: ${ethers.utils.formatEther(await signer.getBalance())} ETH`); const TychoRouter = await ethers.getContractFactory("TychoRouter"); const router = TychoRouter.attach(routerAddress); @@ -22,12 +28,15 @@ async function main() { process.exit(1); } - // Remove executor - const tx = await router.removeExecutor(executorAddress, { + const txData = { + to: router.address, + data: router.interface.encodeFunctionData("removeExecutor", [executorAddress]), + value: "0", gasLimit: 50000 - }); - await tx.wait(); // Wait for the transaction to be mined - console.log(`Executor removed at transaction: ${tx.hash}`); + }; + + const txHash = await proposeOrSendTransaction(safeAddress, txData, signer, "removeExecutor"); + console.log(`TX hash: ${txHash}`); } main() diff --git a/foundry/scripts/revoke-role.js b/foundry/scripts/revoke-role.js new file mode 100644 index 0000000..0c1439b --- /dev/null +++ b/foundry/scripts/revoke-role.js @@ -0,0 +1,51 @@ +require('dotenv').config(); +const {ethers} = require("hardhat"); +const path = require('path'); +const fs = require('fs'); +const hre = require("hardhat"); +const {proposeOrSendTransaction} = require("./utils"); +const prompt = require('prompt-sync')(); + +async function main() { + const network = hre.network.name; + const routerAddress = process.env.ROUTER_ADDRESS; + const safeAddress = process.env.SAFE_ADDRESS; + if (!routerAddress) { + throw new Error("Missing ROUTER_ADDRESS"); + } + + console.log(`Revoking role on TychoRouter at ${routerAddress} on ${network}`); + + const [signer] = await ethers.getSigners(); + console.log(`Setting roles with account: ${signer.address}`); + console.log(`Account balance: ${ethers.utils.formatEther(await signer.getBalance())} ETH`); + const TychoRouter = await ethers.getContractFactory("TychoRouter"); + const router = TychoRouter.attach(routerAddress); + + const roleHash = prompt("Enter role hash to be removed: "); + const address = prompt("Enter the address to remove: "); + + + if (!roleHash || !address) { + console.error("Please provide the executorAddress as an argument."); + process.exit(1); + } + + console.log(`Revoking ${roleHash} to the following address:`, address); + + const txData = { + to: router.address, + data: router.interface.encodeFunctionData("revokeRole", [roleHash, address]), + value: "0", + }; + + const txHash = await proposeOrSendTransaction(safeAddress, txData, signer, "revokeRole"); + console.log(`TX hash: ${txHash}`); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error("Error setting roles:", error); + process.exit(1); + }); \ No newline at end of file diff --git a/foundry/scripts/set-executors.js b/foundry/scripts/set-executors.js index 9455af6..f0de43b 100644 --- a/foundry/scripts/set-executors.js +++ b/foundry/scripts/set-executors.js @@ -1,18 +1,25 @@ require('dotenv').config(); const {ethers} = require("hardhat"); -const path = require('path'); const fs = require('fs'); -const hre = require("hardhat"); +const path = require('path'); +const {proposeOrSendTransaction} = require("./utils"); const prompt = require('prompt-sync')(); async function main() { const network = hre.network.name; const routerAddress = process.env.ROUTER_ADDRESS; + const safeAddress = process.env.SAFE_ADDRESS; + if (!routerAddress) { + throw new Error("Missing ROUTER_ADDRESS"); + } + console.log(`Setting executors on TychoRouter at ${routerAddress} on ${network}`); - const [deployer] = await ethers.getSigners(); - console.log(`Setting executors with account: ${deployer.address}`); - console.log(`Account balance: ${ethers.utils.formatEther(await deployer.getBalance())} ETH`); + const [signer] = await ethers.getSigners(); + const balance = await signer.getBalance(); + + console.log(`Using signer: ${signer.address}`); + console.log(`Account balance: ${ethers.utils.formatEther(balance)} ETH`); const TychoRouter = await ethers.getContractFactory("TychoRouter"); const router = TychoRouter.attach(routerAddress); @@ -48,13 +55,16 @@ async function main() { return; } - // Set executors - const executorAddresses = executorsToSet.map(executor => executor.executor); - const tx = await router.setExecutors(executorAddresses, { - gasLimit: 300000 // should be around 50k per executor - }); - await tx.wait(); // Wait for the transaction to be mined - console.log(`Executors set at transaction: ${tx.hash}`); + const executorAddresses = executorsToSet.map(({executor}) => executor); + const txData = { + to: router.address, + data: router.interface.encodeFunctionData("setExecutors", [executorAddresses]), + value: "0", + gasLimit: 300000 + }; + + const txHash = await proposeOrSendTransaction(safeAddress, txData, signer, "setExecutors"); + console.log(`TX hash: ${txHash}`); } main() diff --git a/foundry/scripts/set-roles.js b/foundry/scripts/set-roles.js index 3e983c2..7c7a94c 100644 --- a/foundry/scripts/set-roles.js +++ b/foundry/scripts/set-roles.js @@ -3,15 +3,21 @@ const {ethers} = require("hardhat"); const path = require('path'); const fs = require('fs'); const hre = require("hardhat"); +const {proposeOrSendTransaction} = require("./utils"); async function main() { const network = hre.network.name; const routerAddress = process.env.ROUTER_ADDRESS; + const safeAddress = process.env.SAFE_ADDRESS; + if (!routerAddress) { + throw new Error("Missing ROUTER_ADDRESS"); + } + console.log(`Setting roles on TychoRouter at ${routerAddress} on ${network}`); - const [deployer] = await ethers.getSigners(); - console.log(`Setting roles with account: ${deployer.address}`); - console.log(`Account balance: ${ethers.utils.formatEther(await deployer.getBalance())} ETH`); + const [signer] = await ethers.getSigners(); + console.log(`Setting roles with account: ${signer.address}`); + console.log(`Account balance: ${ethers.utils.formatEther(await signer.getBalance())} ETH`); const TychoRouter = await ethers.getContractFactory("TychoRouter"); const router = TychoRouter.attach(routerAddress); @@ -27,13 +33,21 @@ async function main() { }; // Iterate through roles and grant them to the corresponding addresses + let nonceOffset = 0 for (const [roleName, roleHash] of Object.entries(roles)) { const addresses = rolesDict[network][roleName]; if (addresses && addresses.length > 0) { console.log(`Granting ${roleName} to the following addresses:`, addresses); - const tx = await router.batchGrantRole(roleHash, addresses); - await tx.wait(); // Wait for the transaction to be mined - console.log(`Role ${roleName} granted at transaction: ${tx.hash}`); + + const txData = { + to: router.address, + data: router.interface.encodeFunctionData("batchGrantRole", [roleHash, addresses]), + value: "0", + }; + + const txHash = await proposeOrSendTransaction(safeAddress, txData, signer, "batchGrantRole", nonceOffset); + nonceOffset += 1 + console.log(`Role ${roleName} granted at TX hash: ${txHash}`); } else { console.log(`No addresses found for role ${roleName}`); } diff --git a/foundry/scripts/utils.js b/foundry/scripts/utils.js new file mode 100644 index 0000000..f47a85c --- /dev/null +++ b/foundry/scripts/utils.js @@ -0,0 +1,55 @@ +const {ethers} = require("hardhat"); +const Safe = require('@safe-global/protocol-kit').default; +const {EthersAdapter} = require('@safe-global/protocol-kit'); +const {default: SafeApiKit} = require("@safe-global/api-kit"); + +const txServiceUrl = 'https://safe-transaction-mainnet.safe.global'; + +async function proposeOrSendTransaction(safeAddress, txData, signer, methodName, nonceOffset = 0) { + if (safeAddress) { + return proposeTransaction(safeAddress, txData, signer, methodName, nonceOffset); + } else { + console.log(`Executing the transaction directly`); + const tx = await signer.sendTransaction(txData); + await tx.wait(); + return tx.hash; + } +} + +async function proposeTransaction(safeAddress, txData, signer, methodName, nonceOffset = 0) { + const signerAddress = await signer.getAddress(); + console.log(`Proposing transaction to Safe: ${safeAddress} with account: ${signerAddress}`); + + const ethAdapter = new EthersAdapter({ + ethers, + signerOrProvider: signer, + }); + + const safeService = new SafeApiKit({txServiceUrl, ethAdapter}); + + const safeSdk = await Safe.create({ + ethAdapter, + safeAddress, + }); + + const safeTransaction = await safeSdk.createTransaction({safeTransactionData: txData}); + const safeTxHash = await safeSdk.getTransactionHash(safeTransaction); + const senderSignature = await safeSdk.signTransactionHash(safeTxHash); + + const proposeArgs = { + safeAddress, + safeTransactionData: safeTransaction.data, + safeTxHash, + senderAddress: signerAddress, + senderSignature: senderSignature.data, + origin: `Proposed from hardhat: ${methodName}`, + nonce: await safeService.getNextNonce(safeAddress) + nonceOffset, + }; + + await safeService.proposeTransaction(proposeArgs); + return safeTxHash; +} + +module.exports = { + proposeOrSendTransaction +} \ No newline at end of file From 00f22d62c1f978f27eb5a922bc7b36af2a0b806b Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Tue, 8 Jul 2025 09:48:25 -0400 Subject: [PATCH 16/58] feat: Take reactor address as input to UniswapXFiller - Put reactor zero address check in separate line for more easy debugging. - Also includes other small cosmetic changes. --- foundry/src/uniswap_x/IStructs.sol | 3 +-- foundry/src/uniswap_x/UniswapXFiller.sol | 12 ++++++------ foundry/test/uniswap_x/UniswapXFiller.t.sol | 15 ++++++++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/foundry/src/uniswap_x/IStructs.sol b/foundry/src/uniswap_x/IStructs.sol index 3781266..9672fd2 100644 --- a/foundry/src/uniswap_x/IStructs.sol +++ b/foundry/src/uniswap_x/IStructs.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.26; /// @dev external struct including a generic encoded order and swapper signature /// The order bytes will be parsed and mapped to a ResolvedOrder in the concrete reactor contract - struct SignedOrder { bytes order; bytes sig; @@ -41,8 +40,8 @@ struct OutputToken { uint256 amount; address recipient; } -/// @dev generic concrete order that specifies exact tokens which need to be sent and received +/// @dev generic concrete order that specifies exact tokens which need to be sent and received struct ResolvedOrder { OrderInfo info; InputToken input; diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol index bbb8af3..7196a0a 100644 --- a/foundry/src/uniswap_x/UniswapXFiller.sol +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -16,8 +16,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback { using SafeERC20 for IERC20; // UniswapX V2DutchOrder Reactor - IReactor public constant USXEDAReactor = - IReactor(0x00000011F84B9aa48e5f8aA8B9897600006289Be); + IReactor public immutable USXEDAReactor; address public immutable tychoRouter; // keccak256("NAME_OF_ROLE") : save gas on deployment @@ -30,12 +29,14 @@ contract UniswapXFiller is AccessControl, IReactorCallback { address indexed token, uint256 amount, address indexed receiver ); - constructor(address _tychoRouter) { + constructor(address _tychoRouter, address _reactor) { if (_tychoRouter == address(0)) revert UniswapXFiller__AddressZero(); + if (_reactor == address(0)) revert UniswapXFiller__AddressZero(); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(REACTOR_ROLE, address(USXEDAReactor)); tychoRouter = _tychoRouter; + USXEDAReactor = IReactor(_reactor); } function execute(SignedOrder calldata order, bytes calldata callbackData) @@ -65,7 +66,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback { } /** - * @dev Allows withdrawing any ERC20 funds if funds get stuck in case of a bug. + * @dev Allows withdrawing any ERC20 funds. */ function withdraw(IERC20[] memory tokens, address receiver) external @@ -84,8 +85,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback { } /** - * @dev Allows withdrawing any NATIVE funds if funds get stuck in case of a bug. - * The contract should never hold any NATIVE tokens for security reasons. + * @dev Allows withdrawing any NATIVE funds. */ function withdrawNative(address receiver) external diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index c267938..1dc11df 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.26; -import "@src/executors/UniswapV4Executor.sol"; import "forge-std/Test.sol"; import "@src/uniswap_x/UniswapXFiller.sol"; import "../TychoRouterTestSetup.sol"; @@ -13,9 +12,6 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { UniswapXFiller filler; address fillerAddr; - bytes32 public constant EXECUTOR_ROLE = - 0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63; - event CallbackVerifierSet(address indexed callbackVerifier); event Withdrawal( address indexed token, uint256 amount, address indexed receiver @@ -23,15 +19,20 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { function fillerSetup() public { vm.startPrank(ADMIN); - filler = new UniswapXFiller(tychoRouterAddr); + filler = new UniswapXFiller(tychoRouterAddr, REACTOR); fillerAddr = address(filler); filler.grantRole(keccak256("EXECUTOR_ROLE"), EXECUTOR); vm.stopPrank(); } - function testTychoAddressZero() public { + function testTychoAddressZeroTychoRouter() public { vm.expectRevert(UniswapXFiller__AddressZero.selector); - filler = new UniswapXFiller(address(0)); + filler = new UniswapXFiller(address(0), REACTOR); + } + + function testTychoAddressZeroReactor() public { + vm.expectRevert(UniswapXFiller__AddressZero.selector); + filler = new UniswapXFiller(tychoRouterAddr, address(0)); } function testWithdrawNative() public { From d61469ea67f2c8d0f28e5185da4099260c2b69ea Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Tue, 8 Jul 2025 10:24:40 -0400 Subject: [PATCH 17/58] fix: Make slither happy Naming conventions (mixed case) for variables --- foundry/src/uniswap_x/UniswapXFiller.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol index 7196a0a..de52edd 100644 --- a/foundry/src/uniswap_x/UniswapXFiller.sol +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -16,7 +16,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback { using SafeERC20 for IERC20; // UniswapX V2DutchOrder Reactor - IReactor public immutable USXEDAReactor; + IReactor public immutable reactor; address public immutable tychoRouter; // keccak256("NAME_OF_ROLE") : save gas on deployment @@ -34,16 +34,16 @@ contract UniswapXFiller is AccessControl, IReactorCallback { if (_reactor == address(0)) revert UniswapXFiller__AddressZero(); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - _grantRole(REACTOR_ROLE, address(USXEDAReactor)); + _grantRole(REACTOR_ROLE, address(reactor)); tychoRouter = _tychoRouter; - USXEDAReactor = IReactor(_reactor); + reactor = IReactor(_reactor); } function execute(SignedOrder calldata order, bytes calldata callbackData) external onlyRole(EXECUTOR_ROLE) { - USXEDAReactor.executeWithCallback(order, callbackData); + reactor.executeWithCallback(order, callbackData); } function reactorCallback( From 7a5cf1b89eb70df3b7c1f124c6db2c3b5c024e1c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 8 Jul 2025 14:31:16 +0000 Subject: [PATCH 18/58] chore(release): 0.104.0 [skip ci] ## [0.104.0](https://github.com/propeller-heads/tycho-execution/compare/0.103.0...0.104.0) (2025-07-08) ### Features * Take reactor address as input to UniswapXFiller ([00f22d6](https://github.com/propeller-heads/tycho-execution/commit/00f22d62c1f978f27eb5a922bc7b36af2a0b806b)) * UniswapXFiller skeleton ([ce1fe1d](https://github.com/propeller-heads/tycho-execution/commit/ce1fe1dd94a4cc68e4695902c80ee30d30d7fd5e)) ### Bug Fixes * Make slither happy ([d61469e](https://github.com/propeller-heads/tycho-execution/commit/d61469ea67f2c8d0f28e5185da4099260c2b69ea)) --- CHANGELOG.md | 13 +++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34d27c2..ab74142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## [0.104.0](https://github.com/propeller-heads/tycho-execution/compare/0.103.0...0.104.0) (2025-07-08) + + +### Features + +* Take reactor address as input to UniswapXFiller ([00f22d6](https://github.com/propeller-heads/tycho-execution/commit/00f22d62c1f978f27eb5a922bc7b36af2a0b806b)) +* UniswapXFiller skeleton ([ce1fe1d](https://github.com/propeller-heads/tycho-execution/commit/ce1fe1dd94a4cc68e4695902c80ee30d30d7fd5e)) + + +### Bug Fixes + +* Make slither happy ([d61469e](https://github.com/propeller-heads/tycho-execution/commit/d61469ea67f2c8d0f28e5185da4099260c2b69ea)) + ## [0.103.0](https://github.com/propeller-heads/tycho-execution/compare/0.102.0...0.103.0) (2025-07-07) diff --git a/Cargo.lock b/Cargo.lock index df435e3..05e0314 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4658,7 +4658,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.103.0" +version = "0.104.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index df96172..136586e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.103.0" +version = "0.104.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From ba60e4bb73741c17c44e1cfcdea3fd599ae027eb Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 8 Jul 2025 16:55:41 +0100 Subject: [PATCH 19/58] fix: Simplify nonceOffset logic Set new role addresses for all chains Took 1 hour 43 minutes --- foundry/scripts/roles.json | 30 ++++++++++++++++++------------ foundry/scripts/set-roles.js | 5 +---- foundry/scripts/utils.js | 25 ++++++++++++++++++------- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/foundry/scripts/roles.json b/foundry/scripts/roles.json index fa5dc3f..4827bdc 100644 --- a/foundry/scripts/roles.json +++ b/foundry/scripts/roles.json @@ -1,44 +1,50 @@ { "ethereum": { "EXECUTOR_SETTER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0x06e580B872a37402764f909FCcAb0Eb5bb38fe23" ], "PAUSER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xB279A562C726F9F3011c1945c9c23Fe1FB631B59", + "0xAC3649A6DFBBB230632604f2fc43773977ec6E67" ], "UNPAUSER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xB279A562C726F9F3011c1945c9c23Fe1FB631B59", + "0xAC3649A6DFBBB230632604f2fc43773977ec6E67" ], "FUND_RESCUER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xF621770E96bcf1335150faecf77D757faf7ca4A9" ] }, "base": { "EXECUTOR_SETTER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0x06e580B872a37402764f909FCcAb0Eb5bb38fe23" ], "PAUSER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xB279A562C726F9F3011c1945c9c23Fe1FB631B59", + "0xAC3649A6DFBBB230632604f2fc43773977ec6E67" ], "UNPAUSER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xB279A562C726F9F3011c1945c9c23Fe1FB631B59", + "0xAC3649A6DFBBB230632604f2fc43773977ec6E67" ], "FUND_RESCUER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xF621770E96bcf1335150faecf77D757faf7ca4A9" ] }, "unichain": { "EXECUTOR_SETTER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0x06e580B872a37402764f909FCcAb0Eb5bb38fe23" ], "PAUSER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xB279A562C726F9F3011c1945c9c23Fe1FB631B59", + "0xAC3649A6DFBBB230632604f2fc43773977ec6E67" ], "UNPAUSER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xB279A562C726F9F3011c1945c9c23Fe1FB631B59", + "0xAC3649A6DFBBB230632604f2fc43773977ec6E67" ], "FUND_RESCUER_ROLE": [ - "0x58Dc7Bf9eD1f4890A7505D5bE4E4252978eAF655" + "0xF621770E96bcf1335150faecf77D757faf7ca4A9" ] } } \ No newline at end of file diff --git a/foundry/scripts/set-roles.js b/foundry/scripts/set-roles.js index 7c7a94c..fb98711 100644 --- a/foundry/scripts/set-roles.js +++ b/foundry/scripts/set-roles.js @@ -26,14 +26,12 @@ async function main() { const roles = { EXECUTOR_SETTER_ROLE: "0x6a1dd52dcad5bd732e45b6af4e7344fa284e2d7d4b23b5b09cb55d36b0685c87", - FEE_SETTER_ROLE: "0xe6ad9a47fbda1dc18de1eb5eeb7d935e5e81b4748f3cfc61e233e64f88182060", PAUSER_ROLE: "0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a", UNPAUSER_ROLE: "0x427da25fe773164f88948d3e215c94b6554e2ed5e5f203a821c9f2f6131cf75a", FUND_RESCUER_ROLE: "0x912e45d663a6f4cc1d0491d8f046e06c616f40352565ea1cdb86a0e1aaefa41b" }; // Iterate through roles and grant them to the corresponding addresses - let nonceOffset = 0 for (const [roleName, roleHash] of Object.entries(roles)) { const addresses = rolesDict[network][roleName]; if (addresses && addresses.length > 0) { @@ -45,8 +43,7 @@ async function main() { value: "0", }; - const txHash = await proposeOrSendTransaction(safeAddress, txData, signer, "batchGrantRole", nonceOffset); - nonceOffset += 1 + const txHash = await proposeOrSendTransaction(safeAddress, txData, signer, "batchGrantRole"); console.log(`Role ${roleName} granted at TX hash: ${txHash}`); } else { console.log(`No addresses found for role ${roleName}`); diff --git a/foundry/scripts/utils.js b/foundry/scripts/utils.js index f47a85c..04faeb8 100644 --- a/foundry/scripts/utils.js +++ b/foundry/scripts/utils.js @@ -3,11 +3,17 @@ const Safe = require('@safe-global/protocol-kit').default; const {EthersAdapter} = require('@safe-global/protocol-kit'); const {default: SafeApiKit} = require("@safe-global/api-kit"); -const txServiceUrl = 'https://safe-transaction-mainnet.safe.global'; +const txServiceUrls = { + mainnet: "https://safe-transaction-mainnet.safe.global", + base: "https://safe-transaction-base.safe.global", + unichain: "https://safe-transaction-unichain.safe.global", +}; -async function proposeOrSendTransaction(safeAddress, txData, signer, methodName, nonceOffset = 0) { +const txServiceUrl = txServiceUrls[hre.network.name]; + +async function proposeOrSendTransaction(safeAddress, txData, signer, methodName) { if (safeAddress) { - return proposeTransaction(safeAddress, txData, signer, methodName, nonceOffset); + return proposeTransaction(safeAddress, txData, signer, methodName); } else { console.log(`Executing the transaction directly`); const tx = await signer.sendTransaction(txData); @@ -16,7 +22,7 @@ async function proposeOrSendTransaction(safeAddress, txData, signer, methodName, } } -async function proposeTransaction(safeAddress, txData, signer, methodName, nonceOffset = 0) { +async function proposeTransaction(safeAddress, txData, signer, methodName) { const signerAddress = await signer.getAddress(); console.log(`Proposing transaction to Safe: ${safeAddress} with account: ${signerAddress}`); @@ -31,8 +37,13 @@ async function proposeTransaction(safeAddress, txData, signer, methodName, nonce ethAdapter, safeAddress, }); - - const safeTransaction = await safeSdk.createTransaction({safeTransactionData: txData}); + let next_nonce = await safeService.getNextNonce(safeAddress); + const safeTransaction = await safeSdk.createTransaction({ + safeTransactionData: { + ...txData, + nonce: next_nonce + } + }); const safeTxHash = await safeSdk.getTransactionHash(safeTransaction); const senderSignature = await safeSdk.signTransactionHash(safeTxHash); @@ -43,7 +54,7 @@ async function proposeTransaction(safeAddress, txData, signer, methodName, nonce senderAddress: signerAddress, senderSignature: senderSignature.data, origin: `Proposed from hardhat: ${methodName}`, - nonce: await safeService.getNextNonce(safeAddress) + nonceOffset, + nonce: next_nonce, }; await safeService.proposeTransaction(proposeArgs); From a114dfc9da52a6393c55b00ea5b57143c8106429 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Mon, 7 Jul 2025 21:34:27 -0400 Subject: [PATCH 20/58] feat: UniswapXFiller callback - naive implementation Added testCallback + execution integration test with real onchain data --- foundry/src/uniswap_x/UniswapXFiller.sol | 30 ++++- foundry/test/uniswap_x/UniswapXFiller.t.sol | 126 ++++++++++++++++++++ 2 files changed, 154 insertions(+), 2 deletions(-) diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol index de52edd..bb5d0dc 100644 --- a/foundry/src/uniswap_x/UniswapXFiller.sol +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -11,6 +11,7 @@ import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/Address.sol"; error UniswapXFiller__AddressZero(); +error UniswapXFiller__BatchExecutionNotSupported(); contract UniswapXFiller is AccessControl, IReactorCallback { using SafeERC20 for IERC20; @@ -34,7 +35,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback { if (_reactor == address(0)) revert UniswapXFiller__AddressZero(); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - _grantRole(REACTOR_ROLE, address(reactor)); + _grantRole(REACTOR_ROLE, address(_reactor)); tychoRouter = _tychoRouter; reactor = IReactor(_reactor); } @@ -50,7 +51,32 @@ contract UniswapXFiller is AccessControl, IReactorCallback { ResolvedOrder[] calldata resolvedOrders, bytes calldata callbackData ) external onlyRole(REACTOR_ROLE) { - // TODO + require( + resolvedOrders.length == 1, + UniswapXFiller__BatchExecutionNotSupported() + ); + + ResolvedOrder memory order = resolvedOrders[0]; + + // TODO properly handle native in and out tokens + uint256 ethValue = 0; + (bool success, bytes memory result) = + tychoRouter.call{value: ethValue}(callbackData); + + if (!success) { + revert( + string( + result.length > 0 + ? result + : abi.encodePacked("Execution failed") + ) + ); + } + + // Multiple outputs are possible when taking fees - but token itself should + // not change. + IERC20 token = IERC20(order.outputs[0].token); + token.forceApprove(address(reactor), type(uint256).max); } /** diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index 1dc11df..6e3bbbb 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -17,11 +17,16 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { address indexed token, uint256 amount, address indexed receiver ); + function getForkBlock() public pure override returns (uint256) { + return 22788691; + } + function fillerSetup() public { vm.startPrank(ADMIN); filler = new UniswapXFiller(tychoRouterAddr, REACTOR); fillerAddr = address(filler); filler.grantRole(keccak256("EXECUTOR_ROLE"), EXECUTOR); + filler.grantRole(keccak256("REACTOR_ROLE"), REACTOR); vm.stopPrank(); } @@ -35,6 +40,127 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { filler = new UniswapXFiller(tychoRouterAddr, address(0)); } + function testCallback() public { + fillerSetup(); + uint256 amountIn = 10 ** 18; + uint256 amountOut = 1847751195973566072891; + bool zeroForOne = false; + bytes memory protocolData = abi.encodePacked( + WETH_ADDR, + WETH_DAI_POOL, + address(filler), + zeroForOne, + RestrictTransferFrom.TransferType.TransferFrom + ); + + bytes memory swap = + encodeSingleSwap(address(usv2Executor), protocolData); + + bytes memory callbackData = abi.encodeWithSelector( + tychoRouter.singleSwap.selector, + amountIn, + WETH_ADDR, + DAI_ADDR, + 2008817438608734439722, + false, + false, + address(filler), + true, + swap + ); + + deal(WETH_ADDR, address(filler), amountIn); + vm.startPrank(address(filler)); + IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); + vm.stopPrank(); + ResolvedOrder[] memory orders = new ResolvedOrder[](1); + OutputToken[] memory outputs = new OutputToken[](1); + outputs[0] = OutputToken({ + token: address(DAI_ADDR), + // Irrelevant fields - we only need the token address for approval + amount: 1847751195973566072891, + recipient: BOB + }); + // All irrelevant fields for this test - we only need the output token address + orders[0] = ResolvedOrder({ + info: OrderInfo({ + reactor: address(0), + swapper: address(0), + nonce: 0, + deadline: 0, + additionalValidationContract: address(0), + additionalValidationData: "" + }), + input: InputToken({token: address(WETH_ADDR), amount: 0, maxAmount: 0}), + outputs: outputs, + sig: "", + hash: "" + }); + + vm.startPrank(REACTOR); + filler.reactorCallback(orders, callbackData); + vm.stopPrank(); + + // Check that the funds are in the filler at the end of the function call + uint256 finalBalance = IERC20(DAI_ADDR).balanceOf(address(filler)); + assertGe(finalBalance, amountOut); + + // Check that the proper approval was set + vm.startPrank(REACTOR); + IERC20(DAI_ADDR).transferFrom(address(filler), BOB, amountOut); + vm.stopPrank(); + assertGe(IERC20(DAI_ADDR).balanceOf(BOB), amountOut); + } + + + function testExecuteIntegration() public { + fillerSetup(); + // tx: 0x5b602b7d0a37e241bd032a907b9ddf314e9f2fc2104fd91cb55bdb3d8dfe4e9c + // 0.2 WBTC -> USDC + SignedOrder memory order = SignedOrder({ + order: hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000004449cd34d1eb1fedcf02a1be3834ffde8e6a61800000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000000000000000000000000000000000000001312d000000000000000000000000000000000000000000000000000000000001312d0000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000011f84b9aa48e5f8aa8b9897600006289be0000000000000000000000000d1100e55ef6c4e5800f4624b1e6121d798eb696046832163cef9c09382cf582bb878b37a42933ea2bdf33757942ab2747b3500100000000000000000000000000000000000000000000000000000000685d4150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000004f921447c00000000000000000000000000000000000000000000000000000004f1464dea0000000000000000000000000d1100e55ef6c4e5800f4624b1e6121d798eb696000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000330d86400000000000000000000000000000000000000000000000000000000032bce2600000000000000000000000027213e28d7fda5c57fe9e5dd923818dbccf71c4700000000000000000000000000000000000000000000000000000000685d407600000000000000000000000000000000000000000000000000000000685d40b2000000000000000000000000225a38bc71102999dd13478bfabd7c4d53f2dc170000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000004fb7f8815000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417067afde0759ae3653dad5d412519f488b6e9ed8955b3e3b8606e85c0198a9d71075295d33fe84b5ccc9c2d38a7ea79d7fad68128a37cabc5557342756a4e8311b00000000000000000000000000000000000000000000000000000000000000", + sig: hex"41b7a696a04f897d1e4ccaf88136092169c2874242d55c3fe4c028125efe95340f5ce764b9dce9d2cae241d97ceb515d3f1739972ca884ed51b2870045438c3a1c" + }); + + uint256 amountIn = 0.2 * 10 ** 8; + bool zeroForOne = true; + bytes memory protocolData = abi.encodePacked( + WBTC_ADDR, + USDC_WBTC_POOL, + fillerAddr, + zeroForOne, + RestrictTransferFrom.TransferType.TransferFrom + ); + + bytes memory swap = + encodeSingleSwap(address(usv2Executor), protocolData); + + bytes memory callbackData = abi.encodeWithSelector( + tychoRouter.singleSwap.selector, + amountIn, + WBTC_ADDR, + USDC_ADDR, + 1, + false, + false, + fillerAddr, + true, + swap + ); + + vm.startPrank(address(filler)); + IERC20(WBTC_ADDR).approve(tychoRouterAddr, amountIn); + vm.stopPrank(); + + // This is a hack because the tx we are trying to replicate returns a looooot more USDC than what the uni v2 pool does at this point + // 5113180081 is the difference and 54068100 is the fee + deal(USDC_ADDR, address(filler), 5113180081 + 54068100); + + vm.startPrank(EXECUTOR); + filler.execute(order, callbackData); + vm.stopPrank(); + } + function testWithdrawNative() public { fillerSetup(); vm.startPrank(ADMIN); From a2d123a26328f71afa6e8c163096d29bfef6957b Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Tue, 8 Jul 2025 12:23:42 -0400 Subject: [PATCH 21/58] fix: disable slither warnings - locked-ether: We do have a withdraw method. Not sure why it doesn't register with slither. Already tried renaming. - low-level-calls: This low level call is integral to the design of our filler contract.= --- foundry/src/uniswap_x/UniswapXFiller.sol | 3 +++ foundry/test/uniswap_x/UniswapXFiller.t.sol | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol index bb5d0dc..1156c31 100644 --- a/foundry/src/uniswap_x/UniswapXFiller.sol +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -60,6 +60,8 @@ contract UniswapXFiller is AccessControl, IReactorCallback { // TODO properly handle native in and out tokens uint256 ethValue = 0; + + // slither-disable-next-line low-level-calls (bool success, bytes memory result) = tychoRouter.call{value: ethValue}(callbackData); @@ -129,6 +131,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback { /** * @dev Allows this contract to receive native token with empty msg.data from contracts */ + // slither-disable-next-line locked-ether receive() external payable { require(msg.sender.code.length != 0); } diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index 6e3bbbb..8102e4f 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -26,7 +26,6 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { filler = new UniswapXFiller(tychoRouterAddr, REACTOR); fillerAddr = address(filler); filler.grantRole(keccak256("EXECUTOR_ROLE"), EXECUTOR); - filler.grantRole(keccak256("REACTOR_ROLE"), REACTOR); vm.stopPrank(); } @@ -112,7 +111,6 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { assertGe(IERC20(DAI_ADDR).balanceOf(BOB), amountOut); } - function testExecuteIntegration() public { fillerSetup(); // tx: 0x5b602b7d0a37e241bd032a907b9ddf314e9f2fc2104fd91cb55bdb3d8dfe4e9c From 94d48881428f8ca1a33442b87d9af90ff66f034e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Jul 2025 08:40:05 +0000 Subject: [PATCH 22/58] chore(release): 0.105.0 [skip ci] ## [0.105.0](https://github.com/propeller-heads/tycho-execution/compare/0.104.0...0.105.0) (2025-07-09) ### Features * Upgrade scripts to submit to Safe wallet ([2733bb0](https://github.com/propeller-heads/tycho-execution/commit/2733bb00724fb2df8d6f8151df02826807289c9a)) ### Bug Fixes * Simplify nonceOffset logic ([ba60e4b](https://github.com/propeller-heads/tycho-execution/commit/ba60e4bb73741c17c44e1cfcdea3fd599ae027eb)) --- CHANGELOG.md | 12 ++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab74142..e494650 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [0.105.0](https://github.com/propeller-heads/tycho-execution/compare/0.104.0...0.105.0) (2025-07-09) + + +### Features + +* Upgrade scripts to submit to Safe wallet ([2733bb0](https://github.com/propeller-heads/tycho-execution/commit/2733bb00724fb2df8d6f8151df02826807289c9a)) + + +### Bug Fixes + +* Simplify nonceOffset logic ([ba60e4b](https://github.com/propeller-heads/tycho-execution/commit/ba60e4bb73741c17c44e1cfcdea3fd599ae027eb)) + ## [0.104.0](https://github.com/propeller-heads/tycho-execution/compare/0.103.0...0.104.0) (2025-07-08) diff --git a/Cargo.lock b/Cargo.lock index 05e0314..aad673c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4658,7 +4658,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.104.0" +version = "0.105.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 136586e..7b2f340 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.104.0" +version = "0.105.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From 808202df8c3de897cdc65329377b96f1426fe3f0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Jul 2025 12:12:39 +0000 Subject: [PATCH 23/58] chore(release): 0.106.0 [skip ci] ## [0.106.0](https://github.com/propeller-heads/tycho-execution/compare/0.105.0...0.106.0) (2025-07-09) ### Features * UniswapXFiller callback - naive implementation ([a114dfc](https://github.com/propeller-heads/tycho-execution/commit/a114dfc9da52a6393c55b00ea5b57143c8106429)) ### Bug Fixes * disable slither warnings ([a2d123a](https://github.com/propeller-heads/tycho-execution/commit/a2d123a26328f71afa6e8c163096d29bfef6957b)) --- CHANGELOG.md | 12 ++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e494650..57f27d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [0.106.0](https://github.com/propeller-heads/tycho-execution/compare/0.105.0...0.106.0) (2025-07-09) + + +### Features + +* UniswapXFiller callback - naive implementation ([a114dfc](https://github.com/propeller-heads/tycho-execution/commit/a114dfc9da52a6393c55b00ea5b57143c8106429)) + + +### Bug Fixes + +* disable slither warnings ([a2d123a](https://github.com/propeller-heads/tycho-execution/commit/a2d123a26328f71afa6e8c163096d29bfef6957b)) + ## [0.105.0](https://github.com/propeller-heads/tycho-execution/compare/0.104.0...0.105.0) (2025-07-09) diff --git a/Cargo.lock b/Cargo.lock index aad673c..099a723 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4658,7 +4658,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.105.0" +version = "0.106.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 7b2f340..65c9e61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.105.0" +version = "0.106.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From e243667f9ee8ec8e79fc5196da6960b19cd120b7 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Tue, 8 Jul 2025 18:15:26 -0400 Subject: [PATCH 24/58] feat: (WIP) Handle approvals in UniswapXFiller Reasons for using regular approvals instead of permit2: - More simplicity, simpler setup - Unfortunately we won't be able to "expire" approvals, which is a risk we may be okay with taking - since one advantage of this is that we will be able save on gas by not approving the reactor every single time (is this our intention?) TODO: - Do we really need input tokens to pass through our router? - Handle native ETH (double check how this is transferred in the reactor) --- foundry/src/uniswap_x/UniswapXFiller.sol | 36 ++++++++++++++++++--- foundry/test/uniswap_x/UniswapXFiller.t.sol | 23 ++++++++++--- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol index 1156c31..bc5a3f9 100644 --- a/foundry/src/uniswap_x/UniswapXFiller.sol +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -9,6 +9,7 @@ import { } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/Address.sol"; +import {TychoRouter} from "../TychoRouter.sol"; error UniswapXFiller__AddressZero(); error UniswapXFiller__BatchExecutionNotSupported(); @@ -58,12 +59,34 @@ contract UniswapXFiller is AccessControl, IReactorCallback { ResolvedOrder memory order = resolvedOrders[0]; + ( + bool tokenInApprovalNeeded, + bool tokenOutApprovalNeeded, + bytes memory tychoCalldata + ) = abi.decode(callbackData, (bool, bool, bytes)); + + // The TychoRouter will take the input tokens from the filler + if (tokenInApprovalNeeded) { + // TODO only if ERC20 + IERC20(order.input.token).forceApprove( + tychoRouter, order.input.maxAmount + ); + } else { + // The filler will manually transfer into the TychoRouter + // Note: We are using the balance of our filler instead of the order + // input amount to avoid having to do a decay calculation in the filler. + IERC20 inputToken = IERC20(order.input.token); + inputToken.transfer( + tychoRouter, inputToken.balanceOf(address(this)) + ); + } + // TODO properly handle native in and out tokens uint256 ethValue = 0; // slither-disable-next-line low-level-calls (bool success, bytes memory result) = - tychoRouter.call{value: ethValue}(callbackData); + tychoRouter.call{value: ethValue}(tychoCalldata); if (!success) { revert( @@ -75,10 +98,13 @@ contract UniswapXFiller is AccessControl, IReactorCallback { ); } - // Multiple outputs are possible when taking fees - but token itself should - // not change. - IERC20 token = IERC20(order.outputs[0].token); - token.forceApprove(address(reactor), type(uint256).max); + if (tokenOutApprovalNeeded) { + // Multiple outputs are possible when taking fees - but token itself should + // not change. + // TODO only if ERC20 + IERC20 token = IERC20(order.outputs[0].token); + token.forceApprove(address(reactor), type(uint256).max); + } } /** diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index 8102e4f..49f9e90 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -55,7 +55,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { bytes memory swap = encodeSingleSwap(address(usv2Executor), protocolData); - bytes memory callbackData = abi.encodeWithSelector( + bytes memory tychoRouterData = abi.encodeWithSelector( tychoRouter.singleSwap.selector, amountIn, WETH_ADDR, @@ -68,6 +68,8 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { swap ); + bytes memory callbackData = abi.encode(true, true, tychoRouterData); + deal(WETH_ADDR, address(filler), amountIn); vm.startPrank(address(filler)); IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); @@ -76,11 +78,11 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { OutputToken[] memory outputs = new OutputToken[](1); outputs[0] = OutputToken({ token: address(DAI_ADDR), - // Irrelevant fields - we only need the token address for approval amount: 1847751195973566072891, recipient: BOB }); - // All irrelevant fields for this test - we only need the output token address + // Mostly irrelevant fields for this test - we only need token input and outputs + // info for the sake of testing. orders[0] = ResolvedOrder({ info: OrderInfo({ reactor: address(0), @@ -90,7 +92,12 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { additionalValidationContract: address(0), additionalValidationData: "" }), - input: InputToken({token: address(WETH_ADDR), amount: 0, maxAmount: 0}), + input: InputToken({ + token: address(WETH_ADDR), + amount: amountIn, + // We need the proper maxAmount for our approval to work + maxAmount: amountIn + }), outputs: outputs, sig: "", hash: "" @@ -133,7 +140,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { bytes memory swap = encodeSingleSwap(address(usv2Executor), protocolData); - bytes memory callbackData = abi.encodeWithSelector( + bytes memory tychoRouterData = abi.encodeWithSelector( tychoRouter.singleSwap.selector, amountIn, WBTC_ADDR, @@ -146,6 +153,12 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { swap ); + bytes memory callbackData = abi.encode( + true, // tokenIn approval needed + true, // tokenOut approval needed + tychoRouterData + ); + vm.startPrank(address(filler)); IERC20(WBTC_ADDR).approve(tychoRouterAddr, amountIn); vm.stopPrank(); From 3752c155ea89d4d2d91be98f2c5fa79264a45999 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Wed, 9 Jul 2025 12:06:15 -0400 Subject: [PATCH 25/58] feat: Handle native ETH outputs - In this case, the ETH needs to be manually transferred to the reactor. - Native ETH input is not supported for UniswapX Source: https://support.uniswap.org/hc/en-us/articles/17544708791821-Are-there-network-costs-for-UniswapX --- foundry/src/uniswap_x/UniswapXFiller.sol | 36 ++++++++++----------- foundry/test/uniswap_x/UniswapXFiller.t.sol | 6 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol index bc5a3f9..2daaf40 100644 --- a/foundry/src/uniswap_x/UniswapXFiller.sol +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -20,6 +20,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback { // UniswapX V2DutchOrder Reactor IReactor public immutable reactor; address public immutable tychoRouter; + address public immutable nativeAddress; // keccak256("NAME_OF_ROLE") : save gas on deployment bytes32 public constant REACTOR_ROLE = @@ -31,7 +32,11 @@ contract UniswapXFiller is AccessControl, IReactorCallback { address indexed token, uint256 amount, address indexed receiver ); - constructor(address _tychoRouter, address _reactor) { + constructor( + address _tychoRouter, + address _reactor, + address _native_address + ) { if (_tychoRouter == address(0)) revert UniswapXFiller__AddressZero(); if (_reactor == address(0)) revert UniswapXFiller__AddressZero(); @@ -39,6 +44,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback { _grantRole(REACTOR_ROLE, address(_reactor)); tychoRouter = _tychoRouter; reactor = IReactor(_reactor); + nativeAddress = _native_address; } function execute(SignedOrder calldata order, bytes calldata callbackData) @@ -67,26 +73,14 @@ contract UniswapXFiller is AccessControl, IReactorCallback { // The TychoRouter will take the input tokens from the filler if (tokenInApprovalNeeded) { - // TODO only if ERC20 + // Native ETH input is not supported by UniswapX IERC20(order.input.token).forceApprove( tychoRouter, order.input.maxAmount ); - } else { - // The filler will manually transfer into the TychoRouter - // Note: We are using the balance of our filler instead of the order - // input amount to avoid having to do a decay calculation in the filler. - IERC20 inputToken = IERC20(order.input.token); - inputToken.transfer( - tychoRouter, inputToken.balanceOf(address(this)) - ); } - // TODO properly handle native in and out tokens - uint256 ethValue = 0; - // slither-disable-next-line low-level-calls - (bool success, bytes memory result) = - tychoRouter.call{value: ethValue}(tychoCalldata); + (bool success, bytes memory result) = tychoRouter.call(tychoCalldata); if (!success) { revert( @@ -101,9 +95,15 @@ contract UniswapXFiller is AccessControl, IReactorCallback { if (tokenOutApprovalNeeded) { // Multiple outputs are possible when taking fees - but token itself should // not change. - // TODO only if ERC20 - IERC20 token = IERC20(order.outputs[0].token); - token.forceApprove(address(reactor), type(uint256).max); + OutputToken memory output = order.outputs[0]; + if (output.token != nativeAddress) { + IERC20 token = IERC20(output.token); + token.forceApprove(address(reactor), type(uint256).max); + } else { + // With native ETH - the filler is responsible for transferring back + // to the reactor. + Address.sendValue(payable(address(reactor)), output.amount); + } } } diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index 49f9e90..9ac004c 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -23,7 +23,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { function fillerSetup() public { vm.startPrank(ADMIN); - filler = new UniswapXFiller(tychoRouterAddr, REACTOR); + filler = new UniswapXFiller(tychoRouterAddr, REACTOR, address(0)); fillerAddr = address(filler); filler.grantRole(keccak256("EXECUTOR_ROLE"), EXECUTOR); vm.stopPrank(); @@ -31,12 +31,12 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { function testTychoAddressZeroTychoRouter() public { vm.expectRevert(UniswapXFiller__AddressZero.selector); - filler = new UniswapXFiller(address(0), REACTOR); + filler = new UniswapXFiller(address(0), REACTOR, address(0)); } function testTychoAddressZeroReactor() public { vm.expectRevert(UniswapXFiller__AddressZero.selector); - filler = new UniswapXFiller(tychoRouterAddr, address(0)); + filler = new UniswapXFiller(tychoRouterAddr, address(0), address(0)); } function testCallback() public { From 1b6a24fd75b91de7570f110e87d81ed081639bb7 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Wed, 9 Jul 2025 12:19:19 -0400 Subject: [PATCH 26/58] fix: silence slither on native address setting - We don't need a zero address check, since we expect this to be the zero address for most cases. --- foundry/src/uniswap_x/UniswapXFiller.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol index 2daaf40..0904ef8 100644 --- a/foundry/src/uniswap_x/UniswapXFiller.sol +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -44,6 +44,8 @@ contract UniswapXFiller is AccessControl, IReactorCallback { _grantRole(REACTOR_ROLE, address(_reactor)); tychoRouter = _tychoRouter; reactor = IReactor(_reactor); + + // slither-disable-next-line missing-zero-check nativeAddress = _native_address; } From 9e2f228a470d163b71cac22a0f95116716490772 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Wed, 9 Jul 2025 14:32:43 -0400 Subject: [PATCH 27/58] fix: use encodePacked to encode if approval needed - Also approve max amount for the tycho router to use (to save on gas) --- foundry/src/uniswap_x/UniswapXFiller.sol | 10 ++++------ foundry/test/uniswap_x/UniswapXFiller.t.sol | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/foundry/src/uniswap_x/UniswapXFiller.sol b/foundry/src/uniswap_x/UniswapXFiller.sol index 0904ef8..7826e3c 100644 --- a/foundry/src/uniswap_x/UniswapXFiller.sol +++ b/foundry/src/uniswap_x/UniswapXFiller.sol @@ -67,17 +67,15 @@ contract UniswapXFiller is AccessControl, IReactorCallback { ResolvedOrder memory order = resolvedOrders[0]; - ( - bool tokenInApprovalNeeded, - bool tokenOutApprovalNeeded, - bytes memory tychoCalldata - ) = abi.decode(callbackData, (bool, bool, bytes)); + bool tokenInApprovalNeeded = bool(uint8(callbackData[0]) == 1); + bool tokenOutApprovalNeeded = bool(uint8(callbackData[1]) == 1); + bytes calldata tychoCalldata = bytes(callbackData[2:]); // The TychoRouter will take the input tokens from the filler if (tokenInApprovalNeeded) { // Native ETH input is not supported by UniswapX IERC20(order.input.token).forceApprove( - tychoRouter, order.input.maxAmount + tychoRouter, type(uint256).max ); } diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index 9ac004c..5128339 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -68,7 +68,8 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { swap ); - bytes memory callbackData = abi.encode(true, true, tychoRouterData); + bytes memory callbackData = + abi.encodePacked(true, true, tychoRouterData); deal(WETH_ADDR, address(filler), amountIn); vm.startPrank(address(filler)); @@ -153,7 +154,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { swap ); - bytes memory callbackData = abi.encode( + bytes memory callbackData = abi.encodePacked( true, // tokenIn approval needed true, // tokenOut approval needed tychoRouterData From d2ba2554179ac374be2bac5863ca8f58f01a575d Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 8 Jul 2025 13:32:13 +0100 Subject: [PATCH 28/58] test: Add encoding test for a uniswap X integration test Took 26 minutes --- foundry/test/assets/calldata.txt | 1 + tests/uniswap_x_integration_tests.rs | 117 +++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 tests/uniswap_x_integration_tests.rs diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 3aecf03..f8bca01 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -33,3 +33,4 @@ test_encode_balancer_v3:7bc3485026ac48b6cf9baf0a377477fff5703af8c71ea051a5f82c67 test_single_encoding_strategy_balancer_v3:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000097ffedb80d4b2ca6105a07a4d90eb739c45a66600000000000000000000000030881baa943777f92dc934d53d3bfdf33382cab300000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000006503a6a84cd762d9707a21605b548aaab891562aab097ffedb80d4b2ca6105a07a4d90eb739c45a66630881baa943777f92dc934d53d3bfdf33382cab3f028ac624074d6793c36dc8a06ecec0f5a39a71800cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000 test_uniswap_v3_balancer_v3:e21dd0d3000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004a220e6096b25eadb88358cb44068a324825467500000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed0000006503a6a84cd762d9707a21605b548aaab891562aab2260fac5e5542a773aa44fbcfedf7c193bc2c5994a220e6096b25eadb88358cb44068a3248254675571bea0e99e139cd0b6b7d9352ca872dfe0d72dd01cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000 test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7f00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411d60a13b5e993ef8088cb2cb7e16281f47fbc329bd0ec2a48165e7898542a7ed12fe7ffdec713b6d94e99ddf0a384674617b6190b8534491d525ecb090c8e4881c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_sequential_swap_unix:0101e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200 diff --git a/tests/uniswap_x_integration_tests.rs b/tests/uniswap_x_integration_tests.rs new file mode 100644 index 0000000..b55bb90 --- /dev/null +++ b/tests/uniswap_x_integration_tests.rs @@ -0,0 +1,117 @@ +use std::{collections::HashMap, str::FromStr}; + +use alloy::{hex::encode, primitives::Address, sol_types::SolValue}; +use num_bigint::{BigInt, BigUint}; +use tycho_common::{models::protocol::ProtocolComponent, Bytes}; +use tycho_execution::encoding::{ + evm::{ + approvals::protocol_approvals_manager::ProtocolApprovalsManager, + utils::{bytes_to_address, write_calldata_to_file}, + }, + models::{Solution, Swap, UserTransferType}, +}; + +use crate::common::{ + encoding::encode_tycho_router_call, eth, eth_chain, get_tycho_router_encoder, router_address, + usdc, wbtc, weth, +}; + +mod common; + +#[test] +fn test_sequential_swap_unix() { + // Performs a sequential swap from WETH to USDC though WBTC using USV3 and USV2 + // pools + // + // WETH ───(USV3)──> WBTC ───(USV2)──> USDC + // Creates all the calldata needed for the uniswap X callbackData + + let filler = Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(); + let unix_reactor = Address::from_str("0x00000011F84B9aa48e5f8aA8B9897600006289Be").unwrap(); + + let weth = weth(); + let wbtc = wbtc(); + let usdc = usdc(); + + let swap_weth_wbtc = Swap { + component: ProtocolComponent { + id: "0xCBCdF9626bC03E24f779434178A73a0B4bad62eD".to_string(), + protocol_system: "uniswap_v3".to_string(), + static_attributes: { + let mut attrs = HashMap::new(); + attrs.insert( + "fee".to_string(), + Bytes::from(BigInt::from(3000).to_signed_bytes_be()), + ); + attrs + }, + ..Default::default() + }, + token_in: weth.clone(), + token_out: wbtc.clone(), + split: 0f64, + user_data: None, + }; + let swap_wbtc_usdc = Swap { + component: ProtocolComponent { + id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(), + protocol_system: "uniswap_v2".to_string(), + ..Default::default() + }, + token_in: wbtc.clone(), + token_out: usdc.clone(), + split: 0f64, + user_data: None, + }; + let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); + + let solution = Solution { + exact_out: false, + given_token: weth.clone(), + given_amount: BigUint::from_str("1_000000000000000000").unwrap(), + checked_token: usdc.clone(), + checked_amount: BigUint::from_str("26173932").unwrap(), + sender: filler.clone(), + receiver: filler.clone(), + swaps: vec![swap_weth_wbtc, swap_wbtc_usdc], + ..Default::default() + }; + + let encoded_solution = encoder + .encode_solutions(vec![solution.clone()]) + .unwrap()[0] + .clone(); + + let tycho_calldata = encode_tycho_router_call( + eth_chain().id, + encoded_solution, + &solution, + &UserTransferType::TransferFrom, + ð(), + None, + ) + .unwrap() + .data; + + // Uniswap X specific part + let filler_address = bytes_to_address(&filler).unwrap(); + let token_approvals_manager = ProtocolApprovalsManager::new().unwrap(); + + let token_in_approval_needed = token_approvals_manager + .approval_needed( + bytes_to_address(&weth).unwrap(), + filler_address, + bytes_to_address(&router_address()).unwrap(), + ) + .unwrap(); + + let token_out_approval_needed = token_approvals_manager + .approval_needed(bytes_to_address(&usdc).unwrap(), filler_address, unix_reactor) + .unwrap(); + + let full_calldata = + (token_in_approval_needed, token_out_approval_needed, tycho_calldata).abi_encode_packed(); + + let hex_calldata = encode(&full_calldata); + write_calldata_to_file("test_sequential_swap_unix", hex_calldata.as_str()); +} From 96d0bf4ba545e4ae369c292aec6b56a32cf77db0 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 9 Jul 2025 11:36:15 +0100 Subject: [PATCH 29/58] fix: Replicate a real Uniswap X order in integration test Took 16 minutes --- foundry/test/assets/calldata.txt | 2 +- tests/common/mod.rs | 4 +++ tests/uniswap_x_integration_tests.rs | 50 ++++++++++++++-------------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index f8bca01..5c45c3b 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -33,4 +33,4 @@ test_encode_balancer_v3:7bc3485026ac48b6cf9baf0a377477fff5703af8c71ea051a5f82c67 test_single_encoding_strategy_balancer_v3:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000097ffedb80d4b2ca6105a07a4d90eb739c45a66600000000000000000000000030881baa943777f92dc934d53d3bfdf33382cab300000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000006503a6a84cd762d9707a21605b548aaab891562aab097ffedb80d4b2ca6105a07a4d90eb739c45a66630881baa943777f92dc934d53d3bfdf33382cab3f028ac624074d6793c36dc8a06ecec0f5a39a71800cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000 test_uniswap_v3_balancer_v3:e21dd0d3000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004a220e6096b25eadb88358cb44068a324825467500000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed0000006503a6a84cd762d9707a21605b548aaab891562aab2260fac5e5542a773aa44fbcfedf7c193bc2c5994a220e6096b25eadb88358cb44068a3248254675571bea0e99e139cd0b6b7d9352ca872dfe0d72dd01cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000 test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7f00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411d60a13b5e993ef8088cb2cb7e16281f47fbc329bd0ec2a48165e7898542a7ed12fe7ffdec713b6d94e99ddf0a384674617b6190b8534491d525ecb090c8e4881c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_sequential_swap_unix:0101e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200 +test_sequential_swap_unix:0101e21dd0d300000000000000000000000000000000000000000000006c6b935b8bbd4000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000769cfd8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470b6b175474e89094c44da98b954eedeac495271d0fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000643041cbd36888becc7bbcbc0045e3b1f144466f5f5777d92f208679db4b9778590fa3cab3ac9e2168010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb483041cbd36888becc7bbcbc0045e3b1f144466f5fcd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200 diff --git a/tests/common/mod.rs b/tests/common/mod.rs index b10ca13..9a0fb98 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -43,6 +43,10 @@ pub fn pepe() -> Bytes { Bytes::from_str("0x6982508145454Ce325dDbE47a25d4ec3d2311933").unwrap() } +pub fn usdt() -> Bytes { + Bytes::from_str("0xdAC17F958D2ee523a2206206994597C13D831ec7").unwrap() +} + pub fn get_signer() -> PrivateKeySigner { // Set up a mock private key for signing (Alice's pk in our contract tests) let private_key = diff --git a/tests/uniswap_x_integration_tests.rs b/tests/uniswap_x_integration_tests.rs index b55bb90..0c60a39 100644 --- a/tests/uniswap_x_integration_tests.rs +++ b/tests/uniswap_x_integration_tests.rs @@ -12,54 +12,54 @@ use tycho_execution::encoding::{ }; use crate::common::{ - encoding::encode_tycho_router_call, eth, eth_chain, get_tycho_router_encoder, router_address, - usdc, wbtc, weth, + dai, encoding::encode_tycho_router_call, eth, eth_chain, get_tycho_router_encoder, + router_address, usdc, usdt, }; mod common; #[test] fn test_sequential_swap_unix() { - // Performs a sequential swap from WETH to USDC though WBTC using USV3 and USV2 - // pools + // Replicates real uniswap X order settled in tx: + // 0x005d7b150017ba1b59d2f99395ccae7bda9b739938ade4e509817e32760aaf9d + // Performs a sequential + // swap from DAI to USDT though USDC using USV3 and USV2 pools // - // WETH ───(USV3)──> WBTC ───(USV2)──> USDC + // DAI ───(USV3)──> USDC ───(USV2)──> USDT // Creates all the calldata needed for the uniswap X callbackData let filler = Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(); let unix_reactor = Address::from_str("0x00000011F84B9aa48e5f8aA8B9897600006289Be").unwrap(); - let weth = weth(); - let wbtc = wbtc(); + let dai = dai(); let usdc = usdc(); + let usdt = usdt(); - let swap_weth_wbtc = Swap { + let swap_dai_usdc = Swap { component: ProtocolComponent { - id: "0xCBCdF9626bC03E24f779434178A73a0B4bad62eD".to_string(), + id: "0x5777d92f208679DB4b9778590Fa3CAB3aC9e2168".to_string(), protocol_system: "uniswap_v3".to_string(), static_attributes: { let mut attrs = HashMap::new(); - attrs.insert( - "fee".to_string(), - Bytes::from(BigInt::from(3000).to_signed_bytes_be()), - ); + attrs + .insert("fee".to_string(), Bytes::from(BigInt::from(100).to_signed_bytes_be())); attrs }, ..Default::default() }, - token_in: weth.clone(), - token_out: wbtc.clone(), + token_in: dai.clone(), + token_out: usdc.clone(), split: 0f64, user_data: None, }; - let swap_wbtc_usdc = Swap { + let swap_usdc_usdt = Swap { component: ProtocolComponent { - id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(), + id: "0x3041CbD36888bECc7bbCBc0045E3B1f144466f5f".to_string(), protocol_system: "uniswap_v2".to_string(), ..Default::default() }, - token_in: wbtc.clone(), - token_out: usdc.clone(), + token_in: usdc.clone(), + token_out: usdt.clone(), split: 0f64, user_data: None, }; @@ -67,13 +67,13 @@ fn test_sequential_swap_unix() { let solution = Solution { exact_out: false, - given_token: weth.clone(), - given_amount: BigUint::from_str("1_000000000000000000").unwrap(), - checked_token: usdc.clone(), - checked_amount: BigUint::from_str("26173932").unwrap(), + given_token: dai.clone(), + given_amount: BigUint::from_str("2_000_000000000000000000").unwrap(), + checked_token: usdt.clone(), + checked_amount: BigUint::from_str("1_990_000000").unwrap(), sender: filler.clone(), receiver: filler.clone(), - swaps: vec![swap_weth_wbtc, swap_wbtc_usdc], + swaps: vec![swap_dai_usdc, swap_usdc_usdt], ..Default::default() }; @@ -99,7 +99,7 @@ fn test_sequential_swap_unix() { let token_in_approval_needed = token_approvals_manager .approval_needed( - bytes_to_address(&weth).unwrap(), + bytes_to_address(&dai).unwrap(), filler_address, bytes_to_address(&router_address()).unwrap(), ) From 4fef906e421d9595b388e463b4f28af1890dabe4 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Wed, 9 Jul 2025 15:44:41 -0400 Subject: [PATCH 30/58] test: Use calldata in USX integration test - Needed to update the filler address with the one from the test - Removed unnecessary approval from non-integration test. The approval is now performed in the callback method. --- foundry/test/assets/calldata.txt | 2 +- foundry/test/uniswap_x/UniswapXFiller.t.sol | 47 ++++++++++++++++++--- tests/uniswap_x_integration_tests.rs | 11 ++--- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 5c45c3b..1bb2e40 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -33,4 +33,4 @@ test_encode_balancer_v3:7bc3485026ac48b6cf9baf0a377477fff5703af8c71ea051a5f82c67 test_single_encoding_strategy_balancer_v3:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000097ffedb80d4b2ca6105a07a4d90eb739c45a66600000000000000000000000030881baa943777f92dc934d53d3bfdf33382cab300000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000006503a6a84cd762d9707a21605b548aaab891562aab097ffedb80d4b2ca6105a07a4d90eb739c45a66630881baa943777f92dc934d53d3bfdf33382cab3f028ac624074d6793c36dc8a06ecec0f5a39a71800cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000 test_uniswap_v3_balancer_v3:e21dd0d3000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004a220e6096b25eadb88358cb44068a324825467500000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed0000006503a6a84cd762d9707a21605b548aaab891562aab2260fac5e5542a773aa44fbcfedf7c193bc2c5994a220e6096b25eadb88358cb44068a3248254675571bea0e99e139cd0b6b7d9352ca872dfe0d72dd01cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000 test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7f00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411d60a13b5e993ef8088cb2cb7e16281f47fbc329bd0ec2a48165e7898542a7ed12fe7ffdec713b6d94e99ddf0a384674617b6190b8534491d525ecb090c8e4881c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_sequential_swap_unix:0101e21dd0d300000000000000000000000000000000000000000000006c6b935b8bbd4000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000769cfd8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470b6b175474e89094c44da98b954eedeac495271d0fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000643041cbd36888becc7bbcbc0045e3b1f144466f5f5777d92f208679db4b9778590fa3cab3ac9e2168010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb483041cbd36888becc7bbcbc0045e3b1f144466f5fcd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200 +test_sequential_swap_usx:0101e21dd0d300000000000000000000000000000000000000000000006c6b935b8bbd4000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000769cfd80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d9da78b6a5bedca287aa5d49613ba36b90c15c40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470b6b175474e89094c44da98b954eedeac495271d0fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000643041cbd36888becc7bbcbc0045e3b1f144466f5f5777d92f208679db4b9778590fa3cab3ac9e2168010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb483041cbd36888becc7bbcbc0045e3b1f144466f5f6d9da78b6a5bedca287aa5d49613ba36b90c15c4010200 diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index 5128339..b473277 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -72,9 +72,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { abi.encodePacked(true, true, tychoRouterData); deal(WETH_ADDR, address(filler), amountIn); - vm.startPrank(address(filler)); - IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); - vm.stopPrank(); + ResolvedOrder[] memory orders = new ResolvedOrder[](1); OutputToken[] memory outputs = new OutputToken[](1); outputs[0] = OutputToken({ @@ -82,7 +80,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { amount: 1847751195973566072891, recipient: BOB }); - // Mostly irrelevant fields for this test - we only need token input and outputs + // Irrelevant fields for this test - we only need token output // info for the sake of testing. orders[0] = ResolvedOrder({ info: OrderInfo({ @@ -96,7 +94,6 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { input: InputToken({ token: address(WETH_ADDR), amount: amountIn, - // We need the proper maxAmount for our approval to work maxAmount: amountIn }), outputs: outputs, @@ -119,7 +116,45 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { assertGe(IERC20(DAI_ADDR).balanceOf(BOB), amountOut); } - function testExecuteIntegration() public { + function testCallbackIntegration() public { + fillerSetup(); + deal(DAI_ADDR, address(filler), 2000 ether); + uint256 amountOut = 1994835180; + + ResolvedOrder[] memory orders = new ResolvedOrder[](1); + OutputToken[] memory outputs = new OutputToken[](1); + + outputs[0] = + OutputToken({token: address(USDT_ADDR), amount: 0, recipient: BOB}); + // Irrelevant fields for this test - we only need token output + // info for the sake of testing. + orders[0] = ResolvedOrder({ + info: OrderInfo({ + reactor: address(0), + swapper: address(0), + nonce: 0, + deadline: 0, + additionalValidationContract: address(0), + additionalValidationData: "" + }), + input: InputToken({token: address(DAI_ADDR), amount: 0, maxAmount: 0}), + outputs: outputs, + sig: "", + hash: "" + }); + bytes memory callbackData = + loadCallDataFromFile("test_sequential_swap_usx"); + + vm.startPrank(REACTOR); + filler.reactorCallback(orders, callbackData); + vm.stopPrank(); + + // Check that the funds are in the filler at the end of the function call + uint256 finalBalance = IERC20(USDT_ADDR).balanceOf(address(filler)); + assertGe(finalBalance, amountOut); + } + + function testExecute() public { fillerSetup(); // tx: 0x5b602b7d0a37e241bd032a907b9ddf314e9f2fc2104fd91cb55bdb3d8dfe4e9c // 0.2 WBTC -> USDC diff --git a/tests/uniswap_x_integration_tests.rs b/tests/uniswap_x_integration_tests.rs index 0c60a39..e349b40 100644 --- a/tests/uniswap_x_integration_tests.rs +++ b/tests/uniswap_x_integration_tests.rs @@ -19,7 +19,7 @@ use crate::common::{ mod common; #[test] -fn test_sequential_swap_unix() { +fn test_sequential_swap_usx() { // Replicates real uniswap X order settled in tx: // 0x005d7b150017ba1b59d2f99395ccae7bda9b739938ade4e509817e32760aaf9d // Performs a sequential @@ -28,8 +28,9 @@ fn test_sequential_swap_unix() { // DAI ───(USV3)──> USDC ───(USV2)──> USDT // Creates all the calldata needed for the uniswap X callbackData - let filler = Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(); - let unix_reactor = Address::from_str("0x00000011F84B9aa48e5f8aA8B9897600006289Be").unwrap(); + let filler = Bytes::from_str("0x6D9da78B6A5BEdcA287AA5d49613bA36b90c15C4").unwrap(); + let usx_reactor = Address::from_str("0x00000011F84B9aa48e5f8aA8B9897600006289Be") + .unwrap(); let dai = dai(); let usdc = usdc(); @@ -106,12 +107,12 @@ fn test_sequential_swap_unix() { .unwrap(); let token_out_approval_needed = token_approvals_manager - .approval_needed(bytes_to_address(&usdc).unwrap(), filler_address, unix_reactor) + .approval_needed(bytes_to_address(&usdc).unwrap(), filler_address, usx_reactor) .unwrap(); let full_calldata = (token_in_approval_needed, token_out_approval_needed, tycho_calldata).abi_encode_packed(); let hex_calldata = encode(&full_calldata); - write_calldata_to_file("test_sequential_swap_unix", hex_calldata.as_str()); + write_calldata_to_file("test_sequential_swap_usx", hex_calldata.as_str()); } From 7cf8a7eeed91334c7b3eb6faaf155243dbad08d4 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Wed, 9 Jul 2025 15:47:43 -0400 Subject: [PATCH 31/58] chore: nightly fmt --- tests/uniswap_x_integration_tests.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/uniswap_x_integration_tests.rs b/tests/uniswap_x_integration_tests.rs index e349b40..80c955a 100644 --- a/tests/uniswap_x_integration_tests.rs +++ b/tests/uniswap_x_integration_tests.rs @@ -29,8 +29,7 @@ fn test_sequential_swap_usx() { // Creates all the calldata needed for the uniswap X callbackData let filler = Bytes::from_str("0x6D9da78B6A5BEdcA287AA5d49613bA36b90c15C4").unwrap(); - let usx_reactor = Address::from_str("0x00000011F84B9aa48e5f8aA8B9897600006289Be") - .unwrap(); + let usx_reactor = Address::from_str("0x00000011F84B9aa48e5f8aA8B9897600006289Be").unwrap(); let dai = dai(); let usdc = usdc(); From 0be6bfbc1a4bb39bb2a8717cba97186afaa11cc3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 10 Jul 2025 14:38:32 +0000 Subject: [PATCH 32/58] chore(release): 0.107.0 [skip ci] ## [0.107.0](https://github.com/propeller-heads/tycho-execution/compare/0.106.0...0.107.0) (2025-07-10) ### Features * (WIP) Handle approvals in UniswapXFiller ([e243667](https://github.com/propeller-heads/tycho-execution/commit/e243667f9ee8ec8e79fc5196da6960b19cd120b7)) * Handle native ETH outputs ([3752c15](https://github.com/propeller-heads/tycho-execution/commit/3752c155ea89d4d2d91be98f2c5fa79264a45999)) ### Bug Fixes * silence slither on native address setting ([1b6a24f](https://github.com/propeller-heads/tycho-execution/commit/1b6a24fd75b91de7570f110e87d81ed081639bb7)) * use encodePacked to encode if approval needed ([9e2f228](https://github.com/propeller-heads/tycho-execution/commit/9e2f228a470d163b71cac22a0f95116716490772)) --- CHANGELOG.md | 14 ++++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57f27d1..d2973e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## [0.107.0](https://github.com/propeller-heads/tycho-execution/compare/0.106.0...0.107.0) (2025-07-10) + + +### Features + +* (WIP) Handle approvals in UniswapXFiller ([e243667](https://github.com/propeller-heads/tycho-execution/commit/e243667f9ee8ec8e79fc5196da6960b19cd120b7)) +* Handle native ETH outputs ([3752c15](https://github.com/propeller-heads/tycho-execution/commit/3752c155ea89d4d2d91be98f2c5fa79264a45999)) + + +### Bug Fixes + +* silence slither on native address setting ([1b6a24f](https://github.com/propeller-heads/tycho-execution/commit/1b6a24fd75b91de7570f110e87d81ed081639bb7)) +* use encodePacked to encode if approval needed ([9e2f228](https://github.com/propeller-heads/tycho-execution/commit/9e2f228a470d163b71cac22a0f95116716490772)) + ## [0.106.0](https://github.com/propeller-heads/tycho-execution/compare/0.105.0...0.106.0) (2025-07-09) diff --git a/Cargo.lock b/Cargo.lock index 099a723..850c202 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4658,7 +4658,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.106.0" +version = "0.107.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 65c9e61..efae5a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.106.0" +version = "0.107.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From cb6042ea7974faee93c1a87ca84fc6677c999548 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 9 Jul 2025 16:48:47 +0100 Subject: [PATCH 33/58] feat: Upgrade tycho-common Took 16 minutes Took 6 minutes --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 850c202..917e099 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4634,15 +4634,15 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tycho-common" -version = "0.70.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da82c4239c76011b8edc19b5d2a2db989c9ff1f74ae6a3dea21486e9b53234" +version = "0.75.0" +source = "git+https://github.com/propeller-heads/tycho-indexer.git?rev=a30c046ac7b022f7a816545486af81e724863f07#a30c046ac7b022f7a816545486af81e724863f07" dependencies = [ "anyhow", "async-trait", "bytes", "chrono", "hex", + "num-bigint", "rand 0.8.5", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index efae5a3..46c6a63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ tokio = { version = "1.38.0", features = ["full"] } chrono = "0.4.39" clap = { version = "4.5.3", features = ["derive"] } once_cell = "1.20.2" -tycho-common = ">0.66.4" +tycho-common = { git = "https://github.com/propeller-heads/tycho-indexer.git", package = "tycho-common", rev = "a30c046ac7b022f7a816545486af81e724863f07" } alloy = { version = "1.0.6", features = ["providers", "rpc-types-eth", "eip712", "signer-local", "node-bindings"], optional = true } From 2c25b5a18f06beb61d93530660d9530bf0c46b36 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Thu, 10 Jul 2025 13:11:46 +0100 Subject: [PATCH 34/58] feat: Use Chain from tycho-core and remove current implementation --- don't change below this line --- ENG-4705 Took 29 minutes --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/encoding/evm/approvals/permit2.rs | 8 +-- src/encoding/evm/encoder_builders.rs | 20 +++--- .../evm/strategy_encoder/strategy_encoders.rs | 32 +++++---- src/encoding/evm/swap_encoder/builder.rs | 3 +- .../evm/swap_encoder/swap_encoder_registry.rs | 13 ++-- .../evm/swap_encoder/swap_encoders.rs | 48 ++++++-------- src/encoding/evm/tycho_encoders.rs | 25 +++---- src/encoding/models.rs | 65 +------------------ src/encoding/swap_encoder.rs | 4 +- tests/common/mod.rs | 7 +- .../optimized_transfers_integration_tests.rs | 12 ++-- tests/protocol_integration_tests.rs | 16 ++--- .../sequential_strategy_integration_tests.rs | 6 +- tests/single_strategy_integration_tests.rs | 10 +-- tests/split_strategy_integration_tests.rs | 6 +- 17 files changed, 110 insertions(+), 169 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 917e099..cdc33dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4635,7 +4635,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tycho-common" version = "0.75.0" -source = "git+https://github.com/propeller-heads/tycho-indexer.git?rev=a30c046ac7b022f7a816545486af81e724863f07#a30c046ac7b022f7a816545486af81e724863f07" +source = "git+https://github.com/propeller-heads/tycho-indexer.git?rev=9c79c8f7a3501e1edd2b86cff43460729b62991f#9c79c8f7a3501e1edd2b86cff43460729b62991f" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 46c6a63..8ab6800 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ tokio = { version = "1.38.0", features = ["full"] } chrono = "0.4.39" clap = { version = "4.5.3", features = ["derive"] } once_cell = "1.20.2" -tycho-common = { git = "https://github.com/propeller-heads/tycho-indexer.git", package = "tycho-common", rev = "a30c046ac7b022f7a816545486af81e724863f07" } +tycho-common = { git = "https://github.com/propeller-heads/tycho-indexer.git", package = "tycho-common", rev = "9c79c8f7a3501e1edd2b86cff43460729b62991f" } alloy = { version = "1.0.6", features = ["providers", "rpc-types-eth", "eip712", "signer-local", "node-bindings"], optional = true } diff --git a/src/encoding/evm/approvals/permit2.rs b/src/encoding/evm/approvals/permit2.rs index 598cb9d..83610ce 100644 --- a/src/encoding/evm/approvals/permit2.rs +++ b/src/encoding/evm/approvals/permit2.rs @@ -187,10 +187,10 @@ mod tests { signers::local::PrivateKeySigner, }; use num_bigint::BigUint; - use tycho_common::models::Chain as TychoCommonChain; + use tycho_common::models::Chain; use super::*; - use crate::encoding::{evm::encoding_utils::sign_permit, models::Chain}; + use crate::encoding::evm::encoding_utils::sign_permit; // These two implementations are to avoid comparing the expiration and sig_deadline fields // because they are timestamps @@ -224,7 +224,7 @@ mod tests { } fn eth_chain() -> Chain { - TychoCommonChain::Ethereum.into() + Chain::Ethereum } #[test] @@ -334,7 +334,7 @@ mod tests { let sol_permit: PermitSingle = PermitSingle::try_from(&permit).expect("Failed to convert to PermitSingle"); - let signature = sign_permit(eth_chain().id, &permit, signer).unwrap(); + let signature = sign_permit(eth_chain().id(), &permit, signer).unwrap(); let encoded = (bytes_to_address(&anvil_account).unwrap(), sol_permit, signature.as_bytes().to_vec()) .abi_encode(); diff --git a/src/encoding/evm/encoder_builders.rs b/src/encoding/evm/encoder_builders.rs index 6ad4d24..b6b6497 100644 --- a/src/encoding/evm/encoder_builders.rs +++ b/src/encoding/evm/encoder_builders.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, str::FromStr}; use alloy::{primitives::B256, signers::local::PrivateKeySigner}; -use tycho_common::{models::Chain as TychoCommonChain, Bytes}; +use tycho_common::{models::Chain, Bytes}; use crate::encoding::{ errors::EncodingError, @@ -10,7 +10,7 @@ use crate::encoding::{ swap_encoder::swap_encoder_registry::SwapEncoderRegistry, tycho_encoders::{TychoExecutorEncoder, TychoRouterEncoder}, }, - models::{Chain, UserTransferType}, + models::UserTransferType, tycho_encoder::TychoEncoder, }; @@ -41,8 +41,8 @@ impl TychoRouterEncoderBuilder { user_transfer_type: None, } } - pub fn chain(mut self, chain: TychoCommonChain) -> Self { - self.chain = Some(chain.into()); + pub fn chain(mut self, chain: Chain) -> Self { + self.chain = Some(chain); self } @@ -85,10 +85,10 @@ impl TychoRouterEncoderBuilder { if let Some(address) = self.router_address { tycho_router_address = address; } else { - let default_routers: HashMap = + let default_routers: HashMap = serde_json::from_str(DEFAULT_ROUTERS_JSON)?; tycho_router_address = default_routers - .get(&chain.name) + .get(&chain) .ok_or(EncodingError::FatalError( "No default router address found for chain".to_string(), ))? @@ -96,7 +96,7 @@ impl TychoRouterEncoderBuilder { } let swap_encoder_registry = - SwapEncoderRegistry::new(self.executors_file_path.clone(), chain.clone())?; + SwapEncoderRegistry::new(self.executors_file_path.clone(), chain)?; let signer = if let Some(pk) = self.swapper_pk { let pk = B256::from_str(&pk).map_err(|_| { @@ -141,8 +141,8 @@ impl TychoExecutorEncoderBuilder { pub fn new() -> Self { TychoExecutorEncoderBuilder { chain: None, executors_file_path: None } } - pub fn chain(mut self, chain: TychoCommonChain) -> Self { - self.chain = Some(chain.into()); + pub fn chain(mut self, chain: Chain) -> Self { + self.chain = Some(chain); self } @@ -158,7 +158,7 @@ impl TychoExecutorEncoderBuilder { pub fn build(self) -> Result, EncodingError> { if let Some(chain) = self.chain { let swap_encoder_registry = - SwapEncoderRegistry::new(self.executors_file_path.clone(), chain.clone())?; + SwapEncoderRegistry::new(self.executors_file_path.clone(), chain)?; Ok(Box::new(TychoExecutorEncoder::new(swap_encoder_registry)?)) } else { Err(EncodingError::FatalError( diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 7c551e0..88eb463 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -1,7 +1,7 @@ use std::{collections::HashSet, str::FromStr}; use alloy::primitives::{aliases::U24, U8}; -use tycho_common::Bytes; +use tycho_common::{models::Chain, Bytes}; use crate::encoding::{ errors::EncodingError, @@ -14,7 +14,7 @@ use crate::encoding::{ swap_encoder::swap_encoder_registry::SwapEncoderRegistry, utils::{get_token_position, percentage_to_uint24, ple_encode}, }, - models::{Chain, EncodedSolution, EncodingContext, NativeAction, Solution, UserTransferType}, + models::{EncodedSolution, EncodingContext, NativeAction, Solution, UserTransferType}, strategy_encoder::StrategyEncoder, swap_encoder::SwapEncoder, }; @@ -52,8 +52,8 @@ impl SingleSwapStrategyEncoder { swap_encoder_registry, router_address: router_address.clone(), transfer_optimization: TransferOptimization::new( - chain.native_token()?, - chain.wrapped_token()?, + chain.native_token().address, + chain.wrapped_native_token().address, user_transfer_type, router_address, ), @@ -186,16 +186,18 @@ impl SequentialSwapStrategyEncoder { "sequentialSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)" }.to_string(); + let native_token_address = chain.native_token().address; + let wrapped_token_address = chain.wrapped_native_token().address; Ok(Self { function_signature, swap_encoder_registry, router_address: router_address.clone(), - native_address: chain.native_token()?, - wrapped_address: chain.wrapped_token()?, + native_address: native_token_address.clone(), + wrapped_address: wrapped_token_address.clone(), sequential_swap_validator: SequentialSwapValidator, transfer_optimization: TransferOptimization::new( - chain.native_token()?, - chain.wrapped_token()?, + native_token_address, + wrapped_token_address, user_transfer_type, router_address, ), @@ -338,16 +340,18 @@ impl SplitSwapStrategyEncoder { } else { "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bool,bytes)" }.to_string(); + let native_token_address = chain.native_token().address; + let wrapped_token_address = chain.wrapped_native_token().address; Ok(Self { function_signature, swap_encoder_registry, - native_address: chain.native_token()?, - wrapped_address: chain.wrapped_token()?, + native_address: native_token_address.clone(), + wrapped_address: wrapped_token_address.clone(), split_swap_validator: SplitSwapValidator, router_address: router_address.clone(), transfer_optimization: TransferOptimization::new( - chain.native_token()?, - chain.wrapped_token()?, + native_token_address, + wrapped_token_address, user_transfer_type, router_address, ), @@ -508,7 +512,7 @@ mod tests { use alloy::{hex::encode, primitives::hex}; use num_bigint::{BigInt, BigUint}; use tycho_common::{ - models::{protocol::ProtocolComponent, Chain as TychoCommonChain}, + models::{protocol::ProtocolComponent, Chain}, Bytes, }; @@ -516,7 +520,7 @@ mod tests { use crate::encoding::models::Swap; fn eth_chain() -> Chain { - TychoCommonChain::Ethereum.into() + Chain::Ethereum } fn weth() -> Bytes { diff --git a/src/encoding/evm/swap_encoder/builder.rs b/src/encoding/evm/swap_encoder/builder.rs index 165758f..0797930 100644 --- a/src/encoding/evm/swap_encoder/builder.rs +++ b/src/encoding/evm/swap_encoder/builder.rs @@ -1,12 +1,13 @@ use std::collections::HashMap; +use tycho_common::models::Chain; + use crate::encoding::{ errors::EncodingError, evm::swap_encoder::swap_encoders::{ BalancerV2SwapEncoder, BalancerV3SwapEncoder, CurveSwapEncoder, EkuboSwapEncoder, MaverickV2SwapEncoder, UniswapV2SwapEncoder, UniswapV3SwapEncoder, UniswapV4SwapEncoder, }, - models::Chain, swap_encoder::SwapEncoder, }; diff --git a/src/encoding/evm/swap_encoder/swap_encoder_registry.rs b/src/encoding/evm/swap_encoder/swap_encoder_registry.rs index a71e187..221ea76 100644 --- a/src/encoding/evm/swap_encoder/swap_encoder_registry.rs +++ b/src/encoding/evm/swap_encoder/swap_encoder_registry.rs @@ -1,12 +1,13 @@ use std::{collections::HashMap, fs}; +use tycho_common::models::Chain; + use crate::encoding::{ errors::EncodingError, evm::{ constants::{DEFAULT_EXECUTORS_JSON, PROTOCOL_SPECIFIC_CONFIG}, swap_encoder::builder::SwapEncoderBuilder, }, - models::Chain, swap_encoder::SwapEncoder, }; @@ -30,15 +31,15 @@ impl SwapEncoderRegistry { } else { DEFAULT_EXECUTORS_JSON.to_string() }; - let config: HashMap> = serde_json::from_str(&config_str)?; + let config: HashMap> = serde_json::from_str(&config_str)?; let executors = config - .get(&chain.name) + .get(&chain) .ok_or(EncodingError::FatalError("No executors found for chain".to_string()))?; - let protocol_specific_config: HashMap>> = + let protocol_specific_config: HashMap>> = serde_json::from_str(PROTOCOL_SPECIFIC_CONFIG)?; let protocol_specific_config = protocol_specific_config - .get(&chain.name) + .get(&chain) .ok_or(EncodingError::FatalError( "No protocol specific config found for chain".to_string(), ))?; @@ -47,7 +48,7 @@ impl SwapEncoderRegistry { let builder = SwapEncoderBuilder::new( protocol, executor_address, - chain.clone(), + chain, protocol_specific_config .get(protocol) .cloned(), diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index c7e30e6..ae79a26 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -5,7 +5,7 @@ use alloy::{ sol_types::SolValue, }; use serde_json::from_str; -use tycho_common::Bytes; +use tycho_common::{models::Chain, Bytes}; use crate::encoding::{ errors::EncodingError, @@ -13,7 +13,7 @@ use crate::encoding::{ approvals::protocol_approvals_manager::ProtocolApprovalsManager, utils::{bytes_to_address, get_static_attribute, pad_to_fixed_size}, }, - models::{Chain, EncodingContext, Swap}, + models::{EncodingContext, Swap}, swap_encoder::SwapEncoder, }; @@ -466,9 +466,9 @@ impl SwapEncoder for CurveSwapEncoder { .to_string(); Ok(Self { executor_address, - native_token_address: chain.native_token()?, + native_token_address: chain.native_token().address, native_token_curve_address, - wrapped_native_token_address: chain.wrapped_token()?, + wrapped_native_token_address: chain.wrapped_native_token().address, }) } @@ -646,7 +646,7 @@ mod tests { use alloy::hex::encode; use num_bigint::BigInt; use tycho_common::{ - models::{protocol::ProtocolComponent, Chain as TychoCoreChain}, + models::{protocol::ProtocolComponent, Chain}, Bytes, }; @@ -681,7 +681,7 @@ mod tests { }; let encoder = UniswapV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, None, ) .unwrap(); @@ -741,7 +741,7 @@ mod tests { }; let encoder = UniswapV3SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, None, ) .unwrap(); @@ -803,7 +803,7 @@ mod tests { }; let encoder = BalancerV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, Some(HashMap::from([( "vault_address".to_string(), "0xba12222222228d8ba445958a75a0704d566bf2c8".to_string(), @@ -878,7 +878,7 @@ mod tests { }; let encoder = UniswapV4SwapEncoder::new( String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, None, ) .unwrap(); @@ -951,7 +951,7 @@ mod tests { let encoder = UniswapV4SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, None, ) .unwrap(); @@ -1046,7 +1046,7 @@ mod tests { let encoder = UniswapV4SwapEncoder::new( String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, None, ) .unwrap(); @@ -1130,9 +1130,7 @@ mod tests { transfer_type: TransferType::Transfer, }; - let encoder = - EkuboSwapEncoder::new(String::default(), TychoCoreChain::Ethereum.into(), None) - .unwrap(); + let encoder = EkuboSwapEncoder::new(String::default(), Chain::Ethereum, None).unwrap(); let encoded_swap = encoder .encode_swap(&swap, &encoding_context) @@ -1163,9 +1161,7 @@ mod tests { let group_token_out = Bytes::from("0xdAC17F958D2ee523a2206206994597C13D831ec7"); // USDT let intermediary_token = Bytes::from("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); // USDC - let encoder = - EkuboSwapEncoder::new(String::default(), TychoCoreChain::Ethereum.into(), None) - .unwrap(); + let encoder = EkuboSwapEncoder::new(String::default(), Chain::Ethereum, None).unwrap(); let encoding_context = EncodingContext { receiver: RECEIVER.into(), @@ -1329,12 +1325,8 @@ mod tests { split: 0f64, user_data: None, }; - let encoder = CurveSwapEncoder::new( - String::default(), - TychoCoreChain::Ethereum.into(), - curve_config(), - ) - .unwrap(); + let encoder = + CurveSwapEncoder::new(String::default(), Chain::Ethereum, curve_config()).unwrap(); let (i, j) = encoder .get_coin_indexes( &swap, @@ -1384,7 +1376,7 @@ mod tests { }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, curve_config(), ) .unwrap(); @@ -1456,7 +1448,7 @@ mod tests { }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, curve_config(), ) .unwrap(); @@ -1529,7 +1521,7 @@ mod tests { }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, Some(HashMap::from([ ( "native_token_address".to_string(), @@ -1603,7 +1595,7 @@ mod tests { }; let encoder = BalancerV3SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, None, ) .unwrap(); @@ -1661,7 +1653,7 @@ mod tests { }; let encoder = MaverickV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, None, ) .unwrap(); diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index 4ecc366..a317b85 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -1,7 +1,7 @@ use std::{collections::HashSet, str::FromStr}; use alloy::signers::local::PrivateKeySigner; -use tycho_common::Bytes; +use tycho_common::{models::Chain, Bytes}; use crate::encoding::{ errors::EncodingError, @@ -16,7 +16,7 @@ use crate::encoding::{ swap_encoder::swap_encoder_registry::SwapEncoderRegistry, }, models::{ - Chain, EncodedSolution, EncodingContext, NativeAction, Solution, Transaction, TransferType, + EncodedSolution, EncodingContext, NativeAction, Solution, Transaction, TransferType, UserTransferType, }, strategy_encoder::StrategyEncoder, @@ -61,19 +61,19 @@ impl TychoRouterEncoder { }; Ok(TychoRouterEncoder { single_swap_strategy: SingleSwapStrategyEncoder::new( - chain.clone(), + chain, swap_encoder_registry.clone(), user_transfer_type.clone(), router_address.clone(), )?, sequential_swap_strategy: SequentialSwapStrategyEncoder::new( - chain.clone(), + chain, swap_encoder_registry.clone(), user_transfer_type.clone(), router_address.clone(), )?, split_swap_strategy: SplitSwapStrategyEncoder::new( - chain.clone(), + chain, swap_encoder_registry, user_transfer_type.clone(), router_address.clone(), @@ -153,11 +153,11 @@ impl TychoEncoder for TychoRouterEncoder { let encoded_solution = self.encode_solution(solution)?; let transaction = encode_tycho_router_call( - self.chain.id, + self.chain.id(), encoded_solution, solution, &self.user_transfer_type, - &self.chain.native_token()?, + &self.chain.native_token().address, self.signer.clone(), )?; @@ -186,8 +186,11 @@ impl TychoEncoder for TychoRouterEncoder { if solution.swaps.is_empty() { return Err(EncodingError::FatalError("No swaps found in solution".to_string())); } - let native_address = self.chain.native_token()?; - let wrapped_address = self.chain.wrapped_token()?; + let native_address = self.chain.native_token().address; + let wrapped_address = self + .chain + .wrapped_native_token() + .address; if let Some(native_action) = &solution.native_action { if native_action == &NativeAction::Wrap { if solution.given_token != native_address { @@ -387,7 +390,7 @@ mod tests { use std::{collections::HashMap, str::FromStr}; use num_bigint::{BigInt, BigUint}; - use tycho_common::models::{protocol::ProtocolComponent, Chain as TychoCommonChain}; + use tycho_common::models::{protocol::ProtocolComponent, Chain}; use super::*; use crate::encoding::models::Swap; @@ -466,7 +469,7 @@ mod tests { } fn eth_chain() -> Chain { - TychoCommonChain::Ethereum.into() + Chain::Ethereum } fn get_swap_encoder_registry() -> SwapEncoderRegistry { diff --git a/src/encoding/models.rs b/src/encoding/models.rs index f26ce86..5f1df64 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -1,13 +1,9 @@ use clap::ValueEnum; -use hex; use num_bigint::BigUint; use serde::{Deserialize, Serialize}; -use tycho_common::{ - models::{protocol::ProtocolComponent, Chain as TychoCommonChain}, - Bytes, -}; +use tycho_common::{models::protocol::ProtocolComponent, Bytes}; -use crate::encoding::{errors::EncodingError, serde_primitives::biguint_string}; +use crate::encoding::serde_primitives::biguint_string; /// Specifies the method for transferring user funds into Tycho execution. /// @@ -210,63 +206,6 @@ pub enum TransferType { None = 2, } -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Chain { - pub id: u64, - pub name: String, -} - -impl From for Chain { - fn from(chain: TychoCommonChain) -> Self { - match chain { - TychoCommonChain::Ethereum => Chain { id: 1, name: chain.to_string() }, - TychoCommonChain::ZkSync => Chain { id: 324, name: chain.to_string() }, - TychoCommonChain::Arbitrum => Chain { id: 42161, name: chain.to_string() }, - TychoCommonChain::Starknet => Chain { id: 0, name: chain.to_string() }, - TychoCommonChain::Base => Chain { id: 8453, name: chain.to_string() }, - TychoCommonChain::Unichain => Chain { id: 130, name: chain.to_string() }, - } - } -} - -impl Chain { - fn decode_hex(&self, hex_str: &str, err_msg: &str) -> Result { - Ok(Bytes::from( - hex::decode(hex_str).map_err(|_| EncodingError::FatalError(err_msg.to_string()))?, - )) - } - - pub fn native_token(&self) -> Result { - let decode_err_msg = "Failed to decode native token"; - match self.id { - 1 | 8453 | 42161 => { - self.decode_hex("0000000000000000000000000000000000000000", decode_err_msg) - } - 324 => self.decode_hex("000000000000000000000000000000000000800A", decode_err_msg), - 130 => self.decode_hex("0000000000000000000000000000000000000000", decode_err_msg), - _ => Err(EncodingError::InvalidInput(format!( - "Native token not set for chain {:?}. Double check the chain is supported.", - self.name - ))), - } - } - - pub fn wrapped_token(&self) -> Result { - let decode_err_msg = "Failed to decode wrapped token"; - match self.id { - 1 => self.decode_hex("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decode_err_msg), - 8453 => self.decode_hex("4200000000000000000000000000000000000006", decode_err_msg), - 324 => self.decode_hex("5AEa5775959fBC2557Cc8789bC1bf90A239D9a91", decode_err_msg), - 42161 => self.decode_hex("82aF49447D8a07e3bd95BD0d56f35241523fBab1", decode_err_msg), - 130 => self.decode_hex("4200000000000000000000000000000000000006", decode_err_msg), - _ => Err(EncodingError::InvalidInput(format!( - "Wrapped token not set for chain {:?}. Double check the chain is supported.", - self.name - ))), - } - } -} - mod tests { use super::*; diff --git a/src/encoding/swap_encoder.rs b/src/encoding/swap_encoder.rs index 2b9c438..233ce58 100644 --- a/src/encoding/swap_encoder.rs +++ b/src/encoding/swap_encoder.rs @@ -1,8 +1,10 @@ use std::collections::HashMap; +use tycho_common::models::Chain; + use crate::encoding::{ errors::EncodingError, - models::{Chain, EncodingContext, Swap}, + models::{EncodingContext, Swap}, }; /// A trait for protocol-specific swap encoding, where each implementation should handle the diff --git a/tests/common/mod.rs b/tests/common/mod.rs index b10ca13..9d31244 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -4,10 +4,9 @@ pub mod encoding; use std::str::FromStr; use alloy::{primitives::B256, signers::local::PrivateKeySigner}; -use tycho_common::{models::Chain as TychoCommonChain, Bytes}; +use tycho_common::{models::Chain, Bytes}; use tycho_execution::encoding::{ - evm::encoder_builders::TychoRouterEncoderBuilder, - models::{Chain, UserTransferType}, + evm::encoder_builders::TychoRouterEncoderBuilder, models::UserTransferType, tycho_encoder::TychoEncoder, }; @@ -16,7 +15,7 @@ pub fn router_address() -> Bytes { } pub fn eth_chain() -> Chain { - TychoCommonChain::Ethereum.into() + Chain::Ethereum } pub fn eth() -> Bytes { diff --git a/tests/optimized_transfers_integration_tests.rs b/tests/optimized_transfers_integration_tests.rs index b348d99..7e7167f 100644 --- a/tests/optimized_transfers_integration_tests.rs +++ b/tests/optimized_transfers_integration_tests.rs @@ -80,7 +80,7 @@ fn test_uniswap_v3_uniswap_v2() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -167,7 +167,7 @@ fn test_uniswap_v3_uniswap_v3() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -263,7 +263,7 @@ fn test_uniswap_v3_curve() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -334,7 +334,7 @@ fn test_balancer_v2_uniswap_v2() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -490,7 +490,7 @@ fn test_multi_protocol() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, @@ -565,7 +565,7 @@ fn test_uniswap_v3_balancer_v3() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, diff --git a/tests/protocol_integration_tests.rs b/tests/protocol_integration_tests.rs index c0cb2ee..5e55513 100644 --- a/tests/protocol_integration_tests.rs +++ b/tests/protocol_integration_tests.rs @@ -63,7 +63,7 @@ fn test_single_encoding_strategy_ekubo() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -115,7 +115,7 @@ fn test_single_encoding_strategy_maverick() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -177,7 +177,7 @@ fn test_single_encoding_strategy_usv4_eth_in() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, @@ -244,7 +244,7 @@ fn test_single_encoding_strategy_usv4_eth_out() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, @@ -330,7 +330,7 @@ fn test_single_encoding_strategy_usv4_grouped_swap() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, @@ -440,7 +440,7 @@ fn test_single_encoding_strategy_curve() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -507,7 +507,7 @@ fn test_single_encoding_strategy_curve_st_eth() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -560,7 +560,7 @@ fn test_single_encoding_strategy_balancer_v3() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, diff --git a/tests/sequential_strategy_integration_tests.rs b/tests/sequential_strategy_integration_tests.rs index 8003854..b296d47 100644 --- a/tests/sequential_strategy_integration_tests.rs +++ b/tests/sequential_strategy_integration_tests.rs @@ -69,7 +69,7 @@ fn test_sequential_swap_strategy_encoder() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, @@ -135,7 +135,7 @@ fn test_sequential_swap_strategy_encoder_no_permit2() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -260,7 +260,7 @@ fn test_sequential_strategy_cyclic_swap() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, diff --git a/tests/single_strategy_integration_tests.rs b/tests/single_strategy_integration_tests.rs index 70374ed..d252ae6 100644 --- a/tests/single_strategy_integration_tests.rs +++ b/tests/single_strategy_integration_tests.rs @@ -54,7 +54,7 @@ fn test_single_swap_strategy_encoder() { .unwrap(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solutions[0].clone(), &solution, &UserTransferType::TransferFromPermit2, @@ -139,7 +139,7 @@ fn test_single_swap_strategy_encoder_no_permit2() { .unwrap()[0] .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -221,7 +221,7 @@ fn test_single_swap_strategy_encoder_no_transfer_in() { .unwrap()[0] .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::None, @@ -305,7 +305,7 @@ fn test_single_swap_strategy_encoder_wrap() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, @@ -357,7 +357,7 @@ fn test_single_swap_strategy_encoder_unwrap() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, diff --git a/tests/split_strategy_integration_tests.rs b/tests/split_strategy_integration_tests.rs index b1d163d..13b9422 100644 --- a/tests/split_strategy_integration_tests.rs +++ b/tests/split_strategy_integration_tests.rs @@ -99,7 +99,7 @@ fn test_split_swap_strategy_encoder() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, @@ -212,7 +212,7 @@ fn test_split_input_cyclic_swap() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, @@ -372,7 +372,7 @@ fn test_split_output_cyclic_swap() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFromPermit2, From effc25c2d723107a56260190d6f7b5c7b8c42e4e Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Thu, 10 Jul 2025 16:30:46 +0100 Subject: [PATCH 35/58] feat: Upgrade tycho-common --- don't change below this line --- ENG-4705 Took 14 minutes --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cdc33dc..8fada03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4635,7 +4635,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tycho-common" version = "0.75.0" -source = "git+https://github.com/propeller-heads/tycho-indexer.git?rev=9c79c8f7a3501e1edd2b86cff43460729b62991f#9c79c8f7a3501e1edd2b86cff43460729b62991f" +source = "git+https://github.com/propeller-heads/tycho-indexer.git?rev=684834a8f053907ad9547b68d870d2e2c4117249#684834a8f053907ad9547b68d870d2e2c4117249" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 8ab6800..a4c35ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ tokio = { version = "1.38.0", features = ["full"] } chrono = "0.4.39" clap = { version = "4.5.3", features = ["derive"] } once_cell = "1.20.2" -tycho-common = { git = "https://github.com/propeller-heads/tycho-indexer.git", package = "tycho-common", rev = "9c79c8f7a3501e1edd2b86cff43460729b62991f" } +tycho-common = { git = "https://github.com/propeller-heads/tycho-indexer.git", package = "tycho-common", rev = "684834a8f053907ad9547b68d870d2e2c4117249" } alloy = { version = "1.0.6", features = ["providers", "rpc-types-eth", "eip712", "signer-local", "node-bindings"], optional = true } From 8458b4628e351daaf4d4a639afc5099903107ff6 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Fri, 11 Jul 2025 16:35:43 +0100 Subject: [PATCH 36/58] feat: Upgrade tycho-common --- don't change below this line --- ENG-4679 Took 5 minutes Took 10 seconds --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8fada03..0233067 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4634,8 +4634,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tycho-common" -version = "0.75.0" -source = "git+https://github.com/propeller-heads/tycho-indexer.git?rev=684834a8f053907ad9547b68d870d2e2c4117249#684834a8f053907ad9547b68d870d2e2c4117249" +version = "0.76.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72ed04dc9d41942c886fc3d58af5b0e23a3e4783ac7294ed7cea61e022a5c4d" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index a4c35ef..84fe0dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ tokio = { version = "1.38.0", features = ["full"] } chrono = "0.4.39" clap = { version = "4.5.3", features = ["derive"] } once_cell = "1.20.2" -tycho-common = { git = "https://github.com/propeller-heads/tycho-indexer.git", package = "tycho-common", rev = "684834a8f053907ad9547b68d870d2e2c4117249" } +tycho-common = ">0.75.1" alloy = { version = "1.0.6", features = ["providers", "rpc-types-eth", "eip712", "signer-local", "node-bindings"], optional = true } From 4c8d5f151adbfbe073ae20efb1034d77df9ee23e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 11 Jul 2025 15:41:55 +0000 Subject: [PATCH 37/58] chore(release): 0.108.0 [skip ci] ## [0.108.0](https://github.com/propeller-heads/tycho-execution/compare/0.107.0...0.108.0) (2025-07-11) ### Features * Upgrade tycho-common ([8458b46](https://github.com/propeller-heads/tycho-execution/commit/8458b4628e351daaf4d4a639afc5099903107ff6)) * Upgrade tycho-common ([effc25c](https://github.com/propeller-heads/tycho-execution/commit/effc25c2d723107a56260190d6f7b5c7b8c42e4e)) * Upgrade tycho-common ([cb6042e](https://github.com/propeller-heads/tycho-execution/commit/cb6042ea7974faee93c1a87ca84fc6677c999548)) * Use Chain from tycho-core and remove current implementation ([2c25b5a](https://github.com/propeller-heads/tycho-execution/commit/2c25b5a18f06beb61d93530660d9530bf0c46b36)) --- CHANGELOG.md | 10 ++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2973e5..e9d50b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [0.108.0](https://github.com/propeller-heads/tycho-execution/compare/0.107.0...0.108.0) (2025-07-11) + + +### Features + +* Upgrade tycho-common ([8458b46](https://github.com/propeller-heads/tycho-execution/commit/8458b4628e351daaf4d4a639afc5099903107ff6)) +* Upgrade tycho-common ([effc25c](https://github.com/propeller-heads/tycho-execution/commit/effc25c2d723107a56260190d6f7b5c7b8c42e4e)) +* Upgrade tycho-common ([cb6042e](https://github.com/propeller-heads/tycho-execution/commit/cb6042ea7974faee93c1a87ca84fc6677c999548)) +* Use Chain from tycho-core and remove current implementation ([2c25b5a](https://github.com/propeller-heads/tycho-execution/commit/2c25b5a18f06beb61d93530660d9530bf0c46b36)) + ## [0.107.0](https://github.com/propeller-heads/tycho-execution/compare/0.106.0...0.107.0) (2025-07-10) diff --git a/Cargo.lock b/Cargo.lock index 0233067..c39cd08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4659,7 +4659,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.107.0" +version = "0.108.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 84fe0dc..63d9cec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.107.0" +version = "0.108.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From 4ba59192fcfe60d6d4f95b9540a2a7d4da202952 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Fri, 11 Jul 2025 17:05:45 -0400 Subject: [PATCH 38/58] feat: add testExecuteIntegration - Needed to change the integration test setup to use two USV3 pools instead of one V3 and V2, since the V2 pool was taking too much fees for the order to be fulfilled. - Also needed to change the fork block to make this test work, which meant also needing to update the data for the existing testExecute. --- foundry/test/Constants.sol | 1 + foundry/test/assets/calldata.txt | 2 +- foundry/test/uniswap_x/UniswapXFiller.t.sol | 68 +++++++++++---------- tests/uniswap_x_integration_tests.rs | 12 +++- 4 files changed, 47 insertions(+), 36 deletions(-) diff --git a/foundry/test/Constants.sol b/foundry/test/Constants.sol index cb81d58..c2ca63d 100644 --- a/foundry/test/Constants.sol +++ b/foundry/test/Constants.sol @@ -77,6 +77,7 @@ contract Constants is Test, BaseConstants { // Uniswap v3 address DAI_WETH_USV3 = 0xC2e9F25Be6257c210d7Adf0D4Cd6E3E881ba25f8; + address DAI_USDT_USV3 = 0x48DA0965ab2d2cbf1C17C09cFB5Cbe67Ad5B1406; address USDC_WETH_USV3 = 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640; // 0.05% fee address USDC_WETH_USV3_2 = 0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8; // 0.3% fee diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 1bb2e40..730de23 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -33,4 +33,4 @@ test_encode_balancer_v3:7bc3485026ac48b6cf9baf0a377477fff5703af8c71ea051a5f82c67 test_single_encoding_strategy_balancer_v3:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000097ffedb80d4b2ca6105a07a4d90eb739c45a66600000000000000000000000030881baa943777f92dc934d53d3bfdf33382cab300000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000006503a6a84cd762d9707a21605b548aaab891562aab097ffedb80d4b2ca6105a07a4d90eb739c45a66630881baa943777f92dc934d53d3bfdf33382cab3f028ac624074d6793c36dc8a06ecec0f5a39a71800cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000 test_uniswap_v3_balancer_v3:e21dd0d3000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004a220e6096b25eadb88358cb44068a324825467500000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed0000006503a6a84cd762d9707a21605b548aaab891562aab2260fac5e5542a773aa44fbcfedf7c193bc2c5994a220e6096b25eadb88358cb44068a3248254675571bea0e99e139cd0b6b7d9352ca872dfe0d72dd01cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000 test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7f00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411d60a13b5e993ef8088cb2cb7e16281f47fbc329bd0ec2a48165e7898542a7ed12fe7ffdec713b6d94e99ddf0a384674617b6190b8534491d525ecb090c8e4881c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_sequential_swap_usx:0101e21dd0d300000000000000000000000000000000000000000000006c6b935b8bbd4000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000769cfd80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d9da78b6a5bedca287aa5d49613ba36b90c15c40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470b6b175474e89094c44da98b954eedeac495271d0fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000643041cbd36888becc7bbcbc0045e3b1f144466f5f5777d92f208679db4b9778590fa3cab3ac9e2168010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb483041cbd36888becc7bbcbc0045e3b1f144466f5f6d9da78b6a5bedca287aa5d49613ba36b90c15c4010200 +test_sequential_swap_usx:0101e21dd0d300000000000000000000000000000000000000000000006c6b935b8bbd4000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000769cfd80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d9da78b6a5bedca287aa5d49613ba36b90c15c40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470b6b175474e89094c44da98b954eedeac495271d0fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000643ede3eca2a72b3aecc820e955b36f38437d013955777d92f208679db4b9778590fa3cab3ac9e2168010000692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48dac17f958d2ee523a2206206994597c13d831ec70000646d9da78b6a5bedca287aa5d49613ba36b90c15c43416cf6c708da44db2624d63ea0aaef7113527c6010100000000000000000000 diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index b473277..6522c84 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -6,7 +6,7 @@ import "@src/uniswap_x/UniswapXFiller.sol"; import "../TychoRouterTestSetup.sol"; contract UniswapXFillerTest is Test, TychoRouterTestSetup { - address EXECUTOR = makeAddr("executor"); + address EXECUTOR = address(0xCe79b081c0c924cb67848723ed3057234d10FC6b); address REACTOR = address(0x00000011F84B9aa48e5f8aA8B9897600006289Be); UniswapXFiller filler; @@ -18,7 +18,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { ); function getForkBlock() public pure override returns (uint256) { - return 22788691; + return 22880493; } function fillerSetup() public { @@ -116,46 +116,49 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { assertGe(IERC20(DAI_ADDR).balanceOf(BOB), amountOut); } - function testCallbackIntegration() public { + function testExecuteIntegration() public { fillerSetup(); - deal(DAI_ADDR, address(filler), 2000 ether); - uint256 amountOut = 1994835180; - ResolvedOrder[] memory orders = new ResolvedOrder[](1); - OutputToken[] memory outputs = new OutputToken[](1); + // Set to time with no more exclusivity penalty for not being exclusive filler + vm.warp(1752050415); - outputs[0] = - OutputToken({token: address(USDT_ADDR), amount: 0, recipient: BOB}); - // Irrelevant fields for this test - we only need token output - // info for the sake of testing. - orders[0] = ResolvedOrder({ - info: OrderInfo({ - reactor: address(0), - swapper: address(0), - nonce: 0, - deadline: 0, - additionalValidationContract: address(0), - additionalValidationData: "" - }), - input: InputToken({token: address(DAI_ADDR), amount: 0, maxAmount: 0}), - outputs: outputs, - sig: "", - hash: "" + deal( + DAI_ADDR, + address(0xD213e6F6dCB2DBaC03FA28b893F6dA1BD822e852), + 2000 ether + ); + + uint256 amountIn = 2000000000000000000000; + + vm.startPrank(address(0xD213e6F6dCB2DBaC03FA28b893F6dA1BD822e852)); + // Approve Permit2 + IERC20(DAI_ADDR).approve( + address(0x000000000022D473030F116dDEE9F6B43aC78BA3), amountIn + ); + vm.stopPrank(); + + // Tx 0x005d7b150017ba1b59d2f99395ccae7bda9b739938ade4e509817e32760aaf9d + // Calldata generated using rust test `test_sequential_swap_usx` + + SignedOrder memory order = SignedOrder({ + order: hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000004449cd34d1eb1fedcf02a1be3834ffde8e6a61800000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006c6b935b8bbd40000000000000000000000000000000000000000000000000006c6b935b8bbd40000000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000011f84b9aa48e5f8aa8b9897600006289be000000000000000000000000d213e6f6dcb2dbac03fa28b893f6da1bd822e8520468320351debb1ddbfb032a239d699e3d54e3ce2b6e1037cd836a784c80b60100000000000000000000000000000000000000000000000000000000686e2bf9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000076f9f4870000000000000000000000000000000000000000000000000000000076566300000000000000000000000000d213e6f6dcb2dbac03fa28b893f6da1bd822e85200000000000000000000000000000000000000000000000000000000686e2aee00000000000000000000000000000000000000000000000000000000686e2b2a000000000000000000000000ce79b081c0c924cb67848723ed3057234d10fc6b0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000007727b5f40000000000000000000000000000000000000000000000000000000000000041a2d261cd4c8930428260f18b55e3036024bac68d58cb2ee6161e6395b0984b827104158713d44ddc4e14d852b48d93d95a4e60b8d5be1ef431c1e82d2f76a4111b00000000000000000000000000000000000000000000000000000000000000", + sig: hex"f4cc5734820e4ee08519045c83a25b75687756053b3d6c0fda2141380dfa6ef17b40f64d9279f237e96982c6ba53a202e01a4358fd66e027c9bdf200d5626f441c" }); + bytes memory callbackData = loadCallDataFromFile("test_sequential_swap_usx"); - vm.startPrank(REACTOR); - filler.reactorCallback(orders, callbackData); + vm.startPrank(EXECUTOR); + filler.execute(order, callbackData); vm.stopPrank(); - - // Check that the funds are in the filler at the end of the function call - uint256 finalBalance = IERC20(USDT_ADDR).balanceOf(address(filler)); - assertGe(finalBalance, amountOut); } function testExecute() public { fillerSetup(); + + // Overwrite block so signature doesn't expire. + vm.rollFork(22788691); + // tx: 0x5b602b7d0a37e241bd032a907b9ddf314e9f2fc2104fd91cb55bdb3d8dfe4e9c // 0.2 WBTC -> USDC SignedOrder memory order = SignedOrder({ @@ -200,11 +203,12 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { vm.stopPrank(); // This is a hack because the tx we are trying to replicate returns a looooot more USDC than what the uni v2 pool does at this point - // 5113180081 is the difference and 54068100 is the fee - deal(USDC_ADDR, address(filler), 5113180081 + 54068100); + // 21613301393 is the difference and 54068100 is the fee + deal(USDC_ADDR, address(filler), 21613301393 + 54068100); vm.startPrank(EXECUTOR); filler.execute(order, callbackData); + console.logUint(IERC20(USDC_ADDR).balanceOf(address(filler))); vm.stopPrank(); } diff --git a/tests/uniswap_x_integration_tests.rs b/tests/uniswap_x_integration_tests.rs index 80c955a..5200578 100644 --- a/tests/uniswap_x_integration_tests.rs +++ b/tests/uniswap_x_integration_tests.rs @@ -23,7 +23,7 @@ fn test_sequential_swap_usx() { // Replicates real uniswap X order settled in tx: // 0x005d7b150017ba1b59d2f99395ccae7bda9b739938ade4e509817e32760aaf9d // Performs a sequential - // swap from DAI to USDT though USDC using USV3 and USV2 pools + // swap from DAI to USDT though USDC using USV3 pools // // DAI ───(USV3)──> USDC ───(USV2)──> USDT // Creates all the calldata needed for the uniswap X callbackData @@ -54,8 +54,14 @@ fn test_sequential_swap_usx() { }; let swap_usdc_usdt = Swap { component: ProtocolComponent { - id: "0x3041CbD36888bECc7bbCBc0045E3B1f144466f5f".to_string(), - protocol_system: "uniswap_v2".to_string(), + id: "0x3416cF6C708Da44DB2624D63ea0AAef7113527C6".to_string(), + protocol_system: "uniswap_v3".to_string(), + static_attributes: { + let mut attrs = HashMap::new(); + attrs + .insert("fee".to_string(), Bytes::from(BigInt::from(100).to_signed_bytes_be())); + attrs + }, ..Default::default() }, token_in: usdc.clone(), From a53fa6502d588c6ee25e190f982c0d67055a0d27 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Fri, 11 Jul 2025 17:17:32 -0400 Subject: [PATCH 39/58] test: rewrite testExecute without hack - We can use the same transaction as the integration test, with a different low-fee USV3 pool. - Don't need to roll the fork either. --- foundry/test/uniswap_x/UniswapXFiller.t.sol | 36 ++++++++++----------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index 6522c84..2c2583f 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -119,7 +119,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { function testExecuteIntegration() public { fillerSetup(); - // Set to time with no more exclusivity penalty for not being exclusive filler + // Set to time with no more penalty for not being exclusive filler vm.warp(1752050415); deal( @@ -153,37 +153,40 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { vm.stopPrank(); } - function testExecute() public { + function testExecutes() public { fillerSetup(); - // Overwrite block so signature doesn't expire. - vm.rollFork(22788691); + // Set to time with no more penalty for not being exclusive filler + vm.warp(1752050415); - // tx: 0x5b602b7d0a37e241bd032a907b9ddf314e9f2fc2104fd91cb55bdb3d8dfe4e9c - // 0.2 WBTC -> USDC + // tx: 0x005d7b150017ba1b59d2f99395ccae7bda9b739938ade4e509817e32760aaf9d + // DAI ──> USDT SignedOrder memory order = SignedOrder({ - order: hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000004449cd34d1eb1fedcf02a1be3834ffde8e6a61800000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000000000000000000000000000000000000001312d000000000000000000000000000000000000000000000000000000000001312d0000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000011f84b9aa48e5f8aa8b9897600006289be0000000000000000000000000d1100e55ef6c4e5800f4624b1e6121d798eb696046832163cef9c09382cf582bb878b37a42933ea2bdf33757942ab2747b3500100000000000000000000000000000000000000000000000000000000685d4150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000004f921447c00000000000000000000000000000000000000000000000000000004f1464dea0000000000000000000000000d1100e55ef6c4e5800f4624b1e6121d798eb696000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000330d86400000000000000000000000000000000000000000000000000000000032bce2600000000000000000000000027213e28d7fda5c57fe9e5dd923818dbccf71c4700000000000000000000000000000000000000000000000000000000685d407600000000000000000000000000000000000000000000000000000000685d40b2000000000000000000000000225a38bc71102999dd13478bfabd7c4d53f2dc170000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000004fb7f8815000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417067afde0759ae3653dad5d412519f488b6e9ed8955b3e3b8606e85c0198a9d71075295d33fe84b5ccc9c2d38a7ea79d7fad68128a37cabc5557342756a4e8311b00000000000000000000000000000000000000000000000000000000000000", - sig: hex"41b7a696a04f897d1e4ccaf88136092169c2874242d55c3fe4c028125efe95340f5ce764b9dce9d2cae241d97ceb515d3f1739972ca884ed51b2870045438c3a1c" + order: hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000004449cd34d1eb1fedcf02a1be3834ffde8e6a61800000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006c6b935b8bbd40000000000000000000000000000000000000000000000000006c6b935b8bbd40000000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000011f84b9aa48e5f8aa8b9897600006289be000000000000000000000000d213e6f6dcb2dbac03fa28b893f6da1bd822e8520468320351debb1ddbfb032a239d699e3d54e3ce2b6e1037cd836a784c80b60100000000000000000000000000000000000000000000000000000000686e2bf9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000076f9f4870000000000000000000000000000000000000000000000000000000076566300000000000000000000000000d213e6f6dcb2dbac03fa28b893f6da1bd822e85200000000000000000000000000000000000000000000000000000000686e2aee00000000000000000000000000000000000000000000000000000000686e2b2a000000000000000000000000ce79b081c0c924cb67848723ed3057234d10fc6b0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000007727b5f40000000000000000000000000000000000000000000000000000000000000041a2d261cd4c8930428260f18b55e3036024bac68d58cb2ee6161e6395b0984b827104158713d44ddc4e14d852b48d93d95a4e60b8d5be1ef431c1e82d2f76a4111b00000000000000000000000000000000000000000000000000000000000000", + sig: hex"f4cc5734820e4ee08519045c83a25b75687756053b3d6c0fda2141380dfa6ef17b40f64d9279f237e96982c6ba53a202e01a4358fd66e027c9bdf200d5626f441c" }); - uint256 amountIn = 0.2 * 10 ** 8; + uint256 amountIn = 2000000000000000000000; bool zeroForOne = true; + uint24 fee = 100; bytes memory protocolData = abi.encodePacked( - WBTC_ADDR, - USDC_WBTC_POOL, + DAI_ADDR, + USDT_ADDR, + fee, fillerAddr, + DAI_USDT_USV3, zeroForOne, RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = - encodeSingleSwap(address(usv2Executor), protocolData); + encodeSingleSwap(address(usv3Executor), protocolData); bytes memory tychoRouterData = abi.encodeWithSelector( tychoRouter.singleSwap.selector, amountIn, - WBTC_ADDR, - USDC_ADDR, + DAI_ADDR, + USDT_ADDR, 1, false, false, @@ -202,13 +205,8 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { IERC20(WBTC_ADDR).approve(tychoRouterAddr, amountIn); vm.stopPrank(); - // This is a hack because the tx we are trying to replicate returns a looooot more USDC than what the uni v2 pool does at this point - // 21613301393 is the difference and 54068100 is the fee - deal(USDC_ADDR, address(filler), 21613301393 + 54068100); - vm.startPrank(EXECUTOR); filler.execute(order, callbackData); - console.logUint(IERC20(USDC_ADDR).balanceOf(address(filler))); vm.stopPrank(); } From a0531bdfadcd4691c6abdd3730a3b234d15b6219 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Fri, 11 Jul 2025 17:18:32 -0400 Subject: [PATCH 40/58] chore: typo fix --- foundry/test/uniswap_x/UniswapXFiller.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foundry/test/uniswap_x/UniswapXFiller.t.sol b/foundry/test/uniswap_x/UniswapXFiller.t.sol index 2c2583f..be92ca3 100644 --- a/foundry/test/uniswap_x/UniswapXFiller.t.sol +++ b/foundry/test/uniswap_x/UniswapXFiller.t.sol @@ -153,7 +153,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup { vm.stopPrank(); } - function testExecutes() public { + function testExecute() public { fillerSetup(); // Set to time with no more penalty for not being exclusive filler From 2d4b0b995b903e42c8b48f499cf406c8d5e46254 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Fri, 11 Jul 2025 18:12:27 -0400 Subject: [PATCH 41/58] feat: UniswapX encoding example --- examples/uniswapx-encoding-example/README.md | 12 ++ examples/uniswapx-encoding-example/main.rs | 172 +++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 examples/uniswapx-encoding-example/README.md create mode 100644 examples/uniswapx-encoding-example/main.rs diff --git a/examples/uniswapx-encoding-example/README.md b/examples/uniswapx-encoding-example/README.md new file mode 100644 index 0000000..d139426 --- /dev/null +++ b/examples/uniswapx-encoding-example/README.md @@ -0,0 +1,12 @@ +# UniswapX Encoding Example + +This guide enables you to: + +1. Create a Solution object +2. Create callback data for executing a UniswapX Order + +## How to run + +```bash +cargo run --release --example uniswapx-encoding-example +``` \ No newline at end of file diff --git a/examples/uniswapx-encoding-example/main.rs b/examples/uniswapx-encoding-example/main.rs new file mode 100644 index 0000000..d60d126 --- /dev/null +++ b/examples/uniswapx-encoding-example/main.rs @@ -0,0 +1,172 @@ +use std::{collections::HashMap, str::FromStr}; + +use alloy::{ + hex::encode, + primitives::{Address, Keccak256}, + sol_types::SolValue, +}; +use num_bigint::{BigInt, BigUint}; +use tycho_common::{models::protocol::ProtocolComponent, Bytes}; +use tycho_execution::encoding::{ + evm::{ + approvals::protocol_approvals_manager::ProtocolApprovalsManager, + encoder_builders::TychoRouterEncoderBuilder, + utils::{biguint_to_u256, bytes_to_address}, + }, + models::{Solution, Swap, UserTransferType}, +}; + +/// Encodes the input data for a function call to the given function selector. +pub fn encode_input(selector: &str, mut encoded_args: Vec) -> Vec { + let mut hasher = Keccak256::new(); + hasher.update(selector.as_bytes()); + let selector_bytes = &hasher.finalize()[..4]; + let mut call_data = selector_bytes.to_vec(); + // Remove extra prefix if present (32 bytes for dynamic data) + // Alloy encoding is including a prefix for dynamic data indicating the offset or length + // but at this point we don't want that + if encoded_args.len() > 32 && + encoded_args[..32] == + [0u8; 31] + .into_iter() + .chain([32].to_vec()) + .collect::>() + { + encoded_args = encoded_args[32..].to_vec(); + } + call_data.extend(encoded_args); + call_data +} + +fn main() { + let router_address = Bytes::from_str("0xfD0b31d2E955fA55e3fa641Fe90e08b677188d35") + .expect("Failed to create router address"); + + // Initialize the encoder + let encoder = TychoRouterEncoderBuilder::new() + .chain(tycho_common::models::Chain::Ethereum) + .user_transfer_type(UserTransferType::TransferFrom) + .executors_file_path("config/test_executor_addresses.json".to_string()) + .router_address(router_address.clone()) + .build() + .expect("Failed to build encoder"); + + // Set up UniswapX-related variables + let filler = Bytes::from_str("0x6D9da78B6A5BEdcA287AA5d49613bA36b90c15C4").unwrap(); + let usx_reactor = Address::from_str("0x00000011F84B9aa48e5f8aA8B9897600006289Be").unwrap(); + + // ------------------- Encode a sequential swap ------------------- + // Prepare data to encode. We will encode a sequential swap from DAI to USDT though USDC using + // USV3 pools + // + // DAI ───(USV3)──> USDC ───(USV2)──> USDT + // + // First we need to create swap objects + + let dai = Bytes::from_str("0x6b175474e89094c44da98b954eedeac495271d0f").unwrap(); + let usdc = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap(); + let usdt = Bytes::from_str("0xdAC17F958D2ee523a2206206994597C13D831ec7").unwrap(); + + let swap_dai_usdc = Swap { + component: ProtocolComponent { + id: "0x5777d92f208679DB4b9778590Fa3CAB3aC9e2168".to_string(), + protocol_system: "uniswap_v3".to_string(), + static_attributes: { + let mut attrs = HashMap::new(); + attrs + .insert("fee".to_string(), Bytes::from(BigInt::from(100).to_signed_bytes_be())); + attrs + }, + ..Default::default() + }, + token_in: dai.clone(), + token_out: usdc.clone(), + split: 0f64, + user_data: None, + }; + let swap_usdc_usdt = Swap { + component: ProtocolComponent { + id: "0x3416cF6C708Da44DB2624D63ea0AAef7113527C6".to_string(), + protocol_system: "uniswap_v3".to_string(), + static_attributes: { + let mut attrs = HashMap::new(); + attrs + .insert("fee".to_string(), Bytes::from(BigInt::from(100).to_signed_bytes_be())); + attrs + }, + ..Default::default() + }, + token_in: usdc.clone(), + token_out: usdt.clone(), + split: 0f64, + user_data: None, + }; + + // Then we create a solution object with the previous swap + let solution = Solution { + exact_out: false, + given_token: dai.clone(), + given_amount: BigUint::from_str("2_000_000000000000000000").unwrap(), + checked_token: usdt.clone(), + checked_amount: BigUint::from_str("1_990_000000").unwrap(), + sender: filler.clone(), + receiver: filler.clone(), + swaps: vec![swap_dai_usdc, swap_usdc_usdt], + ..Default::default() + }; + + // Encode the solution using appropriate safety checks + let encoded_solution = encoder + .encode_solutions(vec![solution.clone()]) + .unwrap()[0] + .clone(); + + let given_amount = biguint_to_u256(&solution.given_amount); + let min_amount_out = biguint_to_u256(&solution.checked_amount); + let given_token = bytes_to_address(&solution.given_token).unwrap(); + let checked_token = bytes_to_address(&solution.checked_token).unwrap(); + let receiver = bytes_to_address(&solution.receiver).unwrap(); + + let method_calldata = ( + given_amount, + given_token, + checked_token, + min_amount_out, + false, // wrap + false, // unwrap + receiver, + true, // transferFrom permitted + encoded_solution.swaps, + ) + .abi_encode(); + + let tycho_calldata = encode_input(&encoded_solution.function_signature, method_calldata); + + // Uniswap X specific part (check necessary approvals) + let filler_address = bytes_to_address(&filler).unwrap(); + let token_approvals_manager = ProtocolApprovalsManager::new().unwrap(); + + let token_in_approval_needed = token_approvals_manager + .approval_needed( + bytes_to_address(&dai).unwrap(), + filler_address, + bytes_to_address(&router_address).unwrap(), + ) + .unwrap(); + + let token_out_approval_needed = token_approvals_manager + .approval_needed(bytes_to_address(&usdc).unwrap(), filler_address, usx_reactor) + .unwrap(); + + let full_calldata = + (token_in_approval_needed, token_out_approval_needed, tycho_calldata).abi_encode_packed(); + + let hex_calldata = encode(&full_calldata); + + println!(" ====== Simple swap WETH -> USDC ======"); + println!( + "The following callback data should be sent to the filler contract, along with the \ + encoded order and signature: {:?}", + hex_calldata + ); +} From 7aa292ef82f411aaf575bcd91ffe640ea12e997b Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Mon, 14 Jul 2025 11:24:05 -0400 Subject: [PATCH 42/58] chore: small polishings to example - Add note in readme that order will need to be encoded still - Fix log - Don't pass executors to builder --- examples/uniswapx-encoding-example/README.md | 3 +++ examples/uniswapx-encoding-example/main.rs | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/uniswapx-encoding-example/README.md b/examples/uniswapx-encoding-example/README.md index d139426..807e685 100644 --- a/examples/uniswapx-encoding-example/README.md +++ b/examples/uniswapx-encoding-example/README.md @@ -5,6 +5,9 @@ This guide enables you to: 1. Create a Solution object 2. Create callback data for executing a UniswapX Order +Note: This guide only encodes the callback data for you. You will still have to encode the call to the +`execute` method of the filler, which also includes the encoded UniswapX order. + ## How to run ```bash diff --git a/examples/uniswapx-encoding-example/main.rs b/examples/uniswapx-encoding-example/main.rs index d60d126..b2e2f5e 100644 --- a/examples/uniswapx-encoding-example/main.rs +++ b/examples/uniswapx-encoding-example/main.rs @@ -46,7 +46,6 @@ fn main() { let encoder = TychoRouterEncoderBuilder::new() .chain(tycho_common::models::Chain::Ethereum) .user_transfer_type(UserTransferType::TransferFrom) - .executors_file_path("config/test_executor_addresses.json".to_string()) .router_address(router_address.clone()) .build() .expect("Failed to build encoder"); @@ -163,7 +162,7 @@ fn main() { let hex_calldata = encode(&full_calldata); - println!(" ====== Simple swap WETH -> USDC ======"); + println!(" ====== Simple swap DAI -> USDT ======"); println!( "The following callback data should be sent to the filler contract, along with the \ encoded order and signature: {:?}", From e775238b0816e71d383193bfdb0cbbfe64e37b7a Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Mon, 14 Jul 2025 11:29:03 -0400 Subject: [PATCH 43/58] fix: chain id call after main update --- tests/uniswap_x_integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/uniswap_x_integration_tests.rs b/tests/uniswap_x_integration_tests.rs index 5200578..8ea134f 100644 --- a/tests/uniswap_x_integration_tests.rs +++ b/tests/uniswap_x_integration_tests.rs @@ -89,7 +89,7 @@ fn test_sequential_swap_usx() { .clone(); let tycho_calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, From f702bf967e43cbeab34819964fcb5e7a5af20116 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 14 Jul 2025 15:39:35 +0000 Subject: [PATCH 44/58] chore(release): 0.109.0 [skip ci] ## [0.109.0](https://github.com/propeller-heads/tycho-execution/compare/0.108.0...0.109.0) (2025-07-14) ### Features * add testExecuteIntegration ([4ba5919](https://github.com/propeller-heads/tycho-execution/commit/4ba59192fcfe60d6d4f95b9540a2a7d4da202952)) ### Bug Fixes * chain id call after main update ([e775238](https://github.com/propeller-heads/tycho-execution/commit/e775238b0816e71d383193bfdb0cbbfe64e37b7a)) * Replicate a real Uniswap X order in integration test ([96d0bf4](https://github.com/propeller-heads/tycho-execution/commit/96d0bf4ba545e4ae369c292aec6b56a32cf77db0)) --- CHANGELOG.md | 13 +++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9d50b4..66ff7fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## [0.109.0](https://github.com/propeller-heads/tycho-execution/compare/0.108.0...0.109.0) (2025-07-14) + + +### Features + +* add testExecuteIntegration ([4ba5919](https://github.com/propeller-heads/tycho-execution/commit/4ba59192fcfe60d6d4f95b9540a2a7d4da202952)) + + +### Bug Fixes + +* chain id call after main update ([e775238](https://github.com/propeller-heads/tycho-execution/commit/e775238b0816e71d383193bfdb0cbbfe64e37b7a)) +* Replicate a real Uniswap X order in integration test ([96d0bf4](https://github.com/propeller-heads/tycho-execution/commit/96d0bf4ba545e4ae369c292aec6b56a32cf77db0)) + ## [0.108.0](https://github.com/propeller-heads/tycho-execution/compare/0.107.0...0.108.0) (2025-07-11) diff --git a/Cargo.lock b/Cargo.lock index c39cd08..a264ecb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4659,7 +4659,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.108.0" +version = "0.109.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 63d9cec..bc099b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.108.0" +version = "0.109.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From 671a456ed7e9b76f118e31a006ae65aba286a42e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 14 Jul 2025 15:46:37 +0000 Subject: [PATCH 45/58] chore(release): 0.110.0 [skip ci] ## [0.110.0](https://github.com/propeller-heads/tycho-execution/compare/0.109.0...0.110.0) (2025-07-14) ### Features * UniswapX encoding example ([2d4b0b9](https://github.com/propeller-heads/tycho-execution/commit/2d4b0b995b903e42c8b48f499cf406c8d5e46254)) --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66ff7fd..7822068 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.110.0](https://github.com/propeller-heads/tycho-execution/compare/0.109.0...0.110.0) (2025-07-14) + + +### Features + +* UniswapX encoding example ([2d4b0b9](https://github.com/propeller-heads/tycho-execution/commit/2d4b0b995b903e42c8b48f499cf406c8d5e46254)) + ## [0.109.0](https://github.com/propeller-heads/tycho-execution/compare/0.108.0...0.109.0) (2025-07-14) diff --git a/Cargo.lock b/Cargo.lock index a264ecb..d93b4e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4659,7 +4659,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.109.0" +version = "0.110.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index bc099b7..4b04d8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.109.0" +version = "0.110.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From efa6fae0e8f3884849dc7ec51f0e32483b483836 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 15 Jul 2025 10:01:38 +0100 Subject: [PATCH 46/58] feat: Uniswap X deployment script --- don't change below this line --- ENG-4675 Took 23 minutes --- foundry/scripts/README.md | 20 ++++++- foundry/scripts/deploy-uniswap-x-filler.js | 62 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 foundry/scripts/deploy-uniswap-x-filler.js diff --git a/foundry/scripts/README.md b/foundry/scripts/README.md index ff170e4..cc7d16e 100644 --- a/foundry/scripts/README.md +++ b/foundry/scripts/README.md @@ -66,4 +66,22 @@ For each of the following, you must select one of `tenderly_ethereum`, `tenderly 2. The scripts deploy-executors, remove-executor, set-roles and revoke-role all support this. 1. If `SAFE_ADDRESS` is set, then it will propose a transaction to the safe wallet and later on it needs to be approved in their UI to execute on chain. - 2. If it's not set, it will submit the transaction directly to the chain. \ No newline at end of file + 2. If it's not set, it will submit the transaction directly to the chain. + +## Deploy Uniswap X filler + +The current script deploys an Uniswap X filler and verifies it in the corresponding blockchain explorer. + +Make sure to run `unset HISTFILE` in your terminal before setting the private key. This will prevent the private key +from being stored in the shell history. + +1. Set the following environment variables: + +``` +export RPC_URL= +export PRIVATE_KEY= +export BLOCKCHAIN_EXPLORER_API_KEY= +``` + +2. Confirm that the variables `tychoRouter`, `uniswapXReactor` and `nativeToken` are correctly set in the script. +3. Run `npx hardhat run scripts/deploy-uniswap-x-filler.js --network NETWORK`. diff --git a/foundry/scripts/deploy-uniswap-x-filler.js b/foundry/scripts/deploy-uniswap-x-filler.js new file mode 100644 index 0000000..e0ab7b4 --- /dev/null +++ b/foundry/scripts/deploy-uniswap-x-filler.js @@ -0,0 +1,62 @@ +require('dotenv').config(); +const {ethers} = require("hardhat"); +const hre = require("hardhat"); + +async function main() { + const network = hre.network.name; + let tychoRouter; + let uniswapXReactor; + let nativeToken; + if (network === "ethereum") { + tychoRouter = "0xfD0b31d2E955fA55e3fa641Fe90e08b677188d35"; + uniswapXReactor = "0x00000011F84B9aa48e5f8aA8B9897600006289Be"; + nativeToken = "0x0000000000000000000000000000000000000000"; + } else if (network === "base") { + tychoRouter = "0xea3207778e39EB02D72C9D3c4Eac7E224ac5d369"; + uniswapXReactor = "0x000000001Ec5656dcdB24D90DFa42742738De729"; + nativeToken = "0x0000000000000000000000000000000000000000"; + } else if (network === "unichain") { + tychoRouter = "0xFfA5ec2e444e4285108e4a17b82dA495c178427B"; + uniswapXReactor = "0x00000006021a6Bce796be7ba509BBBA71e956e37"; + nativeToken = "0x0000000000000000000000000000000000000000"; + } else { + throw new Error(`Unsupported network: ${network}`); + } + + console.log(`Deploying Uniswap X filler to ${network} with:`); + console.log(`- Tycho router: ${tychoRouter}`); + console.log(`- Uniswap X reactor: ${uniswapXReactor}`); + console.log(`- Native token: ${nativeToken}`); + + const [deployer] = await ethers.getSigners(); + console.log(`Deploying with account: ${deployer.address}`); + console.log(`Account balance: ${ethers.utils.formatEther(await deployer.getBalance())} ETH`); + + const UniswapXFiller = await ethers.getContractFactory("UniswapXFiller"); + const filler = await UniswapXFiller.deploy(tychoRouter, uniswapXReactor, nativeToken); + + await filler.deployed(); + console.log(`Uniswap X Filler deployed to: ${filler.address}`); + + console.log("Waiting for 1 minute before verifying the contract on the blockchain explorer..."); + await new Promise(resolve => setTimeout(resolve, 60000)); + + // Verify on Etherscan + try { + await hre.run("verify:verify", { + address: filler.address, + constructorArguments: [tychoRouter, uniswapXReactor, nativeToken], + }); + console.log(`Uniswap X filler verified successfully on blockchain explorer!`); + } catch (error) { + console.error(`Error during blockchain explorer verification:`, error); + } + +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error("Deployment failed:", error); + process.exit(1); + }); \ No newline at end of file From d2d8b290560a435e4b1cac1e3293fe8fd6878091 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 15 Jul 2025 17:08:26 +0100 Subject: [PATCH 47/58] fix: Read Tycho Router addresses from file --- don't change below this line --- ENG-4675 Took 17 minutes --- foundry/scripts/deploy-uniswap-x-filler.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/foundry/scripts/deploy-uniswap-x-filler.js b/foundry/scripts/deploy-uniswap-x-filler.js index e0ab7b4..2528b85 100644 --- a/foundry/scripts/deploy-uniswap-x-filler.js +++ b/foundry/scripts/deploy-uniswap-x-filler.js @@ -1,28 +1,29 @@ require('dotenv').config(); const {ethers} = require("hardhat"); const hre = require("hardhat"); +const path = require("path"); +const fs = require("fs"); async function main() { const network = hre.network.name; - let tychoRouter; let uniswapXReactor; let nativeToken; if (network === "ethereum") { - tychoRouter = "0xfD0b31d2E955fA55e3fa641Fe90e08b677188d35"; uniswapXReactor = "0x00000011F84B9aa48e5f8aA8B9897600006289Be"; nativeToken = "0x0000000000000000000000000000000000000000"; } else if (network === "base") { - tychoRouter = "0xea3207778e39EB02D72C9D3c4Eac7E224ac5d369"; uniswapXReactor = "0x000000001Ec5656dcdB24D90DFa42742738De729"; nativeToken = "0x0000000000000000000000000000000000000000"; } else if (network === "unichain") { - tychoRouter = "0xFfA5ec2e444e4285108e4a17b82dA495c178427B"; uniswapXReactor = "0x00000006021a6Bce796be7ba509BBBA71e956e37"; nativeToken = "0x0000000000000000000000000000000000000000"; } else { throw new Error(`Unsupported network: ${network}`); } + const routerAddressesFilePath = path.join(__dirname, "../../config/router_addresses.json"); + const tychoRouter = JSON.parse(fs.readFileSync(routerAddressesFilePath, "utf8"))[network]; + console.log(`Deploying Uniswap X filler to ${network} with:`); console.log(`- Tycho router: ${tychoRouter}`); console.log(`- Uniswap X reactor: ${uniswapXReactor}`); From 5bf5c8124b764772985b47d92dade2dc68899c08 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 15 Jul 2025 17:13:05 +0100 Subject: [PATCH 48/58] docs: Extend Uniswap X deployment docs --- don't change below this line --- ENG-4675 Took 4 minutes --- foundry/scripts/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/foundry/scripts/README.md b/foundry/scripts/README.md index cc7d16e..713c308 100644 --- a/foundry/scripts/README.md +++ b/foundry/scripts/README.md @@ -83,5 +83,6 @@ export PRIVATE_KEY= export BLOCKCHAIN_EXPLORER_API_KEY= ``` -2. Confirm that the variables `tychoRouter`, `uniswapXReactor` and `nativeToken` are correctly set in the script. +2. Confirm that the variables `tychoRouter`, `uniswapXReactor` and `nativeToken` are correctly set in the script. Make + sure that the Uniswap X Reactor address matches the reactor you are targeting. 3. Run `npx hardhat run scripts/deploy-uniswap-x-filler.js --network NETWORK`. From a057588270cc126280087d255c9b0c9c755a65f0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 15 Jul 2025 16:34:12 +0000 Subject: [PATCH 49/58] chore(release): 0.111.0 [skip ci] ## [0.111.0](https://github.com/propeller-heads/tycho-execution/compare/0.110.0...0.111.0) (2025-07-15) ### Features * Uniswap X deployment script ([efa6fae](https://github.com/propeller-heads/tycho-execution/commit/efa6fae0e8f3884849dc7ec51f0e32483b483836)) ### Bug Fixes * Read Tycho Router addresses from file ([d2d8b29](https://github.com/propeller-heads/tycho-execution/commit/d2d8b290560a435e4b1cac1e3293fe8fd6878091)) --- CHANGELOG.md | 12 ++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7822068..2df9f81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [0.111.0](https://github.com/propeller-heads/tycho-execution/compare/0.110.0...0.111.0) (2025-07-15) + + +### Features + +* Uniswap X deployment script ([efa6fae](https://github.com/propeller-heads/tycho-execution/commit/efa6fae0e8f3884849dc7ec51f0e32483b483836)) + + +### Bug Fixes + +* Read Tycho Router addresses from file ([d2d8b29](https://github.com/propeller-heads/tycho-execution/commit/d2d8b290560a435e4b1cac1e3293fe8fd6878091)) + ## [0.110.0](https://github.com/propeller-heads/tycho-execution/compare/0.109.0...0.110.0) (2025-07-14) diff --git a/Cargo.lock b/Cargo.lock index d93b4e9..e67b69f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4659,7 +4659,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.110.0" +version = "0.111.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 4b04d8f..d880a11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.110.0" +version = "0.111.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From c21770256045b3fdaddb889effa09b839f59755e Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Tue, 22 Jul 2025 12:13:39 -0400 Subject: [PATCH 50/58] feat: Add protocol state to Swap object - This consists of lots of necessary battles with lifetimes. --- Cargo.lock | 4 +- Cargo.toml | 2 +- examples/encoding-example/main.rs | 5 ++ examples/uniswapx-encoding-example/main.rs | 2 + foundry/test/assets/calldata.txt | 24 +++++----- src/encoding/evm/group_swaps.rs | 46 +++++++++++++------ .../evm/strategy_encoder/strategy_encoders.rs | 10 ++++ .../strategy_encoder/strategy_validators.rs | 21 +++++++++ .../transfer_optimizations.rs | 2 + .../evm/swap_encoder/swap_encoders.rs | 16 +++++++ src/encoding/evm/tycho_encoders.rs | 29 +++++++++++- src/encoding/models.rs | 41 +++++++++++++---- .../optimized_transfers_integration_tests.rs | 15 ++++++ tests/protocol_integration_tests.rs | 9 ++++ .../sequential_strategy_integration_tests.rs | 6 +++ tests/single_strategy_integration_tests.rs | 5 ++ tests/split_strategy_integration_tests.rs | 10 ++++ tests/uniswap_x_integration_tests.rs | 2 + 18 files changed, 210 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e67b69f..0606b67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4634,9 +4634,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tycho-common" -version = "0.76.0" +version = "0.78.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72ed04dc9d41942c886fc3d58af5b0e23a3e4783ac7294ed7cea61e022a5c4d" +checksum = "2af4c7e2c8e194a3e9dfc5911ff0ec273b7dd52acb71dfdcf21351dd78a49576" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index d880a11..1a99fe2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ tokio = { version = "1.38.0", features = ["full"] } chrono = "0.4.39" clap = { version = "4.5.3", features = ["derive"] } once_cell = "1.20.2" -tycho-common = ">0.75.1" +tycho-common = ">0.78.1" alloy = { version = "1.0.6", features = ["providers", "rpc-types-eth", "eip712", "signer-local", "node-bindings"], optional = true } diff --git a/examples/encoding-example/main.rs b/examples/encoding-example/main.rs index 1eb1f44..9a4b9e4 100644 --- a/examples/encoding-example/main.rs +++ b/examples/encoding-example/main.rs @@ -43,6 +43,7 @@ fn main() { // the amount or the total remaining balance. split: 0f64, user_data: None, + protocol_state: None, }; // Then we create a solution object with the previous swap @@ -96,6 +97,7 @@ fn main() { token_out: dai.clone(), split: 0.5f64, user_data: None, + protocol_state: None, }; let swap_weth_wbtc = Swap { component: ProtocolComponent { @@ -109,6 +111,7 @@ fn main() { // 0 to signify "the remainder of the WETH value". It should still be very close to 50% split: 0f64, user_data: None, + protocol_state: None, }; let swap_dai_usdc = Swap { component: ProtocolComponent { @@ -120,6 +123,7 @@ fn main() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -131,6 +135,7 @@ fn main() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let mut complex_solution = solution.clone(); complex_solution.swaps = vec![swap_weth_dai, swap_weth_wbtc, swap_dai_usdc, swap_wbtc_usdc]; diff --git a/examples/uniswapx-encoding-example/main.rs b/examples/uniswapx-encoding-example/main.rs index b2e2f5e..928ffff 100644 --- a/examples/uniswapx-encoding-example/main.rs +++ b/examples/uniswapx-encoding-example/main.rs @@ -82,6 +82,7 @@ fn main() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_usdc_usdt = Swap { component: ProtocolComponent { @@ -99,6 +100,7 @@ fn main() { token_out: usdt.clone(), split: 0f64, user_data: None, + protocol_state: None, }; // Then we create a solution object with the previous swap diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 730de23..36b148b 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -3,25 +3,25 @@ test_single_encoding_strategy_ekubo:5c4b639c000000000000000000000000000000000000 test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000 test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006880f27600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7e00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041509fa14e28ad71fed11dae329c5d17b4cc634b74379cef3b5c5bfe445d5a929d0e139ad79e8ec09bc6368b9d1a5ad350d98e467e05e453d47431333ee985fd4d1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:30ace1b100000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006880f27600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7e00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041df4f662a218a599150507f1089ea781771903aa5ed41e5f24d57483074b469c031a18bb247df38ecf866faf5ff86cec389e3410124260218fb99dc9e01b788b01c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c0000000000000000000000000000000000000000 -test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7e00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041176632aaa7a353a547b128b56c490c4da926ad7ba12aeace54629f750e937ab704fa1f9b9149872d39553d2d987ec882840b73a44c036d476ea0e75439346c2f1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041aa05dfce0bca6785026b114e751b149b0e1ef2649598455bbc013893d1a241c546ccd30a543e261c8bb565c673b9c7fcc28f72325d9d059e7fc4e31a299c895a1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:30ace1b100000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041dacc6c754032bb9de8d264c64a46f2b309335b01f837b2f5b8b7b68bfa920a4537220bab168a5b0f3b84469365c91e0013d3950aca01664b993b3c18c291545b1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c0000000000000000000000000000000000000000 +test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ca1a9b5e5aef9624ec8e786ff0fb16fc4ed0758a421d99754184430aa95833b223eee4e65bcbf835f5f2ea2bdc2046231f6befb919298bfeb7d0271d0ce27f391c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7e00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004128c50a468f1b4bb63b28f8dd8c33c89b065effdf718ce87632e7d16f3a22a8c661e05ccd2d9fb65719f6b3123a40e25a0b5ef1e21f939344e2b92ce0d97805b91c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006880f27600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7e00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004110cf1125cc7207bf96734e97da8e1a7e101e8e9a5886128a6e607e8b3d1fb9775b00f4290b2cc85692273a9622388475ba1a62771d1a834d529af36562139e3e1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 +test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000413b7112285f6b953c073324f6563a055155581aacaa2df8bc92cc21619fda72aa25c386899fe9af623d0419095b7b8f4f9af2466e1eebb4d2724dc4e9097d0b111c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415eb48a5bb3d9854bd934b6524f5f568228c9946b22c1f6fd96e3f54ba6d57ce53a9bd5038f43dff33737b1c3f9294336bb9750e8f6c81d3e56b9e087845657c91c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 test_single test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c 6d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006869398600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006841b38e00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041752ca399237fc5086ef89d5f6dabecfb4b43c0753ecfb7020a6a86045db423fd3be9565f79b511fe93f55f76f61b1ac8d786b04051110ca6cbe10bbf69901b871c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006880f27700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ef8669fa0cfea3980202c2526db6e383b14dec72f5b0423432a6e4783a6bc56d51a24d3cf7da4852cd95bb8ad37827877e38bf4b4716111e7113b8af17f6de3d1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004143ab32167d0352fc20dda7b7c0c3fd76452dc2bd6bd675ad3b4ffbcc908ae6401bb7df63b661cb43cab3f8397ea8db0ba510c5c1d939688e4674a108cf46180c1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006880f27800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c80000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041cf6d57a1ab0d7cba6d5c8739142ad0f0a1ea07d50b7f82a644ec5d48125aa3f35a64e1abd5c0007274005e8f5e0031334da2e96a06b2935267f947f8e856f6e11b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 -test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006880f27800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c80000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041cf6d57a1ab0d7cba6d5c8739142ad0f0a1ea07d50b7f82a644ec5d48125aa3f35a64e1abd5c0007274005e8f5e0031334da2e96a06b2935267f947f8e856f6e11b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 -test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c80000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041a0be3470609c83fed0b58f0171e2e929ed46ddc952b8ccd76a54e6eb686f9ad961e9ec6a7f89423584fd0b56336640cf62b44c658b4616a2cf79b0cdf0c8980e1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000068a7452d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3500000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000416cf5d0fb75c24a379e1988e7ffa76de4e9573ecd42f79a380566f720734698e56cbb6034bd9cf713e6c4a89c4a57f768a360fc83df588fed402be248e2291cc51c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3500000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041e3abc1917a9102020e3a8e5f3c9cd8c95088f0f54315938b0fc21d9c74d33ca969bea7ea4cc8889cc403f3940e51b55ee56a5b918e649b5a147d2e47b68411fc1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068a7452e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf360000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416619afeffa8f49edde843d038e64e278de064d24586a84d3f6fc592d0e9e263e1f59599118eb7b25a8d4c1362b52728b076997b99ce7fd780b77ddf9ee674bb71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 +test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068a7452e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf360000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416619afeffa8f49edde843d038e64e278de064d24586a84d3f6fc592d0e9e263e1f59599118eb7b25a8d4c1362b52728b076997b99ce7fd780b77ddf9ee674bb71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 +test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf36000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c742469c49e8a03a8285ba3328e786a99b8a792c642fd9e409bc06f3baee04ea6589bdb0bd195122e9af08c8296f9841fff7a32be8b3afd44a586ee65ed684151b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 -test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf00000000000000000000000000000000000000000000000000000000000006880f27500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7d00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ddbcb13f2381def6b19a68af409abaefa505ddbc282c9db0a48bf53135726b7e603b248a314f46822406c9f406793673ff0e775fa584d41c3c08283f958a59d31c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000068a7452b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417fa6c0b85fb91e2737e39084c4530258c41c99f16a2796ea7400494d6486496525c653898965dde735537ef4b7ee93a79b5c6f11196a35b79e6d00f0b34811ac1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102 test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c @@ -32,5 +32,5 @@ test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e test_encode_balancer_v3:7bc3485026ac48b6cf9baf0a377477fff5703af8c71ea051a5f82c67adcf634c36ffe6334793d24c85b2b559bc2d21104c4defdd6efca8a20343361d011d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e test_single_encoding_strategy_balancer_v3:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000097ffedb80d4b2ca6105a07a4d90eb739c45a66600000000000000000000000030881baa943777f92dc934d53d3bfdf33382cab300000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000006503a6a84cd762d9707a21605b548aaab891562aab097ffedb80d4b2ca6105a07a4d90eb739c45a66630881baa943777f92dc934d53d3bfdf33382cab3f028ac624074d6793c36dc8a06ecec0f5a39a71800cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000 test_uniswap_v3_balancer_v3:e21dd0d3000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004a220e6096b25eadb88358cb44068a324825467500000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed0000006503a6a84cd762d9707a21605b548aaab891562aab2260fac5e5542a773aa44fbcfedf7c193bc2c5994a220e6096b25eadb88358cb44068a3248254675571bea0e99e139cd0b6b7d9352ca872dfe0d72dd01cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000 -test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880f27700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068596c7f00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411d60a13b5e993ef8088cb2cb7e16281f47fbc329bd0ec2a48165e7898542a7ed12fe7ffdec713b6d94e99ddf0a384674617b6190b8534491d525ecb090c8e4881c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3500000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004154d32a9cdc3955c1e9ba8767bb29c3a197c7497bf87aba59eb050278f39a999a609510cf1aa2535142e67b07ce9755f926877ff618c5ffaa684c0bcc310fdd7d1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_sequential_swap_usx:0101e21dd0d300000000000000000000000000000000000000000000006c6b935b8bbd4000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000769cfd80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d9da78b6a5bedca287aa5d49613ba36b90c15c40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470b6b175474e89094c44da98b954eedeac495271d0fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000643ede3eca2a72b3aecc820e955b36f38437d013955777d92f208679db4b9778590fa3cab3ac9e2168010000692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48dac17f958d2ee523a2206206994597c13d831ec70000646d9da78b6a5bedca287aa5d49613ba36b90c15c43416cf6c708da44db2624d63ea0aaef7113527c6010100000000000000000000 diff --git a/src/encoding/evm/group_swaps.rs b/src/encoding/evm/group_swaps.rs index 7aca6c1..a92e28d 100644 --- a/src/encoding/evm/group_swaps.rs +++ b/src/encoding/evm/group_swaps.rs @@ -11,20 +11,30 @@ use crate::encoding::{evm::constants::GROUPABLE_PROTOCOLS, models::Swap}; /// * `protocol_system`: String, the protocol system of the swaps /// * `swaps`: Vec, the sequence of swaps to be executed as a group /// * `split`: f64, the split percentage of the first swap in the group -#[derive(Clone, PartialEq, Debug)] -pub struct SwapGroup { +#[derive(Clone, Debug)] +pub struct SwapGroup<'a> { pub token_in: Bytes, pub token_out: Bytes, pub protocol_system: String, - pub swaps: Vec, + pub swaps: Vec>, pub split: f64, } +impl<'a> PartialEq for SwapGroup<'a> { + fn eq(&self, other: &Self) -> bool { + self.token_in == other.token_in && + self.token_out == other.token_out && + self.protocol_system == other.protocol_system && + self.swaps == other.swaps && + self.split == other.split + } +} + /// Group consecutive swaps which can be encoded into one swap execution for gas optimization. /// /// An example where this applies is the case of USV4, which uses a PoolManager contract /// to save token transfers on consecutive swaps. -pub fn group_swaps(swaps: &Vec) -> Vec { +pub fn group_swaps<'a>(swaps: &'a Vec>) -> Vec> { let mut grouped_swaps: Vec = Vec::new(); let mut current_group: Option = None; let mut last_swap_protocol = "".to_string(); @@ -106,6 +116,7 @@ mod tests { // 0 to signify "the remainder of the WETH value". It should still be very close to 50% split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -116,6 +127,7 @@ mod tests { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_usdc_dai = Swap { component: ProtocolComponent { @@ -126,12 +138,10 @@ mod tests { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }; - let grouped_swaps = group_swaps(&vec![ - swap_weth_wbtc.clone(), - swap_wbtc_usdc.clone(), - swap_usdc_dai.clone(), - ]); + let swaps = vec![swap_weth_wbtc.clone(), swap_wbtc_usdc.clone(), swap_usdc_dai.clone()]; + let grouped_swaps = group_swaps(&swaps); assert_eq!( grouped_swaps, @@ -178,6 +188,7 @@ mod tests { token_out: weth.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_weth_usdc = Swap { component: ProtocolComponent { @@ -188,6 +199,7 @@ mod tests { token_out: usdc.clone(), split: 0.5f64, user_data: None, + protocol_state: None, }; let swap_weth_dai = Swap { component: ProtocolComponent { @@ -200,6 +212,7 @@ mod tests { // 0 to signify "the remainder of the WETH value". It should still be very close to 50% split: 0f64, user_data: None, + protocol_state: None, }; let swap_dai_usdc = Swap { component: ProtocolComponent { @@ -210,13 +223,15 @@ mod tests { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; - let grouped_swaps = group_swaps(&vec![ + let swaps = vec![ swap_wbtc_weth.clone(), swap_weth_usdc.clone(), swap_weth_dai.clone(), swap_dai_usdc.clone(), - ]); + ]; + let grouped_swaps = group_swaps(&swaps); assert_eq!( grouped_swaps, @@ -269,6 +284,7 @@ mod tests { token_out: wbtc.clone(), split: 0.5f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -279,6 +295,7 @@ mod tests { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_weth_dai = Swap { component: ProtocolComponent { @@ -291,6 +308,7 @@ mod tests { // 0 to signify "the remainder of the WETH value". It should still be very close to 50% split: 0f64, user_data: None, + protocol_state: None, }; let swap_dai_usdc = Swap { component: ProtocolComponent { @@ -301,14 +319,16 @@ mod tests { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; - let grouped_swaps = group_swaps(&vec![ + let swaps = vec![ swap_weth_wbtc.clone(), swap_wbtc_usdc.clone(), swap_weth_dai.clone(), swap_dai_usdc.clone(), - ]); + ]; + let grouped_swaps = group_swaps(&swaps); assert_eq!( grouped_swaps, diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 88eb463..0dea823 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -558,6 +558,7 @@ mod tests { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_encoder_registry = get_swap_encoder_registry(); let encoder = SingleSwapStrategyEncoder::new( @@ -619,6 +620,7 @@ mod tests { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_encoder_registry = get_swap_encoder_registry(); let encoder = SingleSwapStrategyEncoder::new( @@ -690,6 +692,7 @@ mod tests { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -701,6 +704,7 @@ mod tests { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_encoder_registry = get_swap_encoder_registry(); let encoder = SequentialSwapStrategyEncoder::new( @@ -793,6 +797,7 @@ mod tests { token_out: weth.clone(), split: 0.6f64, // 60% of input user_data: None, + protocol_state: None, }; // USDC -> WETH (Pool 2) - 40% of input (remaining) @@ -815,6 +820,7 @@ mod tests { token_out: weth.clone(), split: 0f64, user_data: None, // Remaining 40% + protocol_state: None, }; // WETH -> USDC (Pool 2) @@ -837,6 +843,7 @@ mod tests { token_out: usdc.clone(), split: 0.0f64, user_data: None, + protocol_state: None, }; let swap_encoder_registry = get_swap_encoder_registry(); @@ -945,6 +952,7 @@ mod tests { token_out: weth.clone(), split: 0.0f64, user_data: None, + protocol_state: None, }; let swap_weth_usdc_v3_pool1 = Swap { @@ -966,6 +974,7 @@ mod tests { token_out: usdc.clone(), split: 0.6f64, user_data: None, + protocol_state: None, }; let swap_weth_usdc_v3_pool2 = Swap { @@ -987,6 +996,7 @@ mod tests { token_out: usdc.clone(), split: 0.0f64, user_data: None, + protocol_state: None, }; let swap_encoder_registry = get_swap_encoder_registry(); diff --git a/src/encoding/evm/strategy_encoder/strategy_validators.rs b/src/encoding/evm/strategy_encoder/strategy_validators.rs index 9a46507..6303335 100644 --- a/src/encoding/evm/strategy_encoder/strategy_validators.rs +++ b/src/encoding/evm/strategy_encoder/strategy_validators.rs @@ -215,6 +215,7 @@ mod tests { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }]; let result = validator.validate_swap_path(&swaps, &weth, &dai, &None, ð, &weth); assert_eq!(result, Ok(())); @@ -238,6 +239,7 @@ mod tests { token_out: dai.clone(), split: 0.5f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -249,6 +251,7 @@ mod tests { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }, ]; let result = validator.validate_swap_path(&swaps, &weth, &usdc, &None, ð, &weth); @@ -275,6 +278,7 @@ mod tests { token_out: dai.clone(), split: 0.5, user_data: None, + protocol_state: None, }, // This swap is disconnected from the WETH->DAI path Swap { @@ -287,6 +291,7 @@ mod tests { token_out: usdc.clone(), split: 0.0, user_data: None, + protocol_state: None, }, ]; let result = @@ -315,6 +320,7 @@ mod tests { token_out: weth.clone(), split: 0f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -326,6 +332,7 @@ mod tests { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }, ]; @@ -352,6 +359,7 @@ mod tests { token_out: dai.clone(), split: 1.0, user_data: None, + protocol_state: None, }]; let result = validator.validate_swap_path(&unreachable_swaps, &weth, &usdc, &None, ð, &weth); @@ -391,6 +399,7 @@ mod tests { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }]; let result = validator.validate_split_percentages(&swaps); assert_eq!(result, Ok(())); @@ -414,6 +423,7 @@ mod tests { token_out: dai.clone(), split: 0.5, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -425,6 +435,7 @@ mod tests { token_out: dai.clone(), split: 0.3, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -436,6 +447,7 @@ mod tests { token_out: dai.clone(), split: 0.0, // Remainder (20%) user_data: None, + protocol_state: None, }, ]; assert!(validator @@ -460,6 +472,7 @@ mod tests { token_out: dai.clone(), split: 0.7, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -471,6 +484,7 @@ mod tests { token_out: dai.clone(), split: 0.3, user_data: None, + protocol_state: None, }, ]; assert!(matches!( @@ -496,6 +510,7 @@ mod tests { token_out: dai.clone(), split: 0.0, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -507,6 +522,7 @@ mod tests { token_out: dai.clone(), split: 0.5, user_data: None, + protocol_state: None, }, ]; assert!(matches!( @@ -532,6 +548,7 @@ mod tests { token_out: dai.clone(), split: 0.6, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -543,6 +560,7 @@ mod tests { token_out: dai.clone(), split: 0.5, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -554,6 +572,7 @@ mod tests { token_out: dai.clone(), split: 0.0, user_data: None, + protocol_state: None, }, ]; assert!(matches!( @@ -579,6 +598,7 @@ mod tests { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }]; let result = validator.validate_swap_path( @@ -609,6 +629,7 @@ mod tests { token_out: weth.clone(), split: 0f64, user_data: None, + protocol_state: None, }]; let result = validator.validate_swap_path( diff --git a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs index 4a23ebe..5a62bb2 100644 --- a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs +++ b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs @@ -179,6 +179,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }]; let swap = SwapGroup { protocol_system: protocol, @@ -241,6 +242,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }], }) }; diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index ae79a26..adc133d 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -670,6 +670,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { receiver: Bytes::from("0x1D96F2f6BeF1202E4Ce1Ff6Dad0c2CB002861d3e"), // BOB @@ -730,6 +731,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { receiver: Bytes::from("0x0000000000000000000000000000000000000001"), @@ -791,6 +793,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { // The receiver was generated with `makeAddr("bob") using forge` @@ -864,6 +867,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { // The receiver is ALICE to match the solidity tests @@ -937,6 +941,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { @@ -1034,6 +1039,7 @@ mod tests { token_out: usdt_address.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let second_swap = Swap { @@ -1042,6 +1048,7 @@ mod tests { token_out: wbtc_address.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = UniswapV4SwapEncoder::new( @@ -1119,6 +1126,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { @@ -1188,6 +1196,7 @@ mod tests { token_out: intermediary_token.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let second_swap = Swap { @@ -1204,6 +1213,7 @@ mod tests { token_out: group_token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let first_encoded_swap = encoder @@ -1324,6 +1334,7 @@ mod tests { token_out: Bytes::from(token_out), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = CurveSwapEncoder::new(String::default(), Chain::Ethereum, curve_config()).unwrap(); @@ -1364,6 +1375,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { // The receiver was generated with `makeAddr("bob") using forge` @@ -1436,6 +1448,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { // The receiver was generated with `makeAddr("bob") using forge` @@ -1509,6 +1522,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { // The receiver was generated with `makeAddr("bob") using forge` @@ -1583,6 +1597,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { // The receiver was generated with `makeAddr("bob") using forge` @@ -1641,6 +1656,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoding_context = EncodingContext { // The receiver was generated with `makeAddr("bob") using forge` diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index a317b85..89c3920 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -422,7 +422,7 @@ mod tests { // Fee and tick spacing information for this test is obtained by querying the // USV4 Position Manager contract: 0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e // Using the poolKeys function with the first 25 bytes of the pool id - fn swap_usdc_eth_univ4() -> Swap { + fn swap_usdc_eth_univ4() -> Swap<'static> { let pool_fee_usdc_eth = Bytes::from(BigInt::from(3000).to_signed_bytes_be()); let tick_spacing_usdc_eth = Bytes::from(BigInt::from(60).to_signed_bytes_be()); let mut static_attributes_usdc_eth: HashMap = HashMap::new(); @@ -440,10 +440,11 @@ mod tests { token_out: eth().clone(), split: 0f64, user_data: None, + protocol_state: None, } } - fn swap_eth_pepe_univ4() -> Swap { + fn swap_eth_pepe_univ4() -> Swap<'static> { let pool_fee_eth_pepe = Bytes::from(BigInt::from(25000).to_signed_bytes_be()); let tick_spacing_eth_pepe = Bytes::from(BigInt::from(500).to_signed_bytes_be()); let mut static_attributes_eth_pepe: HashMap = HashMap::new(); @@ -461,6 +462,7 @@ mod tests { token_out: pepe().clone(), split: 0f64, user_data: None, + protocol_state: None, } } @@ -509,6 +511,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -574,6 +577,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_dai_usdc = Swap { @@ -586,6 +590,7 @@ mod tests { token_out: usdc(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -666,6 +671,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -695,6 +701,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -729,6 +736,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -783,6 +791,7 @@ mod tests { token_out: weth(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -811,6 +820,7 @@ mod tests { token_out: weth(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -846,6 +856,7 @@ mod tests { token_out: eth(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -886,6 +897,7 @@ mod tests { token_out: weth(), split: 0.5f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -897,6 +909,7 @@ mod tests { token_out: weth(), split: 0f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -908,6 +921,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }, ]; @@ -941,6 +955,7 @@ mod tests { token_out: weth(), split: 0f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -952,6 +967,7 @@ mod tests { token_out: usdc(), split: 0f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -963,6 +979,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -974,6 +991,7 @@ mod tests { token_out: wbtc(), split: 0f64, user_data: None, + protocol_state: None, }, ]; @@ -1014,6 +1032,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -1025,6 +1044,7 @@ mod tests { token_out: weth(), split: 0.5f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -1036,6 +1056,7 @@ mod tests { token_out: weth(), split: 0f64, user_data: None, + protocol_state: None, }, ]; @@ -1069,6 +1090,7 @@ mod tests { token_out: dai(), split: 0f64, user_data: None, + protocol_state: None, }, Swap { component: ProtocolComponent { @@ -1080,6 +1102,7 @@ mod tests { token_out: weth(), split: 0f64, user_data: None, + protocol_state: None, }, ]; @@ -1134,6 +1157,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { @@ -1194,6 +1218,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let solution = Solution { diff --git a/src/encoding/models.rs b/src/encoding/models.rs index 5f1df64..c590912 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -1,7 +1,9 @@ use clap::ValueEnum; use num_bigint::BigUint; use serde::{Deserialize, Serialize}; -use tycho_common::{models::protocol::ProtocolComponent, Bytes}; +use tycho_common::{ + models::protocol::ProtocolComponent, simulation::protocol_sim::ProtocolSim, Bytes, +}; use crate::encoding::serde_primitives::biguint_string; @@ -33,7 +35,7 @@ pub enum UserTransferType { /// Represents a solution containing details describing an order, and instructions for filling /// the order. #[derive(Clone, Default, Debug, Deserialize, Serialize)] -pub struct Solution { +pub struct Solution<'a> { /// Address of the sender. pub sender: Bytes, /// Address of the receiver. @@ -53,7 +55,7 @@ pub struct Solution { #[serde(with = "biguint_string")] pub checked_amount: BigUint, /// List of swaps to fulfill the solution. - pub swaps: Vec, + pub swaps: Vec>, /// If set, the corresponding native action will be executed. pub native_action: Option, } @@ -71,8 +73,8 @@ pub enum NativeAction { } /// Represents a swap operation to be performed on a pool. -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct Swap { +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Swap<'a> { /// Protocol component from tycho indexer pub component: ProtocolComponent, /// Token being input into the pool. @@ -84,17 +86,32 @@ pub struct Swap { pub split: f64, /// Optional user data to be passed to encoding. pub user_data: Option, + /// Optional protocol state used to perform the swap. + #[serde(skip)] + pub protocol_state: Option<&'a Box>, } -impl Swap { +impl<'a> Swap<'a> { pub fn new>( component: T, token_in: Bytes, token_out: Bytes, split: f64, user_data: Option, + protocol_state: Option<&'a Box>, ) -> Self { - Self { component: component.into(), token_in, token_out, split, user_data } + Self { component: component.into(), token_in, token_out, split, user_data, protocol_state } + } +} + +impl<'a> PartialEq for Swap<'a> { + fn eq(&self, other: &Self) -> bool { + self.component == other.component && + self.token_in == other.token_in && + self.token_out == other.token_out && + self.split == other.split && + self.user_data == other.user_data + // Skip protocol_state comparison since trait objects don't implement PartialEq } } @@ -238,8 +255,14 @@ mod tests { protocol_system: "uniswap_v2".to_string(), }; let user_data = Some(Bytes::from("0x1234")); - let swap = - Swap::new(component, Bytes::from("0x12"), Bytes::from("34"), 0.5, user_data.clone()); + let swap = Swap::new( + component, + Bytes::from("0x12"), + Bytes::from("34"), + 0.5, + user_data.clone(), + None, + ); assert_eq!(swap.token_in, Bytes::from("0x12")); assert_eq!(swap.token_out, Bytes::from("0x34")); assert_eq!(swap.component.protocol_system, "uniswap_v2"); diff --git a/tests/optimized_transfers_integration_tests.rs b/tests/optimized_transfers_integration_tests.rs index 7e7167f..af8404c 100644 --- a/tests/optimized_transfers_integration_tests.rs +++ b/tests/optimized_transfers_integration_tests.rs @@ -48,6 +48,7 @@ fn test_uniswap_v3_uniswap_v2() { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -59,6 +60,7 @@ fn test_uniswap_v3_uniswap_v2() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -127,6 +129,7 @@ fn test_uniswap_v3_uniswap_v3() { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -146,6 +149,7 @@ fn test_uniswap_v3_uniswap_v3() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -213,6 +217,7 @@ fn test_uniswap_v3_curve() { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdt = Swap { @@ -242,6 +247,7 @@ fn test_uniswap_v3_curve() { token_out: usdt.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -301,6 +307,7 @@ fn test_balancer_v2_uniswap_v2() { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { @@ -313,6 +320,7 @@ fn test_balancer_v2_uniswap_v2() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -375,6 +383,7 @@ fn test_multi_protocol() { token_out: weth.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let balancer_swap_weth_wbtc = Swap { @@ -387,6 +396,7 @@ fn test_multi_protocol() { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let curve_swap_wbtc_usdt = Swap { @@ -416,6 +426,7 @@ fn test_multi_protocol() { token_out: usdt.clone(), split: 0f64, user_data: None, + protocol_state: None, }; // Ekubo @@ -438,6 +449,7 @@ fn test_multi_protocol() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; // USV4 @@ -461,6 +473,7 @@ fn test_multi_protocol() { token_out: eth.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -533,6 +546,7 @@ fn test_uniswap_v3_balancer_v3() { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_qnt = Swap { component: ProtocolComponent { @@ -544,6 +558,7 @@ fn test_uniswap_v3_balancer_v3() { token_out: qnt.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); diff --git a/tests/protocol_integration_tests.rs b/tests/protocol_integration_tests.rs index 5e55513..2578f16 100644 --- a/tests/protocol_integration_tests.rs +++ b/tests/protocol_integration_tests.rs @@ -40,6 +40,7 @@ fn test_single_encoding_strategy_ekubo() { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -92,6 +93,7 @@ fn test_single_encoding_strategy_maverick() { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -156,6 +158,7 @@ fn test_single_encoding_strategy_usv4_eth_in() { token_out: pepe.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -222,6 +225,7 @@ fn test_single_encoding_strategy_usv4_eth_out() { token_out: eth.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -296,6 +300,7 @@ fn test_single_encoding_strategy_usv4_grouped_swap() { token_out: eth.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_eth_pepe = Swap { @@ -309,6 +314,7 @@ fn test_single_encoding_strategy_usv4_grouped_swap() { token_out: pepe.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -417,6 +423,7 @@ fn test_single_encoding_strategy_curve() { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -484,6 +491,7 @@ fn test_single_encoding_strategy_curve_st_eth() { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -537,6 +545,7 @@ fn test_single_encoding_strategy_balancer_v3() { token_out: token_out.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); diff --git a/tests/sequential_strategy_integration_tests.rs b/tests/sequential_strategy_integration_tests.rs index b296d47..4d2a758 100644 --- a/tests/sequential_strategy_integration_tests.rs +++ b/tests/sequential_strategy_integration_tests.rs @@ -37,6 +37,7 @@ fn test_sequential_swap_strategy_encoder() { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -48,6 +49,7 @@ fn test_sequential_swap_strategy_encoder() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -103,6 +105,7 @@ fn test_sequential_swap_strategy_encoder_no_permit2() { token_out: wbtc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -114,6 +117,7 @@ fn test_sequential_swap_strategy_encoder_no_permit2() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -215,6 +219,7 @@ fn test_sequential_strategy_cyclic_swap() { token_out: weth.clone(), split: 0f64, user_data: None, + protocol_state: None, }; // WETH -> USDC (Pool 2) @@ -237,6 +242,7 @@ fn test_sequential_strategy_cyclic_swap() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); diff --git a/tests/single_strategy_integration_tests.rs b/tests/single_strategy_integration_tests.rs index d252ae6..30302ce 100644 --- a/tests/single_strategy_integration_tests.rs +++ b/tests/single_strategy_integration_tests.rs @@ -33,6 +33,7 @@ fn test_single_swap_strategy_encoder() { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -119,6 +120,7 @@ fn test_single_swap_strategy_encoder_no_permit2() { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -201,6 +203,7 @@ fn test_single_swap_strategy_encoder_no_transfer_in() { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::None); @@ -284,6 +287,7 @@ fn test_single_swap_strategy_encoder_wrap() { token_out: dai.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -336,6 +340,7 @@ fn test_single_swap_strategy_encoder_unwrap() { token_out: weth(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); diff --git a/tests/split_strategy_integration_tests.rs b/tests/split_strategy_integration_tests.rs index 13b9422..2bd5d45 100644 --- a/tests/split_strategy_integration_tests.rs +++ b/tests/split_strategy_integration_tests.rs @@ -42,6 +42,7 @@ fn test_split_swap_strategy_encoder() { token_out: dai.clone(), split: 0.5f64, user_data: None, + protocol_state: None, }; let swap_weth_wbtc = Swap { component: ProtocolComponent { @@ -56,6 +57,7 @@ fn test_split_swap_strategy_encoder() { // It should still be very close to 50% split: 0f64, user_data: None, + protocol_state: None, }; let swap_dai_usdc = Swap { component: ProtocolComponent { @@ -67,6 +69,7 @@ fn test_split_swap_strategy_encoder() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_wbtc_usdc = Swap { component: ProtocolComponent { @@ -78,6 +81,7 @@ fn test_split_swap_strategy_encoder() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -144,6 +148,7 @@ fn test_split_input_cyclic_swap() { token_out: weth.clone(), split: 0.6f64, // 60% of input user_data: None, + protocol_state: None, }; // USDC -> WETH (Pool 2) - 40% of input (remaining) @@ -166,6 +171,7 @@ fn test_split_input_cyclic_swap() { token_out: weth.clone(), split: 0f64, user_data: None, // Remaining 40% + protocol_state: None, }; // WETH -> USDC (Pool 2) @@ -188,6 +194,7 @@ fn test_split_input_cyclic_swap() { token_out: usdc.clone(), split: 0.0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); @@ -308,6 +315,7 @@ fn test_split_output_cyclic_swap() { token_out: weth.clone(), split: 0.0f64, user_data: None, + protocol_state: None, }; let swap_weth_usdc_v3_pool1 = Swap { @@ -327,6 +335,7 @@ fn test_split_output_cyclic_swap() { token_out: usdc.clone(), split: 0.6f64, user_data: None, + protocol_state: None, }; let swap_weth_usdc_v3_pool2 = Swap { @@ -348,6 +357,7 @@ fn test_split_output_cyclic_swap() { token_out: usdc.clone(), split: 0.0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); diff --git a/tests/uniswap_x_integration_tests.rs b/tests/uniswap_x_integration_tests.rs index 8ea134f..0bf898d 100644 --- a/tests/uniswap_x_integration_tests.rs +++ b/tests/uniswap_x_integration_tests.rs @@ -51,6 +51,7 @@ fn test_sequential_swap_usx() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let swap_usdc_usdt = Swap { component: ProtocolComponent { @@ -68,6 +69,7 @@ fn test_sequential_swap_usx() { token_out: usdt.clone(), split: 0f64, user_data: None, + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); From 95c51247f73516f387e2169e63a22311b4343b8d Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Tue, 22 Jul 2025 12:18:54 -0400 Subject: [PATCH 51/58] fix: Replace smart pointer with regular pointer Apparently was not necessary and was causing clippy warnings. ``` warning: you seem to be trying to use `&Box`. Consider using just `&T` --> src/encoding/models.rs:91:32 | 91 | pub protocol_state: Option<&'a Box>, | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a dyn ProtocolSim` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box = note: `#[warn(clippy::borrowed_box)]` on by default ``` --- examples/uniswapx-encoding-example/main.rs | 3 +-- src/encoding/models.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/uniswapx-encoding-example/main.rs b/examples/uniswapx-encoding-example/main.rs index 928ffff..a35b1cb 100644 --- a/examples/uniswapx-encoding-example/main.rs +++ b/examples/uniswapx-encoding-example/main.rs @@ -167,7 +167,6 @@ fn main() { println!(" ====== Simple swap DAI -> USDT ======"); println!( "The following callback data should be sent to the filler contract, along with the \ - encoded order and signature: {:?}", - hex_calldata + encoded order and signature: {hex_calldata:?}" ); } diff --git a/src/encoding/models.rs b/src/encoding/models.rs index c590912..9ffc367 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -88,7 +88,7 @@ pub struct Swap<'a> { pub user_data: Option, /// Optional protocol state used to perform the swap. #[serde(skip)] - pub protocol_state: Option<&'a Box>, + pub protocol_state: Option<&'a dyn ProtocolSim>, } impl<'a> Swap<'a> { @@ -98,7 +98,7 @@ impl<'a> Swap<'a> { token_out: Bytes, split: f64, user_data: Option, - protocol_state: Option<&'a Box>, + protocol_state: Option<&'a dyn ProtocolSim>, ) -> Self { Self { component: component.into(), token_in, token_out, split, user_data, protocol_state } } From ca762b55b6b3efd75cc113b5d8ab835f4506af33 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 22 Jul 2025 19:56:14 +0000 Subject: [PATCH 52/58] chore(release): 0.112.0 [skip ci] ## [0.112.0](https://github.com/propeller-heads/tycho-execution/compare/0.111.0...0.112.0) (2025-07-22) ### Features * Add protocol state to Swap object ([c217702](https://github.com/propeller-heads/tycho-execution/commit/c21770256045b3fdaddb889effa09b839f59755e)) ### Bug Fixes * Replace smart pointer with regular pointer ([95c5124](https://github.com/propeller-heads/tycho-execution/commit/95c51247f73516f387e2169e63a22311b4343b8d)) --- CHANGELOG.md | 12 ++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2df9f81..b669f1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [0.112.0](https://github.com/propeller-heads/tycho-execution/compare/0.111.0...0.112.0) (2025-07-22) + + +### Features + +* Add protocol state to Swap object ([c217702](https://github.com/propeller-heads/tycho-execution/commit/c21770256045b3fdaddb889effa09b839f59755e)) + + +### Bug Fixes + +* Replace smart pointer with regular pointer ([95c5124](https://github.com/propeller-heads/tycho-execution/commit/95c51247f73516f387e2169e63a22311b4343b8d)) + ## [0.111.0](https://github.com/propeller-heads/tycho-execution/compare/0.110.0...0.111.0) (2025-07-15) diff --git a/Cargo.lock b/Cargo.lock index 0606b67..3b2193d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4659,7 +4659,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.111.0" +version = "0.112.0" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 1a99fe2..800ec7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.111.0" +version = "0.112.0" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From 51d9484de0b4c75b78dc8ca839f4ec7df40f972e Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Thu, 31 Jul 2025 17:08:28 +0100 Subject: [PATCH 53/58] fix: Rename mainnet to ethereum in txServiceUrls for Safe This is used the scripts that interact with TychoRouter Took 7 minutes --- foundry/scripts/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foundry/scripts/utils.js b/foundry/scripts/utils.js index 04faeb8..c59bf9e 100644 --- a/foundry/scripts/utils.js +++ b/foundry/scripts/utils.js @@ -4,7 +4,7 @@ const {EthersAdapter} = require('@safe-global/protocol-kit'); const {default: SafeApiKit} = require("@safe-global/api-kit"); const txServiceUrls = { - mainnet: "https://safe-transaction-mainnet.safe.global", + ethereum: "https://safe-transaction-mainnet.safe.global", base: "https://safe-transaction-base.safe.global", unichain: "https://safe-transaction-unichain.safe.global", }; From 8ecbed43aa1a6dea48ca1d4ce121ca76a0cf6383 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Jul 2025 17:32:20 +0000 Subject: [PATCH 54/58] chore(release): 0.112.1 [skip ci] ## [0.112.1](https://github.com/propeller-heads/tycho-execution/compare/0.112.0...0.112.1) (2025-07-31) ### Bug Fixes * Rename mainnet to ethereum in txServiceUrls for Safe ([51d9484](https://github.com/propeller-heads/tycho-execution/commit/51d9484de0b4c75b78dc8ca839f4ec7df40f972e)) --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b669f1d..4efb830 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.112.1](https://github.com/propeller-heads/tycho-execution/compare/0.112.0...0.112.1) (2025-07-31) + + +### Bug Fixes + +* Rename mainnet to ethereum in txServiceUrls for Safe ([51d9484](https://github.com/propeller-heads/tycho-execution/commit/51d9484de0b4c75b78dc8ca839f4ec7df40f972e)) + ## [0.112.0](https://github.com/propeller-heads/tycho-execution/compare/0.111.0...0.112.0) (2025-07-22) diff --git a/Cargo.lock b/Cargo.lock index 3b2193d..c35f2b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4659,7 +4659,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.112.0" +version = "0.112.1" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 800ec7e..97087d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.112.0" +version = "0.112.1" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From c5f3355935a630eafcf0c05a2778270bf2f3dc0b Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 6 Aug 2025 09:54:14 +0100 Subject: [PATCH 55/58] docs: Add 2nd audit report for TychoRouter Took 8 minutes --- docs/audits/Max_2025-08-05.pdf | Bin 0 -> 223752 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/audits/Max_2025-08-05.pdf diff --git a/docs/audits/Max_2025-08-05.pdf b/docs/audits/Max_2025-08-05.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4133c52a9ddaa73bd811ea7b688ead1c396c8456 GIT binary patch literal 223752 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%0A_o+=JLu#88HN@VZ`X|=NvQjo0p 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 tXvVk$GN5#jrFB*mHsOdO0R9cZ^ zv?`Y7yXiL@mKwO5JN7*3V|l%33SK&QRS{#~IG<7aX!eEp4Vn5}GX^O~)&y>tx`ipL zn@O#Y1rjG`6+=f|2PY|gk7Vz-;tVZZ7f0k%?i@7g6DF`*lUGs@j9 zuM|LTCo0TVWrD;u-!fl9Bpz;`8l^G(B-C5%rn(QXci`u+;~=K~jovD^D%Y@IGy4&C zNU}(-95)&V*N5_n%a#LfAf9zB)`mr%VRw1p!GTUx{)QH1~E8~pxN{llD|={K!cmjCKv^-uKqJFff^^ba&&MO0l< z_%}5F*(~ixlD|gtsh*+yA9y}J+cQ}I52TUi-{ARl-;4XVc>a$h|2;hahXKSd7?bX= zJN&)UKebQ42mOZU|839z$9VqtLH{wuf5P|w13do)>3$&`FR1p*^>Y7$OuyX!!o*+j z?f-QBj%WYC!@r~X&)ED=g#Rzm{pSM!Ucz5;{AYCkCFKjg|ML5<$oN0o_gv!7`X&D>tDitUjJI}zkhzI>EEaLzcKb@y#6c7 z|D6Ngnkk8m`+*_fz&d_YF~u zFpV=A>Kf|l>gs~%`{B~_7&f@BzY}G6h%!C|1De#vAy&(fgpGs>E?kxamHT#&SIHOU zgKipE&KP1AL3SfnkVaPEN}Na>`|6b>o?l{HF7S+GSQzF0lFA7ne7iDEl-?^m{b)D< zN^k6_zaomi3D4>1f8)!)T#WoS2LA)ud6d-Kue7fMuDAo@#=hyAOybMtCR5%DjN!Ca zY>d-Jhp$rF-I1r!20&RvE#CEiKL6siLxwVpn=VkBGVK zJj+lp?fAX{fb?;{2RZA8kRjAUgG&%JgtxShvg2JNT3A%g z2UyN`D7$QtrJ*loem#T88Rw~OtUKylXwYsLTO=7L^p|C6$eo}qd6UJ)6q+MtQW|Hj zT|C~XT_T2MT6HM{gCA}tDmtXZM8@U*L`ze))CS}wTSmByx(jzfhqdy07KY?m>lxZ-()u zeexW9(zd>9(QI)0D~Gk;NBbWOPI}f~>LY)3?km&(;M`ZOs5Yw(yyugPIRhdOGJOdS zXd#7?>Lp%l`^vrX`G5ib6ie^zQtYJ9Ru{JmL!o2^O}Y^!o?7vwahTuBVqa26a6wz zPihC;vr);D4^zfT?hl8_@l zcBKYr`z>kn??)1o-{hvHhsZ;baVYcm1dwLhISZxAw%nE*D`%}19%RoH2z#`4^~y`e zzTHA~i?t>D3vTuMaf$Q{zo;zh@3vOIXwWYOl7G(lA4_-z8Ch{T!QZItvjgNGN&cS7 zGCuoeV0vCG{0B<=oaDE;`wx;s^NZI0jQ?*f-M>%b->EI#^OEk@e)(5VzgPL^)cqdx zi~9V1m;ZL{PRGdhV^ID@7w7wE|Bu%0jNhC6lUM!!`oVQgYZRI&b8IhE$cI-^=$+!@;(KU9`=HNkEmIpqTY;Jbb z6P{alIdQ6xbz^jsxSHoYUbbZUx^DKa>q+BiPs9WkH=Wz<{`|h@W=P6DLjrej&)y?r z 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 Iy4(Q#7dmc)(EtDd literal 0 HcmV?d00001 From c42a5dae6a55d315360eaaa510d9dcaf7ef8e4c0 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 6 Aug 2025 17:58:20 +0100 Subject: [PATCH 56/58] fix: Encode sequential swaps with unwrapping WETH correctly Took 24 minutes Took 1 minute Took 24 seconds --- foundry/test/TychoRouterSequentialSwap.t.sol | 21 +++++ foundry/test/assets/calldata.txt | 25 +++--- .../evm/strategy_encoder/strategy_encoders.rs | 9 ++- .../transfer_optimizations.rs | 22 ++++-- .../sequential_strategy_integration_tests.rs | 76 ++++++++++++++++++- 5 files changed, 128 insertions(+), 25 deletions(-) diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index 748993c..61acad6 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -492,4 +492,25 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { assertEq(balanceAfter - balanceBefore, 1949668893); assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); } + + function testSequentialSwapWithUnwrapIntegration() public { + // Performs a sequential swap from USDC to ETH through WBTC using USV2 pools and unwrapping in + // the end + deal(USDC_ADDR, ALICE, 3_000_000_000); + uint256 balanceBefore = ALICE.balance; + + // Approve permit2 + vm.startPrank(ALICE); + IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); + bytes memory callData = + loadCallDataFromFile("test_sequential_swap_strategy_encoder_unwrap"); + (bool success,) = tychoRouterAddr.call(callData); + + vm.stopPrank(); + + uint256 balanceAfter = ALICE.balance; + + assertTrue(success, "Call Failed"); + assertEq(balanceAfter - balanceBefore, 1404194006633772805); + } } diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 36b148b..18e24f7 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -3,25 +3,25 @@ test_single_encoding_strategy_ekubo:5c4b639c000000000000000000000000000000000000 test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000 test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041aa05dfce0bca6785026b114e751b149b0e1ef2649598455bbc013893d1a241c546ccd30a543e261c8bb565c673b9c7fcc28f72325d9d059e7fc4e31a299c895a1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:30ace1b100000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041dacc6c754032bb9de8d264c64a46f2b309335b01f837b2f5b8b7b68bfa920a4537220bab168a5b0f3b84469365c91e0013d3950aca01664b993b3c18c291545b1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c0000000000000000000000000000000000000000 -test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ca1a9b5e5aef9624ec8e786ff0fb16fc4ed0758a421d99754184430aa95833b223eee4e65bcbf835f5f2ea2bdc2046231f6befb919298bfeb7d0271d0ce27f391c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004188d00ad562a3f5886cc865498f086f37097513f6d84135ce9e746d5570ae277f5d067b4fff48cb01febcb7976dd45d0f06ea32e6a323498c00b6e5502dab96601b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:30ace1b100000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041850dadc02f1a1a74884d6c4759a3c2f595e272f7a922e30f1873a14e08fe94f515b4e45aa43c62d35eaa73776baa4d7e14a768e594b0286162cad466e12fa6df1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c0000000000000000000000000000000000000000 +test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411edd2844e649f7f4e5a9611c7dde7dd974b7570a840b949de76aa285f250106c0eb5af01371ccdb0c507d1918875c545d1276850acc947ac0aca0f303685b50a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000413b7112285f6b953c073324f6563a055155581aacaa2df8bc92cc21619fda72aa25c386899fe9af623d0419095b7b8f4f9af2466e1eebb4d2724dc4e9097d0b111c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068a7452c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3400000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415eb48a5bb3d9854bd934b6524f5f568228c9946b22c1f6fd96e3f54ba6d57ce53a9bd5038f43dff33737b1c3f9294336bb9750e8f6c81d3e56b9e087845657c91c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 +test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000413846a7d1fb4eccf46c3e9bfc93e69d9d6b285913ccfc33a63738f3347bde9336791fccc1df0f1f591c0cf776a216928097f4fb2e4d9228affa8701955aa0aac61c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f6341bb003b81e66eaaa158c3a993614fb528cc3a732e8be66c1a5156e6965ce5b6192123dd53a7c625492788eb4fc9576ac7d11e53eee7a982d9102bdf6d2941c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 test_single test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c 6d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006869398600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006841b38e00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041752ca399237fc5086ef89d5f6dabecfb4b43c0753ecfb7020a6a86045db423fd3be9565f79b511fe93f55f76f61b1ac8d786b04051110ca6cbe10bbf69901b871c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000068a7452d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3500000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000416cf5d0fb75c24a379e1988e7ffa76de4e9573ecd42f79a380566f720734698e56cbb6034bd9cf713e6c4a89c4a57f768a360fc83df588fed402be248e2291cc51c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3500000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041e3abc1917a9102020e3a8e5f3c9cd8c95088f0f54315938b0fc21d9c74d33ca969bea7ea4cc8889cc403f3940e51b55ee56a5b918e649b5a147d2e47b68411fc1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068a7452e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf360000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416619afeffa8f49edde843d038e64e278de064d24586a84d3f6fc592d0e9e263e1f59599118eb7b25a8d4c1362b52728b076997b99ce7fd780b77ddf9ee674bb71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 -test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068a7452e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf360000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416619afeffa8f49edde843d038e64e278de064d24586a84d3f6fc592d0e9e263e1f59599118eb7b25a8d4c1362b52728b076997b99ce7fd780b77ddf9ee674bb71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 -test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf36000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c742469c49e8a03a8285ba3328e786a99b8a792c642fd9e409bc06f3baee04ea6589bdb0bd195122e9af08c8296f9841fff7a32be8b3afd44a586ee65ed684151b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041d2f8d88e451a62bbdadff37c73dd86f7aefbc6fe22d8335423f52ccae1de14d3608527b108f913fb0b2d5b0821db7bc5b437387450d4077d4b8c4fbf8b6bee6c1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000413846a7d1fb4eccf46c3e9bfc93e69d9d6b285913ccfc33a63738f3347bde9336791fccc1df0f1f591c0cf776a216928097f4fb2e4d9228affa8701955aa0aac61c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bb161c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689390240000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000412e07ff5ecc4d4420695861eb7b8dcd32c64c4a888c80fec22123b1ca7189ad63659f3b24818f09819a889b7bee66bb6134e49d1660855f049a7d190d572dd7e71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 +test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bb161c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689390240000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000412e07ff5ecc4d4420695861eb7b8dcd32c64c4a888c80fec22123b1ca7189ad63659f3b24818f09819a889b7bee66bb6134e49d1660855f049a7d190d572dd7e71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 +test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068939024000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041fd1b899619c0e35be2ec6b1613f44cd20f65148cf051301c6f0f3452d233b42240daf3dac98f36e92f2d433a7f7dad6f0d2d017a9629f99375938b436bc617c11c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 -test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000068a7452b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417fa6c0b85fb91e2737e39084c4530258c41c99f16a2796ea7400494d6486496525c653898965dde735537ef4b7ee93a79b5c6f11196a35b79e6d00f0b34811ac1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000068bb161a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902200000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415cdf5f3962b83af0ca547c43ee2a5ad254cdf666ae45350ec296c9e226eecb624464d044d1a6c04bc8f58e5ae0d1ddfaacc850e48acc47f3441f88443213f3a71c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102 test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c @@ -32,5 +32,6 @@ test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e test_encode_balancer_v3:7bc3485026ac48b6cf9baf0a377477fff5703af8c71ea051a5f82c67adcf634c36ffe6334793d24c85b2b559bc2d21104c4defdd6efca8a20343361d011d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e test_single_encoding_strategy_balancer_v3:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000097ffedb80d4b2ca6105a07a4d90eb739c45a66600000000000000000000000030881baa943777f92dc934d53d3bfdf33382cab300000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000006503a6a84cd762d9707a21605b548aaab891562aab097ffedb80d4b2ca6105a07a4d90eb739c45a66630881baa943777f92dc934d53d3bfdf33382cab3f028ac624074d6793c36dc8a06ecec0f5a39a71800cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000 test_uniswap_v3_balancer_v3:e21dd0d3000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004a220e6096b25eadb88358cb44068a324825467500000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed0000006503a6a84cd762d9707a21605b548aaab891562aab2260fac5e5542a773aa44fbcfedf7c193bc2c5994a220e6096b25eadb88358cb44068a3248254675571bea0e99e139cd0b6b7d9352ca872dfe0d72dd01cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000 -test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068a7452d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000687fbf3500000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004154d32a9cdc3955c1e9ba8767bb29c3a197c7497bf87aba59eb050278f39a999a609510cf1aa2535142e67b07ce9755f926877ff618c5ffaa684c0bcc310fdd7d1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411edd2844e649f7f4e5a9611c7dde7dd974b7570a840b949de76aa285f250106c0eb5af01371ccdb0c507d1918875c545d1276850acc947ac0aca0f303685b50a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_sequential_swap_usx:0101e21dd0d300000000000000000000000000000000000000000000006c6b935b8bbd4000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000769cfd80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d9da78b6a5bedca287aa5d49613ba36b90c15c40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470b6b175474e89094c44da98b954eedeac495271d0fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000643ede3eca2a72b3aecc820e955b36f38437d013955777d92f208679db4b9778590fa3cab3ac9e2168010000692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48dac17f958d2ee523a2206206994597c13d831ec70000646d9da78b6a5bedca287aa5d49613ba36b90c15c43416cf6c708da44db2624d63ea0aaef7113527c6010100000000000000000000 +test_sequential_swap_strategy_encoder_unwrap:51bcc7b600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041850dadc02f1a1a74884d6c4759a3c2f595e272f7a922e30f1873a14e08fe94f515b4e45aa43c62d35eaa73776baa4d7e14a768e594b0286162cad466e12fa6df1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48004375dff511095cc5a197a54140a24efef3a416bb2b8038a1640196fbe3e38816f3e67cba72d940000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950102000000000000000000000000000000000000000000000000 diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 0dea823..898fc54 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -228,10 +228,11 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { let grouped_swaps = group_swaps(&solution.swaps); - let mut wrap = false; + let (mut wrap, mut unwrap) = (false, false); if let Some(action) = &solution.native_action { - if action == &NativeAction::Wrap { - wrap = true + match *action { + NativeAction::Wrap => wrap = true, + NativeAction::Unwrap => unwrap = true, } } @@ -251,7 +252,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { let next_swap = grouped_swaps.get(i + 1); let (swap_receiver, next_swap_optimization) = self .transfer_optimization - .get_receiver(&solution.receiver, next_swap)?; + .get_receiver(&solution.receiver, next_swap, unwrap)?; next_in_between_swap_optimization_allowed = next_swap_optimization; let transfer = self diff --git a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs index 5a62bb2..6dc8466 100644 --- a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs +++ b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs @@ -82,6 +82,7 @@ impl TransferOptimization { &self, solution_receiver: &Bytes, next_swap: Option<&SwapGroup>, + unwrap: bool, ) -> Result<(Bytes, bool), EncodingError> { if let Some(next) = next_swap { // if the protocol of the next swap supports transfer in optimization @@ -104,7 +105,11 @@ impl TransferOptimization { } } else { // last swap - there is no next swap - Ok((solution_receiver.clone(), false)) + if unwrap { + Ok((self.router_address.clone(), false)) + } else { + Ok((solution_receiver.clone(), false)) + } } } } @@ -204,16 +209,19 @@ mod tests { } #[rstest] - // there is no next swap -> receiver is the solution receiver - #[case(None, receiver(), false)] + // there is no next swap but there is an unwrap -> receiver is the router + #[case(None, true, router_address(), false)] + // there is no next swap and no unwrap -> receiver is the solution receiver + #[case(None, false, receiver(), false)] // protocol of next swap supports transfer in optimization - #[case(Some("uniswap_v2"), component_id(), true)] + #[case(Some("uniswap_v2"), false, component_id(), true)] // protocol of next swap supports transfer in optimization but is callback constrained - #[case(Some("uniswap_v3"), router_address(), false)] + #[case(Some("uniswap_v3"), false, router_address(), false)] // protocol of next swap does not support transfer in optimization - #[case(Some("vm:curve"), router_address(), false)] + #[case(Some("vm:curve"), false, router_address(), false)] fn test_get_receiver( #[case] protocol: Option<&str>, + #[case] unwrap: bool, #[case] expected_receiver: Bytes, #[case] expected_optimization: bool, ) { @@ -247,7 +255,7 @@ mod tests { }) }; - let result = optimization.get_receiver(&receiver(), next_swap.as_ref()); + let result = optimization.get_receiver(&receiver(), next_swap.as_ref(), unwrap); assert!(result.is_ok()); let (actual_receiver, optimization_flag) = result.unwrap(); diff --git a/tests/sequential_strategy_integration_tests.rs b/tests/sequential_strategy_integration_tests.rs index 4d2a758..99f09d6 100644 --- a/tests/sequential_strategy_integration_tests.rs +++ b/tests/sequential_strategy_integration_tests.rs @@ -6,7 +6,7 @@ use num_bigint::{BigInt, BigUint}; use tycho_common::{models::protocol::ProtocolComponent, Bytes}; use tycho_execution::encoding::{ evm::utils::write_calldata_to_file, - models::{Solution, Swap, UserTransferType}, + models::{NativeAction, Solution, Swap, UserTransferType}, }; use crate::common::{ @@ -19,7 +19,7 @@ fn test_sequential_swap_strategy_encoder() { // Note: This test does not assert anything. It is only used to obtain integration // test data for our router solidity test. // - // Performs a sequential swap from WETH to USDC though WBTC using USV2 pools + // Performs a sequential swap from WETH to USDC through WBTC using USV2 pools // // WETH ───(USV2)──> WBTC ───(USV2)──> USDC @@ -316,3 +316,75 @@ fn test_sequential_strategy_cyclic_swap() { assert_eq!(hex_calldata[1224..], expected_swaps); write_calldata_to_file("test_sequential_strategy_cyclic_swap", hex_calldata.as_str()); } + +#[test] +fn test_sequential_swap_strategy_encoder_unwrap() { + // Note: This test does not assert anything. It is only used to obtain integration + // test data for our router solidity test. + // + // Performs a sequential swap from USDC to ETH through WBTC using USV2 pools and unwrapping in + // the end + // + // USDC ───(USV2)──> WBTC ───(USV2)──> WETH -> ETH + + let weth = weth(); + let wbtc = wbtc(); + let usdc = usdc(); + + let swap_usdc_wbtc = Swap { + component: ProtocolComponent { + id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(), + protocol_system: "uniswap_v2".to_string(), + ..Default::default() + }, + token_in: usdc.clone(), + token_out: wbtc.clone(), + split: 0f64, + user_data: None, + protocol_state: None, + }; + let swap_wbtc_weth = Swap { + component: ProtocolComponent { + id: "0xBb2b8038a1640196FbE3e38816F3e67Cba72D940".to_string(), + protocol_system: "uniswap_v2".to_string(), + ..Default::default() + }, + token_in: wbtc.clone(), + token_out: weth.clone(), + split: 0f64, + user_data: None, + protocol_state: None, + }; + let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2); + + let solution = Solution { + exact_out: false, + given_token: usdc, + given_amount: BigUint::from_str("3_000_000_000").unwrap(), + checked_token: eth(), + checked_amount: BigUint::from_str("26173932").unwrap(), + sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(), + receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(), + swaps: vec![swap_usdc_wbtc, swap_wbtc_weth], + native_action: Some(NativeAction::Unwrap), + }; + + let encoded_solution = encoder + .encode_solutions(vec![solution.clone()]) + .unwrap()[0] + .clone(); + + let calldata = encode_tycho_router_call( + eth_chain().id(), + encoded_solution, + &solution, + &UserTransferType::TransferFromPermit2, + ð(), + Some(get_signer()), + ) + .unwrap() + .data; + + let hex_calldata = encode(&calldata); + write_calldata_to_file("test_sequential_swap_strategy_encoder_unwrap", hex_calldata.as_str()); +} From 616b588fc86a70e386d815a3a456a09e2abf71ac Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Aug 2025 08:21:10 +0000 Subject: [PATCH 57/58] chore(release): 0.112.2 [skip ci] ## [0.112.2](https://github.com/propeller-heads/tycho-execution/compare/0.112.1...0.112.2) (2025-08-07) ### Bug Fixes * Encode sequential swaps with unwrapping WETH correctly ([c42a5da](https://github.com/propeller-heads/tycho-execution/commit/c42a5dae6a55d315360eaaa510d9dcaf7ef8e4c0)) --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4efb830..110874f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.112.2](https://github.com/propeller-heads/tycho-execution/compare/0.112.1...0.112.2) (2025-08-07) + + +### Bug Fixes + +* Encode sequential swaps with unwrapping WETH correctly ([c42a5da](https://github.com/propeller-heads/tycho-execution/commit/c42a5dae6a55d315360eaaa510d9dcaf7ef8e4c0)) + ## [0.112.1](https://github.com/propeller-heads/tycho-execution/compare/0.112.0...0.112.1) (2025-07-31) diff --git a/Cargo.lock b/Cargo.lock index c35f2b0..a3f2c77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4659,7 +4659,7 @@ dependencies = [ [[package]] name = "tycho-execution" -version = "0.112.1" +version = "0.112.2" dependencies = [ "alloy", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 97087d9..fd469e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tycho-execution" -version = "0.112.1" +version = "0.112.2" edition = "2021" description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors." repository = "https://github.com/propeller-heads/tycho-execution" From 003ab7cea82fec67dbd54bb1248f75e8c7c74c50 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Fri, 8 Aug 2025 14:54:40 +0100 Subject: [PATCH 58/58] fix: After merging main fixes Took 10 minutes --- foundry/test/assets/calldata.txt | 31 +++++++++++-------- .../evm/swap_encoder/swap_encoders.rs | 6 ++-- src/encoding/models.rs | 2 +- tests/common/mod.rs | 3 +- .../optimized_transfers_integration_tests.rs | 4 ++- tests/protocol_integration_tests.rs | 6 ++-- 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 18e24f7..350cb12 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -3,25 +3,25 @@ test_single_encoding_strategy_ekubo:5c4b639c000000000000000000000000000000000000 test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000 test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004188d00ad562a3f5886cc865498f086f37097513f6d84135ce9e746d5570ae277f5d067b4fff48cb01febcb7976dd45d0f06ea32e6a323498c00b6e5502dab96601b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:30ace1b100000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041850dadc02f1a1a74884d6c4759a3c2f595e272f7a922e30f1873a14e08fe94f515b4e45aa43c62d35eaa73776baa4d7e14a768e594b0286162cad466e12fa6df1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c0000000000000000000000000000000000000000 -test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411edd2844e649f7f4e5a9611c7dde7dd974b7570a840b949de76aa285f250106c0eb5af01371ccdb0c507d1918875c545d1276850acc947ac0aca0f303685b50a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068bd8ce700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606ef00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041372dbf7c534b88213916fa8a601f409d0f44e7a2bdf551ee1ba5eeeedb66c56017f5fe767d5a0d858f5d74bd2d3c5c2f854d003507097d05c88adeb6dcdbe9e31c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:30ace1b100000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068bd8ce700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606ef00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417bf20ed929172e460a5af1415425925026c16c5a144478e769aed5a38ec3929b20bbd914528a555b2ca82190ff6b40cc98c2e8b28010e70708176b6158fa8ba41c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c0000000000000000000000000000000000000000 +test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bd8ce800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000418aa56a28f29f2e912074e7ba696dc5258f671db9462902ac8058b143caf3dac13d6c2340e9025e79378d7a247ccd1aab9ad21e1fbce127cea8ddc9cacd2a66b11c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000413846a7d1fb4eccf46c3e9bfc93e69d9d6b285913ccfc33a63738f3347bde9336791fccc1df0f1f591c0cf776a216928097f4fb2e4d9228affa8701955aa0aac61c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f6341bb003b81e66eaaa158c3a993614fb528cc3a732e8be66c1a5156e6965ce5b6192123dd53a7c625492788eb4fc9576ac7d11e53eee7a982d9102bdf6d2941c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 +test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bd8ce700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606ef00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041150c050f4f899882fc4740b13762fa6cc2b5d0152d55c8bd1d0f2e39f85a6cdf64000a1b1204cbbdb765a014dacb67829f02e069b1002cdeccd11e3a0e2deee11b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bd8ce800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000418f8a7519b35d05d856d3cbadac29119589181303023f5b636e5ccbba8fe9f43a48430ebd56e57a51d62d196dad7cb01c205e3fed46885b8a6382c1c0ac0404571b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 test_single test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c 6d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006869398600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006841b38e00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041752ca399237fc5086ef89d5f6dabecfb4b43c0753ecfb7020a6a86045db423fd3be9565f79b511fe93f55f76f61b1ac8d786b04051110ca6cbe10bbf69901b871c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041d2f8d88e451a62bbdadff37c73dd86f7aefbc6fe22d8335423f52ccae1de14d3608527b108f913fb0b2d5b0821db7bc5b437387450d4077d4b8c4fbf8b6bee6c1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000413846a7d1fb4eccf46c3e9bfc93e69d9d6b285913ccfc33a63738f3347bde9336791fccc1df0f1f591c0cf776a216928097f4fb2e4d9228affa8701955aa0aac61c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bb161c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689390240000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000412e07ff5ecc4d4420695861eb7b8dcd32c64c4a888c80fec22123b1ca7189ad63659f3b24818f09819a889b7bee66bb6134e49d1660855f049a7d190d572dd7e71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 -test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bb161c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689390240000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000412e07ff5ecc4d4420695861eb7b8dcd32c64c4a888c80fec22123b1ca7189ad63659f3b24818f09819a889b7bee66bb6134e49d1660855f049a7d190d572dd7e71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 -test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068939024000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041fd1b899619c0e35be2ec6b1613f44cd20f65148cf051301c6f0f3452d233b42240daf3dac98f36e92f2d433a7f7dad6f0d2d017a9629f99375938b436bc617c11c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000068bd8ce800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004144449e54233dfc322ad8745277a9130ce6fd9aba97674b617bd4e3407af98bcb4707e8a8fb0cfe4d17f08290da1d6e6de0b316d05ebb7d9794485878f6237a731c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bd8ce800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041bc77934a779238cda29ff1266e802ef07e6e2889b8066011b4fb35cb1e9439ec32f4d2a91f187132c3b29795e6bb04fa2b413b9968019d16afd2929ab3f546a01b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bd8ce900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f100000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004168f164635b94dbc33524c418d4b6ec765989ae0c10002336a463cbedee894d941f7c5dbb3d3440146fb643c11aa14cc6c67bcf8adebe1a199bf293f51260a5611b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 +test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068bd8ce900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f100000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004168f164635b94dbc33524c418d4b6ec765989ae0c10002336a463cbedee894d941f7c5dbb3d3440146fb643c11aa14cc6c67bcf8adebe1a199bf293f51260a5611b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 +test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bd8ce900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f10000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411d8d7ea6828dd74ea8dd92d2407e2f20bae2eda14ce425643449949f78979f854ae737030189410d695c6b2fdba13a7ed0e4f8d2000f97407b501c24c4108ae41c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 -test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000068bb161a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902200000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415cdf5f3962b83af0ca547c43ee2a5ad254cdf666ae45350ec296c9e226eecb624464d044d1a6c04bc8f58e5ae0d1ddfaacc850e48acc47f3441f88443213f3a71c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000068bd8ce700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606ef00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041008e52eefa160f49bf0d12bd86a1ce67e34bc8cdd580bd7ef3254c1032ea071a64d9f568151c0dfbec4fe643bfd1370c0429735b4db64b751b85faea2ede9c281c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102 test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c @@ -32,6 +32,11 @@ test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e test_encode_balancer_v3:7bc3485026ac48b6cf9baf0a377477fff5703af8c71ea051a5f82c67adcf634c36ffe6334793d24c85b2b559bc2d21104c4defdd6efca8a20343361d011d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e test_single_encoding_strategy_balancer_v3:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000097ffedb80d4b2ca6105a07a4d90eb739c45a66600000000000000000000000030881baa943777f92dc934d53d3bfdf33382cab300000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000006503a6a84cd762d9707a21605b548aaab891562aab097ffedb80d4b2ca6105a07a4d90eb739c45a66630881baa943777f92dc934d53d3bfdf33382cab3f028ac624074d6793c36dc8a06ecec0f5a39a71800cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000 test_uniswap_v3_balancer_v3:e21dd0d3000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004a220e6096b25eadb88358cb44068a324825467500000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed0000006503a6a84cd762d9707a21605b548aaab891562aab2260fac5e5542a773aa44fbcfedf7c193bc2c5994a220e6096b25eadb88358cb44068a3248254675571bea0e99e139cd0b6b7d9352ca872dfe0d72dd01cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000 -test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411edd2844e649f7f4e5a9611c7dde7dd974b7570a840b949de76aa285f250106c0eb5af01371ccdb0c507d1918875c545d1276850acc947ac0aca0f303685b50a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068bd8ce800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000418aa56a28f29f2e912074e7ba696dc5258f671db9462902ac8058b143caf3dac13d6c2340e9025e79378d7a247ccd1aab9ad21e1fbce127cea8ddc9cacd2a66b11c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_sequential_swap_usx:0101e21dd0d300000000000000000000000000000000000000000000006c6b935b8bbd4000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000769cfd80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d9da78b6a5bedca287aa5d49613ba36b90c15c40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470b6b175474e89094c44da98b954eedeac495271d0fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000643ede3eca2a72b3aecc820e955b36f38437d013955777d92f208679db4b9778590fa3cab3ac9e2168010000692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48dac17f958d2ee523a2206206994597c13d831ec70000646d9da78b6a5bedca287aa5d49613ba36b90c15c43416cf6c708da44db2624d63ea0aaef7113527c6010100000000000000000000 -test_sequential_swap_strategy_encoder_unwrap:51bcc7b600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068bb161b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006893902300000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041850dadc02f1a1a74884d6c4759a3c2f595e272f7a922e30f1873a14e08fe94f515b4e45aa43c62d35eaa73776baa4d7e14a768e594b0286162cad466e12fa6df1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48004375dff511095cc5a197a54140a24efef3a416bb2b8038a1640196fbe3e38816f3e67cba72d940000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950102000000000000000000000000000000000000000000000000 +test_sequential_swap_strategy_encoder_unwrap:51bcc7b600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068bd8ce800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000689606f000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004170c5a2d9e6142b1de2a91c631a79dde111f9d46c694d84189f0803e4819702a17a9bc1afd7452167f43fb87d4446cdb9bc7335f14ffa74be359506ce018baf071c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48004375dff511095cc5a197a54140a24efef3a416bb2b8038a1640196fbe3e38816f3e67cba72d940000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950102000000000000000000000000000000000000000000000000 +test_encode_bebop_single:a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48faba6f8e4a5e8ab82f62fe7c39859fa577269be301000002844dcebcba000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000bebc2000000000000000000000000000000000000000000000000000000000068470140000000000000000000000000c5564c13a157e6240659fb81882a28091add8670000000000000000000000000ce79b081c0c924cb67848723ed3057234d10fc6b000000000000000000000000000000000000000000000000000637256e698be1000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000faba6f8e4a5e8ab82f62fe7c39859fa577269be3000000000000000000000000000000000000000000000000000000000bebc2000000000000000000000000000000000000000000000000cd97e88ccc64d54000000000000000000000000000c5564c13a157e6240659fb81882a28091add86700000000000000000000000000000000000000000000000000000000000000000727220e0ad42bc02077c9bb3a3d60c41bfd3df1a80f5e97aa87e3ea6e93a0000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041eb5419631614978da217532a40f02a8f2ece37d8cfb94aaa602baabbdefb56b474f4c2048a0f56502caff4ea7411d99eed6027cd67dc1088aaf4181dcb0df7051c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000bebc20001c5564c13a157e6240659fb81882a28091add8670 +test_encode_bebop_aggregate:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480100000844a2f74893000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000006600000000000000000000000000000000000000000000000000022fe85d709a000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000681773350000000000000000000000007078b12ca5b294d95e9ac16d90b7d38238d8f4e6000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000007078b12ca5b294d95e9ac16d90b7d38238d8f4e600000000000000000000000000000000000000000000000000000000000005a0d3fa5d891de82c082d5c51f03b47e826f86c96b88802b96a09bbae087e880000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000067336cec42645f55059eff241cb02ea5cc52ff86000000000000000000000000bf19cbf0256f19f39a016a86ff3551ecc6f2aafe0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000001969b98b07c0000000000000000000000000000000000000000000000000000000000ebe7000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000014a614797ce1520000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000e58715d8cbeae00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000a1da6b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000070572e00000000000000000000000000000000000000000000000000000000000000040004000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d5abb425f9bac1f44d48705f41a8ab9cae207517be8553d2c03b06a88995f2f351ab8ce7627a87048178d539dd64fd2380245531a0c8e43fdc614652b1f32fc71c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f38c698e48a3eac48f184bc324fef0b135ee13705ab38cc0bbf5a792f21002f051e445b9e7d57cf24c35e17629ea35b3263591c4abf8ca87ffa44b41301b89c41b00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000022fe85d709a000010000000000000000000000000000000000000000 +test_uniswap_v3_bebop:e21dd0d3000000000000000000000000000000000000000000000000015fb7f9b8c38000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000faba6f8e4a5e8ab82f62fe7c39859fa577269be300000000000000000000000000000000000000000000000cdbfbba0faafaf02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c5564c13a157e6240659fb81882a28091add867000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000036800692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640000002fbd6bbde9174b1cdaa358d2cf4d57d1a9f7178fbffa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48faba6f8e4a5e8ab82f62fe7c39859fa577269be301000002844dcebcba000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000068470140000000000000000000000000c5564c13a157e6240659fb81882a28091add8670000000000000000000000000ce79b081c0c924cb67848723ed3057234d10fc6b000000000000000000000000000000000000000000000000000637256e698be1000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000faba6f8e4a5e8ab82f62fe7c39859fa577269be3000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000cdbfbba0faafaf020000000000000000000000000c5564c13a157e6240659fb81882a28091add8670000000000000000000000000000000000000000000000000000000000000000072c75365fbad713c3dbdcac257c4355400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041eb5419631614978da217532a40f02a8f2ece37d8cfb94aaa602baabbdefb56b474f4c2048a0f56502caff4ea7411d99eed6027cd67dc1088aaf4181dcb0df7051c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000bebc20001c5564c13a157e6240659fb81882a28091add8670000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_bebop_aggregate:5c4b639c0000000000000000000000000000000000000000000000000022fe85d709a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000001123199000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007078b12ca5b294d95e9ac16d90b7d38238d8f4e60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000008bbd6bbde9174b1cdaa358d2cf4d57d1a9f7178fbff0000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480200000844a2f74893000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000006600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000681773350000000000000000000000007078b12ca5b294d95e9ac16d90b7d38238d8f4e6000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000007078b12ca5b294d95e9ac16d90b7d38238d8f4e600000000000000000000000000000000000000000000000000000000000005a0d3bb6e37a886dc243affa93ce81c8a4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000067336cec42645f55059eff241cb02ea5cc52ff86000000000000000000000000bf19cbf0256f19f39a016a86ff3551ecc6f2aafe0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000001969b98b07c0000000000000000000000000000000000000000000000000000000000ebe7000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000014a614797ce1520000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000e58715d8cbeae00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000a1da6b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000070572e00000000000000000000000000000000000000000000000000000000000000040004000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d5abb425f9bac1f44d48705f41a8ab9cae207517be8553d2c03b06a88995f2f351ab8ce7627a87048178d539dd64fd2380245531a0c8e43fdc614652b1f32fc71c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f38c698e48a3eac48f184bc324fef0b135ee13705ab38cc0bbf5a792f21002f051e445b9e7d57cf24c35e17629ea35b3263591c4abf8ca87ffa44b41301b89c41b000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_bebop:5c4b639c000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000faba6f8e4a5e8ab82f62fe7c39859fa577269be300000000000000000000000000000000000000000000000cdbfbba0faafaf02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c5564c13a157e6240659fb81882a28091add86700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002fbd6bbde9174b1cdaa358d2cf4d57d1a9f7178fbffa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48faba6f8e4a5e8ab82f62fe7c39859fa577269be300000002844dcebcba000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000068470140000000000000000000000000c5564c13a157e6240659fb81882a28091add8670000000000000000000000000ce79b081c0c924cb67848723ed3057234d10fc6b000000000000000000000000000000000000000000000000000637256e698be1000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000faba6f8e4a5e8ab82f62fe7c39859fa577269be3000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000cdbfbba0faafaf020000000000000000000000000c5564c13a157e6240659fb81882a28091add8670000000000000000000000000000000000000000000000000000000000000000072c75365fbad713c3dbdcac257c4355400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041eb5419631614978da217532a40f02a8f2ece37d8cfb94aaa602baabbdefb56b474f4c2048a0f56502caff4ea7411d99eed6027cd67dc1088aaf4181dcb0df7051c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000bebc20001c5564c13a157e6240659fb81882a28091add86700000000000 diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 3e8536a..acfe26c 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -2134,6 +2134,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: Some(Bytes::from(user_data)), + protocol_state: None, }; let encoding_context = EncodingContext { @@ -2147,7 +2148,7 @@ mod tests { let encoder = BebopSwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, Some(HashMap::from([( "bebop_settlement_address".to_string(), "0xbbbbbBB520d69a9775E85b458C58c648259FAD5F".to_string(), @@ -2328,6 +2329,7 @@ mod tests { token_out: token_out.clone(), split: 0f64, user_data: Some(Bytes::from(user_data)), + protocol_state: None, }; let encoding_context = EncodingContext { @@ -2341,7 +2343,7 @@ mod tests { let encoder = BebopSwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), + Chain::Ethereum, Some(HashMap::from([( "bebop_settlement_address".to_string(), "0xbbbbbBB520d69a9775E85b458C58c648259FAD5F".to_string(), diff --git a/src/encoding/models.rs b/src/encoding/models.rs index 14bbd4f..cbc5d85 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -5,7 +5,7 @@ use tycho_common::{ models::protocol::ProtocolComponent, simulation::protocol_sim::ProtocolSim, Bytes, }; -use crate::encoding::serde_primitives::biguint_string; +use crate::encoding::{errors::EncodingError, serde_primitives::biguint_string}; /// Specifies the method for transferring user funds into Tycho execution. /// diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 88fa9a0..3bf887b 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -9,7 +9,8 @@ use alloy::{ }; use tycho_common::{models::Chain, Bytes}; use tycho_execution::encoding::{ - evm::encoder_builders::TychoRouterEncoderBuilder, models::UserTransferType, + evm::encoder_builders::TychoRouterEncoderBuilder, + models::{BebopOrderType, UserTransferType}, tycho_encoder::TychoEncoder, }; diff --git a/tests/optimized_transfers_integration_tests.rs b/tests/optimized_transfers_integration_tests.rs index a2fff55..5b0ce66 100644 --- a/tests/optimized_transfers_integration_tests.rs +++ b/tests/optimized_transfers_integration_tests.rs @@ -631,6 +631,7 @@ fn test_uniswap_v3_bebop() { token_out: usdc.clone(), split: 0f64, user_data: None, + protocol_state: None, }; // Second swap: USDC -> ONDO via Bebop RFQ using real order data @@ -691,6 +692,7 @@ fn test_uniswap_v3_bebop() { token_out: ondo.clone(), split: 0f64, user_data: Some(user_data), + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -716,7 +718,7 @@ fn test_uniswap_v3_bebop() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, diff --git a/tests/protocol_integration_tests.rs b/tests/protocol_integration_tests.rs index 9e0501f..9850986 100644 --- a/tests/protocol_integration_tests.rs +++ b/tests/protocol_integration_tests.rs @@ -653,6 +653,7 @@ fn test_single_encoding_strategy_bebop() { token_out: token_out.clone(), split: 0f64, user_data: Some(user_data), + protocol_state: None, }; let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom); @@ -678,7 +679,7 @@ fn test_single_encoding_strategy_bebop() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::TransferFrom, @@ -780,6 +781,7 @@ fn test_single_encoding_strategy_bebop_aggregate() { token_out: token_out.clone(), split: 0f64, user_data: Some(user_data), + protocol_state: None, }; // Use TransferFrom for WETH token transfer @@ -804,7 +806,7 @@ fn test_single_encoding_strategy_bebop_aggregate() { .clone(); let calldata = encode_tycho_router_call( - eth_chain().id, + eth_chain().id(), encoded_solution, &solution, &UserTransferType::None,