From b19ae3cfef58ff75780f0795c929b83ffe725751 Mon Sep 17 00:00:00 2001 From: Wayne Cheng <677680+welps@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:28:36 -0400 Subject: [PATCH] chore: remove unused code, remove guardrails that cause issues with new providers (#88) * chore: remove unused code, remove guardrails that cause issues with new providers * introduce new field for approvals * remove no_approval field instead of deprecating --- sdk/.gitignore | 1 + sdk/src/quotes.ts | 91 ++---------- sdk/src/types/index.ts | 17 ++- sdk/src/utils/constants.ts | 23 +-- sdk/src/utils/sanity_check.ts | 146 +----------------- sdk/tests/utils/build_url.test.ts | 6 +- sdk/tests/utils/sanity_check.test.ts | 212 +-------------------------- 7 files changed, 39 insertions(+), 457 deletions(-) diff --git a/sdk/.gitignore b/sdk/.gitignore index 4c9d7c3..89eff09 100644 --- a/sdk/.gitignore +++ b/sdk/.gitignore @@ -2,3 +2,4 @@ .DS_Store node_modules dist +.idea diff --git a/sdk/src/quotes.ts b/sdk/src/quotes.ts index bdb6045..b0ebcaf 100644 --- a/sdk/src/quotes.ts +++ b/sdk/src/quotes.ts @@ -16,7 +16,6 @@ import { QuoteParams, SocketChainsData, Source, - SwapType, TransactionOptions, } from './types'; import { @@ -26,14 +25,10 @@ import { PERMIT_EXPIRATION_TS, RAINBOW_ROUTER_CONTRACT_ADDRESS, RAINBOW_ROUTER_CONTRACT_ADDRESS_ZORA, - WRAPPED_ASSET, } from './utils/constants'; import { signPermit } from './utils/permit'; import { getReferrerCode } from './utils/referrer'; -import { - extractDestinationAddress, - sanityCheckAddress, -} from './utils/sanity_check'; +import { sanityCheckAddress } from './utils/sanity_check'; /** * Function to get the rainbow router contract address based on the chainId @@ -94,16 +89,10 @@ const buildRainbowQuoteUrl = ({ fromAddress, sellToken: sellTokenAddress, slippage: String(slippage), - swapType: SwapType.normal, ...(source ? { source } : {}), ...(sellAmount ? { sellAmount: String(sellAmount) } : { buyAmount: String(buyAmount) }), - // When buying ETH, we need to tell the aggregator - // to return the funds to the contract if we need to take a fee - ...(buyTokenAddress === ETH_ADDRESS - ? { destReceiver: getRainbowRouterContractAddress(chainId) } - : {}), ...(feePercentageBasisPoints !== undefined ? { feePercentageBasisPoints: String(feePercentageBasisPoints) } : {}), @@ -157,13 +146,12 @@ export const buildRainbowCrosschainQuoteUrl = ({ sellAmount: String(sellAmount), sellToken: sellTokenAddress, slippage: String(slippage), - swapType: SwapType.crossChain, toChainId: String(toChainId), ...(feePercentageBasisPoints !== undefined ? { feePercentageBasisPoints: String(feePercentageBasisPoints) } : {}), }); - return `${API_BASE_URL}/v1/quote?bridgeVersion=3&` + searchParams.toString(); + return `${API_BASE_URL}/v1/quote?bridgeVersion=4&` + searchParams.toString(); }; /** @@ -202,10 +190,9 @@ export const buildRainbowClaimBridgeQuoteUrl = ({ sellToken: sellTokenAddress, slippage: String(slippage), source: Source.CrosschainAggregatorRelay.toString(), - swapType: SwapType.crossChain, toChainId: String(toChainId), }); - return `${API_BASE_URL}/v1/quote?bridgeVersion=3&` + searchParams.toString(); + return `${API_BASE_URL}/v1/quote?bridgeVersion=4&` + searchParams.toString(); }; /** @@ -270,51 +257,6 @@ export const getQuote = async ( currency, } = params; - const sellTokenAddressLowercase = sellTokenAddress.toLowerCase(); - const buyTokenAddressLowercase = buyTokenAddress.toLowerCase(); - const ethAddressLowerCase = ETH_ADDRESS.toLowerCase(); - const wrappedAssetLowercase = WRAPPED_ASSET[chainId]?.toLowerCase(); - const isWrap = - sellTokenAddressLowercase === ethAddressLowerCase && - buyTokenAddressLowercase === wrappedAssetLowercase; - const isUnwrap = - sellTokenAddressLowercase === wrappedAssetLowercase && - buyTokenAddressLowercase === ethAddressLowerCase; - - // When wrapping or unwrapping ETH, the quote is always 1:1 - // so we don't need to call our backend. - if (isWrap || isUnwrap) { - const amount = sellAmount || buyAmount; - // For wrapping/unwrapping, we need either sell amount or buy amount - if (!amount) { - return null; - } - - return { - buyAmount: amount, - buyAmountDisplay: amount, - buyAmountDisplayMinimum: amount, - buyAmountInEth: amount, - buyAmountMinusFees: amount, - buyTokenAddress, - chainId, - defaultGasLimit: isWrap ? '30000' : '40000', - fee: 0, - feeInEth: 0, - feePercentageBasisPoints: 0, - from: fromAddress, - inputTokenDecimals: 18, - outputTokenDecimals: 18, - sellAmount: amount, - sellAmountDisplay: amount, - sellAmountInEth: amount, - sellAmountMinusFees: amount, - sellTokenAddress, - tradeAmountUSD: 0, - tradeFeeAmountUSD: 0, - }; - } - if (isNaN(Number(sellAmount)) && isNaN(Number(buyAmount))) { return null; } @@ -441,24 +383,19 @@ const fetchAndSanityCheckCrosschainQuote = async ( return quote as QuoteError; } - const quoteWithRestrictedAllowanceTarget = quote as CrosschainQuote; try { - quoteWithRestrictedAllowanceTarget.allowanceTarget = sanityCheckAddress( - quoteWithRestrictedAllowanceTarget.source, - quoteWithRestrictedAllowanceTarget.chainId, - quoteWithRestrictedAllowanceTarget.allowanceTarget - ); + sanityCheckAddress(quote?.to); } catch (e) { return { error: true, message: e instanceof Error ? e.message - : `unexpected error happened while checking crosschain quote's address: ${quoteWithRestrictedAllowanceTarget.allowanceTarget}`, + : `unexpected error happened while checking crosschain quote's address: ${quote?.to}`, } as QuoteError; } - return quoteWithRestrictedAllowanceTarget; + return quote; }; const calculateDeadline = async (wallet: Wallet) => { @@ -629,11 +566,7 @@ export const fillCrosschainQuote = async ( ): Promise => { const { data, from, value } = quote; - const to = sanityCheckAddress( - quote.source, - quote.fromChainId, - extractDestinationAddress(quote) - ); + sanityCheckAddress(quote?.to); let txData = data; if (referrer) { @@ -643,7 +576,7 @@ export const fillCrosschainQuote = async ( const swapTx = await wallet.sendTransaction({ data: txData, from, - to, + to: quote.to, ...{ ...transactionOptions, value, @@ -733,17 +666,13 @@ export const getCrosschainQuoteExecutionDetails = ( ): CrosschainQuoteExecutionDetails => { const { from, data, value } = quote; - const to = sanityCheckAddress( - quote.source, - quote.fromChainId, - extractDestinationAddress(quote) - ); + sanityCheckAddress(quote?.to); return { method: provider.estimateGas({ data, from, - to, + to: quote.to, value, }), params: { diff --git a/sdk/src/types/index.ts b/sdk/src/types/index.ts index 7c28988..e8f3289 100644 --- a/sdk/src/types/index.ts +++ b/sdk/src/types/index.ts @@ -34,10 +34,13 @@ export enum Source { export enum SwapType { normal = 'normal', crossChain = 'cross-chain', + wrap = 'wrap', + unwrap = 'unwrap', } export type EthereumAddress = string; +// QuoteParams are the parameters required to get a quote from the Swap API export interface QuoteParams { source?: Source; chainId: number; @@ -49,7 +52,6 @@ export interface QuoteParams { slippage: number; destReceiver?: EthereumAddress; refuel?: boolean; - swapType: SwapType; feePercentageBasisPoints?: number; toChainId?: number; currency: string; @@ -60,12 +62,14 @@ export interface ProtocolShare { part: number; } +// QuoteError is returned when a swap quote failed export interface QuoteError { error: boolean; error_code?: number; message: string; } +// Quote is the response from the Swap API export interface Quote { source?: Source; from: EthereumAddress; @@ -93,11 +97,13 @@ export interface Quote { inputTokenDecimals?: number; outputTokenDecimals?: number; defaultGasLimit?: string; - swapType?: string; + swapType: SwapType; tradeAmountUSD: number; tradeFeeAmountUSD: number; rewards?: Reward[]; chainId: number; + allowanceTarget: string; + allowanceNeeded: boolean; } export interface TokenAsset { @@ -257,15 +263,10 @@ export interface SocketChainsData { }[]; } +// CrosschainQuote holds additional fields relevant for crosschain swaps export interface CrosschainQuote extends Quote { - fromAsset: SocketAsset; - fromChainId: number; - toAsset: SocketAsset; - toChainId: number; - allowanceTarget?: string; routes: SocketRoute[]; refuel: SocketRefuelData | null; - no_approval: boolean | undefined; } export interface TransactionOptions { diff --git a/sdk/src/utils/constants.ts b/sdk/src/utils/constants.ts index 3dc9a74..d88a4a1 100644 --- a/sdk/src/utils/constants.ts +++ b/sdk/src/utils/constants.ts @@ -8,30 +8,13 @@ export const RAINBOW_ROUTER_CONTRACT_ADDRESS = export const RAINBOW_ROUTER_CONTRACT_ADDRESS_ZORA = '0xa61550e9ddd2797e16489db09343162be98d9483'; -// SOCKET_GATEWAY_CONTRACT_ADDRESSES is mapped by int chain ID to avoid a breaking change -export const SOCKET_GATEWAY_CONTRACT_ADDRESSESS = new Map([ - [ChainId.mainnet, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.optimism, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.polygon, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.arbitrum, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.bsc, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.zora, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.base, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.avalanche, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.blast, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], - [ChainId.apechain, '0x3a23F943181408EAC424116Af7b7790c94Cb97a5'], -]); - -// RELAY_LINK_BRIDGING_RELAYER_ADDRESS is the EOA used by relay link as relayer on all chains -export const RELAY_LINK_BRIDGING_RELAYER_ADDRESS = - '0xf70da97812CB96acDF810712Aa562db8dfA3dbEF'; - -export const ERC20_TRANSFER_SIGNATURE = `0xa9059cbb`; - export type MultiChainAsset = { [key: string]: EthereumAddress; }; +/** + * @deprecated: Should not use this anymore to reduce friction for new network support + */ export const WRAPPED_ASSET: MultiChainAsset = { [`${ChainId.mainnet}`]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', [`${ChainId.optimism}`]: '0x4200000000000000000000000000000000000006', diff --git a/sdk/src/utils/sanity_check.ts b/sdk/src/utils/sanity_check.ts index f0efa6a..ae85945 100644 --- a/sdk/src/utils/sanity_check.ts +++ b/sdk/src/utils/sanity_check.ts @@ -1,148 +1,18 @@ -import { ChainId, CrosschainQuote, Source } from '../types'; -import { - ERC20_TRANSFER_SIGNATURE, - ETH_ADDRESS, - RELAY_LINK_BRIDGING_RELAYER_ADDRESS, - SOCKET_GATEWAY_CONTRACT_ADDRESSESS, -} from './constants'; - /** - * Sanity checks the quote's returned address against the expected address stored in the SDK. - * This function ensures the integrity and correctness of the destination address provided by the quote source. + * sanityCheckAddress ensures the integrity and correctness of the destination address to prevent transactions to null address * - * @param quoteSource The aggregator used for the quote. - * @param chainID The origin network chain ID for the quote. * @param assertedAddress The destination address provided by the quote. - * @returns {string} The destination address stored in the SDK for the provided (source, chainID) combination. - * And if it should be overridden in the quote. * @throws {Error} Throws an error if any of the following conditions are met: * - The quote's destination address is undefined. * - No destination address is defined in the SDK for the provided (source, chainID) combination. * - The provided quote's destination address does not case-insensitively match the SDK's stored destination address. */ -export function sanityCheckAddress( - quoteSource: Source | undefined, - chainID: ChainId, - assertedAddress: string | undefined -): string { - if (assertedAddress === undefined || assertedAddress === '') { - throw new Error( - `quote's destination addresses must be defined (API Response)` - ); +export function sanityCheckAddress(assertedAddress: string | undefined) { + if ( + assertedAddress === undefined || + assertedAddress === '' || + assertedAddress === '0x0000000000000000000000000000000000000000' + ) { + throw new Error(`provided address is not defined (API issue)`); } - const expectedAddress = getExpectedDestinationAddress(quoteSource, chainID); - if (expectedAddress === undefined || expectedAddress === '') { - throw new Error( - `expected source ${quoteSource}'s destination address on chainID ${chainID} must be defined (Swap SDK)` - ); - } - if (expectedAddress.toLowerCase() !== assertedAddress?.toLowerCase()) { - throw new Error( - `source ${quoteSource}'s destination address '${assertedAddress}' on chainID ${chainID} is not consistent, expected: '${expectedAddress}'` - ); - } - return expectedAddress; -} - -/** - * Retrieves the destination address from a cross-chain quote object, returning undefined - * when the quote source is not known or the quote does not contain a valid destination address. - * - * @param quote The cross-chain quote object returned by the API. - * - * @returns The destination address as a string if available. - * Returns undefined if the quote does not properly specify a destination. - * - * @example - * // Example for a quote from socket - * const quoteSocket = { - * to: '0x1234567890123456789012345678901234567890', - * data: '0x...', - * sellTokenAddress: '0x...' - * }; - * console.log(getToAddressFromCrosschainQuote(Source.CrosschainAggregatorSocket, quoteSocket)); - * // Output: '0x1234567890123456789012345678901234567890' - * - * // Example for a quote from CrosschainAggregatorRelay where the sell token is ETH - * const quoteRelayETH = { - * to: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef', - * data: '0x...', - * sellTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' - * }; - * console.log(getToAddressFromCrosschainQuote(Source.CrosschainAggregatorRelay, quoteRelayETH)); - * // Output: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef' - * - * // Example for a quote from CrosschainAggregatorRelay where the sell token is not ETH - * const quoteRelayERC20 = { - * to: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef', - * data: '0xa9059cbb000000000000000000000000f70da97812cb96acdf810712aa562db8dfa3dbef...', - * sellTokenAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef' - * }; - * console.log(getToAddressFromCrosschainQuote(Source.CrosschainAggregatorRelay, quoteRelayERC20)); - * // Output: '0xf70da97812cb96acdf810712aa562db8dfa3dbef' (assuming the call data was a ERC20 transfer) - */ -export function extractDestinationAddress( - quote: CrosschainQuote -): string | undefined { - const quoteSource = quote.source; - const validQuoteSource = quoteSource !== undefined; - if (validQuoteSource && quoteSource === Source.CrosschainAggregatorSocket) { - return quote.to; - } - if (validQuoteSource && quoteSource === Source.CrosschainAggregatorRelay) { - if (quote.sellTokenAddress?.toLowerCase() === ETH_ADDRESS.toLowerCase()) { - return quote.to; - } - return decodeERC20TransferToData(quote.data); - } - return undefined; -} - -/** - * Decodes the ERC-20 token transfer data from a transaction's input data. - * This function expects the input data to start with the ERC-20 transfer method ID (`0xa9059cbb`), - * followed by the 64 hexadecimal characters for the destination address and 64 hexadecimal characters - * for the transfer amount. The function will check and parse the input data, extracting the recipient's address - * - * The method assumes the data is properly formatted and begins with the correct method ID. - * If the data does not conform to these expectations, the function will return an 'undefined' object. - * - * @param data The hex encoded input data string from an ERC-20 transfer transaction. This string - * should include the method ID followed by the encoded parameters (address and amount). - * - * @returns { string | undefined } The destination address. If any error happens. - * Returns 'undefined' if it could not decode the call data. - */ -export function decodeERC20TransferToData( - data: string | undefined -): string | undefined { - if (!data?.startsWith(ERC20_TRANSFER_SIGNATURE)) { - return undefined; - } - const paramsData = data.slice(ERC20_TRANSFER_SIGNATURE.length); - if (paramsData.length < 64 * 2) { - return undefined; - } - return `0x${paramsData.slice(0, 64).replace(/^0+/, '')}`; -} - -/** - * Retrieves the destination address stored in the SDK corresponding to the specified aggregator and chain ID. - * - * @param quoteSource The aggregator used for the quote. - * @param chainID The origin network chain ID for the quote. - * @returns {string | undefined} The destination address stored in the SDK for the provided (source, chainID) - * combination. Returns `undefined` if there is no address for the specified combination. - */ -export function getExpectedDestinationAddress( - quoteSource: Source | undefined, - chainID: ChainId -): string | undefined { - const validSource = quoteSource !== undefined; - if (validSource && quoteSource === Source.CrosschainAggregatorSocket) { - return SOCKET_GATEWAY_CONTRACT_ADDRESSESS.get(chainID); - } else if (validSource && quoteSource === Source.CrosschainAggregatorRelay) { - return RELAY_LINK_BRIDGING_RELAYER_ADDRESS; - } - return undefined; } diff --git a/sdk/tests/utils/build_url.test.ts b/sdk/tests/utils/build_url.test.ts index f70faca..683a3f4 100644 --- a/sdk/tests/utils/build_url.test.ts +++ b/sdk/tests/utils/build_url.test.ts @@ -19,7 +19,7 @@ describe('when creating crosschain swap URL', () => { toChainId: 137, }) ).toEqual( - 'https://swap.p.rainbow.me/v1/quote?bridgeVersion=3&buyToken=0x456&chainId=1¤cy=usd&fromAddress=0x789&refuel=false&sellAmount=100&sellToken=0x123&slippage=2&swapType=cross-chain&toChainId=137&feePercentageBasisPoints=0' + 'https://swap.p.rainbow.me/v1/quote?bridgeVersion=4&buyToken=0x456&chainId=1¤cy=usd&fromAddress=0x789&refuel=false&sellAmount=100&sellToken=0x123&slippage=2&toChainId=137&feePercentageBasisPoints=0' ); }); it('should ignore feePercentageBasisPoints if not passed', () => { @@ -37,7 +37,7 @@ describe('when creating crosschain swap URL', () => { toChainId: 137, }) ).toEqual( - 'https://swap.p.rainbow.me/v1/quote?bridgeVersion=3&buyToken=0x456&chainId=1¤cy=usd&fromAddress=0x789&refuel=false&sellAmount=100&sellToken=0x123&slippage=2&swapType=cross-chain&toChainId=137' + 'https://swap.p.rainbow.me/v1/quote?bridgeVersion=4&buyToken=0x456&chainId=1¤cy=usd&fromAddress=0x789&refuel=false&sellAmount=100&sellToken=0x123&slippage=2&toChainId=137' ); }); }); @@ -57,7 +57,7 @@ describe('when creating claim bridge swap URL', () => { toChainId: 137, }) ).toEqual( - 'https://swap.p.rainbow.me/v1/quote?bridgeVersion=3&buyToken=0x456&chainId=1&claim=true¤cy=usd&feePercentageBasisPoints=0&fromAddress=0x789&refuel=false&sellAmount=100&sellToken=0x123&slippage=2&source=relay&swapType=cross-chain&toChainId=137' + 'https://swap.p.rainbow.me/v1/quote?bridgeVersion=4&buyToken=0x456&chainId=1&claim=true¤cy=usd&feePercentageBasisPoints=0&fromAddress=0x789&refuel=false&sellAmount=100&sellToken=0x123&slippage=2&source=relay&toChainId=137' ); }); }); diff --git a/sdk/tests/utils/sanity_check.test.ts b/sdk/tests/utils/sanity_check.test.ts index af69ee1..d7ad46b 100644 --- a/sdk/tests/utils/sanity_check.test.ts +++ b/sdk/tests/utils/sanity_check.test.ts @@ -1,212 +1,10 @@ -import { ChainId, CrosschainQuote, EthereumAddress, Source } from '../../src'; -import { - decodeERC20TransferToData, - extractDestinationAddress, - getExpectedDestinationAddress, - sanityCheckAddress, -} from '../../src/utils/sanity_check'; - -const okERC20Data = - '0xa9059cbb000000000000000000000000f70da97812cb96acdf810712aa562db8dfa3dbef0000000000000000000000000000000000000000000000056bc75e2d631000000085078f'; - -function getQuote( - chainID: ChainId, - source: Source | undefined = undefined, - to: string | undefined = undefined, - sellTokenAddress: string | undefined = undefined, - data: string | undefined = undefined -): CrosschainQuote { - return { - buyAmount: '', - buyAmountDisplay: '', - buyAmountDisplayMinimum: '', - buyAmountInEth: '', - buyAmountMinusFees: '', - buyTokenAddress: '' as EthereumAddress, - buyTokenAsset: { - assetCode: '', - chainId: chainID, - decimals: 18, - iconUrl: '', - name: '', - network: '', - networks: { - '1': { - address: '', - decimals: 18, - }, - }, - price: { - available: false, - value: 0, - }, - symbol: '', - totalPrice: { - available: false, - value: 0, - }, - }, - chainId: chainID, - data: data, - fee: '', - feeInEth: '', - feePercentageBasisPoints: 0, - feeTokenAsset: { - assetCode: '', - chainId: chainID, - decimals: 18, - iconUrl: '', - name: '', - network: '', - networks: { - '1': { - address: '', - decimals: 18, - }, - }, - price: { - available: false, - value: 0, - }, - symbol: '', - totalPrice: { - available: false, - value: 0, - }, - }, - from: '', - fromAsset: { - address: '', - chainAgnosticId: chainID, - chainId: chainID, - decimals: 18, - icon: '', - logoURI: '', - name: '', - symbol: '', - }, - fromChainId: chainID, - no_approval: false, - refuel: null, - routes: [], - sellAmount: '', - sellAmountDisplay: '', - sellAmountInEth: '', - sellAmountMinusFees: '', - sellTokenAddress: sellTokenAddress as EthereumAddress, - sellTokenAsset: { - assetCode: '', - chainId: chainID, - decimals: 18, - iconUrl: '', - name: '', - network: '', - networks: { - '1': { - address: '', - decimals: 18, - }, - }, - price: { - available: false, - value: 0, - }, - symbol: '', - totalPrice: { - available: false, - value: 0, - }, - }, - source: source, - to: to, - toAsset: { - address: '', - chainAgnosticId: chainID, - chainId: chainID, - decimals: 18, - icon: '', - logoURI: '', - name: '', - symbol: '', - }, - toChainId: 0, - tradeAmountUSD: 0, - tradeFeeAmountUSD: 0, - }; -} - -describe('getToAddressFromCrosschainQuote', () => { - it('should return undefined if non defined source', () => { - const quote = getQuote(1, undefined, '0x1234'); - expect(extractDestinationAddress(quote)).toBeUndefined(); - }); - it('should just use to address for socket', () => { - const quote = getQuote(1, Source.CrosschainAggregatorSocket, '0x1234'); - expect(extractDestinationAddress(quote)).toEqual('0x1234'); - }); -}); - -describe('decodeERC20TransferData', () => { - it('should correctly decode valid ERC20 transfer data', () => { - expect(decodeERC20TransferToData(okERC20Data)).toEqual( - '0xf70da97812cb96acdf810712aa562db8dfa3dbef' - ); - }); - it('should return null for invalid data', () => { - const data = '0xdeadbeef'; - expect(decodeERC20TransferToData(data)).toBeUndefined(); - }); - it('should return null for incomplete data', () => { - const data = - '0xa9059cbb000000000000000000000000f70da97812cb96acdf810712aa562db8dfa3dbef'; - expect(decodeERC20TransferToData(data)).toBeUndefined(); - }); - - it('should return decode erc20 data', () => { - const data = - '0xa9059cbb000000000000000000000000f70da97812cb96acdf810712aa562db8dfa3dbef000000000000000000000000000000000000000000000001a055690d9db8000000878469'; - expect(decodeERC20TransferToData(data)).toEqual( - `0xf70da97812cb96acdf810712aa562db8dfa3dbef` - ); - }); -}); - -describe('getExpectedDestinationAddress', () => { - it('should return expected and true for socket', () => { - expect( - getExpectedDestinationAddress( - Source.CrosschainAggregatorSocket, - ChainId.mainnet - ) - ).toEqual('0x3a23F943181408EAC424116Af7b7790c94Cb97a5'); - }); - it('should return expected and false for relay', () => { - expect( - getExpectedDestinationAddress( - Source.CrosschainAggregatorRelay, - ChainId.mainnet - ) - ).toEqual('0xf70da97812CB96acDF810712Aa562db8dfA3dbEF'); - }); -}); +import { sanityCheckAddress } from '../../src/utils/sanity_check'; describe('sanityCheckAddress', () => { - it('should return expected and true for socket', () => { - expect( - sanityCheckAddress( - Source.CrosschainAggregatorSocket, - ChainId.mainnet, - '0x3a23F943181408EAC424116Af7b7790c94Cb97a5' - ) - ).toEqual('0x3a23F943181408EAC424116Af7b7790c94Cb97a5'); + it('should not throw on valid address', () => { + expect(() => {sanityCheckAddress('0x3a23F943181408EAC424116Af7b7790c94Cb97a5')}).not.toThrow(); }); - it('should return expected and false for relay', () => { - expect( - sanityCheckAddress( - Source.CrosschainAggregatorRelay, - ChainId.mainnet, - '0xf70da97812CB96acDF810712Aa562db8dfA3dbEF' - ) - ).toEqual('0xf70da97812CB96acDF810712Aa562db8dfA3dbEF'); + it('should throw on invalid address', () => { + expect(() => {sanityCheckAddress('')}).toThrow('provided address is not defined'); }); });