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