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