Skip to content

Commit

Permalink
Fix crash due to failed estimated gas limit (#6055)
Browse files Browse the repository at this point in the history
* who knows

* more error checking for if NaN numbers exist

* more boundary checks

* fix lint

* code review changes

* change calculate gas fee worklet with new changes

* Update src/raps/actions/unlock.ts
  • Loading branch information
walmat authored Sep 12, 2024
1 parent 79239f1 commit 56e9585
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 19 deletions.
18 changes: 16 additions & 2 deletions src/__swaps__/screens/Swap/hooks/useEstimatedGasFee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,22 @@ function safeBigInt(value: string) {
}
}

const isFeeNaN = (value: string | undefined) => isNaN(Number(value)) || typeof value === 'undefined';

export function calculateGasFee(gasSettings: GasSettings, gasLimit: string) {
const amount = gasSettings.isEIP1559 ? add(gasSettings.maxBaseFee, gasSettings.maxPriorityFee || '0') : gasSettings.gasPrice;
return multiply(gasLimit, amount);
if (gasSettings.isEIP1559) {
if (isFeeNaN(gasSettings.maxBaseFee) || isFeeNaN(gasSettings.maxPriorityFee)) {
return null;
}

return add(gasSettings.maxBaseFee, gasSettings.maxPriorityFee);
}

if (isFeeNaN(gasSettings.gasPrice)) {
return null;
}

return multiply(gasLimit, gasSettings.gasPrice);
}

