1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

feat(mme-17214): migrate L33 files to typescript (#17372)

This commit is contained in:
Danica Shen 2023-01-31 12:01:10 +00:00 committed by GitHub
parent 8a7c897a1c
commit 2958d68af8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 330 additions and 170 deletions

View File

@ -4,6 +4,9 @@ import { SWAPS_API_V2_BASE_URL } from '../../../shared/constants/swaps';
import { import {
BUYABLE_CHAINS_MAP, BUYABLE_CHAINS_MAP,
CHAIN_IDS, CHAIN_IDS,
WyreChainSettings,
CurrencySymbol,
ChainId,
} from '../../../shared/constants/network'; } from '../../../shared/constants/network';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'; import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
import { import {
@ -18,13 +21,17 @@ const fetchWithTimeout = getFetchWithTimeout();
/** /**
* Create a Wyre purchase URL. * Create a Wyre purchase URL.
* *
* @param {string} walletAddress - Ethereum destination address * @param walletAddress - Ethereum destination address
* @param {string} chainId - Current chain ID * @param chainId - Current chain ID
* @param {string|undefined} symbol - Token symbol to buy * @param symbol - Token symbol to buy
* @returns String * @returns String
*/ */
const createWyrePurchaseUrl = async (walletAddress, chainId, symbol) => { const createWyrePurchaseUrl = async (
const { wyre = {} } = BUYABLE_CHAINS_MAP[chainId]; walletAddress: string,
chainId: keyof typeof BUYABLE_CHAINS_MAP,
symbol: CurrencySymbol,
): Promise<any> => {
const { wyre = {} as WyreChainSettings } = BUYABLE_CHAINS_MAP[chainId];
const { srn, currencyCode } = wyre; const { srn, currencyCode } = wyre;
const networkId = parseInt(chainId, 16); const networkId = parseInt(chainId, 16);
@ -57,12 +64,16 @@ const createWyrePurchaseUrl = async (walletAddress, chainId, symbol) => {
* Create a Transak Checkout URL. * Create a Transak Checkout URL.
* API docs here: https://www.notion.so/Query-Parameters-9ec523df3b874ec58cef4fa3a906f238 * API docs here: https://www.notion.so/Query-Parameters-9ec523df3b874ec58cef4fa3a906f238
* *
* @param {string} walletAddress - Ethereum destination address * @param walletAddress - Ethereum destination address
* @param {string} chainId - Current chain ID * @param chainId - Current chain ID
* @param {string|undefined} symbol - Token symbol to buy * @param symbol - Token symbol to buy
* @returns String * @returns String
*/ */
const createTransakUrl = (walletAddress, chainId, symbol) => { const createTransakUrl = (
walletAddress: string,
chainId: keyof typeof BUYABLE_CHAINS_MAP,
symbol: CurrencySymbol,
): string => {
const { nativeCurrency, network } = BUYABLE_CHAINS_MAP[chainId]; const { nativeCurrency, network } = BUYABLE_CHAINS_MAP[chainId];
const queryParams = new URLSearchParams({ const queryParams = new URLSearchParams({
@ -79,13 +90,17 @@ const createTransakUrl = (walletAddress, chainId, symbol) => {
/** /**
* Create a MoonPay Checkout URL. * Create a MoonPay Checkout URL.
* *
* @param {string} walletAddress - Destination address * @param walletAddress - Destination address
* @param {string} chainId - Current chain ID * @param chainId - Current chain ID
* @param {string|undefined} symbol - Token symbol to buy * @param symbol - Token symbol to buy
* @returns String * @returns String
*/ */
const createMoonPayUrl = async (walletAddress, chainId, symbol) => { const createMoonPayUrl = async (
const { moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {} } = walletAddress: string,
chainId: keyof typeof BUYABLE_CHAINS_MAP,
symbol: CurrencySymbol,
): Promise<string> => {
const { moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {} as any } =
BUYABLE_CHAINS_MAP[chainId]; BUYABLE_CHAINS_MAP[chainId];
const moonPayQueryParams = new URLSearchParams({ const moonPayQueryParams = new URLSearchParams({
apiKey: MOONPAY_API_KEY, apiKey: MOONPAY_API_KEY,
@ -121,12 +136,16 @@ const createMoonPayUrl = async (walletAddress, chainId, symbol) => {
/** /**
* Create a Coinbase Pay Checkout URL. * Create a Coinbase Pay Checkout URL.
* *
* @param {string} walletAddress - Ethereum destination address * @param walletAddress - Ethereum destination address
* @param {string} chainId - Current chain ID * @param chainId - Current chain ID
* @param {string|undefined} symbol - Token symbol to buy * @param symbol - Token symbol to buy
* @returns String * @returns String
*/ */
const createCoinbasePayUrl = (walletAddress, chainId, symbol) => { const createCoinbasePayUrl = (
walletAddress: string,
chainId: keyof typeof BUYABLE_CHAINS_MAP,
symbol: CurrencySymbol,
): string => {
// since coinbasePayCurrencies is going to be extended to include all tokens supported // since coinbasePayCurrencies is going to be extended to include all tokens supported
// we now default to nativeCurrency instead of the 2 previous tokens + eth that we had before // we now default to nativeCurrency instead of the 2 previous tokens + eth that we had before
const { nativeCurrency } = BUYABLE_CHAINS_MAP[chainId]; const { nativeCurrency } = BUYABLE_CHAINS_MAP[chainId];
@ -146,15 +165,25 @@ const createCoinbasePayUrl = (walletAddress, chainId, symbol) => {
/** /**
* Gives the caller a url at which the user can acquire eth, depending on the network they are in * Gives the caller a url at which the user can acquire eth, depending on the network they are in
* *
* @param {object} opts - Options required to determine the correct url * @param opts - Options required to determine the correct url
* @param {string} opts.chainId - The chainId for which to return a url * @param opts.chainId - The chainId for which to return a url
* @param {string} opts.address - The address the bought ETH should be sent to. Only relevant if chainId === '0x1'. * @param opts.address - The address the bought ETH should be sent to. Only relevant if chainId === '0x1'.
* @param opts.service * @param opts.service
* @param {string|undefined} opts.symbol - The symbol of the token to buy. Only relevant if buying a token. * @param opts.symbol - The symbol of the token to buy. Only relevant if buying a token.
* @returns {string|undefined} The url at which the user can access ETH, while in the given chain. If the passed * @returns The url at which the user can access ETH, while in the given chain. If the passed
* chainId does not match any of the specified cases, or if no chainId is given, returns undefined. * chainId does not match any of the specified cases, or if no chainId is given, returns undefined.
*/ */
export default async function getBuyUrl({ chainId, address, service, symbol }) { export default async function getBuyUrl({
chainId,
address,
service,
symbol,
}: {
chainId: keyof typeof BUYABLE_CHAINS_MAP;
address: string;
service: string;
symbol: CurrencySymbol;
}): Promise<string> {
// default service by network if not specified // default service by network if not specified
if (!service) { if (!service) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
@ -183,7 +212,7 @@ export default async function getBuyUrl({ chainId, address, service, symbol }) {
} }
} }
function getDefaultServiceForChain(chainId) { function getDefaultServiceForChain(chainId: ChainId): string {
switch (chainId) { switch (chainId) {
case CHAIN_IDS.MAINNET: case CHAIN_IDS.MAINNET:
return 'wyre'; return 'wyre';

View File

@ -174,15 +174,19 @@ async function verifyEnglishLocale() {
// and gradually phase out the key based search // and gradually phase out the key based search
const globsToStrictSearch = [ const globsToStrictSearch = [
'ui/components/app/metamask-translation/*.js', 'ui/components/app/metamask-translation/*.js',
'ui/components/app/metamask-translation/*.ts',
'ui/pages/confirmation/templates/*.js', 'ui/pages/confirmation/templates/*.js',
'ui/pages/confirmation/templates/*.ts',
]; ];
const testGlob = '**/*.test.js'; const testGlob = '**/*.test.js';
const javascriptFiles = await glob( const javascriptFiles = await glob(
[ [
'ui/**/*.js', 'ui/**/*.js',
'ui/**/*.ts',
'shared/**/*.js', 'shared/**/*.js',
'shared/**/*.ts', 'shared/**/*.ts',
'app/scripts/constants/**/*.js', 'app/scripts/constants/**/*.js',
'app/scripts/constants/**/*.ts',
], ],
{ {
ignore: [...globsToStrictSearch, testGlob], ignore: [...globsToStrictSearch, testGlob],

View File

@ -306,7 +306,7 @@
"labeled-stream-splicer": "^2.0.2", "labeled-stream-splicer": "^2.0.2",
"localforage": "^1.9.0", "localforage": "^1.9.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"loglevel": "^1.4.1", "loglevel": "^1.8.1",
"luxon": "^3.2.1", "luxon": "^3.2.1",
"nanoid": "^2.1.6", "nanoid": "^2.1.6",
"nonce-tracker": "^1.0.0", "nonce-tracker": "^1.0.0",

View File

@ -17,7 +17,8 @@ export type ChainId = typeof CHAIN_IDS[keyof typeof CHAIN_IDS];
* This type is non-exhaustive, and cannot be used for areas where the user * This type is non-exhaustive, and cannot be used for areas where the user
* or dapp may supply their own symbol. * or dapp may supply their own symbol.
*/ */
type CurrencySymbol = typeof CURRENCY_SYMBOLS[keyof typeof CURRENCY_SYMBOLS]; export type CurrencySymbol =
typeof CURRENCY_SYMBOLS[keyof typeof CURRENCY_SYMBOLS];
/** /**
* A type that is a union type for the supported symbols on different onramp providers. * A type that is a union type for the supported symbols on different onramp providers.
*/ */
@ -41,7 +42,7 @@ type MoonPayNetworkAbbreviation = 'BSC' | 'CCHAIN' | 'POLYGON';
* MoonPay requires some settings that are configured per network that it is * MoonPay requires some settings that are configured per network that it is
* enabled on. This type describes those settings. * enabled on. This type describes those settings.
*/ */
type MoonPayChainSettings = { export type MoonPayChainSettings = {
/** /**
* What should the default onramp currency be, for example 'eth' on 'mainnet' * What should the default onramp currency be, for example 'eth' on 'mainnet'
* This type matches a single SupportedCurrencySymbol or a * This type matches a single SupportedCurrencySymbol or a
@ -77,7 +78,7 @@ type RPCPreferences = {
/** /**
* An object that describes a network to be used inside of MetaMask * An object that describes a network to be used inside of MetaMask
*/ */
type RPCDefinition = { export type RPCDefinition = {
/** /**
* The hex encoded ChainId for the network * The hex encoded ChainId for the network
*/ */
@ -104,7 +105,7 @@ type RPCDefinition = {
* Wyre is a fiat onramp provider. We must provide some settings for networks * Wyre is a fiat onramp provider. We must provide some settings for networks
* that support Wyre. * that support Wyre.
*/ */
type WyreChainSettings = { export type WyreChainSettings = {
/** /**
* The network name * The network name
*/ */

View File

@ -20,7 +20,7 @@ export const SWAPS_FETCH_ORDER_CONFLICT = 'swaps-fetch-order-conflict';
// in place of the token address that ERC-20 tokens have // in place of the token address that ERC-20 tokens have
const DEFAULT_TOKEN_ADDRESS = '0x0000000000000000000000000000000000000000'; const DEFAULT_TOKEN_ADDRESS = '0x0000000000000000000000000000000000000000';
interface SwapsTokenObject { export interface SwapsTokenObject {
/** /**
* The symbol of token object * The symbol of token object
*/ */

View File

@ -143,12 +143,13 @@ const getBaseUrlForNewSwapsApi = (type, chainId) => {
return `${v2ApiBaseUrl}/networks/${chainIdDecimal}`; return `${v2ApiBaseUrl}/networks/${chainIdDecimal}`;
}; };
export const getBaseApi = function (type, chainId = CHAIN_IDS.MAINNET) { export const getBaseApi = function (type, chainId) {
// eslint-disable-next-line no-param-reassign const _chainId = TEST_CHAIN_IDS.includes(chainId)
chainId = TEST_CHAIN_IDS.includes(chainId) ? CHAIN_IDS.MAINNET : chainId; ? CHAIN_IDS.MAINNET
const baseUrl = getBaseUrlForNewSwapsApi(type, chainId); : chainId;
const baseUrl = getBaseUrlForNewSwapsApi(type, _chainId);
if (!baseUrl) { if (!baseUrl) {
throw new Error(`Swaps API calls are disabled for chainId: ${chainId}`); throw new Error(`Swaps API calls are disabled for chainId: ${_chainId}`);
} }
switch (type) { switch (type) {
case 'trade': case 'trade':

1
shared/modules/declare-modules.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'human-standard-token-abi';

View File

@ -49,7 +49,7 @@ import {
isContractAddressValid, isContractAddressValid,
getSwapsLivenessForNetwork, getSwapsLivenessForNetwork,
parseSmartTransactionsError, parseSmartTransactionsError,
stxErrorTypes, StxErrorTypes,
} from '../../pages/swaps/swaps.util'; } from '../../pages/swaps/swaps.util';
import { import {
addHexes, addHexes,
@ -206,9 +206,9 @@ const slice = createSlice({
state.customGas.fallBackPrice = action.payload; state.customGas.fallBackPrice = action.payload;
}, },
setCurrentSmartTransactionsError: (state, action) => { setCurrentSmartTransactionsError: (state, action) => {
const errorType = Object.values(stxErrorTypes).includes(action.payload) const errorType = Object.values(StxErrorTypes).includes(action.payload)
? action.payload ? action.payload
: stxErrorTypes.UNAVAILABLE; : StxErrorTypes.UNAVAILABLE;
state.currentSmartTransactionsError = errorType; state.currentSmartTransactionsError = errorType;
}, },
setSwapsSTXSubmitLoading: (state, action) => { setSwapsSTXSubmitLoading: (state, action) => {
@ -554,7 +554,7 @@ const disableStxIfRegularTxInProgress = (dispatch, transactions) => {
for (const transaction of transactions) { for (const transaction of transactions) {
if (IN_PROGRESS_TRANSACTION_STATUSES.includes(transaction.status)) { if (IN_PROGRESS_TRANSACTION_STATUSES.includes(transaction.status)) {
dispatch( dispatch(
setCurrentSmartTransactionsError(stxErrorTypes.REGULAR_TX_IN_PROGRESS), setCurrentSmartTransactionsError(StxErrorTypes.REGULAR_TX_IN_PROGRESS),
); );
break; break;
} }
@ -581,8 +581,8 @@ export const fetchSwapsLivenessAndFeatureFlags = () => {
disableStxIfRegularTxInProgress(dispatch, transactions); disableStxIfRegularTxInProgress(dispatch, transactions);
} }
swapsLivenessForNetwork = getSwapsLivenessForNetwork( swapsLivenessForNetwork = getSwapsLivenessForNetwork(
swapsFeatureFlags,
chainId, chainId,
swapsFeatureFlags,
); );
} catch (error) { } catch (error) {
log.error( log.error(
@ -621,8 +621,8 @@ export const fetchQuotesAndSetQuoteState = (
try { try {
const swapsFeatureFlags = await fetchSwapsFeatureFlags(); const swapsFeatureFlags = await fetchSwapsFeatureFlags();
swapsLivenessForNetwork = getSwapsLivenessForNetwork( swapsLivenessForNetwork = getSwapsLivenessForNetwork(
swapsFeatureFlags,
chainId, chainId,
swapsFeatureFlags,
); );
} catch (error) { } catch (error) {
log.error('Failed to fetch Swaps liveness, defaulting to false.', error); log.error('Failed to fetch Swaps liveness, defaulting to false.', error);
@ -939,7 +939,7 @@ export const signAndSendSwapsSmartTransaction = ({
if (!fees) { if (!fees) {
log.error('"fetchSwapsSmartTransactionFees" failed'); log.error('"fetchSwapsSmartTransactionFees" failed');
dispatch(setSwapsSTXSubmitLoading(false)); dispatch(setSwapsSTXSubmitLoading(false));
dispatch(setCurrentSmartTransactionsError(stxErrorTypes.UNAVAILABLE)); dispatch(setCurrentSmartTransactionsError(StxErrorTypes.UNAVAILABLE));
return; return;
} }
if (approveTxParams) { if (approveTxParams) {
@ -1020,8 +1020,8 @@ export const signAndSendTransactions = (
try { try {
const swapsFeatureFlags = await fetchSwapsFeatureFlags(); const swapsFeatureFlags = await fetchSwapsFeatureFlags();
swapsLivenessForNetwork = getSwapsLivenessForNetwork( swapsLivenessForNetwork = getSwapsLivenessForNetwork(
swapsFeatureFlags,
chainId, chainId,
swapsFeatureFlags,
); );
} catch (error) { } catch (error) {
log.error('Failed to fetch Swaps liveness, defaulting to false.', error); log.error('Failed to fetch Swaps liveness, defaulting to false.', error);
@ -1329,7 +1329,7 @@ export function fetchSwapsSmartTransactionFees({
const errorObj = parseSmartTransactionsError(e.message); const errorObj = parseSmartTransactionsError(e.message);
if ( if (
fallbackOnNotEnoughFunds || fallbackOnNotEnoughFunds ||
errorObj?.error !== stxErrorTypes.NOT_ENOUGH_FUNDS errorObj?.error !== StxErrorTypes.NOT_ENOUGH_FUNDS
) { ) {
dispatch(setCurrentSmartTransactionsError(errorObj?.error)); dispatch(setCurrentSmartTransactionsError(errorObj?.error));
} }

View File

@ -129,7 +129,7 @@ describe('i18n helper', () => {
); );
}); });
it('should correctly render falsey substitutions', () => { it('should correctly render falsy substitutions', () => {
const result = t(TEST_KEY_4, [0, -0, '', false, NaN]); const result = t(TEST_KEY_4, [0, -0, '', false, NaN]);
expect(result).toStrictEqual('0 - 0 - - false - NaN'); expect(result).toStrictEqual('0 - 0 - - false - NaN');
}); });

View File

@ -1,25 +1,60 @@
// cross-browser connection to extension i18n API // cross-browser connection to extension i18n API
import React from 'react'; import React from 'react';
import log from 'loglevel'; import log from 'loglevel';
import { Json } from '@metamask/utils';
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'; import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
const fetchWithTimeout = getFetchWithTimeout(); const fetchWithTimeout = getFetchWithTimeout();
const warned = {}; // From app/_locales folders there is a messages.json file such as app/_locales/en, comes with key and translated results
const missingMessageErrors = {}; // and we use as t('reject') to get the translated message in the codebase
const missingSubstitutionErrors = {}; // and in i18n lib, the translated message is an object (I18NMessage) with message & description -
// message is the string that will replace the translationKey, and that message may contain replacement variables such as $1, $2, etc.
// Description is key describing the usage of the message.
interface I18NMessage {
message: string;
description?: string;
}
// The overall translation file is made of same entries
// translationKey (string) and the I18NMessage as the value.
interface I18NMessageDict {
[translationKey: string]: I18NMessage;
}
// A parameterized type (or generic type) of maps that use the same structure (translationKey) key
interface I18NMessageDictMap<R> {
[translationKey: string]: R;
}
const warned: { [localeCode: string]: I18NMessageDictMap<boolean> } = {};
const missingMessageErrors: I18NMessageDictMap<Error> = {};
const missingSubstitutionErrors: {
[localeCode: string]: I18NMessageDictMap<boolean>;
} = {};
function getHasSubstitutions(
substitutions?: string[],
): substitutions is string[] {
return (substitutions?.length ?? 0) > 0;
}
/** /**
* Returns a localized message for the given key * Returns a localized message for the given key
* *
* @param {string} localeCode - The code for the current locale * @param localeCode - The code for the current locale
* @param {object} localeMessages - The map of messages for the current locale * @param localeMessages - The map of messages for the current locale
* @param {string} key - The message key * @param key - The message key
* @param {string[]} substitutions - A list of message substitution replacements * @param substitutions - A list of message substitution replacements can replace $n in given message
* @returns {null|string} The localized message * @returns The localized message
*/ */
export const getMessage = (localeCode, localeMessages, key, substitutions) => { export const getMessage = (
localeCode: string,
localeMessages: I18NMessageDict,
key: string,
substitutions?: string[],
): JSX.Element | string | null => {
if (!localeMessages) { if (!localeMessages) {
return null; return null;
} }
@ -46,23 +81,22 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => {
} }
return null; return null;
} }
const entry = localeMessages[key];
let phrase = entry.message;
const hasSubstitutions = Boolean(substitutions && substitutions.length); const hasSubstitutions = getHasSubstitutions(substitutions);
const hasReactSubstitutions = const hasReactSubstitutions =
hasSubstitutions && hasSubstitutions &&
substitutions.some( substitutions?.some(
(element) => (element) =>
element !== null && element !== null &&
(typeof element === 'function' || typeof element === 'object'), (typeof element === 'function' || typeof element === 'object'),
); );
const entry = localeMessages[key];
const phrase = entry.message;
// perform substitutions // perform substitutions
if (hasSubstitutions) { if (hasSubstitutions) {
const parts = phrase.split(/(\$\d)/gu); const parts = phrase.split(/(\$\d)/gu);
const substitutedParts = parts.map((part) => { const substitutedParts = parts.map((part: string) => {
const subMatch = part.match(/\$(\d)/u); const subMatch = part.match(/\$(\d)/u);
if (!subMatch) { if (!subMatch) {
return part; return part;
@ -83,20 +117,21 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => {
log.error(error); log.error(error);
Sentry.captureException(error); Sentry.captureException(error);
} }
return substitutions[substituteIndex]; return substitutions?.[substituteIndex];
}); });
phrase = hasReactSubstitutions ? ( return hasReactSubstitutions ? (
<span> {substitutedParts} </span> <span> {substitutedParts} </span>
) : ( ) : (
substitutedParts.join('') substitutedParts.join('')
); );
} }
return phrase; return phrase;
}; };
export async function fetchLocale(localeCode) { export async function fetchLocale(
localeCode: string,
): Promise<I18NMessageDict> {
try { try {
const response = await fetchWithTimeout( const response = await fetchWithTimeout(
`./_locales/${localeCode}/messages.json`, `./_locales/${localeCode}/messages.json`,
@ -110,19 +145,21 @@ export async function fetchLocale(localeCode) {
const relativeTimeFormatLocaleData = new Set(); const relativeTimeFormatLocaleData = new Set();
export async function loadRelativeTimeFormatLocaleData(localeCode) { export async function loadRelativeTimeFormatLocaleData(
localeCode: string,
): Promise<void> {
const languageTag = localeCode.split('_')[0]; const languageTag = localeCode.split('_')[0];
if ( if (
Intl.RelativeTimeFormat && Intl.RelativeTimeFormat &&
typeof Intl.RelativeTimeFormat.__addLocaleData === 'function' && typeof (Intl.RelativeTimeFormat as any).__addLocaleData === 'function' &&
!relativeTimeFormatLocaleData.has(languageTag) !relativeTimeFormatLocaleData.has(languageTag)
) { ) {
const localeData = await fetchRelativeTimeFormatData(languageTag); const localeData = await fetchRelativeTimeFormatData(languageTag);
Intl.RelativeTimeFormat.__addLocaleData(localeData); (Intl.RelativeTimeFormat as any).__addLocaleData(localeData);
} }
} }
async function fetchRelativeTimeFormatData(languageTag) { async function fetchRelativeTimeFormatData(languageTag: string): Promise<Json> {
const response = await fetchWithTimeout( const response = await fetchWithTimeout(
`./intl/${languageTag}/relative-time-format-data.json`, `./intl/${languageTag}/relative-time-format-data.json`,
); );

View File

@ -3,7 +3,10 @@ import {
CHAIN_IDS, CHAIN_IDS,
} from '../../../shared/constants/network'; } from '../../../shared/constants/network';
export const formatMoonpaySymbol = (symbol, chainId = CHAIN_IDS.MAINNET) => { export const formatMoonpaySymbol = (
symbol: string | null,
chainId: keyof typeof BUYABLE_CHAINS_MAP,
): string | null => {
if (!symbol) { if (!symbol) {
return symbol; return symbol;
} }

View File

@ -11,7 +11,16 @@ describe('txHelper', () => {
c: { metamaskNetworkId, time: 2 }, c: { metamaskNetworkId, time: 2 },
}; };
const sorted = txHelper(txs, null, null, metamaskNetworkId, chainId); const sorted = txHelper(
txs,
null,
null,
null,
null,
null,
metamaskNetworkId,
chainId,
);
expect(sorted[0].time).toStrictEqual(1); expect(sorted[0].time).toStrictEqual(1);
expect(sorted[2].time).toStrictEqual(3); expect(sorted[2].time).toStrictEqual(3);
}); });

View File

@ -3,15 +3,15 @@ import { transactionMatchesNetwork } from '../../../shared/modules/transaction.u
import { valuesFor } from './util'; import { valuesFor } from './util';
export default function txHelper( export default function txHelper(
unapprovedTxs, unapprovedTxs: Record<string, any> | null,
unapprovedMsgs, unapprovedMsgs: Record<string, any> | null,
personalMsgs, personalMsgs: Record<string, any> | null,
decryptMsgs, decryptMsgs: Record<string, any> | null,
encryptionPublicKeyMsgs, encryptionPublicKeyMsgs: Record<string, any> | null,
typedMessages, typedMessages: Record<string, any> | null,
network, network: string,
chainId, chainId: string,
) { ): Record<string, any> {
log.debug('tx-helper called with params:'); log.debug('tx-helper called with params:');
log.debug({ log.debug({
unapprovedTxs, unapprovedTxs,

View File

@ -173,6 +173,7 @@ const mapDispatchToProps = (dispatch) => ({
setRecoveryPhraseReminderLastShown: (lastShown) => setRecoveryPhraseReminderLastShown: (lastShown) =>
dispatch(setRecoveryPhraseReminderLastShown(lastShown)), dispatch(setRecoveryPhraseReminderLastShown(lastShown)),
setNewNetworkAdded: (newNetwork) => { setNewNetworkAdded: (newNetwork) => {
console.log({ newNetwork });
dispatch(setNewNetworkAdded(newNetwork)); dispatch(setNewNetworkAdded(newNetwork));
}, },
setNewCollectibleAddedMessage: (message) => { setNewCollectibleAddedMessage: (message) => {

View File

@ -267,8 +267,8 @@ describe('Swaps Util', () => {
}; };
expect( expect(
getSwapsLivenessForNetwork( getSwapsLivenessForNetwork(
MOCKS.createFeatureFlagsResponse(),
CHAIN_IDS.LOCALHOST, CHAIN_IDS.LOCALHOST,
MOCKS.createFeatureFlagsResponse(),
), ),
).toMatchObject(expectedSwapsLiveness); ).toMatchObject(expectedSwapsLiveness);
}); });
@ -279,8 +279,8 @@ describe('Swaps Util', () => {
}; };
expect( expect(
getSwapsLivenessForNetwork( getSwapsLivenessForNetwork(
MOCKS.createFeatureFlagsResponse(),
CHAIN_IDS.GOERLI, CHAIN_IDS.GOERLI,
MOCKS.createFeatureFlagsResponse(),
), ),
).toMatchObject(expectedSwapsLiveness); ).toMatchObject(expectedSwapsLiveness);
}); });
@ -291,8 +291,8 @@ describe('Swaps Util', () => {
}; };
expect( expect(
getSwapsLivenessForNetwork( getSwapsLivenessForNetwork(
MOCKS.createFeatureFlagsResponse(),
CHAIN_IDS.SEPOLIA, CHAIN_IDS.SEPOLIA,
MOCKS.createFeatureFlagsResponse(),
), ),
).toMatchObject(expectedSwapsLiveness); ).toMatchObject(expectedSwapsLiveness);
}); });
@ -303,8 +303,8 @@ describe('Swaps Util', () => {
}; };
expect( expect(
getSwapsLivenessForNetwork( getSwapsLivenessForNetwork(
MOCKS.createFeatureFlagsResponse(),
CHAIN_IDS.MAINNET, CHAIN_IDS.MAINNET,
MOCKS.createFeatureFlagsResponse(),
), ),
).toMatchObject(expectedSwapsLiveness); ).toMatchObject(expectedSwapsLiveness);
}); });
@ -316,7 +316,7 @@ describe('Swaps Util', () => {
const swapsFeatureFlags = MOCKS.createFeatureFlagsResponse(); const swapsFeatureFlags = MOCKS.createFeatureFlagsResponse();
swapsFeatureFlags[ETHEREUM].extensionActive = false; swapsFeatureFlags[ETHEREUM].extensionActive = false;
expect( expect(
getSwapsLivenessForNetwork(swapsFeatureFlags, CHAIN_IDS.MAINNET), getSwapsLivenessForNetwork(CHAIN_IDS.MAINNET, swapsFeatureFlags),
).toMatchObject(expectedSwapsLiveness); ).toMatchObject(expectedSwapsLiveness);
}); });
}); });

View File

@ -1,24 +1,27 @@
import BigNumber from 'bignumber.js'; import { BigNumber } from 'bignumber.js';
import abi from 'human-standard-token-abi'; import abi from 'human-standard-token-abi';
import { Json } from '@metamask/controller-utils';
import { IndividualTxFees } from '@metamask/smart-transactions-controller/dist/types';
import { import {
SWAPS_CHAINID_DEFAULT_TOKEN_MAP,
ALLOWED_CONTRACT_ADDRESSES, ALLOWED_CONTRACT_ADDRESSES,
ETHEREUM,
POLYGON,
BSC,
GOERLI,
AVALANCHE,
OPTIMISM,
ARBITRUM, ARBITRUM,
AVALANCHE,
BSC,
ETHEREUM,
GOERLI,
OPTIMISM,
POLYGON,
SWAPS_API_V2_BASE_URL, SWAPS_API_V2_BASE_URL,
SWAPS_DEV_API_V2_BASE_URL, SWAPS_CHAINID_DEFAULT_TOKEN_MAP,
SWAPS_CLIENT_ID, SWAPS_CLIENT_ID,
SWAPS_DEV_API_V2_BASE_URL,
SwapsTokenObject,
} from '../../../shared/constants/swaps'; } from '../../../shared/constants/swaps';
import { import {
isSwapsDefaultTokenAddress, isSwapsDefaultTokenAddress,
isSwapsDefaultTokenSymbol, isSwapsDefaultTokenSymbol,
} from '../../../shared/modules/swaps.utils'; } from '../../../shared/modules/swaps.utils';
import { CHAIN_IDS, CURRENCY_SYMBOLS } from '../../../shared/constants/network'; import { CHAIN_IDS } from '../../../shared/constants/network';
import { formatCurrency } from '../../helpers/utils/confirm-tx.util'; import { formatCurrency } from '../../helpers/utils/confirm-tx.util';
import fetchWithCache from '../../../shared/lib/fetch-with-cache'; import fetchWithCache from '../../../shared/lib/fetch-with-cache';
@ -38,13 +41,20 @@ import {
getValueFromWeiHex, getValueFromWeiHex,
sumHexes, sumHexes,
} from '../../../shared/modules/conversion.utils'; } from '../../../shared/modules/conversion.utils';
import { EtherDenomination } from '../../../shared/constants/common';
const CACHE_REFRESH_FIVE_MINUTES = 300000; const CACHE_REFRESH_FIVE_MINUTES = 300000;
const USD_CURRENCY_CODE = 'usd'; const USD_CURRENCY_CODE = 'usd';
const clientIdHeader = { 'X-Client-Id': SWAPS_CLIENT_ID }; const clientIdHeader = { 'X-Client-Id': SWAPS_CLIENT_ID };
const TOKEN_VALIDATORS = [ interface Validator {
property: string;
type: string;
validator: (a: string) => boolean;
}
const TOKEN_VALIDATORS: Validator[] = [
{ {
property: 'address', property: 'address',
type: 'string', type: 'string',
@ -64,7 +74,7 @@ const TOKEN_VALIDATORS = [
const TOP_ASSET_VALIDATORS = TOKEN_VALIDATORS.slice(0, 2); const TOP_ASSET_VALIDATORS = TOKEN_VALIDATORS.slice(0, 2);
const AGGREGATOR_METADATA_VALIDATORS = [ const AGGREGATOR_METADATA_VALIDATORS: Validator[] = [
{ {
property: 'color', property: 'color',
type: 'string', type: 'string',
@ -82,10 +92,10 @@ const AGGREGATOR_METADATA_VALIDATORS = [
}, },
]; ];
const isValidDecimalNumber = (string) => const isValidDecimalNumber = (string: any): boolean =>
!isNaN(string) && string.match(/^[.0-9]+$/u) && !isNaN(parseFloat(string)); !isNaN(string) && string.match(/^[.0-9]+$/u) && !isNaN(parseFloat(string));
const SWAP_GAS_PRICE_VALIDATOR = [ const SWAP_GAS_PRICE_VALIDATOR: Validator[] = [
{ {
property: 'SafeGasPrice', property: 'SafeGasPrice',
type: 'string', type: 'string',
@ -103,17 +113,22 @@ const SWAP_GAS_PRICE_VALIDATOR = [
}, },
]; ];
export async function fetchToken(contractAddress, chainId) { export async function fetchToken(
contractAddress: string,
chainId: any,
): Promise<Json> {
const tokenUrl = getBaseApi('token', chainId); const tokenUrl = getBaseApi('token', chainId);
const token = await fetchWithCache( return await fetchWithCache(
`${tokenUrl}?address=${contractAddress}`, `${tokenUrl}?address=${contractAddress}`,
{ method: 'GET', headers: clientIdHeader }, { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES }, { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
); );
return token;
} }
export async function fetchTokens(chainId) { type Token = { symbol: string; address: string };
export async function fetchTokens(
chainId: keyof typeof SWAPS_CHAINID_DEFAULT_TOKEN_MAP,
): Promise<SwapsTokenObject[]> {
const tokensUrl = getBaseApi('tokens', chainId); const tokensUrl = getBaseApi('tokens', chainId);
const tokens = await fetchWithCache( const tokens = await fetchWithCache(
tokensUrl, tokensUrl,
@ -121,9 +136,10 @@ export async function fetchTokens(chainId) {
{ cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES }, { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
); );
const logError = false; const logError = false;
const filteredTokens = [ const tokenObject = SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId] || null;
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId], return [
...tokens.filter((token) => { tokenObject,
...tokens.filter((token: Token) => {
return ( return (
validateData(TOKEN_VALIDATORS, token, tokensUrl, logError) && validateData(TOKEN_VALIDATORS, token, tokensUrl, logError) &&
!( !(
@ -133,17 +149,16 @@ export async function fetchTokens(chainId) {
); );
}), }),
]; ];
return filteredTokens;
} }
export async function fetchAggregatorMetadata(chainId) { export async function fetchAggregatorMetadata(chainId: any): Promise<object> {
const aggregatorMetadataUrl = getBaseApi('aggregatorMetadata', chainId); const aggregatorMetadataUrl = getBaseApi('aggregatorMetadata', chainId);
const aggregators = await fetchWithCache( const aggregators = await fetchWithCache(
aggregatorMetadataUrl, aggregatorMetadataUrl,
{ method: 'GET', headers: clientIdHeader }, { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES }, { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
); );
const filteredAggregators = {}; const filteredAggregators = {} as any;
for (const aggKey in aggregators) { for (const aggKey in aggregators) {
if ( if (
validateData( validateData(
@ -158,7 +173,7 @@ export async function fetchAggregatorMetadata(chainId) {
return filteredAggregators; return filteredAggregators;
} }
export async function fetchTopAssets(chainId) { export async function fetchTopAssets(chainId: any): Promise<object> {
const topAssetsUrl = getBaseApi('topAssets', chainId); const topAssetsUrl = getBaseApi('topAssets', chainId);
const response = const response =
(await fetchWithCache( (await fetchWithCache(
@ -166,28 +181,30 @@ export async function fetchTopAssets(chainId) {
{ method: 'GET', headers: clientIdHeader }, { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES }, { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
)) || []; )) || [];
const topAssetsMap = response.reduce((_topAssetsMap, asset, index) => { const topAssetsMap = response.reduce(
(_topAssetsMap: any, asset: { address: string }, index: number) => {
if (validateData(TOP_ASSET_VALIDATORS, asset, topAssetsUrl)) { if (validateData(TOP_ASSET_VALIDATORS, asset, topAssetsUrl)) {
return { ..._topAssetsMap, [asset.address]: { index: String(index) } }; return { ..._topAssetsMap, [asset.address]: { index: String(index) } };
} }
return _topAssetsMap; return _topAssetsMap;
}, {}); },
{},
);
return topAssetsMap; return topAssetsMap;
} }
export async function fetchSwapsFeatureFlags() { export async function fetchSwapsFeatureFlags(): Promise<any> {
const v2ApiBaseUrl = process.env.SWAPS_USE_DEV_APIS const v2ApiBaseUrl = process.env.SWAPS_USE_DEV_APIS
? SWAPS_DEV_API_V2_BASE_URL ? SWAPS_DEV_API_V2_BASE_URL
: SWAPS_API_V2_BASE_URL; : SWAPS_API_V2_BASE_URL;
const response = await fetchWithCache( return await fetchWithCache(
`${v2ApiBaseUrl}/featureFlags`, `${v2ApiBaseUrl}/featureFlags`,
{ method: 'GET', headers: clientIdHeader }, { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: 600000 }, { cacheRefreshTime: 600000 },
); );
return response;
} }
export async function fetchTokenPrice(address) { export async function fetchTokenPrice(address: string): Promise<any> {
const query = `contract_addresses=${address}&vs_currencies=eth`; const query = `contract_addresses=${address}&vs_currencies=eth`;
const prices = await fetchWithCache( const prices = await fetchWithCache(
@ -195,19 +212,28 @@ export async function fetchTokenPrice(address) {
{ method: 'GET' }, { method: 'GET' },
{ cacheRefreshTime: 60000 }, { cacheRefreshTime: 60000 },
); );
return prices && prices[address]?.eth; return prices?.[address]?.eth;
} }
export async function fetchTokenBalance(address, userAddress) { export async function fetchTokenBalance(
const tokenContract = global.eth.contract(abi).at(address); address: string,
userAddress: string,
): Promise<any> {
const tokenContract = (global as any).eth.contract(abi).at(address);
const tokenBalancePromise = tokenContract const tokenBalancePromise = tokenContract
? tokenContract.balanceOf(userAddress) ? tokenContract.balanceOf(userAddress)
: Promise.resolve(); : Promise.resolve();
const usersToken = await tokenBalancePromise; return await tokenBalancePromise;
return usersToken;
} }
export async function fetchSwapsGasPrices(chainId) { export async function fetchSwapsGasPrices(chainId: any): Promise<
| any
| {
safeLow: string;
average: string;
fast: string;
}
> {
const gasPricesUrl = getBaseApi('gasPrices', chainId); const gasPricesUrl = getBaseApi('gasPrices', chainId);
const response = await fetchWithCache( const response = await fetchWithCache(
gasPricesUrl, gasPricesUrl,
@ -244,11 +270,18 @@ export const getFeeForSmartTransaction = ({
USDConversionRate, USDConversionRate,
nativeCurrencySymbol, nativeCurrencySymbol,
feeInWeiDec, feeInWeiDec,
}: {
chainId: keyof typeof SWAPS_CHAINID_DEFAULT_TOKEN_MAP;
currentCurrency: string;
conversionRate: number;
USDConversionRate?: number;
nativeCurrencySymbol: string;
feeInWeiDec: number;
}) => { }) => {
const feeInWeiHex = decimalToHex(feeInWeiDec); const feeInWeiHex = decimalToHex(feeInWeiDec);
const ethFee = getValueFromWeiHex({ const ethFee = getValueFromWeiHex({
value: feeInWeiHex, value: feeInWeiHex,
toDenomination: CURRENCY_SYMBOLS.ETH, toDenomination: EtherDenomination.ETH,
numberOfDecimals: 5, numberOfDecimals: 5,
}); });
const rawNetworkFees = getValueFromWeiHex({ const rawNetworkFees = getValueFromWeiHex({
@ -270,7 +303,7 @@ export const getFeeForSmartTransaction = ({
} }
const formattedNetworkFee = formatCurrency(rawNetworkFees, currentCurrency); const formattedNetworkFee = formatCurrency(rawNetworkFees, currentCurrency);
const chainCurrencySymbolToUse = const chainCurrencySymbolToUse =
nativeCurrencySymbol || SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId].symbol; nativeCurrencySymbol || SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId]?.symbol;
return { return {
feeInUsd, feeInUsd,
feeInFiat: formattedNetworkFee, feeInFiat: formattedNetworkFee,
@ -292,7 +325,27 @@ export function getRenderableNetworkFeesForQuote({
chainId, chainId,
nativeCurrencySymbol, nativeCurrencySymbol,
multiLayerL1FeeTotal, multiLayerL1FeeTotal,
}) { }: {
tradeGas: string;
approveGas: string;
gasPrice: string;
currentCurrency: string;
conversionRate: number;
USDConversionRate?: number;
tradeValue: number;
sourceSymbol: string;
sourceAmount: number;
chainId: keyof typeof SWAPS_CHAINID_DEFAULT_TOKEN_MAP;
nativeCurrencySymbol?: string;
multiLayerL1FeeTotal: string | null;
}): {
rawNetworkFees: string | number | BigNumber;
feeInUsd: string | number | BigNumber;
rawEthFee: string | number | BigNumber;
feeInFiat: string;
feeInEth: string;
nonGasFee: string;
} {
const totalGasLimitForCalculation = new BigNumber(tradeGas || '0x0', 16) const totalGasLimitForCalculation = new BigNumber(tradeGas || '0x0', 16)
.plus(approveGas || '0x0', 16) .plus(approveGas || '0x0', 16)
.toString(16); .toString(16);
@ -314,10 +367,9 @@ export function getRenderableNetworkFeesForQuote({
const totalWeiCost = new BigNumber(gasTotalInWeiHex, 16) const totalWeiCost = new BigNumber(gasTotalInWeiHex, 16)
.plus(nonGasFee, 16) .plus(nonGasFee, 16)
.toString(16); .toString(16);
const ethFee = getValueFromWeiHex({ const ethFee = getValueFromWeiHex({
value: totalWeiCost, value: totalWeiCost,
toDenomination: 'ETH', toDenomination: EtherDenomination.ETH,
numberOfDecimals: 5, numberOfDecimals: 5,
}); });
const rawNetworkFees = getValueFromWeiHex({ const rawNetworkFees = getValueFromWeiHex({
@ -353,7 +405,7 @@ export function getRenderableNetworkFeesForQuote({
}; };
} }
export function quotesToRenderableData( export function quotesToRenderableData({
quotes, quotes,
gasPrice, gasPrice,
conversionRate, conversionRate,
@ -364,7 +416,18 @@ export function quotesToRenderableData(
smartTransactionEstimatedGas, smartTransactionEstimatedGas,
nativeCurrencySymbol, nativeCurrencySymbol,
multiLayerL1ApprovalFeeTotal, multiLayerL1ApprovalFeeTotal,
) { }: {
quotes: object;
gasPrice: string;
conversionRate: number;
currentCurrency: string;
approveGas: string;
tokenConversionRates: Record<string, any>;
chainId: keyof typeof SWAPS_CHAINID_DEFAULT_TOKEN_MAP;
smartTransactionEstimatedGas: IndividualTxFees;
nativeCurrencySymbol: string;
multiLayerL1ApprovalFeeTotal: string | null;
}): Record<string, any> {
return Object.values(quotes).map((quote) => { return Object.values(quotes).map((quote) => {
const { const {
destinationAmount = 0, destinationAmount = 0,
@ -426,7 +489,7 @@ export function quotesToRenderableData(
currentCurrency, currentCurrency,
conversionRate, conversionRate,
nativeCurrencySymbol, nativeCurrencySymbol,
estimatedFeeInWeiDec: smartTransactionEstimatedGas.feeEstimate, feeInWeiDec: smartTransactionEstimatedGas.feeEstimate,
})); }));
} }
@ -494,7 +557,7 @@ export function quotesToRenderableData(
}); });
} }
export function formatSwapsValueForDisplay(destinationAmount) { export function formatSwapsValueForDisplay(destinationAmount: string): string {
let amountToDisplay = toPrecisionWithoutTrailingZeros(destinationAmount, 12); let amountToDisplay = toPrecisionWithoutTrailingZeros(destinationAmount, 12);
if (amountToDisplay.match(/e[+-]/u)) { if (amountToDisplay.match(/e[+-]/u)) {
amountToDisplay = new BigNumber(amountToDisplay).toFixed(); amountToDisplay = new BigNumber(amountToDisplay).toFixed();
@ -505,30 +568,30 @@ export function formatSwapsValueForDisplay(destinationAmount) {
/** /**
* Checks whether a contract address is valid before swapping tokens. * Checks whether a contract address is valid before swapping tokens.
* *
* @param {string} contractAddress - E.g. "0x881d40237659c251811cec9c364ef91dc08d300c" for mainnet * @param contractAddress - E.g. "0x881d40237659c251811cec9c364ef91dc08d300c" for mainnet
* @param {string} chainId - The hex encoded chain ID to check * @param chainId - The hex encoded chain ID to check
* @returns {boolean} Whether a contract address is valid or not * @returns Whether a contract address is valid or not
*/ */
export const isContractAddressValid = ( export const isContractAddressValid = (
contractAddress, contractAddress: string,
chainId = CHAIN_IDS.MAINNET, chainId: keyof typeof ALLOWED_CONTRACT_ADDRESSES,
) => { ): boolean => {
if (!contractAddress || !ALLOWED_CONTRACT_ADDRESSES[chainId]) { if (!contractAddress || !ALLOWED_CONTRACT_ADDRESSES[chainId]) {
return false; return false;
} }
return ALLOWED_CONTRACT_ADDRESSES[chainId].some( return ALLOWED_CONTRACT_ADDRESSES[chainId].some(
// Sometimes we get a contract address with a few upper-case chars and since addresses are // Sometimes we get a contract address with a few upper-case chars and since addresses are
// case-insensitive, we compare lowercase versions for validity. // case-insensitive, we compare lowercase versions for validity.
(allowedContractAddress) => (allowedContractAddress: string) =>
contractAddress.toLowerCase() === allowedContractAddress.toLowerCase(), contractAddress.toLowerCase() === allowedContractAddress.toLowerCase(),
); );
}; };
/** /**
* @param {string} chainId * @param chainId
* @returns string e.g. ethereum, bsc or polygon * @returns string e.g. ethereum, bsc or polygon
*/ */
export const getNetworkNameByChainId = (chainId) => { export const getNetworkNameByChainId = (chainId: string): string => {
switch (chainId) { switch (chainId) {
case CHAIN_IDS.MAINNET: case CHAIN_IDS.MAINNET:
return ETHEREUM; return ETHEREUM;
@ -552,11 +615,14 @@ export const getNetworkNameByChainId = (chainId) => {
/** /**
* It returns info about if Swaps are enabled and if we should use our new APIs for it. * It returns info about if Swaps are enabled and if we should use our new APIs for it.
* *
* @param {object} swapsFeatureFlags * @param chainId
* @param {string} chainId * @param swapsFeatureFlags
* @returns object with 2 items: "swapsFeatureIsLive" * @returns object with 2 items: "swapsFeatureIsLive"
*/ */
export const getSwapsLivenessForNetwork = (swapsFeatureFlags = {}, chainId) => { export const getSwapsLivenessForNetwork = (
chainId: any,
swapsFeatureFlags: any = {},
) => {
const networkName = getNetworkNameByChainId(chainId); const networkName = getNetworkNameByChainId(chainId);
// Use old APIs for testnet and Goerli. // Use old APIs for testnet and Goerli.
if ([CHAIN_IDS.LOCALHOST, CHAIN_IDS.GOERLI].includes(chainId)) { if ([CHAIN_IDS.LOCALHOST, CHAIN_IDS.GOERLI].includes(chainId)) {
@ -583,17 +649,19 @@ export const getSwapsLivenessForNetwork = (swapsFeatureFlags = {}, chainId) => {
}; };
/** /**
* @param {number} value * @param value
* @returns number * @returns number
*/ */
export const countDecimals = (value) => { export const countDecimals = (value: any): number => {
if (!value || Math.floor(value) === value) { if (!value || Math.floor(value) === value) {
return 0; return 0;
} }
return value.toString().split('.')[1]?.length || 0; return value.toString().split('.')[1]?.length || 0;
}; };
export const showRemainingTimeInMinAndSec = (remainingTimeInSec) => { export const showRemainingTimeInMinAndSec = (
remainingTimeInSec: any,
): string => {
if (!Number.isInteger(remainingTimeInSec)) { if (!Number.isInteger(remainingTimeInSec)) {
return '0:00'; return '0:00';
} }
@ -602,25 +670,28 @@ export const showRemainingTimeInMinAndSec = (remainingTimeInSec) => {
return `${minutes}:${seconds.toString().padStart(2, '0')}`; return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}; };
export const stxErrorTypes = { export enum StxErrorTypes {
UNAVAILABLE: 'unavailable', unavailable = 'unavailable',
NOT_ENOUGH_FUNDS: 'not_enough_funds', notEnoughFunds = 'not_enough_funds',
REGULAR_TX_IN_PROGRESS: 'regular_tx_pending', regularTxPending = 'regular_tx_pending',
}; }
export const getTranslatedStxErrorMessage = (errorType, t) => { export const getTranslatedStxErrorMessage = (
errorType: StxErrorTypes,
t: (...args: any[]) => string,
): string => {
switch (errorType) { switch (errorType) {
case stxErrorTypes.UNAVAILABLE: case StxErrorTypes.unavailable:
case stxErrorTypes.REGULAR_TX_IN_PROGRESS: case StxErrorTypes.regularTxPending:
return t('stxErrorUnavailable'); return t('stxErrorUnavailable');
case stxErrorTypes.NOT_ENOUGH_FUNDS: case StxErrorTypes.notEnoughFunds:
return t('stxErrorNotEnoughFunds'); return t('stxErrorNotEnoughFunds');
default: default:
return t('stxErrorUnavailable'); return t('stxErrorUnavailable');
} }
}; };
export const parseSmartTransactionsError = (errorMessage) => { export const parseSmartTransactionsError = (errorMessage: string): string => {
const errorJson = errorMessage.slice(12); const errorJson = errorMessage.slice(12);
return JSON.parse(errorJson.trim()); return JSON.parse(errorJson.trim());
}; };

View File

@ -297,20 +297,23 @@ export default function ViewQuote() {
const approveGas = approveTxParams?.gas; const approveGas = approveTxParams?.gas;
const renderablePopoverData = useMemo(() => { const renderablePopoverData = useMemo(() => {
return quotesToRenderableData( return quotesToRenderableData({
quotes, quotes,
networkAndAccountSupports1559 ? baseAndPriorityFeePerGas : gasPrice, gasPrice: networkAndAccountSupports1559
? baseAndPriorityFeePerGas
: gasPrice,
conversionRate, conversionRate,
currentCurrency, currentCurrency,
approveGas, approveGas,
memoizedTokenConversionRates, tokenConversionRates: memoizedTokenConversionRates,
chainId, chainId,
smartTransactionEstimatedGas:
smartTransactionsEnabled && smartTransactionsEnabled &&
smartTransactionsOptInStatus && smartTransactionsOptInStatus &&
smartTransactionFees?.tradeTxFees, smartTransactionFees?.tradeTxFees,
nativeCurrencySymbol, nativeCurrencySymbol,
multiLayerL1ApprovalFeeTotal, multiLayerL1ApprovalFeeTotal,
); });
}, [ }, [
quotes, quotes,
gasPrice, gasPrice,

View File

@ -23360,10 +23360,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"loglevel@npm:^1.4.1": "loglevel@npm:^1.8.1":
version: 1.6.0 version: 1.8.1
resolution: "loglevel@npm:1.6.0" resolution: "loglevel@npm:1.8.1"
checksum: 85e59bde900d8c7ddb6bd8f4ac466ca59fab54239e9bbf99193181c316fe49b067e3ed5945524894404c77db1a3a4d17f5fe272a808f05a8a8914a527628dea4 checksum: a1a62db40291aaeaef2f612334c49e531bff71cc1d01a2acab689ab80d59e092f852ab164a5aedc1a752fdc46b7b162cb097d8a9eb2cf0b299511106c29af61d
languageName: node languageName: node
linkType: hard linkType: hard
@ -24305,7 +24305,7 @@ __metadata:
localforage: ^1.9.0 localforage: ^1.9.0
lockfile-lint: ^4.9.6 lockfile-lint: ^4.9.6
lodash: ^4.17.21 lodash: ^4.17.21
loglevel: ^1.4.1 loglevel: ^1.8.1
loose-envify: ^1.4.0 loose-envify: ^1.4.0
luxon: ^3.2.1 luxon: ^3.2.1
madge: ^5.0.1 madge: ^5.0.1