1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-22 09:23:21 +01:00

Swaps / STX improvements (#14622)

This commit is contained in:
Daniel 2022-05-09 18:48:14 +02:00 committed by GitHub
parent 9e401b14bf
commit 2bd7127433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 104 additions and 40 deletions

View File

@ -19,6 +19,11 @@ import {
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP,
} from '../../../shared/constants/swaps';
import { GAS_ESTIMATE_TYPES } from '../../../shared/constants/gas';
import {
FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
FALLBACK_SMART_TRANSACTIONS_DEADLINE,
FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER,
} from '../../../shared/constants/smartTransactions';
import { isSwapsDefaultTokenAddress } from '../../../shared/modules/swaps.utils';
@ -41,8 +46,6 @@ const POLL_COUNT_LIMIT = 3;
// If for any reason the MetaSwap API fails to provide a refresh time,
// provide a reasonable fallback to avoid further errors
const FALLBACK_QUOTE_REFRESH_TIME = MINUTE;
const FALLBACK_SMART_TRANSACTION_REFRESH_TIME = SECOND * 10;
const FALLBACK_SMART_TRANSACTIONS_DEADLINE = 180;
function calculateGasEstimateWithRefund(
maxGas = MAX_GAS_LIMIT,
@ -86,8 +89,9 @@ const initialState = {
saveFetchedQuotes: false,
swapsQuoteRefreshTime: FALLBACK_QUOTE_REFRESH_TIME,
swapsQuotePrefetchingRefreshTime: FALLBACK_QUOTE_REFRESH_TIME,
swapsStxBatchStatusRefreshTime: FALLBACK_SMART_TRANSACTION_REFRESH_TIME,
swapsStxGetTransactionsRefreshTime: FALLBACK_SMART_TRANSACTION_REFRESH_TIME,
swapsStxBatchStatusRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxGetTransactionsRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxMaxFeeMultiplier: FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER,
swapsFeatureFlags: {},
},
};
@ -129,13 +133,13 @@ export default class SwapsController {
});
}
async fetchSwapsRefreshRates(chainId) {
async fetchSwapsNetworkConfig(chainId) {
const response = await fetchWithCache(
getBaseApi('network', chainId),
{ method: 'GET' },
{ cacheRefreshTime: 600000 },
);
const { refreshRates } = response || {};
const { refreshRates, parameters = {} } = response || {};
if (
!refreshRates ||
typeof refreshRates.quotes !== 'number' ||
@ -152,35 +156,39 @@ export default class SwapsController {
stxGetTransactions: refreshRates.stxGetTransactions * 1000,
stxBatchStatus: refreshRates.stxBatchStatus * 1000,
stxStatusDeadline: refreshRates.stxStatusDeadline,
stxMaxFeeMultiplier: parameters.stxMaxFeeMultiplier,
};
}
// Sets the refresh rate for quote updates from the MetaSwap API
async _setSwapsRefreshRates() {
// Sets the network config from the MetaSwap API.
async _setSwapsNetworkConfig() {
const chainId = this._getCurrentChainId();
let swapsRefreshRates;
let swapsNetworkConfig;
try {
swapsRefreshRates = await this.fetchSwapsRefreshRates(chainId);
swapsNetworkConfig = await this.fetchSwapsNetworkConfig(chainId);
} catch (e) {
console.error('Request for swaps quote refresh time failed: ', e);
console.error('Request for Swaps network config failed: ', e);
}
const { swapsState: latestSwapsState } = this.store.getState();
this.store.updateState({
swapsState: {
...latestSwapsState,
swapsQuoteRefreshTime:
swapsRefreshRates?.quotes || FALLBACK_QUOTE_REFRESH_TIME,
swapsNetworkConfig?.quotes || FALLBACK_QUOTE_REFRESH_TIME,
swapsQuotePrefetchingRefreshTime:
swapsRefreshRates?.quotesPrefetching || FALLBACK_QUOTE_REFRESH_TIME,
swapsNetworkConfig?.quotesPrefetching || FALLBACK_QUOTE_REFRESH_TIME,
swapsStxGetTransactionsRefreshTime:
swapsRefreshRates?.stxGetTransactions ||
FALLBACK_SMART_TRANSACTION_REFRESH_TIME,
swapsNetworkConfig?.stxGetTransactions ||
FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxBatchStatusRefreshTime:
swapsRefreshRates?.stxBatchStatus ||
FALLBACK_SMART_TRANSACTION_REFRESH_TIME,
swapsNetworkConfig?.stxBatchStatus ||
FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxStatusDeadline:
swapsRefreshRates?.stxStatusDeadline ||
swapsNetworkConfig?.stxStatusDeadline ||
FALLBACK_SMART_TRANSACTIONS_DEADLINE,
swapsStxMaxFeeMultiplier:
swapsNetworkConfig?.stxMaxFeeMultiplier ||
FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER,
},
});
}
@ -253,7 +261,7 @@ export default class SwapsController {
this._fetchTradesInfo(fetchParams, {
...fetchParamsMetaData,
}),
this._setSwapsRefreshRates(),
this._setSwapsNetworkConfig(),
]);
const {

View File

@ -13,6 +13,10 @@ import { ETH_SWAPS_TOKEN_OBJECT } from '../../../shared/constants/swaps';
import { createTestProviderTools } from '../../../test/stub/provider';
import { SECOND } from '../../../shared/constants/time';
import { GAS_ESTIMATE_TYPES } from '../../../shared/constants/gas';
import {
FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER,
} from '../../../shared/constants/smartTransactions';
import SwapsController, { utils } from './swaps';
import { NETWORK_EVENTS } from './network';
@ -134,8 +138,9 @@ const EMPTY_INIT_STATE = {
swapsFeatureFlags: {},
swapsQuoteRefreshTime: 60000,
swapsQuotePrefetchingRefreshTime: 60000,
swapsStxBatchStatusRefreshTime: 10000,
swapsStxGetTransactionsRefreshTime: 10000,
swapsStxBatchStatusRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxGetTransactionsRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxMaxFeeMultiplier: FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER,
swapsUserFeeLevel: '',
saveFetchedQuotes: false,
},

View File

@ -18,10 +18,12 @@ import {
getChainType,
} from '../../lib/util';
import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/helpers/constants/error-keys';
import { calcGasTotal } from '../../../../ui/pages/send/send.utils';
import { getSwapsTokensReceivedFromTxMeta } from '../../../../ui/pages/swaps/swaps.util';
import {
hexWEIToDecGWEI,
decimalToHex,
hexWEIToDecETH,
} from '../../../../ui/helpers/utils/conversions.util';
import {
TRANSACTION_STATUSES,
@ -1877,6 +1879,30 @@ export default class TransactionController extends EventEmitter {
this.memStore.updateState({ unapprovedTxs, currentNetworkTxList });
}
_calculateTransactionsCost(txMeta, approvalTxMeta) {
let approvalGasCost = '0x0';
if (approvalTxMeta?.txReceipt) {
approvalGasCost = calcGasTotal(
approvalTxMeta.txReceipt.gasUsed,
approvalTxMeta.txReceipt.effectiveGasPrice,
);
}
const tradeGasCost = calcGasTotal(
txMeta.txReceipt.gasUsed,
txMeta.txReceipt.effectiveGasPrice,
);
const tradeAndApprovalGasCost = new BigNumber(tradeGasCost, 16)
.plus(approvalGasCost, 16)
.toString(16);
return {
approvalGasCostInEth: Number(hexWEIToDecETH(approvalGasCost)),
tradeGasCostInEth: Number(hexWEIToDecETH(tradeGasCost)),
tradeAndApprovalGasCostInEth: Number(
hexWEIToDecETH(tradeAndApprovalGasCost),
),
};
}
_trackSwapsMetrics(txMeta, approvalTxMeta) {
if (this._getParticipateInMetrics() && txMeta.swapMetaData) {
if (txMeta.txReceipt.status === '0x0') {
@ -1911,6 +1937,11 @@ export default class TransactionController extends EventEmitter {
.round(2)}%`
: null;
const transactionsCost = this._calculateTransactionsCost(
txMeta,
approvalTxMeta,
);
this._trackMetaMetricsEvent({
event: 'Swap Completed',
category: EVENT.CATEGORIES.SWAPS,
@ -1919,6 +1950,10 @@ export default class TransactionController extends EventEmitter {
token_to_amount_received: tokensReceived,
quote_vs_executionRatio: quoteVsExecutionRatio,
estimated_vs_used_gasRatio: estimatedVsUsedGasRatio,
approval_gas_cost_in_eth: transactionsCost.approvalGasCostInEth,
trade_gas_cost_in_eth: transactionsCost.tradeGasCostInEth,
trade_and_approval_gas_cost_in_eth:
transactionsCost.tradeAndApprovalGasCostInEth,
},
});
}

View File

@ -0,0 +1,5 @@
import { SECOND } from './time';
export const FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME = SECOND * 10;
export const FALLBACK_SMART_TRANSACTIONS_DEADLINE = 180;
export const FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER = 2;

View File

@ -445,13 +445,14 @@ export const getSmartTransactionEstimatedGas = (state) => {
return state.metamask.smartTransactionsState?.estimatedGas;
};
export const getSwapsRefreshStates = (state) => {
export const getSwapsNetworkConfig = (state) => {
const {
swapsQuoteRefreshTime,
swapsQuotePrefetchingRefreshTime,
swapsStxGetTransactionsRefreshTime,
swapsStxBatchStatusRefreshTime,
swapsStxStatusDeadline,
swapsStxMaxFeeMultiplier,
} = state.metamask.swapsState;
return {
quoteRefreshTime: swapsQuoteRefreshTime,
@ -459,6 +460,7 @@ export const getSwapsRefreshStates = (state) => {
stxGetTransactionsRefreshTime: swapsStxGetTransactionsRefreshTime,
stxBatchStatusRefreshTime: swapsStxBatchStatusRefreshTime,
stxStatusDeadline: swapsStxStatusDeadline,
stxMaxFeeMultiplier: swapsStxMaxFeeMultiplier,
};
};
@ -855,12 +857,12 @@ export const signAndSendSwapsSmartTransaction = ({
const { metaData, value: swapTokenValue, slippage } = fetchParams;
const { sourceTokenInfo = {}, destinationTokenInfo = {} } = metaData;
const usedQuote = getUsedQuote(state);
const swapsRefreshStates = getSwapsRefreshStates(state);
const swapsNetworkConfig = getSwapsNetworkConfig(state);
const chainId = getCurrentChainId(state);
dispatch(
setSmartTransactionsRefreshInterval(
swapsRefreshStates?.stxBatchStatusRefreshTime,
swapsNetworkConfig?.stxBatchStatusRefreshTime,
),
);

View File

@ -12,7 +12,7 @@ import {
getSmartTransactionsOptInStatus,
getSmartTransactionsEnabled,
getCurrentSmartTransactionsEnabled,
getSwapsRefreshStates,
getSwapsNetworkConfig,
cancelSwapsSmartTransaction,
} from '../../../ducks/swaps/swaps';
import {
@ -71,7 +71,7 @@ export default function SmartTransactionStatus() {
const smartTransactionsOptInStatus = useSelector(
getSmartTransactionsOptInStatus,
);
const swapsRefreshRates = useSelector(getSwapsRefreshStates);
const swapsNetworkConfig = useSelector(getSwapsNetworkConfig);
const smartTransactionsEnabled = useSelector(getSmartTransactionsEnabled);
const currentSmartTransactionsEnabled = useSelector(
getCurrentSmartTransactionsEnabled,
@ -89,7 +89,7 @@ export default function SmartTransactionStatus() {
}
const [timeLeftForPendingStxInSec, setTimeLeftForPendingStxInSec] = useState(
swapsRefreshRates.stxStatusDeadline,
swapsNetworkConfig.stxStatusDeadline,
);
const sensitiveProperties = {
@ -139,13 +139,13 @@ export default function SmartTransactionStatus() {
const secondsAfterStxSubmission = Math.round(
(Date.now() - latestSmartTransaction.time) / 1000,
);
if (secondsAfterStxSubmission > swapsRefreshRates.stxStatusDeadline) {
if (secondsAfterStxSubmission > swapsNetworkConfig.stxStatusDeadline) {
setTimeLeftForPendingStxInSec(0);
clearInterval(intervalId);
return;
}
setTimeLeftForPendingStxInSec(
swapsRefreshRates.stxStatusDeadline - secondsAfterStxSubmission,
swapsNetworkConfig.stxStatusDeadline - secondsAfterStxSubmission,
);
};
intervalId = setInterval(calculateRemainingTime, 1000);
@ -158,7 +158,7 @@ export default function SmartTransactionStatus() {
isSmartTransactionPending,
latestSmartTransactionUuid,
latestSmartTransaction.time,
swapsRefreshRates.stxStatusDeadline,
swapsNetworkConfig.stxStatusDeadline,
]);
useEffect(() => {
@ -358,8 +358,8 @@ export default function SmartTransactionStatus() {
className="smart-transaction-status__loading-bar"
style={{
width: `${
(100 / swapsRefreshRates.stxStatusDeadline) *
(swapsRefreshRates.stxStatusDeadline -
(100 / swapsNetworkConfig.stxStatusDeadline) *
(swapsNetworkConfig.stxStatusDeadline -
timeLeftForPendingStxInSec)
}%`,
}}

View File

@ -500,6 +500,7 @@ export const getFeeForSmartTransaction = ({
chainId,
currentCurrency,
conversionRate,
USDConversionRate,
nativeCurrencySymbol,
feeInWeiDec,
}) => {
@ -522,7 +523,7 @@ export const getFeeForSmartTransaction = ({
feeInUsd = getValueFromWeiHex({
value: feeInWeiHex,
toCurrency: USD_CURRENCY_CODE,
conversionRate,
conversionRate: USDConversionRate,
numberOfDecimals: 2,
});
}
@ -543,6 +544,7 @@ export function getRenderableNetworkFeesForQuote({
gasPrice,
currentCurrency,
conversionRate,
USDConversionRate,
tradeValue,
sourceSymbol,
sourceAmount,
@ -585,7 +587,7 @@ export function getRenderableNetworkFeesForQuote({
feeInUsd = getValueFromWeiHex({
value: totalWeiCost,
toCurrency: USD_CURRENCY_CODE,
conversionRate,
conversionRate: USDConversionRate,
numberOfDecimals: 2,
});
}

View File

@ -43,7 +43,7 @@ import {
getReviewSwapClickedTimestamp,
getSmartTransactionsOptInStatus,
signAndSendSwapsSmartTransaction,
getSwapsRefreshStates,
getSwapsNetworkConfig,
getSmartTransactionsEnabled,
getCurrentSmartTransactionsError,
getCurrentSmartTransactionsErrorMessageDismissed,
@ -62,6 +62,7 @@ import {
getHardwareWalletType,
checkNetworkAndAccountSupports1559,
getEIP1559V2Enabled,
getUSDConversionRate,
} from '../../../selectors';
import { getNativeCurrency, getTokens } from '../../../ducks/metamask/metamask';
@ -171,6 +172,7 @@ export default function ViewQuote() {
const memoizedTokenConversionRates = useEqualityCheck(tokenConversionRates);
const { balance: ethBalance } = useSelector(getSelectedAccount, shallowEqual);
const conversionRate = useSelector(conversionRateSelector);
const USDConversionRate = useSelector(getUSDConversionRate);
const currentCurrency = useSelector(getCurrentCurrency);
const swapsTokens = useSelector(getTokens, isEqual);
const networkAndAccountSupports1559 = useSelector(
@ -209,7 +211,7 @@ export default function ViewQuote() {
const smartTransactionEstimatedGas = useSelector(
getSmartTransactionEstimatedGas,
);
const swapsRefreshRates = useSelector(getSwapsRefreshStates);
const swapsNetworkConfig = useSelector(getSwapsNetworkConfig);
const unsignedTransaction = usedQuote.trade;
let gasFeeInputs;
@ -360,6 +362,7 @@ export default function ViewQuote() {
: gasPrice,
currentCurrency,
conversionRate,
USDConversionRate,
tradeValue,
sourceSymbol: sourceTokenSymbol,
sourceAmount: usedQuote.sourceAmount,
@ -375,6 +378,7 @@ export default function ViewQuote() {
gasPrice: maxFeePerGas || gasPrice,
currentCurrency,
conversionRate,
USDConversionRate,
tradeValue,
sourceSymbol: sourceTokenSymbol,
sourceAmount: usedQuote.sourceAmount,
@ -399,11 +403,13 @@ export default function ViewQuote() {
const stxEstimatedFeeInWeiDec =
smartTransactionEstimatedGas.txData.feeEstimate +
(smartTransactionEstimatedGas.approvalTxData?.feeEstimate || 0);
const stxMaxFeeInWeiDec = stxEstimatedFeeInWeiDec * 2;
const stxMaxFeeInWeiDec =
stxEstimatedFeeInWeiDec * swapsNetworkConfig.stxMaxFeeMultiplier;
({ feeInFiat, feeInEth, rawEthFee, feeInUsd } = getFeeForSmartTransaction({
chainId,
currentCurrency,
conversionRate,
USDConversionRate,
nativeCurrencySymbol,
feeInWeiDec: stxEstimatedFeeInWeiDec,
}));
@ -420,6 +426,7 @@ export default function ViewQuote() {
chainId,
currentCurrency,
conversionRate,
USDConversionRate,
nativeCurrencySymbol,
feeInWeiDec: stxMaxFeeInWeiDec,
}));
@ -835,7 +842,7 @@ export default function ViewQuote() {
dispatch(
estimateSwapsSmartTransactionsGas(unsignedTx, approveTxParams),
);
}, swapsRefreshRates.stxGetTransactionsRefreshTime);
}, swapsNetworkConfig.stxGetTransactionsRefreshTime);
dispatch(estimateSwapsSmartTransactionsGas(unsignedTx, approveTxParams));
} else if (intervalId) {
clearInterval(intervalId);
@ -852,7 +859,7 @@ export default function ViewQuote() {
unsignedTransaction.gas,
unsignedTransaction.to,
chainId,
swapsRefreshRates.stxGetTransactionsRefreshTime,
swapsNetworkConfig.stxGetTransactionsRefreshTime,
isSwapButtonDisabled,
]);

View File

@ -671,7 +671,7 @@ export function getSwapsDefaultToken(state) {
export function getIsSwapsChain(state) {
const chainId = getCurrentChainId(state);
const isNotDevelopment =
process.env.METAMASK_ENVIRONMENT !== 'development' ||
process.env.METAMASK_ENVIRONMENT !== 'development' &&
process.env.METAMASK_ENVIRONMENT !== 'testing';
return isNotDevelopment
? ALLOWED_PROD_SWAPS_CHAIN_IDS.includes(chainId)