export function useEstimatedGasFee({
Expand All @@ -40,6 +53,7 @@ export function useEstimatedGasFee({
if (!gasLimit || !gasSettings || !nativeNetworkAsset?.price) return;

const fee = calculateGasFee(gasSettings, gasLimit);
if (!fee) return;

const networkAssetPrice = nativeNetworkAsset.price.value?.toString();
if (!networkAssetPrice) return `${formatNumber(weiToGwei(fee))} Gwei`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,28 @@ export const SyncQuoteSharedValuesToState = () => {
return null;
};

const isFeeNaNWorklet = (value: string | undefined) => {
'worklet';

return isNaN(Number(value)) || typeof value === 'undefined';
};

export function calculateGasFeeWorklet(gasSettings: GasSettings, gasLimit: string) {
'worklet';
const amount = gasSettings.isEIP1559 ? sumWorklet(gasSettings.maxBaseFee, gasSettings.maxPriorityFee || '0') : gasSettings.gasPrice;
return mulWorklet(gasLimit, amount);

if (gasSettings.isEIP1559) {
if (isFeeNaNWorklet(gasSettings.maxBaseFee) || isFeeNaNWorklet(gasSettings.maxPriorityFee)) {
return null;
}

return sumWorklet(gasSettings.maxBaseFee || '0', gasSettings.maxPriorityFee || '0');
}

if (isFeeNaNWorklet(gasSettings.gasPrice)) {
return null;
}

return mulWorklet(gasLimit, gasSettings.gasPrice);
}

export function formatUnitsWorklet(value: string, decimals: number) {
Expand Down Expand Up @@ -166,12 +184,23 @@ export function SyncGasStateToSharedValues() {
hasEnoughFundsForGas.value = undefined;
if (!gasSettings || !estimatedGasLimit || !quote || 'error' in quote || isLoadingNativeNetworkAsset) return;

// NOTE: if we don't have a gas price or max base fee or max priority fee, we can't calculate the gas fee
if (
(gasSettings.isEIP1559 && !(gasSettings.maxBaseFee || gasSettings.maxPriorityFee)) ||
(!gasSettings.isEIP1559 && !gasSettings.gasPrice)
) {
return;
}

if (!userNativeNetworkAsset) {
hasEnoughFundsForGas.value = false;
return;
}

const gasFee = calculateGasFeeWorklet(gasSettings, estimatedGasLimit);
if (gasFee === null || isNaN(Number(gasFee))) {
return;
}

const nativeGasFee = divWorklet(gasFee, powWorklet(10, userNativeNetworkAsset.decimals));

Expand Down
4 changes: 4 additions & 0 deletions src/handlers/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ export async function estimateGasWithPadding(
? contractCallEstimateGas(...(callArguments ?? []), txPayloadToEstimate)
: p.estimateGas(cleanTxPayload));

if (!BigNumber.isBigNumber(estimatedGas)) {
throw new Error('Invalid gas limit type');
}

const lastBlockGasLimit = addBuffer(gasLimit.toString(), 0.9);
const paddedGas = addBuffer(estimatedGas.toString(), paddingFactor.toString());
logger.debug('[web3]: ⛽ GAS CALCULATIONS!', {
Expand Down
8 changes: 6 additions & 2 deletions src/raps/actions/crosschainSwap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,13 @@ export const estimateCrosschainSwapGasLimit = async ({
SWAP_GAS_PADDING
);

return gasLimit || getCrosschainSwapDefaultGasLimit(quote);
if (gasLimit === null || gasLimit === undefined || isNaN(Number(gasLimit))) {
return getCrosschainSwapDefaultGasLimit(quote) || getDefaultGasLimitForTrade(quote, chainId);
}

return gasLimit;
} catch (error) {
return getCrosschainSwapDefaultGasLimit(quote);
return getCrosschainSwapDefaultGasLimit(quote) || getDefaultGasLimitForTrade(quote, chainId);
}
};

Expand Down
13 changes: 10 additions & 3 deletions src/raps/actions/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,13 @@ export const estimateSwapGasLimit = async ({
WRAP_GAS_PADDING
);

return gasLimit || String(quote?.defaultGasLimit) || String(default_estimate);
if (gasLimit === null || gasLimit === undefined || isNaN(Number(gasLimit))) {
return quote?.defaultGasLimit || default_estimate;
}

return gasLimit;
} catch (e) {
return String(quote?.defaultGasLimit) || String(default_estimate);
return quote?.defaultGasLimit || default_estimate;
}
// Swap
} else {
Expand All @@ -116,8 +120,11 @@ export const estimateSwapGasLimit = async ({
}

const gasLimit = await estimateGasWithPadding(params, method, methodArgs, provider, SWAP_GAS_PADDING);
if (gasLimit === null || gasLimit === undefined || isNaN(Number(gasLimit))) {
return getDefaultGasLimitForTrade(quote, chainId);
}

return gasLimit || getDefaultGasLimitForTrade(quote, chainId);
return gasLimit;
} catch (error) {
return getDefaultGasLimitForTrade(quote, chainId);
}
Expand Down
7 changes: 6 additions & 1 deletion src/raps/actions/unlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,12 @@ export const estimateApprove = async ({
const gasLimit = await tokenContract.estimateGas.approve(spender, MaxUint256, {
from: owner,
});
return gasLimit ? gasLimit.toString() : `${gasUnits.basic_approval}`;

if (gasLimit === null || gasLimit === undefined || isNaN(Number(gasLimit.toString()))) {
return `${gasUnits.basic_approval}`;
}

return gasLimit.toString();
} catch (error) {
logger.error(new RainbowError('[raps/unlock]: error estimateApprove'), {
message: (error as Error)?.message,
Expand Down
11 changes: 8 additions & 3 deletions src/raps/unlockAndCrosschainSwap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,8 @@ export const estimateUnlockAndCrosschainSwap = async ({
});
}

let unlockGasLimit;

if (swapAssetNeedsUnlocking) {
unlockGasLimit = await estimateApprove({
const unlockGasLimit = await estimateApprove({
owner: accountAddress,
tokenAddress: sellTokenAddress,
spender: allowanceTarget,
Expand All @@ -71,7 +69,14 @@ export const estimateUnlockAndCrosschainSwap = async ({
quote,
});

if (swapGasLimit === null || swapGasLimit === undefined || isNaN(Number(swapGasLimit))) {
return null;
}

const gasLimit = gasLimits.concat(swapGasLimit).reduce((acc, limit) => add(acc, limit), '0');
if (isNaN(Number(gasLimit))) {
return null;
}

return gasLimit.toString();
};
Expand Down
14 changes: 8 additions & 6 deletions src/raps/unlockAndSwap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export const estimateUnlockAndSwap = async ({
let swapAssetNeedsUnlocking = false;

const nativeAsset = isLowerCaseMatch(ETH_ADDRESS_AGGREGATOR, sellTokenAddress) || isNativeAsset(sellTokenAddress, chainId);

if (!isNativeAssetUnwrapping && !nativeAsset) {
swapAssetNeedsUnlocking = await assetNeedsUnlocking({
owner: accountAddress,
Expand All @@ -65,12 +64,8 @@ export const estimateUnlockAndSwap = async ({
if (gasLimitFromMetadata) {
return gasLimitFromMetadata;
}
}

let unlockGasLimit;

if (swapAssetNeedsUnlocking) {
unlockGasLimit = await estimateApprove({
const unlockGasLimit = await estimateApprove({
owner: accountAddress,
tokenAddress: sellTokenAddress,
spender: getRainbowRouterContractAddress(chainId),
Expand All @@ -85,7 +80,14 @@ export const estimateUnlockAndSwap = async ({
quote,
});

if (swapGasLimit === null || swapGasLimit === undefined || isNaN(Number(swapGasLimit))) {
return null;
}

const gasLimit = gasLimits.concat(swapGasLimit).reduce((acc, limit) => add(acc, limit), '0');
if (isNaN(Number(gasLimit))) {
return null;
}

return gasLimit.toString();
};
Expand Down

0 comments on commit 56e9585

Please sign in to comment.