umbracle/ethgo

encode nested tuple error

Closed this issue · 1 comments

code

import (
	"fmt"
	"github.com/umbracle/ethgo"
	"github.com/umbracle/ethgo/abi"
	"github.com/umbracle/ethgo/contract"
	"github.com/umbracle/ethgo/jsonrpc"
	"github.com/umbracle/ethgo/wallet"
	"math/big"
	"testing"
)



type SwapParams struct {
	PoolID    [32]byte
	Kind      *big.Int
	AssertIn  string
	AssertOut string
	Amount    *big.Int
	UserData  []byte
}

type FunderParams struct {
	Sender              string
	FromInternalBalance bool
	Recipient           string
	ToInternalBalance   bool
}


func MethodEncode(function string, args ...interface{}) ([]byte, error) {
	method, err := abi.NewMethod(function)
	if err != nil {
		return nil, err
	}
	data, err := method.Encode(args)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func TestEncodeNestedTuple(t *testing.T) {
	poolID := [32]byte{}
	copy(poolID[:], "0xf3946a0e5368f716b1f40586272c9066b419035c000200000000000000000424")
	swapParams := SwapParams{
		PoolID:    poolID,
		Kind:      big.NewInt(0),
		AssertIn:  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
		AssertOut: "0xfd0205066521550D7d7AB19DA8F72bb004b4C341",
		Amount:    big.NewInt(500000000),
		UserData:  []byte("0x"),
	}
	funderParams := FunderParams{
		Sender:              "0x8EbEC7277a5c0C43ac708BC641CBF9756E7938f4",
		FromInternalBalance: false,
		Recipient:           "0x8EbEC7277a5c0C43ac708BC641CBF9756E7938f4",
		ToInternalBalance:   false,
	}

	encodeData, err := MethodEncode("swap((bytes32,uint8,address,address,uint256,bytes),(address,bool,address,bool),uint256,uint256)", swapParams, funderParams, 1, 1)
	if err != nil {
		panic(err)
	}
	fmt.Println(encodeData)
}


result

--- FAIL: TestEncodeNestedTuple (0.00s)
panic: cannot get key  [recovered]
	panic: cannot get key 

image

Apologize for the late response.

The error is that the abi encoder does not know how to match the inputs in the function signature with the struct. If it were a list instead, it matches by index (i.e. input at index 1 is item at index 1) but it needs a name when working with structs.

To fix it, you have to assign a name to the input and a tag to the fields in the struct:

type SwapParams struct {
	PoolID    [32]byte `abi:"a"`
	Kind      *big.Int `abi:"b"`
	AssertIn  string   `abi:"c"`
	AssertOut string   `abi:"d"`
	Amount    *big.Int `abi:"e"`
	UserData  []byte   `abi:"f"`
}

type FunderParams struct {
	Sender              string `abi:"a"`
	FromInternalBalance bool   `abi:"b"`
	Recipient           string `abi:"c"`
	ToInternalBalance   bool   `abi:"d"`
}

...

encodeData, err := MethodEncode("swap((bytes32 a,uint8 b,address c,address d,uint256 e,bytes f),(address a,bool b,address c,bool d),uint256,uint256)", swapParams, funderParams, 1, 1)
if err != nil {
	panic(err)
}