diff --git a/go.mod b/go.mod index f50924f7..27d51ece 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.23.1 // replace github.com/0xsequence/ethkit => /Users/peter/Dev/0xsequence/ethkit require ( - github.com/0xsequence/ethkit v1.27.11 + github.com/0xsequence/ethkit v1.28.0 github.com/0xsequence/go-ethauth v0.13.0 github.com/BurntSushi/toml v1.2.1 github.com/davecgh/go-spew v1.1.1 diff --git a/go.sum b/go.sum index 9669fc71..915ccc7f 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/0xsequence/ethkit v1.27.11 h1:fWcABQx1WIH4SWvesCuKBJ+D4XdwZcIGWGSYnBCM+VU= -github.com/0xsequence/ethkit v1.27.11/go.mod h1:rv0FAIyEyN0hhwGefbduAz4ujmyjyJXhCd6a0/yF3tk= +github.com/0xsequence/ethkit v1.28.0 h1:11p4UXXvYnixQk01+qmAcOF71N9DlSeMcEMbaCPtjaY= +github.com/0xsequence/ethkit v1.28.0/go.mod h1:rv0FAIyEyN0hhwGefbduAz4ujmyjyJXhCd6a0/yF3tk= github.com/0xsequence/go-ethauth v0.13.0 h1:ZaqFEEqy574A2b1P7vjpcy5tb4W/izn+A3swwOYi9wA= github.com/0xsequence/go-ethauth v0.13.0/go.mod h1:f3kx39S9F+W+qvZEB6bkKKbpUstmyB7goUntO3wvlhg= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= diff --git a/go.work.sum b/go.work.sum index 48ed467a..74318f18 100644 --- a/go.work.sum +++ b/go.work.sum @@ -36,6 +36,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/0xsequence/ethkit v1.27.11 h1:fWcABQx1WIH4SWvesCuKBJ+D4XdwZcIGWGSYnBCM+VU= +github.com/0xsequence/ethkit v1.27.11/go.mod h1:rv0FAIyEyN0hhwGefbduAz4ujmyjyJXhCd6a0/yF3tk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -46,6 +48,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bits-and-blooms/bitset v1.14.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -119,6 +122,7 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= +github.com/goware/cachestore v0.8.1/go.mod h1:ikiO2RmxIt4cVqEBII6yR+V4Z7pH+y8bMQHpd1MvG1Y= github.com/goware/pp v0.0.3/go.mod h1:shID9y83CUGdg/BfO0SrVhchPpIAcT3ArfLVkq3x7tQ= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -137,6 +141,7 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -173,6 +178,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -216,6 +222,7 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -226,6 +233,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -251,6 +259,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -331,12 +340,15 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -390,6 +402,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/intents/intent_data_transaction_contract_abi.go b/intents/intent_data_transaction_contract_abi.go index 7c5bd677..dfcb256b 100644 --- a/intents/intent_data_transaction_contract_abi.go +++ b/intents/intent_data_transaction_contract_abi.go @@ -1,13 +1,7 @@ package intents import ( - "encoding/json" - "errors" - "fmt" - "strings" - "github.com/0xsequence/ethkit/ethcoder" - "github.com/0xsequence/ethkit/go-ethereum/common" ) type contractCallType struct { @@ -16,129 +10,13 @@ type contractCallType struct { Args []any `json:"args"` } +// EncodeContractCall encodes a contract call as a hex encoded calldata. +// NOTE: see ethcoder.EncodeContractCall for more details. func EncodeContractCall(data *contractCallType) (string, error) { - // Get the method from the abi - method, _, err := getMethodFromAbi(data.Abi, data.Func) - if err != nil { - return "", err + callDef := ethcoder.ContractCallDef{ + ABI: data.Abi, + Func: data.Func, + Args: data.Args, } - - enc := make([]string, len(data.Args)) - - // String args can be used right away, but any nested - // `contractCallType` must be handled recursively - for i, arg := range data.Args { - switch arg := arg.(type) { - case string: - enc[i] = arg - - case map[string]interface{}: - nst := arg - - var funcName string - if v, ok := nst["func"].(string); ok { - funcName = v - } - - args, ok := nst["args"].([]interface{}) - if !ok { - return "", fmt.Errorf("nested args expected to be an array") - } - - abi, _ := nst["abi"].(string) - - enc[i], err = EncodeContractCall(&contractCallType{ - Abi: abi, - Func: funcName, - Args: args, - }) - if err != nil { - return "", err - } - - default: - return "", fmt.Errorf("invalid arg type") - } - } - - // Encode the method call - res, err := ethcoder.AbiEncodeMethodCalldataFromStringValues(method, enc) - if err != nil { - return "", err - } - - return "0x" + common.Bytes2Hex(res), nil -} - -// The abi may be a: -// - already encoded method abi: transferFrom(address,address,uint256) -// - already encoded named method: transferFrom(address from,address to,uint256 val) -// - an array of function abis: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_orderId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_maxCost\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_fees\",\"type\":\"address\"}],\"name\":\"fillOrKillOrder\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}]" -// - or a single function abi: "{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_orderId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_maxCost\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_fees\",\"type\":\"address\"}],\"name\":\"fillOrKillOrder\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}" -// And it must always return it encoded, like this: -// - transferFrom(address,address,uint256) -// making sure that the method matches the returned one -func getMethodFromAbi(abi string, method string) (string, []string, error) { - // - // First attempt to parse `abi` string as a plain method abi - // ie. transferFrom(address,address,uint256) - // - - // Handle the case for already encoded method abi. - // NOTE: we do not need the know the `method` argument here. - abi = strings.TrimSpace(abi) - if len(abi) > 0 && strings.Contains(abi, "(") && abi[len(abi)-1] == ')' { - // NOTE: even though the ethcoder function is `ParseEventDef`, designed for event type parsing - // the abi format for a single function structure is the same, so it works. Perhaps we will rename - // `ParseEventDef` in the future, or just add another method with a different name. - eventDef, err := ethcoder.ParseEventDef(abi) - if err != nil { - return "", nil, err - } - return eventDef.Sig, eventDef.ArgNames, nil - } - - // - // If above didn't work, attempt to parse `abi` string as - // a JSON object of the full abi definition - // - - type FunctionAbi struct { - Name string `json:"name"` - Type string `json:"type"` - Inputs []struct { - InternalType string `json:"internalType"` - Name string `json:"name"` - Type string `json:"type"` - } `json:"inputs"` - } - - // Handle array of function abis and single function abi - var abis []FunctionAbi - if strings.HasPrefix(abi, "[") { - if err := json.Unmarshal([]byte(abi), &abis); err != nil { - return "", nil, err - } - } else { - var singleAbi FunctionAbi - if err := json.Unmarshal([]byte(abi), &singleAbi); err != nil { - return "", nil, err - } - abis = append(abis, singleAbi) - } - - // Find the correct method and encode it - for _, fnAbi := range abis { - if fnAbi.Name == method { - var paramTypes []string - order := make([]string, len(fnAbi.Inputs)) - for i, input := range fnAbi.Inputs { - paramTypes = append(paramTypes, input.Type) - order[i] = input.Name - } - return method + "(" + strings.Join(paramTypes, ",") + ")", order, nil - } - } - - return "", nil, errors.New("Method not found in ABI") + return ethcoder.EncodeContractCall(callDef) } diff --git a/intents/intent_data_transaction_contract_abi_test.go b/intents/intent_data_transaction_contract_abi_test.go deleted file mode 100644 index b6426f0d..00000000 --- a/intents/intent_data_transaction_contract_abi_test.go +++ /dev/null @@ -1,162 +0,0 @@ -package intents - -import ( - "testing" - - "github.com/0xsequence/ethkit/ethcoder" - "github.com/0xsequence/ethkit/go-ethereum/common" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGetMethodFromABI(t *testing.T) { - // From ABI, alone, in array - res, order, err := getMethodFromAbi(`[{"name":"transfer","type":"function","inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}]}]`, "transfer") - assert.Nil(t, err) - - assert.Equal(t, "transfer(address,uint256)", res) - assert.Equal(t, []string{"_to", "_value"}, order) - - // From ABI, alone, as object - res, order, err = getMethodFromAbi(`{"name":"transfer","type":"function","inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}]}`, "transfer") - assert.Nil(t, err) - - assert.Equal(t, "transfer(address,uint256)", res) - assert.Equal(t, []string{"_to", "_value"}, order) - - // From ABI, with many args - res, order, err = getMethodFromAbi(`[{"inputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"uint256","name":"_maxCost","type":"uint256"},{"internalType":"address[]","name":"_fees","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"fillOrKillOrder","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_val","type":"uint256"},{"internalType":"string","name":"_data","type":"string"}],"name":"notExpired","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otherMethods","outputs":[],"stateMutability":"nonpayable","type":"function"}]`, "fillOrKillOrder") - assert.Nil(t, err) - - assert.Equal(t, "fillOrKillOrder(bytes32,uint256,address[],bytes)", res) - assert.Equal(t, []string{"_orderId", "_maxCost", "_fees", "_data"}, order) - - res, order, err = getMethodFromAbi(`[{"inputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"uint256","name":"_maxCost","type":"uint256"},{"internalType":"address[]","name":"_fees","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"fillOrKillOrder","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_val","type":"uint256"},{"internalType":"string","name":"_data","type":"string"}],"name":"notExpired","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otherMethods","outputs":[],"stateMutability":"nonpayable","type":"function"}]`, "notExpired") - assert.Nil(t, err) - - assert.Equal(t, "notExpired(uint256,string)", res) - assert.Equal(t, []string{"_val", "_data"}, order) - - res, order, err = getMethodFromAbi(`[{"inputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"uint256","name":"_maxCost","type":"uint256"},{"internalType":"address[]","name":"_fees","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"fillOrKillOrder","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_val","type":"uint256"},{"internalType":"string","name":"_data","type":"string"}],"name":"notExpired","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otherMethods","outputs":[],"stateMutability":"nonpayable","type":"function"}]`, "otherMethods") - assert.Nil(t, err) - - assert.Equal(t, "otherMethods()", res) - assert.Equal(t, []string{}, order) - - // From plain method, without named args - res, order, err = getMethodFromAbi(`transfer(address,uint256)`, "transfer") - assert.Nil(t, err) - - assert.Equal(t, "transfer(address,uint256)", res) - assert.Equal(t, []string{"arg1", "arg2"}, order) - - // From plain method, with named args - res, order, err = getMethodFromAbi(`transfer(address _to,uint256 _value, bytes _mas)`, "transfer") - assert.Nil(t, err) - - assert.Equal(t, "transfer(address,uint256,bytes)", res) - assert.Equal(t, []string{"_to", "_value", "_mas"}, order) - - // Mixed plain method should return nil order - res, order, err = getMethodFromAbi(`transfer(address _to,uint256, bytes _mas)`, "transfer") - - assert.Nil(t, err) - assert.Equal(t, "transfer(address,uint256,bytes)", res) - assert.Equal(t, []string{"_to", "arg2", "_mas"}, order) -} - -func TestEncodeContractCall(t *testing.T) { - // Encode simple transferFrom, not named - res, err := EncodeContractCall(&contractCallType{ - Abi: `[{"name":"transferFrom","type":"function","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}]}]`, - Func: "transferFrom", - Args: []any{"0x0dc9603d4da53841C1C83f3B550C6143e60e0425", "0x0dc9603d4da53841C1C83f3B550C6143e60e0425", "100"}, - }) - require.Nil(t, err) - require.Equal(t, "0x23b872dd0000000000000000000000000dc9603d4da53841c1c83f3b550c6143e60e04250000000000000000000000000dc9603d4da53841c1c83f3b550c6143e60e04250000000000000000000000000000000000000000000000000000000000000064", res) - - // Encode simple transferFrom, selector - res, err = EncodeContractCall(&contractCallType{ - Abi: `transferFrom(address,address,uint256)`, - Args: []any{"0x0dc9603d4da53841C1C83f3B550C6143e60e0425", "0x0dc9603d4da53841C1C83f3B550C6143e60e0425", "100"}, - }) - require.Nil(t, err) - require.Equal(t, "0x23b872dd0000000000000000000000000dc9603d4da53841c1c83f3b550c6143e60e04250000000000000000000000000dc9603d4da53841c1c83f3b550c6143e60e04250000000000000000000000000000000000000000000000000000000000000064", res) - - // Encode simple transferFrom, named - // res, err = EncodeContractCall(&contractCallType{ - // Abi: `[{"name":"transferFrom","type":"function","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}]}]`, - // Func: "transferFrom", - // Args: json.RawMessage(`{"_from": "0x0dc9603d4da53841C1C83f3B550C6143e60e0425", "_value": "100", "_to": "0x0dc9603d4da53841C1C83f3B550C6143e60e0425"}`), - // }) - // require.Nil(t, err) - // require.Equal(t, res, "0x23b872dd0000000000000000000000000dc9603d4da53841c1c83f3b550c6143e60e04250000000000000000000000000dc9603d4da53841c1c83f3b550c6143e60e04250000000000000000000000000000000000000000000000000000000000000064") - - // Encode simple transferFrom, not named, passed as function - res, err = EncodeContractCall(&contractCallType{ - Abi: `transferFrom(address,address,uint256)`, - Args: []any{"0x13915b1ea28Fd2E8197c88ff9D2422182E83bf25", "0x4Ad47F1611c78C824Ff3892c4aE1CC04637D6462", "5192381927398174182391237"}, - }) - require.Nil(t, err) - require.Equal(t, "0x23b872dd00000000000000000000000013915b1ea28fd2e8197c88ff9d2422182e83bf250000000000000000000000004ad47f1611c78c824ff3892c4ae1cc04637d6462000000000000000000000000000000000000000000044b87969b06250e50bdc5", res) - - // Encode simple transferFrom, named, passed as function - // res, err = EncodeContractCall(&contractCallType{ - // Abi: `transferFrom(address _from,address _to,uint256 _value)`, - // Func: "transferFrom", - // Args: json.RawMessage(`{"_from": "0x13915b1ea28Fd2E8197c88ff9D2422182E83bf25", "_value": "5192381927398174182391237", "_to": "0x4Ad47F1611c78C824Ff3892c4aE1CC04637D6462"}`), - // }) - // require.Nil(t, err) - // require.Equal(t, res, "0x23b872dd00000000000000000000000013915b1ea28fd2e8197c88ff9d2422182e83bf250000000000000000000000004ad47f1611c78c824ff3892c4ae1cc04637d6462000000000000000000000000000000000000000000044b87969b06250e50bdc5") - - // // Encode nested bytes, passed as function - // nestedEncodeType1 := &contractCallType{ - // Abi: `transferFrom(uint256)`, - // Args: []any{"481923749816926378123"}, - // } - - // nestedEncodeType2 := &contractCallType{ - // Abi: `hola(string)`, - // Args: []any{"mundo"}, - // } - - // net1jsn, err := json.Marshal(nestedEncodeType1) - // require.Nil(t, err) - - // net2jsn, err := json.Marshal(nestedEncodeType2) - // require.Nil(t, err) - - arg2, err := ethcoder.AbiEncodeMethodCalldataFromStringValues("transferFrom(uint256)", []string{"481923749816926378123"}) - require.NoError(t, err) - - arg3, err := ethcoder.AbiEncodeMethodCalldataFromStringValues("hola(string)", []string{"mundo"}) - require.NoError(t, err) - - arg2Hex := "0x" + common.Bytes2Hex(arg2) - arg3Hex := "0x" + common.Bytes2Hex(arg3) - - res, err = EncodeContractCall(&contractCallType{ - Abi: "caller(address,bytes,bytes)", - Func: "caller", - Args: []any{"0x13915b1ea28Fd2E8197c88ff9D2422182E83bf25", arg2Hex, arg3Hex}, - }) - require.Nil(t, err) - require.Equal(t, "0x8b6701df00000000000000000000000013915b1ea28fd2e8197c88ff9d2422182e83bf25000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002477a11f7e00000000000000000000000000000000000000000000001a2009191df61e988b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000646ce8ea55000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000056d756e646f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", res) - - // Fail passing named args to non-named abi - // res, err = EncodeContractCall(&contractCallType{ - // Abi: `transferFrom(address,uint256)`, - // Func: "transferFrom", - // Args: json.RawMessage(`{"_from": "0x13915b1ea28Fd2E8197c88ff9D2422182E83bf25", "_value": "5192381927398174182391237", "_to": "0x4Ad47F1611c78C824Ff3892c4aE1CC04637D6462"}`), - // }) - // assert.NotNil(t, err) - - // Accept passing ordened args to named abi - res, err = EncodeContractCall(&contractCallType{ - Abi: `transferFrom(address _from,address _to,uint256 _value)`, - Func: "transferFrom", - Args: []any{"0x13915b1ea28Fd2E8197c88ff9D2422182E83bf25", "0x4Ad47F1611c78C824Ff3892c4aE1CC04637D6462", "9"}, - }) - require.Nil(t, err) - require.Equal(t, "0x23b872dd00000000000000000000000013915b1ea28fd2e8197c88ff9d2422182e83bf250000000000000000000000004ad47f1611c78c824ff3892c4ae1cc04637d64620000000000000000000000000000000000000000000000000000000000000009", res) -} diff --git a/intents/intent_data_transaction_delayed_abi.go b/intents/intent_data_transaction_delayed_abi.go index 56fec2a1..9abfc980 100644 --- a/intents/intent_data_transaction_delayed_abi.go +++ b/intents/intent_data_transaction_delayed_abi.go @@ -3,6 +3,7 @@ package intents import ( "encoding/json" "fmt" + "strings" "github.com/0xsequence/ethkit/ethcoder" "github.com/0xsequence/ethkit/go-ethereum/common" @@ -18,7 +19,7 @@ type delayedEncodeType struct { // Deprecated: use EncodeContractCall instead func EncodeDelayedABI(data *delayedEncodeType) (string, error) { // Get the method from the abi - method, order, err := getMethodFromAbi(data.Abi, data.Func) + _, method, order, _, err := getMethodFromAbi(data.Abi, data.Func) if err != nil { return "", err } @@ -96,3 +97,78 @@ func EncodeDelayedABI(data *delayedEncodeType) (string, error) { return "", err } + +// The abi may be a: +// - already encoded method abi: transferFrom(address,address,uint256) +// - already encoded named method: transferFrom(address from,address to,uint256 val) +// - an array of function abis: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_orderId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_maxCost\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_fees\",\"type\":\"address\"}],\"name\":\"fillOrKillOrder\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}]" +// - or a single function abi: "{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_orderId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_maxCost\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_fees\",\"type\":\"address\"}],\"name\":\"fillOrKillOrder\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}" +// And it must always return it encoded, like this: +// - transferFrom(address,address,uint256) +// making sure that the method matches the returned one +func getMethodFromAbi(abiSigOrJSON string, method string) (*ethcoder.ABISignature, string, []string, []string, error) { + // + // First attempt to parse `abiSigOrJSON` string as a plain method abi + // ie. transferFrom(address,address,uint256) + // + + // Handle the case for already encoded method abi. + // NOTE: we do not need the know the `method` argument here. + abiSigOrJSON = strings.TrimSpace(abiSigOrJSON) + if len(abiSigOrJSON) > 0 && strings.Contains(abiSigOrJSON, "(") && abiSigOrJSON[len(abiSigOrJSON)-1] == ')' { + // NOTE: even though the ethcoder function is `ParseEventDef`, designed for event type parsing + // the abi format for a single function structure is the same, so it works. Perhaps we will rename + // `ParseEventDef` in the future, or just add another method with a different name. + abiSig, err := ethcoder.ParseABISignature(abiSigOrJSON) + if err != nil { + return nil, "", nil, nil, err + } + + // NOTE: we only return the abiSig if the `abiSigOrJSON` is an abi signature + return &abiSig, abiSig.Signature, abiSig.ArgNames, abiSig.ArgTypes, nil + } + + // + // If above didn't work, attempt to parse `abi` string as + // a JSON object of the full abi definition + // + + type FunctionAbi struct { + Name string `json:"name"` + Type string `json:"type"` + Inputs []struct { + InternalType string `json:"internalType"` + Name string `json:"name"` + Type string `json:"type"` + } `json:"inputs"` + } + + // Handle array of function abis and single function abi + var abis []FunctionAbi + if strings.HasPrefix(abiSigOrJSON, "[") { + if err := json.Unmarshal([]byte(abiSigOrJSON), &abis); err != nil { + return nil, "", nil, nil, err + } + } else { + var singleAbi FunctionAbi + if err := json.Unmarshal([]byte(abiSigOrJSON), &singleAbi); err != nil { + return nil, "", nil, nil, err + } + abis = append(abis, singleAbi) + } + + // Find the correct method and encode it + for _, fnAbi := range abis { + if fnAbi.Name == method { + var paramTypes []string + order := make([]string, len(fnAbi.Inputs)) + for i, input := range fnAbi.Inputs { + paramTypes = append(paramTypes, input.Type) + order[i] = input.Name + } + return nil, method + "(" + strings.Join(paramTypes, ",") + ")", order, paramTypes, nil + } + } + + return nil, "", nil, nil, fmt.Errorf("method not found in abi") +} diff --git a/intents/intent_data_transaction_delayed_abi_test.go b/intents/intent_data_transaction_delayed_abi_test.go index 9284ab58..bd39c72d 100644 --- a/intents/intent_data_transaction_delayed_abi_test.go +++ b/intents/intent_data_transaction_delayed_abi_test.go @@ -4,9 +4,67 @@ import ( "encoding/json" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +func TestGetMethodFromABI(t *testing.T) { + // From ABI, alone, in array + _, res, argNames, argTypes, err := getMethodFromAbi(`[{"name":"transfer","type":"function","inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}]}]`, "transfer") + assert.Nil(t, err) + + require.Equal(t, "transfer(address,uint256)", res) + require.Equal(t, []string{"_to", "_value"}, argNames) + require.Equal(t, []string{"address", "uint256"}, argTypes) + + // From ABI, alone, as object + _, res, order, _, err := getMethodFromAbi(`{"name":"transfer","type":"function","inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}]}`, "transfer") + assert.Nil(t, err) + + assert.Equal(t, "transfer(address,uint256)", res) + assert.Equal(t, []string{"_to", "_value"}, order) + + // From ABI, with many args + _, res, order, _, err = getMethodFromAbi(`[{"inputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"uint256","name":"_maxCost","type":"uint256"},{"internalType":"address[]","name":"_fees","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"fillOrKillOrder","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_val","type":"uint256"},{"internalType":"string","name":"_data","type":"string"}],"name":"notExpired","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otherMethods","outputs":[],"stateMutability":"nonpayable","type":"function"}]`, "fillOrKillOrder") + assert.Nil(t, err) + + assert.Equal(t, "fillOrKillOrder(bytes32,uint256,address[],bytes)", res) + assert.Equal(t, []string{"_orderId", "_maxCost", "_fees", "_data"}, order) + + _, res, order, _, err = getMethodFromAbi(`[{"inputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"uint256","name":"_maxCost","type":"uint256"},{"internalType":"address[]","name":"_fees","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"fillOrKillOrder","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_val","type":"uint256"},{"internalType":"string","name":"_data","type":"string"}],"name":"notExpired","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otherMethods","outputs":[],"stateMutability":"nonpayable","type":"function"}]`, "notExpired") + assert.Nil(t, err) + + assert.Equal(t, "notExpired(uint256,string)", res) + assert.Equal(t, []string{"_val", "_data"}, order) + + _, res, order, _, err = getMethodFromAbi(`[{"inputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"uint256","name":"_maxCost","type":"uint256"},{"internalType":"address[]","name":"_fees","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"fillOrKillOrder","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_val","type":"uint256"},{"internalType":"string","name":"_data","type":"string"}],"name":"notExpired","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otherMethods","outputs":[],"stateMutability":"nonpayable","type":"function"}]`, "otherMethods") + assert.Nil(t, err) + + assert.Equal(t, "otherMethods()", res) + assert.Equal(t, []string{}, order) + + // From plain method, without named args + _, res, order, _, err = getMethodFromAbi(`transfer(address,uint256)`, "transfer") + assert.Nil(t, err) + + assert.Equal(t, "transfer(address,uint256)", res) + assert.Equal(t, []string{"arg1", "arg2"}, order) + + // From plain method, with named args + _, res, order, _, err = getMethodFromAbi(`transfer(address _to,uint256 _value, bytes _mas)`, "transfer") + assert.Nil(t, err) + + assert.Equal(t, "transfer(address,uint256,bytes)", res) + assert.Equal(t, []string{"_to", "_value", "_mas"}, order) + + // Mixed plain method should return nil order + _, res, order, _, err = getMethodFromAbi(`transfer(address _to,uint256, bytes _mas)`, "transfer") + + assert.Nil(t, err) + assert.Equal(t, "transfer(address,uint256,bytes)", res) + assert.Equal(t, []string{"_to", "arg2", "_mas"}, order) +} + func TestEncodeDelayedABI(t *testing.T) { // Encode simple transferFrom, not named res, err := EncodeDelayedABI(&delayedEncodeType{ @@ -50,14 +108,12 @@ func TestEncodeDelayedABI(t *testing.T) { // Encode nested bytes, passed as function - // TODO/NOTE: this makes no sense, we are making up an abi type of transferFrom just to encode a uint256 nestedEncodeType1 := &delayedEncodeType{ Abi: `transferFrom(uint256)`, Func: "transferFrom", Args: json.RawMessage(`["481923749816926378123"]`), } - // TODO/NOTE: this makes no sense, we are making up a random abi just so we can encode a string.. nestedEncodeType2 := &delayedEncodeType{ Abi: `hola(string)`, Func: "hola", diff --git a/intents/intent_data_transaction_ext.go b/intents/intent_data_transaction_ext.go index e7aa50d2..0d030768 100644 --- a/intents/intent_data_transaction_ext.go +++ b/intents/intent_data_transaction_ext.go @@ -279,16 +279,16 @@ func (p *IntentDataSendTransaction) Nonce() (*big.Int, error) { return sequence.EncodeNonce(big.NewInt(0).SetBytes(hashed[:20]), common.Big0) } -func (p *IntentDataSendTransaction) IsValidInterpretation(subdigest common.Hash, txns sequence.Transactions, nonce *big.Int) bool { +func (p *IntentDataSendTransaction) IsValidInterpretation(subdigest common.Hash, txns sequence.Transactions, nonce *big.Int) (bool, error) { // Nonce must be the expected one // (defined by the identifier) enonce, err := p.Nonce() if err != nil { - return false + return false, fmt.Errorf("invalid nonce: %w", err) } if enonce.Cmp(nonce) != 0 { - return false + return false, fmt.Errorf("invalid nonce") } // Compare the digest with the provided transactions @@ -300,49 +300,49 @@ func (p *IntentDataSendTransaction) IsValidInterpretation(subdigest common.Hash, calcDigest, err := bundle.Digest() if err != nil { - return false + return false, fmt.Errorf("invalid bundle digest: %w", err) } chainID, err := p.chainID() if err != nil { - return false + return false, err } calcSubdigest, err := sequence.SubDigest(chainID, p.wallet(), calcDigest) if err != nil || !bytes.Equal(calcSubdigest, subdigest[:]) { - return false + return false, fmt.Errorf("invalid subdigest: %w", err) } // Now check that every transaction maps 1:1 to the transactions in the intent // meaning that they follow the intent signed by it if len(txns) != len(p.Transactions) { - return false + return false, fmt.Errorf("intent transaction count mismatch") } for i, txn := range txns { if txn.DelegateCall { - return false + return false, fmt.Errorf("delegate call not allowed") } expected, err := p.ExpectedValuesFor(&p.Transactions[i]) if err != nil { - return false + return false, fmt.Errorf("invalid transaction: %w", err) } if !bytes.Equal(txn.To.Bytes(), expected.To.Bytes()) { - return false + return false, fmt.Errorf("invalid to address") } if txn.Value.Cmp(expected.Value) != 0 { - return false + return false, fmt.Errorf("invalid value") } if !bytes.Equal(txn.Data, expected.Data) { - return false + return false, fmt.Errorf("invalid data") } } - return true + return true, nil } type SendTransactionResponse struct { diff --git a/intents/intent_data_transaction_ext_test.go b/intents/intent_data_transaction_ext_test.go index f75c40a4..55689b93 100644 --- a/intents/intent_data_transaction_ext_test.go +++ b/intents/intent_data_transaction_ext_test.go @@ -69,7 +69,7 @@ func TestRecoverTransactionIntent(t *testing.T) { "args": [ "48774435471364917511246724398022004900255301025912680232738918790354204737320", "1000000000000000000", - "[\"0x8541D65829f98f7D71A4655cCD7B2bB8494673bF\"]", + ["0x8541D65829f98f7D71A4655cCD7B2bB8494673bF"], { "abi": "notExpired(uint256,string)", "args": [ @@ -185,41 +185,53 @@ func TestRecoverTransactionIntent(t *testing.T) { ) require.Nil(t, err) - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + isValid, err := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.NoError(t, err) + require.True(t, isValid) // changing any transaction value should invalidate the interpretation for i := range transactions { prev := transactions[i].Value transactions[i].Value = big.NewInt(123) - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + isValid, err = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.Error(t, err) + require.False(t, isValid) transactions[i].Value = prev - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + isValid, err = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.NoError(t, err) + require.True(t, isValid) } // changing any transaction data should invalidate the interpretation for i := range transactions { prev := transactions[i].Data transactions[i].Data = common.Hex2Bytes("0x1234") - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) transactions[i].Data = prev - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.True(t, ok) } // changing any to address should invalidate the interpretation for i := range transactions { prev := transactions[i].To transactions[i].To = common.HexToAddress("0xd1333D70A344c26041a869077381209462e586F8") - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) transactions[i].To = prev - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.True(t, ok) } // setting any delegate call should invalidate the interpretation for i := range transactions { transactions[i].DelegateCall = true - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) transactions[i].DelegateCall = false - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.True(t, ok) } // changing revert on error should NOT invalidate the interpretation @@ -239,7 +251,8 @@ func TestRecoverTransactionIntent(t *testing.T) { ) require.Nil(t, err) - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, nonce) + require.True(t, ok) transactions[i].RevertOnError = true } @@ -261,7 +274,8 @@ func TestRecoverTransactionIntent(t *testing.T) { ) require.Nil(t, err) - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, nonce) + require.True(t, ok) transactions[i].GasLimit = prev } @@ -279,10 +293,12 @@ func TestRecoverTransactionIntent(t *testing.T) { nxtdigest, ) require.Nil(t, err) - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, big.NewInt(123))) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, big.NewInt(123)) + require.False(t, ok) // removing a transaction should invalidate the interpretation - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions[1:], nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions[1:], nonce) + require.False(t, ok) // adding an extra transaction should invalidate the interpretation transactions = append(transactions, &sequence.Transaction{ @@ -294,11 +310,12 @@ func TestRecoverTransactionIntent(t *testing.T) { Data: common.FromHex("0x3251ba32"), }) - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) } -// NOTE: DelayedEncode is deprecated, see TestRecoverTransactionIntent below which uses contractCall -func Test2RecoverTransactionIntentWithDelayedEncode(t *testing.T) { +// NOTE: DelayedEncode is deprecated, see TestRecoverTransactionIntent below which uses contractCall type +func TestDelayedEncodeRecoverTransactionIntent(t *testing.T) { data := `{ "version": "1", "name": "sendTransaction", @@ -473,41 +490,50 @@ func Test2RecoverTransactionIntentWithDelayedEncode(t *testing.T) { ) require.Nil(t, err) - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.True(t, ok) // changing any transaction value should invalidate the interpretation for i := range transactions { prev := transactions[i].Value transactions[i].Value = big.NewInt(123) - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) transactions[i].Value = prev - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.True(t, ok) } // changing any transaction data should invalidate the interpretation for i := range transactions { prev := transactions[i].Data transactions[i].Data = common.Hex2Bytes("0x1234") - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) transactions[i].Data = prev - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.True(t, ok) } // changing any to address should invalidate the interpretation for i := range transactions { prev := transactions[i].To transactions[i].To = common.HexToAddress("0xd1333D70A344c26041a869077381209462e586F8") - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) transactions[i].To = prev - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.True(t, ok) } // setting any delegate call should invalidate the interpretation for i := range transactions { transactions[i].DelegateCall = true - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) transactions[i].DelegateCall = false - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.True(t, ok) } // changing revert on error should NOT invalidate the interpretation @@ -527,7 +553,8 @@ func Test2RecoverTransactionIntentWithDelayedEncode(t *testing.T) { ) require.Nil(t, err) - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, nonce) + require.True(t, ok) transactions[i].RevertOnError = true } @@ -549,7 +576,8 @@ func Test2RecoverTransactionIntentWithDelayedEncode(t *testing.T) { ) require.Nil(t, err) - require.True(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, nonce)) + ok, _ := sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, nonce) + require.True(t, ok) transactions[i].GasLimit = prev } @@ -567,10 +595,12 @@ func Test2RecoverTransactionIntentWithDelayedEncode(t *testing.T) { nxtdigest, ) require.Nil(t, err) - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, big.NewInt(123))) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(nxtsubdigest), transactions, big.NewInt(123)) + require.False(t, ok) // removing a transaction should invalidate the interpretation - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions[1:], nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions[1:], nonce) + require.False(t, ok) // adding an extra transaction should invalidate the interpretation transactions = append(transactions, &sequence.Transaction{ @@ -582,5 +612,6 @@ func Test2RecoverTransactionIntentWithDelayedEncode(t *testing.T) { Data: common.FromHex("0x3251ba32"), }) - require.False(t, sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce)) + ok, _ = sendTransactionData.IsValidInterpretation(common.BytesToHash(subdigest), transactions, nonce) + require.False(t, ok) }