github.com/ethereum/go-ethereum@v1.16.1/accounts/abi/bind/v2/lib.go (about)

     1  // Copyright 2024 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package bind implements utilities for interacting with Solidity contracts.
    18  // This is the 'runtime' for contract bindings generated with the abigen command.
    19  // It includes methods for calling/transacting, filtering chain history for
    20  // specific custom Solidity event types, and creating event subscriptions to monitor the
    21  // chain for event occurrences.
    22  //
    23  // Two methods for contract deployment are provided:
    24  //   - [DeployContract] is intended to be used for deployment of a single contract.
    25  //   - [LinkAndDeploy] is intended for the deployment of multiple
    26  //     contracts, potentially with library dependencies.
    27  package bind
    28  
    29  import (
    30  	"errors"
    31  
    32  	"github.com/ethereum/go-ethereum"
    33  	"github.com/ethereum/go-ethereum/accounts/abi"
    34  	"github.com/ethereum/go-ethereum/common"
    35  	"github.com/ethereum/go-ethereum/core/types"
    36  	"github.com/ethereum/go-ethereum/crypto"
    37  	"github.com/ethereum/go-ethereum/event"
    38  )
    39  
    40  // ContractEvent is a type constraint for ABI event types.
    41  type ContractEvent interface {
    42  	ContractEventName() string
    43  }
    44  
    45  // FilterEvents filters a historical block range for instances of emission of a
    46  // specific event type from a specified contract.  It returns an error if the
    47  // provided filter opts are invalid or the backend is closed.
    48  //
    49  // FilterEvents is intended to be used with contract event unpack methods in
    50  // bindings generated with the abigen --v2 flag. It should be
    51  // preferred over BoundContract.FilterLogs.
    52  func FilterEvents[Ev ContractEvent](c *BoundContract, opts *FilterOpts, unpack func(*types.Log) (*Ev, error), topics ...[]any) (*EventIterator[Ev], error) {
    53  	var e Ev
    54  	logs, sub, err := c.FilterLogs(opts, e.ContractEventName(), topics...)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	return &EventIterator[Ev]{unpack: unpack, logs: logs, sub: sub}, nil
    59  }
    60  
    61  // WatchEvents creates an event subscription to notify when logs of the
    62  // specified event type are emitted from the given contract. Received logs are
    63  // unpacked and forwarded to sink.  If topics are specified, only events are
    64  // forwarded which match the topics.
    65  //
    66  // WatchEvents returns a subscription or an error if the provided WatchOpts are
    67  // invalid or the backend is closed.
    68  //
    69  // WatchEvents is intended to be used with contract event unpack methods in
    70  // bindings generated with the abigen --v2 flag. It should be
    71  // preferred over BoundContract.WatchLogs.
    72  func WatchEvents[Ev ContractEvent](c *BoundContract, opts *WatchOpts, unpack func(*types.Log) (*Ev, error), sink chan<- *Ev, topics ...[]any) (event.Subscription, error) {
    73  	var e Ev
    74  	logs, sub, err := c.WatchLogs(opts, e.ContractEventName(), topics...)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	return event.NewSubscription(func(quit <-chan struct{}) error {
    79  		defer sub.Unsubscribe()
    80  		for {
    81  			select {
    82  			case log := <-logs:
    83  				// New log arrived, parse the event and forward to the user
    84  				ev, err := unpack(&log)
    85  				if err != nil {
    86  					return err
    87  				}
    88  
    89  				select {
    90  				case sink <- ev:
    91  				case err := <-sub.Err():
    92  					return err
    93  				case <-quit:
    94  					return nil
    95  				}
    96  			case err := <-sub.Err():
    97  				return err
    98  			case <-quit:
    99  				return nil
   100  			}
   101  		}
   102  	}), nil
   103  }
   104  
   105  // EventIterator is an object for iterating over the results of a event log
   106  // filter call.
   107  type EventIterator[T any] struct {
   108  	current *T
   109  	unpack  func(*types.Log) (*T, error)
   110  	logs    <-chan types.Log
   111  	sub     ethereum.Subscription
   112  	fail    error // error to hold reason for iteration failure
   113  	closed  bool  // true if Close has been called
   114  }
   115  
   116  // Value returns the current value of the iterator, or nil if there isn't one.
   117  func (it *EventIterator[T]) Value() *T {
   118  	return it.current
   119  }
   120  
   121  // Next advances the iterator to the subsequent event (if there is one),
   122  // returning true if the iterator advanced.
   123  //
   124  // If the attempt to convert the raw log object to an instance of T using the
   125  // unpack function provided via FilterEvents returns an error: that error is
   126  // returned and subsequent calls to Next will not advance the iterator.
   127  func (it *EventIterator[T]) Next() (advanced bool) {
   128  	// If the iterator failed with an error, don't proceed
   129  	if it.fail != nil || it.closed {
   130  		return false
   131  	}
   132  	// if the iterator is still active, block until a log is received or the
   133  	// underlying subscription terminates.
   134  	select {
   135  	case log := <-it.logs:
   136  		res, err := it.unpack(&log)
   137  		if err != nil {
   138  			it.fail = err
   139  			return false
   140  		}
   141  		it.current = res
   142  		return true
   143  	case <-it.sub.Err():
   144  		// regardless of how the subscription ends, still be able to iterate
   145  		// over any unread logs.
   146  		select {
   147  		case log := <-it.logs:
   148  			res, err := it.unpack(&log)
   149  			if err != nil {
   150  				it.fail = err
   151  				return false
   152  			}
   153  			it.current = res
   154  			return true
   155  		default:
   156  			return false
   157  		}
   158  	}
   159  }
   160  
   161  // Error returns an error if iteration has failed.
   162  func (it *EventIterator[T]) Error() error {
   163  	return it.fail
   164  }
   165  
   166  // Close releases any pending underlying resources.  Any subsequent calls to
   167  // Next will not advance the iterator, but the current value remains accessible.
   168  func (it *EventIterator[T]) Close() error {
   169  	it.closed = true
   170  	it.sub.Unsubscribe()
   171  	return nil
   172  }
   173  
   174  // Call performs an eth_call to a contract with optional call data.
   175  //
   176  // To call a function that doesn't return any output, pass nil as the unpack
   177  // function. This can be useful if you just want to check that the function
   178  // doesn't revert.
   179  //
   180  // Call is intended to be used with contract method unpack methods in
   181  // bindings generated with the abigen --v2 flag. It should be
   182  // preferred over BoundContract.Call
   183  func Call[T any](c *BoundContract, opts *CallOpts, calldata []byte, unpack func([]byte) (T, error)) (T, error) {
   184  	var defaultResult T
   185  	packedOutput, err := c.CallRaw(opts, calldata)
   186  	if err != nil {
   187  		return defaultResult, err
   188  	}
   189  	if unpack == nil {
   190  		if len(packedOutput) > 0 {
   191  			return defaultResult, errors.New("contract returned data, but no unpack function was given")
   192  		}
   193  		return defaultResult, nil
   194  	}
   195  	res, err := unpack(packedOutput)
   196  	if err != nil {
   197  		return defaultResult, err
   198  	}
   199  	return res, err
   200  }
   201  
   202  // Transact creates and submits a transaction to a contract with optional input
   203  // data.
   204  //
   205  // Transact is identical to BoundContract.RawTransact, and is provided as a
   206  // package-level method so that interactions with contracts whose bindings were
   207  // generated with the abigen --v2 flag are consistent (they do not require
   208  // calling methods on the BoundContract instance).
   209  func Transact(c *BoundContract, opt *TransactOpts, data []byte) (*types.Transaction, error) {
   210  	return c.RawTransact(opt, data)
   211  }
   212  
   213  // DeployContract creates and submits a deployment transaction based on the
   214  // deployer bytecode and optional ABI-encoded constructor input.  It returns
   215  // the address and creation transaction of the pending contract, or an error
   216  // if the creation failed.
   217  //
   218  // To initiate the deployment of multiple contracts with one method call, see the
   219  // [LinkAndDeploy] method.
   220  func DeployContract(opts *TransactOpts, bytecode []byte, backend ContractBackend, constructorInput []byte) (common.Address, *types.Transaction, error) {
   221  	c := NewBoundContract(common.Address{}, abi.ABI{}, backend, backend, backend)
   222  
   223  	tx, err := c.RawCreationTransact(opts, append(bytecode, constructorInput...))
   224  	if err != nil {
   225  		return common.Address{}, nil, err
   226  	}
   227  	return crypto.CreateAddress(opts.From, tx.Nonce()), tx, nil
   228  }
   229  
   230  // DefaultDeployer returns a DeployFn that signs and submits creation transactions
   231  // using the given signer.
   232  //
   233  // The DeployFn returned by DefaultDeployer should be used by LinkAndDeploy in
   234  // almost all cases, unless a custom DeployFn implementation is needed.
   235  func DefaultDeployer(opts *TransactOpts, backend ContractBackend) DeployFn {
   236  	return func(input []byte, deployer []byte) (common.Address, *types.Transaction, error) {
   237  		addr, tx, err := DeployContract(opts, deployer, backend, input)
   238  		if err != nil {
   239  			return common.Address{}, nil, err
   240  		}
   241  		return addr, tx, nil
   242  	}
   243  }