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