package parser import ( "math/big" "strings" "testing" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) const uniswapV3RouterABI = `[ { "name":"multicall", "type":"function", "stateMutability":"payable", "inputs":[ {"name":"deadline","type":"uint256"}, {"name":"data","type":"bytes[]"} ], "outputs":[] }, { "name":"exactInputSingle", "type":"function", "stateMutability":"payable", "inputs":[ { "name":"params", "type":"tuple", "components":[ {"name":"tokenIn","type":"address"}, {"name":"tokenOut","type":"address"}, {"name":"fee","type":"uint24"}, {"name":"recipient","type":"address"}, {"name":"deadline","type":"uint256"}, {"name":"amountIn","type":"uint256"}, {"name":"amountOutMinimum","type":"uint256"}, {"name":"sqrtPriceLimitX96","type":"uint160"} ] } ], "outputs":[{"name":"","type":"uint256"}] } ]` type exactInputSingleParams struct { TokenIn common.Address `abi:"tokenIn"` TokenOut common.Address `abi:"tokenOut"` Fee *big.Int `abi:"fee"` Recipient common.Address `abi:"recipient"` Deadline *big.Int `abi:"deadline"` AmountIn *big.Int `abi:"amountIn"` AmountOutMinimum *big.Int `abi:"amountOutMinimum"` SqrtPriceLimitX96 *big.Int `abi:"sqrtPriceLimitX96"` } func TestDecodeUniswapV3Multicall(t *testing.T) { decoder, err := NewABIDecoder() require.NoError(t, err) routerABI, err := abi.JSON(strings.NewReader(uniswapV3RouterABI)) require.NoError(t, err) tokenIn := common.HexToAddress("0xaf88d065e77c8cc2239327c5edb3a432268e5831") tokenOut := common.HexToAddress("0x82af49447d8a07e3bd95bd0d56f35241523fbab1") params := exactInputSingleParams{ TokenIn: tokenIn, TokenOut: tokenOut, Fee: big.NewInt(500), Recipient: common.HexToAddress("0x1111111254eeb25477b68fb85ed929f73a960582"), Deadline: big.NewInt(0), AmountIn: big.NewInt(1_000_000), AmountOutMinimum: big.NewInt(950_000), SqrtPriceLimitX96: big.NewInt(0), } innerCall, err := routerABI.Pack("exactInputSingle", params) require.NoError(t, err) multicallPayload, err := routerABI.Pack("multicall", big.NewInt(0), [][]byte{innerCall}) require.NoError(t, err) rawSwap, err := decoder.DecodeSwapTransaction("uniswap_v3", multicallPayload) require.NoError(t, err) swap, ok := rawSwap.(*SwapEvent) require.True(t, ok, "expected SwapEvent from multicall decode") require.Equal(t, tokenIn, swap.TokenIn) require.Equal(t, tokenOut, swap.TokenOut) require.Equal(t, big.NewInt(1_000_000), swap.AmountIn) require.Equal(t, big.NewInt(950_000), swap.AmountOut) }