diff --git a/src/tx-builder/config/index.ts b/src/tx-builder/config/index.ts index a4213aa3..ccc5d36f 100644 --- a/src/tx-builder/config/index.ts +++ b/src/tx-builder/config/index.ts @@ -21,10 +21,46 @@ export const uniswapEthAmount = '0.1'; export const SURPLUS = '0.05'; export const gasLimitRecommendations: GasRecommendationType = { + [ProtocolAction.default]: { + limit: '210000', + recommended: '210000', + }, + [ProtocolAction.deposit]: { + limit: '300000', + recommended: '300000', + }, [ProtocolAction.withdraw]: { limit: '230000', recommended: '300000', }, + [ProtocolAction.liquidationCall]: { + limit: '700000', + recommended: '700000', + }, + [ProtocolAction.liquidationFlash]: { + limit: '995000', + recommended: '995000', + }, + [ProtocolAction.repay]: { + limit: '300000', + recommended: '300000', + }, + [ProtocolAction.borrowETH]: { + limit: '450000', + recommended: '450000', + }, + [ProtocolAction.withdrawETH]: { + limit: '640000', + recommended: '640000', + }, + [ProtocolAction.swapCollateral]: { + limit: '700000', + recommended: '700000', + }, + [ProtocolAction.repayCollateral]: { + limit: '700000', + recommended: '700000', + }, }; export const distinctStakingAddressesBetweenTokens: StakingConfigType = { diff --git a/src/tx-builder/services/BaseDebtToken.ts b/src/tx-builder/services/BaseDebtToken.ts index b65e7971..fc74bec3 100644 --- a/src/tx-builder/services/BaseDebtToken.ts +++ b/src/tx-builder/services/BaseDebtToken.ts @@ -45,6 +45,7 @@ export default class BaseDebtToken return { tx: txCallback, txType: eEthereumTxType.ERC20_APPROVAL, + gas: this.generateTxPriceEstimation([], txCallback), }; } diff --git a/src/tx-builder/services/BaseService.ts b/src/tx-builder/services/BaseService.ts index d21db54c..b3b92d8d 100644 --- a/src/tx-builder/services/BaseService.ts +++ b/src/tx-builder/services/BaseService.ts @@ -4,9 +4,13 @@ import { tEthereumAddress, TransactionGenerationMethod, transactionType, + GasResponse, + ProtocolAction, + EthereumTransactionTypeExtended, + eEthereumTxType, } from '../types'; import { ContractsFactory } from '../interfaces/ContractsFactory'; -import { estimateGas } from '../utils/gasStation'; +import { estimateGas, getGasPrice } from '../utils/gasStation'; import { DEFAULT_NULL_VALUE_ON_TX, gasLimitRecommendations } from '../config'; export default class BaseService { @@ -61,4 +65,44 @@ export default class BaseService { return tx; }; + + readonly generateTxPriceEstimation = ( + txs: EthereumTransactionTypeExtended[], + txCallback: () => Promise, + action: string = ProtocolAction.default + ): GasResponse => async () => { + try { + const gasPrice = await getGasPrice(this.config); + const hasPendingApprovals = txs.find( + (tx) => tx.txType === eEthereumTxType.ERC20_APPROVAL + ); + if (!hasPendingApprovals) { + const { + gasLimit, + gasPrice: gasPriceProv, + }: transactionType = await txCallback(); + if (!gasLimit) { + // If we don't recieve the correct gas we throw a error + throw new Error('Transaction calculation error'); + } + + return { + gasLimit: gasLimit.toString(), + gasPrice: gasPriceProv + ? gasPriceProv.toString() + : gasPrice.toString(), + }; + } + return { + gasLimit: gasLimitRecommendations[action].recommended, + gasPrice: gasPrice.toString(), + }; + } catch (error) { + console.error( + 'Calculate error on calculate estimation gas price.', + error + ); + return null; + } + }; } diff --git a/src/tx-builder/services/ERC20.ts b/src/tx-builder/services/ERC20.ts index 7b54535b..ab6060e3 100644 --- a/src/tx-builder/services/ERC20.ts +++ b/src/tx-builder/services/ERC20.ts @@ -42,6 +42,7 @@ export default class ERC20Service return { tx: txCallback, txType: eEthereumTxType.ERC20_APPROVAL, + gas: this.generateTxPriceEstimation([], txCallback), }; }; diff --git a/src/tx-builder/services/Faucet.ts b/src/tx-builder/services/Faucet.ts index 78537cd1..d60933ca 100644 --- a/src/tx-builder/services/Faucet.ts +++ b/src/tx-builder/services/Faucet.ts @@ -67,6 +67,7 @@ export default class FaucetService { tx: txCallback, txType: eEthereumTxType.FAUCET_MINT, + gas: this.generateTxPriceEstimation([], txCallback), }, ]; } diff --git a/src/tx-builder/services/LTAMigrator.ts b/src/tx-builder/services/LTAMigrator.ts index ce2c8511..57e05545 100644 --- a/src/tx-builder/services/LTAMigrator.ts +++ b/src/tx-builder/services/LTAMigrator.ts @@ -78,6 +78,7 @@ export default class LTAMigratorService txs.push({ txType: eEthereumTxType.MIGRATION_LEND_AAVE, tx: txCallback, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; diff --git a/src/tx-builder/services/LiquiditySwapAdapter.ts b/src/tx-builder/services/LiquiditySwapAdapter.ts index 3fb5214e..eb4b42bf 100644 --- a/src/tx-builder/services/LiquiditySwapAdapter.ts +++ b/src/tx-builder/services/LiquiditySwapAdapter.ts @@ -63,6 +63,7 @@ export default class LiquiditySwapAdapterService return { tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), }; } } diff --git a/src/tx-builder/services/RepayWithCollateralAdapter.ts b/src/tx-builder/services/RepayWithCollateralAdapter.ts index 72567c32..e0fb2ad2 100644 --- a/src/tx-builder/services/RepayWithCollateralAdapter.ts +++ b/src/tx-builder/services/RepayWithCollateralAdapter.ts @@ -66,6 +66,10 @@ export default class RepayWithCollateralAdapterService from: user, }); - return { tx: txCallback, txType: eEthereumTxType.DLP_ACTION }; + return { + tx: txCallback, + txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), + }; } } diff --git a/src/tx-builder/services/Staking.ts b/src/tx-builder/services/Staking.ts index 22f7201d..32b5ea8f 100644 --- a/src/tx-builder/services/Staking.ts +++ b/src/tx-builder/services/Staking.ts @@ -164,6 +164,7 @@ export default class StakingService txs.push({ tx: txCallback, txType: eEthereumTxType.STAKE_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; @@ -214,6 +215,7 @@ export default class StakingService txs.push({ tx: txCallback, txType: eEthereumTxType.STAKE_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; @@ -249,6 +251,7 @@ export default class StakingService { tx: txCallback, txType: eEthereumTxType.STAKE_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), }, ]; } @@ -270,6 +273,7 @@ export default class StakingService { tx: txCallback, txType: eEthereumTxType.STAKE_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), }, ]; } @@ -303,6 +307,7 @@ export default class StakingService { tx: txCallback, txType: eEthereumTxType.STAKE_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), }, ]; } diff --git a/src/tx-builder/services/WETHGateway.ts b/src/tx-builder/services/WETHGateway.ts index 25a3cf1f..bcd94255 100644 --- a/src/tx-builder/services/WETHGateway.ts +++ b/src/tx-builder/services/WETHGateway.ts @@ -9,6 +9,7 @@ import { eEthereumTxType, EthereumTransactionTypeExtended, InterestRate, + ProtocolAction, transactionType, tStringDecimalUnits, } from '../types'; @@ -81,6 +82,7 @@ export default class WETHGatewayService { tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), }, ]; } @@ -136,6 +138,11 @@ export default class WETHGatewayService txs.push({ tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation( + txs, + txCallback, + ProtocolAction.borrowETH + ), }); return txs; @@ -188,6 +195,11 @@ export default class WETHGatewayService txs.push({ tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation( + txs, + txCallback, + ProtocolAction.withdrawETH + ), }); return txs; @@ -221,6 +233,7 @@ export default class WETHGatewayService { tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), }, ]; } diff --git a/src/tx-builder/services/v2/AaveGovernanceV2.ts b/src/tx-builder/services/v2/AaveGovernanceV2.ts index d72f130a..3c1c75c9 100644 --- a/src/tx-builder/services/v2/AaveGovernanceV2.ts +++ b/src/tx-builder/services/v2/AaveGovernanceV2.ts @@ -171,6 +171,7 @@ export default class AaveGovernanceV2Service txs.push({ tx: txCallback, txType: eEthereumTxType.GOVERNANCE_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; } @@ -194,6 +195,7 @@ export default class AaveGovernanceV2Service txs.push({ tx: txCallback, txType: eEthereumTxType.GOVERNANCE_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; } @@ -217,6 +219,7 @@ export default class AaveGovernanceV2Service txs.push({ tx: txCallback, txType: eEthereumTxType.GOVERNANCE_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; } @@ -240,6 +243,7 @@ export default class AaveGovernanceV2Service txs.push({ tx: txCallback, txType: eEthereumTxType.GOVERNANCE_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; } @@ -264,6 +268,7 @@ export default class AaveGovernanceV2Service txs.push({ tx: txCallback, txType: eEthereumTxType.GOVERNANCE_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; } @@ -328,6 +333,7 @@ export default class AaveGovernanceV2Service txs.push({ tx: txCallback, txType: eEthereumTxType.GOVERNANCE_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; } diff --git a/src/tx-builder/services/v2/GovernanceDelegationTokenService.ts b/src/tx-builder/services/v2/GovernanceDelegationTokenService.ts index 0ddf9a7c..9c9c0fa3 100644 --- a/src/tx-builder/services/v2/GovernanceDelegationTokenService.ts +++ b/src/tx-builder/services/v2/GovernanceDelegationTokenService.ts @@ -67,6 +67,7 @@ export default class GovernanceDelegationTokenService txs.push({ tx: txCallback, txType: eEthereumTxType.GOV_DELEGATION_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; @@ -98,6 +99,7 @@ export default class GovernanceDelegationTokenService txs.push({ tx: txCallback, txType: eEthereumTxType.GOV_DELEGATION_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; @@ -135,6 +137,7 @@ export default class GovernanceDelegationTokenService txs.push({ tx: txCallback, txType: eEthereumTxType.GOV_DELEGATION_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; @@ -180,6 +183,7 @@ export default class GovernanceDelegationTokenService txs.push({ tx: txCallback, txType: eEthereumTxType.GOV_DELEGATION_ACTION, + gas: this.generateTxPriceEstimation(txs, txCallback), }); return txs; diff --git a/src/tx-builder/services/v2/LendingPool.ts b/src/tx-builder/services/v2/LendingPool.ts index 1e41ec8b..466ee9b7 100644 --- a/src/tx-builder/services/v2/LendingPool.ts +++ b/src/tx-builder/services/v2/LendingPool.ts @@ -157,6 +157,11 @@ export default class LendingPool txs.push({ tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation( + txs, + txCallback, + ProtocolAction.deposit + ), }); return txs; @@ -212,6 +217,11 @@ export default class LendingPool { tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation( + [], + txCallback, + ProtocolAction.withdraw + ), }, ]; } @@ -272,7 +282,13 @@ export default class LendingPool from: user, }); - return [{ tx: txCallback, txType: eEthereumTxType.DLP_ACTION }]; + return [ + { + tx: txCallback, + txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), + }, + ]; } @LPValidator @@ -353,6 +369,11 @@ export default class LendingPool txs.push({ tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation( + txs, + txCallback, + ProtocolAction.repay + ), }); return txs; @@ -382,6 +403,7 @@ export default class LendingPool { txType: eEthereumTxType.DLP_ACTION, tx: txCallback, + gas: this.generateTxPriceEstimation([], txCallback), }, ]; } @@ -405,7 +427,13 @@ export default class LendingPool from: user, }); - return [{ tx: txCallback, txType: eEthereumTxType.DLP_ACTION }]; + return [ + { + tx: txCallback, + txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation([], txCallback), + }, + ]; } @LPValidator @@ -480,6 +508,11 @@ export default class LendingPool txs.push({ tx: txCallback, txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation( + txs, + txCallback, + ProtocolAction.liquidationCall + ), }); return txs; @@ -623,7 +656,15 @@ export default class LendingPool } ); - txs.push({ tx: txCallback, txType: eEthereumTxType.DLP_ACTION }); + txs.push({ + tx: txCallback, + txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation( + txs, + txCallback, + ProtocolAction.swapCollateral + ), + }); return txs; } @@ -770,7 +811,15 @@ export default class LendingPool } ); - txs.push({ tx: txCallback, txType: eEthereumTxType.DLP_ACTION }); + txs.push({ + tx: txCallback, + txType: eEthereumTxType.DLP_ACTION, + gas: this.generateTxPriceEstimation( + txs, + txCallback, + ProtocolAction.repayCollateral + ), + }); return txs; } diff --git a/src/tx-builder/types/index.ts b/src/tx-builder/types/index.ts index 8dd220ac..18536e15 100644 --- a/src/tx-builder/types/index.ts +++ b/src/tx-builder/types/index.ts @@ -40,8 +40,16 @@ export enum eEthereumTxType { } export enum ProtocolAction { + default = 'default', withdraw = 'withdraw', deposit = 'deposit', + liquidationCall = 'liquidationCall', + liquidationFlash = 'liquidationFlash', + repay = 'repay', + swapCollateral = 'swapCollateral', + repayCollateral = 'repayCollateral', + withdrawETH = 'withdrawETH', + borrowETH = 'borrwoETH', } export enum GovernanceVote { @@ -62,6 +70,14 @@ export type GasRecommendationType = { }; }; +export type GeneratedTx = { + tx: transactionType; + gas: { + price: string; + limit: string; + }; +}; + export type transactionType = { value?: string; from?: string; @@ -142,6 +158,7 @@ export type Configuration = { export type EthereumTransactionTypeExtended = { txType: eEthereumTxType; tx: () => Promise; + gas?: GasResponse; }; export type TransactionGenerationMethod = { @@ -152,6 +169,17 @@ export type TransactionGenerationMethod = { action?: ProtocolAction; }; +export type TransactionGasGenerationMethod = { + txCallback: () => Promise; + action?: ProtocolAction; +}; + +export type GasType = { + gasLimit: string | undefined; + gasPrice: string; +}; +export type GasResponse = () => Promise; + export type TokenMetadataType = { name: string; symbol: string; diff --git a/src/tx-builder/utils/gasStation.ts b/src/tx-builder/utils/gasStation.ts index c0b724ce..6cb4cf7f 100644 --- a/src/tx-builder/utils/gasStation.ts +++ b/src/tx-builder/utils/gasStation.ts @@ -1,12 +1,22 @@ import { BigNumber } from 'ethers'; import { transactionType, Configuration } from '../types'; -// eslint-disable-next-line import/prefer-default-export +const DEFAULT_SURPLUS = 15; // 15% + export const estimateGas = async ( tx: transactionType, config: Configuration, gasSurplus?: number ): Promise => { const estimatedGas = await config.provider.estimateGas(tx); - return estimatedGas.add(estimatedGas.mul(gasSurplus || 10).div(100)); + return estimatedGas.add( + estimatedGas.mul(gasSurplus || DEFAULT_SURPLUS).div(100) + ); +}; + +export const getGasPrice = async ( + config: Configuration +): Promise => { + const gasPrice = await config.provider.getGasPrice(); + return gasPrice; };