github.com/ava-labs/subnet-evm@v0.6.4/accounts/abi/bind/base.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2015 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package bind 28 29 import ( 30 "context" 31 "errors" 32 "fmt" 33 "math/big" 34 "strings" 35 "sync" 36 37 "github.com/ava-labs/subnet-evm/accounts/abi" 38 "github.com/ava-labs/subnet-evm/core/types" 39 "github.com/ava-labs/subnet-evm/interfaces" 40 "github.com/ethereum/go-ethereum/common" 41 "github.com/ethereum/go-ethereum/crypto" 42 "github.com/ethereum/go-ethereum/event" 43 ) 44 45 const basefeeWiggleMultiplier = 2 46 47 var ( 48 errNoEventSignature = errors.New("no event signature") 49 errEventSignatureMismatch = errors.New("event signature mismatch") 50 ) 51 52 // SignerFn is a signer function callback when a contract requires a method to 53 // sign the transaction before submission. 54 type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error) 55 56 // CallOpts is the collection of options to fine tune a contract call request. 57 type CallOpts struct { 58 Accepted bool // Whether to operate on the accepted state or the last known one 59 From common.Address // Optional the sender address, otherwise the first account is used 60 BlockNumber *big.Int // Optional the block number on which the call should be performed 61 Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) 62 } 63 64 // TransactOpts is the collection of authorization data required to create a 65 // valid Ethereum transaction. 66 type TransactOpts struct { 67 From common.Address // Ethereum account to send the transaction from 68 Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) 69 Signer SignerFn // Method to use for signing the transaction (mandatory) 70 71 Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds) 72 GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) 73 GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle) 74 GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle) 75 GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) 76 77 Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) 78 79 NoSend bool // Do all transact steps but do not send the transaction 80 } 81 82 // FilterOpts is the collection of options to fine tune filtering for events 83 // within a bound contract. 84 type FilterOpts struct { 85 Start uint64 // Start of the queried range 86 End *uint64 // End of the range (nil = latest) 87 88 Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) 89 } 90 91 // WatchOpts is the collection of options to fine tune subscribing for events 92 // within a bound contract. 93 type WatchOpts struct { 94 Start *uint64 // Start of the queried range (nil = latest) 95 Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) 96 } 97 98 // MetaData collects all metadata for a bound contract. 99 type MetaData struct { 100 mu sync.Mutex 101 Sigs map[string]string 102 Bin string 103 ABI string 104 ab *abi.ABI 105 } 106 107 func (m *MetaData) GetAbi() (*abi.ABI, error) { 108 m.mu.Lock() 109 defer m.mu.Unlock() 110 if m.ab != nil { 111 return m.ab, nil 112 } 113 if parsed, err := abi.JSON(strings.NewReader(m.ABI)); err != nil { 114 return nil, err 115 } else { 116 m.ab = &parsed 117 } 118 return m.ab, nil 119 } 120 121 // BoundContract is the base wrapper object that reflects a contract on the 122 // Ethereum network. It contains a collection of methods that are used by the 123 // higher level contract bindings to operate. 124 type BoundContract struct { 125 address common.Address // Deployment address of the contract on the Ethereum blockchain 126 abi abi.ABI // Reflect based ABI to access the correct Ethereum methods 127 caller ContractCaller // Read interface to interact with the blockchain 128 transactor ContractTransactor // Write interface to interact with the blockchain 129 filterer ContractFilterer // Event filtering to interact with the blockchain 130 } 131 132 // NewBoundContract creates a low level contract interface through which calls 133 // and transactions may be made through. 134 func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller, transactor ContractTransactor, filterer ContractFilterer) *BoundContract { 135 return &BoundContract{ 136 address: address, 137 abi: abi, 138 caller: caller, 139 transactor: transactor, 140 filterer: filterer, 141 } 142 } 143 144 // DeployContract deploys a contract onto the Ethereum blockchain and binds the 145 // deployment address with a Go wrapper. 146 func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) { 147 // Otherwise try to deploy the contract 148 c := NewBoundContract(common.Address{}, abi, backend, backend, backend) 149 150 input, err := c.abi.Pack("", params...) 151 if err != nil { 152 return common.Address{}, nil, nil, err 153 } 154 tx, err := c.transact(opts, nil, append(bytecode, input...)) 155 if err != nil { 156 return common.Address{}, nil, nil, err 157 } 158 c.address = crypto.CreateAddress(opts.From, tx.Nonce()) 159 return c.address, tx, c, nil 160 } 161 162 // Call invokes the (constant) contract method with params as input values and 163 // sets the output to result. The result type might be a single field for simple 164 // returns, a slice of interfaces for anonymous returns and a struct for named 165 // returns. 166 func (c *BoundContract) Call(opts *CallOpts, results *[]interface{}, method string, params ...interface{}) error { 167 // Don't crash on a lazy user 168 if opts == nil { 169 opts = new(CallOpts) 170 } 171 if results == nil { 172 results = new([]interface{}) 173 } 174 // Pack the input, call and unpack the results 175 input, err := c.abi.Pack(method, params...) 176 if err != nil { 177 return err 178 } 179 var ( 180 msg = interfaces.CallMsg{From: opts.From, To: &c.address, Data: input} 181 ctx = ensureContext(opts.Context) 182 code []byte 183 output []byte 184 ) 185 if opts.Accepted { 186 pb, ok := c.caller.(AcceptedContractCaller) 187 if !ok { 188 return ErrNoAcceptedState 189 } 190 output, err = pb.AcceptedCallContract(ctx, msg) 191 if err != nil { 192 return err 193 } 194 if len(output) == 0 { 195 // Make sure we have a contract to operate on, and bail out otherwise. 196 if code, err = pb.AcceptedCodeAt(ctx, c.address); err != nil { 197 return err 198 } else if len(code) == 0 { 199 return ErrNoCode 200 } 201 } 202 } else { 203 output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber) 204 if err != nil { 205 return err 206 } 207 if len(output) == 0 { 208 // Make sure we have a contract to operate on, and bail out otherwise. 209 if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil { 210 return err 211 } else if len(code) == 0 { 212 return ErrNoCode 213 } 214 } 215 } 216 217 if len(*results) == 0 { 218 res, err := c.abi.Unpack(method, output) 219 *results = res 220 return err 221 } 222 res := *results 223 return c.abi.UnpackIntoInterface(res[0], method, output) 224 } 225 226 // Transact invokes the (paid) contract method with params as input values. 227 func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 228 // Otherwise pack up the parameters and invoke the contract 229 input, err := c.abi.Pack(method, params...) 230 if err != nil { 231 return nil, err 232 } 233 // todo(rjl493456442) check the method is payable or not, 234 // reject invalid transaction at the first place 235 return c.transact(opts, &c.address, input) 236 } 237 238 // RawTransact initiates a transaction with the given raw calldata as the input. 239 // It's usually used to initiate transactions for invoking **Fallback** function. 240 func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) { 241 // todo(rjl493456442) check the method is payable or not, 242 // reject invalid transaction at the first place 243 return c.transact(opts, &c.address, calldata) 244 } 245 246 // Transfer initiates a plain transaction to move funds to the contract, calling 247 // its default method if one is available. 248 func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error) { 249 // todo(rjl493456442) check the payable fallback or receive is defined 250 // or not, reject invalid transaction at the first place 251 return c.transact(opts, &c.address, nil) 252 } 253 254 func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Address, input []byte, head *types.Header) (*types.Transaction, error) { 255 // Normalize value 256 value := opts.Value 257 if value == nil { 258 value = new(big.Int) 259 } 260 // Estimate TipCap 261 gasTipCap := opts.GasTipCap 262 if gasTipCap == nil { 263 tip, err := c.transactor.SuggestGasTipCap(ensureContext(opts.Context)) 264 if err != nil { 265 return nil, err 266 } 267 gasTipCap = tip 268 } 269 // Estimate FeeCap 270 gasFeeCap := opts.GasFeeCap 271 if gasFeeCap == nil { 272 gasFeeCap = new(big.Int).Add( 273 gasTipCap, 274 new(big.Int).Mul(head.BaseFee, big.NewInt(basefeeWiggleMultiplier)), 275 ) 276 } 277 if gasFeeCap.Cmp(gasTipCap) < 0 { 278 return nil, fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", gasFeeCap, gasTipCap) 279 } 280 // Estimate GasLimit 281 gasLimit := opts.GasLimit 282 if opts.GasLimit == 0 { 283 var err error 284 gasLimit, err = c.estimateGasLimit(opts, contract, input, nil, gasTipCap, gasFeeCap, value) 285 if err != nil { 286 return nil, err 287 } 288 } 289 // create the transaction 290 nonce, err := c.getNonce(opts) 291 if err != nil { 292 return nil, err 293 } 294 baseTx := &types.DynamicFeeTx{ 295 To: contract, 296 Nonce: nonce, 297 GasFeeCap: gasFeeCap, 298 GasTipCap: gasTipCap, 299 Gas: gasLimit, 300 Value: value, 301 Data: input, 302 } 303 return types.NewTx(baseTx), nil 304 } 305 306 func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { 307 if opts.GasFeeCap != nil || opts.GasTipCap != nil { 308 return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") 309 } 310 // Normalize value 311 value := opts.Value 312 if value == nil { 313 value = new(big.Int) 314 } 315 // Estimate GasPrice 316 gasPrice := opts.GasPrice 317 if gasPrice == nil { 318 price, err := c.transactor.SuggestGasPrice(ensureContext(opts.Context)) 319 if err != nil { 320 return nil, err 321 } 322 gasPrice = price 323 } 324 // Estimate GasLimit 325 gasLimit := opts.GasLimit 326 if opts.GasLimit == 0 { 327 var err error 328 gasLimit, err = c.estimateGasLimit(opts, contract, input, gasPrice, nil, nil, value) 329 if err != nil { 330 return nil, err 331 } 332 } 333 // create the transaction 334 nonce, err := c.getNonce(opts) 335 if err != nil { 336 return nil, err 337 } 338 baseTx := &types.LegacyTx{ 339 To: contract, 340 Nonce: nonce, 341 GasPrice: gasPrice, 342 Gas: gasLimit, 343 Value: value, 344 Data: input, 345 } 346 return types.NewTx(baseTx), nil 347 } 348 349 func (c *BoundContract) estimateGasLimit(opts *TransactOpts, contract *common.Address, input []byte, gasPrice, gasTipCap, gasFeeCap, value *big.Int) (uint64, error) { 350 if contract != nil { 351 // Gas estimation cannot succeed without code for method invocations. 352 if code, err := c.transactor.AcceptedCodeAt(ensureContext(opts.Context), c.address); err != nil { 353 return 0, err 354 } else if len(code) == 0 { 355 return 0, ErrNoCode 356 } 357 } 358 msg := interfaces.CallMsg{ 359 From: opts.From, 360 To: contract, 361 GasPrice: gasPrice, 362 GasTipCap: gasTipCap, 363 GasFeeCap: gasFeeCap, 364 Value: value, 365 Data: input, 366 } 367 return c.transactor.EstimateGas(ensureContext(opts.Context), msg) 368 } 369 370 func (c *BoundContract) getNonce(opts *TransactOpts) (uint64, error) { 371 if opts.Nonce == nil { 372 return c.transactor.AcceptedNonceAt(ensureContext(opts.Context), opts.From) 373 } else { 374 return opts.Nonce.Uint64(), nil 375 } 376 } 377 378 // transact executes an actual transaction invocation, first deriving any missing 379 // authorization fields, and then scheduling the transaction for execution. 380 func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { 381 if opts.GasPrice != nil && (opts.GasFeeCap != nil || opts.GasTipCap != nil) { 382 return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 383 } 384 // Create the transaction 385 var ( 386 rawTx *types.Transaction 387 err error 388 ) 389 if opts.GasPrice != nil { 390 rawTx, err = c.createLegacyTx(opts, contract, input) 391 } else if opts.GasFeeCap != nil && opts.GasTipCap != nil { 392 rawTx, err = c.createDynamicTx(opts, contract, input, nil) 393 } else { 394 // Only query for basefee if gasPrice not specified 395 if head, errHead := c.transactor.HeaderByNumber(ensureContext(opts.Context), nil); errHead != nil { 396 return nil, errHead 397 } else if head.BaseFee != nil { 398 rawTx, err = c.createDynamicTx(opts, contract, input, head) 399 } else { 400 // Chain is not London ready -> use legacy transaction 401 rawTx, err = c.createLegacyTx(opts, contract, input) 402 } 403 } 404 if err != nil { 405 return nil, err 406 } 407 // Sign the transaction and schedule it for execution 408 if opts.Signer == nil { 409 return nil, errors.New("no signer to authorize the transaction with") 410 } 411 signedTx, err := opts.Signer(opts.From, rawTx) 412 if err != nil { 413 return nil, err 414 } 415 if opts.NoSend { 416 return signedTx, nil 417 } 418 if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil { 419 return nil, err 420 } 421 return signedTx, nil 422 } 423 424 // FilterLogs filters contract logs for past blocks, returning the necessary 425 // channels to construct a strongly typed bound iterator on top of them. 426 func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { 427 // Don't crash on a lazy user 428 if opts == nil { 429 opts = new(FilterOpts) 430 } 431 // Append the event selector to the query parameters and construct the topic set 432 query = append([][]interface{}{{c.abi.Events[name].ID}}, query...) 433 434 topics, err := abi.MakeTopics(query...) 435 if err != nil { 436 return nil, nil, err 437 } 438 // Start the background filtering 439 logs := make(chan types.Log, 128) 440 441 config := interfaces.FilterQuery{ 442 Addresses: []common.Address{c.address}, 443 Topics: topics, 444 FromBlock: new(big.Int).SetUint64(opts.Start), 445 } 446 if opts.End != nil { 447 config.ToBlock = new(big.Int).SetUint64(*opts.End) 448 } 449 /* TODO(karalabe): Replace the rest of the method below with this when supported 450 sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs) 451 */ 452 buff, err := c.filterer.FilterLogs(ensureContext(opts.Context), config) 453 if err != nil { 454 return nil, nil, err 455 } 456 sub, err := event.NewSubscription(func(quit <-chan struct{}) error { 457 for _, log := range buff { 458 select { 459 case logs <- log: 460 case <-quit: 461 return nil 462 } 463 } 464 return nil 465 }), nil 466 467 if err != nil { 468 return nil, nil, err 469 } 470 return logs, sub, nil 471 } 472 473 // WatchLogs filters subscribes to contract logs for future blocks, returning a 474 // subscription object that can be used to tear down the watcher. 475 func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { 476 // Don't crash on a lazy user 477 if opts == nil { 478 opts = new(WatchOpts) 479 } 480 // Append the event selector to the query parameters and construct the topic set 481 query = append([][]interface{}{{c.abi.Events[name].ID}}, query...) 482 483 topics, err := abi.MakeTopics(query...) 484 if err != nil { 485 return nil, nil, err 486 } 487 // Start the background filtering 488 logs := make(chan types.Log, 128) 489 490 config := interfaces.FilterQuery{ 491 Addresses: []common.Address{c.address}, 492 Topics: topics, 493 } 494 if opts.Start != nil { 495 config.FromBlock = new(big.Int).SetUint64(*opts.Start) 496 } 497 sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs) 498 if err != nil { 499 return nil, nil, err 500 } 501 return logs, sub, nil 502 } 503 504 // UnpackLog unpacks a retrieved log into the provided output structure. 505 func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { 506 // Anonymous events are not supported. 507 if len(log.Topics) == 0 { 508 return errNoEventSignature 509 } 510 if log.Topics[0] != c.abi.Events[event].ID { 511 return errEventSignatureMismatch 512 } 513 if len(log.Data) > 0 { 514 if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { 515 return err 516 } 517 } 518 var indexed abi.Arguments 519 for _, arg := range c.abi.Events[event].Inputs { 520 if arg.Indexed { 521 indexed = append(indexed, arg) 522 } 523 } 524 return abi.ParseTopics(out, indexed, log.Topics[1:]) 525 } 526 527 // UnpackLogIntoMap unpacks a retrieved log into the provided map. 528 func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { 529 // Anonymous events are not supported. 530 if len(log.Topics) == 0 { 531 return errNoEventSignature 532 } 533 if log.Topics[0] != c.abi.Events[event].ID { 534 return errEventSignatureMismatch 535 } 536 if len(log.Data) > 0 { 537 if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { 538 return err 539 } 540 } 541 var indexed abi.Arguments 542 for _, arg := range c.abi.Events[event].Inputs { 543 if arg.Indexed { 544 indexed = append(indexed, arg) 545 } 546 } 547 return abi.ParseTopicsIntoMap(out, indexed, log.Topics[1:]) 548 } 549 550 // ensureContext is a helper method to ensure a context is not nil, even if the 551 // user specified it as such. 552 func ensureContext(ctx context.Context) context.Context { 553 if ctx == nil { 554 return context.Background() 555 } 556 return ctx 557 }