Skip to content

Commit

Permalink
feat: Enable gas included swaps (#27427)
Browse files Browse the repository at this point in the history
  • Loading branch information
dan437 authored Oct 1, 2024
1 parent cf55b09 commit facf905
Show file tree
Hide file tree
Showing 15 changed files with 424 additions and 113 deletions.
16 changes: 16 additions & 0 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions app/scripts/controllers/swaps/swaps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const MOCK_FETCH_PARAMS: FetchTradesInfoParams = {
fromAddress: '0x7F18BB4Dd92CF2404C54CBa1A9BE4A1153bdb078',
exchangeList: 'zeroExV1',
balanceError: false,
enableGasIncludedQuotes: false,
};

const TEST_AGG_ID_1 = 'TEST_AGG_1';
Expand Down Expand Up @@ -1164,6 +1165,7 @@ describe('SwapsController', function () {
fromAddress: '',
exchangeList: 'zeroExV1',
balanceError: false,
enableGasIncludedQuotes: false,
metaData: {} as FetchTradesInfoParamsMetadata,
};
const swapsFeatureIsLive = false;
Expand Down
1 change: 1 addition & 0 deletions app/scripts/controllers/swaps/swaps.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ export type FetchTradesInfoParams = {
fromAddress: string;
exchangeList: string;
balanceError: boolean;
enableGasIncludedQuotes: boolean;
};

export type FetchTradesInfoParamsMetadata = {
Expand Down
2 changes: 2 additions & 0 deletions shared/lib/swaps-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ export async function fetchTradesInfo(
value,
fromAddress,
exchangeList,
enableGasIncludedQuotes,
},
{ chainId },
) {
Expand All @@ -275,6 +276,7 @@ export async function fetchTradesInfo(
slippage,
timeout: SECOND * 10,
walletAddress: fromAddress,
enableGasIncludedQuotes,
};

if (exchangeList) {
Expand Down
1 change: 1 addition & 0 deletions shared/lib/swaps-utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ describe('Swaps Utils', () => {
sourceDecimals: TOKENS[0].decimals,
sourceTokenInfo: { ...TOKENS[0] },
destinationTokenInfo: { ...TOKENS[1] },
enableGasIncludedQuotes: false,
},
{ chainId: CHAIN_IDS.MAINNET },
);
Expand Down
49 changes: 48 additions & 1 deletion test/jest/mock-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ export const createSwapsMockStore = () => {
},
],
useCurrencyRateCheck: true,
currentCurrency: 'ETH',
currentCurrency: 'usd',
currencyRates: {
ETH: {
conversionRate: 1,
Expand Down Expand Up @@ -469,6 +469,23 @@ export const createSwapsMockStore = () => {
decimals: 18,
},
fee: 1,
isGasIncludedTrade: false,
approvalTxFees: {
feeEstimate: 42000000000000,
fees: [
{ maxFeePerGas: 2310003200, maxPriorityFeePerGas: 513154852 },
],
gasLimit: 21000,
gasUsed: 21000,
},
tradeTxFees: {
feeEstimate: 42000000000000,
fees: [
{ maxFeePerGas: 2310003200, maxPriorityFeePerGas: 513154852 },
],
gasLimit: 21000,
gasUsed: 21000,
},
},
TEST_AGG_2: {
trade: {
Expand Down Expand Up @@ -503,6 +520,36 @@ export const createSwapsMockStore = () => {
decimals: 18,
},
fee: 1,
isGasIncludedTrade: false,
approvalTxFees: {
feeEstimate: 42000000000000,
fees: [
{ maxFeePerGas: 2310003200, maxPriorityFeePerGas: 513154852 },
],
gasLimit: 21000,
gasUsed: 21000,
},
tradeTxFees: {
feeEstimate: 42000000000000,
fees: [
{
maxFeePerGas: 2310003200,
maxPriorityFeePerGas: 513154852,
tokenFees: [
{
token: {
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
symbol: 'DAI',
decimals: 18,
},
balanceNeededToken: '0x426dc933c2e5a',
},
],
},
],
gasLimit: 21000,
gasUsed: 21000,
},
},
},
fetchParams: {
Expand Down
31 changes: 23 additions & 8 deletions ui/ducks/swaps/swaps.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,14 @@ export const getPendingSmartTransactions = (state) => {
};

export const getSmartTransactionFees = (state) => {
return state.metamask.smartTransactionsState?.fees;
const usedQuote = getUsedQuote(state);
if (!usedQuote?.isGasIncludedTrade) {
return state.metamask.smartTransactionsState?.fees;
}
return {
approvalTxFees: usedQuote.approvalTxFees,
tradeTxFees: usedQuote.tradeTxFees,
};
};

export const getSmartTransactionEstimatedGas = (state) => {
Expand Down Expand Up @@ -780,6 +787,8 @@ export const fetchQuotesAndSetQuoteState = (
fromAddress: selectedAccount.address,
balanceError,
sourceDecimals: fromTokenDecimals,
enableGasIncludedQuotes:
currentSmartTransactionsEnabled && smartTransactionsOptInStatus,
},
{
sourceTokenInfo,
Expand Down Expand Up @@ -933,6 +942,7 @@ export const signAndSendSwapsSmartTransaction = ({
stx_enabled: smartTransactionsEnabled,
current_stx_enabled: currentSmartTransactionsEnabled,
stx_user_opt_in: smartTransactionsOptInStatus,
is_gas_included_trade: usedQuote.isGasIncludedTrade,
...additionalTrackingParams,
};
trackEvent({
Expand Down Expand Up @@ -964,13 +974,18 @@ export const signAndSendSwapsSmartTransaction = ({
value: '0x0',
};
}
const fees = await dispatch(
fetchSwapsSmartTransactionFees({
unsignedTransaction,
approveTxParams: updatedApproveTxParams,
fallbackOnNotEnoughFunds: true,
}),
);
let fees;
if (usedQuote.isGasIncludedTrade) {
fees = getSmartTransactionFees(state);
} else {
fees = await dispatch(
fetchSwapsSmartTransactionFees({
unsignedTransaction,
approveTxParams: updatedApproveTxParams,
fallbackOnNotEnoughFunds: true,
}),
);
}
if (!fees) {
log.error('"fetchSwapsSmartTransactionFees" failed');
dispatch(setSwapsSTXSubmitLoading(false));
Expand Down
25 changes: 24 additions & 1 deletion ui/ducks/swaps/swaps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -652,13 +652,36 @@ describe('Ducks - Swaps', () => {
});

describe('getSmartTransactionFees', () => {
it('returns unsigned transactions and estimates', () => {
it('returns estimates from the STX controller', () => {
const state = createSwapsMockStore();
const smartTransactionFees = swaps.getSmartTransactionFees(state);
expect(smartTransactionFees).toMatchObject(
state.metamask.smartTransactionsState.fees,
);
});

it('returns estimates from a selected quote', () => {
const state = createSwapsMockStore();
state.metamask.swapsState.quotes.TEST_AGG_2.isGasIncludedTrade = true;
const smartTransactionFees = swaps.getSmartTransactionFees(state);
expect(smartTransactionFees).toMatchObject({
approvalTxFees:
state.metamask.swapsState.quotes.TEST_AGG_2.approvalTxFees,
tradeTxFees: state.metamask.swapsState.quotes.TEST_AGG_2.tradeTxFees,
});
});

it('returns estimates from a top quote if no quote is selected', () => {
const state = createSwapsMockStore();
state.metamask.swapsState.selectedAggId = null;
state.metamask.swapsState.quotes.TEST_AGG_BEST.isGasIncludedTrade = true;
const smartTransactionFees = swaps.getSmartTransactionFees(state);
expect(smartTransactionFees).toMatchObject({
approvalTxFees:
state.metamask.swapsState.quotes.TEST_AGG_BEST.approvalTxFees,
tradeTxFees: state.metamask.swapsState.quotes.TEST_AGG_BEST.tradeTxFees,
});
});
});

describe('getSmartTransactionEstimatedGas', () => {
Expand Down
2 changes: 2 additions & 0 deletions ui/helpers/constants/zendesk-url.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const ZENDESK_URLS = {
CUSTOMIZE_NONCE:
'https://support.metamask.io/transactions-and-gas/transactions/how-to-customize-a-transaction-nonce/',
GAS_FEES: 'https://support.metamask.io/transactions-and-gas/gas-fees/',
SWAPS_GAS_FEES:
'https://support.metamask.io/token-swaps/user-guide-swaps/#gas-fees',
HARDWARE_CONNECTION:
'https://support.metamask.io/privacy-and-security/hardware-wallet-hub/',
IMPORT_ACCOUNTS:
Expand Down
11 changes: 9 additions & 2 deletions ui/pages/swaps/prepare-swap-page/prepare-swap-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -782,10 +782,17 @@ export default function PrepareSwapPage({
);
}

const isNonDefaultToken = !isSwapsDefaultTokenSymbol(
fromTokenSymbol,
chainId,
);
const hasPositiveFromTokenBalance = rawFromTokenBalance > 0;
const isTokenEligibleForMaxBalance =
isSmartTransaction || (!isSmartTransaction && isNonDefaultToken);
const showMaxBalanceLink =
fromTokenSymbol &&
!isSwapsDefaultTokenSymbol(fromTokenSymbol, chainId) &&
rawFromTokenBalance > 0;
isTokenEligibleForMaxBalance &&
hasPositiveFromTokenBalance;

return (
<div className="prepare-swap-page">
Expand Down
Loading

0 comments on commit facf905

Please sign in to comment.