From a81420fc945aaea3e154dc049177f69d4c0826a0 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Thu, 2 Mar 2023 00:37:33 +0100 Subject: [PATCH] Improve parsing of ETH input data --- bchain/coins/eth/dataparser.go | 16 ++++--- bchain/coins/eth/dataparser_test.go | 67 ++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/bchain/coins/eth/dataparser.go b/bchain/coins/eth/dataparser.go index 060fcfca..81826926 100644 --- a/bchain/coins/eth/dataparser.go +++ b/bchain/coins/eth/dataparser.go @@ -76,7 +76,8 @@ func decamel(s string) string { b.WriteByte(' ') } b.WriteRune(v) - splittable = unicode.IsLower(v) || unicode.IsNumber(v) + // special handling of ETH to be able to convert "addETHToContract" to "Add ETH To Contract" + splittable = unicode.IsLower(v) || unicode.IsNumber(v) || (i >= 2 && s[i-2:i+1] == "ETH") } } return b.String() @@ -98,7 +99,7 @@ func GetSignatureFromData(data string) uint32 { const ErrorTy byte = 255 -func processParam(data string, index int, t *abi.Type, processed []bool) ([]string, int, bool) { +func processParam(data string, index int, dataOffset int, t *abi.Type, processed []bool) ([]string, int, bool) { var retval []string d := index << 6 if d+64 > len(data) { @@ -140,7 +141,7 @@ func processParam(data string, index int, t *abi.Type, processed []bool) ([]stri for i := 0; i < t.Size; i++ { var r []string var ok bool - r, index, ok = processParam(data, index, t.Elem, processed) + r, index, ok = processParam(data, index, dataOffset, t.Elem, processed) if !ok { return nil, 0, false } @@ -156,7 +157,7 @@ func processParam(data string, index int, t *abi.Type, processed []bool) ([]stri processed[index] = true index++ offset <<= 1 - d = int(offset) + d = int(offset) + dataOffset dynIndex := d >> 6 if d+64 > len(data) || d < 0 { return nil, 0, false @@ -195,10 +196,11 @@ func processParam(data string, index int, t *abi.Type, processed []bool) ([]stri } } } else { + newOffset := dataOffset + dynIndex<<6 for i := 0; i < count; i++ { var r []string var ok bool - r, dynIndex, ok = processParam(data, dynIndex, t.Elem, processed) + r, dynIndex, ok = processParam(data, dynIndex, newOffset, t.Elem, processed) if !ok { return nil, 0, false } @@ -222,7 +224,7 @@ func tryParseParams(data string, params []string, parsedParams []abi.Type) []bch var ok bool for i := range params { t := &parsedParams[i] - values, index, ok = processParam(data, index, t, processed) + values, index, ok = processParam(data, index, 0, t, processed) if !ok { return nil } @@ -244,7 +246,7 @@ func ParseInputData(signatures *[]bchain.FourByteSignature, data string) *bchain if len(data) <= 2 { // data is empty or 0x return &bchain.EthereumParsedInputData{Name: "Transfer"} } - if len(data) < 10 || (len(data)-10)%64 != 0 { + if len(data) < 10 { return nil } parsed := bchain.EthereumParsedInputData{ diff --git a/bchain/coins/eth/dataparser_test.go b/bchain/coins/eth/dataparser_test.go index 745e6b62..b13ecd16 100644 --- a/bchain/coins/eth/dataparser_test.go +++ b/bchain/coins/eth/dataparser_test.go @@ -112,7 +112,7 @@ func TestParseInputData(t *testing.T) { Parameters: []string{"address"}, }, { - Name: "addLiquidityETH", + Name: "addLiquidityETHToContract", Parameters: []string{"address", "uint256", "uint256", "uint256", "address", "uint256"}, }, { @@ -131,6 +131,10 @@ func TestParseInputData(t *testing.T) { Name: "transmitAndSellTokenForEth", Parameters: []string{"address", "uint256", "uint256", "uint256", "address", "(uint8,bytes32,bytes32)", "bytes"}, }, + { + Name: "execute", + Parameters: []string{"bytes", "bytes[]", "uint256"}, + }, } tests := []struct { name string @@ -191,13 +195,13 @@ func TestParseInputData(t *testing.T) { }, }, { - name: "addLiquidityETH", + name: "addLiquidityETHToContract", signatures: &signatures, data: "0xf305d719000000000000000000000000b80e5aaa2131c07568128f68b8538ed3c8951234000000000000000000000000000000000000007e37be2022c0914b2680000000000000000000000000000000000000000000007e37be2022c0914b26800000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000009f64b014ca26f2def573246543dd1115b229e4f400000000000000000000000000000000000000000000000000000000623f56f8", want: &bchain.EthereumParsedInputData{ MethodId: "0xf305d719", - Name: "Add Liquidity ETH", - Function: "addLiquidityETH(address, uint256, uint256, uint256, address, uint256)", + Name: "Add Liquidity ETH To Contract", + Function: "addLiquidityETHToContract(address, uint256, uint256, uint256, address, uint256)", Params: []bchain.EthereumParsedInputParam{ { Type: "address", @@ -227,7 +231,7 @@ func TestParseInputData(t *testing.T) { }, }, { - name: "addLiquidityETH data don't match - too long", + name: "addLiquidityETHToContract data don't match - too long", signatures: &signatures, data: "0xf305d719000000000000000000000000b80e5aaa2131c07568128f68b8538ed3c8951234000000000000000000000000000000000000007e37be2022c0914b2680000000000000000000000000000000000000000000007e37be2022c0914b26800000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000009f64b014ca26f2def573246543dd1115b229e4f400000000000000000000000000000000000000000000000000000000623f56f800000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", want: &bchain.EthereumParsedInputData{ @@ -235,7 +239,7 @@ func TestParseInputData(t *testing.T) { }, }, { - name: "addLiquidityETH data don't match - too short", + name: "addLiquidityETHToContract data don't match - too short", signatures: &signatures, data: "0xf305d719000000000000000000000000b80e5aaa2131c07568128f68b8538ed3c8951234000000000000000000000000000000000000007e37be2022c0914b2680000000000000000000000000000000000000000000007e37be2022c0914b26800000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000009f64b014ca26f2def573246543dd1115b229e4f4", want: &bchain.EthereumParsedInputData{ @@ -362,6 +366,57 @@ func TestParseInputData(t *testing.T) { }, }, }, + { + name: "execute", + signatures: &signatures, + data: "0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000063fd167b00000000000000000000000000000000000000000000000000000000000000010800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000021e19e0c9bab2400000000000000000000000000000000000000000000000000000000000002fa5e9a300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cda4e840411c00a614ad9205caec807c7458a0e3000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + want: &bchain.EthereumParsedInputData{ + MethodId: "0x3593564c", + Name: "Execute", + Function: "execute(bytes, bytes[], uint256)", + Params: []bchain.EthereumParsedInputParam{ + { + Type: "bytes", + Values: []string{"0x08"}, + }, + { + Type: "bytes[]", + Values: []string{"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000021e19e0c9bab2400000000000000000000000000000000000000000000000000000000000002fa5e9a300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cda4e840411c00a614ad9205caec807c7458a0e3000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"}, + }, + { + Type: "uint256", + Values: []string{"1677530747"}, + }, + }, + }, + }, + { + name: "execute2", + signatures: &signatures, + data: "0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000063ffd82300000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000491478480c282e75df8b5700000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000f0f9d895aca5c8678f706fb8216fa22957685a13", + want: &bchain.EthereumParsedInputData{ + MethodId: "0x3593564c", + Name: "Execute", + Function: "execute(bytes, bytes[], uint256)", + Params: []bchain.EthereumParsedInputParam{ + { + Type: "bytes", + Values: []string{"0x0b08"}, + }, + { + Type: "bytes[]", + Values: []string{ + "0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000491478480c282e75df8b5700000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000f0f9d895aca5c8678f706fb8216fa22957685a13", + }, + }, + { + Type: "uint256", + Values: []string{"1677711395"}, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {