diff --git a/README.md b/README.md index 5debc0a..976a138 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Each storyline token trades on a Mint Club V2 bonding curve with 1% creator roya | Contract | Address | |----------|---------| | StoryFactory | [`0x337c5b96f03fB335b433291695A4171fd5dED8B0`](https://basescan.org/address/0x337c5b96f03fB335b433291695A4171fd5dED8B0) | -| ZapPlotLinkV2 | [`0x952606df750C01e0a12458C3F814598B94AD5C5f`](https://basescan.org/address/0x952606df750C01e0a12458C3F814598B94AD5C5f) | +| ZapPlotLinkV2 | [`0xAe50C9444DA2Ac80B209dC8B416d1B4A7D3939B0`](https://basescan.org/address/0xAe50C9444DA2Ac80B209dC8B416d1B4A7D3939B0) | ## External Dependencies diff --git a/script/E2EZapTest.s.sol b/script/E2EZapTest.s.sol index d0e4044..79de351 100644 --- a/script/E2EZapTest.s.sol +++ b/script/E2EZapTest.s.sol @@ -18,7 +18,7 @@ contract E2EZapTest is Script { // ----------------------------------------------------------------------- // Base mainnet addresses // ----------------------------------------------------------------------- - ZapPlotLinkV2 constant ZAP = ZapPlotLinkV2(payable(0x7bC192848003ab1Ba286C66AFD0dd8a1729c6b02)); + ZapPlotLinkV2 constant ZAP = ZapPlotLinkV2(payable(0xAe50C9444DA2Ac80B209dC8B416d1B4A7D3939B0)); IMCV2_Bond constant BOND = IMCV2_Bond(0xc5a076cad94176c2996B32d8466Be1cE757FAa27); IERC20 constant PLOT = IERC20(0xF8A2C39111FCEB9C950aAf28A9E34EBaD99b85C1); IERC20 constant HUNT = IERC20(0x37f0c2915CeCC7e977183B8543Fc0864d03E064C); diff --git a/src/ZapPlotLinkV2.sol b/src/ZapPlotLinkV2.sol index 8d127c0..dd78089 100644 --- a/src/ZapPlotLinkV2.sol +++ b/src/ZapPlotLinkV2.sol @@ -483,7 +483,10 @@ contract ZapPlotLinkV2 { hookData: bytes("") }); - actionParams[0] = abi.encode(USDC, path, amountIn, uint128(0)); + // V4 Router's CalldataDecoder.decodeSwapExactInParams reads the first word as + // an offset pointer to the struct data. _encodeAsStruct prepends 0x20 to match + // the ABI encoding of a single struct parameter (abi.encode(ExactInputParams)). + actionParams[0] = _encodeAsStruct(abi.encode(USDC, path, amountIn, uint128(0))); actionParams[1] = abi.encode(USDC, amountIn); actionParams[2] = abi.encode(plotToken, address(this), ActionConstants.OPEN_DELTA); @@ -520,7 +523,7 @@ contract ZapPlotLinkV2 { hookData: bytes("") }); - actionParams[0] = abi.encode(plotToken, path, plotAmountOut, maxUsdcIn); + actionParams[0] = _encodeAsStruct(abi.encode(plotToken, path, plotAmountOut, maxUsdcIn)); actionParams[1] = abi.encode(USDC, maxUsdcIn); actionParams[2] = abi.encode(plotToken, address(this), ActionConstants.OPEN_DELTA); @@ -531,6 +534,15 @@ contract ZapPlotLinkV2 { UNIVERSAL_ROUTER.execute(commands, inputs, block.timestamp); } + /// @dev Wraps ABI-encoded fields with an outer offset word (0x20) to match + /// struct-style ABI encoding expected by the V4 Router's CalldataDecoder. + /// decodeSwapExactInParams/decodeSwapExactOutParams read the first word + /// of params as an offset pointer to the struct data. abi.encode(field1, ...) + /// produces a flat tuple without this offset; this function adds it. + function _encodeAsStruct(bytes memory data) private pure returns (bytes memory) { + return abi.encodePacked(uint256(0x20), data); + } + function _refundPlot() private { uint256 balance = IERC20(plotToken).balanceOf(address(this)); if (balance > 0) {