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 }