-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: added relay bridging support * fix: ocd and lint * fix: temp version * fix: testing on staging * fix: lint * feat: moving to another file for testing * feat: refactored a bit * fix: tests were not running * fix: error message * fix: should not change these * feat: new field * fix: should not replace to address * feat: tests and lsat details * fix: doc for erc20 transfer example
- Loading branch information
1 parent
a8f7070
commit a1071ec
Showing
8 changed files
with
386 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
.idea | ||
.idea/** | ||
sdk/*.tgz | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
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, boolean} 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 | ||
): { | ||
expectedAddress: string; | ||
shouldOverride: boolean; | ||
} { | ||
if (assertedAddress === undefined || assertedAddress === '') { | ||
throw new Error( | ||
`quote's destination addresses must be defined (API Response)` | ||
); | ||
} | ||
const { expectedAddress, shouldOverride } = 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, shouldOverride }; | ||
} | ||
|
||
/** | ||
* 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, boolean} The destination address stored in the SDK for the provided (source, chainID) | ||
* combination and if we need to overwrite it on the quote. | ||
* Returns `undefined` if there is no address for the specified combination. | ||
*/ | ||
export function getExpectedDestinationAddress( | ||
quoteSource: Source | undefined, | ||
chainID: ChainId | ||
): { | ||
expectedAddress: string | undefined; | ||
shouldOverride: boolean; | ||
} { | ||
const validSource = quoteSource !== undefined; | ||
if (validSource && quoteSource === Source.CrosschainAggregatorSocket) { | ||
return { | ||
expectedAddress: SOCKET_GATEWAY_CONTRACT_ADDRESSESS.get(chainID), | ||
shouldOverride: true, | ||
}; | ||
} else if (validSource && quoteSource === Source.CrosschainAggregatorRelay) { | ||
return { | ||
expectedAddress: RELAY_LINK_BRIDGING_RELAYER_ADDRESS, | ||
shouldOverride: false, | ||
}; | ||
} | ||
return { | ||
expectedAddress: undefined, | ||
shouldOverride: false, | ||
}; | ||
} |
Oops, something went wrong.