@avalabs/fusion-sdk 0.14.4 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +62 -1
- package/dist/errors.d.ts +62 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/mod.cjs +1 -1
- package/dist/mod.d.cts +2 -2
- package/dist/mod.d.ts +2 -2
- package/dist/mod.js +1 -1
- package/dist/quoter/constants.cjs +1 -1
- package/dist/quoter/constants.js +1 -1
- package/dist/quoter/constants.js.map +1 -1
- package/dist/quoter/quoter.cjs +1 -1
- package/dist/quoter/quoter.cjs.map +1 -1
- package/dist/quoter/quoter.d.ts +0 -3
- package/dist/quoter/quoter.js +1 -1
- package/dist/quoter/quoter.js.map +1 -1
- package/dist/transfer-service/_evm-errors.cjs +2 -0
- package/dist/transfer-service/_evm-errors.cjs.map +1 -0
- package/dist/transfer-service/_evm-errors.js +2 -0
- package/dist/transfer-service/_evm-errors.js.map +1 -0
- package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.cjs +1 -1
- package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.cjs.map +1 -1
- package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.js +1 -1
- package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.js.map +1 -1
- package/dist/transfer-service/lombard/_utils/fee.js +1 -1
- package/dist/transfer-service/lombard/_utils/fee.js.map +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/estimate-native-fee.cjs +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/estimate-native-fee.cjs.map +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/estimate-native-fee.js +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/estimate-native-fee.js.map +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/track-transfer.cjs +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/track-transfer.cjs.map +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/track-transfer.js +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/track-transfer.js.map +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/transfer-asset.cjs +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/transfer-asset.cjs.map +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/transfer-asset.js +1 -1
- package/dist/transfer-service/lombard/btc-to-btcb/_handlers/transfer-asset.js.map +1 -1
- package/dist/transfer-service/lombard/btcb-to-btc/_handlers/estimate-native-fee.cjs +1 -1
- package/dist/transfer-service/lombard/btcb-to-btc/_handlers/estimate-native-fee.cjs.map +1 -1
- package/dist/transfer-service/lombard/btcb-to-btc/_handlers/estimate-native-fee.js +1 -1
- package/dist/transfer-service/lombard/btcb-to-btc/_handlers/estimate-native-fee.js.map +1 -1
- package/dist/transfer-service/lombard/btcb-to-btc/_handlers/transfer-asset.cjs +1 -1
- package/dist/transfer-service/lombard/btcb-to-btc/_handlers/transfer-asset.cjs.map +1 -1
- package/dist/transfer-service/lombard/btcb-to-btc/_handlers/transfer-asset.js +1 -1
- package/dist/transfer-service/lombard/btcb-to-btc/_handlers/transfer-asset.js.map +1 -1
- package/dist/transfer-service/lombard/constants.cjs +1 -1
- package/dist/transfer-service/lombard/constants.js +1 -1
- package/dist/transfer-service/lombard/constants.js.map +1 -1
- package/dist/transfer-service/markr/_handlers/estimate-native-fee.cjs +1 -1
- package/dist/transfer-service/markr/_handlers/estimate-native-fee.cjs.map +1 -1
- package/dist/transfer-service/markr/_handlers/estimate-native-fee.js +1 -1
- package/dist/transfer-service/markr/_handlers/estimate-native-fee.js.map +1 -1
- package/dist/transfer-service/markr/_handlers/track-transfer.cjs +1 -1
- package/dist/transfer-service/markr/_handlers/track-transfer.cjs.map +1 -1
- package/dist/transfer-service/markr/_handlers/track-transfer.js +1 -1
- package/dist/transfer-service/markr/_handlers/track-transfer.js.map +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset.cjs +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset.cjs.map +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset.js +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset.js.map +1 -1
- package/dist/transfer-service/markr/_utils.cjs +1 -1
- package/dist/transfer-service/markr/_utils.cjs.map +1 -1
- package/dist/transfer-service/markr/_utils.js +1 -1
- package/dist/transfer-service/markr/_utils.js.map +1 -1
- package/dist/transfer-service/markr/constants.cjs +1 -1
- package/dist/transfer-service/markr/constants.js +1 -1
- package/dist/transfer-service/markr/constants.js.map +1 -1
- package/dist/transfer-service/markr/markr-service.cjs +1 -1
- package/dist/transfer-service/markr/markr-service.cjs.map +1 -1
- package/dist/transfer-service/markr/markr-service.js +1 -1
- package/dist/transfer-service/markr/markr-service.js.map +1 -1
- package/dist/transfer-service/wrap-unwrap/_handlers/estimate-native-fee.cjs +1 -1
- package/dist/transfer-service/wrap-unwrap/_handlers/estimate-native-fee.cjs.map +1 -1
- package/dist/transfer-service/wrap-unwrap/_handlers/estimate-native-fee.js +1 -1
- package/dist/transfer-service/wrap-unwrap/_handlers/estimate-native-fee.js.map +1 -1
- package/dist/transfer-service/wrap-unwrap/_utils.cjs +1 -1
- package/dist/transfer-service/wrap-unwrap/_utils.cjs.map +1 -1
- package/dist/transfer-service/wrap-unwrap/_utils.js +1 -1
- package/dist/transfer-service/wrap-unwrap/_utils.js.map +1 -1
- package/dist/types/service.d.cts +11 -49
- package/dist/types/service.d.ts +11 -49
- package/dist/utils/solana.cjs +2 -0
- package/dist/utils/solana.cjs.map +1 -0
- package/dist/utils/solana.js +2 -0
- package/dist/utils/solana.js.map +1 -0
- package/package.json +4 -4
- package/dist/transfer-service/markr/_solana-utils.cjs +0 -2
- package/dist/transfer-service/markr/_solana-utils.cjs.map +0 -1
- package/dist/transfer-service/markr/_solana-utils.js +0 -2
- package/dist/transfer-service/markr/_solana-utils.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-transfer.js","names":["isSolanaAddress","isEvmAddress"],"sources":["../../../../src/transfer-service/markr/_handlers/track-transfer.ts"],"sourcesContent":["import { assertIsSignature, isAddress as isSolanaAddress, type Signature } from '@solana/kit';\nimport { isAddress as isEvmAddress, isHash } from 'viem';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { TokenType } from '../../../constants';\nimport { ErrorCode } from '../../../errors';\nimport type { TransferService, TrackTransferProps } from '../../../types/service';\nimport type { Asset } from '../../../types/asset';\nimport type {\n CompletedTransfer,\n FailedTransfer,\n SourceCompletedTransfer,\n SourcePendingTransfer,\n TargetPendingTransfer,\n Transfer,\n} from '../../../types/transfer';\nimport { awaitOrAbort, getEvmClientForChain, getSolanaRpcForChain, waitForTimeoutOrAbort } from '../../_utils';\nimport { trackSameChainEvmTransfer } from '../../_tracking-utilities';\nimport { markrGetCrossChainStatus, type ApiOptions } from '../_api';\nimport type { CrossChainStatusResponse } from '../_schema';\nimport {\n CROSS_CHAIN_POLLING_INTERVAL_MS,\n FINALITY_MS_BY_CHAIN_ID,\n FINALITY_MS_BY_CHAIN_NAME_ALIAS,\n FINALITY_TIER_MAX_FINALITY_MS,\n SOLANA_POLLING_INTERVAL_MS,\n SOLANA_TX_TIMEOUT_MS,\n} from '../constants';\nimport type { Caip2ChainId } from '../../../mod';\n\ntype FinalityTier = keyof typeof CROSS_CHAIN_POLLING_INTERVAL_MS;\n\ntype InFlightTransfer = SourcePendingTransfer | SourceCompletedTransfer | TargetPendingTransfer;\n\nexport interface TrackTransferFactoryConfig {\n apiOptions: ApiOptions;\n}\n\nexport function trackTransferFactory({ apiOptions }: TrackTransferFactoryConfig): TransferService['trackTransfer'] {\n return ({ transfer, updateListener }) => {\n if (transfer.sourceChain.chainId === transfer.targetChain.chainId) {\n if (isSolanaNamespace(transfer.sourceChain.chainId)) {\n return _trackSameChainSolanaTransfer({ transfer, updateListener });\n }\n return trackSameChainEvmTransfer({ transfer, updateListener });\n }\n\n return _trackCrossChainTransfer({ transfer, updateListener }, apiOptions);\n };\n}\n\nexport function _trackSameChainSolanaTransfer({ transfer, updateListener }: TrackTransferProps): {\n cancel: () => void;\n result: Promise<Transfer>;\n} {\n const ac = new AbortController();\n const cancel = () => ac.abort();\n\n if (transfer.status !== 'source-pending') {\n return { cancel, result: Promise.resolve(transfer) };\n }\n\n return { cancel, result: _pollSolanaSignatureStatus(transfer, updateListener, ac.signal) };\n}\n\nasync function _pollSolanaSignatureStatus(\n transfer: SourcePendingTransfer,\n updateListener: (transfer: Transfer) => void,\n signal: AbortSignal,\n): Promise<Transfer> {\n const { txHash } = transfer.source;\n\n try {\n assertIsSignature(txHash);\n } catch {\n const failed: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n updateListener(failed);\n return failed;\n }\n\n const rpc = getSolanaRpcForChain({ chain: transfer.sourceChain });\n const startTime = Date.now();\n\n while (!signal.aborted) {\n if (Date.now() - startTime > SOLANA_TX_TIMEOUT_MS) {\n return transfer;\n }\n\n try {\n const { value } = await rpc.getSignatureStatuses([txHash], { searchTransactionHistory: true }).send();\n const status = value[0];\n\n if (!status) {\n await waitForTimeoutOrAbort({ timeoutMs: SOLANA_POLLING_INTERVAL_MS, signal });\n continue;\n }\n\n if (status.err !== null) {\n const failed: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n updateListener(failed);\n return failed;\n }\n\n if (status.confirmationStatus === 'finalized') {\n const completed: CompletedTransfer = {\n ...transfer,\n completedAtMs: Date.now(),\n source: {\n ...transfer.source,\n confirmationCount: transfer.source.requiredConfirmationCount,\n },\n status: 'completed',\n target: null,\n };\n updateListener(completed);\n return completed;\n }\n\n const confirmations = Number(status.confirmations ?? 0);\n const cappedCount = Math.min(confirmations, transfer.source.requiredConfirmationCount - 1);\n\n if (cappedCount !== transfer.source.confirmationCount) {\n transfer = {\n ...transfer,\n source: {\n ...transfer.source,\n confirmationCount: cappedCount,\n },\n };\n updateListener(transfer);\n }\n\n await waitForTimeoutOrAbort({ timeoutMs: SOLANA_POLLING_INTERVAL_MS, signal });\n } catch {\n return transfer;\n }\n }\n\n return transfer;\n}\n\nexport function _trackCrossChainTransfer(\n { transfer, updateListener }: TrackTransferProps,\n apiOptions: ApiOptions,\n): { cancel: () => void; result: Promise<Transfer> } {\n const ac = new AbortController();\n const cancel = () => {\n ac.abort();\n };\n\n const executeTracking = async (): Promise<Transfer> => {\n let currentTransfer: Transfer = structuredClone(transfer);\n while (!ac.signal.aborted) {\n const updatedTransfer = await _getMarkrCrossChainTxStatus(currentTransfer, apiOptions, ac.signal);\n\n if (ac.signal.aborted) {\n break;\n }\n\n currentTransfer = updatedTransfer;\n\n updateListener(updatedTransfer);\n\n if (\n updatedTransfer.status === 'completed' ||\n updatedTransfer.status === 'failed' ||\n updatedTransfer.status === 'refunded'\n ) {\n return updatedTransfer;\n }\n\n const pollingIntervalMs = _getPollingIntervalMsForTransfer(updatedTransfer);\n\n // Wait before polling again.\n await new Promise((resolve) => {\n const timeoutId = setTimeout(resolve, pollingIntervalMs);\n ac.signal.addEventListener('abort', () => clearTimeout(timeoutId), { once: true });\n });\n }\n\n return currentTransfer;\n };\n\n return {\n cancel,\n result: executeTracking(),\n };\n}\n\nexport async function _getMarkrCrossChainTxStatus(\n transfer: Transfer,\n apiOptions: ApiOptions,\n signal: AbortSignal,\n): Promise<Transfer> {\n if (transfer.status === 'completed' || transfer.status === 'failed' || transfer.status === 'refunded') {\n return transfer;\n }\n\n // We only support tracking EVM or Solana source transactions.\n if (!_isValidSourceTxHash(transfer.source.txHash, transfer.sourceChain.chainId)) {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n return failedTransfer;\n }\n\n // If transfer is `source-pending`, we first confirm source-chain finality before\n // querying Markr's cross-chain status endpoint.\n // Once source finality is confirmed, we mark the transfer as source-completed and\n // defer Markr polling to subsequent iterations.\n if (transfer.status === 'source-pending') {\n if (isEvmNamespace(transfer.sourceChain.chainId)) {\n const sourceTxHash = transfer.source.txHash;\n\n if (!isHash(sourceTxHash)) {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n\n return failedTransfer;\n }\n\n const client = getEvmClientForChain({ chain: transfer.sourceChain });\n\n try {\n const receiptResult = await awaitOrAbort(\n client.waitForTransactionReceipt({\n hash: sourceTxHash,\n }),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return transfer;\n }\n\n const receipt = receiptResult.value;\n\n if (receipt.status === 'reverted') {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n return failedTransfer;\n }\n\n const finalityResult = await _waitForEvmSourceFinalization(\n client,\n transfer.sourceChain.chainId,\n transfer.sourceChain.chainName,\n receipt.blockNumber,\n signal,\n );\n if (finalityResult.status === 'aborted') {\n return transfer;\n }\n\n return _toSourceCompletedTransfer(transfer);\n } catch {\n return transfer;\n }\n }\n\n if (isSolanaNamespace(transfer.sourceChain.chainId)) {\n const sourceTxHash = transfer.source.txHash;\n\n try {\n assertIsSignature(sourceTxHash);\n } catch {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n return failedTransfer;\n }\n\n const finalityResult = await _waitForSolanaSourceFinalization(transfer.sourceChain, sourceTxHash, signal);\n\n if (finalityResult.status === 'aborted') {\n return transfer;\n }\n\n if (finalityResult.status === 'reverted') {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n return failedTransfer;\n }\n\n if (finalityResult.status === 'unknown') {\n return transfer;\n }\n\n return _toSourceCompletedTransfer(transfer);\n }\n }\n\n try {\n const statusResponse = await markrGetCrossChainStatus(apiOptions, transfer.source.txHash, { signal });\n const transferWithMarkrMetadata = _withMarkrTrackingMetadata(transfer, statusResponse);\n\n switch (statusResponse.status) {\n case 'failed': {\n const failedTransfer: FailedTransfer = {\n ...transferWithMarkrMetadata,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Transaction execution failed.',\n failedAtMs: _getLastStatusActivityTime(statusResponse),\n status: 'failed',\n };\n\n return failedTransfer;\n }\n\n case 'pending': {\n return _isMarkrSourceFinalized(statusResponse.sourceChain.finalized)\n ? _toSourceCompletedTransfer(transferWithMarkrMetadata)\n : transferWithMarkrMetadata;\n }\n\n case 'committed':\n case 'pending_execution': {\n return _toTargetPendingTransfer(transferWithMarkrMetadata, statusResponse);\n }\n\n case 'completed': {\n return _toCompletedTransfer(transferWithMarkrMetadata, statusResponse);\n }\n\n case 'refunded': {\n return _toRefundedTransfer(transferWithMarkrMetadata, statusResponse);\n }\n\n case 'unknown':\n default: {\n return _deriveTransferFromUnknownStatus(transferWithMarkrMetadata, statusResponse);\n }\n }\n } catch (error) {\n // TODO: Clean this console.error up before v1 release.\n // This is just here for now to try to track down tracking issues.\n console.error('[Fusion SDK] Error fetching cross-chain status from Markr API', {\n error,\n now: Date.now(),\n });\n\n return transfer;\n }\n}\n\nasync function _waitForEvmSourceFinalization(\n client: ReturnType<typeof getEvmClientForChain>,\n chainId: Caip2ChainId,\n chainName: string,\n txBlockNumber: bigint,\n signal: AbortSignal,\n): Promise<{ status: 'aborted' } | { status: 'ok' }> {\n const pollingIntervalMs = _getCrossChainPollingIntervalMs(chainId, chainName);\n\n while (!signal.aborted) {\n const finalizedBlockResult = await awaitOrAbort(client.getBlock({ blockTag: 'finalized' }), signal);\n\n if (finalizedBlockResult.status === 'aborted') {\n return { status: 'aborted' };\n }\n\n if (finalizedBlockResult.value.number >= txBlockNumber) {\n return { status: 'ok' };\n }\n\n await waitForTimeoutOrAbort({\n timeoutMs: pollingIntervalMs,\n signal,\n });\n }\n\n return { status: 'aborted' };\n}\n\nfunction _getCrossChainPollingIntervalMs(chainId: Caip2ChainId, chainName: string): number {\n const knownFinalityMs = _getKnownFinalityMs(chainId, chainName);\n const finalityTier = _toFinalityTier(knownFinalityMs);\n return CROSS_CHAIN_POLLING_INTERVAL_MS[finalityTier];\n}\n\nfunction _getPollingIntervalMsForTransfer(transfer: Transfer): number {\n if (transfer.status === 'source-pending') {\n return _getCrossChainPollingIntervalMs(transfer.sourceChain.chainId, transfer.sourceChain.chainName);\n }\n\n return _getCrossChainPollingIntervalMs(transfer.targetChain.chainId, transfer.targetChain.chainName);\n}\n\nfunction _getKnownFinalityMs(chainId: Caip2ChainId, chainName: string): number | undefined {\n const chainIdFinalityMs = FINALITY_MS_BY_CHAIN_ID[chainId];\n if (chainIdFinalityMs !== undefined) {\n return chainIdFinalityMs;\n }\n\n const normalizedName = _normalizeChainName(chainName);\n const matchingAlias = FINALITY_MS_BY_CHAIN_NAME_ALIAS.find(({ aliases }) =>\n aliases.some((alias) => normalizedName.includes(alias)),\n );\n\n return matchingAlias?.finalityMs;\n}\n\nfunction _normalizeChainName(chainName: string): string {\n return chainName.toLowerCase().replace(/[^a-z0-9]/g, '');\n}\n\nfunction _toFinalityTier(knownFinalityMs: number | undefined): FinalityTier {\n if (knownFinalityMs === undefined) {\n return 'medium';\n }\n\n if (knownFinalityMs <= FINALITY_TIER_MAX_FINALITY_MS.fast) {\n return 'fast';\n }\n\n if (knownFinalityMs <= FINALITY_TIER_MAX_FINALITY_MS.medium) {\n return 'medium';\n }\n\n if (knownFinalityMs <= FINALITY_TIER_MAX_FINALITY_MS.slow) {\n return 'slow';\n }\n\n return 'verySlow';\n}\n\nasync function _waitForSolanaSourceFinalization(\n chain: SourcePendingTransfer['sourceChain'],\n txHash: Signature,\n signal: AbortSignal,\n): Promise<{ status: 'aborted' } | { status: 'ok' } | { status: 'reverted' } | { status: 'unknown' }> {\n const rpc = getSolanaRpcForChain({ chain });\n const startTime = Date.now();\n\n while (!signal.aborted) {\n if (Date.now() - startTime > SOLANA_TX_TIMEOUT_MS) {\n return { status: 'unknown' };\n }\n\n try {\n const { value } = await rpc.getSignatureStatuses([txHash], { searchTransactionHistory: true }).send();\n const txStatus = value[0];\n\n if (!txStatus) {\n await waitForTimeoutOrAbort({ timeoutMs: SOLANA_POLLING_INTERVAL_MS, signal });\n continue;\n }\n\n if (txStatus.err !== null) {\n return { status: 'reverted' };\n }\n\n if (txStatus.confirmationStatus === 'finalized') {\n return { status: 'ok' };\n }\n\n await waitForTimeoutOrAbort({ timeoutMs: SOLANA_POLLING_INTERVAL_MS, signal });\n } catch {\n return { status: 'unknown' };\n }\n }\n\n return { status: 'aborted' };\n}\n\nfunction _isValidSourceTxHash(txHash: string, sourceChainId: Caip2ChainId): boolean {\n if (isEvmNamespace(sourceChainId)) {\n return isHash(txHash);\n }\n\n if (isSolanaNamespace(sourceChainId)) {\n try {\n assertIsSignature(txHash);\n return true;\n } catch {\n return false;\n }\n }\n\n return false;\n}\n\nfunction _isMarkrSourceFinalized(finalized: CrossChainStatusResponse['sourceChain']['finalized']): boolean {\n return finalized === true || typeof finalized === 'string';\n}\n\nfunction _toSourceCompletedTransfer(transfer: InFlightTransfer): SourceCompletedTransfer {\n return {\n ...transfer,\n source: {\n ...transfer.source,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n },\n status: 'source-completed',\n };\n}\n\nfunction _withMarkrTrackingMetadata(\n transfer: InFlightTransfer,\n statusResponse: CrossChainStatusResponse,\n): InFlightTransfer {\n const metadata: Record<string, unknown> = { ...(transfer.metadata ?? {}) };\n\n if (statusResponse.destinationChain.bridgeHash) {\n metadata.bridgeHash = statusResponse.destinationChain.bridgeHash;\n }\n\n if (statusResponse.debug) {\n metadata.debug = statusResponse.debug;\n }\n\n if (Object.keys(metadata).length === 0) {\n return transfer;\n }\n\n return {\n ...transfer,\n metadata,\n };\n}\n\nfunction _toTargetPendingTransfer(\n transfer: InFlightTransfer,\n statusResponse: CrossChainStatusResponse,\n): TargetPendingTransfer {\n const { timestamp, transactionHash } = statusResponse.destinationChain;\n\n return {\n ...transfer,\n source: {\n ...transfer.source,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n },\n status: 'target-pending',\n target: {\n confirmationCount: transactionHash ? 1 : 0,\n requiredConfirmationCount: 2,\n startedAtMs: timestamp ? new Date(timestamp).getTime() : Date.now(),\n txHash: transactionHash ?? undefined,\n },\n };\n}\n\nfunction _toCompletedTransfer(transfer: InFlightTransfer, statusResponse: CrossChainStatusResponse): CompletedTransfer {\n const { timestamp, transactionHash } = statusResponse.destinationChain;\n\n return {\n ...transfer,\n completedAtMs: _getLastStatusActivityTime(statusResponse),\n status: 'completed',\n source: {\n ...transfer.source,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n },\n target: transactionHash\n ? {\n txHash: transactionHash,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n startedAtMs: timestamp ? new Date(timestamp).getTime() : Date.now(),\n }\n : null,\n };\n}\n\nfunction _toRefundedTransfer(transfer: InFlightTransfer, statusResponse: CrossChainStatusResponse): Transfer {\n const { transactionHash } = statusResponse.destinationChain;\n // This _should_ exist.\n // If it doesn't, thats a problem with Markr's API and they should resolve it.\n // We were \"guaranteed\" by them that in a \"refunded\" status, there would be exactly 1\n // transferred token in the response, which represents the refund.\n const refundedToken = statusResponse.transferredTokens[0];\n\n const refundAsset = refundedToken ? _getRefundAsset(transfer.targetChain.chainId, refundedToken.token) ?? null : null;\n const existingTarget = 'target' in transfer ? transfer.target : null;\n\n return {\n ...transfer,\n refund: {\n amount: refundedToken?.amount ?? 0n,\n asset: refundAsset,\n chainId: transfer.targetChain.chainId,\n txHash: transactionHash ?? null,\n timestampMs: _getLastStatusActivityTime(statusResponse),\n },\n source: {\n ...transfer.source,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n },\n status: 'refunded',\n target: existingTarget\n ? {\n ...existingTarget,\n txHash: undefined,\n }\n : null,\n };\n}\n\nfunction _getRefundAsset(chainId: Caip2ChainId, tokenAddress: string): Asset | undefined {\n if (isSolanaNamespace(chainId)) {\n if (!isSolanaAddress(tokenAddress)) {\n return undefined;\n }\n\n return {\n address: tokenAddress,\n decimals: 6,\n name: 'USD Coin',\n symbol: 'USDC',\n type: TokenType.SPL,\n };\n }\n\n if (isEvmNamespace(chainId)) {\n if (!isEvmAddress(tokenAddress)) {\n return undefined;\n }\n\n return {\n address: tokenAddress,\n decimals: 6,\n name: 'USD Coin',\n symbol: 'USDC',\n type: TokenType.ERC20,\n };\n }\n\n return undefined;\n}\n\nfunction _deriveTransferFromUnknownStatus(\n transfer: InFlightTransfer,\n statusResponse: CrossChainStatusResponse,\n): Transfer {\n if (statusResponse.progress.executed === true) {\n return _toCompletedTransfer(transfer, statusResponse);\n }\n\n if (statusResponse.progress.committed === true) {\n return _toTargetPendingTransfer(transfer, statusResponse);\n }\n\n if (_isMarkrSourceFinalized(statusResponse.sourceChain.finalized)) {\n return _toSourceCompletedTransfer(transfer);\n }\n\n return {\n ...transfer,\n source: {\n ...transfer.source,\n confirmationCount: 0,\n requiredConfirmationCount: 2,\n },\n status: 'source-pending',\n };\n}\n\nfunction _getLastStatusActivityTime(response: CrossChainStatusResponse): number {\n if (response.destinationChain.finalized) {\n return new Date(response.destinationChain.finalized).getTime();\n }\n\n if (response.destinationChain.timestamp) {\n return new Date(response.destinationChain.timestamp).getTime();\n }\n\n if (response.sourceChain.finalized) {\n if (typeof response.sourceChain.finalized === 'boolean' && response.sourceChain.finalized === true) {\n // Handle case where finalized is returned as boolean `true` instead of a timestamp.\n return new Date(response.sourceChain.timestamp).getTime();\n }\n return new Date(response.sourceChain.finalized).getTime();\n }\n\n return new Date(response.sourceChain.timestamp).getTime();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"track-transfer.js","names":["isSolanaAddress","isEvmAddress"],"sources":["../../../../src/transfer-service/markr/_handlers/track-transfer.ts"],"sourcesContent":["import { assertIsSignature, isAddress as isSolanaAddress, type Signature } from '@solana/kit';\nimport { isAddress as isEvmAddress, isHash } from 'viem';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { TokenType } from '../../../constants';\nimport { ErrorCode } from '../../../errors';\nimport type { TransferService, TrackTransferProps } from '../../../types/service';\nimport type { Asset } from '../../../types/asset';\nimport type {\n CompletedTransfer,\n FailedTransfer,\n SourceCompletedTransfer,\n SourcePendingTransfer,\n TargetPendingTransfer,\n Transfer,\n} from '../../../types/transfer';\nimport { awaitOrAbort, getEvmClientForChain, getSolanaRpcForChain, waitForTimeoutOrAbort } from '../../_utils';\nimport { trackSameChainEvmTransfer } from '../../_tracking-utilities';\nimport { markrGetCrossChainStatus, type ApiOptions } from '../_api';\nimport type { CrossChainStatusResponse } from '../_schema';\nimport {\n CROSS_CHAIN_POLLING_INTERVAL_MS,\n FINALITY_MS_BY_CHAIN_ID,\n FINALITY_MS_BY_CHAIN_NAME_ALIAS,\n FINALITY_TIER_MAX_FINALITY_MS,\n SOLANA_POLLING_INTERVAL_MS,\n SOLANA_TX_TIMEOUT_MS,\n} from '../constants';\nimport type { Caip2ChainId } from '../../../mod';\n\ntype FinalityTier = keyof typeof CROSS_CHAIN_POLLING_INTERVAL_MS;\n\ntype InFlightTransfer = SourcePendingTransfer | SourceCompletedTransfer | TargetPendingTransfer;\n\nexport interface TrackTransferFactoryConfig {\n apiOptions: ApiOptions;\n}\n\nexport function trackTransferFactory({ apiOptions }: TrackTransferFactoryConfig): TransferService['trackTransfer'] {\n return ({ transfer, updateListener }) => {\n if (transfer.sourceChain.chainId === transfer.targetChain.chainId) {\n if (isSolanaNamespace(transfer.sourceChain.chainId)) {\n return _trackSameChainSolanaTransfer({ transfer, updateListener });\n }\n return trackSameChainEvmTransfer({ transfer, updateListener });\n }\n\n return _trackCrossChainTransfer({ transfer, updateListener }, apiOptions);\n };\n}\n\nexport function _trackSameChainSolanaTransfer({ transfer, updateListener }: TrackTransferProps): {\n cancel: () => void;\n result: Promise<Transfer>;\n} {\n const ac = new AbortController();\n const cancel = () => ac.abort();\n\n if (transfer.status !== 'source-pending') {\n return { cancel, result: Promise.resolve(transfer) };\n }\n\n return { cancel, result: _pollSolanaSignatureStatus(transfer, updateListener, ac.signal) };\n}\n\nasync function _pollSolanaSignatureStatus(\n transfer: SourcePendingTransfer,\n updateListener: (transfer: Transfer) => void,\n signal: AbortSignal,\n): Promise<Transfer> {\n const { txHash } = transfer.source;\n\n try {\n assertIsSignature(txHash);\n } catch {\n const failed: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n updateListener(failed);\n return failed;\n }\n\n const rpc = getSolanaRpcForChain({ chain: transfer.sourceChain });\n const startTime = Date.now();\n\n while (!signal.aborted) {\n if (Date.now() - startTime > SOLANA_TX_TIMEOUT_MS) {\n return transfer;\n }\n\n try {\n const { value } = await rpc.getSignatureStatuses([txHash], { searchTransactionHistory: true }).send();\n const status = value[0];\n\n if (!status) {\n await waitForTimeoutOrAbort({ timeoutMs: SOLANA_POLLING_INTERVAL_MS, signal });\n continue;\n }\n\n if (status.err !== null) {\n const failed: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n updateListener(failed);\n return failed;\n }\n\n if (status.confirmationStatus === 'finalized') {\n const completed: CompletedTransfer = {\n ...transfer,\n completedAtMs: Date.now(),\n source: {\n ...transfer.source,\n confirmationCount: transfer.source.requiredConfirmationCount,\n },\n status: 'completed',\n target: null,\n };\n updateListener(completed);\n return completed;\n }\n\n const confirmations = Number(status.confirmations ?? 0);\n const cappedCount = Math.min(confirmations, transfer.source.requiredConfirmationCount - 1);\n\n if (cappedCount !== transfer.source.confirmationCount) {\n transfer = {\n ...transfer,\n source: {\n ...transfer.source,\n confirmationCount: cappedCount,\n },\n };\n updateListener(transfer);\n }\n\n await waitForTimeoutOrAbort({ timeoutMs: SOLANA_POLLING_INTERVAL_MS, signal });\n } catch {\n return transfer;\n }\n }\n\n return transfer;\n}\n\nexport function _trackCrossChainTransfer(\n { transfer, updateListener }: TrackTransferProps,\n apiOptions: ApiOptions,\n): { cancel: () => void; result: Promise<Transfer> } {\n const ac = new AbortController();\n const cancel = () => {\n ac.abort();\n };\n\n const executeTracking = async (): Promise<Transfer> => {\n let currentTransfer: Transfer = structuredClone(transfer);\n while (!ac.signal.aborted) {\n const updatedTransfer = await _getMarkrCrossChainTxStatus(currentTransfer, apiOptions, ac.signal);\n\n if (ac.signal.aborted) {\n break;\n }\n\n currentTransfer = updatedTransfer;\n\n updateListener(updatedTransfer);\n\n if (\n updatedTransfer.status === 'completed' ||\n updatedTransfer.status === 'failed' ||\n updatedTransfer.status === 'refunded'\n ) {\n return updatedTransfer;\n }\n\n const pollingIntervalMs = _getPollingIntervalMsForTransfer(updatedTransfer);\n\n // Wait before polling again.\n await new Promise((resolve) => {\n const timeoutId = setTimeout(resolve, pollingIntervalMs);\n ac.signal.addEventListener('abort', () => clearTimeout(timeoutId), { once: true });\n });\n }\n\n return currentTransfer;\n };\n\n return {\n cancel,\n result: executeTracking(),\n };\n}\n\nexport async function _getMarkrCrossChainTxStatus(\n transfer: Transfer,\n apiOptions: ApiOptions,\n signal: AbortSignal,\n): Promise<Transfer> {\n if (transfer.status === 'completed' || transfer.status === 'failed' || transfer.status === 'refunded') {\n return transfer;\n }\n\n // We only support tracking EVM or Solana source transactions.\n if (!_isValidSourceTxHash(transfer.source.txHash, transfer.sourceChain.chainId)) {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n return failedTransfer;\n }\n\n // If transfer is `source-pending`, we first confirm source-chain finality before\n // querying Markr's cross-chain status endpoint.\n // Once source finality is confirmed, we mark the transfer as source-completed and\n // defer Markr polling to subsequent iterations.\n if (transfer.status === 'source-pending') {\n if (isEvmNamespace(transfer.sourceChain.chainId)) {\n const sourceTxHash = transfer.source.txHash;\n\n if (!isHash(sourceTxHash)) {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n\n return failedTransfer;\n }\n\n const client = getEvmClientForChain({ chain: transfer.sourceChain });\n\n try {\n const receiptResult = await awaitOrAbort(\n client.waitForTransactionReceipt({\n hash: sourceTxHash,\n }),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return transfer;\n }\n\n const receipt = receiptResult.value;\n\n if (receipt.status === 'reverted') {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n return failedTransfer;\n }\n\n const finalityResult = await _waitForEvmSourceFinalization(\n client,\n transfer.sourceChain.chainId,\n transfer.sourceChain.chainName,\n receipt.blockNumber,\n signal,\n );\n if (finalityResult.status === 'aborted') {\n return transfer;\n }\n\n return _toSourceCompletedTransfer(transfer);\n } catch {\n return transfer;\n }\n }\n\n if (isSolanaNamespace(transfer.sourceChain.chainId)) {\n const sourceTxHash = transfer.source.txHash;\n\n try {\n assertIsSignature(sourceTxHash);\n } catch {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n return failedTransfer;\n }\n\n const finalityResult = await _waitForSolanaSourceFinalization(transfer.sourceChain, sourceTxHash, signal);\n\n if (finalityResult.status === 'aborted') {\n return transfer;\n }\n\n if (finalityResult.status === 'reverted') {\n const failedTransfer: FailedTransfer = {\n ...transfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n return failedTransfer;\n }\n\n if (finalityResult.status === 'unknown') {\n return transfer;\n }\n\n return _toSourceCompletedTransfer(transfer);\n }\n }\n\n try {\n const statusResponse = await markrGetCrossChainStatus(apiOptions, transfer.source.txHash, { signal });\n const transferWithMarkrMetadata = _withMarkrTrackingMetadata(transfer, statusResponse);\n\n switch (statusResponse.status) {\n case 'failed': {\n const failedTransfer: FailedTransfer = {\n ...transferWithMarkrMetadata,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Transaction execution failed.',\n failedAtMs: _getLastStatusActivityTime(statusResponse),\n status: 'failed',\n };\n\n return failedTransfer;\n }\n\n case 'pending': {\n return _isMarkrSourceFinalized(statusResponse.sourceChain.finalized)\n ? _toSourceCompletedTransfer(transferWithMarkrMetadata)\n : transferWithMarkrMetadata;\n }\n\n case 'committed':\n case 'pending_execution': {\n return _toTargetPendingTransfer(transferWithMarkrMetadata, statusResponse);\n }\n\n case 'completed': {\n return _toCompletedTransfer(transferWithMarkrMetadata, statusResponse);\n }\n\n case 'refunded': {\n return _toRefundedTransfer(transferWithMarkrMetadata, statusResponse);\n }\n\n case 'unknown':\n default: {\n return _deriveTransferFromUnknownStatus(transferWithMarkrMetadata, statusResponse);\n }\n }\n } catch (error) {\n // TODO: Clean this console.error up before v1 release.\n // This is just here for now to try to track down tracking issues.\n console.error('[Fusion SDK] Error fetching cross-chain status from Markr API', {\n error,\n now: Date.now(),\n });\n\n return transfer;\n }\n}\n\nasync function _waitForEvmSourceFinalization(\n client: ReturnType<typeof getEvmClientForChain>,\n chainId: Caip2ChainId,\n chainName: string,\n txBlockNumber: bigint,\n signal: AbortSignal,\n): Promise<{ status: 'aborted' } | { status: 'ok' }> {\n const pollingIntervalMs = _getCrossChainPollingIntervalMs(chainId, chainName);\n\n while (!signal.aborted) {\n const finalizedBlockResult = await awaitOrAbort(client.getBlock({ blockTag: 'finalized' }), signal);\n\n if (finalizedBlockResult.status === 'aborted') {\n return { status: 'aborted' };\n }\n\n if (finalizedBlockResult.value.number >= txBlockNumber) {\n return { status: 'ok' };\n }\n\n await waitForTimeoutOrAbort({\n timeoutMs: pollingIntervalMs,\n signal,\n });\n }\n\n return { status: 'aborted' };\n}\n\nfunction _getCrossChainPollingIntervalMs(chainId: Caip2ChainId, chainName: string): number {\n const knownFinalityMs = _getKnownFinalityMs(chainId, chainName);\n const finalityTier = _toFinalityTier(knownFinalityMs);\n return CROSS_CHAIN_POLLING_INTERVAL_MS[finalityTier];\n}\n\nfunction _getPollingIntervalMsForTransfer(transfer: Transfer): number {\n if (transfer.status === 'source-pending') {\n return _getCrossChainPollingIntervalMs(transfer.sourceChain.chainId, transfer.sourceChain.chainName);\n }\n\n return _getCrossChainPollingIntervalMs(transfer.targetChain.chainId, transfer.targetChain.chainName);\n}\n\nfunction _getKnownFinalityMs(chainId: Caip2ChainId, chainName: string): number | undefined {\n const chainIdFinalityMs = FINALITY_MS_BY_CHAIN_ID[chainId];\n if (chainIdFinalityMs !== undefined) {\n return chainIdFinalityMs;\n }\n\n const normalizedName = _normalizeChainName(chainName);\n const matchingAlias = FINALITY_MS_BY_CHAIN_NAME_ALIAS.find(({ aliases }) =>\n aliases.some((alias) => normalizedName.includes(alias)),\n );\n\n return matchingAlias?.finalityMs;\n}\n\nfunction _normalizeChainName(chainName: string): string {\n return chainName.toLowerCase().replace(/[^a-z0-9]/g, '');\n}\n\nfunction _toFinalityTier(knownFinalityMs: number | undefined): FinalityTier {\n if (knownFinalityMs === undefined) {\n return 'medium';\n }\n\n if (knownFinalityMs <= FINALITY_TIER_MAX_FINALITY_MS.fast) {\n return 'fast';\n }\n\n if (knownFinalityMs <= FINALITY_TIER_MAX_FINALITY_MS.medium) {\n return 'medium';\n }\n\n if (knownFinalityMs <= FINALITY_TIER_MAX_FINALITY_MS.slow) {\n return 'slow';\n }\n\n return 'verySlow';\n}\n\nasync function _waitForSolanaSourceFinalization(\n chain: SourcePendingTransfer['sourceChain'],\n txHash: Signature,\n signal: AbortSignal,\n): Promise<{ status: 'aborted' } | { status: 'ok' } | { status: 'reverted' } | { status: 'unknown' }> {\n const rpc = getSolanaRpcForChain({ chain });\n const startTime = Date.now();\n\n while (!signal.aborted) {\n if (Date.now() - startTime > SOLANA_TX_TIMEOUT_MS) {\n return { status: 'unknown' };\n }\n\n try {\n const { value } = await rpc.getSignatureStatuses([txHash], { searchTransactionHistory: true }).send();\n const txStatus = value[0];\n\n if (!txStatus) {\n await waitForTimeoutOrAbort({ timeoutMs: SOLANA_POLLING_INTERVAL_MS, signal });\n continue;\n }\n\n if (txStatus.err !== null) {\n return { status: 'reverted' };\n }\n\n if (txStatus.confirmationStatus === 'finalized') {\n return { status: 'ok' };\n }\n\n await waitForTimeoutOrAbort({ timeoutMs: SOLANA_POLLING_INTERVAL_MS, signal });\n } catch {\n return { status: 'unknown' };\n }\n }\n\n return { status: 'aborted' };\n}\n\nfunction _isValidSourceTxHash(txHash: string, sourceChainId: Caip2ChainId): boolean {\n if (isEvmNamespace(sourceChainId)) {\n return isHash(txHash);\n }\n\n if (isSolanaNamespace(sourceChainId)) {\n try {\n assertIsSignature(txHash);\n return true;\n } catch {\n return false;\n }\n }\n\n return false;\n}\n\nfunction _isMarkrSourceFinalized(finalized: CrossChainStatusResponse['sourceChain']['finalized']): boolean {\n return finalized === true || typeof finalized === 'string';\n}\n\nfunction _toSourceCompletedTransfer(transfer: InFlightTransfer): SourceCompletedTransfer {\n return {\n ...transfer,\n source: {\n ...transfer.source,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n },\n status: 'source-completed',\n };\n}\n\nfunction _withMarkrTrackingMetadata(\n transfer: InFlightTransfer,\n statusResponse: CrossChainStatusResponse,\n): InFlightTransfer {\n const metadata: Record<string, unknown> = { ...(transfer.metadata ?? {}) };\n\n if (statusResponse.destinationChain.bridgeHash) {\n metadata.bridgeHash = statusResponse.destinationChain.bridgeHash;\n }\n\n if (statusResponse.debug) {\n metadata.debug = statusResponse.debug;\n }\n\n if (Object.keys(metadata).length === 0) {\n return transfer;\n }\n\n return {\n ...transfer,\n metadata,\n };\n}\n\nfunction _toTargetPendingTransfer(\n transfer: InFlightTransfer,\n statusResponse: CrossChainStatusResponse,\n): TargetPendingTransfer {\n const { timestamp, transactionHash } = statusResponse.destinationChain;\n\n return {\n ...transfer,\n source: {\n ...transfer.source,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n },\n status: 'target-pending',\n target: {\n confirmationCount: transactionHash ? 1 : 0,\n requiredConfirmationCount: 2,\n startedAtMs: timestamp ? new Date(timestamp).getTime() : Date.now(),\n txHash: transactionHash ?? undefined,\n },\n };\n}\n\nfunction _toCompletedTransfer(transfer: InFlightTransfer, statusResponse: CrossChainStatusResponse): CompletedTransfer {\n const { timestamp, transactionHash } = statusResponse.destinationChain;\n\n return {\n ...transfer,\n completedAtMs: _getLastStatusActivityTime(statusResponse),\n status: 'completed',\n source: {\n ...transfer.source,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n },\n target: transactionHash\n ? {\n txHash: transactionHash,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n startedAtMs: timestamp ? new Date(timestamp).getTime() : Date.now(),\n }\n : null,\n };\n}\n\nfunction _toRefundedTransfer(transfer: InFlightTransfer, statusResponse: CrossChainStatusResponse): Transfer {\n const { transactionHash } = statusResponse.destinationChain;\n // This _should_ exist.\n // If it doesn't, thats a problem with Markr's API and they should resolve it.\n // We were \"guaranteed\" by them that in a \"refunded\" status, there would be exactly 1\n // transferred token in the response, which represents the refund.\n const refundedToken = statusResponse.transferredTokens[0];\n\n const refundAsset = refundedToken ? _getRefundAsset(transfer.targetChain.chainId, refundedToken.token) ?? null : null;\n const existingTarget = 'target' in transfer ? transfer.target : null;\n\n return {\n ...transfer,\n refund: {\n amount: refundedToken?.amount ?? 0n,\n asset: refundAsset,\n chainId: transfer.targetChain.chainId,\n txHash: transactionHash ?? null,\n timestampMs: _getLastStatusActivityTime(statusResponse),\n },\n source: {\n ...transfer.source,\n confirmationCount: 2,\n requiredConfirmationCount: 2,\n },\n status: 'refunded',\n target: existingTarget\n ? {\n ...existingTarget,\n txHash: undefined,\n }\n : null,\n };\n}\n\nfunction _getRefundAsset(chainId: Caip2ChainId, tokenAddress: string): Asset | undefined {\n if (isSolanaNamespace(chainId)) {\n if (!isSolanaAddress(tokenAddress)) {\n return undefined;\n }\n\n return {\n address: tokenAddress,\n decimals: 6,\n name: 'USD Coin',\n symbol: 'USDC',\n type: TokenType.SPL,\n };\n }\n\n if (isEvmNamespace(chainId)) {\n if (!isEvmAddress(tokenAddress)) {\n return undefined;\n }\n\n return {\n address: tokenAddress,\n decimals: 6,\n name: 'USD Coin',\n symbol: 'USDC',\n type: TokenType.ERC20,\n };\n }\n\n return undefined;\n}\n\nfunction _deriveTransferFromUnknownStatus(\n transfer: InFlightTransfer,\n statusResponse: CrossChainStatusResponse,\n): Transfer {\n if (statusResponse.progress.executed === true) {\n return _toCompletedTransfer(transfer, statusResponse);\n }\n\n if (statusResponse.progress.committed === true) {\n return _toTargetPendingTransfer(transfer, statusResponse);\n }\n\n if (_isMarkrSourceFinalized(statusResponse.sourceChain.finalized)) {\n return _toSourceCompletedTransfer(transfer);\n }\n\n return {\n ...transfer,\n source: {\n ...transfer.source,\n confirmationCount: 0,\n requiredConfirmationCount: 2,\n },\n status: 'source-pending',\n };\n}\n\nfunction _getLastStatusActivityTime(response: CrossChainStatusResponse): number {\n if (response.destinationChain.finalized) {\n return new Date(response.destinationChain.finalized).getTime();\n }\n\n if (response.destinationChain.timestamp) {\n return new Date(response.destinationChain.timestamp).getTime();\n }\n\n if (response.sourceChain.finalized) {\n if (typeof response.sourceChain.finalized === 'boolean' && response.sourceChain.finalized === true) {\n // Handle case where finalized is returned as boolean `true` instead of a timestamp.\n return new Date(response.sourceChain.timestamp).getTime();\n }\n return new Date(response.sourceChain.finalized).getTime();\n }\n\n return new Date(response.sourceChain.timestamp).getTime();\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../../utils/caip.cjs`),r=require(`../../../_utils/chain.cjs`),i=require(`../../_utils.cjs`),a=require(`../_api.cjs`),
|
|
1
|
+
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../../utils/caip.cjs`),r=require(`../../../_utils/chain.cjs`),i=require(`../../_utils.cjs`),a=require(`../../_evm-errors.cjs`),o=require(`../_api.cjs`),s=require(`../../../utils/sol-address.cjs`),c=require(`../_utils.cjs`),l=require(`../_type-guards.cjs`),u=require(`../../../utils/solana.cjs`),d=require(`./estimate-native-fee.cjs`);let f=require(`viem`);function p({apiOptions:n,appId:i,environment:a,evmSigner:o,solanaSigner:s}){return async({quote:c,gasSettings:l,fallbackToDefaultOnBatchFailure:u,onStepChange:d})=>{if(c.serviceType!==e.ServiceType.MARKR)throw new t.SdkError(t.ErrorReason.INCORRECT_PROVIDER_PROVIDED,t.ErrorCode.INVALID_PARAMS);let f=Math.floor(Date.now()/1e3);if(c.expiresAt<=f)throw new t.SdkError(t.ErrorReason.QUOTE_EXPIRED,t.ErrorCode.INVALID_PARAMS);let p=c.sourceChain.chainId;if(r.isSolanaNamespace(p))return h({apiOptions:n,appId:i,environment:a,solanaSigner:s,quote:c,onStepChange:d});if(r.isEvmNamespace(p))return m({apiOptions:n,appId:i,environment:a,evmSigner:o,quote:c,gasSettings:l,fallbackToDefaultOnBatchFailure:u,onStepChange:d});throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Unsupported source chain namespace: ${p}`})}}async function m({apiOptions:r,appId:s,environment:u,evmSigner:p,quote:m,gasSettings:h,fallbackToDefaultOnBatchFailure:_,onStepChange:v}){let y=m.fromAddress;if(!(0,f.isAddress)(y))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let b=c.calculateMarkrMinimumAmountOut({amountOut:m.amountOut,assetOut:m.assetOut,slippageBps:m.slippageBps}),x=i.getEvmClientForChain({chain:m.sourceChain}),S=c.assetToAddressString(m.assetIn,m.sourceChain.chainId),C=c.assetToAddressString(m.assetOut,m.targetChain.chainId);if(!(0,f.isAddress)(S))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address.`});let w=S,T=c.isTokenAddressNative(w),E=m.sourceChain.chainId.toLowerCase()!==m.targetChain.chainId.toLowerCase(),D=m.amountIn+c.getAdditiveSourceAssetFeeAmount(m),{address:O}=await o.markrGetSpenderAddress(r,{chainId:n.caip2ToEip155ChainId(m.sourceChain.chainId),crossChainSwap:E,quoteId:m.id});if(!T&&!O)throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${m.sourceChain.chainId}.`});let k=!1,A;if(!T&&O&&await x.readContract({address:w,abi:f.erc20Abi,functionName:`allowance`,args:[y,O]})<D){k=!0;let e=(0,f.encodeFunctionData)({abi:f.erc20Abi,functionName:`approve`,args:[O,D]}),t=i.applyFeeUnitsBpsMargin(await a.estimateGasWithRevert(x,{account:y,to:w,data:e},f.erc20Abi,`Failed to estimate gas for ERC20 approval transaction.`),h?.estimateGasMarginBps);A={chainId:n.caip2ToEip155HexChainId(m.sourceChain.chainId),data:e,from:y,gas:t,to:w,value:0n,...h?.maxFeePerGas===void 0?null:{maxFeePerGas:h.maxFeePerGas,maxPriorityFeePerGas:h.maxPriorityFeePerGas}}}let j=g({approvalRequest:A,requiresApprovalSignature:k,signBatch:p.signBatch,sourceChainId:m.sourceChain.chainId,targetChainId:m.targetChain.chainId}),M=await o.markrSwap(r,{amountIn:m.amountIn.toString(),appId:s,minAmountOut:b.toString(),tokenIn:S,tokenOut:C,uuid:m.id});if(!l.isEvmSwapResponse(M))throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.`});let N=(t,n=Date.now())=>{let r=m.sourceChain.chainId===m.targetChain.chainId;return{amountIn:m.amountIn,amountOut:m.amountOut,environment:u,fees:m.fees,fromAddress:m.fromAddress,id:m.id,partnerFeeBps:m.partnerFeeBps,sourceAsset:m.assetIn,sourceChain:m.sourceChain,status:`source-pending`,targetAsset:m.assetOut,targetChain:m.targetChain,toAddress:m.toAddress,type:e.ServiceType.MARKR,source:{confirmationCount:0,requiredConfirmationCount:r?1:2,startedAtMs:n,txHash:t}}};if(j&&A){let r={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.TokensTransfer,quote:m,requiredSignatures:1},i=p.signBatch;if(!i)throw new t.SdkError(`One-click batch signer is not available.`,t.ErrorCode.SIGNING_FAILED);let a={chainId:n.caip2ToEip155HexChainId(m.sourceChain.chainId),data:M.data,from:y,gas:void 0,to:M.to,value:M.value,...h?.maxFeePerGas===void 0?null:{maxFeePerGas:h.maxFeePerGas,maxPriorityFeePerGas:h.maxPriorityFeePerGas}};v?.(r);try{let e=(await i([A,a],async e=>x.sendRawTransaction({serializedTransaction:e}),r)).at(-1);if(!e)throw new t.SdkError(`One-click batch signing returned no transaction hashes.`,t.ErrorCode.SIGNING_FAILED);return N(e)}catch(e){if(!_)throw e}}if(k&&A){let n={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.AllowanceApproval,quote:m,requiredSignatures:2};v?.(n);let r=await p.sign(A,async e=>x.sendRawTransaction({serializedTransaction:e}),n);if((await x.waitForTransactionReceipt({hash:r})).status===`reverted`)return i.makeFailedTransferFromQuote(m,{environment:u,errorCode:t.ErrorCode.TRANSACTION_REVERTED,errorReason:`ERC20 approval transaction was reverted`})}let P=await d._estimateGasFromSwapResponse({crossChain:E,fromAddress:y,feeUnitsMarginBps:h?.estimateGasMarginBps,sourceClient:x,swap:M}),F={chainId:n.caip2ToEip155HexChainId(m.sourceChain.chainId),data:M.data,from:y,gas:P,to:M.to,value:M.value,...h?.maxFeePerGas===void 0?null:{maxFeePerGas:h.maxFeePerGas,maxPriorityFeePerGas:h.maxPriorityFeePerGas}},I={currentSignature:k?2:1,currentSignatureReason:e.TransferSignatureReason.TokensTransfer,quote:m,requiredSignatures:k?2:1};v?.(I);let L=Date.now();return N(await p.sign(F,async e=>x.sendRawTransaction({serializedTransaction:e}),I),L)}async function h({apiOptions:n,appId:r,environment:a,solanaSigner:d,quote:f,onStepChange:p}){if(!d)throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`solanaSigner is required for Solana transfers but was not provided.`});if(!s.isSolAddress(f.fromAddress))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid Solana address.`});let m=c.calculateMarkrMinimumAmountOut({amountOut:f.amountOut,assetOut:f.assetOut,slippageBps:f.slippageBps}),h=c.assetToAddressString(f.assetIn,f.sourceChain.chainId),g=c.assetToAddressString(f.assetOut,f.targetChain.chainId),_=await o.markrSwap(n,{amountIn:f.amountIn.toString(),appId:r,minAmountOut:m.toString(),tokenIn:h,tokenOut:g,userPublicKey:f.fromAddress,uuid:f.id});if(!l.isSolanaSwapResponse(_))throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.`});console.debug(`[Fusion SDK] Original swap transaction (base64):`,_.swapTransaction);let v=await u.refreshSolanaSwapTransactionBlockhash(_.swapTransaction,i.getSolanaRpcForChain({chain:f.sourceChain}));console.debug(`[Fusion SDK] Refreshed swap transaction with new blockhash (base64):`,v);let y={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.TokensTransfer,quote:f,requiredSignatures:1};p?.(y);let b=Date.now(),x=await d.signAndSend({account:f.fromAddress,serializedTx:v},y),S=f.sourceChain.chainId.toLowerCase()!==f.targetChain.chainId.toLowerCase();return{amountIn:f.amountIn,amountOut:f.amountOut,environment:a,fees:f.fees,fromAddress:f.fromAddress,id:f.id,partnerFeeBps:f.partnerFeeBps,sourceAsset:f.assetIn,sourceChain:f.sourceChain,status:`source-pending`,targetAsset:f.assetOut,targetChain:f.targetChain,toAddress:f.toAddress,type:e.ServiceType.MARKR,source:{confirmationCount:0,requiredConfirmationCount:S?2:32,startedAtMs:b,txHash:x}}}function g({approvalRequest:e,requiresApprovalSignature:t,signBatch:n,sourceChainId:i,targetChainId:a}){return r.isEvmNamespace(i)&&r.isEvmNamespace(a)&&i===a&&t&&e!==void 0&&typeof n==`function`}exports.transferAssetFactory=p;
|
|
2
2
|
//# sourceMappingURL=transfer-asset.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer-asset.cjs","names":["ServiceType","SdkError","ErrorReason","ErrorCode","isSolanaNamespace","isEvmNamespace","calculateMarkrMinimumAmountOut","getEvmClientForChain","assetToAddressString","isTokenAddressNative","getAdditiveSourceAssetFeeAmount","markrGetSpenderAddress","caip2ToEip155ChainId","erc20Abi","applyFeeUnitsBpsMargin","caip2ToEip155HexChainId","markrSwap","isEvmSwapResponse","TransferSignatureReason","makeFailedTransferFromQuote","_estimateGasFromSwapResponse","isSolAddress","isSolanaSwapResponse","refreshSolanaSwapTransactionBlockhash","getSolanaRpcForChain","SOLANA_REQUIRED_CONFIRMATIONS"],"sources":["../../../../src/transfer-service/markr/_handlers/transfer-asset.ts"],"sourcesContent":["import { encodeFunctionData, erc20Abi, isAddress } from 'viem';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { ServiceType, TransferSignatureReason } from '../../../constants';\nimport type { Environment } from '../../../constants';\nimport { ErrorCode, ErrorReason, SdkError } from '../../../errors';\nimport type { TransferService } from '../../../types/service';\nimport type { EvmSigner, EvmTransactionRequest, SolanaSigner } from '../../../types/signer';\nimport type { Transfer, TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport {\n applyFeeUnitsBpsMargin,\n getEvmClientForChain,\n getSolanaRpcForChain,\n makeFailedTransferFromQuote,\n} from '../../_utils';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n isTokenAddressNative,\n} from '../_utils';\nimport { isEvmSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { SOLANA_REQUIRED_CONFIRMATIONS } from '../constants';\nimport { _estimateGasFromSwapResponse } from './estimate-native-fee';\nimport type { Caip2ChainId } from '../../../types/caip';\nimport { refreshSolanaSwapTransactionBlockhash } from '../_solana-utils';\n\nexport interface TransferAssetFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n solanaSigner?: SolanaSigner;\n}\n\nexport function transferAssetFactory({\n apiOptions,\n appId,\n environment,\n evmSigner,\n solanaSigner,\n}: TransferAssetFactoryConfig): TransferService['transferAsset'] {\n return async ({ quote, gasSettings, fallbackToDefaultOnBatchFailure, onStepChange }) => {\n if (quote.serviceType !== ServiceType.MARKR) {\n throw new SdkError(ErrorReason.INCORRECT_PROVIDER_PROVIDED, ErrorCode.INVALID_PARAMS);\n }\n\n const now = Math.floor(Date.now() / 1_000);\n\n if (quote.expiresAt <= now) {\n throw new SdkError(ErrorReason.QUOTE_EXPIRED, ErrorCode.INVALID_PARAMS);\n }\n\n const sourceChainId = quote.sourceChain.chainId;\n\n if (isSolanaNamespace(sourceChainId)) {\n return _executeSvmTransfer({ apiOptions, appId, environment, solanaSigner, quote, onStepChange });\n }\n\n if (isEvmNamespace(sourceChainId)) {\n return _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n });\n }\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Unsupported source chain namespace: ${sourceChainId}`,\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// EVM transfer path\n// ---------------------------------------------------------------------------\n\ninterface EvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n gasSettings?: Parameters<TransferService['transferAsset']>[0]['gasSettings'];\n fallbackToDefaultOnBatchFailure?: Parameters<TransferService['transferAsset']>[0]['fallbackToDefaultOnBatchFailure'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n}: EvmTransferParams): Promise<Transfer> {\n const fromAddress = quote.fromAddress;\n\n if (!isAddress(fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid EVM address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n if (!isAddress(tokenInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'assetIn address is not a valid EVM address.',\n });\n }\n\n const tokenInAddress = tokenInAddressString;\n const isTokenInNative = isTokenAddressNative(tokenInAddress);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n if (!isTokenInNative && !spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${quote.sourceChain.chainId}.`,\n });\n }\n\n let requiresApprovalSignature = false;\n let approvalRequest: EvmTransactionRequest | undefined;\n\n if (!isTokenInNative && spenderAddress) {\n const allowance = await sourceClient.readContract({\n address: tokenInAddress,\n abi: erc20Abi,\n functionName: 'allowance',\n args: [fromAddress, spenderAddress],\n });\n\n if (allowance < allowanceAmount) {\n requiresApprovalSignature = true;\n\n const approvalData = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, allowanceAmount],\n });\n\n let approvalGasWithMargin: bigint | undefined;\n\n try {\n const approvalGasEstimate = await sourceClient.estimateGas({\n account: fromAddress,\n to: tokenInAddress,\n data: approvalData,\n value: 0n,\n });\n\n approvalGasWithMargin = applyFeeUnitsBpsMargin(approvalGasEstimate, gasSettings?.estimateGasMarginBps);\n } catch (err) {\n throw new SdkError('Error during gas estimation', ErrorCode.VIEM_ERROR, {\n cause: err,\n details: 'Failed to estimate gas for ERC20 approval transaction.',\n });\n }\n\n approvalRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: approvalData,\n from: fromAddress,\n gas: approvalGasWithMargin,\n to: tokenInAddress,\n value: 0n,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n }\n }\n\n const maybeOneClickBatch = isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch: evmSigner.signBatch,\n sourceChainId: quote.sourceChain.chainId,\n targetChainId: quote.targetChain.chainId,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.',\n });\n }\n\n const makePendingTransfer = (txHash: `0x${string}`, startedAtMs: number = Date.now()): Transfer => {\n const isSameChainTransfer = quote.sourceChain.chainId === quote.targetChain.chainId;\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isSameChainTransfer ? 1 : 2,\n startedAtMs,\n txHash,\n },\n };\n };\n\n if (maybeOneClickBatch && approvalRequest) {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n const signBatch = evmSigner.signBatch;\n\n if (!signBatch) {\n throw new SdkError('One-click batch signer is not available.', ErrorCode.SIGNING_FAILED);\n }\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n // Gas is purposely left undefined here.\n // We can't estimate the gas because we aren't executing the\n // approval tx. It's up to the wallet to correctly handle gas estimation.\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n\n onStepChange?.(batchStep);\n\n try {\n const txHashes = await signBatch(\n [approvalRequest, swapRequest],\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n\n const swapTxHash = txHashes.at(-1);\n\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n\n return makePendingTransfer(swapTxHash);\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n }\n }\n\n if (requiresApprovalSignature && approvalRequest) {\n const approvalStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote,\n requiredSignatures: 2,\n };\n\n onStepChange?.(approvalStep);\n\n const approvalTxHash = await evmSigner.sign(\n approvalRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n approvalStep,\n );\n\n const approvalReceipt = await sourceClient.waitForTransactionReceipt({ hash: approvalTxHash });\n\n if (approvalReceipt.status === 'reverted') {\n return makeFailedTransferFromQuote(quote, {\n environment,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'ERC20 approval transaction was reverted',\n });\n }\n }\n\n const swapGasWithMargin = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress,\n feeUnitsMarginBps: gasSettings?.estimateGasMarginBps,\n sourceClient,\n swap,\n });\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n gas: swapGasWithMargin,\n to: swap.to,\n value: swap.value,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n\n const step: TransferStepDetails = {\n currentSignature: requiresApprovalSignature ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: requiresApprovalSignature ? 2 : 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await evmSigner.sign(\n swapRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return makePendingTransfer(txHash, startedAtMs);\n}\n\n// ---------------------------------------------------------------------------\n// SVM (Solana) transfer path\n// ---------------------------------------------------------------------------\n\ninterface SvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n solanaSigner?: SolanaSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeSvmTransfer({\n apiOptions,\n appId,\n environment,\n solanaSigner,\n quote,\n onStepChange,\n}: SvmTransferParams): Promise<Transfer> {\n if (!solanaSigner) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'solanaSigner is required for Solana transfers but was not provided.',\n });\n }\n\n if (!isSolAddress(quote.fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid Solana address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.',\n });\n }\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Original swap transaction (base64):', swap.swapTransaction);\n\n const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Refreshed swap transaction with new blockhash (base64):', swapTransactionBase64);\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await solanaSigner.signAndSend(\n {\n account: quote.fromAddress,\n serializedTx: swapTransactionBase64,\n },\n step,\n );\n\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isCrossChainSwap ? 2 : SOLANA_REQUIRED_CONFIRMATIONS,\n startedAtMs,\n txHash,\n },\n };\n}\n\n/**\n * Determines whether one-click swap eligibility criteria is met.\n *\n * Only same-chain EVM swaps are currently eligible.\n */\nfunction isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch,\n sourceChainId,\n targetChainId,\n}: {\n approvalRequest?: EvmTransactionRequest;\n requiresApprovalSignature: boolean;\n signBatch?: EvmSigner['signBatch'];\n sourceChainId: Caip2ChainId;\n targetChainId: Caip2ChainId;\n}): boolean {\n return (\n isEvmNamespace(sourceChainId) &&\n isEvmNamespace(targetChainId) &&\n sourceChainId === targetChainId &&\n requiresApprovalSignature &&\n approvalRequest !== undefined &&\n typeof signBatch === 'function'\n );\n}\n"],"mappings":"seAqCA,SAAgB,EAAqB,CACnC,aACA,QACA,cACA,YACA,gBAC+D,CAC/D,OAAO,MAAO,CAAE,QAAO,cAAa,kCAAiC,kBAAmB,CACtF,GAAI,EAAM,cAAgBA,EAAAA,YAAY,MACpC,MAAM,IAAIC,EAAAA,SAASC,EAAAA,YAAY,4BAA6BC,EAAAA,UAAU,eAAe,CAGvF,IAAM,EAAM,KAAK,MAAM,KAAK,KAAK,CAAG,IAAM,CAE1C,GAAI,EAAM,WAAa,EACrB,MAAM,IAAIF,EAAAA,SAASC,EAAAA,YAAY,cAAeC,EAAAA,UAAU,eAAe,CAGzE,IAAM,EAAgB,EAAM,YAAY,QAExC,GAAIC,EAAAA,kBAAkB,EAAc,CAClC,OAAO,EAAoB,CAAE,aAAY,QAAO,cAAa,eAAc,QAAO,eAAc,CAAC,CAGnG,GAAIC,EAAAA,eAAe,EAAc,CAC/B,OAAO,EAAoB,CACzB,aACA,QACA,cACA,YACA,QACA,cACA,kCACA,eACD,CAAC,CAGJ,MAAM,IAAIJ,EAAAA,SAASC,EAAAA,YAAY,oBAAqBC,EAAAA,UAAU,eAAgB,CAC5E,QAAS,uCAAuC,IACjD,CAAC,EAmBN,eAAe,EAAoB,CACjC,aACA,QACA,cACA,YACA,QACA,cACA,kCACA,gBACuC,CACvC,IAAM,EAAc,EAAM,YAE1B,GAAI,EAAA,EAAA,EAAA,WAAW,EAAY,CACzB,MAAM,IAAIF,EAAAA,SAASC,EAAAA,YAAY,eAAgBC,EAAAA,UAAU,eAAgB,CACvE,QAAS,0CACV,CAAC,CAGJ,IAAM,EAAeG,EAAAA,+BAA+B,CAClD,UAAW,EAAM,UACjB,SAAU,EAAM,SAChB,YAAa,EAAM,YACpB,CAAC,CAEI,EAAeC,EAAAA,qBAAqB,CAAE,MAAO,EAAM,YAAa,CAAC,CAEjE,EAAuBC,EAAAA,qBAAqB,EAAM,QAAS,EAAM,YAAY,QAAQ,CACrF,EAAwBA,EAAAA,qBAAqB,EAAM,SAAU,EAAM,YAAY,QAAQ,CAE7F,GAAI,EAAA,EAAA,EAAA,WAAW,EAAqB,CAClC,MAAM,IAAIP,EAAAA,SAASC,EAAAA,YAAY,eAAgBC,EAAAA,UAAU,eAAgB,CACvE,QAAS,8CACV,CAAC,CAGJ,IAAM,EAAiB,EACjB,EAAkBM,EAAAA,qBAAqB,EAAe,CACtD,EAAmB,EAAM,YAAY,QAAQ,aAAa,GAAK,EAAM,YAAY,QAAQ,aAAa,CACtG,EAAkB,EAAM,SAAWC,EAAAA,gCAAgC,EAAM,CAEzE,CAAE,QAAS,GAAmB,MAAMC,EAAAA,uBAAuB,EAAY,CAC3E,QAASC,EAAAA,qBAAqB,EAAM,YAAY,QAAQ,CACxD,eAAgB,EAChB,QAAS,EAAM,GAChB,CAAC,CAEF,GAAI,CAAC,GAAmB,CAAC,EACvB,MAAM,IAAIX,EAAAA,SAASC,EAAAA,YAAY,oBAAqBC,EAAAA,UAAU,eAAgB,CAC5E,QAAS,kDAAkD,EAAM,YAAY,QAAQ,GACtF,CAAC,CAGJ,IAAI,EAA4B,GAC5B,EAEJ,GAAI,CAAC,GAAmB,GACJ,MAAM,EAAa,aAAa,CAChD,QAAS,EACT,IAAKU,EAAAA,SACL,aAAc,YACd,KAAM,CAAC,EAAa,EAAe,CACpC,CAAC,CAEc,EAAiB,CAC/B,EAA4B,GAE5B,IAAM,GAAA,EAAA,EAAA,oBAAkC,CACtC,IAAKA,EAAAA,SACL,aAAc,UACd,KAAM,CAAC,EAAgB,EAAgB,CACxC,CAAC,CAEE,EAEJ,GAAI,CAQF,EAAwBC,EAAAA,uBAPI,MAAM,EAAa,YAAY,CACzD,QAAS,EACT,GAAI,EACJ,KAAM,EACN,MAAO,GACR,CAAC,CAEkE,GAAa,qBAAqB,OAC/F,EAAK,CACZ,MAAM,IAAIb,EAAAA,SAAS,8BAA+BE,EAAAA,UAAU,WAAY,CACtE,MAAO,EACP,QAAS,yDACV,CAAC,CAGJ,EAAkB,CAChB,QAASY,EAAAA,wBAAwB,EAAM,YAAY,QAAQ,CAC3D,KAAM,EACN,KAAM,EACN,IAAK,EACL,GAAI,EACJ,MAAO,GACP,GAAI,GAAa,eAAiB,IAAA,GAK9B,KAJA,CACE,aAAc,EAAY,aAC1B,qBAAsB,EAAY,qBACnC,CAEN,CAIL,IAAM,EAAqB,EAAwB,CACjD,kBACA,4BACA,UAAW,EAAU,UACrB,cAAe,EAAM,YAAY,QACjC,cAAe,EAAM,YAAY,QAClC,CAAC,CAEI,EAAO,MAAMC,EAAAA,UAAU,EAAY,CACvC,SAAU,EAAM,SAAS,UAAU,CACnC,QACA,aAAc,EAAa,UAAU,CACrC,QAAS,EACT,SAAU,EACV,KAAM,EAAM,GACb,CAAC,CAEF,GAAI,CAACC,EAAAA,kBAAkB,EAAK,CAC1B,MAAM,IAAIhB,EAAAA,SAASC,EAAAA,YAAY,oBAAqBC,EAAAA,UAAU,eAAgB,CAC5E,QAAS,qGACV,CAAC,CAGJ,IAAM,GAAuB,EAAuB,EAAsB,KAAK,KAAK,GAAe,CACjG,IAAM,EAAsB,EAAM,YAAY,UAAY,EAAM,YAAY,QAE5E,MAAO,CACL,SAAU,EAAM,SAChB,UAAW,EAAM,UACjB,cACA,KAAM,EAAM,KACZ,YAAa,EAAM,YACnB,GAAI,EAAM,GACV,cAAe,EAAM,cACrB,YAAa,EAAM,QACnB,YAAa,EAAM,YACnB,OAAQ,iBACR,YAAa,EAAM,SACnB,YAAa,EAAM,YACnB,UAAW,EAAM,UACjB,KAAMH,EAAAA,YAAY,MAClB,OAAQ,CACN,kBAAmB,EACnB,0BAA2B,EAAsB,EAAI,EACrD,cACA,SACD,CACF,EAGH,GAAI,GAAsB,EAAiB,CACzC,IAAM,EAAiC,CACrC,iBAAkB,EAClB,uBAAwBkB,EAAAA,wBAAwB,eAChD,QACA,mBAAoB,EACrB,CAEK,EAAY,EAAU,UAE5B,GAAI,CAAC,EACH,MAAM,IAAIjB,EAAAA,SAAS,2CAA4CE,EAAAA,UAAU,eAAe,CAG1F,IAAM,EAAqC,CACzC,QAASY,EAAAA,wBAAwB,EAAM,YAAY,QAAQ,CAC3D,KAAM,EAAK,KACX,KAAM,EAIN,IAAK,IAAA,GACL,GAAI,EAAK,GACT,MAAO,EAAK,MACZ,GAAI,GAAa,eAAiB,IAAA,GAK9B,KAJA,CACE,aAAc,EAAY,aAC1B,qBAAsB,EAAY,qBACnC,CAEN,CAED,IAAe,EAAU,CAEzB,GAAI,CAOF,IAAM,GANW,MAAM,EACrB,CAAC,EAAiB,EAAY,CAC9B,KAAO,IAAiB,EAAa,mBAAmB,CAAE,sBAAuB,EAAc,CAAC,CAChG,EACD,EAE2B,GAAG,GAAG,CAElC,GAAI,CAAC,EACH,MAAM,IAAId,EAAAA,SAAS,0DAA2DE,EAAAA,UAAU,eAAe,CAGzG,OAAO,EAAoB,EAAW,OAC/B,EAAO,CACd,GAAI,CAAC,EACH,MAAM,GAKZ,GAAI,GAA6B,EAAiB,CAChD,IAAM,EAAoC,CACxC,iBAAkB,EAClB,uBAAwBe,EAAAA,wBAAwB,kBAChD,QACA,mBAAoB,EACrB,CAED,IAAe,EAAa,CAE5B,IAAM,EAAiB,MAAM,EAAU,KACrC,EACA,KAAO,IAAiB,EAAa,mBAAmB,CAAE,sBAAuB,EAAc,CAAC,CAChG,EACD,CAID,IAFwB,MAAM,EAAa,0BAA0B,CAAE,KAAM,EAAgB,CAAC,EAE1E,SAAW,WAC7B,OAAOC,EAAAA,4BAA4B,EAAO,CACxC,cACA,UAAWhB,EAAAA,UAAU,qBACrB,YAAa,0CACd,CAAC,CAIN,IAAM,EAAoB,MAAMiB,EAAAA,6BAA6B,CAC3D,WAAY,EACZ,cACA,kBAAmB,GAAa,qBAChC,eACA,OACD,CAAC,CAEI,EAAqC,CACzC,QAASL,EAAAA,wBAAwB,EAAM,YAAY,QAAQ,CAC3D,KAAM,EAAK,KACX,KAAM,EACN,IAAK,EACL,GAAI,EAAK,GACT,MAAO,EAAK,MACZ,GAAI,GAAa,eAAiB,IAAA,GAK9B,KAJA,CACE,aAAc,EAAY,aAC1B,qBAAsB,EAAY,qBACnC,CAEN,CAEK,EAA4B,CAChC,iBAAkB,EAA4B,EAAI,EAClD,uBAAwBG,EAAAA,wBAAwB,eAChD,QACA,mBAAoB,EAA4B,EAAI,EACrD,CAED,IAAe,EAAK,CAEpB,IAAM,EAAc,KAAK,KAAK,CAQ9B,OAAO,EANQ,MAAM,EAAU,KAC7B,EACA,KAAO,IAAiB,EAAa,mBAAmB,CAAE,sBAAuB,EAAc,CAAC,CAChG,EACD,CAEkC,EAAY,CAgBjD,eAAe,EAAoB,CACjC,aACA,QACA,cACA,eACA,QACA,gBACuC,CACvC,GAAI,CAAC,EACH,MAAM,IAAIjB,EAAAA,SAASC,EAAAA,YAAY,eAAgBC,EAAAA,UAAU,eAAgB,CACvE,QAAS,sEACV,CAAC,CAGJ,GAAI,CAACkB,EAAAA,aAAa,EAAM,YAAY,CAClC,MAAM,IAAIpB,EAAAA,SAASC,EAAAA,YAAY,eAAgBC,EAAAA,UAAU,eAAgB,CACvE,QAAS,6CACV,CAAC,CAGJ,IAAM,EAAeG,EAAAA,+BAA+B,CAClD,UAAW,EAAM,UACjB,SAAU,EAAM,SAChB,YAAa,EAAM,YACpB,CAAC,CAEI,EAAuBE,EAAAA,qBAAqB,EAAM,QAAS,EAAM,YAAY,QAAQ,CACrF,EAAwBA,EAAAA,qBAAqB,EAAM,SAAU,EAAM,YAAY,QAAQ,CAEvF,EAAO,MAAMQ,EAAAA,UAAU,EAAY,CACvC,SAAU,EAAM,SAAS,UAAU,CACnC,QACA,aAAc,EAAa,UAAU,CACrC,QAAS,EACT,SAAU,EACV,cAAe,EAAM,YACrB,KAAM,EAAM,GACb,CAAC,CAEF,GAAI,CAACM,EAAAA,qBAAqB,EAAK,CAC7B,MAAM,IAAIrB,EAAAA,SAASC,EAAAA,YAAY,oBAAqBC,EAAAA,UAAU,eAAgB,CAC5E,QAAS,qGACV,CAAC,CAIJ,QAAQ,MAAM,mDAAoD,EAAK,gBAAgB,CAEvF,IAAM,EAAwB,MAAMoB,EAAAA,sCAClC,EAAK,gBACLC,EAAAA,qBAAqB,CAAE,MAAO,EAAM,YAAa,CAAC,CACnD,CAGD,QAAQ,MAAM,uEAAwE,EAAsB,CAE5G,IAAM,EAA4B,CAChC,iBAAkB,EAClB,uBAAwBN,EAAAA,wBAAwB,eAChD,QACA,mBAAoB,EACrB,CAED,IAAe,EAAK,CAEpB,IAAM,EAAc,KAAK,KAAK,CAExB,EAAS,MAAM,EAAa,YAChC,CACE,QAAS,EAAM,YACf,aAAc,EACf,CACD,EACD,CAEK,EAAmB,EAAM,YAAY,QAAQ,aAAa,GAAK,EAAM,YAAY,QAAQ,aAAa,CAE5G,MAAO,CACL,SAAU,EAAM,SAChB,UAAW,EAAM,UACjB,cACA,KAAM,EAAM,KACZ,YAAa,EAAM,YACnB,GAAI,EAAM,GACV,cAAe,EAAM,cACrB,YAAa,EAAM,QACnB,YAAa,EAAM,YACnB,OAAQ,iBACR,YAAa,EAAM,SACnB,YAAa,EAAM,YACnB,UAAW,EAAM,UACjB,KAAMlB,EAAAA,YAAY,MAClB,OAAQ,CACN,kBAAmB,EACnB,0BAA2B,EAAmB,EAAIyB,EAAAA,8BAClD,cACA,SACD,CACF,CAQH,SAAS,EAAwB,CAC/B,kBACA,4BACA,YACA,gBACA,iBAOU,CACV,OACEpB,EAAAA,eAAe,EAAc,EAC7BA,EAAAA,eAAe,EAAc,EAC7B,IAAkB,GAClB,GACA,IAAoB,IAAA,IACpB,OAAO,GAAc"}
|
|
1
|
+
{"version":3,"file":"transfer-asset.cjs","names":["ServiceType","SdkError","ErrorReason","ErrorCode","isSolanaNamespace","isEvmNamespace","calculateMarkrMinimumAmountOut","getEvmClientForChain","assetToAddressString","isTokenAddressNative","getAdditiveSourceAssetFeeAmount","markrGetSpenderAddress","caip2ToEip155ChainId","erc20Abi","applyFeeUnitsBpsMargin","estimateGasWithRevert","caip2ToEip155HexChainId","markrSwap","isEvmSwapResponse","TransferSignatureReason","makeFailedTransferFromQuote","_estimateGasFromSwapResponse","isSolAddress","isSolanaSwapResponse","refreshSolanaSwapTransactionBlockhash","getSolanaRpcForChain"],"sources":["../../../../src/transfer-service/markr/_handlers/transfer-asset.ts"],"sourcesContent":["import { encodeFunctionData, erc20Abi, isAddress } from 'viem';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { ServiceType, TransferSignatureReason } from '../../../constants';\nimport type { Environment } from '../../../constants';\nimport { ErrorCode, ErrorReason, SdkError } from '../../../errors';\nimport type { TransferService } from '../../../types/service';\nimport type { EvmSigner, EvmTransactionRequest, SolanaSigner } from '../../../types/signer';\nimport type { Transfer, TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport {\n applyFeeUnitsBpsMargin,\n getEvmClientForChain,\n getSolanaRpcForChain,\n makeFailedTransferFromQuote,\n} from '../../_utils';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n isTokenAddressNative,\n} from '../_utils';\nimport { isEvmSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { SOLANA_REQUIRED_CONFIRMATIONS } from '../constants';\nimport { _estimateGasFromSwapResponse } from './estimate-native-fee';\nimport type { Caip2ChainId } from '../../../types/caip';\nimport { refreshSolanaSwapTransactionBlockhash } from '../../../utils/solana';\n\nexport interface TransferAssetFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n solanaSigner?: SolanaSigner;\n}\n\nexport function transferAssetFactory({\n apiOptions,\n appId,\n environment,\n evmSigner,\n solanaSigner,\n}: TransferAssetFactoryConfig): TransferService['transferAsset'] {\n return async ({ quote, gasSettings, fallbackToDefaultOnBatchFailure, onStepChange }) => {\n if (quote.serviceType !== ServiceType.MARKR) {\n throw new SdkError(ErrorReason.INCORRECT_PROVIDER_PROVIDED, ErrorCode.INVALID_PARAMS);\n }\n\n const now = Math.floor(Date.now() / 1_000);\n\n if (quote.expiresAt <= now) {\n throw new SdkError(ErrorReason.QUOTE_EXPIRED, ErrorCode.INVALID_PARAMS);\n }\n\n const sourceChainId = quote.sourceChain.chainId;\n\n if (isSolanaNamespace(sourceChainId)) {\n return _executeSvmTransfer({ apiOptions, appId, environment, solanaSigner, quote, onStepChange });\n }\n\n if (isEvmNamespace(sourceChainId)) {\n return _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n });\n }\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Unsupported source chain namespace: ${sourceChainId}`,\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// EVM transfer path\n// ---------------------------------------------------------------------------\n\ninterface EvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n gasSettings?: Parameters<TransferService['transferAsset']>[0]['gasSettings'];\n fallbackToDefaultOnBatchFailure?: Parameters<TransferService['transferAsset']>[0]['fallbackToDefaultOnBatchFailure'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n}: EvmTransferParams): Promise<Transfer> {\n const fromAddress = quote.fromAddress;\n\n if (!isAddress(fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid EVM address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n if (!isAddress(tokenInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'assetIn address is not a valid EVM address.',\n });\n }\n\n const tokenInAddress = tokenInAddressString;\n const isTokenInNative = isTokenAddressNative(tokenInAddress);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n if (!isTokenInNative && !spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${quote.sourceChain.chainId}.`,\n });\n }\n\n let requiresApprovalSignature = false;\n let approvalRequest: EvmTransactionRequest | undefined;\n\n if (!isTokenInNative && spenderAddress) {\n const allowance = await sourceClient.readContract({\n address: tokenInAddress,\n abi: erc20Abi,\n functionName: 'allowance',\n args: [fromAddress, spenderAddress],\n });\n\n if (allowance < allowanceAmount) {\n requiresApprovalSignature = true;\n\n const approvalData = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, allowanceAmount],\n });\n\n const approvalGasEstimate = await estimateGasWithRevert(\n sourceClient,\n {\n account: fromAddress,\n to: tokenInAddress,\n data: approvalData,\n },\n erc20Abi,\n 'Failed to estimate gas for ERC20 approval transaction.',\n );\n\n const approvalGasWithMargin = applyFeeUnitsBpsMargin(approvalGasEstimate, gasSettings?.estimateGasMarginBps);\n\n approvalRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: approvalData,\n from: fromAddress,\n gas: approvalGasWithMargin,\n to: tokenInAddress,\n value: 0n,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n }\n }\n\n const maybeOneClickBatch = isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch: evmSigner.signBatch,\n sourceChainId: quote.sourceChain.chainId,\n targetChainId: quote.targetChain.chainId,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.',\n });\n }\n\n const makePendingTransfer = (txHash: `0x${string}`, startedAtMs: number = Date.now()): Transfer => {\n const isSameChainTransfer = quote.sourceChain.chainId === quote.targetChain.chainId;\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isSameChainTransfer ? 1 : 2,\n startedAtMs,\n txHash,\n },\n };\n };\n\n if (maybeOneClickBatch && approvalRequest) {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n const signBatch = evmSigner.signBatch;\n\n if (!signBatch) {\n throw new SdkError('One-click batch signer is not available.', ErrorCode.SIGNING_FAILED);\n }\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n // Gas is purposely left undefined here.\n // We can't estimate the gas because we aren't executing the\n // approval tx. It's up to the wallet to correctly handle gas estimation.\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n\n onStepChange?.(batchStep);\n\n try {\n const txHashes = await signBatch(\n [approvalRequest, swapRequest],\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n\n const swapTxHash = txHashes.at(-1);\n\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n\n return makePendingTransfer(swapTxHash);\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n }\n }\n\n if (requiresApprovalSignature && approvalRequest) {\n const approvalStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote,\n requiredSignatures: 2,\n };\n\n onStepChange?.(approvalStep);\n\n const approvalTxHash = await evmSigner.sign(\n approvalRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n approvalStep,\n );\n\n const approvalReceipt = await sourceClient.waitForTransactionReceipt({ hash: approvalTxHash });\n\n if (approvalReceipt.status === 'reverted') {\n return makeFailedTransferFromQuote(quote, {\n environment,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'ERC20 approval transaction was reverted',\n });\n }\n }\n\n const swapGasWithMargin = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress,\n feeUnitsMarginBps: gasSettings?.estimateGasMarginBps,\n sourceClient,\n swap,\n });\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n gas: swapGasWithMargin,\n to: swap.to,\n value: swap.value,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n\n const step: TransferStepDetails = {\n currentSignature: requiresApprovalSignature ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: requiresApprovalSignature ? 2 : 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await evmSigner.sign(\n swapRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return makePendingTransfer(txHash, startedAtMs);\n}\n\n// ---------------------------------------------------------------------------\n// SVM (Solana) transfer path\n// ---------------------------------------------------------------------------\n\ninterface SvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n solanaSigner?: SolanaSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeSvmTransfer({\n apiOptions,\n appId,\n environment,\n solanaSigner,\n quote,\n onStepChange,\n}: SvmTransferParams): Promise<Transfer> {\n if (!solanaSigner) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'solanaSigner is required for Solana transfers but was not provided.',\n });\n }\n\n if (!isSolAddress(quote.fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid Solana address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.',\n });\n }\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Original swap transaction (base64):', swap.swapTransaction);\n\n const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Refreshed swap transaction with new blockhash (base64):', swapTransactionBase64);\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await solanaSigner.signAndSend(\n {\n account: quote.fromAddress,\n serializedTx: swapTransactionBase64,\n },\n step,\n );\n\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isCrossChainSwap ? 2 : SOLANA_REQUIRED_CONFIRMATIONS,\n startedAtMs,\n txHash,\n },\n };\n}\n\n/**\n * Determines whether one-click swap eligibility criteria is met.\n *\n * Only same-chain EVM swaps are currently eligible.\n */\nfunction isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch,\n sourceChainId,\n targetChainId,\n}: {\n approvalRequest?: EvmTransactionRequest;\n requiresApprovalSignature: boolean;\n signBatch?: EvmSigner['signBatch'];\n sourceChainId: Caip2ChainId;\n targetChainId: Caip2ChainId;\n}): boolean {\n return (\n isEvmNamespace(sourceChainId) &&\n isEvmNamespace(targetChainId) &&\n sourceChainId === targetChainId &&\n requiresApprovalSignature &&\n approvalRequest !== undefined &&\n typeof signBatch === 'function'\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ServiceType as e,TransferSignatureReason as t}from"../../../constants.js";import{ErrorCode as n,ErrorReason as r,SdkError as i}from"../../../errors.js";import{caip2ToEip155ChainId as a,caip2ToEip155HexChainId as o}from"../../../utils/caip.js";import{isEvmNamespace as s,isSolanaNamespace as c}from"../../../_utils/chain.js";import{applyFeeUnitsBpsMargin as l,getEvmClientForChain as u,getSolanaRpcForChain as d,makeFailedTransferFromQuote as f}from"../../_utils.js";import{markrGetSpenderAddress as
|
|
1
|
+
import{ServiceType as e,TransferSignatureReason as t}from"../../../constants.js";import{ErrorCode as n,ErrorReason as r,SdkError as i}from"../../../errors.js";import{caip2ToEip155ChainId as a,caip2ToEip155HexChainId as o}from"../../../utils/caip.js";import{isEvmNamespace as s,isSolanaNamespace as c}from"../../../_utils/chain.js";import{applyFeeUnitsBpsMargin as l,getEvmClientForChain as u,getSolanaRpcForChain as d,makeFailedTransferFromQuote as f}from"../../_utils.js";import{estimateGasWithRevert as p}from"../../_evm-errors.js";import{markrGetSpenderAddress as m,markrSwap as h}from"../_api.js";import{isSolAddress as g}from"../../../utils/sol-address.js";import{assetToAddressString as _,calculateMarkrMinimumAmountOut as v,getAdditiveSourceAssetFeeAmount as y,isTokenAddressNative as b}from"../_utils.js";import{isEvmSwapResponse as x,isSolanaSwapResponse as S}from"../_type-guards.js";import{refreshSolanaSwapTransactionBlockhash as C}from"../../../utils/solana.js";import{_estimateGasFromSwapResponse as w}from"./estimate-native-fee.js";import{encodeFunctionData as T,erc20Abi as E,isAddress as D}from"viem";function O({apiOptions:t,appId:a,environment:o,evmSigner:l,solanaSigner:u}){return async({quote:d,gasSettings:f,fallbackToDefaultOnBatchFailure:p,onStepChange:m})=>{if(d.serviceType!==e.MARKR)throw new i(r.INCORRECT_PROVIDER_PROVIDED,n.INVALID_PARAMS);let h=Math.floor(Date.now()/1e3);if(d.expiresAt<=h)throw new i(r.QUOTE_EXPIRED,n.INVALID_PARAMS);let g=d.sourceChain.chainId;if(c(g))return A({apiOptions:t,appId:a,environment:o,solanaSigner:u,quote:d,onStepChange:m});if(s(g))return k({apiOptions:t,appId:a,environment:o,evmSigner:l,quote:d,gasSettings:f,fallbackToDefaultOnBatchFailure:p,onStepChange:m});throw new i(r.CHAIN_NOT_SUPPORTED,n.INVALID_PARAMS,{details:`Unsupported source chain namespace: ${g}`})}}async function k({apiOptions:s,appId:c,environment:d,evmSigner:g,quote:S,gasSettings:C,fallbackToDefaultOnBatchFailure:O,onStepChange:k}){let A=S.fromAddress;if(!D(A))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let M=v({amountOut:S.amountOut,assetOut:S.assetOut,slippageBps:S.slippageBps}),N=u({chain:S.sourceChain}),P=_(S.assetIn,S.sourceChain.chainId),F=_(S.assetOut,S.targetChain.chainId);if(!D(P))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address.`});let I=P,L=b(I),R=S.sourceChain.chainId.toLowerCase()!==S.targetChain.chainId.toLowerCase(),z=S.amountIn+y(S),{address:B}=await m(s,{chainId:a(S.sourceChain.chainId),crossChainSwap:R,quoteId:S.id});if(!L&&!B)throw new i(r.CHAIN_NOT_SUPPORTED,n.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${S.sourceChain.chainId}.`});let V=!1,H;if(!L&&B&&await N.readContract({address:I,abi:E,functionName:`allowance`,args:[A,B]})<z){V=!0;let e=T({abi:E,functionName:`approve`,args:[B,z]}),t=l(await p(N,{account:A,to:I,data:e},E,`Failed to estimate gas for ERC20 approval transaction.`),C?.estimateGasMarginBps);H={chainId:o(S.sourceChain.chainId),data:e,from:A,gas:t,to:I,value:0n,...C?.maxFeePerGas===void 0?null:{maxFeePerGas:C.maxFeePerGas,maxPriorityFeePerGas:C.maxPriorityFeePerGas}}}let U=j({approvalRequest:H,requiresApprovalSignature:V,signBatch:g.signBatch,sourceChainId:S.sourceChain.chainId,targetChainId:S.targetChain.chainId}),W=await h(s,{amountIn:S.amountIn.toString(),appId:c,minAmountOut:M.toString(),tokenIn:P,tokenOut:F,uuid:S.id});if(!x(W))throw new i(r.CHAIN_NOT_SUPPORTED,n.INVALID_PARAMS,{details:`Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.`});let G=(t,n=Date.now())=>{let r=S.sourceChain.chainId===S.targetChain.chainId;return{amountIn:S.amountIn,amountOut:S.amountOut,environment:d,fees:S.fees,fromAddress:S.fromAddress,id:S.id,partnerFeeBps:S.partnerFeeBps,sourceAsset:S.assetIn,sourceChain:S.sourceChain,status:`source-pending`,targetAsset:S.assetOut,targetChain:S.targetChain,toAddress:S.toAddress,type:e.MARKR,source:{confirmationCount:0,requiredConfirmationCount:r?1:2,startedAtMs:n,txHash:t}}};if(U&&H){let e={currentSignature:1,currentSignatureReason:t.TokensTransfer,quote:S,requiredSignatures:1},r=g.signBatch;if(!r)throw new i(`One-click batch signer is not available.`,n.SIGNING_FAILED);let a={chainId:o(S.sourceChain.chainId),data:W.data,from:A,gas:void 0,to:W.to,value:W.value,...C?.maxFeePerGas===void 0?null:{maxFeePerGas:C.maxFeePerGas,maxPriorityFeePerGas:C.maxPriorityFeePerGas}};k?.(e);try{let t=(await r([H,a],async e=>N.sendRawTransaction({serializedTransaction:e}),e)).at(-1);if(!t)throw new i(`One-click batch signing returned no transaction hashes.`,n.SIGNING_FAILED);return G(t)}catch(e){if(!O)throw e}}if(V&&H){let e={currentSignature:1,currentSignatureReason:t.AllowanceApproval,quote:S,requiredSignatures:2};k?.(e);let r=await g.sign(H,async e=>N.sendRawTransaction({serializedTransaction:e}),e);if((await N.waitForTransactionReceipt({hash:r})).status===`reverted`)return f(S,{environment:d,errorCode:n.TRANSACTION_REVERTED,errorReason:`ERC20 approval transaction was reverted`})}let K=await w({crossChain:R,fromAddress:A,feeUnitsMarginBps:C?.estimateGasMarginBps,sourceClient:N,swap:W}),q={chainId:o(S.sourceChain.chainId),data:W.data,from:A,gas:K,to:W.to,value:W.value,...C?.maxFeePerGas===void 0?null:{maxFeePerGas:C.maxFeePerGas,maxPriorityFeePerGas:C.maxPriorityFeePerGas}},J={currentSignature:V?2:1,currentSignatureReason:t.TokensTransfer,quote:S,requiredSignatures:V?2:1};k?.(J);let Y=Date.now();return G(await g.sign(q,async e=>N.sendRawTransaction({serializedTransaction:e}),J),Y)}async function A({apiOptions:a,appId:o,environment:s,solanaSigner:c,quote:l,onStepChange:u}){if(!c)throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`solanaSigner is required for Solana transfers but was not provided.`});if(!g(l.fromAddress))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`fromAddress is not a valid Solana address.`});let f=v({amountOut:l.amountOut,assetOut:l.assetOut,slippageBps:l.slippageBps}),p=_(l.assetIn,l.sourceChain.chainId),m=_(l.assetOut,l.targetChain.chainId),y=await h(a,{amountIn:l.amountIn.toString(),appId:o,minAmountOut:f.toString(),tokenIn:p,tokenOut:m,userPublicKey:l.fromAddress,uuid:l.id});if(!S(y))throw new i(r.CHAIN_NOT_SUPPORTED,n.INVALID_PARAMS,{details:`Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.`});console.debug(`[Fusion SDK] Original swap transaction (base64):`,y.swapTransaction);let b=await C(y.swapTransaction,d({chain:l.sourceChain}));console.debug(`[Fusion SDK] Refreshed swap transaction with new blockhash (base64):`,b);let x={currentSignature:1,currentSignatureReason:t.TokensTransfer,quote:l,requiredSignatures:1};u?.(x);let w=Date.now(),T=await c.signAndSend({account:l.fromAddress,serializedTx:b},x),E=l.sourceChain.chainId.toLowerCase()!==l.targetChain.chainId.toLowerCase();return{amountIn:l.amountIn,amountOut:l.amountOut,environment:s,fees:l.fees,fromAddress:l.fromAddress,id:l.id,partnerFeeBps:l.partnerFeeBps,sourceAsset:l.assetIn,sourceChain:l.sourceChain,status:`source-pending`,targetAsset:l.assetOut,targetChain:l.targetChain,toAddress:l.toAddress,type:e.MARKR,source:{confirmationCount:0,requiredConfirmationCount:E?2:32,startedAtMs:w,txHash:T}}}function j({approvalRequest:e,requiresApprovalSignature:t,signBatch:n,sourceChainId:r,targetChainId:i}){return s(r)&&s(i)&&r===i&&t&&e!==void 0&&typeof n==`function`}export{O as transferAssetFactory};
|
|
2
2
|
//# sourceMappingURL=transfer-asset.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer-asset.js","names":[],"sources":["../../../../src/transfer-service/markr/_handlers/transfer-asset.ts"],"sourcesContent":["import { encodeFunctionData, erc20Abi, isAddress } from 'viem';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { ServiceType, TransferSignatureReason } from '../../../constants';\nimport type { Environment } from '../../../constants';\nimport { ErrorCode, ErrorReason, SdkError } from '../../../errors';\nimport type { TransferService } from '../../../types/service';\nimport type { EvmSigner, EvmTransactionRequest, SolanaSigner } from '../../../types/signer';\nimport type { Transfer, TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport {\n applyFeeUnitsBpsMargin,\n getEvmClientForChain,\n getSolanaRpcForChain,\n makeFailedTransferFromQuote,\n} from '../../_utils';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n isTokenAddressNative,\n} from '../_utils';\nimport { isEvmSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { SOLANA_REQUIRED_CONFIRMATIONS } from '../constants';\nimport { _estimateGasFromSwapResponse } from './estimate-native-fee';\nimport type { Caip2ChainId } from '../../../types/caip';\nimport { refreshSolanaSwapTransactionBlockhash } from '../_solana-utils';\n\nexport interface TransferAssetFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n solanaSigner?: SolanaSigner;\n}\n\nexport function transferAssetFactory({\n apiOptions,\n appId,\n environment,\n evmSigner,\n solanaSigner,\n}: TransferAssetFactoryConfig): TransferService['transferAsset'] {\n return async ({ quote, gasSettings, fallbackToDefaultOnBatchFailure, onStepChange }) => {\n if (quote.serviceType !== ServiceType.MARKR) {\n throw new SdkError(ErrorReason.INCORRECT_PROVIDER_PROVIDED, ErrorCode.INVALID_PARAMS);\n }\n\n const now = Math.floor(Date.now() / 1_000);\n\n if (quote.expiresAt <= now) {\n throw new SdkError(ErrorReason.QUOTE_EXPIRED, ErrorCode.INVALID_PARAMS);\n }\n\n const sourceChainId = quote.sourceChain.chainId;\n\n if (isSolanaNamespace(sourceChainId)) {\n return _executeSvmTransfer({ apiOptions, appId, environment, solanaSigner, quote, onStepChange });\n }\n\n if (isEvmNamespace(sourceChainId)) {\n return _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n });\n }\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Unsupported source chain namespace: ${sourceChainId}`,\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// EVM transfer path\n// ---------------------------------------------------------------------------\n\ninterface EvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n gasSettings?: Parameters<TransferService['transferAsset']>[0]['gasSettings'];\n fallbackToDefaultOnBatchFailure?: Parameters<TransferService['transferAsset']>[0]['fallbackToDefaultOnBatchFailure'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n}: EvmTransferParams): Promise<Transfer> {\n const fromAddress = quote.fromAddress;\n\n if (!isAddress(fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid EVM address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n if (!isAddress(tokenInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'assetIn address is not a valid EVM address.',\n });\n }\n\n const tokenInAddress = tokenInAddressString;\n const isTokenInNative = isTokenAddressNative(tokenInAddress);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n if (!isTokenInNative && !spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${quote.sourceChain.chainId}.`,\n });\n }\n\n let requiresApprovalSignature = false;\n let approvalRequest: EvmTransactionRequest | undefined;\n\n if (!isTokenInNative && spenderAddress) {\n const allowance = await sourceClient.readContract({\n address: tokenInAddress,\n abi: erc20Abi,\n functionName: 'allowance',\n args: [fromAddress, spenderAddress],\n });\n\n if (allowance < allowanceAmount) {\n requiresApprovalSignature = true;\n\n const approvalData = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, allowanceAmount],\n });\n\n let approvalGasWithMargin: bigint | undefined;\n\n try {\n const approvalGasEstimate = await sourceClient.estimateGas({\n account: fromAddress,\n to: tokenInAddress,\n data: approvalData,\n value: 0n,\n });\n\n approvalGasWithMargin = applyFeeUnitsBpsMargin(approvalGasEstimate, gasSettings?.estimateGasMarginBps);\n } catch (err) {\n throw new SdkError('Error during gas estimation', ErrorCode.VIEM_ERROR, {\n cause: err,\n details: 'Failed to estimate gas for ERC20 approval transaction.',\n });\n }\n\n approvalRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: approvalData,\n from: fromAddress,\n gas: approvalGasWithMargin,\n to: tokenInAddress,\n value: 0n,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n }\n }\n\n const maybeOneClickBatch = isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch: evmSigner.signBatch,\n sourceChainId: quote.sourceChain.chainId,\n targetChainId: quote.targetChain.chainId,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.',\n });\n }\n\n const makePendingTransfer = (txHash: `0x${string}`, startedAtMs: number = Date.now()): Transfer => {\n const isSameChainTransfer = quote.sourceChain.chainId === quote.targetChain.chainId;\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isSameChainTransfer ? 1 : 2,\n startedAtMs,\n txHash,\n },\n };\n };\n\n if (maybeOneClickBatch && approvalRequest) {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n const signBatch = evmSigner.signBatch;\n\n if (!signBatch) {\n throw new SdkError('One-click batch signer is not available.', ErrorCode.SIGNING_FAILED);\n }\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n // Gas is purposely left undefined here.\n // We can't estimate the gas because we aren't executing the\n // approval tx. It's up to the wallet to correctly handle gas estimation.\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n\n onStepChange?.(batchStep);\n\n try {\n const txHashes = await signBatch(\n [approvalRequest, swapRequest],\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n\n const swapTxHash = txHashes.at(-1);\n\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n\n return makePendingTransfer(swapTxHash);\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n }\n }\n\n if (requiresApprovalSignature && approvalRequest) {\n const approvalStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote,\n requiredSignatures: 2,\n };\n\n onStepChange?.(approvalStep);\n\n const approvalTxHash = await evmSigner.sign(\n approvalRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n approvalStep,\n );\n\n const approvalReceipt = await sourceClient.waitForTransactionReceipt({ hash: approvalTxHash });\n\n if (approvalReceipt.status === 'reverted') {\n return makeFailedTransferFromQuote(quote, {\n environment,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'ERC20 approval transaction was reverted',\n });\n }\n }\n\n const swapGasWithMargin = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress,\n feeUnitsMarginBps: gasSettings?.estimateGasMarginBps,\n sourceClient,\n swap,\n });\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n gas: swapGasWithMargin,\n to: swap.to,\n value: swap.value,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n\n const step: TransferStepDetails = {\n currentSignature: requiresApprovalSignature ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: requiresApprovalSignature ? 2 : 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await evmSigner.sign(\n swapRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return makePendingTransfer(txHash, startedAtMs);\n}\n\n// ---------------------------------------------------------------------------\n// SVM (Solana) transfer path\n// ---------------------------------------------------------------------------\n\ninterface SvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n solanaSigner?: SolanaSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeSvmTransfer({\n apiOptions,\n appId,\n environment,\n solanaSigner,\n quote,\n onStepChange,\n}: SvmTransferParams): Promise<Transfer> {\n if (!solanaSigner) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'solanaSigner is required for Solana transfers but was not provided.',\n });\n }\n\n if (!isSolAddress(quote.fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid Solana address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.',\n });\n }\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Original swap transaction (base64):', swap.swapTransaction);\n\n const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Refreshed swap transaction with new blockhash (base64):', swapTransactionBase64);\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await solanaSigner.signAndSend(\n {\n account: quote.fromAddress,\n serializedTx: swapTransactionBase64,\n },\n step,\n );\n\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isCrossChainSwap ? 2 : SOLANA_REQUIRED_CONFIRMATIONS,\n startedAtMs,\n txHash,\n },\n };\n}\n\n/**\n * Determines whether one-click swap eligibility criteria is met.\n *\n * Only same-chain EVM swaps are currently eligible.\n */\nfunction isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch,\n sourceChainId,\n targetChainId,\n}: {\n approvalRequest?: EvmTransactionRequest;\n requiresApprovalSignature: boolean;\n signBatch?: EvmSigner['signBatch'];\n sourceChainId: Caip2ChainId;\n targetChainId: Caip2ChainId;\n}): boolean {\n return (\n isEvmNamespace(sourceChainId) &&\n isEvmNamespace(targetChainId) &&\n sourceChainId === targetChainId &&\n requiresApprovalSignature &&\n approvalRequest !== undefined &&\n typeof signBatch === 'function'\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transfer-asset.js","names":[],"sources":["../../../../src/transfer-service/markr/_handlers/transfer-asset.ts"],"sourcesContent":["import { encodeFunctionData, erc20Abi, isAddress } from 'viem';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { ServiceType, TransferSignatureReason } from '../../../constants';\nimport type { Environment } from '../../../constants';\nimport { ErrorCode, ErrorReason, SdkError } from '../../../errors';\nimport type { TransferService } from '../../../types/service';\nimport type { EvmSigner, EvmTransactionRequest, SolanaSigner } from '../../../types/signer';\nimport type { Transfer, TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport {\n applyFeeUnitsBpsMargin,\n getEvmClientForChain,\n getSolanaRpcForChain,\n makeFailedTransferFromQuote,\n} from '../../_utils';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n isTokenAddressNative,\n} from '../_utils';\nimport { isEvmSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { SOLANA_REQUIRED_CONFIRMATIONS } from '../constants';\nimport { _estimateGasFromSwapResponse } from './estimate-native-fee';\nimport type { Caip2ChainId } from '../../../types/caip';\nimport { refreshSolanaSwapTransactionBlockhash } from '../../../utils/solana';\n\nexport interface TransferAssetFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n solanaSigner?: SolanaSigner;\n}\n\nexport function transferAssetFactory({\n apiOptions,\n appId,\n environment,\n evmSigner,\n solanaSigner,\n}: TransferAssetFactoryConfig): TransferService['transferAsset'] {\n return async ({ quote, gasSettings, fallbackToDefaultOnBatchFailure, onStepChange }) => {\n if (quote.serviceType !== ServiceType.MARKR) {\n throw new SdkError(ErrorReason.INCORRECT_PROVIDER_PROVIDED, ErrorCode.INVALID_PARAMS);\n }\n\n const now = Math.floor(Date.now() / 1_000);\n\n if (quote.expiresAt <= now) {\n throw new SdkError(ErrorReason.QUOTE_EXPIRED, ErrorCode.INVALID_PARAMS);\n }\n\n const sourceChainId = quote.sourceChain.chainId;\n\n if (isSolanaNamespace(sourceChainId)) {\n return _executeSvmTransfer({ apiOptions, appId, environment, solanaSigner, quote, onStepChange });\n }\n\n if (isEvmNamespace(sourceChainId)) {\n return _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n });\n }\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Unsupported source chain namespace: ${sourceChainId}`,\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// EVM transfer path\n// ---------------------------------------------------------------------------\n\ninterface EvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n gasSettings?: Parameters<TransferService['transferAsset']>[0]['gasSettings'];\n fallbackToDefaultOnBatchFailure?: Parameters<TransferService['transferAsset']>[0]['fallbackToDefaultOnBatchFailure'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n}: EvmTransferParams): Promise<Transfer> {\n const fromAddress = quote.fromAddress;\n\n if (!isAddress(fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid EVM address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n if (!isAddress(tokenInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'assetIn address is not a valid EVM address.',\n });\n }\n\n const tokenInAddress = tokenInAddressString;\n const isTokenInNative = isTokenAddressNative(tokenInAddress);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n if (!isTokenInNative && !spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${quote.sourceChain.chainId}.`,\n });\n }\n\n let requiresApprovalSignature = false;\n let approvalRequest: EvmTransactionRequest | undefined;\n\n if (!isTokenInNative && spenderAddress) {\n const allowance = await sourceClient.readContract({\n address: tokenInAddress,\n abi: erc20Abi,\n functionName: 'allowance',\n args: [fromAddress, spenderAddress],\n });\n\n if (allowance < allowanceAmount) {\n requiresApprovalSignature = true;\n\n const approvalData = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, allowanceAmount],\n });\n\n const approvalGasEstimate = await estimateGasWithRevert(\n sourceClient,\n {\n account: fromAddress,\n to: tokenInAddress,\n data: approvalData,\n },\n erc20Abi,\n 'Failed to estimate gas for ERC20 approval transaction.',\n );\n\n const approvalGasWithMargin = applyFeeUnitsBpsMargin(approvalGasEstimate, gasSettings?.estimateGasMarginBps);\n\n approvalRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: approvalData,\n from: fromAddress,\n gas: approvalGasWithMargin,\n to: tokenInAddress,\n value: 0n,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n }\n }\n\n const maybeOneClickBatch = isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch: evmSigner.signBatch,\n sourceChainId: quote.sourceChain.chainId,\n targetChainId: quote.targetChain.chainId,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.',\n });\n }\n\n const makePendingTransfer = (txHash: `0x${string}`, startedAtMs: number = Date.now()): Transfer => {\n const isSameChainTransfer = quote.sourceChain.chainId === quote.targetChain.chainId;\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isSameChainTransfer ? 1 : 2,\n startedAtMs,\n txHash,\n },\n };\n };\n\n if (maybeOneClickBatch && approvalRequest) {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n const signBatch = evmSigner.signBatch;\n\n if (!signBatch) {\n throw new SdkError('One-click batch signer is not available.', ErrorCode.SIGNING_FAILED);\n }\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n // Gas is purposely left undefined here.\n // We can't estimate the gas because we aren't executing the\n // approval tx. It's up to the wallet to correctly handle gas estimation.\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n\n onStepChange?.(batchStep);\n\n try {\n const txHashes = await signBatch(\n [approvalRequest, swapRequest],\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n\n const swapTxHash = txHashes.at(-1);\n\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n\n return makePendingTransfer(swapTxHash);\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n }\n }\n\n if (requiresApprovalSignature && approvalRequest) {\n const approvalStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote,\n requiredSignatures: 2,\n };\n\n onStepChange?.(approvalStep);\n\n const approvalTxHash = await evmSigner.sign(\n approvalRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n approvalStep,\n );\n\n const approvalReceipt = await sourceClient.waitForTransactionReceipt({ hash: approvalTxHash });\n\n if (approvalReceipt.status === 'reverted') {\n return makeFailedTransferFromQuote(quote, {\n environment,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'ERC20 approval transaction was reverted',\n });\n }\n }\n\n const swapGasWithMargin = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress,\n feeUnitsMarginBps: gasSettings?.estimateGasMarginBps,\n sourceClient,\n swap,\n });\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n gas: swapGasWithMargin,\n to: swap.to,\n value: swap.value,\n ...(gasSettings?.maxFeePerGas !== undefined\n ? {\n maxFeePerGas: gasSettings.maxFeePerGas,\n maxPriorityFeePerGas: gasSettings.maxPriorityFeePerGas,\n }\n : null),\n };\n\n const step: TransferStepDetails = {\n currentSignature: requiresApprovalSignature ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: requiresApprovalSignature ? 2 : 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await evmSigner.sign(\n swapRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return makePendingTransfer(txHash, startedAtMs);\n}\n\n// ---------------------------------------------------------------------------\n// SVM (Solana) transfer path\n// ---------------------------------------------------------------------------\n\ninterface SvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n solanaSigner?: SolanaSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeSvmTransfer({\n apiOptions,\n appId,\n environment,\n solanaSigner,\n quote,\n onStepChange,\n}: SvmTransferParams): Promise<Transfer> {\n if (!solanaSigner) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'solanaSigner is required for Solana transfers but was not provided.',\n });\n }\n\n if (!isSolAddress(quote.fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid Solana address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.',\n });\n }\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Original swap transaction (base64):', swap.swapTransaction);\n\n const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Refreshed swap transaction with new blockhash (base64):', swapTransactionBase64);\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await solanaSigner.signAndSend(\n {\n account: quote.fromAddress,\n serializedTx: swapTransactionBase64,\n },\n step,\n );\n\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isCrossChainSwap ? 2 : SOLANA_REQUIRED_CONFIRMATIONS,\n startedAtMs,\n txHash,\n },\n };\n}\n\n/**\n * Determines whether one-click swap eligibility criteria is met.\n *\n * Only same-chain EVM swaps are currently eligible.\n */\nfunction isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch,\n sourceChainId,\n targetChainId,\n}: {\n approvalRequest?: EvmTransactionRequest;\n requiresApprovalSignature: boolean;\n signBatch?: EvmSigner['signBatch'];\n sourceChainId: Caip2ChainId;\n targetChainId: Caip2ChainId;\n}): boolean {\n return (\n isEvmNamespace(sourceChainId) &&\n isEvmNamespace(targetChainId) &&\n sourceChainId === targetChainId &&\n requiresApprovalSignature &&\n approvalRequest !== undefined &&\n typeof signBatch === 'function'\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../constants.cjs`),t=require(`../../errors.cjs`),n=require(`../../utils/caip.cjs`),r=require(`../../_utils/chain.cjs`),i=require(`../../utils/evm-address.cjs`),a=require(`../../_utils/math.cjs`),o=require(`./_api.cjs`),s=require(`../../utils/sol-address.cjs`);let c=require(`viem`);function l(e,t,n){let r=e.get(t),i=e.get(n);return!r||!i?!1:t===n?r.swapEnabled:r.crossChainSwapEnabled&&r.crossChainTargetChainIds.has(n)}async function u(e,r=!1){let i=new Map;try{let t=(await o.markrGetInfoChains(e)).filter(e=>e.chainType===`evm`||e.chainType===`svm`);for(let e of t){let t=typeof e.chainId==`number`?n.eip155ChainIdToCaip2(e.chainId):e.chainId,a=e.enabled_services.includes(`cross-chain-quote`)&&e.enabled_services.includes(`cross-chain-swap`),o=e.enabled_services.includes(`quote`)&&e.enabled_services.includes(`swap`),s=new Set;for(let r of e.lanes){let e=typeof r==`number`?n.eip155ChainIdToCaip2(r):r;e!==t&&s.add(e)}let c=r?!1:a,l=c?s:new Set;!o&&l.size===0||i.set(t,{chainId:e.chainId,crossChainSwapEnabled:c,crossChainTargetChainIds:l,swapEnabled:o,tokenList:e.enabled_services.includes(`token-list`)})}}catch(e){throw new t.SdkError(t.ErrorReason.UNKNOWN,t.ErrorCode.INITIALIZATION_FAILED,{cause:e,details:`Failed to fetch supported chains from Markr API.`})}return i}async function d(e,t){let n=new Map;for(let[r,i]of t.entries())if(typeof i.chainId==`number`&&i.tokenList&&(i.crossChainSwapEnabled||i.swapEnabled))try{let t=o.markrGetTokenList(e,i.chainId);n.set(r,t)}catch{}return n}function f(
|
|
1
|
+
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../constants.cjs`),t=require(`../../errors.cjs`),n=require(`../../utils/caip.cjs`),r=require(`../../_utils/chain.cjs`),i=require(`../../utils/evm-address.cjs`),a=require(`../../_utils/math.cjs`),o=require(`./_api.cjs`),s=require(`../../utils/sol-address.cjs`);let c=require(`viem`);function l(e,t,n){let r=e.get(t),i=e.get(n);return!r||!i?!1:t===n?r.swapEnabled:r.crossChainSwapEnabled&&r.crossChainTargetChainIds.has(n)}async function u(e,r=!1){let i=new Map;try{let t=(await o.markrGetInfoChains(e)).filter(e=>e.chainType===`evm`||e.chainType===`svm`);for(let e of t){let t=typeof e.chainId==`number`?n.eip155ChainIdToCaip2(e.chainId):e.chainId,a=e.enabled_services.includes(`cross-chain-quote`)&&e.enabled_services.includes(`cross-chain-swap`),o=e.enabled_services.includes(`quote`)&&e.enabled_services.includes(`swap`),s=new Set;for(let r of e.lanes){let e=typeof r==`number`?n.eip155ChainIdToCaip2(r):r;e!==t&&s.add(e)}let c=r?!1:a,l=c?s:new Set;!o&&l.size===0||i.set(t,{chainId:e.chainId,crossChainSwapEnabled:c,crossChainTargetChainIds:l,swapEnabled:o,tokenList:e.enabled_services.includes(`token-list`)})}}catch(e){throw new t.SdkError(t.ErrorReason.UNKNOWN,t.ErrorCode.INITIALIZATION_FAILED,{cause:e,details:`Failed to fetch supported chains from Markr API.`})}return i}async function d(e,t){let n=new Map;for(let[r,i]of t.entries())if(typeof i.chainId==`number`&&i.tokenList&&(i.crossChainSwapEnabled||i.swapEnabled))try{let t=o.markrGetTokenList(e,i.chainId);n.set(r,t)}catch{}return n}function f(e){return e===`0x0000000000000000000000000000000000000000`||e===`11111111111111111111111111111111`}function p(t,n){return t.type===e.TokenType.NATIVE?r.isSolanaNamespace(n)?e.NATIVE_SOL_ADDRESS:e.ERC_ZERO_ADDRESS:t.address}function m({amountOut:e,assetOut:t,slippageBps:n}){let r=a.calculateMinimumAmountOut({amountOut:e,assetOut:t,slippageBps:n});return e>0n&&r===0n?1n:r}function h({assetIn:t,fees:n,sourceChain:r},i=3e3){return n.reduce((n,i)=>i.fundingModel!==`additive`||i.chainId!==r.chainId?n:t.type===e.TokenType.NATIVE?i.token.type===e.TokenType.NATIVE?n+i.amount:n:t.type===e.TokenType.ERC20?i.token.type===e.TokenType.ERC20&&(0,c.isAddressEqual)(i.token.address,t.address)?n+i.amount:n:i.token.type===e.TokenType.SPL&&i.token.address===t.address?n+i.amount:n,0n)*BigInt(1e4+i)/10000n}function g({fees:t,sourceChain:n}){return t.reduce((t,r)=>r.fundingModel!==`additive`||r.chainId!==n.chainId?t:r.token.type===e.TokenType.NATIVE?t+r.amount:t,0n)}function _(t,n,r){let i=t.amountOut*BigInt(r)/10000n,a=t.amountOut-i,o=[...y(t.fees),{type:`partner`,fundingModel:`included`,name:`Core Fee`,amount:i,chainId:n.targetChain.chainId,token:b(n.targetAsset)}];return{aggregator:{id:t.aggregator.id,logoUrl:t.aggregator.logo_url,name:t.aggregator.name},amountIn:t.amountIn,amountOut:a,assetIn:n.sourceAsset,assetOut:n.targetAsset,expiresAt:t.expiredAt,fees:o,fromAddress:n.fromAddress,gasEstimate:t.gasEstimate,id:t.uuid,partnerFeeBps:r,serviceType:e.ServiceType.MARKR,slippageBps:n.slippageBps??t.recommendedSlippage,sourceChain:n.sourceChain,targetChain:n.targetChain,toAddress:n.toAddress}}async function v(e){try{return(await o.markrGetPartnerInfo(e)).fee}catch(e){throw new t.SdkError(t.ErrorReason.UNKNOWN,t.ErrorCode.INITIALIZATION_FAILED,{cause:e,details:`Failed to fetch partner info from Markr API.`})}}function y(t){if(!t)return[];let r=[];for(let a of t){let t=typeof a.token.chainId==`number`?n.eip155ChainIdToCaip2(a.token.chainId):a.token.chainId,o;f(a.token.address)?o={type:e.TokenType.NATIVE}:i.isEvmAddress(a.token.address)?o={type:e.TokenType.ERC20,address:a.token.address}:s.isSolAddress(a.token.address)&&(o={type:e.TokenType.SPL,address:a.token.address}),o&&r.push({type:a.type,fundingModel:a.extra?`additive`:`included`,name:a.name,amount:a.amount,chainId:t,token:o})}return r}function b(t){return t.type===e.TokenType.NATIVE?{type:e.TokenType.NATIVE}:t.type===e.TokenType.SPL?{type:e.TokenType.SPL,address:t.address}:{type:e.TokenType.ERC20,address:t.address}}async function x(e){return e?(await Promise.resolve().then(()=>require(`./_abis/cross-chain-swap-wrapper-abi.cjs`))).MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI:(await Promise.resolve().then(()=>require(`./_abis/swap-wrapper-abi.cjs`))).MARKR_SWAP_WRAPPER_ABI}exports.assetToAddressString=p,exports.calculateMarkrMinimumAmountOut=m,exports.getAdditiveSourceAssetFeeAmount=h,exports.getAdditiveSourceNativeAssetFeeAmount=g,exports.getMarkrSwapWrapperAbi=x,exports.getPartnerFeeBps=v,exports.getSupportedChains=u,exports.getSupportedTokens=d,exports.isRouteSupported=l,exports.isTokenAddressNative=f,exports.quoteFromMarkrQuoteResponseData=_;
|
|
2
2
|
//# sourceMappingURL=_utils.cjs.map
|