mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 18:00:18 +01:00
Handle an RPC provider delay in Swaps (#14821)
* Return an estimated amount for a completed swap if an RPC provider has a delay * Create a recursive function for updating post tx balance * Add a few tests for the "getSwapsTokensReceivedFromTxMeta" fn * Trigger Build
This commit is contained in:
parent
4fa4930c8a
commit
b0557daa05
@ -41,6 +41,7 @@ import {
|
|||||||
PRIORITY_LEVELS,
|
PRIORITY_LEVELS,
|
||||||
} from '../../../../shared/constants/gas';
|
} from '../../../../shared/constants/gas';
|
||||||
import { decGWEIToHexWEI } from '../../../../shared/modules/conversion.utils';
|
import { decGWEIToHexWEI } from '../../../../shared/modules/conversion.utils';
|
||||||
|
import { isSwapsDefaultTokenAddress } from '../../../../shared/modules/swaps.utils';
|
||||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||||
import {
|
import {
|
||||||
HARDFORKS,
|
HARDFORKS,
|
||||||
@ -60,6 +61,7 @@ import PendingTransactionTracker from './pending-tx-tracker';
|
|||||||
import * as txUtils from './lib/util';
|
import * as txUtils from './lib/util';
|
||||||
|
|
||||||
const MAX_MEMSTORE_TX_LIST_SIZE = 100; // Number of transactions (by unique nonces) to keep in memory
|
const MAX_MEMSTORE_TX_LIST_SIZE = 100; // Number of transactions (by unique nonces) to keep in memory
|
||||||
|
const UPDATE_POST_TX_BALANCE_TIMEOUT = 5000;
|
||||||
|
|
||||||
const SWAP_TRANSACTION_TYPES = [
|
const SWAP_TRANSACTION_TYPES = [
|
||||||
TRANSACTION_TYPES.SWAP,
|
TRANSACTION_TYPES.SWAP,
|
||||||
@ -1465,6 +1467,39 @@ export default class TransactionController extends EventEmitter {
|
|||||||
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.SUBMITTED);
|
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.SUBMITTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updatePostTxBalance({ txMeta, txId, numberOfAttempts = 6 }) {
|
||||||
|
const postTxBalance = await this.query.getBalance(txMeta.txParams.from);
|
||||||
|
const latestTxMeta = this.txStateManager.getTransaction(txId);
|
||||||
|
const approvalTxMeta = latestTxMeta.approvalTxId
|
||||||
|
? this.txStateManager.getTransaction(latestTxMeta.approvalTxId)
|
||||||
|
: null;
|
||||||
|
latestTxMeta.postTxBalance = postTxBalance.toString(16);
|
||||||
|
const isDefaultTokenAddress = isSwapsDefaultTokenAddress(
|
||||||
|
txMeta.destinationTokenAddress,
|
||||||
|
txMeta.chainId,
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
isDefaultTokenAddress &&
|
||||||
|
txMeta.preTxBalance === latestTxMeta.postTxBalance &&
|
||||||
|
numberOfAttempts > 0
|
||||||
|
) {
|
||||||
|
setTimeout(() => {
|
||||||
|
// If postTxBalance is the same as preTxBalance, try it again.
|
||||||
|
this.updatePostTxBalance({
|
||||||
|
txMeta,
|
||||||
|
txId,
|
||||||
|
numberOfAttempts: numberOfAttempts - 1,
|
||||||
|
});
|
||||||
|
}, UPDATE_POST_TX_BALANCE_TIMEOUT);
|
||||||
|
} else {
|
||||||
|
this.txStateManager.updateTransaction(
|
||||||
|
latestTxMeta,
|
||||||
|
'transactions#confirmTransaction - add postTxBalance',
|
||||||
|
);
|
||||||
|
this._trackSwapsMetrics(latestTxMeta, approvalTxMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the status of the transaction to confirmed and sets the status of nonce duplicates as
|
* Sets the status of the transaction to confirmed and sets the status of nonce duplicates as
|
||||||
* dropped if the txParams have data it will fetch the txReceipt
|
* dropped if the txParams have data it will fetch the txReceipt
|
||||||
@ -1528,21 +1563,10 @@ export default class TransactionController extends EventEmitter {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (txMeta.type === TRANSACTION_TYPES.SWAP) {
|
if (txMeta.type === TRANSACTION_TYPES.SWAP) {
|
||||||
const postTxBalance = await this.query.getBalance(txMeta.txParams.from);
|
await this.updatePostTxBalance({
|
||||||
const latestTxMeta = this.txStateManager.getTransaction(txId);
|
txMeta,
|
||||||
|
txId,
|
||||||
const approvalTxMeta = latestTxMeta.approvalTxId
|
});
|
||||||
? this.txStateManager.getTransaction(latestTxMeta.approvalTxId)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
latestTxMeta.postTxBalance = postTxBalance.toString(16);
|
|
||||||
|
|
||||||
this.txStateManager.updateTransaction(
|
|
||||||
latestTxMeta,
|
|
||||||
'transactions#confirmTransaction - add postTxBalance',
|
|
||||||
);
|
|
||||||
|
|
||||||
this._trackSwapsMetrics(latestTxMeta, approvalTxMeta);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error(err);
|
log.error(err);
|
||||||
@ -1600,21 +1624,10 @@ export default class TransactionController extends EventEmitter {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (txMeta.type === TRANSACTION_TYPES.SWAP) {
|
if (txMeta.type === TRANSACTION_TYPES.SWAP) {
|
||||||
const postTxBalance = await this.query.getBalance(txMeta.txParams.from);
|
await this.updatePostTxBalance({
|
||||||
const latestTxMeta = this.txStateManager.getTransaction(txId);
|
txMeta,
|
||||||
|
txId,
|
||||||
const approvalTxMeta = latestTxMeta.approvalTxId
|
});
|
||||||
? this.txStateManager.getTransaction(latestTxMeta.approvalTxId)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
latestTxMeta.postTxBalance = postTxBalance.toString(16);
|
|
||||||
|
|
||||||
this.txStateManager.updateTransaction(
|
|
||||||
latestTxMeta,
|
|
||||||
'transactions#confirmTransaction - add postTxBalance',
|
|
||||||
);
|
|
||||||
|
|
||||||
this._trackSwapsMetrics(latestTxMeta, approvalTxMeta);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error(err);
|
log.error(err);
|
||||||
|
@ -758,6 +758,12 @@ export function getSwapsTokensReceivedFromTxMeta(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (txMeta.swapMetaData && txMeta.preTxBalance === txMeta.postTxBalance) {
|
||||||
|
// If preTxBalance and postTxBalance are equal, postTxBalance hasn't been updated on time
|
||||||
|
// because of the RPC provider delay, so we return an estimated receiving amount instead.
|
||||||
|
return txMeta.swapMetaData.token_to_amount;
|
||||||
|
}
|
||||||
|
|
||||||
let approvalTxGasCost = '0x0';
|
let approvalTxGasCost = '0x0';
|
||||||
if (approvalTxMeta && approvalTxMeta.txReceipt) {
|
if (approvalTxMeta && approvalTxMeta.txReceipt) {
|
||||||
approvalTxGasCost = calcGasTotal(
|
approvalTxGasCost = calcGasTotal(
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
RINKEBY_CHAIN_ID,
|
RINKEBY_CHAIN_ID,
|
||||||
KOVAN_CHAIN_ID,
|
KOVAN_CHAIN_ID,
|
||||||
AVALANCHE_CHAIN_ID,
|
AVALANCHE_CHAIN_ID,
|
||||||
|
ETH_SYMBOL,
|
||||||
} from '../../../shared/constants/network';
|
} from '../../../shared/constants/network';
|
||||||
import {
|
import {
|
||||||
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP,
|
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP,
|
||||||
@ -39,6 +40,7 @@ import {
|
|||||||
countDecimals,
|
countDecimals,
|
||||||
shouldEnableDirectWrapping,
|
shouldEnableDirectWrapping,
|
||||||
showRemainingTimeInMinAndSec,
|
showRemainingTimeInMinAndSec,
|
||||||
|
getSwapsTokensReceivedFromTxMeta,
|
||||||
} from './swaps.util';
|
} from './swaps.util';
|
||||||
|
|
||||||
jest.mock('../../helpers/utils/storage-helpers.js', () => ({
|
jest.mock('../../helpers/utils/storage-helpers.js', () => ({
|
||||||
@ -567,4 +569,106 @@ describe('Swaps Util', () => {
|
|||||||
expect(true).toBe(true);
|
expect(true).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getSwapsTokensReceivedFromTxMeta', () => {
|
||||||
|
const createProps = () => {
|
||||||
|
return {
|
||||||
|
tokenSymbol: ETH_SYMBOL,
|
||||||
|
txMeta: {
|
||||||
|
swapMetaData: {
|
||||||
|
token_to_amount: 5,
|
||||||
|
},
|
||||||
|
txReceipt: {
|
||||||
|
status: '0x0',
|
||||||
|
},
|
||||||
|
preTxBalance: '8b11',
|
||||||
|
postTxBalance: '8b11',
|
||||||
|
},
|
||||||
|
tokenAddress: '0x881d40237659c251811cec9c364ef91234567890',
|
||||||
|
accountAddress: '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f',
|
||||||
|
tokenDecimals: 6,
|
||||||
|
approvalTxMeta: null,
|
||||||
|
chainId: MAINNET_CHAIN_ID,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
it('returns an estimated amount if preTxBalance and postTxBalance are the same for ETH', () => {
|
||||||
|
const props = createProps();
|
||||||
|
expect(
|
||||||
|
getSwapsTokensReceivedFromTxMeta(
|
||||||
|
props.tokenSymbol,
|
||||||
|
props.txMeta,
|
||||||
|
props.tokenAddress,
|
||||||
|
props.accountAddress,
|
||||||
|
props.tokenDecimals,
|
||||||
|
props.approvalTxMeta,
|
||||||
|
props.chainId,
|
||||||
|
),
|
||||||
|
).toBe(props.txMeta.swapMetaData.token_to_amount);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null if there is no txMeta', () => {
|
||||||
|
const props = createProps();
|
||||||
|
props.txMeta = undefined;
|
||||||
|
expect(
|
||||||
|
getSwapsTokensReceivedFromTxMeta(
|
||||||
|
props.tokenSymbol,
|
||||||
|
props.txMeta,
|
||||||
|
props.tokenAddress,
|
||||||
|
props.accountAddress,
|
||||||
|
props.tokenDecimals,
|
||||||
|
props.approvalTxMeta,
|
||||||
|
props.chainId,
|
||||||
|
),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null if there is no txMeta.txReceipt', () => {
|
||||||
|
const props = createProps();
|
||||||
|
props.txMeta.txReceipt = undefined;
|
||||||
|
expect(
|
||||||
|
getSwapsTokensReceivedFromTxMeta(
|
||||||
|
props.tokenSymbol,
|
||||||
|
props.txMeta,
|
||||||
|
props.tokenAddress,
|
||||||
|
props.accountAddress,
|
||||||
|
props.tokenDecimals,
|
||||||
|
props.approvalTxMeta,
|
||||||
|
props.chainId,
|
||||||
|
),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null if there is no txMeta.postTxBalance', () => {
|
||||||
|
const props = createProps();
|
||||||
|
props.txMeta.postTxBalance = undefined;
|
||||||
|
expect(
|
||||||
|
getSwapsTokensReceivedFromTxMeta(
|
||||||
|
props.tokenSymbol,
|
||||||
|
props.txMeta,
|
||||||
|
props.tokenAddress,
|
||||||
|
props.accountAddress,
|
||||||
|
props.tokenDecimals,
|
||||||
|
props.approvalTxMeta,
|
||||||
|
props.chainId,
|
||||||
|
),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null if there is no txMeta.preTxBalance', () => {
|
||||||
|
const props = createProps();
|
||||||
|
props.txMeta.preTxBalance = undefined;
|
||||||
|
expect(
|
||||||
|
getSwapsTokensReceivedFromTxMeta(
|
||||||
|
props.tokenSymbol,
|
||||||
|
props.txMeta,
|
||||||
|
props.tokenAddress,
|
||||||
|
props.accountAddress,
|
||||||
|
props.tokenDecimals,
|
||||||
|
props.approvalTxMeta,
|
||||||
|
props.chainId,
|
||||||
|
),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user