Description
Rationale
Why should this feature exist?
Currently, gas estimation (if not already set) is called automatically internally inside the func (c *BoundContract) createLegacyTx
or func (c *BoundContract) createDynamicTx
functions.
gasLimit := opts.GasLimit
if opts.GasLimit == 0 {
var err error
gasLimit, err = c.estimateGasLimit(opts, contract, input, gasPrice, nil, nil, value)
if err != nil {
return nil, err
}
}
This does not give the user the possibility to manually adjust this value. For example, a smart contract function can have a lot of conditionals (ifs), which can drastically change the gas needed if the transaction enters a block before or after some other transaction. Our solution usually was to multiply the base estimation by some arbitrary percentage value (170%) to ensure that the transaction execution will pass in any case.
What are the use-cases?
Sometimes, a user wants to manually adjust the returned gas estimation value or call it for multiple different possibilities. It would be nice if the structures generated by abigen provided that capability in an easy way.
Implementation
Do you have ideas regarding the implementation of this feature?
BoundContract
can implement public method EstimateGas
like this:
// EstimateGas estimates gas for method and params. GasPrice or GasFeeCap/GasTipCap should be set before calling this method
func (c *BoundContract) EstimateGas(opts *TransactOpts, method string, params ...interface{}) (uint64, error) {
input, err := c.abi.Pack(method, params...)
if err != nil {
return uint64(0), err
}
value := opts.Value
if value == nil {
value = new(big.Int)
}
contract := &c.address
if opts.GasPrice != nil {
return c.estimateGasLimit(opts, contract, input, opts.GasPrice, nil, nil, value)
}
return c.estimateGasLimit(opts, contract, input, nil, opts.GasTipCap, opts.GasFeeCap, value)
}
Generated contract code can expose BoundCountract
func (_BridgeContract *BridgeContract) GetContract() *bind.BoundContract {
return _BridgeContract.BridgeContractCaller.contract
}
After that, user can easily use estimation with something like this:
gasLimit, err := contract.GetContract().EstimateGas(opts, "submitSignedBatch", newSignedBatch)
if err != nil {
return nil, err
}
// gasLimit = gasLimit * 170
tmp := new(big.Int).SetUint64(gasLimit)
opts.GasLimit = new(big.Int).Div(tmp.Mul(tmp, big.NewInt(170)), big.NewInt(100)).Uint64()
return contract.SubmitSignedBatch(opts, newSignedBatch)
Are you willing to implement this feature?
yes