add errors to emitted code.
This commit is contained in:
parent
4f6ae72a66
commit
c589b31073
|
@ -189,6 +189,7 @@ func bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
|||
calls = make(map[string]*tmplMethod)
|
||||
transacts = make(map[string]*tmplMethod)
|
||||
events = make(map[string]*tmplEvent)
|
||||
errors = make(map[string]*tmplError)
|
||||
fallback *tmplMethod
|
||||
receive *tmplMethod
|
||||
|
||||
|
@ -304,6 +305,51 @@ func bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
|||
// Append the event to the accumulator list
|
||||
events[original.Name] = &tmplEvent{Original: original, Normalized: normalized}
|
||||
}
|
||||
for _, original := range evmABI.Errors {
|
||||
// TODO: I copied this from events. I think it should be correct but not totally sure
|
||||
// even if it is correct, should consider deduplicating this into its own function.
|
||||
|
||||
// Normalize the event for capital cases and non-anonymous outputs
|
||||
normalized := original
|
||||
|
||||
// Ensure there is no duplicated identifier
|
||||
normalizedName := methodNormalizer(alias(aliases, original.Name))
|
||||
// Name shouldn't start with a digit. It will make the generated code invalid.
|
||||
if len(normalizedName) > 0 && unicode.IsDigit(rune(normalizedName[0])) {
|
||||
normalizedName = fmt.Sprintf("E%s", normalizedName)
|
||||
normalizedName = abi.ResolveNameConflict(normalizedName, func(name string) bool {
|
||||
_, ok := eventIdentifiers[name]
|
||||
return ok
|
||||
})
|
||||
}
|
||||
if eventIdentifiers[normalizedName] {
|
||||
return nil, fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
|
||||
}
|
||||
eventIdentifiers[normalizedName] = true
|
||||
normalized.Name = normalizedName
|
||||
|
||||
used := make(map[string]bool)
|
||||
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
||||
copy(normalized.Inputs, original.Inputs)
|
||||
for j, input := range normalized.Inputs {
|
||||
if input.Name == "" || isKeyWord(input.Name) {
|
||||
normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j)
|
||||
}
|
||||
// Event is a bit special, we need to define event struct in binding,
|
||||
// ensure there is no camel-case-style name conflict.
|
||||
for index := 0; ; index++ {
|
||||
if !used[capitalise(normalized.Inputs[j].Name)] {
|
||||
used[capitalise(normalized.Inputs[j].Name)] = true
|
||||
break
|
||||
}
|
||||
normalized.Inputs[j].Name = fmt.Sprintf("%s%d", normalized.Inputs[j].Name, index)
|
||||
}
|
||||
if hasStruct(input.Type) {
|
||||
bindStructType(input.Type, structs)
|
||||
}
|
||||
}
|
||||
errors[original.Name] = &tmplError{Original: original, Normalized: normalized}
|
||||
}
|
||||
// Add two special fallback functions if they exist
|
||||
if evmABI.HasFallback() {
|
||||
fallback = &tmplMethod{Original: evmABI.Fallback}
|
||||
|
@ -324,6 +370,7 @@ func bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
|||
Events: events,
|
||||
Libraries: make(map[string]string),
|
||||
AllLibraries: make(map[string]string),
|
||||
Errors: errors,
|
||||
}
|
||||
|
||||
// Function 4-byte signatures are stored in the same sequence
|
||||
|
|
|
@ -46,6 +46,7 @@ type tmplContract struct {
|
|||
Libraries map[string]string // Same as tmplData, but filtered to only keep direct deps that the contract needs
|
||||
AllLibraries map[string]string // same as Libraries, but all direct/indirect library dependencies
|
||||
Library bool // Indicator whether the contract is a library
|
||||
Errors map[string]*tmplError
|
||||
}
|
||||
|
||||
// tmplMethod is a wrapper around an abi.Method that contains a few preprocessed
|
||||
|
@ -63,6 +64,11 @@ type tmplEvent struct {
|
|||
Normalized abi.Event // Normalized version of the parsed fields
|
||||
}
|
||||
|
||||
type tmplError struct {
|
||||
Original abi.Error
|
||||
Normalized abi.Error
|
||||
}
|
||||
|
||||
// tmplField is a wrapper around a struct field with binding language
|
||||
// struct type definition and relative filed name.
|
||||
type tmplField struct {
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
// Reference imports to suppress solc_errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
// Reference imports to suppress solc_errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
// Reference imports to suppress solc_errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
// Code generated via abigen V2 - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package solc_errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
_ = bind.Bind
|
||||
_ = common.Big1
|
||||
_ = types.BloomLookup
|
||||
_ = abi.ConvertType
|
||||
)
|
||||
|
||||
var CLibraryDeps = []*bind.MetaData{}
|
||||
|
||||
// TODO: convert this type to value type after everything works.
|
||||
// CMetaData contains all meta data concerning the C contract.
|
||||
var CMetaData = &bind.MetaData{
|
||||
ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"arg1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg2\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg3\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"arg4\",\"type\":\"bool\"}],\"name\":\"BadThing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Foo\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
|
||||
Pattern: "55ef3c19a0ab1c1845f9e347540c1e51f5",
|
||||
Bin: "0x6080604052348015600e575f80fd5b506101148061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063bfb4ebcf14602a575b5f80fd5b60306032565b005b5f600160025f6040517fbb6a82f1000000000000000000000000000000000000000000000000000000008152600401606c949392919060a3565b60405180910390fd5b5f819050919050565b6085816075565b82525050565b5f8115159050919050565b609d81608b565b82525050565b5f60808201905060b45f830187607e565b60bf6020830186607e565b60ca6040830185607e565b60d560608301846096565b9594505050505056fea26469706673582212205ce065ab1cfe16beba2b766e14009fc67ac66c214872149c889f0589720b870a64736f6c634300081a0033",
|
||||
}
|
||||
|
||||
// C is an auto generated Go binding around an Ethereum contract.
|
||||
type C struct {
|
||||
abi abi.ABI
|
||||
}
|
||||
|
||||
// NewC creates a new instance of C.
|
||||
func NewC() (*C, error) {
|
||||
parsed, err := CMetaData.GetAbi()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &C{abi: *parsed}, nil
|
||||
}
|
||||
|
||||
func (_C *C) PackConstructor() ([]byte, error) {
|
||||
return _C.abi.Pack("")
|
||||
}
|
||||
|
||||
// Foo is a free data retrieval call binding the contract method 0xbfb4ebcf.
|
||||
//
|
||||
// Solidity: function Foo() pure returns()
|
||||
func (_C *C) PackFoo() ([]byte, error) {
|
||||
return _C.abi.Pack("Foo")
|
||||
}
|
||||
|
||||
// CBadThing represents a BadThing error raised by the C contract.
|
||||
type CBadThing struct {
|
||||
Arg1 *big.Int
|
||||
Arg2 *big.Int
|
||||
Arg3 *big.Int
|
||||
Arg4 bool
|
||||
}
|
||||
|
||||
func CBadThingErrorID() common.Hash {
|
||||
return common.HexToHash("0xbb6a82f123854747ef4381e30e497f934a3854753fec99a69c35c30d4b46714d")
|
||||
}
|
||||
|
||||
func (_C *C) UnpackBadThingError(raw []byte) (*CBadThing, error) {
|
||||
errName := "BadThing"
|
||||
out := new(CBadThing)
|
||||
if err := _C.abi.UnpackIntoInterface(out, errName, raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"contracts":{"contract.sol:C":{"abi":[{"inputs":[{"internalType":"uint256","name":"arg1","type":"uint256"},{"internalType":"uint256","name":"arg2","type":"uint256"},{"internalType":"uint256","name":"arg3","type":"uint256"},{"internalType":"bool","name":"arg4","type":"bool"}],"name":"BadThing","type":"error"},{"inputs":[],"name":"Foo","outputs":[],"stateMutability":"pure","type":"function"}],"bin":"6080604052348015600e575f80fd5b506101148061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063bfb4ebcf14602a575b5f80fd5b60306032565b005b5f600160025f6040517fbb6a82f1000000000000000000000000000000000000000000000000000000008152600401606c949392919060a3565b60405180910390fd5b5f819050919050565b6085816075565b82525050565b5f8115159050919050565b609d81608b565b82525050565b5f60808201905060b45f830187607e565b60bf6020830186607e565b60ca6040830185607e565b60d560608301846096565b9594505050505056fea26469706673582212205ce065ab1cfe16beba2b766e14009fc67ac66c214872149c889f0589720b870a64736f6c634300081a0033"}},"version":"0.8.26+commit.8a97fa7a.Darwin.appleclang"}
|
|
@ -0,0 +1,15 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
error BadThing(uint256 arg1, uint256 arg2, uint256 arg3, bool arg4);
|
||||
|
||||
contract C {
|
||||
function Foo() public pure {
|
||||
revert BadThing({
|
||||
arg1: uint256(0),
|
||||
arg2: uint256(1),
|
||||
arg3: uint256(2),
|
||||
arg4: false
|
||||
});
|
||||
}
|
||||
}
|
|
@ -278,7 +278,7 @@ type EventIterator[T any] struct {
|
|||
unpack func(*types.Log) (*T, error) // Unpack function for the event
|
||||
|
||||
logs chan types.Log // Log channel receiving the found contract events
|
||||
sub ethereum.Subscription // Subscription for errors, completion and termination
|
||||
sub ethereum.Subscription // Subscription for solc_errors, completion and termination
|
||||
done bool // Whether the subscription completed delivering logs
|
||||
fail error // Occurred error to stop iteration
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/testdata/v2/events"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/testdata/v2/nested_libraries"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/testdata/v2/solc_errors"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
@ -98,8 +99,60 @@ func testSetup() (*bind.TransactOpts, *backends.SimulatedBackend, error) {
|
|||
}
|
||||
|
||||
// test deployment and interaction for a basic contract with no library deps
|
||||
func TestDeployment(t *testing.T) {
|
||||
func TestErrors(t *testing.T) {
|
||||
opts, bindBackend, err := testSetup()
|
||||
if err != nil {
|
||||
t.Fatalf("err setting up test: %v", err)
|
||||
}
|
||||
defer bindBackend.Backend.Close()
|
||||
|
||||
deploymentParams := DeploymentParams{
|
||||
Contracts: []ContractDeployParams{
|
||||
{
|
||||
Meta: solc_errors.CMetaData,
|
||||
},
|
||||
},
|
||||
}
|
||||
res, err := LinkAndDeploy(opts, bindBackend, deploymentParams)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %+v\n", err)
|
||||
}
|
||||
bindBackend.Commit()
|
||||
|
||||
if len(res.Addrs) != 1 {
|
||||
t.Fatalf("deployment should have generated 1 addresses. got %d", len(res.Addrs))
|
||||
}
|
||||
for _, tx := range res.Txs {
|
||||
_, err = bind.WaitDeployed(context.Background(), bindBackend, tx)
|
||||
if err != nil {
|
||||
t.Fatalf("error deploying library: %+v", err)
|
||||
}
|
||||
}
|
||||
c, err := solc_errors.NewC()
|
||||
if err != nil {
|
||||
t.Fatalf("err is %v", err)
|
||||
}
|
||||
doInput, err := c.PackFoo()
|
||||
if err != nil {
|
||||
t.Fatalf("pack function input err: %v\n", doInput)
|
||||
}
|
||||
|
||||
cABI, err := nested_libraries.C1MetaData.GetAbi()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting abi object: %v", err)
|
||||
}
|
||||
contractAddr := res.Addrs[solc_errors.CMetaData.Pattern]
|
||||
boundC := bind.NewBoundContract(contractAddr, *cABI, bindBackend, bindBackend, bindBackend)
|
||||
callOpts := &bind.CallOpts{
|
||||
From: common.Address{},
|
||||
Context: context.Background(),
|
||||
}
|
||||
callRes, err := boundC.CallRaw(callOpts, doInput)
|
||||
if err != nil {
|
||||
fmt.Println(callRes)
|
||||
t.Fatalf("err calling contract: %v", err)
|
||||
}
|
||||
_ = callRes
|
||||
}
|
||||
|
||||
// test that deploying a contract with library dependencies works,
|
||||
|
|
Loading…
Reference in New Issue