1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-28 23:06:37 +01:00

Add support for swaps via a direct contract for wrapping and unwrapping (#11845)

* Update contract address validations in swaps for different networks

* Add support for direct contract swaps for wrapping and unwrapping

* Add WETH_RINKEBY_CONTRACT_ADDRESS
This commit is contained in:
Daniel 2021-09-08 20:08:55 +02:00 committed by GitHub
parent a35f22fcdf
commit 6f0d6b1693
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 262 additions and 177 deletions

View File

@ -2131,6 +2131,9 @@
"swapDecentralizedExchange": { "swapDecentralizedExchange": {
"message": "Decentralized exchange" "message": "Decentralized exchange"
}, },
"swapDirectContract": {
"message": "Direct contract"
},
"swapEditLimit": { "swapEditLimit": {
"message": "Edit limit" "message": "Edit limit"
}, },

View File

@ -75,8 +75,14 @@ const BSC_CONTRACT_ADDRESS = '0x1a1ec25dc08e98e5e93f1104b5e5cdd298707d31';
// It's the same as we use for BSC. // It's the same as we use for BSC.
const POLYGON_CONTRACT_ADDRESS = '0x1a1ec25dc08e98e5e93f1104b5e5cdd298707d31'; const POLYGON_CONTRACT_ADDRESS = '0x1a1ec25dc08e98e5e93f1104b5e5cdd298707d31';
export const ETH_WETH_CONTRACT_ADDRESS = export const WETH_CONTRACT_ADDRESS =
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
export const WETH_RINKEBY_CONTRACT_ADDRESS =
'0xc778417e063141139fce010982780140aa0cd5ab';
export const WBNB_CONTRACT_ADDRESS =
'0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c';
export const WMATIC_CONTRACT_ADDRESS =
'0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270';
const METASWAP_ETH_API_HOST = 'https://api.metaswap.codefi.network'; const METASWAP_ETH_API_HOST = 'https://api.metaswap.codefi.network';
@ -121,6 +127,37 @@ export const SWAPS_CHAINID_CONTRACT_ADDRESS_MAP = {
[RINKEBY_CHAIN_ID]: TESTNET_CONTRACT_ADDRESS, [RINKEBY_CHAIN_ID]: TESTNET_CONTRACT_ADDRESS,
}; };
export const SWAPS_WRAPPED_TOKENS_ADDRESSES = {
[MAINNET_CHAIN_ID]: WETH_CONTRACT_ADDRESS,
[SWAPS_TESTNET_CHAIN_ID]: WETH_CONTRACT_ADDRESS,
[BSC_CHAIN_ID]: WBNB_CONTRACT_ADDRESS,
[POLYGON_CHAIN_ID]: WMATIC_CONTRACT_ADDRESS,
[RINKEBY_CHAIN_ID]: WETH_RINKEBY_CONTRACT_ADDRESS,
};
export const ALLOWED_CONTRACT_ADDRESSES = {
[MAINNET_CHAIN_ID]: [
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[MAINNET_CHAIN_ID],
SWAPS_WRAPPED_TOKENS_ADDRESSES[MAINNET_CHAIN_ID],
],
[SWAPS_TESTNET_CHAIN_ID]: [
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[SWAPS_TESTNET_CHAIN_ID],
SWAPS_WRAPPED_TOKENS_ADDRESSES[SWAPS_TESTNET_CHAIN_ID],
],
[RINKEBY_CHAIN_ID]: [
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[RINKEBY_CHAIN_ID],
SWAPS_WRAPPED_TOKENS_ADDRESSES[RINKEBY_CHAIN_ID],
],
[BSC_CHAIN_ID]: [
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[BSC_CHAIN_ID],
SWAPS_WRAPPED_TOKENS_ADDRESSES[BSC_CHAIN_ID],
],
[POLYGON_CHAIN_ID]: [
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[POLYGON_CHAIN_ID],
SWAPS_WRAPPED_TOKENS_ADDRESSES[POLYGON_CHAIN_ID],
],
};
export const SWAPS_CHAINID_DEFAULT_TOKEN_MAP = { export const SWAPS_CHAINID_DEFAULT_TOKEN_MAP = {
[MAINNET_CHAIN_ID]: ETH_SWAPS_TOKEN_OBJECT, [MAINNET_CHAIN_ID]: ETH_SWAPS_TOKEN_OBJECT,
[SWAPS_TESTNET_CHAIN_ID]: TEST_ETH_SWAPS_TOKEN_OBJECT, [SWAPS_TESTNET_CHAIN_ID]: TEST_ETH_SWAPS_TOKEN_OBJECT,

View File

@ -779,7 +779,7 @@ export const signAndSendTransactions = (history, metaMetricsEvent) => {
sensitiveProperties: swapMetaData, sensitiveProperties: swapMetaData,
}); });
if (!isContractAddressValid(usedTradeTxParams.to, swapMetaData, chainId)) { if (!isContractAddressValid(usedTradeTxParams.to, chainId)) {
captureMessage('Invalid contract address', { captureMessage('Invalid contract address', {
extra: { extra: {
token_from: swapMetaData.token_from, token_from: swapMetaData.token_from,

View File

@ -59,7 +59,11 @@ import {
} from '../../../../shared/constants/swaps'; } from '../../../../shared/constants/swaps';
import { resetSwapsPostFetchState, removeToken } from '../../../store/actions'; import { resetSwapsPostFetchState, removeToken } from '../../../store/actions';
import { fetchTokenPrice, fetchTokenBalance } from '../swaps.util'; import {
fetchTokenPrice,
fetchTokenBalance,
shouldEnableDirectWrapping,
} from '../swaps.util';
import SwapsFooter from '../swaps-footer'; import SwapsFooter from '../swaps-footer';
const fuseSearchKeys = [ const fuseSearchKeys = [
@ -375,6 +379,12 @@ export default function BuildQuote({
fromTokenSymbol || SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId]?.symbol || '', fromTokenSymbol || SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId]?.symbol || '',
]); ]);
const isDirectWrappingEnabled = shouldEnableDirectWrapping(
chainId,
fromTokenAddress,
selectedToToken.address,
);
return ( return (
<div className="build-quote"> <div className="build-quote">
<div className="build-quote__content"> <div className="build-quote__content">
@ -552,15 +562,17 @@ export default function BuildQuote({
)} )}
</div> </div>
))} ))}
<div className="build-quote__slippage-buttons-container"> {!isDirectWrappingEnabled && (
<SlippageButtons <div className="build-quote__slippage-buttons-container">
onSelect={(newSlippage) => { <SlippageButtons
setMaxSlippage(newSlippage); onSelect={(newSlippage) => {
}} setMaxSlippage(newSlippage);
maxAllowedSlippage={MAX_ALLOWED_SLIPPAGE} }}
currentSlippage={maxSlippage} maxAllowedSlippage={MAX_ALLOWED_SLIPPAGE}
/> currentSlippage={maxSlippage}
</div> />
</div>
)}
</div> </div>
<SwapsFooter <SwapsFooter
onSubmit={() => { onSubmit={() => {

View File

@ -82,17 +82,19 @@ export default function FeeCard({
{bestQuoteText && ( {bestQuoteText && (
<p className="fee-card__savings-text">{bestQuoteText}</p> <p className="fee-card__savings-text">{bestQuoteText}</p>
)} )}
<div {numberOfQuotes > 1 && (
className="fee-card__quote-link-container" <div
onClick={onQuotesClick} className="fee-card__quote-link-container"
> onClick={onQuotesClick}
<p className="fee-card__quote-link-text"> >
{t('swapNQuotes', [numberOfQuotes])} <p className="fee-card__quote-link-text">
</p> {t('swapNQuotes', [numberOfQuotes])}
<div className="fee-card__caret-right"> </p>
<i className="fa fa-angle-up" /> <div className="fee-card__caret-right">
<i className="fa fa-angle-up" />
</div>
</div> </div>
</div> )}
</div> </div>
</div> </div>
<div className="fee-card__main"> <div className="fee-card__main">

View File

@ -4,8 +4,8 @@ import abi from 'human-standard-token-abi';
import { import {
SWAPS_CHAINID_DEFAULT_TOKEN_MAP, SWAPS_CHAINID_DEFAULT_TOKEN_MAP,
METASWAP_CHAINID_API_HOST_MAP, METASWAP_CHAINID_API_HOST_MAP,
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP, ALLOWED_CONTRACT_ADDRESSES,
ETH_WETH_CONTRACT_ADDRESS, SWAPS_WRAPPED_TOKENS_ADDRESSES,
ETHEREUM, ETHEREUM,
POLYGON, POLYGON,
BSC, BSC,
@ -21,8 +21,6 @@ import {
isSwapsDefaultTokenSymbol, isSwapsDefaultTokenSymbol,
} from '../../../shared/modules/swaps.utils'; } from '../../../shared/modules/swaps.utils';
import { import {
ETH_SYMBOL,
WETH_SYMBOL,
MAINNET_CHAIN_ID, MAINNET_CHAIN_ID,
BSC_CHAIN_ID, BSC_CHAIN_ID,
POLYGON_CHAIN_ID, POLYGON_CHAIN_ID,
@ -267,6 +265,19 @@ function validateData(validators, object, urlUsed) {
}); });
} }
export const shouldEnableDirectWrapping = (
chainId,
sourceToken,
destinationToken,
) => {
const wrappedToken = SWAPS_WRAPPED_TOKENS_ADDRESSES[chainId];
const nativeToken = SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId]?.address;
return (
(sourceToken === wrappedToken && destinationToken === nativeToken) ||
(sourceToken === nativeToken && destinationToken === wrappedToken)
);
};
export async function fetchTradesInfo( export async function fetchTradesInfo(
{ {
slippage, slippage,
@ -291,6 +302,9 @@ export async function fetchTradesInfo(
if (exchangeList) { if (exchangeList) {
urlParams.exchangeList = exchangeList; urlParams.exchangeList = exchangeList;
} }
if (shouldEnableDirectWrapping(chainId, sourceToken, destinationToken)) {
urlParams.enableDirectWrapping = true;
}
const queryString = new URLSearchParams(urlParams).toString(); const queryString = new URLSearchParams(urlParams).toString();
const tradeURL = `${getBaseApi( const tradeURL = `${getBaseApi(
@ -628,6 +642,8 @@ export function quotesToRenderableData(
renderedSlippage = 0; renderedSlippage = 0;
} else if (aggType === 'DEX') { } else if (aggType === 'DEX') {
liquiditySourceKey = 'swapDecentralizedExchange'; liquiditySourceKey = 'swapDecentralizedExchange';
} else if (aggType === 'CONTRACT') {
liquiditySourceKey = 'swapDirectContract';
} else { } else {
liquiditySourceKey = 'swapUnknown'; liquiditySourceKey = 'swapUnknown';
} }
@ -769,29 +785,16 @@ export function formatSwapsValueForDisplay(destinationAmount) {
*/ */
export const isContractAddressValid = ( export const isContractAddressValid = (
contractAddress, contractAddress,
swapMetaData,
chainId = MAINNET_CHAIN_ID, chainId = MAINNET_CHAIN_ID,
) => { ) => {
const contractAddressForChainId = SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[chainId]; if (!contractAddress || !ALLOWED_CONTRACT_ADDRESSES[chainId]) {
if (!contractAddress || !contractAddressForChainId) {
return false; return false;
} }
if ( return ALLOWED_CONTRACT_ADDRESSES[chainId].some(
(swapMetaData.token_from === ETH_SYMBOL &&
swapMetaData.token_to === WETH_SYMBOL) ||
(swapMetaData.token_from === WETH_SYMBOL &&
swapMetaData.token_to === ETH_SYMBOL)
) {
// 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 uppercase versions for validity. // case-insensitive, we compare lowercase versions for validity.
return ( (allowedContractAddress) =>
contractAddress.toUpperCase() === contractAddress.toLowerCase() === allowedContractAddress.toLowerCase(),
ETH_WETH_CONTRACT_ADDRESS.toUpperCase() ||
contractAddressForChainId.toUpperCase() === contractAddress.toUpperCase()
);
}
return (
contractAddressForChainId.toUpperCase() === contractAddress.toUpperCase()
); );
}; };

View File

@ -1,8 +1,6 @@
import nock from 'nock'; import nock from 'nock';
import { MOCKS } from '../../../test/jest'; import { MOCKS } from '../../../test/jest';
import { import {
ETH_SYMBOL,
WETH_SYMBOL,
MAINNET_CHAIN_ID, MAINNET_CHAIN_ID,
BSC_CHAIN_ID, BSC_CHAIN_ID,
POLYGON_CHAIN_ID, POLYGON_CHAIN_ID,
@ -12,7 +10,10 @@ import {
} from '../../../shared/constants/network'; } from '../../../shared/constants/network';
import { import {
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP, SWAPS_CHAINID_CONTRACT_ADDRESS_MAP,
ETH_WETH_CONTRACT_ADDRESS, SWAPS_CHAINID_DEFAULT_TOKEN_MAP,
WETH_CONTRACT_ADDRESS,
WBNB_CONTRACT_ADDRESS,
WMATIC_CONTRACT_ADDRESS,
ETHEREUM, ETHEREUM,
POLYGON, POLYGON,
BSC, BSC,
@ -34,6 +35,7 @@ import {
getNetworkNameByChainId, getNetworkNameByChainId,
getSwapsLivenessForNetwork, getSwapsLivenessForNetwork,
countDecimals, countDecimals,
shouldEnableDirectWrapping,
} from './swaps.util'; } from './swaps.util';
jest.mock('../../helpers/utils/storage-helpers.js', () => ({ jest.mock('../../helpers/utils/storage-helpers.js', () => ({
@ -188,197 +190,113 @@ describe('Swaps Util', () => {
}); });
describe('isContractAddressValid', () => { describe('isContractAddressValid', () => {
let swapMetaData;
let usedTradeTxParams; let usedTradeTxParams;
beforeEach(() => { beforeEach(() => {
swapMetaData = {
available_quotes: undefined,
average_savings: undefined,
best_quote_source: 'paraswap',
custom_slippage: true,
estimated_gas: '134629',
fee_savings: undefined,
gas_fees: '47.411896',
median_metamask_fee: undefined,
other_quote_selected: false,
other_quote_selected_source: '',
performance_savings: undefined,
slippage: 5,
suggested_gas_price: '164',
token_from: ETH_SYMBOL,
token_from_amount: '1',
token_to: WETH_SYMBOL,
token_to_amount: '1.0000000',
used_gas_price: '164',
};
usedTradeTxParams = { usedTradeTxParams = {
data: 'testData', data: 'testData',
from: '0xe53a5bc256898bfa5673b20aceeb2b2152075d17', from: '0xe53a5bc256898bfa5673b20aceeb2b2152075d17',
gas: '2427c', gas: '2427c',
gasPrice: '27592f5a00', gasPrice: '27592f5a00',
to: ETH_WETH_CONTRACT_ADDRESS, to: WETH_CONTRACT_ADDRESS,
value: '0xde0b6b3a7640000', value: '0xde0b6b3a7640000',
}; };
}); });
it('returns true if "token_from" is ETH, "token_to" is WETH and "to" is ETH_WETH contract address', () => { it('returns true if "to" is WETH contract address', () => {
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, MAINNET_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
MAINNET_CHAIN_ID,
),
).toBe(true); ).toBe(true);
}); });
it('returns true if "token_from" is WETH, "token_to" is ETH and "to" is ETH_WETH contract address', () => { it('returns true if "to" is WETH contract address with some uppercase chars', () => {
swapMetaData.token_from = WETH_SYMBOL;
swapMetaData.token_to = ETH_SYMBOL;
expect(
isContractAddressValid(
usedTradeTxParams.to,
swapMetaData,
MAINNET_CHAIN_ID,
),
).toBe(true);
});
it('returns true if "token_from" is ETH, "token_to" is WETH and "to" is ETH_WETH contract address with some uppercase chars', () => {
usedTradeTxParams.to = '0xc02AAA39B223fe8d0a0e5c4f27ead9083c756cc2'; usedTradeTxParams.to = '0xc02AAA39B223fe8d0a0e5c4f27ead9083c756cc2';
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, MAINNET_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
MAINNET_CHAIN_ID,
),
).toBe(true); ).toBe(true);
}); });
it('returns true if "token_from" is ETH, "token_to" is WETH and "to" is mainnet contract address', () => { it('returns true if "to" is ETH mainnet contract address on ETH mainnet', () => {
usedTradeTxParams.to = usedTradeTxParams.to =
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[MAINNET_CHAIN_ID]; SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[MAINNET_CHAIN_ID];
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, MAINNET_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
MAINNET_CHAIN_ID,
),
).toBe(true); ).toBe(true);
}); });
it('returns true if "token_from" is WETH, "token_to" is ETH and "to" is mainnet contract address', () => { it('returns true if "to" is WBNB contract address on BSC mainnet', () => {
swapMetaData.token_from = WETH_SYMBOL; usedTradeTxParams.to = WBNB_CONTRACT_ADDRESS;
swapMetaData.token_to = ETH_SYMBOL; expect(isContractAddressValid(usedTradeTxParams.to, BSC_CHAIN_ID)).toBe(
usedTradeTxParams.to = true,
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[MAINNET_CHAIN_ID]; );
});
it('returns true if "to" is WMATIC contract address on Polygon mainnet', () => {
usedTradeTxParams.to = WMATIC_CONTRACT_ADDRESS;
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, POLYGON_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
MAINNET_CHAIN_ID,
),
).toBe(true); ).toBe(true);
}); });
it('returns false if "token_from" is ETH, "token_to" is WETH and "to" is BSC contract address', () => { it('returns false if "to" is BSC contract address on ETH mainnet', () => {
usedTradeTxParams.to = SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[BSC_CHAIN_ID]; usedTradeTxParams.to = SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[BSC_CHAIN_ID];
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, MAINNET_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
MAINNET_CHAIN_ID,
),
).toBe(false);
});
it('returns false if "token_from" is WETH, "token_to" is ETH and "to" is BSC contract address', () => {
swapMetaData.token_from = WETH_SYMBOL;
swapMetaData.token_to = ETH_SYMBOL;
usedTradeTxParams.to = SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[BSC_CHAIN_ID];
expect(
isContractAddressValid(
usedTradeTxParams.to,
swapMetaData,
MAINNET_CHAIN_ID,
),
).toBe(false); ).toBe(false);
}); });
it('returns false if contractAddress is null', () => { it('returns false if contractAddress is null', () => {
expect( expect(isContractAddressValid(null, LOCALHOST_CHAIN_ID)).toBe(false);
isContractAddressValid(null, swapMetaData, LOCALHOST_CHAIN_ID),
).toBe(false);
}); });
it('returns false if chainId is incorrect', () => { it('returns false if chainId is incorrect', () => {
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, 'incorrectChainId'),
usedTradeTxParams.to,
swapMetaData,
'incorrectChainId',
),
).toBe(false); ).toBe(false);
}); });
it('returns true if "token_from" is BAT and "to" is mainnet contract address', () => { it('returns true if "to" is BSC contract address on BSC network', () => {
swapMetaData.token_from = 'BAT';
usedTradeTxParams.to =
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[MAINNET_CHAIN_ID];
expect(
isContractAddressValid(
usedTradeTxParams.to,
swapMetaData,
MAINNET_CHAIN_ID,
),
).toBe(true);
});
it('returns true if "token_to" is BAT and "to" is BSC contract address', () => {
swapMetaData.token_to = 'BAT';
usedTradeTxParams.to = SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[BSC_CHAIN_ID]; usedTradeTxParams.to = SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[BSC_CHAIN_ID];
expect(isContractAddressValid(usedTradeTxParams.to, BSC_CHAIN_ID)).toBe(
true,
);
});
it('returns true if "to" is Polygon contract address on Polygon network', () => {
usedTradeTxParams.to =
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[POLYGON_CHAIN_ID];
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, POLYGON_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
BSC_CHAIN_ID,
),
).toBe(true); ).toBe(true);
}); });
it('returns true if "token_to" is BAT and "to" is testnet contract address', () => { it('returns true if "to" is Rinkeby contract address on Rinkeby network', () => {
swapMetaData.token_to = 'BAT'; usedTradeTxParams.to =
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[RINKEBY_CHAIN_ID];
expect(
isContractAddressValid(usedTradeTxParams.to, RINKEBY_CHAIN_ID),
).toBe(true);
});
it('returns true if "to" is testnet contract address', () => {
usedTradeTxParams.to = usedTradeTxParams.to =
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[LOCALHOST_CHAIN_ID]; SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[LOCALHOST_CHAIN_ID];
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, LOCALHOST_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
LOCALHOST_CHAIN_ID,
),
).toBe(true); ).toBe(true);
}); });
it('returns true if "token_to" is BAT and "to" is testnet contract address with some uppercase chars', () => { it('returns true if "to" is testnet contract address with some uppercase chars', () => {
swapMetaData.token_to = 'BAT';
usedTradeTxParams.to = '0x881D40237659C251811CEC9c364ef91dC08D300C'; usedTradeTxParams.to = '0x881D40237659C251811CEC9c364ef91dC08D300C';
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, LOCALHOST_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
LOCALHOST_CHAIN_ID,
),
).toBe(true); ).toBe(true);
}); });
it('returns false if "token_to" is BAT and "to" has mismatch with current chainId', () => { it('returns false if "to" has mismatch with current chainId', () => {
swapMetaData.token_to = 'BAT'; usedTradeTxParams.to = SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[BSC_CHAIN_ID];
expect( expect(
isContractAddressValid( isContractAddressValid(usedTradeTxParams.to, LOCALHOST_CHAIN_ID),
usedTradeTxParams.to,
swapMetaData,
LOCALHOST_CHAIN_ID,
),
).toBe(false); ).toBe(false);
}); });
}); });
@ -492,4 +410,114 @@ describe('Swaps Util', () => {
expect(countDecimals(1.123456789)).toBe(9); expect(countDecimals(1.123456789)).toBe(9);
}); });
}); });
describe('shouldEnableDirectWrapping', () => {
const randomTokenAddress = '0x881d40237659c251811cec9c364ef91234567890';
it('returns true if swapping from ETH to WETH', () => {
expect(
shouldEnableDirectWrapping(
MAINNET_CHAIN_ID,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[MAINNET_CHAIN_ID]?.address,
WETH_CONTRACT_ADDRESS,
),
).toBe(true);
});
it('returns true if swapping from WETH to ETH', () => {
expect(
shouldEnableDirectWrapping(
MAINNET_CHAIN_ID,
WETH_CONTRACT_ADDRESS,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[MAINNET_CHAIN_ID]?.address,
),
).toBe(true);
});
it('returns false if swapping from ETH to a non-WETH token', () => {
expect(
shouldEnableDirectWrapping(
MAINNET_CHAIN_ID,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[MAINNET_CHAIN_ID]?.address,
randomTokenAddress,
),
).toBe(false);
});
it('returns true if swapping from BNB to WBNB', () => {
expect(
shouldEnableDirectWrapping(
BSC_CHAIN_ID,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[BSC_CHAIN_ID]?.address,
WBNB_CONTRACT_ADDRESS,
),
).toBe(true);
});
it('returns true if swapping from WBNB to BNB', () => {
expect(
shouldEnableDirectWrapping(
BSC_CHAIN_ID,
WBNB_CONTRACT_ADDRESS,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[BSC_CHAIN_ID]?.address,
),
).toBe(true);
});
it('returns false if swapping from BNB to a non-WBNB token', () => {
expect(
shouldEnableDirectWrapping(
BSC_CHAIN_ID,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[BSC_CHAIN_ID]?.address,
randomTokenAddress,
),
).toBe(false);
});
it('returns true if swapping from MATIC to WMATIC', () => {
expect(
shouldEnableDirectWrapping(
POLYGON_CHAIN_ID,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[POLYGON_CHAIN_ID]?.address,
WMATIC_CONTRACT_ADDRESS,
),
).toBe(true);
});
it('returns true if swapping from WMATIC to MATIC', () => {
expect(
shouldEnableDirectWrapping(
POLYGON_CHAIN_ID,
WMATIC_CONTRACT_ADDRESS,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[POLYGON_CHAIN_ID]?.address,
),
).toBe(true);
});
it('returns false if swapping from MATIC to a non-WMATIC token', () => {
expect(
shouldEnableDirectWrapping(
POLYGON_CHAIN_ID,
SWAPS_CHAINID_DEFAULT_TOKEN_MAP[POLYGON_CHAIN_ID]?.address,
randomTokenAddress,
),
).toBe(false);
});
it('returns false if a source token is undefined', () => {
expect(
shouldEnableDirectWrapping(
MAINNET_CHAIN_ID,
undefined,
WETH_CONTRACT_ADDRESS,
),
).toBe(false);
});
it('returns false if a destination token is undefined', () => {
expect(
shouldEnableDirectWrapping(MAINNET_CHAIN_ID, WETH_CONTRACT_ADDRESS),
).toBe(false);
});
});
}); });