From bde7a9fbf9dc9b01d3f0058c79d2f54e598e3ce0 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 4 Apr 2023 11:41:11 -0700 Subject: [PATCH] fix(smart-contracts): add increased gas limit estimation (#3371) --- libs/smart-contracts/src/contracts/claim.ts | 31 +++++------ .../src/contracts/collateral-bridge.ts | 49 ++++++++++++++--- .../src/contracts/multisig-control.ts | 53 +++++++++++++++---- .../src/contracts/staking-bridge.ts | 39 ++++++++++---- .../src/contracts/token-faucetable.ts | 13 +++-- .../src/contracts/token-vesting.ts | 31 ++++++++--- libs/smart-contracts/src/contracts/token.ts | 9 ++-- .../src/utils/calc-gas-buffer.ts | 5 ++ libs/smart-contracts/src/utils/index.ts | 1 + 9 files changed, 176 insertions(+), 55 deletions(-) create mode 100644 libs/smart-contracts/src/utils/calc-gas-buffer.ts diff --git a/libs/smart-contracts/src/contracts/claim.ts b/libs/smart-contracts/src/contracts/claim.ts index e81cc6a04..8dd7c7606 100644 --- a/libs/smart-contracts/src/contracts/claim.ts +++ b/libs/smart-contracts/src/contracts/claim.ts @@ -1,6 +1,7 @@ import { ethers } from 'ethers'; import { hexlify } from 'ethers/lib/utils'; import abi from '../abis/claim_abi.json'; +import { calcGasBuffer } from '../utils'; export const UNSPENT_CODE = '0x0000000000000000000000000000000000000000'; export const SPENT_CODE = '0x0000000000000000000000000000000000000001'; @@ -42,7 +43,7 @@ export class Claim { * was performed and mined beforehand * @return {Promise} */ - public claim({ + public async claim({ amount, tranche, expiry, @@ -61,20 +62,20 @@ export class Claim { r: string; s: string; }): Promise { - return this.contract[ - target != null ? 'claim_targeted' : 'claim_untargeted' - ]( - ...[ - { r, s, v }, - { - amount, - tranche, - expiry, - }, - hexlify(country), - target, - ].filter(Boolean) - ); + const method = target != null ? 'claim_targeted' : 'claim_untargeted'; + const args = [ + { r, s, v }, + { + amount, + tranche, + expiry, + }, + hexlify(country), + target, + ].filter(Boolean); + const res = await this.contract.estimateGas[method](...args); + const gasLimit = calcGasBuffer(res); + return this.contract[method](...args, { gasLimit }); } /** diff --git a/libs/smart-contracts/src/contracts/collateral-bridge.ts b/libs/smart-contracts/src/contracts/collateral-bridge.ts index ae3d4a72b..dac18dd69 100644 --- a/libs/smart-contracts/src/contracts/collateral-bridge.ts +++ b/libs/smart-contracts/src/contracts/collateral-bridge.ts @@ -1,6 +1,7 @@ import type { BigNumber } from 'ethers'; import { ethers } from 'ethers'; import abi from '../abis/erc20_bridge_abi.json'; +import { calcGasBuffer } from '../utils'; export class CollateralBridge { public contract: ethers.Contract; @@ -13,8 +14,20 @@ export class CollateralBridge { this.contract = new ethers.Contract(address, abi, signerOrProvider); } - deposit_asset(assetSource: string, amount: string, vegaPublicKey: string) { - return this.contract.deposit_asset(assetSource, amount, vegaPublicKey); + async deposit_asset( + assetSource: string, + amount: string, + vegaPublicKey: string + ) { + const res = await this.contract.estimateGas.deposit_asset( + assetSource, + amount, + vegaPublicKey + ); + const gasLimit = calcGasBuffer(res); + return this.contract.deposit_asset(assetSource, amount, vegaPublicKey, { + gasLimit, + }); } get_asset_source(vegaAssetId: string) { return this.contract.get_asset_source(vegaAssetId); @@ -37,7 +50,7 @@ export class CollateralBridge { default_withdraw_delay() { return this.contract.default_withdraw_delay(); } - list_asset( + async list_asset( address: string, vegaAssetId: string, lifetimeLimit: string, @@ -45,7 +58,7 @@ export class CollateralBridge { nonce: string, signatures: string ) { - return this.contract.list_asset( + const res = await this.contract.estimateGas.list_asset( address, vegaAssetId, lifetimeLimit, @@ -53,8 +66,20 @@ export class CollateralBridge { nonce, signatures ); + const gasLimit = calcGasBuffer(res); + return this.contract.list_asset( + address, + vegaAssetId, + lifetimeLimit, + withdraw_threshold, + nonce, + signatures, + { + gasLimit, + } + ); } - withdraw_asset( + async withdraw_asset( assetSource: string, amount: string, target: string, @@ -62,7 +87,7 @@ export class CollateralBridge { nonce: string, signatures: string ) { - return this.contract.withdraw_asset( + const res = await this.contract.estimateGas.withdraw_asset( assetSource, amount, target, @@ -70,6 +95,18 @@ export class CollateralBridge { nonce, signatures ); + const gasLimit = calcGasBuffer(res); + return this.contract.withdraw_asset( + assetSource, + amount, + target, + creation, + nonce, + signatures, + { + gasLimit, + } + ); } is_stopped() { diff --git a/libs/smart-contracts/src/contracts/multisig-control.ts b/libs/smart-contracts/src/contracts/multisig-control.ts index 6826378eb..ccb3333bd 100644 --- a/libs/smart-contracts/src/contracts/multisig-control.ts +++ b/libs/smart-contracts/src/contracts/multisig-control.ts @@ -1,5 +1,6 @@ import { ethers } from 'ethers'; import abi from '../abis/multisig_abi.json'; +import { calcGasBuffer } from '../utils'; export class MultisigControl { public contract: ethers.Contract; @@ -13,12 +14,20 @@ export class MultisigControl { this.address = address; } - add_signer(newSigner: string, nonce: string, signatures: string) { - return this.contract.add_signer(newSigner, nonce, signatures); + async add_signer(newSigner: string, nonce: string, signatures: string) { + const res = await this.contract.estimateGas.add_signer( + newSigner, + nonce, + signatures + ); + const gasLimit = calcGasBuffer(res); + return this.contract.add_signer(newSigner, nonce, signatures, { gasLimit }); } - burn_nonce(nonce: string, signatures: string) { - return this.contract.burn_nonce(nonce, signatures); + async burn_nonce(nonce: string, signatures: string) { + const res = await this.contract.estimateGas.burn_nonce(nonce, signatures); + const gasLimit = calcGasBuffer(res); + return this.contract.burn_nonce(nonce, signatures, { gasLimit }); } get_current_threshold() { @@ -37,19 +46,43 @@ export class MultisigControl { return this.contract.is_valid_signer(signerAddress); } - remove_signer(oldSigner: string, nonce: string, signatures: string) { - return this.contract.remove_signer(oldSigner, nonce, signatures); + async remove_signer(oldSigner: string, nonce: string, signatures: string) { + const res = await this.contract.estimateGas.remove_signer( + oldSigner, + nonce, + signatures + ); + const gasLimit = calcGasBuffer(res); + return this.contract.remove_signer(oldSigner, nonce, signatures, { + gasLimit, + }); } - set_threshold(newThreshold: string, nonce: string, signatures: string) { - return this.contract.set_threshold(newThreshold, nonce, signatures); + async set_threshold(newThreshold: string, nonce: string, signatures: string) { + const res = await this.contract.estimateGas.set_threshold( + newThreshold, + nonce, + signatures + ); + const gasLimit = calcGasBuffer(res); + return this.contract.set_threshold(newThreshold, nonce, signatures, { + gasLimit, + }); } signers(address: string) { return this.contract.signers(address); } - verify_signatures(nonce: string, message: string, signatures: string) { - return this.contract.verify_signatures(nonce, message, signatures); + async verify_signatures(nonce: string, message: string, signatures: string) { + const res = await this.contract.estimateGas.verify_signatures( + nonce, + message, + signatures + ); + const gasLimit = calcGasBuffer(res); + return this.contract.verify_signatures(nonce, message, signatures, { + gasLimit, + }); } } diff --git a/libs/smart-contracts/src/contracts/staking-bridge.ts b/libs/smart-contracts/src/contracts/staking-bridge.ts index 86da676f8..cfd190768 100644 --- a/libs/smart-contracts/src/contracts/staking-bridge.ts +++ b/libs/smart-contracts/src/contracts/staking-bridge.ts @@ -1,6 +1,6 @@ import { ethers } from 'ethers'; import abi from '../abis/staking_abi.json'; -import { prepend0x } from '../utils'; +import { calcGasBuffer, prepend0x } from '../utils'; export class StakingBridge { public contract: ethers.Contract; @@ -13,20 +13,41 @@ export class StakingBridge { this.contract = new ethers.Contract(address, abi, signerOrProvider); this.address = address; } + async stake(amount: string, vegaPublicKey: string) { + const key = prepend0x(vegaPublicKey); + const res = await this.contract.estimateGas.stake(amount, key); + const gasLimit = calcGasBuffer(res); + return this.contract.stake(amount, key, { + gasLimit, + }); + } - stake(amount: string, vegaPublicKey: string) { - return this.contract.stake(amount, prepend0x(vegaPublicKey)); + async remove_stake(amount: string, vegaPublicKey: string) { + const key = prepend0x(vegaPublicKey); + const res = await this.contract.estimateGas.remove_stake(amount, key); + const gasLimit = calcGasBuffer(res); + return this.contract.remove_stake(amount, key, { + gasLimit, + }); } - remove_stake(amount: string, vegaPublicKey: string) { - return this.contract.remove_stake(amount, prepend0x(vegaPublicKey)); - } - transfer_stake(amount: string, newAddress: string, vegaPublicKey: string) { - return this.contract.transfer_stake( + + async transfer_stake( + amount: string, + newAddress: string, + vegaPublicKey: string + ) { + const key = prepend0x(vegaPublicKey); + const res = await this.contract.estimateGas.transfer_stake( amount, newAddress, - prepend0x(vegaPublicKey) + key ); + const gasLimit = calcGasBuffer(res); + return this.contract.transfer_stake(amount, newAddress, key, { + gasLimit, + }); } + staking_token() { return this.contract.staking_token(); } diff --git a/libs/smart-contracts/src/contracts/token-faucetable.ts b/libs/smart-contracts/src/contracts/token-faucetable.ts index 703b4e888..43a78f336 100644 --- a/libs/smart-contracts/src/contracts/token-faucetable.ts +++ b/libs/smart-contracts/src/contracts/token-faucetable.ts @@ -1,6 +1,7 @@ import type { BigNumber } from 'ethers'; import { ethers } from 'ethers'; import erc20AbiFaucetable from '../abis/erc20_abi_faucet.json'; +import { calcGasBuffer } from '../utils'; export class TokenFaucetable { public contract: ethers.Contract; @@ -27,13 +28,17 @@ export class TokenFaucetable { allowance(owner: string, spender: string): Promise { return this.contract.allowance(owner, spender); } - approve(spender: string, amount: string) { - return this.contract.approve(spender, amount); + async approve(spender: string, amount: string) { + const res = await this.contract.estimateGas.approve(spender, amount); + const gasLimit = calcGasBuffer(res); + return this.contract.approve(spender, amount, { gasLimit }); } decimals(): Promise { return this.contract.decimals(); } - faucet() { - return this.contract.faucet(); + async faucet() { + const res = await this.contract.estimateGas.faucet(); + const gasLimit = calcGasBuffer(res); + return this.contract.faucet({ gasLimit }); } } diff --git a/libs/smart-contracts/src/contracts/token-vesting.ts b/libs/smart-contracts/src/contracts/token-vesting.ts index 0ec6fdb9d..43ad9d43c 100644 --- a/libs/smart-contracts/src/contracts/token-vesting.ts +++ b/libs/smart-contracts/src/contracts/token-vesting.ts @@ -1,6 +1,6 @@ import { ethers } from 'ethers'; import abi from '../abis/vesting_abi.json'; -import { prepend0x } from '../utils'; +import { calcGasBuffer, prepend0x } from '../utils'; export class TokenVesting { public contract: ethers.Contract; @@ -13,12 +13,21 @@ export class TokenVesting { this.contract = new ethers.Contract(address, abi, signerOrProvider); this.address = address; } - - stake_tokens(amount: string, vegaPublicKey: string) { - return this.contract.stake_tokens(amount, prepend0x(vegaPublicKey)); + async stake_tokens(amount: string, vegaPublicKey: string) { + const key = prepend0x(vegaPublicKey); + const res = await this.contract.estimateGas.stake_tokens(amount, key); + const gasLimit = calcGasBuffer(res); + return this.contract.stake_tokens(amount, key, { + gasLimit, + }); } - remove_stake(amount: string, vegaPublicKey: string) { - return this.contract.remove_stake(amount, prepend0x(vegaPublicKey)); + async remove_stake(amount: string, vegaPublicKey: string) { + const key = prepend0x(vegaPublicKey); + const res = await this.contract.estimateGas.remove_stake(amount, key); + const gasLimit = calcGasBuffer(res); + return this.contract.remove_stake(amount, key, { + gasLimit, + }); } stake_balance(address: string, vegaPublicKey: string) { return this.contract.stake_balance(address, prepend0x(vegaPublicKey)); @@ -38,7 +47,13 @@ export class TokenVesting { user_total_all_tranches(address: string) { return this.contract.user_total_all_tranches(address); } - withdraw_from_tranche(trancheId: number) { - return this.contract.withdraw_from_tranche(trancheId); + async withdraw_from_tranche(trancheId: number) { + const res = await this.contract.estimateGas.withdraw_from_tranche( + trancheId + ); + const gasLimit = calcGasBuffer(res); + return this.contract.withdraw_from_tranche(trancheId, { + gasLimit, + }); } } diff --git a/libs/smart-contracts/src/contracts/token.ts b/libs/smart-contracts/src/contracts/token.ts index 48ecb7839..8b99a6d69 100644 --- a/libs/smart-contracts/src/contracts/token.ts +++ b/libs/smart-contracts/src/contracts/token.ts @@ -1,6 +1,7 @@ import type { BigNumber } from 'ethers'; import { ethers } from 'ethers'; import erc20Abi from '../abis/erc20_abi.json'; +import { calcGasBuffer } from '../utils'; export class Token { public contract: ethers.Contract; @@ -23,13 +24,15 @@ export class Token { allowance(owner: string, spender: string): Promise { return this.contract.allowance(owner, spender); } - approve(spender: string, amount: string) { - return this.contract.approve(spender, amount); + async approve(spender: string, amount: string) { + const res = await this.contract.estimateGas.approve(spender, amount); + const gasLimit = calcGasBuffer(res); + return this.contract.approve(spender, amount, { gasLimit }); } decimals(): Promise { return this.contract.decimals(); } - faucet() { + async faucet() { /* No op */ } } diff --git a/libs/smart-contracts/src/utils/calc-gas-buffer.ts b/libs/smart-contracts/src/utils/calc-gas-buffer.ts new file mode 100644 index 000000000..2287f78ba --- /dev/null +++ b/libs/smart-contracts/src/utils/calc-gas-buffer.ts @@ -0,0 +1,5 @@ +import type { BigNumber as EthersBigNumber } from 'ethers'; + +export function calcGasBuffer(value: EthersBigNumber): EthersBigNumber { + return value.mul(120).div(100); +} diff --git a/libs/smart-contracts/src/utils/index.ts b/libs/smart-contracts/src/utils/index.ts index d5fc7c3f7..eda8e4051 100644 --- a/libs/smart-contracts/src/utils/index.ts +++ b/libs/smart-contracts/src/utils/index.ts @@ -1 +1,2 @@ +export * from './calc-gas-buffer'; export * from './prepend-0x';