Skip to content

Commit

Permalink
feat: moving to another file for testing
Browse files Browse the repository at this point in the history
  • Loading branch information
fringlesinthestreet committed Apr 29, 2024
1 parent 57a2032 commit 908a022
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 65 deletions.
71 changes: 6 additions & 65 deletions sdk/src/quotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ import {
PERMIT_EXPIRATION_TS,
RAINBOW_ROUTER_CONTRACT_ADDRESS,
RAINBOW_ROUTER_CONTRACT_ADDRESS_ZORA,
RELAY_LINK_BRIDGING_RELAYER_ADDRESS,
SOCKET_GATEWAY_CONTRACT_ADDRESSESS,
WRAPPED_ASSET,
} from './utils/constants';
import { signPermit } from './utils/permit';
import { getReferrerCode } from './utils/referrer';
import {
getDestinationAddressForCrosschainSwap,
getToAddressFromCrosschainQuote,
} from './utils/sanity_check';

/**
* Function to get the rainbow router contract address based on the chainId
Expand Down Expand Up @@ -339,67 +341,6 @@ export const getCrosschainQuote = async (
return quoteWithRestrictedAllowanceTarget;
};

/**
* 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.
*
* @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.
* @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.
*/
const getDestinationAddressForCrosschainSwap = (
quoteSource: Source | undefined,
chainID: ChainId,
assertedAddress: string | undefined
): string => {
if (assertedAddress === undefined || assertedAddress === '') {
throw new Error(
`quote's allowance and to addresses must be defined (API Response)`
);
}
let expectedAddress = getStoredAddressByCrosschainSource(
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!.toString();
};

/**
* 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 no address is stored for the specified combination.
*/
const getStoredAddressByCrosschainSource = (
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;
};

const calculateDeadline = async (wallet: Wallet) => {
const { timestamp } = await wallet.provider.getBlock('latest');
return timestamp + PERMIT_EXPIRATION_TS;
Expand Down Expand Up @@ -571,7 +512,7 @@ export const fillCrosschainQuote = async (
const to = getDestinationAddressForCrosschainSwap(
quote.source,
quote.fromChainId,
quote.to
getToAddressFromCrosschainQuote(quote)
);

let txData = data;
Expand Down Expand Up @@ -674,7 +615,7 @@ export const getCrosschainQuoteExecutionDetails = (
const to = getDestinationAddressForCrosschainSwap(
quote.source,
quote.fromChainId,
quote.to
getToAddressFromCrosschainQuote(quote)
);

return {
Expand Down
2 changes: 2 additions & 0 deletions sdk/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export const SOCKET_GATEWAY_CONTRACT_ADDRESSESS = new Map([
export const RELAY_LINK_BRIDGING_RELAYER_ADDRESS =
'0xf70da97812CB96acDF810712Aa562db8dfA3dbEF';

export const ERC20_TRANSFER_SIGNATURE = `0xa9059cbb`;

export type MultiChainAsset = {
[key: string]: EthereumAddress;
};
Expand Down
150 changes: 150 additions & 0 deletions sdk/src/utils/sanity_check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
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.
*
* @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.
* @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 getDestinationAddressForCrosschainSwap(
quoteSource: Source | undefined,
chainID: ChainId,
assertedAddress: string | undefined
): string {
if (assertedAddress === undefined || assertedAddress === '') {
throw new Error(
`quote's allowance and to addresses must be defined (API Response)`
);
}
let expectedAddress = getStoredAddressByCrosschainSource(
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!.toString();
}

/**
* 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: '0x1234567890123456789012345678901234567890'
* };
* console.log(getToAddressFromCrosschainQuote(Source.CrosschainAggregatorRelay, quoteRelayERC20));
* // Output: '0xf70da97812cb96acdf810712aa562db8dfa3dbef' (assuming the call data was a ERC20 transfer)
*/
export function getToAddressFromCrosschainQuote(
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 decodeERC20TransferData(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 decodeERC20TransferData(
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 `0x${paramsData.slice(0, 64).replace(/^0+/, '')}`;
}
return undefined;
}

/**
* 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 no address is stored for the specified combination.
*/
export function getStoredAddressByCrosschainSource(
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;
}

0 comments on commit 908a022

Please sign in to comment.