mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 03:30:37 +00:00
feature: support generate parse transaction input bytes codes in abigen
(#7593)
feature: support generate parse transaction input bytes codes in `abigen`. It's easy to use abigen to generate code that help you parse the event log and call the payable method with the transactor. But parsing the transaction call data is missing. You can only send a transaction with a transactor. This PR aims to generate codes that help developer parse transaction calldata. abigen can generate code to parse the transaction call data. With this PR, transaction parse codes are generated like this: ```go // CollectParams is an auto generated read-only Go binding of transcaction calldata params type CollectParams struct { Param_params INonfungiblePositionManagerCollectParams } // Parse Collect method from calldata of a transaction // // Solidity: function collect((uint256,address,uint128,uint128) params) payable returns(uint256 amount0, uint256 amount1) func ParseCollect(calldata []byte) (*CollectParams, error) { if len(calldata) <= 4 { return nil, fmt.Errorf("invalid calldata input") } _abi, err := abi.JSON(strings.NewReader(UniswapABI)) if err != nil { return nil, fmt.Errorf("failed to get abi of registry metadata: %w", err) } out, err := _abi.Methods["collect"].Inputs.Unpack(calldata[4:]) if err != nil { return nil, fmt.Errorf("failed to unpack collect params data: %w", err) } var paramsResult = new(CollectParams) value := reflect.ValueOf(paramsResult).Elem() if value.NumField() != len(out) { return nil, fmt.Errorf("failed to match calldata with param field number") } out0 := *abi.ConvertType(out[0], new(INonfungiblePositionManagerCollectParams)).(*INonfungiblePositionManagerCollectParams) return &CollectParams{ Param_params: out0, }, nil } ``` Example of using `Parse` Function above: ```go package bin import ( "context" "fmt" "testing" "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/log/v3" ) func TestOnParse(t *testing.T) { cli, err := rpc.Dial("https://rpc.ankr.com/polygon", log.New(context.Background())) if err != nil { t.Fatal(err) } var collectTx struct { Input string `json:"input"` } err = cli.CallContext(context.Background(), &collectTx, "eth_getTransactionByHash", "0x741146cce64d873cfe82ade413651de355a6db92f992e5bfc4e1c58d92f5dd5b") if err != nil { t.Fatal(err) } var increaseLiquidityTx struct { Input string `json:"input"` } err = cli.CallContext(context.Background(), &increaseLiquidityTx, "eth_getTransactionByHash", "0x645ff650d7bfb9a74f573af474b9ebee48c3fadc7dac67257a8da6b55c71f338") if err != nil { t.Fatal(err) } fmt.Println(collectTx.Input) fmt.Println(increaseLiquidityTx.Input) collectBytes, _ := hexutil.Decode(collectTx.Input) increaseLiquidityBytes, _ := hexutil.Decode(increaseLiquidityTx.Input) collectInfo, err := ParseCollect(collectBytes) if err != nil { t.Fatal(err) } increaseLiquidityInfo, err := ParseIncreaseLiquidity(increaseLiquidityBytes) if err != nil { t.Fatal(err) } fmt.Printf("%+v\n", collectInfo) fmt.Printf("%+v\n", increaseLiquidityInfo) } ``` Output of code above: &{Param_params:{TokenId:+894123 Recipient:0x48B8e4ed457da9B64c33Ee50Fd5490614833A37D Amount0Max:+340282366920938463463374607431768211455 Amount1Max:+340282366920938463463374607431768211455}} &{Param_params:{TokenId:+891904 Amount0Desired:+331092 Amount1Desired:+0 Amount0Min:+331092 Amount1Min:+0 Deadline:+1685112789}}
This commit is contained in:
parent
3c2b99e19c
commit
5554ff34a6
@ -90,6 +90,8 @@ package {{.Package}}
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
ethereum "github.com/ledgerwatch/erigon"
|
||||
"github.com/ledgerwatch/erigon/accounts/abi"
|
||||
@ -335,7 +337,7 @@ var (
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{range .Transacts}}
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
@ -360,6 +362,52 @@ var (
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{$metaType := .Type}}
|
||||
{{range .Transacts}}
|
||||
{{if ne (len .Normalized.Inputs) 0}}
|
||||
|
||||
// {{.Normalized.Name}}Params is an auto generated read-only Go binding of transcaction calldata params
|
||||
type {{.Normalized.Name}}Params struct {
|
||||
{{range $i, $_ := .Normalized.Inputs}} Param_{{.Name}} {{bindtype .Type $structs}}
|
||||
{{end}}
|
||||
}
|
||||
|
||||
// Parse {{.Normalized.Name}} method from calldata of a transaction
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func Parse{{.Normalized.Name}}(calldata []byte) (*{{.Normalized.Name}}Params, error) {
|
||||
if len(calldata) <= 4 {
|
||||
return nil, fmt.Errorf("invalid calldata input")
|
||||
}
|
||||
|
||||
_abi, err := abi.JSON(strings.NewReader({{$metaType}}ABI))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get abi of registry metadata: %w", err)
|
||||
}
|
||||
|
||||
out, err := _abi.Methods["{{.Original.Name}}"].Inputs.Unpack(calldata[4:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unpack {{.Original.Name}} params data: %w", err)
|
||||
}
|
||||
|
||||
var paramsResult = new({{.Normalized.Name}}Params)
|
||||
value := reflect.ValueOf(paramsResult).Elem()
|
||||
|
||||
if value.NumField() != len(out) {
|
||||
return nil, fmt.Errorf("failed to match calldata with param field number")
|
||||
}
|
||||
|
||||
{{range $i, $t := .Normalized.Inputs}}
|
||||
out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return &{{.Normalized.Name}}Params{
|
||||
{{range $i, $_ := .Normalized.Inputs}} Param_{{.Name}} : out{{$i}},{{end}}
|
||||
}, nil
|
||||
}
|
||||
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if .Fallback}}
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user