Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It would be helpful if abigen provided an easy way to manually call estimateGas #29798

Open
igorcrevar opened this issue May 17, 2024 · 1 comment

Comments

@igorcrevar
Copy link

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

@igorcrevar igorcrevar changed the title It would be nice if abigen can provide easy way to manually call estimateGas It would be helpful if abigen provided an easy way to manually call estimateGas May 20, 2024
@fjl
Copy link
Contributor

fjl commented Oct 29, 2024

ABIGEN v2 (#26782) will solve this. It's not done yet, but the new package will allow encoding calls and then you can submit them to EstimateGas yourself.

@fjl fjl removed the status:triage label Oct 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants