import { BigNumber } from 'ethers'; import { ErrorCode } from '../error-handler/constants'; import { ContractMethodLastGasParams } from '../types'; export const DESIRED_LEAST_GAS_LIMIT_CONSUMPTION = 70; export const GAS_MULTIPLIER_THRESHOLD = 75; export const MAX_GAS_MULTIPLIER = 5; export const INCREMENT_GAS_MULTIPLIER = 1.2; export const GAS_LIMIT_MULTIPLIER_LIMIT = 10000000; export const PERCENTAGE_INCREMENT_ON_GAS_LIMIT = 0.15; export const isDroppedAndReplaced = (e: any) => e?.code === ErrorCode.TRANSACTION_REPLACED && e?.replacement && (e?.reason === 'repriced' || e?.cancelled === false); export function calculateMultiplier( gasLimit: BigNumber, gasMultiplier: number, simulatedGasLimit?: BigNumber, ): number { const newGasMultiplier = gasMultiplier + INCREMENT_GAS_MULTIPLIER; const newGasLimit = parseInt(gasLimit.toString()) * newGasMultiplier; { process.env.DEBUG == 'true' && console.log( '🚀 ~ file: helper.ts:24 ~ newGasLimit: (Calculated new gas limit)', newGasLimit, ); } // never allow thrice the gas limit on base gas limit estimation let gasLimitUpperCap: number; if (simulatedGasLimit) { gasLimitUpperCap = parseInt(simulatedGasLimit.toString()) * 3; } else { gasLimitUpperCap = GAS_LIMIT_MULTIPLIER_LIMIT; } if ( parseInt(newGasLimit.toString()) >= parseInt((gasLimitUpperCap * 0.7).toString()) ) { process.env.DEBUG == 'true' && console.log( ' Gas Limit has increased more than 10M, so we will increase gas limit by 15%', ); const expectedIncrease = parseInt(gasLimit.toString()) * (1 + PERCENTAGE_INCREMENT_ON_GAS_LIMIT); process.env.DEBUG == 'true' && console.log( '🚀 ~ file: helper.ts:28 ~ expectedIncrease: (Calculated expected increase)', expectedIncrease, ); const multiplier = expectedIncrease / parseInt(gasLimit.toString()); process.env.DEBUG == 'true' && console.log( '🚀 ~ file: helper.ts:30 ~ multiplier: (Calculated multiplier)', multiplier, ); return multiplier; } else { return newGasMultiplier; } } export const getGasMultiplier = ( gasMultiplier: number, gasUsed: BigNumber, gasPercentage: number, gasLimit: BigNumber, ): number => { // check if gas percentage is lower then 60% if (gasPercentage < DESIRED_LEAST_GAS_LIMIT_CONSUMPTION) { // decrease gas multiplier // reduce multiplier to have gasPercentage of 65% console.log('🚀 ~ file: helper.ts:47 ~ gasPercentage:', gasPercentage); const desiredFactor = DESIRED_LEAST_GAS_LIMIT_CONSUMPTION / 100; const desiredGasLimit = Math.ceil( parseInt(gasUsed.toString()) / desiredFactor, ); process.env.DEBUG == 'true' && console.log(' ~ file: helper.ts:33 ~ desiredGasLimit:', desiredGasLimit); const multiplier = parseInt(desiredGasLimit.toString()) / parseInt(gasLimit.toString()); process.env.DEBUG == 'true' && console.log(' ~ file: helper.ts:35 ~ multiplier:', multiplier); // if (multiplier < MAX_GAS_MULTIPLIER) { // return multiplier; // } return 1; } else if (gasPercentage > GAS_MULTIPLIER_THRESHOLD) { // increase gas multiplier // increase multiplier to have gasPercentage of 75% const desiredFactor = GAS_MULTIPLIER_THRESHOLD / 100; const desiredGasLimit = Math.ceil( parseInt(gasUsed.toString()) / desiredFactor, ); process.env.DEBUG == 'true' && console.log(' ~ file: helper.ts:33 ~ desiredGasLimit:', desiredGasLimit); const multiplier = parseInt(desiredGasLimit.toString()) / parseInt(gasLimit.toString()); process.env.DEBUG == 'true' && console.log(' ~ file: helper.ts:35 ~ multiplier:', multiplier); if (multiplier < MAX_GAS_MULTIPLIER) { return multiplier; } return gasMultiplier; } else { // return 1 as gas percentage is between 70% and 75% return 1; } }; export function reduceGasLimits(contractGasUsed: ContractMethodLastGasParams, defaultGasMultiplier: number): { gasLimit?: BigNumber; gasMultiplier: number; } { const simulatedGasLimit = contractGasUsed.simulatedGasLimit; const previousGasLimit = contractGasUsed.lastGasLimit; if (simulatedGasLimit && previousGasLimit) { // increase simulated gas limit by 30 % const newGasLimit = BigNumber.from(parseInt((parseFloat(simulatedGasLimit.toString()) * 1.3).toString())); return { gasLimit: newGasLimit, gasMultiplier: defaultGasMultiplier, }; } else if (contractGasUsed.lastGasLimit) { // reduce last gas limit by 50% const newGasLimit = BigNumber.from(parseInt((parseFloat(contractGasUsed.lastGasLimit.toString()) * 0.5).toString())); return { gasLimit: newGasLimit, gasMultiplier: defaultGasMultiplier, } } return { gasLimit: contractGasUsed.lastGasLimit, gasMultiplier: defaultGasMultiplier, } }