accounts/abi/bind/v2: improvement on the previous commit: remove all publicly-exported member methods from v2 BoundContract. Most of these are only needed to implement the contract interaction methods in accounts/abi/bind/v2/lib.go . Add 'Transact' method to the contract interaction API.

This commit is contained in:
Jared Wasinger 2025-02-03 20:00:45 -08:00
parent 028ef2f263
commit 6c70418313
6 changed files with 46 additions and 38 deletions

View File

@ -69,7 +69,7 @@ var (
// Instance creates a wrapper for a deployed contract instance at the given address. // Instance creates a wrapper for a deployed contract instance at the given address.
// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. // Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc.
func (c *{{.Type}}) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { func (c *{{.Type}}) Instance(backend bind.ContractBackend, addr common.Address) bind.BoundContract {
return bind.NewContractInstance(backend, addr, c.abi) return bind.NewContractInstance(backend, addr, c.abi)
} }

View File

@ -19,6 +19,7 @@ package bind
import ( import (
"context" "context"
"errors" "errors"
"github.com/ethereum/go-ethereum/event"
"math/big" "math/big"
"strings" "strings"
"sync" "sync"
@ -121,21 +122,34 @@ func (m *MetaData) ParseABI() (*abi.ABI, error) {
return m.parsedABI, nil return m.parsedABI, nil
} }
// BoundContract is the base wrapper object that reflects a contract on the // BoundContract represents a contract deployed on-chain. It does not export any methods, and is used in the low-level
// Ethereum network. It contains a collection of methods that are used by the // contract interaction API methods provided in the v2 package.
// higher level contract bindings to operate. type BoundContract interface {
type BoundContract struct { filterLogs(opts *FilterOpts, name string, query ...[]any) (chan types.Log, event.Subscription, error)
address common.Address // Deployment address of the contract on the Ethereum blockchain watchLogs(opts *WatchOpts, name string, query ...[]any) (chan types.Log, event.Subscription, error)
abi abi.ABI // Reflect based ABI to access the correct Ethereum methods rawCreationTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error)
backend ContractBackend call(opts *CallOpts, input []byte) ([]byte, error)
transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error)
addr() common.Address
} }
// NewBoundContract creates a low level contract interface through which calls // NewBoundContract creates a new BoundContract instance.
// and transactions may be made through. func NewBoundContract(backend ContractBackend, address common.Address, abi abi.ABI) BoundContract {
func NewBoundContract(backend ContractBackend, address common.Address, abi abi.ABI) *BoundContract { return NewBoundContractV1(address, abi, backend, backend, backend)
return &BoundContract{
address,
abi,
backend,
} }
func (c *BoundContractV1) filterLogs(opts *FilterOpts, name string, query ...[]any) (chan types.Log, event.Subscription, error) {
return c.FilterLogs(opts, name, query...)
}
func (c *BoundContractV1) watchLogs(opts *WatchOpts, name string, query ...[]any) (chan types.Log, event.Subscription, error) {
return c.WatchLogs(opts, name, query...)
}
func (c *BoundContractV1) rawCreationTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
return c.RawCreationTransact(opts, calldata)
}
func (c *BoundContractV1) addr() common.Address {
return c.address
} }

View File

@ -168,7 +168,7 @@ func (c *BoundContractV1) RawTransact(opts *TransactOpts, calldata []byte) (*typ
return c.transact(opts, &c.address, calldata) return c.transact(opts, &c.address, calldata)
} }
// RawTransact initiates a contract-creation transaction with the given raw calldata as the input. // RawCreationTransact initiates a contract-creation transaction with the given raw calldata as the input.
func (c *BoundContractV1) RawCreationTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) { func (c *BoundContractV1) RawCreationTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
return c.transact(opts, nil, calldata) return c.transact(opts, nil, calldata)
} }

View File

@ -47,7 +47,7 @@ type DeploymentResult struct {
} }
// DeployFn deploys a contract given a deployer and optional input. It returns // DeployFn deploys a contract given a deployer and optional input. It returns
// the address and a pending transaction, or an error if the deployment failed. // the address of the deployed contract and the deployment transaction, or an error if the deployment failed.
type DeployFn func(input, deployer []byte) (common.Address, *types.Transaction, error) type DeployFn func(input, deployer []byte) (common.Address, *types.Transaction, error)
// depTreeDeployer is responsible for taking a dependency, deploying-and-linking its components in the proper // depTreeDeployer is responsible for taking a dependency, deploying-and-linking its components in the proper

View File

