From 3cee9d150aa6d0067755f19bfc853d0c0a0c455c Mon Sep 17 00:00:00 2001 From: Mikhala <122326421+imx-mikhala@users.noreply.github.com> Date: Tue, 16 Jan 2024 09:37:24 +0800 Subject: [PATCH] WT-1957 Ignore casing on address check when finding balance in smart checkout (#1322) --- .../checkout/sdk/src/balances/balances.ts | 5 ++-- packages/checkout/sdk/src/sdk.ts | 3 ++- .../smartCheckout/allowList/allowListCheck.ts | 6 ++++- .../balanceCheck/balanceCheck.ts | 3 ++- .../balanceCheck/balanceRequirement.ts | 5 ++-- .../routing/bridge/bridgeRoute.ts | 7 ++++-- .../bridgeAndSwap/bridgeAndSwapRoute.ts | 25 +++++++++++++------ .../constructBridgeRequirements.ts | 15 +++++------ .../routing/indexer/fetchL1Representation.ts | 4 +-- .../routing/onRamp/onRampRoute.ts | 3 ++- .../routing/swap/swapRoute.test.ts | 12 ++++++++- .../smartCheckout/routing/swap/swapRoute.ts | 18 ++++++++----- packages/checkout/sdk/src/tokens/tokens.ts | 3 ++- packages/checkout/sdk/src/utils/utils.test.ts | 18 +++++++++++++ packages/checkout/sdk/src/utils/utils.ts | 3 +++ 15 files changed, 96 insertions(+), 34 deletions(-) create mode 100644 packages/checkout/sdk/src/utils/utils.test.ts create mode 100644 packages/checkout/sdk/src/utils/utils.ts diff --git a/packages/checkout/sdk/src/balances/balances.ts b/packages/checkout/sdk/src/balances/balances.ts index 57a943f685..9297a32017 100644 --- a/packages/checkout/sdk/src/balances/balances.ts +++ b/packages/checkout/sdk/src/balances/balances.ts @@ -23,6 +23,7 @@ import { DEFAULT_TOKEN_DECIMALS, ERC20ABI, NATIVE, } from '../env'; import { measureAsyncExecution } from '../logger/debugLogger'; +import { isMatchingAddress } from '../utils/utils'; export const getBalance = async ( config: CheckoutConfiguration, @@ -219,7 +220,7 @@ export const getBalances = async ( // For some reason isNativeToken always returns undefined. // We have spent way too much time figuring out why this is happening. // That we have given up -- keep it as it is for now. - if (!token.address || token.address.toLocaleLowerCase() === NATIVE) { + if (!token.address || isMatchingAddress(token.address, NATIVE)) { allBalancePromises.push( getBalance(config, web3Provider, walletAddress), ); @@ -240,7 +241,7 @@ export const getBalances = async ( // For some reason isNativeToken always returns undefined. // We have spent way too much time figuring out why this is happening. // That we have given up -- keep it as it is for now. - if (!token.address || token.address.toLocaleLowerCase() === NATIVE) resp.value.token.address = NATIVE; + if (!token.address || isMatchingAddress(token.address, NATIVE)) resp.value.token.address = NATIVE; return resp.value; }); diff --git a/packages/checkout/sdk/src/sdk.ts b/packages/checkout/sdk/src/sdk.ts index c5cc7ccfb7..06a95a51d1 100644 --- a/packages/checkout/sdk/src/sdk.ts +++ b/packages/checkout/sdk/src/sdk.ts @@ -67,6 +67,7 @@ import { AvailabilityService, availabilityService } from './availability'; import { loadUnresolved } from './widgets/load'; import { WidgetsInit } from './types/widgets'; import { HttpClient } from './api/http'; +import { isMatchingAddress } from './utils/utils'; const SANDBOX_CONFIGURATION = { baseConfig: { @@ -490,7 +491,7 @@ export class Checkout { } const tokenList = await tokens.getTokenAllowList(this.config, { type: TokenFilterTypes.ONRAMP }); - const token = tokenList.tokens?.find((t) => t.address?.toLowerCase() === params.tokenAddress?.toLowerCase()); + const token = tokenList.tokens?.find((t) => isMatchingAddress(t.address, params.tokenAddress)); if (token) { tokenAmount = params.tokenAmount; tokenSymbol = token.symbol; diff --git a/packages/checkout/sdk/src/smartCheckout/allowList/allowListCheck.ts b/packages/checkout/sdk/src/smartCheckout/allowList/allowListCheck.ts index 0f858be410..9dd52cdab7 100644 --- a/packages/checkout/sdk/src/smartCheckout/allowList/allowListCheck.ts +++ b/packages/checkout/sdk/src/smartCheckout/allowList/allowListCheck.ts @@ -6,13 +6,17 @@ import { TokenFilterTypes, } from '../../types'; import { TokenBalanceResult, TokenBalances } from '../routing/types'; +import { isMatchingAddress } from '../../utils/utils'; import { RoutingTokensAllowList } from './types'; const filterTokens = (allowedTokens: TokenInfo[], balances: TokenBalanceResult | undefined) => { if (balances && balances.success) { return allowedTokens.filter((token) => { if ('address' in token) { - return balances.balances.find((balance) => balance.token.address === token.address && balance.balance.gt(0)); + return balances.balances.find( + (balance) => isMatchingAddress(balance.token.address, token.address) + && balance.balance.gt(0), + ); } return balances.balances.find((balance) => !('address' in balance.token) && balance.balance.gt(0)); }); diff --git a/packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceCheck.ts b/packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceCheck.ts index f19629ee99..5c791f2703 100644 --- a/packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceCheck.ts +++ b/packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceCheck.ts @@ -22,6 +22,7 @@ import { getTokensFromRequirements, } from './balanceRequirement'; import { ERC721ABI, NATIVE } from '../../env'; +import { isMatchingAddress } from '../../utils/utils'; /** * Gets the balances for all NATIVE and ERC20 balance requirements. @@ -85,7 +86,7 @@ const getERC721Balances = async ( erc721Owners.forEach((erc721OwnerAddress, index) => { const itemRequirement = erc721s.get(erc721OwnersPromiseIds[index]); let itemCount = 0; - if (itemRequirement && ownerAddress === erc721OwnerAddress) { + if (itemRequirement && isMatchingAddress(ownerAddress, erc721OwnerAddress)) { itemCount = 1; } erc721Balances.push({ diff --git a/packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceRequirement.ts b/packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceRequirement.ts index fe17a9d1d6..2e5e027652 100644 --- a/packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceRequirement.ts +++ b/packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceRequirement.ts @@ -18,6 +18,7 @@ import { } from './types'; import { DEFAULT_TOKEN_DECIMALS, NATIVE, ZKEVM_NATIVE_TOKEN } from '../../env'; import { isNativeToken } from '../../tokens'; +import { isMatchingAddress } from '../../utils/utils'; export const getTokensFromRequirements = (itemRequirements: ItemRequirement[]): TokenInfo[] => itemRequirements .map((itemRequirement) => { @@ -50,7 +51,7 @@ export const getERC721BalanceRequirement = ( // Find the requirements related balance const itemBalanceResult = balances.find((balance) => { const balanceERC721Result = balance as ERC721Balance; - return balanceERC721Result.contractAddress === itemRequirement.contractAddress + return isMatchingAddress(balanceERC721Result.contractAddress, itemRequirement.contractAddress) && balanceERC721Result.id === itemRequirement.id; }); @@ -96,7 +97,7 @@ export const getTokenBalanceRequirement = ( // Get the requirements related balance if (itemRequirement.type === ItemType.ERC20) { itemBalanceResult = balances.find((balance) => { - return (balance as TokenBalance).token?.address === itemRequirement.tokenAddress; + return isMatchingAddress((balance as TokenBalance).token?.address, itemRequirement.tokenAddress); }); } else if (itemRequirement.type === ItemType.NATIVE) { itemBalanceResult = balances.find((balance) => { diff --git a/packages/checkout/sdk/src/smartCheckout/routing/bridge/bridgeRoute.ts b/packages/checkout/sdk/src/smartCheckout/routing/bridge/bridgeRoute.ts index 6f06532f3b..1a55f9dbd6 100644 --- a/packages/checkout/sdk/src/smartCheckout/routing/bridge/bridgeRoute.ts +++ b/packages/checkout/sdk/src/smartCheckout/routing/bridge/bridgeRoute.ts @@ -24,6 +24,7 @@ import { } from '../indexer/fetchL1Representation'; import { DEFAULT_TOKEN_DECIMALS } from '../../../env'; import { isNativeToken } from '../../../tokens'; +import { isMatchingAddress } from '../../../utils/utils'; export const hasSufficientL1Eth = ( tokenBalanceResult: TokenBalanceResult, @@ -147,7 +148,7 @@ export const bridgeRoute = async ( const { l1address } = l1RepresentationResult as L1ToL2TokenAddressMapping; if (isNativeToken(l1address)) { if (!allowedL1TokenList.find((token) => isNativeToken(token.address))) return undefined; - } else if (!allowedL1TokenList.find((token) => token.address === l1address)) { + } else if (!allowedL1TokenList.find((token) => isMatchingAddress(token.address, l1address))) { return undefined; } @@ -191,7 +192,9 @@ export const bridgeRoute = async ( } // Find the balance of the L1 representation of the token and check if the balance covers the delta - const erc20balance = tokenBalanceResult.balances.find((balance) => balance.token.address === l1address); + const erc20balance = tokenBalanceResult.balances.find( + (balance) => isMatchingAddress(balance.token.address, l1address), + ); if (erc20balance && erc20balance.balance.gte( bridgeRequirement.amount, diff --git a/packages/checkout/sdk/src/smartCheckout/routing/bridgeAndSwap/bridgeAndSwapRoute.ts b/packages/checkout/sdk/src/smartCheckout/routing/bridgeAndSwap/bridgeAndSwapRoute.ts index f3cd25ecad..7e34bfddbb 100644 --- a/packages/checkout/sdk/src/smartCheckout/routing/bridgeAndSwap/bridgeAndSwapRoute.ts +++ b/packages/checkout/sdk/src/smartCheckout/routing/bridgeAndSwap/bridgeAndSwapRoute.ts @@ -24,6 +24,7 @@ import { constructBridgeRequirements } from './constructBridgeRequirements'; import { fetchL1ToL2Mappings } from './fetchL1ToL2Mappings'; import { INDEXER_ETH_ROOT_CONTRACT_ADDRESS, L1ToL2TokenAddressMapping } from '../indexer/fetchL1Representation'; import { getDexQuotes } from './getDexQuotes'; +import { isMatchingAddress } from '../../../utils/utils'; export const abortBridgeAndSwap = ( bridgeableTokens: string[], @@ -56,9 +57,11 @@ export const filterSwappableTokensByBridgeableAddresses = ( // TODO: Check for ETH (native) L1 in bridgeableTokens first if (!bridgeableTokens.includes(addresses.l1address)) continue; // Filter out the token that is required from the swappable tokens list - if (addresses.l2address === requiredTokenAddress) continue; + if (isMatchingAddress(addresses.l2address, requiredTokenAddress)) continue; - const tokenInfo = swappableTokens.find((token) => token.address === addresses.l2address); + const tokenInfo = swappableTokens.find( + (token) => isMatchingAddress(token.address, addresses.l2address), + ); if (!tokenInfo) continue; filteredSwappableTokens.push(tokenInfo); } @@ -104,7 +107,7 @@ const modifyTokenBalancesWithBridgedAmount = ( const newBalance = l2balance.add(amount); - const tokenInfo = swappableTokens.find((token) => token.address === l2address) as TokenInfo; + const tokenInfo = swappableTokens.find((token) => isMatchingAddress(token.address, l2address)) as TokenInfo; balanceMap.set(l2address, { balance: newBalance, @@ -143,7 +146,9 @@ export const reapplyOriginalSwapBalances = ( let originalBalance = BigNumber.from(0); let originalFormattedBalance = '0'; - const l2balance = tokenBalance.balances.find((balance) => balance.token.address === fundingItem.token.address); + const l2balance = tokenBalance.balances.find( + (balance) => isMatchingAddress(balance.token.address, fundingItem.token.address), + ); if (l2balance) { originalBalance = l2balance.balance; originalFormattedBalance = l2balance.formattedBalance; @@ -170,15 +175,21 @@ export const constructBridgeAndSwapRoutes = ( const mapping = l1tol2Addresses.find( (addresses) => { if (bridgeFundingStep.fundingItem.token.address === undefined) { - return addresses.l1address === INDEXER_ETH_ROOT_CONTRACT_ADDRESS && addresses.l2address; + return isMatchingAddress(addresses.l1address, INDEXER_ETH_ROOT_CONTRACT_ADDRESS) && addresses.l2address; } - return addresses.l1address === bridgeFundingStep.fundingItem.token.address && addresses.l2address; + return ( + isMatchingAddress( + addresses.l1address, + bridgeFundingStep.fundingItem.token.address, + ) + && addresses.l2address + ); }, ); if (!mapping) continue; const swapFundingStep = swapFundingSteps.find( - (step) => step.fundingItem.token.address === mapping.l2address, + (step) => isMatchingAddress(step.fundingItem.token.address, mapping.l2address), ); if (!swapFundingStep) continue; diff --git a/packages/checkout/sdk/src/smartCheckout/routing/bridgeAndSwap/constructBridgeRequirements.ts b/packages/checkout/sdk/src/smartCheckout/routing/bridgeAndSwap/constructBridgeRequirements.ts index dfbc84b8f2..9f3f68223b 100644 --- a/packages/checkout/sdk/src/smartCheckout/routing/bridgeAndSwap/constructBridgeRequirements.ts +++ b/packages/checkout/sdk/src/smartCheckout/routing/bridgeAndSwap/constructBridgeRequirements.ts @@ -4,6 +4,7 @@ import { BridgeRequirement } from '../bridge/bridgeRoute'; import { DexQuote, DexQuotes } from '../types'; import { INDEXER_ETH_ROOT_CONTRACT_ADDRESS, L1ToL2TokenAddressMapping } from '../indexer/fetchL1Representation'; import { BalanceCheckResult } from '../../balanceCheck/types'; +import { isMatchingAddress } from '../../../utils/utils'; // The dex will return all the fees which is in a particular token (currently always IMX) // If any of the fees are in the same token that is trying to be swapped (e.g. trying to swap IMX) @@ -16,13 +17,13 @@ export const getFeesForTokenAddress = ( let fees = BigNumber.from(0); dexQuote.quote.fees.forEach((fee) => { - if (fee.amount.token.address === tokenAddress) { + if (isMatchingAddress(fee.amount.token.address, tokenAddress)) { fees = fees.add(fee.amount.value); } }); if (dexQuote.approval) { - if (dexQuote.approval.token.address === tokenAddress) { + if (isMatchingAddress(dexQuote.approval.token.address, tokenAddress)) { fees = fees.add(dexQuote.approval.value); } } @@ -40,7 +41,7 @@ export const getAmountFromBalanceRequirement = ( // Find if there is an existing balance requirement of the token attempting to be bridged->swapped for (const requirement of balanceRequirements.balanceRequirements) { if (requirement.type === ItemType.NATIVE || requirement.type === ItemType.ERC20) { - if (requirement.required.token.address === quotedTokenAddress) { + if (isMatchingAddress(requirement.required.token.address, quotedTokenAddress)) { return requirement.required.balance; } } @@ -97,9 +98,9 @@ export const constructBridgeRequirements = ( for (const [tokenAddress, quote] of dexQuotes) { // Get the L2 balance for the token address - const l2balance = l2balances.find((balance) => balance.token.address === tokenAddress); + const l2balance = l2balances.find((balance) => isMatchingAddress(balance.token.address, tokenAddress)); const l1tol2TokenMapping = l1tol2addresses.find( - (token) => token.l2address === tokenAddress, + (token) => isMatchingAddress(token.l2address, tokenAddress), ); if (!l1tol2TokenMapping) continue; @@ -109,10 +110,10 @@ export const constructBridgeRequirements = ( // If the user does not have any L1 balance for this token then cannot bridge const l1balance = l1balances.find((balance) => { if (balance.token.address === undefined - && l1address === INDEXER_ETH_ROOT_CONTRACT_ADDRESS) { + && isMatchingAddress(l1address, INDEXER_ETH_ROOT_CONTRACT_ADDRESS)) { return true; } - return balance.token.address === l1address; + return isMatchingAddress(balance.token.address, l1address); }); if (!l1balance) continue; diff --git a/packages/checkout/sdk/src/smartCheckout/routing/indexer/fetchL1Representation.ts b/packages/checkout/sdk/src/smartCheckout/routing/indexer/fetchL1Representation.ts index 426dad826c..a5c990b535 100644 --- a/packages/checkout/sdk/src/smartCheckout/routing/indexer/fetchL1Representation.ts +++ b/packages/checkout/sdk/src/smartCheckout/routing/indexer/fetchL1Representation.ts @@ -3,6 +3,7 @@ import { createBlockchainDataInstance } from '../../../instance'; import { NATIVE } from '../../../env'; import { ChainId, ChainSlug, ImxAddressConfig } from '../../../types'; import { isNativeToken } from '../../../tokens'; +import { isMatchingAddress } from '../../../utils/utils'; // If the root address evaluates to this then its ETH export const INDEXER_ETH_ROOT_CONTRACT_ADDRESS = '0x0000000000000000000000000000000000000eee'; @@ -46,9 +47,8 @@ export const fetchL1Representation = async ( contractAddress: l2address, }); - // TODO: When bridge is ready we need to understand how L2 ETH will be mapped back to L1 ETH const l1address = tokenData.result.root_contract_address; - if (l1address === INDEXER_ETH_ROOT_CONTRACT_ADDRESS) { + if (isMatchingAddress(l1address ?? '', INDEXER_ETH_ROOT_CONTRACT_ADDRESS)) { return { l1address: 'native', l2address, diff --git a/packages/checkout/sdk/src/smartCheckout/routing/onRamp/onRampRoute.ts b/packages/checkout/sdk/src/smartCheckout/routing/onRamp/onRampRoute.ts index e9e0668a41..0883128825 100644 --- a/packages/checkout/sdk/src/smartCheckout/routing/onRamp/onRampRoute.ts +++ b/packages/checkout/sdk/src/smartCheckout/routing/onRamp/onRampRoute.ts @@ -7,6 +7,7 @@ import { import { BalanceERC20Requirement, BalanceNativeRequirement, BalanceRequirement } from '../../balanceCheck/types'; import { allowListCheckForOnRamp } from '../../allowList'; import { isNativeToken } from '../../../tokens'; +import { isMatchingAddress } from '../../../utils/utils'; export const onRampRoute = async ( config: CheckoutConfiguration, @@ -26,7 +27,7 @@ export const onRampRoute = async ( if (!required.token) return; if ( isNativeToken(required.token.address) - || token.address.toLowerCase() === required.token.address?.toLowerCase() + || isMatchingAddress(token.address, required.token.address) ) { hasAllowList = true; } diff --git a/packages/checkout/sdk/src/smartCheckout/routing/swap/swapRoute.test.ts b/packages/checkout/sdk/src/smartCheckout/routing/swap/swapRoute.test.ts index e11b95791c..f3f9e3c763 100644 --- a/packages/checkout/sdk/src/smartCheckout/routing/swap/swapRoute.test.ts +++ b/packages/checkout/sdk/src/smartCheckout/routing/swap/swapRoute.test.ts @@ -285,7 +285,7 @@ describe('swapRoute', () => { ]); }); - xit('should recommend swap route for NATIVE', async () => { + it('should recommend swap route for NATIVE', async () => { const balanceRequirement = { type: ItemType.NATIVE, sufficient: false, @@ -328,6 +328,16 @@ describe('swapRoute', () => { decimals: 18, }, }, + { + balance: BigNumber.from(10), + formattedBalance: '10', + token: { + name: 'ERC20', + symbol: 'ERC20', + decimals: 18, + address: '0xERC20_2', + }, + }, ], }], ]); diff --git a/packages/checkout/sdk/src/smartCheckout/routing/swap/swapRoute.ts b/packages/checkout/sdk/src/smartCheckout/routing/swap/swapRoute.ts index ec7a74b5d6..b4ac090477 100644 --- a/packages/checkout/sdk/src/smartCheckout/routing/swap/swapRoute.ts +++ b/packages/checkout/sdk/src/smartCheckout/routing/swap/swapRoute.ts @@ -16,6 +16,7 @@ import { BalanceCheckResult, BalanceRequirement } from '../../balanceCheck/types import { TokenBalanceResult } from '../types'; import { quoteFetcher } from './quoteFetcher'; import { isNativeToken } from '../../../tokens'; +import { isMatchingAddress } from '../../../utils/utils'; const constructFees = ( approvalGasFee: Amount | null | undefined, @@ -175,7 +176,7 @@ export const checkUserCanCoverApprovalFees = ( const l2BalanceOfApprovalToken = l2Balances.find( (balance) => ( isNativeToken(balance.token.address) && isNativeToken(approvalGasTokenAddress)) - || balance.token.address === approvalGasTokenAddress, + || isMatchingAddress(balance.token.address, approvalGasTokenAddress), ); if (!l2BalanceOfApprovalToken) return { sufficient: false, approvalGasFee, approvalGasTokenAddress }; @@ -244,7 +245,7 @@ export const checkUserCanCoverSwapFees = ( const l2BalanceOfFeeToken = l2Balances.find( (balance) => ( isNativeToken(balance.token.address) && isNativeToken(tokenAddress)) - || balance.token.address === tokenAddress, + || isMatchingAddress(balance.token.address, tokenAddress), ); if (!l2BalanceOfFeeToken) { return false; @@ -276,7 +277,10 @@ export const checkIfUserCanCoverRequirement = ( balanceRequirements.balanceRequirements.forEach((requirement) => { if (requirement.type === ItemType.NATIVE || requirement.type === ItemType.ERC20) { - if (requirement.required.token.address === quoteTokenAddress) { + if ( + requirement.required.token.address + && isMatchingAddress(requirement.required.token.address, quoteTokenAddress) + ) { balanceRequirementToken = requirement.required.token.address; requirementExists = true; // Get the balance that would remain if the requirement was removed from the users balance @@ -289,13 +293,13 @@ export const checkIfUserCanCoverRequirement = ( if (!requirementExists) return true; // Remove approval fees from the remainder if token matches as these need to be taken out to cover the swap - if (approvalFees.approvalGasTokenAddress === balanceRequirementToken) { + if (isMatchingAddress(approvalFees.approvalGasTokenAddress, balanceRequirementToken)) { remainingBalance = remainingBalance.sub(approvalFees.approvalGasFee); } // Remove swap fees from the remainder if token matches as these need to be taken out to cover the swap for (const swapFee of swapFees) { - if (swapFee.amount.token.address === balanceRequirementToken) { + if (isMatchingAddress(swapFee.amount.token.address, balanceRequirementToken)) { remainingBalance = remainingBalance.sub(swapFee.amount.value); } } @@ -340,7 +344,9 @@ export const swapRoute = async ( const quote = quotes.get(quoteTokenAddress); if (!quote) continue; // Find the balance the user has for this quoted token - const userBalanceOfQuotedToken = l2Balances.find((balance) => balance.token.address === quoteTokenAddress); + const userBalanceOfQuotedToken = l2Balances.find( + (balance) => isMatchingAddress(balance.token.address, quoteTokenAddress), + ); // If no balance found on L2 for this quoted token then continue if (!userBalanceOfQuotedToken) continue; // Check the amount of quoted token required against the user balance diff --git a/packages/checkout/sdk/src/tokens/tokens.ts b/packages/checkout/sdk/src/tokens/tokens.ts index 85e9ba9d59..29afd81bdf 100644 --- a/packages/checkout/sdk/src/tokens/tokens.ts +++ b/packages/checkout/sdk/src/tokens/tokens.ts @@ -13,6 +13,7 @@ import { import { CheckoutConfiguration, getL1ChainId } from '../config'; import { ERC20ABI, NATIVE } from '../env'; import { CheckoutErrorType, withCheckoutError } from '../errors'; +import { isMatchingAddress } from '../utils/utils'; type TokenAllowListParams = { type: TokenFilterTypes; @@ -68,7 +69,7 @@ export const getTokenAllowList = async ( export const isNativeToken = ( address: string | undefined, -): boolean => !address || address.toLocaleLowerCase() === NATIVE; +): boolean => !address || isMatchingAddress(address, NATIVE); export async function getERC20TokenInfo( web3Provider: Web3Provider | JsonRpcProvider, diff --git a/packages/checkout/sdk/src/utils/utils.test.ts b/packages/checkout/sdk/src/utils/utils.test.ts new file mode 100644 index 0000000000..07bb00cc70 --- /dev/null +++ b/packages/checkout/sdk/src/utils/utils.test.ts @@ -0,0 +1,18 @@ +import { isMatchingAddress } from './utils'; + +describe('utils', () => { + it('should return true if addresses are the same', () => { + const address = isMatchingAddress('0x123', '0x123'); + expect(address).toBeTruthy(); + }); + + it('should return true if addresses are the same with different casing', () => { + const address = isMatchingAddress('0xABC123', '0xabc123'); + expect(address).toBeTruthy(); + }); + + it('should return false if addresses do not match', () => { + const address = isMatchingAddress('0x123', '0x1234'); + expect(address).toBeFalsy(); + }); +}); diff --git a/packages/checkout/sdk/src/utils/utils.ts b/packages/checkout/sdk/src/utils/utils.ts new file mode 100644 index 0000000000..de50a7974d --- /dev/null +++ b/packages/checkout/sdk/src/utils/utils.ts @@ -0,0 +1,3 @@ +export const isMatchingAddress = (addressA: string = '', addressB: string = '') => ( + addressA.toLowerCase() === addressB.toLowerCase() +);