github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/accounts/abi/bind/base.go (about) 1 // Copyright 2016 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 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "sync/atomic" 24 25 "github.com/ethereumproject/go-ethereum/accounts/abi" 26 "github.com/ethereumproject/go-ethereum/common" 27 "github.com/ethereumproject/go-ethereum/core/types" 28 "github.com/ethereumproject/go-ethereum/crypto" 29 ) 30 31 // SignerFn is a signer function callback when a contract requires a method to 32 // sign the transaction before submission. 33 type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Transaction, error) 34 35 // CallOpts is the collection of options to fine tune a contract call request. 36 type CallOpts struct { 37 Pending bool // Whether to operate on the pending state or the last known one 38 } 39 40 // TransactOpts is the collection of authorization data required to create a 41 // valid Ethereum transaction. 42 type TransactOpts struct { 43 From common.Address // Ethereum account to send the transaction from 44 Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) 45 Signer SignerFn // Method to use for signing the transaction (mandatory) 46 47 Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds) 48 GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) 49 GasLimit *big.Int // Gas limit to set for the transaction execution (nil = estimate + 10%) 50 } 51 52 // BoundContract is the base wrapper object that reflects a contract on the 53 // Ethereum network. It contains a collection of methods that are used by the 54 // higher level contract bindings to operate. 55 type BoundContract struct { 56 address common.Address // Deployment address of the contract on the Ethereum blockchain 57 abi abi.ABI // Reflect based ABI to access the correct Ethereum methods 58 caller ContractCaller // Read interface to interact with the blockchain 59 transactor ContractTransactor // Write interface to interact with the blockchain 60 61 latestHasCode uint32 // Cached verification that the latest state contains code for this contract 62 pendingHasCode uint32 // Cached verification that the pending state contains code for this contract 63 } 64 65 // NewBoundContract creates a low level contract interface through which calls 66 // and transactions may be made through. 67 func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller, transactor ContractTransactor) *BoundContract { 68 return &BoundContract{ 69 address: address, 70 abi: abi, 71 caller: caller, 72 transactor: transactor, 73 } 74 } 75 76 // DeployContract deploys a contract onto the Ethereum blockchain and binds the 77 // deployment address with a Go wrapper. 78 func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) { 79 // Otherwise try to deploy the contract 80 c := NewBoundContract(common.Address{}, abi, backend, backend) 81 82 input, err := c.abi.Pack("", params...) 83 if err != nil { 84 return common.Address{}, nil, nil, err 85 } 86 tx, err := c.transact(opts, nil, append(bytecode, input...)) 87 if err != nil { 88 return common.Address{}, nil, nil, err 89 } 90 c.address = crypto.CreateAddress(opts.From, tx.Nonce()) 91 return c.address, tx, c, nil 92 } 93 94 // Call invokes the (constant) contract method with params as input values and 95 // sets the output to result. The result type might be a single field for simple 96 // returns, a slice of interfaces for anonymous returns and a struct for named 97 // returns. 98 func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, params ...interface{}) error { 99 // Don't crash on a lazy user 100 if opts == nil { 101 opts = new(CallOpts) 102 } 103 // Make sure we have a contract to operate on, and bail out otherwise 104 if (opts.Pending && atomic.LoadUint32(&c.pendingHasCode) == 0) || (!opts.Pending && atomic.LoadUint32(&c.latestHasCode) == 0) { 105 if code, err := c.caller.HasCode(c.address, opts.Pending); err != nil { 106 return err 107 } else if !code { 108 return ErrNoCode 109 } 110 if opts.Pending { 111 atomic.StoreUint32(&c.pendingHasCode, 1) 112 } else { 113 atomic.StoreUint32(&c.latestHasCode, 1) 114 } 115 } 116 // Pack the input, call and unpack the results 117 input, err := c.abi.Pack(method, params...) 118 if err != nil { 119 return err 120 } 121 output, err := c.caller.ContractCall(c.address, input, opts.Pending) 122 if err != nil { 123 return err 124 } 125 return c.abi.Unpack(result, method, output) 126 } 127 128 // Transact invokes the (paid) contract method with params as input values. 129 func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 130 // Otherwise pack up the parameters and invoke the contract 131 input, err := c.abi.Pack(method, params...) 132 if err != nil { 133 return nil, err 134 } 135 return c.transact(opts, &c.address, input) 136 } 137 138 // Transfer initiates a plain transaction to move funds to the contract, calling 139 // its default method if one is available. 140 func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error) { 141 return c.transact(opts, &c.address, nil) 142 } 143 144 // transact executes an actual transaction invocation, first deriving any missing 145 // authorization fields, and then scheduling the transaction for execution. 146 func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { 147 var err error 148 149 // Ensure a valid value field and resolve the account nonce 150 value := opts.Value 151 if value == nil { 152 value = new(big.Int) 153 } 154 nonce := uint64(0) 155 if opts.Nonce == nil { 156 nonce, err = c.transactor.PendingAccountNonce(opts.From) 157 if err != nil { 158 return nil, fmt.Errorf("failed to retrieve account nonce: %v", err) 159 } 160 } else { 161 nonce = opts.Nonce.Uint64() 162 } 163 // Figure out the gas allowance and gas price values 164 gasPrice := opts.GasPrice 165 if gasPrice == nil { 166 gasPrice, err = c.transactor.SuggestGasPrice() 167 if err != nil { 168 return nil, fmt.Errorf("failed to suggest gas price: %v", err) 169 } 170 } 171 gasLimit := opts.GasLimit 172 if gasLimit == nil { 173 // Gas estimation cannot succeed without code for method invocations 174 if contract != nil && atomic.LoadUint32(&c.pendingHasCode) == 0 { 175 if code, err := c.transactor.HasCode(c.address, true); err != nil { 176 return nil, err 177 } else if !code { 178 return nil, ErrNoCode 179 } 180 atomic.StoreUint32(&c.pendingHasCode, 1) 181 } 182 // If the contract surely has code (or code is not needed), estimate the transaction 183 gasLimit, err = c.transactor.EstimateGasLimit(opts.From, contract, value, input) 184 if err != nil { 185 return nil, fmt.Errorf("failed to exstimate gas needed: %v", err) 186 } 187 } 188 // Create the transaction, sign it and schedule it for execution 189 var rawTx *types.Transaction 190 if contract == nil { 191 rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input) 192 } else { 193 rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input) 194 } 195 if opts.Signer == nil { 196 return nil, errors.New("no signer to authorize the transaction with") 197 } 198 signedTx, err := opts.Signer(types.BasicSigner{}, opts.From, rawTx) 199 if err != nil { 200 return nil, err 201 } 202 if err := c.transactor.SendTransaction(signedTx); err != nil { 203 return nil, err 204 } 205 return signedTx, nil 206 }