@ -28,7 +28,7 @@ import (
) )
// TODO: remove this and use NewBoundContract directly // TODO: remove this and use NewBoundContract directly
func NewContractInstance(backend ContractBackend, addr common.Address, abi abi.ABI) *BoundContract { func NewContractInstance(backend ContractBackend, addr common.Address, abi abi.ABI) BoundContract {
return NewBoundContract(backend, addr, abi) return NewBoundContract(backend, addr, abi)
} }
@ -38,10 +38,9 @@ type ContractEvent interface {
} }
// FilterEvents returns an EventIterator instance for filtering historical events based on the event id and a block range. // FilterEvents returns an EventIterator instance for filtering historical events based on the event id and a block range.
func FilterEvents[Ev ContractEvent](c *BoundContract, opts *FilterOpts, unpack func(*types.Log) (*Ev, error), topics ...[]any) (*EventIterator[Ev], error) { func FilterEvents[Ev ContractEvent](c BoundContract, opts *FilterOpts, unpack func(*types.Log) (*Ev, error), topics ...[]any) (*EventIterator[Ev], error) {
var e Ev var e Ev
v1Instance := BoundContractV1{c.address, c.abi, c.backend, c.backend, c.backend} logs, sub, err := c.filterLogs(opts, e.ContractEventName(), topics...)
logs, sub, err := v1Instance.FilterLogs(opts, e.ContractEventName(), topics...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -52,10 +51,9 @@ func FilterEvents[Ev ContractEvent](c *BoundContract, opts *FilterOpts, unpack f
// contract to be intercepted, unpacked, and forwarded to sink. If // contract to be intercepted, unpacked, and forwarded to sink. If
// unpack returns an error, the returned subscription is closed with the // unpack returns an error, the returned subscription is closed with the
// error. // error.
func WatchEvents[Ev ContractEvent](c *BoundContract, opts *WatchOpts, unpack func(*types.Log) (*Ev, error), sink chan<- *Ev, topics ...[]any) (event.Subscription, error) { func WatchEvents[Ev ContractEvent](c BoundContract, opts *WatchOpts, unpack func(*types.Log) (*Ev, error), sink chan<- *Ev, topics ...[]any) (event.Subscription, error) {
var e Ev var e Ev
v1Instance := BoundContractV1{c.address, c.abi, c.backend, c.backend, c.backend} logs, sub, err := c.watchLogs(opts, e.ContractEventName(), topics...)
logs, sub, err := v1Instance.WatchLogs(opts, e.ContractEventName(), topics...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -162,10 +160,9 @@ func (it *EventIterator[T]) Close() error {
// //
// To call a function that doesn't return any output, pass nil as the unpack function. // To call a function that doesn't return any output, pass nil as the unpack function.
// This can be useful if you just want to check that the function doesn't revert. // This can be useful if you just want to check that the function doesn't revert.
func Call[T any](c *BoundContract, opts *CallOpts, packedInput []byte, unpack func([]byte) (T, error)) (T, error) { func Call[T any](c BoundContract, opts *CallOpts, packedInput []byte, unpack func([]byte) (T, error)) (T, error) {
var defaultResult T var defaultResult T
v1Instance := BoundContractV1{c.address, c.abi, c.backend, c.backend, c.backend} packedOutput, err := c.call(opts, packedInput)
packedOutput, err := v1Instance.CallRaw(opts, packedInput)
if err != nil { if err != nil {
return defaultResult, err return defaultResult, err
} }
@ -182,11 +179,15 @@ func Call[T any](c *BoundContract, opts *CallOpts, packedInput []byte, unpack fu
return res, err return res, err
} }
// Transact initiates a transaction with the given raw calldata as the input.
func Transact(c BoundContract, opt *TransactOpts, packedInput []byte) (*types.Transaction, error) {
addr := c.addr()
return c.transact(opt, &addr, packedInput)
}
// DeployContractRaw deploys a contract onto the Ethereum blockchain and binds the // DeployContractRaw deploys a contract onto the Ethereum blockchain and binds the
// deployment address with a Go wrapper. It expects its parameters to be abi-encoded // deployment address with a Go wrapper. It expects its parameters to be abi-encoded
// bytes. // bytes.
//
// TODO: remove address return? we can calculate it from the returned tx
func DeployContractRaw(opts *TransactOpts, bytecode []byte, backend ContractBackend, packedParams []byte) (common.Address, *types.Transaction, error) { func DeployContractRaw(opts *TransactOpts, bytecode []byte, backend ContractBackend, packedParams []byte) (common.Address, *types.Transaction, error) {
c := NewBoundContractV1(common.Address{}, abi.ABI{}, backend, backend, backend) c := NewBoundContractV1(common.Address{}, abi.ABI{}, backend, backend, backend)
tx, err := c.RawCreationTransact(opts, append(bytecode, packedParams...)) tx, err := c.RawCreationTransact(opts, append(bytecode, packedParams...))
@ -196,10 +197,3 @@ func DeployContractRaw(opts *TransactOpts, bytecode []byte, backend ContractBack
address := crypto.CreateAddress(opts.From, tx.Nonce()) address := crypto.CreateAddress(opts.From, tx.Nonce())
return address, tx, nil return address, tx, nil
} }
// RawTransact initiates a transaction with the given raw calldata as the input.
// It's usually used to initiate transactions for invoking **Fallback** function.
func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
v1Instance := BoundContractV1{c.address, c.abi, c.backend, c.backend, c.backend}
return v1Instance.RawTransact(opts, calldata)
}

View File

@ -245,7 +245,7 @@ func TestEvents(t *testing.T) {
defer sub2.Unsubscribe() defer sub2.Unsubscribe()
packedInput := c.PackEmitMulti() packedInput := c.PackEmitMulti()
tx, err := instance.RawTransact(txAuth, packedInput) tx, err := bind.Transact(instance, txAuth, packedInput)
if err != nil { if err != nil {
t.Fatalf("failed to send transaction: %v", err) t.Fatalf("failed to send transaction: %v", err)
} }