Skip to content

Commit

Permalink
Fix approval + swaps (#6259)
Browse files Browse the repository at this point in the history
* remove permit usage on mainnet swaps

* remove logging

* make approval + swap parallel again

* remove import

* Skip node ack check if txn params are for mainnet (#6261)

* Skip node ack check if txn params are for mainnet

* Cap retries to 10 retries for node ack

* Remove ALLOWS_PERMIT gas estimation checks

---------

Co-authored-by: Jin <[email protected]>
  • Loading branch information
brunobar79 and jinchung authored Nov 12, 2024
1 parent 9209139 commit 910a789
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 59 deletions.
10 changes: 1 addition & 9 deletions src/handlers/swap.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { BigNumberish } from '@ethersproject/bignumber';
import { Block, StaticJsonRpcProvider } from '@ethersproject/providers';
import {
ALLOWS_PERMIT,
CrosschainQuote,
getQuoteExecutionDetails,
getRainbowRouterContractAddress,
Expand Down Expand Up @@ -86,14 +85,7 @@ const getCrosschainSwapRainbowDefaultGasLimit = (chainId: ChainId) =>
ethereumUtils.getBasicSwapGasLimit(Number(chainId)) * EXTRA_GAS_PADDING;

export const getDefaultGasLimitForTrade = (tradeDetails: Quote, chainId: ChainId): number => {
const allowsPermit =
chainId === ChainId.mainnet && ALLOWS_PERMIT[tradeDetails?.sellTokenAddress?.toLowerCase() as keyof PermitSupportedTokenList];

let defaultGasLimit = tradeDetails?.defaultGasLimit;

if (allowsPermit) {
defaultGasLimit = Math.max(Number(defaultGasLimit), Number(ethUnits.basic_swap_permit) * EXTRA_GAS_PADDING).toString();
}
const defaultGasLimit = tradeDetails?.defaultGasLimit;
return Number(defaultGasLimit || 0) || ethereumUtils.getBasicSwapGasLimit(Number(chainId)) * EXTRA_GAS_PADDING;
};

Expand Down
10 changes: 5 additions & 5 deletions src/raps/actions/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,10 @@ export const executeSwap = async ({
wallet: Signer;
permit: boolean;
}): Promise<Transaction | null> => {
if (!wallet || !quote) return null;
if (!wallet || !quote) {
return null;
}

const { sellTokenAddress, buyTokenAddress } = quote;
const transactionParams = {
gasLimit: toHex(gasLimit) || undefined,
nonce: nonce ? toHex(`${nonce}`) : undefined,
Expand Down Expand Up @@ -236,9 +237,8 @@ export const swap = async ({
gasFeeParamsBySpeed,
}: ActionProps<'swap'>): Promise<RapActionResult> => {
let gasParamsToUse = gasParams;
// let gasParams = parseGasParamAmounts(selectedGasFee);

const { quote, permit, chainId, requiresApprove } = parameters;
const { quote, chainId, requiresApprove } = parameters;
// if swap isn't the last action, use fast gas or custom (whatever is faster)

if (currentRap.actions.length - 1 > index) {
Expand Down Expand Up @@ -272,7 +272,7 @@ export const swap = async ({
chainId,
gasLimit,
nonce,
permit: !!permit,
permit: false,
quote,
wallet,
};
Expand Down
37 changes: 25 additions & 12 deletions src/raps/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* eslint-disable no-async-promise-executor */
/* eslint-disable no-promise-executor-return */
import { Signer } from '@ethersproject/abstract-signer';

import { ChainId } from '@/chains/types';
import { RainbowError, logger } from '@/logger';

import { claim, swap, unlock } from './actions';
Expand Down Expand Up @@ -111,18 +111,29 @@ function getRapFullName<T extends RapActionTypes>(actions: RapAction<T>[]) {

const delay = (ms: number) => new Promise(res => setTimeout(res, ms));

const waitForNodeAck = async (hash: string, provider: Signer['provider']): Promise<void> => {
return new Promise(async resolve => {
const NODE_ACK_MAX_TRIES = 10;

const waitForNodeAck = async (hash: string, provider: Signer['provider'], tries = 0): Promise<void> => {
try {
const tx = await provider?.getTransaction(hash);

// This means the node is aware of the tx, we're good to go
if ((tx && tx.blockNumber === null) || (tx && tx?.blockNumber && tx?.blockNumber > 0)) {
resolve();
} else {
// Wait for 1 second and try again
return;
}

// Wait for 1 second and try again
if (tries < NODE_ACK_MAX_TRIES) {
await delay(1000);
return waitForNodeAck(hash, provider);
return waitForNodeAck(hash, provider, tries + 1);
}
});
} catch (e) {
// Wait for 1 second and try again
if (tries < NODE_ACK_MAX_TRIES) {
await delay(1000);
return waitForNodeAck(hash, provider, tries + 1);
}
}
};

export const walletExecuteRap = async (
Expand Down Expand Up @@ -161,11 +172,13 @@ export const walletExecuteRap = async (
gasFeeParamsBySpeed: parameters?.gasFeeParamsBySpeed,
};

const { baseNonce, errorMessage: error, hash } = await executeAction(actionParams);
const { baseNonce, errorMessage: error, hash: firstHash } = await executeAction(actionParams);
const shouldWaitForNodeAck = parameters.chainId !== ChainId.mainnet;

if (typeof baseNonce === 'number') {
actions.length > 1 && hash && (await waitForNodeAck(hash, wallet.provider));
let latestHash = firstHash;
for (let index = 1; index < actions.length; index++) {
latestHash && shouldWaitForNodeAck && (await waitForNodeAck(latestHash, wallet.provider));
const action = actions[index];
const actionParams = {
action,
Expand All @@ -178,8 +191,8 @@ export const walletExecuteRap = async (
gasParams: parameters?.gasParams,
gasFeeParamsBySpeed: parameters?.gasFeeParamsBySpeed,
};
const { hash } = await executeAction(actionParams);
hash && (await waitForNodeAck(hash, wallet.provider));
const { hash: nextHash } = await executeAction(actionParams);
latestHash = nextHash;
}
nonce = baseNonce + actions.length - 1;
} else {
Expand Down
29 changes: 5 additions & 24 deletions src/raps/unlockAndSwap.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import {
ALLOWS_PERMIT,
ETH_ADDRESS as ETH_ADDRESS_AGGREGATOR,
getRainbowRouterContractAddress,
PermitSupportedTokenList,
} from '@rainbow-me/swaps';
import { getRainbowRouterContractAddress } from '@rainbow-me/swaps';
import { Address } from 'viem';

import { ChainId } from '@/chains/types';
import { isNativeAsset } from '@/handlers/assets';
import { add } from '@/helpers/utilities';
import { isLowerCaseMatch } from '@/utils';

import { assetNeedsUnlocking, estimateApprove, estimateSwapGasLimit } from './actions';
import { estimateUnlockAndSwapFromMetadata } from './actions/swap';
Expand Down Expand Up @@ -56,7 +48,6 @@ export const estimateUnlockAndSwap = async ({
if (gasLimitFromMetadata) {
return gasLimitFromMetadata;
}

const unlockGasLimit = await estimateApprove({
owner: accountAddress,
tokenAddress: sellTokenAddress,
Expand Down Expand Up @@ -89,19 +80,12 @@ export const createUnlockAndSwapRap = async (swapParameters: RapSwapActionParame

const { sellAmount, quote, chainId, assetToSell, assetToBuy } = swapParameters;

const {
from: accountAddress,
sellTokenAddress,
allowanceNeeded,
} = quote as {
const { from: accountAddress, allowanceNeeded } = quote as {
from: Address;
sellTokenAddress: Address;
allowanceNeeded: boolean;
};

// Aggregators represent native asset as 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
const nativeAsset = isLowerCaseMatch(ETH_ADDRESS_AGGREGATOR, sellTokenAddress) || isNativeAsset(sellTokenAddress, chainId);

let swapAssetNeedsUnlocking = false;

if (allowanceNeeded) {
Expand All @@ -114,10 +98,7 @@ export const createUnlockAndSwapRap = async (swapParameters: RapSwapActionParame
});
}

const allowsPermit =
!nativeAsset && chainId === ChainId.mainnet && ALLOWS_PERMIT[assetToSell.address?.toLowerCase() as keyof PermitSupportedTokenList];

if (swapAssetNeedsUnlocking && !allowsPermit) {
if (swapAssetNeedsUnlocking) {
const unlock = createNewAction('unlock', {
fromAddress: accountAddress,
amount: sellAmount,
Expand All @@ -132,8 +113,8 @@ export const createUnlockAndSwapRap = async (swapParameters: RapSwapActionParame
const swap = createNewAction('swap', {
chainId,
sellAmount,
permit: swapAssetNeedsUnlocking && allowsPermit,
requiresApprove: swapAssetNeedsUnlocking && !allowsPermit,
permit: false,
requiresApprove: swapAssetNeedsUnlocking,
quote,
meta: swapParameters.meta,
assetToSell,
Expand Down
11 changes: 2 additions & 9 deletions src/raps/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Block, Provider } from '@ethersproject/abstract-provider';
import { MaxUint256 } from '@ethersproject/constants';
import { Contract, PopulatedTransaction } from '@ethersproject/contracts';
import { StaticJsonRpcProvider } from '@ethersproject/providers';
import { ALLOWS_PERMIT, CrosschainQuote, Quote, getQuoteExecutionDetails, getRainbowRouterContractAddress } from '@rainbow-me/swaps';
import { CrosschainQuote, Quote, getQuoteExecutionDetails, getRainbowRouterContractAddress } from '@rainbow-me/swaps';
import { mainnet } from 'viem/chains';
import { Chain, erc20Abi } from 'viem';
import { GasFeeParamsBySpeed, LegacyGasFeeParamsBySpeed, LegacyTransactionGasParamAmounts, TransactionGasParamAmounts } from '@/entities';
Expand Down Expand Up @@ -140,14 +140,7 @@ const getClosestGasEstimate = async (estimationFn: (gasEstimate: number) => Prom
};

export const getDefaultGasLimitForTrade = (quote: Quote, chainId: Chain['id']): string => {
const allowsPermit = chainId === mainnet.id && ALLOWS_PERMIT[quote?.sellTokenAddress?.toLowerCase()];

let defaultGasLimit = quote?.defaultGasLimit;

if (allowsPermit) {
defaultGasLimit = Math.max(Number(defaultGasLimit), Number(multiply(gasUnits.basic_swap_permit, EXTRA_GAS_PADDING))).toString();
}
return defaultGasLimit || multiply(gasUnits.basic_swap[chainId], EXTRA_GAS_PADDING);
return quote?.defaultGasLimit || multiply(gasUnits.basic_swap[chainId], EXTRA_GAS_PADDING);
};

export const estimateSwapGasLimitWithFakeApproval = async (
Expand Down

0 comments on commit 910a789

Please sign in to comment.