go-ethereum
go-ethereum copied to clipboard
[proposal] abigen: add encoder to pack or unpack functions
Add global encoder to auto generated contract for handling pack(unpack) data.
For example, Crowdsale Contract in bind_test.go will generate below codes.
var CrowdsaleEncoder = newCrowdsaleEncoder()
...
type _CrowdsaleEncoder struct {
abi *abi.ABI
initErr error
}
...
func newCrowdsaleEncoder() *_CrowdsaleEncoder {
parsed, err := CrowdsaleMetaData.GetAbi()
if err == nil && parsed == nil {
err = errors.New("GetABI returned nil")
}
return &_CrowdsaleEncoder{
abi: parsed,
initErr: err,
}
}
...
func (_Crowdsale *_CrowdsaleEncoder) PackAmountRaised() ([]byte, error) {
if _Crowdsale.initErr != nil {
return nil, _Crowdsale.initErr
}
return _Crowdsale.abi.Pack("amountRaised")
}
...
func (_Crowdsale *_CrowdsaleEncoder) UnpackAmountRaised(output []byte) (*big.Int, error) {
if _Crowdsale.initErr != nil {
return *new(*big.Int), _Crowdsale.initErr
}
out, err := _Crowdsale.abi.Unpack("amountRaised", output)
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, nil
}
func (_Crowdsale *_CrowdsaleEncoder) UnpackFunders(output []byte) (struct {
Addr common.Address
Amount *big.Int
}, error) {
if _Crowdsale.initErr != nil {
outstruct := new(struct {
Addr common.Address
Amount *big.Int
})
return *outstruct, _Crowdsale.initErr
}
out, err := _Crowdsale.abi.Unpack("funders", output)
outstruct := new(struct {
Addr common.Address
Amount *big.Int
})
if err != nil {
return *outstruct, err
}
outstruct.Addr = *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
outstruct.Amount = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
return *outstruct, err
}
Right now, the way that I do this is:
abi, err := bindings.Contract.GetAbi()
if err != nil {
return nil, err
}
method, err := abi.MethodById(calldata)
if err != nil {
return nil, err
}
// Perhaps check method.Name here as well
args, err := method.Inputs.Unpack(calldata[4:])
if err != nil {
return nil, err
}
There is probably a better API out there but I'm not sold on what it is yet
@tynes I also know the way but i just want to use auto-generated source code :) It will be helpful to use it even if we don't know the exact input/ouput types.
After thinking about this more, I generally think this would be useful. In my example above, there is more boilerplate code that does type coercion and validation after the call to Unpack
. I'd love to be able to have autogenerated code to remove all of the boilerplate.
How does the top level encoder get initialized? Maybe something in the init
function, so you can directly access the encoder right out of the package without needing a constructor.
How does the top level encoder get initialized?
Updated the suggestion to use a global variable :) Although there is a lot of redundant code (because of init error), It will be easier to use.
@zacscoding Do you have any time to add some tests? Perhaps that would make this more interesting to review
@s1na has an alternative implementation of this idea in #26782