@avalabs/fusion-sdk 0.10.0 → 0.11.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/dist/constants.cjs +1 -1
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +2 -2
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +1 -1
- package/dist/constants.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/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/avalanche-evm/_handlers/track-transfer.cjs.map +1 -1
- package/dist/transfer-service/avalanche-evm/_handlers/track-transfer.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/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/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/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/_solana-utils.cjs +1 -1
- package/dist/transfer-service/markr/_solana-utils.cjs.map +1 -1
- package/dist/transfer-service/markr/_solana-utils.js +1 -1
- package/dist/transfer-service/markr/_solana-utils.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/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/types/service.d.cts +6 -2
- package/dist/types/service.d.ts +6 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer-asset.cjs","names":["ServiceType","SdkError","ErrorReason","ErrorCode","isSolanaNamespace","isEvmNamespace","calculateMarkrMinimumAmountOut","getEvmClientForChain","assetToAddressString","isTokenAddressNative","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 { assetToAddressString, calculateMarkrMinimumAmountOut, isTokenAddressNative } 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\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 < quote.amountIn) {\n requiresApprovalSignature = true;\n\n const approvalData = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, quote.amountIn],\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 const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\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 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: 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.cjs","names":["ServiceType","SdkError","ErrorReason","ErrorCode","isSolanaNamespace","isEvmNamespace","calculateMarkrMinimumAmountOut","getEvmClientForChain","assetToAddressString","isTokenAddressNative","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 { assetToAddressString, calculateMarkrMinimumAmountOut, isTokenAddressNative } 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\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 < quote.amountIn) {\n requiresApprovalSignature = true;\n\n const approvalData = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, quote.amountIn],\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 const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\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 p,markrSwap as m}from"../_api.js";import{isSolAddress as h}from"../../../utils/sol-address.js";import{assetToAddressString as g,calculateMarkrMinimumAmountOut as _,isTokenAddressNative as v}from"../_utils.js";import{isEvmSwapResponse as y,isSolanaSwapResponse as b}from"../_type-guards.js";import{refreshSolanaSwapTransactionBlockhash as x}from"../_solana-utils.js";import{_estimateGasFromSwapResponse as S}from"./estimate-native-fee.js";import{SOLANA_REQUIRED_CONFIRMATIONS as C}from"../constants.js";import{encodeFunctionData as w,erc20Abi as T,isAddress as E}from"viem";function D({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 k({apiOptions:t,appId:a,environment:o,solanaSigner:u,quote:d,onStepChange:m});if(s(g))return O({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 O({apiOptions:s,appId:c,environment:d,evmSigner:h,quote:b,gasSettings:x,fallbackToDefaultOnBatchFailure:C,onStepChange:D}){let O=b.fromAddress;if(!E(O))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let k=_({amountOut:b.amountOut,assetOut:b.assetOut,slippageBps:b.slippageBps}),j=u({chain:b.sourceChain}),M=g(b.assetIn,b.sourceChain.chainId),N=g(b.assetOut,b.targetChain.chainId);if(!E(M))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address.`});let P=M,F=v(P),I=b.sourceChain.chainId.toLowerCase()!==b.targetChain.chainId.toLowerCase(),{address:L}=await p(s,{chainId:a(b.sourceChain.chainId),crossChainSwap:I,quoteId:b.id});if(!F&&!L)throw new i(r.CHAIN_NOT_SUPPORTED,n.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${b.sourceChain.chainId}.`});let R=!1,z;if(!F&&L&&await j.readContract({address:P,abi:T,functionName:`allowance`,args:[O,L]})<b.amountIn){R=!0;let e=w({abi:T,functionName:`approve`,args:[L,b.amountIn]}),t;try{t=l(await j.estimateGas({account:O,to:P,data:e,value:0n}),x?.estimateGasMarginBps)}catch(e){throw new i(`Error during gas estimation`,n.VIEM_ERROR,{cause:e,details:`Failed to estimate gas for ERC20 approval transaction.`})}z={chainId:o(b.sourceChain.chainId),data:e,from:O,gas:t,to:P,value:0n,...x?.maxFeePerGas===void 0?null:{maxFeePerGas:x.maxFeePerGas,maxPriorityFeePerGas:x.maxPriorityFeePerGas}}}let B=A({approvalRequest:z,requiresApprovalSignature:R,signBatch:h.signBatch,sourceChainId:b.sourceChain.chainId,targetChainId:b.targetChain.chainId}),V=await m(s,{amountIn:b.amountIn.toString(),appId:c,minAmountOut:k.toString(),tokenIn:M,tokenOut:N,uuid:b.id});if(!y(V))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 H=(t,n=Date.now())=>{let r=b.sourceChain.chainId===b.targetChain.chainId;return{amountIn:b.amountIn,amountOut:b.amountOut,environment:d,fees:b.fees,fromAddress:b.fromAddress,id:b.id,partnerFeeBps:b.partnerFeeBps,sourceAsset:b.assetIn,sourceChain:b.sourceChain,status:`source-pending`,targetAsset:b.assetOut,targetChain:b.targetChain,toAddress:b.toAddress,type:e.MARKR,source:{confirmationCount:0,requiredConfirmationCount:r?1:2,startedAtMs:n,txHash:t}}};if(B&&z){let e={currentSignature:1,currentSignatureReason:t.TokensTransfer,quote:b,requiredSignatures:1},r=h.signBatch;if(!r)throw new i(`One-click batch signer is not available.`,n.SIGNING_FAILED);let a={chainId:o(b.sourceChain.chainId),data:V.data,from:O,gas:void 0,to:V.to,value:V.value,...x?.maxFeePerGas===void 0?null:{maxFeePerGas:x.maxFeePerGas,maxPriorityFeePerGas:x.maxPriorityFeePerGas}};D?.(e);try{let t=(await r([z,a],async e=>j.sendRawTransaction({serializedTransaction:e}),e)).at(-1);if(!t)throw new i(`One-click batch signing returned no transaction hashes.`,n.SIGNING_FAILED);return H(t)}catch(e){if(!C)throw e}}if(R&&z){let e={currentSignature:1,currentSignatureReason:t.AllowanceApproval,quote:b,requiredSignatures:2};D?.(e);let r=await h.sign(z,async e=>j.sendRawTransaction({serializedTransaction:e}),e);if((await j.waitForTransactionReceipt({hash:r})).status===`reverted`)return f(b,{environment:d,errorCode:n.TRANSACTION_REVERTED,errorReason:`ERC20 approval transaction was reverted`})}let U=await S({crossChain:I,fromAddress:O,feeUnitsMarginBps:x?.estimateGasMarginBps,sourceClient:j,swap:V}),W={chainId:o(b.sourceChain.chainId),data:V.data,from:O,gas:U,to:V.to,value:V.value,...x?.maxFeePerGas===void 0?null:{maxFeePerGas:x.maxFeePerGas,maxPriorityFeePerGas:x.maxPriorityFeePerGas}},G={currentSignature:R?2:1,currentSignatureReason:t.TokensTransfer,quote:b,requiredSignatures:R?2:1};D?.(G);let K=Date.now();return H(await h.sign(W,async e=>j.sendRawTransaction({serializedTransaction:e}),G),K)}async function k({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(!h(l.fromAddress))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`fromAddress is not a valid Solana address.`});let f=_({amountOut:l.amountOut,assetOut:l.assetOut,slippageBps:l.slippageBps}),p=g(l.assetIn,l.sourceChain.chainId),v=g(l.assetOut,l.targetChain.chainId),y=await m(a,{amountIn:l.amountIn.toString(),appId:o,minAmountOut:f.toString(),tokenIn:p,tokenOut:v,userPublicKey:l.fromAddress,uuid:l.id});if(!b(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.`});let S=await x(y.swapTransaction,d({chain:l.sourceChain})),w={currentSignature:1,currentSignatureReason:t.TokensTransfer,quote:l,requiredSignatures:1};u?.(w);let T=Date.now(),E=await c.signAndSend({account:l.fromAddress,serializedTx:S},w);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:C,startedAtMs:T,txHash:E}}}function A({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{D as transferAssetFactory};
|
|
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 p,markrSwap as m}from"../_api.js";import{isSolAddress as h}from"../../../utils/sol-address.js";import{assetToAddressString as g,calculateMarkrMinimumAmountOut as _,isTokenAddressNative as v}from"../_utils.js";import{isEvmSwapResponse as y,isSolanaSwapResponse as b}from"../_type-guards.js";import{refreshSolanaSwapTransactionBlockhash as x}from"../_solana-utils.js";import{_estimateGasFromSwapResponse as S}from"./estimate-native-fee.js";import{SOLANA_REQUIRED_CONFIRMATIONS as C}from"../constants.js";import{encodeFunctionData as w,erc20Abi as T,isAddress as E}from"viem";function D({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 k({apiOptions:t,appId:a,environment:o,solanaSigner:u,quote:d,onStepChange:m});if(s(g))return O({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 O({apiOptions:s,appId:c,environment:d,evmSigner:h,quote:b,gasSettings:x,fallbackToDefaultOnBatchFailure:C,onStepChange:D}){let O=b.fromAddress;if(!E(O))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let k=_({amountOut:b.amountOut,assetOut:b.assetOut,slippageBps:b.slippageBps}),j=u({chain:b.sourceChain}),M=g(b.assetIn,b.sourceChain.chainId),N=g(b.assetOut,b.targetChain.chainId);if(!E(M))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address.`});let P=M,F=v(P),I=b.sourceChain.chainId.toLowerCase()!==b.targetChain.chainId.toLowerCase(),{address:L}=await p(s,{chainId:a(b.sourceChain.chainId),crossChainSwap:I,quoteId:b.id});if(!F&&!L)throw new i(r.CHAIN_NOT_SUPPORTED,n.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${b.sourceChain.chainId}.`});let R=!1,z;if(!F&&L&&await j.readContract({address:P,abi:T,functionName:`allowance`,args:[O,L]})<b.amountIn){R=!0;let e=w({abi:T,functionName:`approve`,args:[L,b.amountIn]}),t;try{t=l(await j.estimateGas({account:O,to:P,data:e,value:0n}),x?.estimateGasMarginBps)}catch(e){throw new i(`Error during gas estimation`,n.VIEM_ERROR,{cause:e,details:`Failed to estimate gas for ERC20 approval transaction.`})}z={chainId:o(b.sourceChain.chainId),data:e,from:O,gas:t,to:P,value:0n,...x?.maxFeePerGas===void 0?null:{maxFeePerGas:x.maxFeePerGas,maxPriorityFeePerGas:x.maxPriorityFeePerGas}}}let B=A({approvalRequest:z,requiresApprovalSignature:R,signBatch:h.signBatch,sourceChainId:b.sourceChain.chainId,targetChainId:b.targetChain.chainId}),V=await m(s,{amountIn:b.amountIn.toString(),appId:c,minAmountOut:k.toString(),tokenIn:M,tokenOut:N,uuid:b.id});if(!y(V))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 H=(t,n=Date.now())=>{let r=b.sourceChain.chainId===b.targetChain.chainId;return{amountIn:b.amountIn,amountOut:b.amountOut,environment:d,fees:b.fees,fromAddress:b.fromAddress,id:b.id,partnerFeeBps:b.partnerFeeBps,sourceAsset:b.assetIn,sourceChain:b.sourceChain,status:`source-pending`,targetAsset:b.assetOut,targetChain:b.targetChain,toAddress:b.toAddress,type:e.MARKR,source:{confirmationCount:0,requiredConfirmationCount:r?1:2,startedAtMs:n,txHash:t}}};if(B&&z){let e={currentSignature:1,currentSignatureReason:t.TokensTransfer,quote:b,requiredSignatures:1},r=h.signBatch;if(!r)throw new i(`One-click batch signer is not available.`,n.SIGNING_FAILED);let a={chainId:o(b.sourceChain.chainId),data:V.data,from:O,gas:void 0,to:V.to,value:V.value,...x?.maxFeePerGas===void 0?null:{maxFeePerGas:x.maxFeePerGas,maxPriorityFeePerGas:x.maxPriorityFeePerGas}};D?.(e);try{let t=(await r([z,a],async e=>j.sendRawTransaction({serializedTransaction:e}),e)).at(-1);if(!t)throw new i(`One-click batch signing returned no transaction hashes.`,n.SIGNING_FAILED);return H(t)}catch(e){if(!C)throw e}}if(R&&z){let e={currentSignature:1,currentSignatureReason:t.AllowanceApproval,quote:b,requiredSignatures:2};D?.(e);let r=await h.sign(z,async e=>j.sendRawTransaction({serializedTransaction:e}),e);if((await j.waitForTransactionReceipt({hash:r})).status===`reverted`)return f(b,{environment:d,errorCode:n.TRANSACTION_REVERTED,errorReason:`ERC20 approval transaction was reverted`})}let U=await S({crossChain:I,fromAddress:O,feeUnitsMarginBps:x?.estimateGasMarginBps,sourceClient:j,swap:V}),W={chainId:o(b.sourceChain.chainId),data:V.data,from:O,gas:U,to:V.to,value:V.value,...x?.maxFeePerGas===void 0?null:{maxFeePerGas:x.maxFeePerGas,maxPriorityFeePerGas:x.maxPriorityFeePerGas}},G={currentSignature:R?2:1,currentSignatureReason:t.TokensTransfer,quote:b,requiredSignatures:R?2:1};D?.(G);let K=Date.now();return H(await h.sign(W,async e=>j.sendRawTransaction({serializedTransaction:e}),G),K)}async function k({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(!h(l.fromAddress))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`fromAddress is not a valid Solana address.`});let f=_({amountOut:l.amountOut,assetOut:l.assetOut,slippageBps:l.slippageBps}),p=g(l.assetIn,l.sourceChain.chainId),v=g(l.assetOut,l.targetChain.chainId),y=await m(a,{amountIn:l.amountIn.toString(),appId:o,minAmountOut:f.toString(),tokenIn:p,tokenOut:v,userPublicKey:l.fromAddress,uuid:l.id});if(!b(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.`});let S=await x(y.swapTransaction,d({chain:l.sourceChain})),w={currentSignature:1,currentSignatureReason:t.TokensTransfer,quote:l,requiredSignatures:1};u?.(w);let T=Date.now(),E=await c.signAndSend({account:l.fromAddress,serializedTx:S},w),D=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:D?2:C,startedAtMs:T,txHash:E}}}function A({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{D 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 { assetToAddressString, calculateMarkrMinimumAmountOut, isTokenAddressNative } 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\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 < quote.amountIn) {\n requiresApprovalSignature = true;\n\n const approvalData = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, quote.amountIn],\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 const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\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 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: 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 { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport { assetToAddressString, calculateMarkrMinimumAmountOut, isTokenAddressNative } 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\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 < quote.amountIn) {\n requiresApprovalSignature = true;\n\n const approvalData = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, quote.amountIn],\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 const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\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(`../../errors.cjs`);let t=require(`zod`)
|
|
1
|
+
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../errors.cjs`);let t=require(`zod`);require(`viem`);let n=require(`@solana/kit`);const r=t.z.base64();function i(t){if(!r.safeParse(t).success)throw new e.InvalidParamsError(`Not a valid base64 string`,`Expected a base64-encoded Solana Transaction string.`);let i=Uint8Array.from(atob(t),e=>e.charCodeAt(0)),a;try{a=(0,n.getTransactionDecoder)().decode(i)}catch(t){throw new e.SdkError(`Failed to decode transaction.`,e.ErrorCode.SOLANA_ERROR,{cause:t})}return a}async function a(e,t){return await(0,n.decompileTransactionMessageFetchingLookupTables)((0,n.getCompiledTransactionMessageDecoder)().decode(e.messageBytes),t)}async function o(e,t){let r=i(e),[o,s]=await Promise.all([a(r,t),t.getLatestBlockhash().send()]);return(0,n.getBase64EncodedWireTransaction)((0,n.compileTransaction)((0,n.setTransactionMessageLifetimeUsingBlockhash)(s.value,o)))}exports.decodeSolanaTransactionBase64=i,exports.refreshSolanaSwapTransactionBlockhash=o;
|
|
2
2
|
//# sourceMappingURL=_solana-utils.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_solana-utils.cjs","names":["z","InvalidParamsError","SdkError","ErrorCode"],"sources":["../../../src/transfer-service/markr/_solana-utils.ts"],"sourcesContent":["import {\n compileTransaction,\n decompileTransactionMessageFetchingLookupTables,\n getBase64EncodedWireTransaction,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n setTransactionMessageLifetimeUsingBlockhash,\n type Base64EncodedWireTransaction,\n type Rpc,\n type SolanaRpcApi,\n type Transaction,\n} from '@solana/kit';\nimport { z } from 'zod';\nimport { ErrorCode, InvalidParamsError, SdkError } from '../../errors';\n\nconst SolanaSwapTransactionBase64Schema = z.base64();\n\n/**\n * Decodes a base64-encoded serialized Solana transaction.\n *\n * Validates that the input is base64 before attempting to deserialize.\n * Throws SDK errors with stable codes so callers can map failures.\n */\nexport function decodeSolanaTransactionBase64(swapTransactionBase64: string): Transaction {\n const parsedBase64 = SolanaSwapTransactionBase64Schema.safeParse(swapTransactionBase64);\n\n if (!parsedBase64.success) {\n throw new InvalidParamsError('Not a valid base64 string', 'Expected a base64-encoded Solana Transaction string.');\n }\n\n const txBytes = Uint8Array.from(atob(swapTransactionBase64), (character) => character.charCodeAt(0));\n\n let tx: Transaction;\n\n try {\n tx = getTransactionDecoder().decode(txBytes);\n } catch (error) {\n throw new SdkError('Failed to decode transaction.', ErrorCode.SOLANA_ERROR, { cause: error });\n }\n\n return tx;\n}\n\n/**\n * Decompiles a transaction message, resolving address lookup tables via RPC.\n *\n * This returns a message shape that can be mutated (for example, to refresh\n * blockhash lifetime) and recompiled into a new transaction.\n */\nexport async function getDecompiledMessageFromTransaction(\n tx: Transaction,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<ReturnType<typeof decompileTransactionMessageFetchingLookupTables>> {\n const compiledMessageWithLifetime = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return await decompileTransactionMessageFetchingLookupTables(compiledMessageWithLifetime, rpc);\n}\n\n/**\n * Refreshes a serialized Solana swap transaction to use the latest blockhash.\n *\n * The returned value is a base64-encoded serialized transaction suitable for\n * signing and broadcast.\n */\nexport async function refreshSolanaSwapTransactionBlockhash(\n swapTransactionBase64: string,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Base64EncodedWireTransaction> {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const [decompiledMessage, latestBlockhashResponse] = await Promise.all([\n getDecompiledMessageFromTransaction(tx, rpc),\n rpc.getLatestBlockhash().send(),\n ]);\n\n const refreshedTxMessage = setTransactionMessageLifetimeUsingBlockhash(\n latestBlockhashResponse.value,\n decompiledMessage,\n );\n\n const refreshedTx = compileTransaction(refreshedTxMessage);\n\n return getBase64EncodedWireTransaction(refreshedTx);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"_solana-utils.cjs","names":["z","InvalidParamsError","SdkError","ErrorCode"],"sources":["../../../src/transfer-service/markr/_solana-utils.ts"],"sourcesContent":["import {\n compileTransaction,\n decompileTransactionMessageFetchingLookupTables,\n getBase64EncodedWireTransaction,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n setTransactionMessageLifetimeUsingBlockhash,\n type Base64EncodedWireTransaction,\n type Rpc,\n type SolanaRpcApi,\n type Transaction,\n} from '@solana/kit';\nimport { bytesToHex, bytesToString } from 'viem';\nimport { z } from 'zod';\nimport { ErrorCode, InvalidParamsError, SdkError } from '../../errors';\n\nconst SolanaSwapTransactionBase64Schema = z.base64();\n\nexport interface DecodedSolanaInstructionDebug {\n index: number;\n programAddressIndex: number;\n programAddress: string | undefined;\n accountIndices: number[];\n accountAddresses: Array<string | undefined>;\n dataBase64: string;\n dataHex: string;\n}\n\nfunction _bytesToBase64(bytes: Uint8Array): string {\n return btoa(bytesToString(bytes));\n}\n\n/**\n * Decodes a base64-encoded serialized Solana transaction.\n *\n * Validates that the input is base64 before attempting to deserialize.\n * Throws SDK errors with stable codes so callers can map failures.\n */\nexport function decodeSolanaTransactionBase64(swapTransactionBase64: string): Transaction {\n const parsedBase64 = SolanaSwapTransactionBase64Schema.safeParse(swapTransactionBase64);\n\n if (!parsedBase64.success) {\n throw new InvalidParamsError('Not a valid base64 string', 'Expected a base64-encoded Solana Transaction string.');\n }\n\n const txBytes = Uint8Array.from(atob(swapTransactionBase64), (character) => character.charCodeAt(0));\n\n let tx: Transaction;\n\n try {\n tx = getTransactionDecoder().decode(txBytes);\n } catch (error) {\n throw new SdkError('Failed to decode transaction.', ErrorCode.SOLANA_ERROR, { cause: error });\n }\n\n return tx;\n}\n\n/**\n * Returns a normalized, readable instruction list from a base64 Solana transaction.\n *\n * This is intended for debugging and inspection. Account addresses are resolved\n * from the decoded message static account list when available.\n */\nexport function decodeSolanaInstructionListFromSwapTransactionBase64(\n swapTransactionBase64: string,\n): DecodedSolanaInstructionDebug[] {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const compiledMessage = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return compiledMessage.instructions.map((instruction, index) => {\n const accountIndices = instruction.accountIndices ? [...instruction.accountIndices] : [];\n const data = instruction.data ? new Uint8Array(instruction.data) : new Uint8Array();\n\n return {\n index,\n programAddressIndex: instruction.programAddressIndex,\n programAddress: compiledMessage.staticAccounts[instruction.programAddressIndex],\n accountIndices,\n accountAddresses: accountIndices.map((accountIndex) => compiledMessage.staticAccounts[accountIndex]),\n dataBase64: _bytesToBase64(data),\n dataHex: bytesToHex(data),\n };\n });\n}\n\n/**\n * Decompiles a transaction message, resolving address lookup tables via RPC.\n *\n * This returns a message shape that can be mutated (for example, to refresh\n * blockhash lifetime) and recompiled into a new transaction.\n */\nexport async function getDecompiledMessageFromTransaction(\n tx: Transaction,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<ReturnType<typeof decompileTransactionMessageFetchingLookupTables>> {\n const compiledMessageWithLifetime = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return await decompileTransactionMessageFetchingLookupTables(compiledMessageWithLifetime, rpc);\n}\n\n/**\n * Refreshes a serialized Solana swap transaction to use the latest blockhash.\n *\n * The returned value is a base64-encoded serialized transaction suitable for\n * signing and broadcast.\n */\nexport async function refreshSolanaSwapTransactionBlockhash(\n swapTransactionBase64: string,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Base64EncodedWireTransaction> {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const [decompiledMessage, latestBlockhashResponse] = await Promise.all([\n getDecompiledMessageFromTransaction(tx, rpc),\n rpc.getLatestBlockhash().send(),\n ]);\n\n const refreshedTxMessage = setTransactionMessageLifetimeUsingBlockhash(\n latestBlockhashResponse.value,\n decompiledMessage,\n );\n\n const refreshedTx = compileTransaction(refreshedTxMessage);\n\n return getBase64EncodedWireTransaction(refreshedTx);\n}\n"],"mappings":"sJAgBA,MAAM,EAAoCA,EAAAA,EAAE,QAAQ,CAsBpD,SAAgB,EAA8B,EAA4C,CAGxF,GAAI,CAFiB,EAAkC,UAAU,EAAsB,CAErE,QAChB,MAAM,IAAIC,EAAAA,mBAAmB,4BAA6B,uDAAuD,CAGnH,IAAM,EAAU,WAAW,KAAK,KAAK,EAAsB,CAAG,GAAc,EAAU,WAAW,EAAE,CAAC,CAEhG,EAEJ,GAAI,CACF,GAAA,EAAA,EAAA,wBAA4B,CAAC,OAAO,EAAQ,OACrC,EAAO,CACd,MAAM,IAAIC,EAAAA,SAAS,gCAAiCC,EAAAA,UAAU,aAAc,CAAE,MAAO,EAAO,CAAC,CAG/F,OAAO,EAqCT,eAAsB,EACpB,EACA,EAC6E,CAG7E,OAAO,MAAA,EAAA,EAAA,kDAAA,EAAA,EAAA,uCAFmE,CAAC,OAAO,EAAG,aAAa,CAER,EAAI,CAShG,eAAsB,EACpB,EACA,EACuC,CACvC,IAAM,EAAK,EAA8B,EAAsB,CACzD,CAAC,EAAmB,GAA2B,MAAM,QAAQ,IAAI,CACrE,EAAoC,EAAI,EAAI,CAC5C,EAAI,oBAAoB,CAAC,MAAM,CAChC,CAAC,CASF,OAAA,EAAA,EAAA,kCAAA,EAAA,EAAA,qBAAA,EAAA,EAAA,6CANE,EAAwB,MACxB,EACD,CAEyD,CAEP"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ErrorCode as e,InvalidParamsError as t,SdkError as n}from"../../errors.js";import{z as r}from"zod";import{compileTransaction as i,decompileTransactionMessageFetchingLookupTables as a,getBase64EncodedWireTransaction as o,getCompiledTransactionMessageDecoder as s,getTransactionDecoder as c,setTransactionMessageLifetimeUsingBlockhash as l}from"@solana/kit";const u=r.base64();function d(r){if(!u.safeParse(r).success)throw new t(`Not a valid base64 string`,`Expected a base64-encoded Solana Transaction string.`);let i=Uint8Array.from(atob(r),e=>e.charCodeAt(0)),a;try{a=c().decode(i)}catch(t){throw new n(`Failed to decode transaction.`,e.SOLANA_ERROR,{cause:t})}return a}async function f(e,t){return await a(s().decode(e.messageBytes),t)}async function p(e,t){let n=d(e),[r,a]=await Promise.all([f(n,t),t.getLatestBlockhash().send()]);return o(i(l(a.value,r)))}export{d as decodeSolanaTransactionBase64,p as refreshSolanaSwapTransactionBlockhash};
|
|
1
|
+
import{ErrorCode as e,InvalidParamsError as t,SdkError as n}from"../../errors.js";import{z as r}from"zod";import"viem";import{compileTransaction as i,decompileTransactionMessageFetchingLookupTables as a,getBase64EncodedWireTransaction as o,getCompiledTransactionMessageDecoder as s,getTransactionDecoder as c,setTransactionMessageLifetimeUsingBlockhash as l}from"@solana/kit";const u=r.base64();function d(r){if(!u.safeParse(r).success)throw new t(`Not a valid base64 string`,`Expected a base64-encoded Solana Transaction string.`);let i=Uint8Array.from(atob(r),e=>e.charCodeAt(0)),a;try{a=c().decode(i)}catch(t){throw new n(`Failed to decode transaction.`,e.SOLANA_ERROR,{cause:t})}return a}async function f(e,t){return await a(s().decode(e.messageBytes),t)}async function p(e,t){let n=d(e),[r,a]=await Promise.all([f(n,t),t.getLatestBlockhash().send()]);return o(i(l(a.value,r)))}export{d as decodeSolanaTransactionBase64,p as refreshSolanaSwapTransactionBlockhash};
|
|
2
2
|
//# sourceMappingURL=_solana-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_solana-utils.js","names":[],"sources":["../../../src/transfer-service/markr/_solana-utils.ts"],"sourcesContent":["import {\n compileTransaction,\n decompileTransactionMessageFetchingLookupTables,\n getBase64EncodedWireTransaction,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n setTransactionMessageLifetimeUsingBlockhash,\n type Base64EncodedWireTransaction,\n type Rpc,\n type SolanaRpcApi,\n type Transaction,\n} from '@solana/kit';\nimport { z } from 'zod';\nimport { ErrorCode, InvalidParamsError, SdkError } from '../../errors';\n\nconst SolanaSwapTransactionBase64Schema = z.base64();\n\n/**\n * Decodes a base64-encoded serialized Solana transaction.\n *\n * Validates that the input is base64 before attempting to deserialize.\n * Throws SDK errors with stable codes so callers can map failures.\n */\nexport function decodeSolanaTransactionBase64(swapTransactionBase64: string): Transaction {\n const parsedBase64 = SolanaSwapTransactionBase64Schema.safeParse(swapTransactionBase64);\n\n if (!parsedBase64.success) {\n throw new InvalidParamsError('Not a valid base64 string', 'Expected a base64-encoded Solana Transaction string.');\n }\n\n const txBytes = Uint8Array.from(atob(swapTransactionBase64), (character) => character.charCodeAt(0));\n\n let tx: Transaction;\n\n try {\n tx = getTransactionDecoder().decode(txBytes);\n } catch (error) {\n throw new SdkError('Failed to decode transaction.', ErrorCode.SOLANA_ERROR, { cause: error });\n }\n\n return tx;\n}\n\n/**\n * Decompiles a transaction message, resolving address lookup tables via RPC.\n *\n * This returns a message shape that can be mutated (for example, to refresh\n * blockhash lifetime) and recompiled into a new transaction.\n */\nexport async function getDecompiledMessageFromTransaction(\n tx: Transaction,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<ReturnType<typeof decompileTransactionMessageFetchingLookupTables>> {\n const compiledMessageWithLifetime = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return await decompileTransactionMessageFetchingLookupTables(compiledMessageWithLifetime, rpc);\n}\n\n/**\n * Refreshes a serialized Solana swap transaction to use the latest blockhash.\n *\n * The returned value is a base64-encoded serialized transaction suitable for\n * signing and broadcast.\n */\nexport async function refreshSolanaSwapTransactionBlockhash(\n swapTransactionBase64: string,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Base64EncodedWireTransaction> {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const [decompiledMessage, latestBlockhashResponse] = await Promise.all([\n getDecompiledMessageFromTransaction(tx, rpc),\n rpc.getLatestBlockhash().send(),\n ]);\n\n const refreshedTxMessage = setTransactionMessageLifetimeUsingBlockhash(\n latestBlockhashResponse.value,\n decompiledMessage,\n );\n\n const refreshedTx = compileTransaction(refreshedTxMessage);\n\n return getBase64EncodedWireTransaction(refreshedTx);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"_solana-utils.js","names":[],"sources":["../../../src/transfer-service/markr/_solana-utils.ts"],"sourcesContent":["import {\n compileTransaction,\n decompileTransactionMessageFetchingLookupTables,\n getBase64EncodedWireTransaction,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n setTransactionMessageLifetimeUsingBlockhash,\n type Base64EncodedWireTransaction,\n type Rpc,\n type SolanaRpcApi,\n type Transaction,\n} from '@solana/kit';\nimport { bytesToHex, bytesToString } from 'viem';\nimport { z } from 'zod';\nimport { ErrorCode, InvalidParamsError, SdkError } from '../../errors';\n\nconst SolanaSwapTransactionBase64Schema = z.base64();\n\nexport interface DecodedSolanaInstructionDebug {\n index: number;\n programAddressIndex: number;\n programAddress: string | undefined;\n accountIndices: number[];\n accountAddresses: Array<string | undefined>;\n dataBase64: string;\n dataHex: string;\n}\n\nfunction _bytesToBase64(bytes: Uint8Array): string {\n return btoa(bytesToString(bytes));\n}\n\n/**\n * Decodes a base64-encoded serialized Solana transaction.\n *\n * Validates that the input is base64 before attempting to deserialize.\n * Throws SDK errors with stable codes so callers can map failures.\n */\nexport function decodeSolanaTransactionBase64(swapTransactionBase64: string): Transaction {\n const parsedBase64 = SolanaSwapTransactionBase64Schema.safeParse(swapTransactionBase64);\n\n if (!parsedBase64.success) {\n throw new InvalidParamsError('Not a valid base64 string', 'Expected a base64-encoded Solana Transaction string.');\n }\n\n const txBytes = Uint8Array.from(atob(swapTransactionBase64), (character) => character.charCodeAt(0));\n\n let tx: Transaction;\n\n try {\n tx = getTransactionDecoder().decode(txBytes);\n } catch (error) {\n throw new SdkError('Failed to decode transaction.', ErrorCode.SOLANA_ERROR, { cause: error });\n }\n\n return tx;\n}\n\n/**\n * Returns a normalized, readable instruction list from a base64 Solana transaction.\n *\n * This is intended for debugging and inspection. Account addresses are resolved\n * from the decoded message static account list when available.\n */\nexport function decodeSolanaInstructionListFromSwapTransactionBase64(\n swapTransactionBase64: string,\n): DecodedSolanaInstructionDebug[] {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const compiledMessage = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return compiledMessage.instructions.map((instruction, index) => {\n const accountIndices = instruction.accountIndices ? [...instruction.accountIndices] : [];\n const data = instruction.data ? new Uint8Array(instruction.data) : new Uint8Array();\n\n return {\n index,\n programAddressIndex: instruction.programAddressIndex,\n programAddress: compiledMessage.staticAccounts[instruction.programAddressIndex],\n accountIndices,\n accountAddresses: accountIndices.map((accountIndex) => compiledMessage.staticAccounts[accountIndex]),\n dataBase64: _bytesToBase64(data),\n dataHex: bytesToHex(data),\n };\n });\n}\n\n/**\n * Decompiles a transaction message, resolving address lookup tables via RPC.\n *\n * This returns a message shape that can be mutated (for example, to refresh\n * blockhash lifetime) and recompiled into a new transaction.\n */\nexport async function getDecompiledMessageFromTransaction(\n tx: Transaction,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<ReturnType<typeof decompileTransactionMessageFetchingLookupTables>> {\n const compiledMessageWithLifetime = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return await decompileTransactionMessageFetchingLookupTables(compiledMessageWithLifetime, rpc);\n}\n\n/**\n * Refreshes a serialized Solana swap transaction to use the latest blockhash.\n *\n * The returned value is a base64-encoded serialized transaction suitable for\n * signing and broadcast.\n */\nexport async function refreshSolanaSwapTransactionBlockhash(\n swapTransactionBase64: string,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Base64EncodedWireTransaction> {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const [decompiledMessage, latestBlockhashResponse] = await Promise.all([\n getDecompiledMessageFromTransaction(tx, rpc),\n rpc.getLatestBlockhash().send(),\n ]);\n\n const refreshedTxMessage = setTransactionMessageLifetimeUsingBlockhash(\n latestBlockhashResponse.value,\n decompiledMessage,\n );\n\n const refreshedTx = compileTransaction(refreshedTxMessage);\n\n return getBase64EncodedWireTransaction(refreshedTx);\n}\n"],"mappings":"wXAgBA,MAAM,EAAoC,EAAE,QAAQ,CAsBpD,SAAgB,EAA8B,EAA4C,CAGxF,GAAI,CAFiB,EAAkC,UAAU,EAAsB,CAErE,QAChB,MAAM,IAAI,EAAmB,4BAA6B,uDAAuD,CAGnH,IAAM,EAAU,WAAW,KAAK,KAAK,EAAsB,CAAG,GAAc,EAAU,WAAW,EAAE,CAAC,CAEhG,EAEJ,GAAI,CACF,EAAK,GAAuB,CAAC,OAAO,EAAQ,OACrC,EAAO,CACd,MAAM,IAAI,EAAS,gCAAiC,EAAU,aAAc,CAAE,MAAO,EAAO,CAAC,CAG/F,OAAO,EAqCT,eAAsB,EACpB,EACA,EAC6E,CAG7E,OAAO,MAAM,EAFuB,GAAsC,CAAC,OAAO,EAAG,aAAa,CAER,EAAI,CAShG,eAAsB,EACpB,EACA,EACuC,CACvC,IAAM,EAAK,EAA8B,EAAsB,CACzD,CAAC,EAAmB,GAA2B,MAAM,QAAQ,IAAI,CACrE,EAAoC,EAAI,EAAI,CAC5C,EAAI,oBAAoB,CAAC,MAAM,CAChC,CAAC,CASF,OAAO,EAFa,EALO,EACzB,EAAwB,MACxB,EACD,CAEyD,CAEP"}
|
|
@@ -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(t){return t===e.ERC_ZERO_ADDRESS||t===e.
|
|
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(t){return t===e.ERC_ZERO_ADDRESS||t===e.NATIVE_SOL_ADDRESS}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(t,n,r){let i=t.amountOut*BigInt(r)/10000n,a=t.amountOut-i,o=[..._(t.fees),{type:`partner`,name:`Core Fee`,amount:i,chainId:n.targetChain.chainId,token:v(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 g(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 _(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,name:a.name,amount:a.amount,chainId:t,token:o})}return r}function v(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 y(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}function b(e){if(e instanceof c.BaseError){let t=e.data;if((0,c.isHex)(t))return t;let n;if(e.walk(e=>{let t=e.data;return!n&&(0,c.isHex)(t)&&(n=t),!1}),n)return n;let r=e.cause?.data;if((0,c.isHex)(r))return r}if(!e||typeof e!=`object`)return;let t=e;if((0,c.isHex)(t.data))return t.data;if((0,c.isHex)(t.error?.data))return t.error.data;if((0,c.isHex)(t.cause?.data))return t.cause.data;if((0,c.isHex)(t.response?.data))return t.response.data;if((0,c.isHex)(t.body?.error?.data))return t.body.error.data}function x(e,t){let n=b(t);if(!n)return null;try{let t=(0,c.decodeErrorResult)({abi:e,data:n}),r=t.args.length>0?`(${t.args.map(String).join(`, `)})`:`()`;return`${t.errorName}${r}`}catch{let t=n.slice(0,10).toLowerCase();for(let n of e)if(n.type===`error`&&(0,c.toFunctionSelector)(`${n.name}(${n.inputs.map(e=>e.type).join(`,`)})`).toLowerCase()===t)return`${n.name}()`}return null}exports.assetToAddressString=p,exports.calculateMarkrMinimumAmountOut=m,exports.decodeMarkrRevertError=x,exports.getMarkrSwapWrapperAbi=y,exports.getPartnerFeeBps=g,exports.getSupportedChains=u,exports.getSupportedTokens=d,exports.isRouteSupported=l,exports.isTokenAddressNative=f,exports.quoteFromMarkrQuoteResponseData=h;
|
|
2
2
|
//# sourceMappingURL=_utils.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_utils.cjs","names":["markrGetInfoChains","eip155ChainIdToCaip2","SdkError","ErrorReason","ErrorCode","markrGetTokenList","ERC_ZERO_ADDRESS","SOL_MINT_ADDRESS","TokenType","isSolanaNamespace","calculateMinimumAmountOut","ServiceType","markrGetPartnerInfo","isEvmAddress","isSolAddress","BaseError"],"sources":["../../../src/transfer-service/markr/_utils.ts"],"sourcesContent":["import { ErrorCode, ErrorReason, SdkError } from '../../errors';\nimport { BaseError, decodeErrorResult, type Hex, isHex, toFunctionSelector } from 'viem';\nimport {\n type QuoteResponseData,\n type SupportedChainsResponseItemEvm,\n type SupportedChainsResponseItemSvm,\n type TokenListResponse,\n} from './_schema';\nimport { ERC_ZERO_ADDRESS, SOL_MINT_ADDRESS, ServiceType, TokenType } from '../../constants';\nimport { isSolanaNamespace } from '../../_utils/chain';\nimport { calculateMinimumAmountOut } from '../../_utils/math';\nimport { eip155ChainIdToCaip2 } from '../../utils/caip';\nimport type { Asset } from '../../types/asset';\nimport type { Caip2ChainId } from '../../types/caip';\nimport type { Quote, QuoteFee, QuoteFees, QuoteFeeToken, QuoterProps } from '../../types/quote';\nimport { markrGetInfoChains, markrGetPartnerInfo, markrGetTokenList, type ApiOptions } from './_api';\nimport { isEvmAddress } from '../../utils/evm-address';\nimport { isSolAddress } from '../../utils/sol-address';\n\nexport type SupportedChainsMap = Map<\n Caip2ChainId,\n {\n /** `number` for EVM, `Caip2ChainId` for SVM */\n chainId: number | Caip2ChainId;\n crossChainSwapEnabled: boolean;\n crossChainTargetChainIds: ReadonlySet<Caip2ChainId>;\n swapEnabled: boolean;\n tokenList: boolean;\n }\n>;\n\n/**\n * Checks whether the given source → target chain route is supported by Markr.\n */\nexport function isRouteSupported(\n supportedChains: SupportedChainsMap,\n sourceChainId: Caip2ChainId,\n targetChainId: Caip2ChainId,\n): boolean {\n const sourceChain = supportedChains.get(sourceChainId);\n const targetChain = supportedChains.get(targetChainId);\n\n if (!sourceChain || !targetChain) return false;\n\n if (sourceChainId === targetChainId) {\n return sourceChain.swapEnabled;\n }\n\n return sourceChain.crossChainSwapEnabled && sourceChain.crossChainTargetChainIds.has(targetChainId);\n}\n\nexport async function getSupportedChains(\n apiOptions: ApiOptions,\n disableCrossChainSwaps = false,\n): Promise<SupportedChainsMap> {\n const supportedChains: SupportedChainsMap = new Map();\n\n try {\n const chains = await markrGetInfoChains(apiOptions);\n const filteredSupportedChains = chains.filter(\n (chain): chain is SupportedChainsResponseItemEvm | SupportedChainsResponseItemSvm => {\n // Only include chains types that we support in the SDK (EVM and Solana for now).\n return chain.chainType === 'evm' || chain.chainType === 'svm';\n },\n );\n\n for (const chain of filteredSupportedChains) {\n const key: Caip2ChainId = typeof chain.chainId === 'number' ? eip155ChainIdToCaip2(chain.chainId) : chain.chainId;\n\n const isCrossChainSwapEnabled =\n chain.enabled_services.includes('cross-chain-quote') && chain.enabled_services.includes('cross-chain-swap');\n const isSwapEnabled = chain.enabled_services.includes('quote') && chain.enabled_services.includes('swap');\n const normalizedLaneChainIds = new Set<Caip2ChainId>();\n\n for (const lane of chain.lanes) {\n const laneChainId = typeof lane === 'number' ? eip155ChainIdToCaip2(lane) : lane;\n\n if (laneChainId !== key) {\n normalizedLaneChainIds.add(laneChainId);\n }\n }\n\n const crossChainSwapEnabled = disableCrossChainSwaps ? false : isCrossChainSwapEnabled;\n const crossChainTargetChainIds = crossChainSwapEnabled ? normalizedLaneChainIds : new Set<Caip2ChainId>();\n\n if (!isSwapEnabled && crossChainTargetChainIds.size === 0) {\n continue;\n }\n\n supportedChains.set(key, {\n chainId: chain.chainId,\n crossChainSwapEnabled,\n crossChainTargetChainIds,\n swapEnabled: isSwapEnabled,\n tokenList: chain.enabled_services.includes('token-list'),\n });\n }\n } catch (error) {\n throw new SdkError(ErrorReason.UNKNOWN, ErrorCode.INITIALIZATION_FAILED, {\n cause: error,\n details: 'Failed to fetch supported chains from Markr API.',\n });\n }\n\n return supportedChains;\n}\n\nexport async function getSupportedTokens(\n apiOptions: ApiOptions,\n supportedChains: SupportedChainsMap,\n): Promise<Map<Caip2ChainId, Promise<TokenListResponse>>> {\n // Parallel fetch token lists for all supported chains.\n const supportedTokens: Map<Caip2ChainId, Promise<TokenListResponse>> = new Map();\n\n for (const [caip2ChainId, chainInfo] of supportedChains.entries()) {\n // Only fetch token list for EVM chains that support swaps.\n if (\n typeof chainInfo.chainId === 'number' &&\n chainInfo.tokenList &&\n (chainInfo.crossChainSwapEnabled || chainInfo.swapEnabled)\n ) {\n try {\n const tokenListPromise = markrGetTokenList(apiOptions, chainInfo.chainId);\n supportedTokens.set(caip2ChainId, tokenListPromise);\n } catch {\n // Ignore errors for individual token list fetches.\n // TODO: Logger?\n }\n }\n }\n\n return supportedTokens;\n}\n\n/**\n * Determine if the provided token address represents the native token for its chain.\n *\n * Markr represents EVM native tokens as the zero address and Solana native SOL\n * as the wrapped SOL mint address.\n */\nexport function isTokenAddressNative(address: string): boolean {\n return address === ERC_ZERO_ADDRESS || address === SOL_MINT_ADDRESS;\n}\n\n/**\n * Convert an `Asset` to the address string expected by the Markr API.\n *\n * For NATIVE assets the representation depends on the chain:\n * - EVM chains: `0x0000...0000` (ERC zero address)\n * - Solana chains: `So11111111111111111111111111111111111111112` (wrapped SOL mint)\n *\n * @param asset The asset to convert.\n * @param chainId CAIP-2 chain ID used to disambiguate NATIVE assets across chain types.\n */\nexport function assetToAddressString(asset: Asset, chainId: Caip2ChainId): string {\n if (asset.type === TokenType.NATIVE) {\n if (isSolanaNamespace(chainId)) {\n return SOL_MINT_ADDRESS;\n }\n\n return ERC_ZERO_ADDRESS;\n }\n\n return asset.address;\n}\n\n/**\n * Markr rejects `minAmountOut=0` for non-zero quotes.\n *\n * For very small quotes, integer truncation after slippage can produce `0`.\n * Clamp to `1` in that edge case to satisfy Markr API validation while\n * preserving normal slippage behavior for larger quotes.\n */\nexport function calculateMarkrMinimumAmountOut({\n amountOut,\n assetOut,\n slippageBps,\n}: Pick<Quote, 'amountOut' | 'assetOut' | 'slippageBps'>): bigint {\n const minAmountOut = calculateMinimumAmountOut({ amountOut, assetOut, slippageBps });\n\n if (amountOut > 0n && minAmountOut === 0n) {\n return 1n;\n }\n\n return minAmountOut;\n}\n\nexport function quoteFromMarkrQuoteResponseData(\n data: QuoteResponseData,\n quoterProps: QuoterProps,\n partnerFeeBps: number,\n): Quote {\n const partnerFee: bigint = (data.amountOut * BigInt(partnerFeeBps)) / 10_000n;\n const amountOutAfterFees: bigint = data.amountOut - partnerFee;\n\n const fees: QuoteFees = [\n ...mapMarkrQuoteResponseDataFeesToQuoteFees(data.fees),\n // Add the partner fee as a QuoteFee component for Markr quotes.\n {\n type: 'partner',\n name: 'Core Fee',\n amount: partnerFee,\n chainId: quoterProps.targetChain.chainId,\n token: assetToFeeToken(quoterProps.targetAsset),\n },\n ];\n\n return {\n aggregator: {\n id: data.aggregator.id,\n logoUrl: data.aggregator.logo_url,\n name: data.aggregator.name,\n },\n amountIn: data.amountIn,\n amountOut: amountOutAfterFees,\n assetIn: quoterProps.sourceAsset,\n assetOut: quoterProps.targetAsset,\n expiresAt: data.expiredAt, // Markr returns `expiredAt` as Unix time in seconds; use as-is.\n fees,\n fromAddress: quoterProps.fromAddress,\n /**\n * This gasEstimate is rough or may be missing.\n * Consumers should use TransferManager.estimateGas for a more accurate estimate.\n */\n gasEstimate: data.gasEstimate,\n id: data.uuid,\n partnerFeeBps,\n serviceType: ServiceType.MARKR,\n slippageBps: quoterProps.slippageBps ?? data.recommendedSlippage,\n sourceChain: quoterProps.sourceChain,\n targetChain: quoterProps.targetChain,\n toAddress: quoterProps.toAddress,\n } satisfies Quote;\n}\n\nexport async function getPartnerFeeBps(apiOptions: ApiOptions): Promise<number> {\n try {\n const partnerInfo = await markrGetPartnerInfo(apiOptions);\n return partnerInfo.fee;\n } catch (error) {\n throw new SdkError(ErrorReason.UNKNOWN, ErrorCode.INITIALIZATION_FAILED, {\n cause: error,\n details: 'Failed to fetch partner info from Markr API.',\n });\n }\n}\n\nexport function mapMarkrQuoteResponseDataFeesToQuoteFees(markrFees: QuoteResponseData['fees']): QuoteFees {\n if (!markrFees) {\n return [];\n }\n\n const fees: QuoteFee[] = [];\n\n for (const fee of markrFees) {\n const chainId = typeof fee.token.chainId === 'number' ? eip155ChainIdToCaip2(fee.token.chainId) : fee.token.chainId;\n\n let token: QuoteFeeToken | undefined;\n\n if (isTokenAddressNative(fee.token.address)) {\n token = { type: TokenType.NATIVE };\n } else if (isEvmAddress(fee.token.address)) {\n token = { type: TokenType.ERC20, address: fee.token.address };\n } else if (isSolAddress(fee.token.address)) {\n token = { type: TokenType.SPL, address: fee.token.address };\n }\n\n if (!token) {\n // Skip fee if we can't determine token type.\n continue;\n }\n\n fees.push({\n type: fee.type,\n name: fee.name,\n amount: fee.amount,\n chainId,\n token,\n });\n }\n\n return fees;\n}\n\nfunction assetToFeeToken(asset: Asset): QuoteFeeToken {\n if (asset.type === TokenType.NATIVE) {\n return { type: TokenType.NATIVE };\n }\n\n if (asset.type === TokenType.SPL) {\n return { type: TokenType.SPL, address: asset.address };\n }\n\n return { type: TokenType.ERC20, address: asset.address };\n}\n\nexport type MarkrRouterAbi =\n | (typeof import('./_abis/swap-wrapper-abi'))['MARKR_SWAP_WRAPPER_ABI']\n | (typeof import('./_abis/cross-chain-swap-wrapper-abi'))['MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI'];\n\nexport async function getMarkrSwapWrapperAbi(crossChain: boolean): Promise<MarkrRouterAbi> {\n if (crossChain) {\n return (await import('./_abis/cross-chain-swap-wrapper-abi')).MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI;\n }\n\n return (await import('./_abis/swap-wrapper-abi')).MARKR_SWAP_WRAPPER_ABI;\n}\n\nexport function extractHexDataFromError(error: unknown): Hex | undefined {\n if (error instanceof BaseError) {\n const directData = (error as { data?: unknown }).data;\n if (isHex(directData)) {\n return directData;\n }\n\n let walkedData: Hex | undefined;\n error.walk((walkedError) => {\n const nestedData = (walkedError as { data?: unknown }).data;\n if (!walkedData && isHex(nestedData)) {\n walkedData = nestedData;\n }\n return false;\n });\n\n if (walkedData) {\n return walkedData;\n }\n\n const causeData = (error as { cause?: { data?: unknown } }).cause?.data;\n if (isHex(causeData)) {\n return causeData;\n }\n }\n\n if (!error || typeof error !== 'object') {\n return undefined;\n }\n\n const genericError = error as {\n data?: unknown;\n error?: { data?: unknown };\n cause?: { data?: unknown };\n response?: { data?: unknown };\n body?: { error?: { data?: unknown } };\n };\n\n if (isHex(genericError.data)) {\n return genericError.data;\n }\n\n if (isHex(genericError.error?.data)) {\n return genericError.error.data;\n }\n\n if (isHex(genericError.cause?.data)) {\n return genericError.cause.data;\n }\n\n if (isHex(genericError.response?.data)) {\n return genericError.response.data;\n }\n\n if (isHex(genericError.body?.error?.data)) {\n return genericError.body.error.data;\n }\n\n return undefined;\n}\n\nexport function decodeMarkrRevertError(abi: MarkrRouterAbi, error: unknown): string | null {\n const revertData = extractHexDataFromError(error);\n\n if (!revertData) {\n return null;\n }\n\n try {\n const decoded = decodeErrorResult({ abi, data: revertData });\n const decodedArgs = decoded.args.length > 0 ? `(${decoded.args.map(String).join(', ')})` : '()';\n\n return `${decoded.errorName}${decodedArgs}`;\n } catch {\n const selector = revertData.slice(0, 10).toLowerCase();\n\n for (const abiItem of abi) {\n if (abiItem.type !== 'error') {\n continue;\n }\n\n const signature = `${abiItem.name}(${abiItem.inputs.map((input) => input.type).join(',')})`;\n if (toFunctionSelector(signature).toLowerCase() === selector) {\n return `${abiItem.name}()`;\n }\n }\n }\n\n return null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"_utils.cjs","names":["markrGetInfoChains","eip155ChainIdToCaip2","SdkError","ErrorReason","ErrorCode","markrGetTokenList","ERC_ZERO_ADDRESS","NATIVE_SOL_ADDRESS","TokenType","isSolanaNamespace","calculateMinimumAmountOut","ServiceType","markrGetPartnerInfo","isEvmAddress","isSolAddress","BaseError"],"sources":["../../../src/transfer-service/markr/_utils.ts"],"sourcesContent":["import { ErrorCode, ErrorReason, SdkError } from '../../errors';\nimport { BaseError, decodeErrorResult, type Hex, isHex, toFunctionSelector } from 'viem';\nimport {\n type QuoteResponseData,\n type SupportedChainsResponseItemEvm,\n type SupportedChainsResponseItemSvm,\n type TokenListResponse,\n} from './_schema';\nimport { ERC_ZERO_ADDRESS, NATIVE_SOL_ADDRESS, ServiceType, TokenType } from '../../constants';\nimport { isSolanaNamespace } from '../../_utils/chain';\nimport { calculateMinimumAmountOut } from '../../_utils/math';\nimport { eip155ChainIdToCaip2 } from '../../utils/caip';\nimport type { Asset } from '../../types/asset';\nimport type { Caip2ChainId } from '../../types/caip';\nimport type { Quote, QuoteFee, QuoteFees, QuoteFeeToken, QuoterProps } from '../../types/quote';\nimport { markrGetInfoChains, markrGetPartnerInfo, markrGetTokenList, type ApiOptions } from './_api';\nimport { isEvmAddress } from '../../utils/evm-address';\nimport { isSolAddress } from '../../utils/sol-address';\n\nexport type SupportedChainsMap = Map<\n Caip2ChainId,\n {\n /** `number` for EVM, `Caip2ChainId` for SVM */\n chainId: number | Caip2ChainId;\n crossChainSwapEnabled: boolean;\n crossChainTargetChainIds: ReadonlySet<Caip2ChainId>;\n swapEnabled: boolean;\n tokenList: boolean;\n }\n>;\n\n/**\n * Checks whether the given source → target chain route is supported by Markr.\n */\nexport function isRouteSupported(\n supportedChains: SupportedChainsMap,\n sourceChainId: Caip2ChainId,\n targetChainId: Caip2ChainId,\n): boolean {\n const sourceChain = supportedChains.get(sourceChainId);\n const targetChain = supportedChains.get(targetChainId);\n\n if (!sourceChain || !targetChain) return false;\n\n if (sourceChainId === targetChainId) {\n return sourceChain.swapEnabled;\n }\n\n return sourceChain.crossChainSwapEnabled && sourceChain.crossChainTargetChainIds.has(targetChainId);\n}\n\nexport async function getSupportedChains(\n apiOptions: ApiOptions,\n disableCrossChainSwaps = false,\n): Promise<SupportedChainsMap> {\n const supportedChains: SupportedChainsMap = new Map();\n\n try {\n const chains = await markrGetInfoChains(apiOptions);\n const filteredSupportedChains = chains.filter(\n (chain): chain is SupportedChainsResponseItemEvm | SupportedChainsResponseItemSvm => {\n // Only include chains types that we support in the SDK (EVM and Solana for now).\n return chain.chainType === 'evm' || chain.chainType === 'svm';\n },\n );\n\n for (const chain of filteredSupportedChains) {\n const key: Caip2ChainId = typeof chain.chainId === 'number' ? eip155ChainIdToCaip2(chain.chainId) : chain.chainId;\n\n const isCrossChainSwapEnabled =\n chain.enabled_services.includes('cross-chain-quote') && chain.enabled_services.includes('cross-chain-swap');\n const isSwapEnabled = chain.enabled_services.includes('quote') && chain.enabled_services.includes('swap');\n const normalizedLaneChainIds = new Set<Caip2ChainId>();\n\n for (const lane of chain.lanes) {\n const laneChainId = typeof lane === 'number' ? eip155ChainIdToCaip2(lane) : lane;\n\n if (laneChainId !== key) {\n normalizedLaneChainIds.add(laneChainId);\n }\n }\n\n const crossChainSwapEnabled = disableCrossChainSwaps ? false : isCrossChainSwapEnabled;\n const crossChainTargetChainIds = crossChainSwapEnabled ? normalizedLaneChainIds : new Set<Caip2ChainId>();\n\n if (!isSwapEnabled && crossChainTargetChainIds.size === 0) {\n continue;\n }\n\n supportedChains.set(key, {\n chainId: chain.chainId,\n crossChainSwapEnabled,\n crossChainTargetChainIds,\n swapEnabled: isSwapEnabled,\n tokenList: chain.enabled_services.includes('token-list'),\n });\n }\n } catch (error) {\n throw new SdkError(ErrorReason.UNKNOWN, ErrorCode.INITIALIZATION_FAILED, {\n cause: error,\n details: 'Failed to fetch supported chains from Markr API.',\n });\n }\n\n return supportedChains;\n}\n\nexport async function getSupportedTokens(\n apiOptions: ApiOptions,\n supportedChains: SupportedChainsMap,\n): Promise<Map<Caip2ChainId, Promise<TokenListResponse>>> {\n // Parallel fetch token lists for all supported chains.\n const supportedTokens: Map<Caip2ChainId, Promise<TokenListResponse>> = new Map();\n\n for (const [caip2ChainId, chainInfo] of supportedChains.entries()) {\n // Only fetch token list for EVM chains that support swaps.\n if (\n typeof chainInfo.chainId === 'number' &&\n chainInfo.tokenList &&\n (chainInfo.crossChainSwapEnabled || chainInfo.swapEnabled)\n ) {\n try {\n const tokenListPromise = markrGetTokenList(apiOptions, chainInfo.chainId);\n supportedTokens.set(caip2ChainId, tokenListPromise);\n } catch {\n // Ignore errors for individual token list fetches.\n // TODO: Logger?\n }\n }\n }\n\n return supportedTokens;\n}\n\n/**\n * Determine if the provided token address represents the native token for its chain.\n *\n * Markr represents EVM native tokens as the zero address and Solana native SOL\n * as the wrapped SOL mint address.\n */\nexport function isTokenAddressNative(address: string): boolean {\n return address === ERC_ZERO_ADDRESS || address === NATIVE_SOL_ADDRESS;\n}\n\n/**\n * Convert an `Asset` to the address string expected by the Markr API.\n *\n * For NATIVE assets the representation depends on the chain:\n * - EVM chains: `0x0000...0000` (ERC zero address)\n * - Solana chains: `So11111111111111111111111111111111111111112` (wrapped SOL mint)\n *\n * @param asset The asset to convert.\n * @param chainId CAIP-2 chain ID used to disambiguate NATIVE assets across chain types.\n */\nexport function assetToAddressString(asset: Asset, chainId: Caip2ChainId): string {\n if (asset.type === TokenType.NATIVE) {\n if (isSolanaNamespace(chainId)) {\n return NATIVE_SOL_ADDRESS;\n }\n\n return ERC_ZERO_ADDRESS;\n }\n\n return asset.address;\n}\n\n/**\n * Markr rejects `minAmountOut=0` for non-zero quotes.\n *\n * For very small quotes, integer truncation after slippage can produce `0`.\n * Clamp to `1` in that edge case to satisfy Markr API validation while\n * preserving normal slippage behavior for larger quotes.\n */\nexport function calculateMarkrMinimumAmountOut({\n amountOut,\n assetOut,\n slippageBps,\n}: Pick<Quote, 'amountOut' | 'assetOut' | 'slippageBps'>): bigint {\n const minAmountOut = calculateMinimumAmountOut({ amountOut, assetOut, slippageBps });\n\n if (amountOut > 0n && minAmountOut === 0n) {\n return 1n;\n }\n\n return minAmountOut;\n}\n\nexport function quoteFromMarkrQuoteResponseData(\n data: QuoteResponseData,\n quoterProps: QuoterProps,\n partnerFeeBps: number,\n): Quote {\n const partnerFee: bigint = (data.amountOut * BigInt(partnerFeeBps)) / 10_000n;\n const amountOutAfterFees: bigint = data.amountOut - partnerFee;\n\n const fees: QuoteFees = [\n ...mapMarkrQuoteResponseDataFeesToQuoteFees(data.fees),\n // Add the partner fee as a QuoteFee component for Markr quotes.\n {\n type: 'partner',\n name: 'Core Fee',\n amount: partnerFee,\n chainId: quoterProps.targetChain.chainId,\n token: assetToFeeToken(quoterProps.targetAsset),\n },\n ];\n\n return {\n aggregator: {\n id: data.aggregator.id,\n logoUrl: data.aggregator.logo_url,\n name: data.aggregator.name,\n },\n amountIn: data.amountIn,\n amountOut: amountOutAfterFees,\n assetIn: quoterProps.sourceAsset,\n assetOut: quoterProps.targetAsset,\n expiresAt: data.expiredAt, // Markr returns `expiredAt` as Unix time in seconds; use as-is.\n fees,\n fromAddress: quoterProps.fromAddress,\n /**\n * This gasEstimate is rough or may be missing.\n * Consumers should use TransferManager.estimateGas for a more accurate estimate.\n */\n gasEstimate: data.gasEstimate,\n id: data.uuid,\n partnerFeeBps,\n serviceType: ServiceType.MARKR,\n slippageBps: quoterProps.slippageBps ?? data.recommendedSlippage,\n sourceChain: quoterProps.sourceChain,\n targetChain: quoterProps.targetChain,\n toAddress: quoterProps.toAddress,\n } satisfies Quote;\n}\n\nexport async function getPartnerFeeBps(apiOptions: ApiOptions): Promise<number> {\n try {\n const partnerInfo = await markrGetPartnerInfo(apiOptions);\n return partnerInfo.fee;\n } catch (error) {\n throw new SdkError(ErrorReason.UNKNOWN, ErrorCode.INITIALIZATION_FAILED, {\n cause: error,\n details: 'Failed to fetch partner info from Markr API.',\n });\n }\n}\n\nexport function mapMarkrQuoteResponseDataFeesToQuoteFees(markrFees: QuoteResponseData['fees']): QuoteFees {\n if (!markrFees) {\n return [];\n }\n\n const fees: QuoteFee[] = [];\n\n for (const fee of markrFees) {\n const chainId = typeof fee.token.chainId === 'number' ? eip155ChainIdToCaip2(fee.token.chainId) : fee.token.chainId;\n\n let token: QuoteFeeToken | undefined;\n\n if (isTokenAddressNative(fee.token.address)) {\n token = { type: TokenType.NATIVE };\n } else if (isEvmAddress(fee.token.address)) {\n token = { type: TokenType.ERC20, address: fee.token.address };\n } else if (isSolAddress(fee.token.address)) {\n token = { type: TokenType.SPL, address: fee.token.address };\n }\n\n if (!token) {\n // Skip fee if we can't determine token type.\n continue;\n }\n\n fees.push({\n type: fee.type,\n name: fee.name,\n amount: fee.amount,\n chainId,\n token,\n });\n }\n\n return fees;\n}\n\nfunction assetToFeeToken(asset: Asset): QuoteFeeToken {\n if (asset.type === TokenType.NATIVE) {\n return { type: TokenType.NATIVE };\n }\n\n if (asset.type === TokenType.SPL) {\n return { type: TokenType.SPL, address: asset.address };\n }\n\n return { type: TokenType.ERC20, address: asset.address };\n}\n\nexport type MarkrRouterAbi =\n | (typeof import('./_abis/swap-wrapper-abi'))['MARKR_SWAP_WRAPPER_ABI']\n | (typeof import('./_abis/cross-chain-swap-wrapper-abi'))['MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI'];\n\nexport async function getMarkrSwapWrapperAbi(crossChain: boolean): Promise<MarkrRouterAbi> {\n if (crossChain) {\n return (await import('./_abis/cross-chain-swap-wrapper-abi')).MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI;\n }\n\n return (await import('./_abis/swap-wrapper-abi')).MARKR_SWAP_WRAPPER_ABI;\n}\n\nexport function extractHexDataFromError(error: unknown): Hex | undefined {\n if (error instanceof BaseError) {\n const directData = (error as { data?: unknown }).data;\n if (isHex(directData)) {\n return directData;\n }\n\n let walkedData: Hex | undefined;\n error.walk((walkedError) => {\n const nestedData = (walkedError as { data?: unknown }).data;\n if (!walkedData && isHex(nestedData)) {\n walkedData = nestedData;\n }\n return false;\n });\n\n if (walkedData) {\n return walkedData;\n }\n\n const causeData = (error as { cause?: { data?: unknown } }).cause?.data;\n if (isHex(causeData)) {\n return causeData;\n }\n }\n\n if (!error || typeof error !== 'object') {\n return undefined;\n }\n\n const genericError = error as {\n data?: unknown;\n error?: { data?: unknown };\n cause?: { data?: unknown };\n response?: { data?: unknown };\n body?: { error?: { data?: unknown } };\n };\n\n if (isHex(genericError.data)) {\n return genericError.data;\n }\n\n if (isHex(genericError.error?.data)) {\n return genericError.error.data;\n }\n\n if (isHex(genericError.cause?.data)) {\n return genericError.cause.data;\n }\n\n if (isHex(genericError.response?.data)) {\n return genericError.response.data;\n }\n\n if (isHex(genericError.body?.error?.data)) {\n return genericError.body.error.data;\n }\n\n return undefined;\n}\n\nexport function decodeMarkrRevertError(abi: MarkrRouterAbi, error: unknown): string | null {\n const revertData = extractHexDataFromError(error);\n\n if (!revertData) {\n return null;\n }\n\n try {\n const decoded = decodeErrorResult({ abi, data: revertData });\n const decodedArgs = decoded.args.length > 0 ? `(${decoded.args.map(String).join(', ')})` : '()';\n\n return `${decoded.errorName}${decodedArgs}`;\n } catch {\n const selector = revertData.slice(0, 10).toLowerCase();\n\n for (const abiItem of abi) {\n if (abiItem.type !== 'error') {\n continue;\n }\n\n const signature = `${abiItem.name}(${abiItem.inputs.map((input) => input.type).join(',')})`;\n if (toFunctionSelector(signature).toLowerCase() === selector) {\n return `${abiItem.name}()`;\n }\n }\n }\n\n return null;\n}\n"],"mappings":"8VAkCA,SAAgB,EACd,EACA,EACA,EACS,CACT,IAAM,EAAc,EAAgB,IAAI,EAAc,CAChD,EAAc,EAAgB,IAAI,EAAc,CAQtD,MANI,CAAC,GAAe,CAAC,EAAoB,GAErC,IAAkB,EACb,EAAY,YAGd,EAAY,uBAAyB,EAAY,yBAAyB,IAAI,EAAc,CAGrG,eAAsB,EACpB,EACA,EAAyB,GACI,CAC7B,IAAM,EAAsC,IAAI,IAEhD,GAAI,CAEF,IAAM,GADS,MAAMA,EAAAA,mBAAmB,EAAW,EACZ,OACpC,GAEQ,EAAM,YAAc,OAAS,EAAM,YAAc,MAE3D,CAED,IAAK,IAAM,KAAS,EAAyB,CAC3C,IAAM,EAAoB,OAAO,EAAM,SAAY,SAAWC,EAAAA,qBAAqB,EAAM,QAAQ,CAAG,EAAM,QAEpG,EACJ,EAAM,iBAAiB,SAAS,oBAAoB,EAAI,EAAM,iBAAiB,SAAS,mBAAmB,CACvG,EAAgB,EAAM,iBAAiB,SAAS,QAAQ,EAAI,EAAM,iBAAiB,SAAS,OAAO,CACnG,EAAyB,IAAI,IAEnC,IAAK,IAAM,KAAQ,EAAM,MAAO,CAC9B,IAAM,EAAc,OAAO,GAAS,SAAWA,EAAAA,qBAAqB,EAAK,CAAG,EAExE,IAAgB,GAClB,EAAuB,IAAI,EAAY,CAI3C,IAAM,EAAwB,EAAyB,GAAQ,EACzD,EAA2B,EAAwB,EAAyB,IAAI,IAElF,CAAC,GAAiB,EAAyB,OAAS,GAIxD,EAAgB,IAAI,EAAK,CACvB,QAAS,EAAM,QACf,wBACA,2BACA,YAAa,EACb,UAAW,EAAM,iBAAiB,SAAS,aAAa,CACzD,CAAC,QAEG,EAAO,CACd,MAAM,IAAIC,EAAAA,SAASC,EAAAA,YAAY,QAASC,EAAAA,UAAU,sBAAuB,CACvE,MAAO,EACP,QAAS,mDACV,CAAC,CAGJ,OAAO,EAGT,eAAsB,EACpB,EACA,EACwD,CAExD,IAAM,EAAiE,IAAI,IAE3E,IAAK,GAAM,CAAC,EAAc,KAAc,EAAgB,SAAS,CAE/D,GACE,OAAO,EAAU,SAAY,UAC7B,EAAU,YACT,EAAU,uBAAyB,EAAU,aAE9C,GAAI,CACF,IAAM,EAAmBC,EAAAA,kBAAkB,EAAY,EAAU,QAAQ,CACzE,EAAgB,IAAI,EAAc,EAAiB,MAC7C,EAOZ,OAAO,EAST,SAAgB,EAAqB,EAA0B,CAC7D,OAAO,IAAYC,EAAAA,kBAAoB,IAAYC,EAAAA,mBAarD,SAAgB,EAAqB,EAAc,EAA+B,CAShF,OARI,EAAM,OAASC,EAAAA,UAAU,OACvBC,EAAAA,kBAAkB,EAAQ,CACrBF,EAAAA,mBAGFD,EAAAA,iBAGF,EAAM,QAUf,SAAgB,EAA+B,CAC7C,YACA,WACA,eACgE,CAChE,IAAM,EAAeI,EAAAA,0BAA0B,CAAE,YAAW,WAAU,cAAa,CAAC,CAMpF,OAJI,EAAY,IAAM,IAAiB,GAC9B,GAGF,EAGT,SAAgB,EACd,EACA,EACA,EACO,CACP,IAAM,EAAsB,EAAK,UAAY,OAAO,EAAc,CAAI,OAChE,EAA6B,EAAK,UAAY,EAE9C,EAAkB,CACtB,GAAG,EAAyC,EAAK,KAAK,CAEtD,CACE,KAAM,UACN,KAAM,WACN,OAAQ,EACR,QAAS,EAAY,YAAY,QACjC,MAAO,EAAgB,EAAY,YAAY,CAChD,CACF,CAED,MAAO,CACL,WAAY,CACV,GAAI,EAAK,WAAW,GACpB,QAAS,EAAK,WAAW,SACzB,KAAM,EAAK,WAAW,KACvB,CACD,SAAU,EAAK,SACf,UAAW,EACX,QAAS,EAAY,YACrB,SAAU,EAAY,YACtB,UAAW,EAAK,UAChB,OACA,YAAa,EAAY,YAKzB,YAAa,EAAK,YAClB,GAAI,EAAK,KACT,gBACA,YAAaC,EAAAA,YAAY,MACzB,YAAa,EAAY,aAAe,EAAK,oBAC7C,YAAa,EAAY,YACzB,YAAa,EAAY,YACzB,UAAW,EAAY,UACxB,CAGH,eAAsB,EAAiB,EAAyC,CAC9E,GAAI,CAEF,OADoB,MAAMC,EAAAA,oBAAoB,EAAW,EACtC,UACZ,EAAO,CACd,MAAM,IAAIV,EAAAA,SAASC,EAAAA,YAAY,QAASC,EAAAA,UAAU,sBAAuB,CACvE,MAAO,EACP,QAAS,+CACV,CAAC,EAIN,SAAgB,EAAyC,EAAiD,CACxG,GAAI,CAAC,EACH,MAAO,EAAE,CAGX,IAAM,EAAmB,EAAE,CAE3B,IAAK,IAAM,KAAO,EAAW,CAC3B,IAAM,EAAU,OAAO,EAAI,MAAM,SAAY,SAAWH,EAAAA,qBAAqB,EAAI,MAAM,QAAQ,CAAG,EAAI,MAAM,QAExG,EAEA,EAAqB,EAAI,MAAM,QAAQ,CACzC,EAAQ,CAAE,KAAMO,EAAAA,UAAU,OAAQ,CACzBK,EAAAA,aAAa,EAAI,MAAM,QAAQ,CACxC,EAAQ,CAAE,KAAML,EAAAA,UAAU,MAAO,QAAS,EAAI,MAAM,QAAS,CACpDM,EAAAA,aAAa,EAAI,MAAM,QAAQ,GACxC,EAAQ,CAAE,KAAMN,EAAAA,UAAU,IAAK,QAAS,EAAI,MAAM,QAAS,EAGxD,GAKL,EAAK,KAAK,CACR,KAAM,EAAI,KACV,KAAM,EAAI,KACV,OAAQ,EAAI,OACZ,UACA,QACD,CAAC,CAGJ,OAAO,EAGT,SAAS,EAAgB,EAA6B,CASpD,OARI,EAAM,OAASA,EAAAA,UAAU,OACpB,CAAE,KAAMA,EAAAA,UAAU,OAAQ,CAG/B,EAAM,OAASA,EAAAA,UAAU,IACpB,CAAE,KAAMA,EAAAA,UAAU,IAAK,QAAS,EAAM,QAAS,CAGjD,CAAE,KAAMA,EAAAA,UAAU,MAAO,QAAS,EAAM,QAAS,CAO1D,eAAsB,EAAuB,EAA8C,CAKzF,OAJI,GACM,MAAA,QAAA,SAAA,CAAA,SAAA,QAAM,2CAAA,CAAA,EAAgD,oCAGxD,MAAA,QAAA,SAAA,CAAA,SAAA,QAAM,+BAAA,CAAA,EAAoC,uBAGpD,SAAgB,EAAwB,EAAiC,CACvE,GAAI,aAAiBO,EAAAA,UAAW,CAC9B,IAAM,EAAc,EAA6B,KACjD,IAAA,EAAA,EAAA,OAAU,EAAW,CACnB,OAAO,EAGT,IAAI,EASJ,GARA,EAAM,KAAM,GAAgB,CAC1B,IAAM,EAAc,EAAmC,KAIvD,MAHI,CAAC,IAAA,EAAA,EAAA,OAAoB,EAAW,GAClC,EAAa,GAER,IACP,CAEE,EACF,OAAO,EAGT,IAAM,EAAa,EAAyC,OAAO,KACnE,IAAA,EAAA,EAAA,OAAU,EAAU,CAClB,OAAO,EAIX,GAAI,CAAC,GAAS,OAAO,GAAU,SAC7B,OAGF,IAAM,EAAe,EAQrB,IAAA,EAAA,EAAA,OAAU,EAAa,KAAK,CAC1B,OAAO,EAAa,KAGtB,IAAA,EAAA,EAAA,OAAU,EAAa,OAAO,KAAK,CACjC,OAAO,EAAa,MAAM,KAG5B,IAAA,EAAA,EAAA,OAAU,EAAa,OAAO,KAAK,CACjC,OAAO,EAAa,MAAM,KAG5B,IAAA,EAAA,EAAA,OAAU,EAAa,UAAU,KAAK,CACpC,OAAO,EAAa,SAAS,KAG/B,IAAA,EAAA,EAAA,OAAU,EAAa,MAAM,OAAO,KAAK,CACvC,OAAO,EAAa,KAAK,MAAM,KAMnC,SAAgB,EAAuB,EAAqB,EAA+B,CACzF,IAAM,EAAa,EAAwB,EAAM,CAEjD,GAAI,CAAC,EACH,OAAO,KAGT,GAAI,CACF,IAAM,GAAA,EAAA,EAAA,mBAA4B,CAAE,MAAK,KAAM,EAAY,CAAC,CACtD,EAAc,EAAQ,KAAK,OAAS,EAAI,IAAI,EAAQ,KAAK,IAAI,OAAO,CAAC,KAAK,KAAK,CAAC,GAAK,KAE3F,MAAO,GAAG,EAAQ,YAAY,SACxB,CACN,IAAM,EAAW,EAAW,MAAM,EAAG,GAAG,CAAC,aAAa,CAEtD,IAAK,IAAM,KAAW,EAChB,KAAQ,OAAS,UAKrB,EAAA,EAAA,oBADkB,GAAG,EAAQ,KAAK,GAAG,EAAQ,OAAO,IAAK,GAAU,EAAM,KAAK,CAAC,KAAK,IAAI,CAAC,GACxD,CAAC,aAAa,GAAK,EAClD,MAAO,GAAG,EAAQ,KAAK,IAK7B,OAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ERC_ZERO_ADDRESS as e,
|
|
1
|
+
import{ERC_ZERO_ADDRESS as e,NATIVE_SOL_ADDRESS as t,ServiceType as n,TokenType as r}from"../../constants.js";import{ErrorCode as i,ErrorReason as a,SdkError as o}from"../../errors.js";import{eip155ChainIdToCaip2 as s}from"../../utils/caip.js";import{isSolanaNamespace as c}from"../../_utils/chain.js";import{isEvmAddress as l}from"../../utils/evm-address.js";import{calculateMinimumAmountOut as u}from"../../_utils/math.js";import{markrGetInfoChains as d,markrGetPartnerInfo as f,markrGetTokenList as p}from"./_api.js";import{isSolAddress as m}from"../../utils/sol-address.js";import{BaseError as h,decodeErrorResult as g,isHex as _,toFunctionSelector as v}from"viem";function y(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 b(e,t=!1){let n=new Map;try{let r=(await d(e)).filter(e=>e.chainType===`evm`||e.chainType===`svm`);for(let e of r){let r=typeof e.chainId==`number`?s(e.chainId):e.chainId,i=e.enabled_services.includes(`cross-chain-quote`)&&e.enabled_services.includes(`cross-chain-swap`),a=e.enabled_services.includes(`quote`)&&e.enabled_services.includes(`swap`),o=new Set;for(let t of e.lanes){let e=typeof t==`number`?s(t):t;e!==r&&o.add(e)}let c=t?!1:i,l=c?o:new Set;!a&&l.size===0||n.set(r,{chainId:e.chainId,crossChainSwapEnabled:c,crossChainTargetChainIds:l,swapEnabled:a,tokenList:e.enabled_services.includes(`token-list`)})}}catch(e){throw new o(a.UNKNOWN,i.INITIALIZATION_FAILED,{cause:e,details:`Failed to fetch supported chains from Markr API.`})}return n}async function x(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=p(e,i.chainId);n.set(r,t)}catch{}return n}function S(n){return n===e||n===t}function C(n,i){return n.type===r.NATIVE?c(i)?t:e:n.address}function w({amountOut:e,assetOut:t,slippageBps:n}){let r=u({amountOut:e,assetOut:t,slippageBps:n});return e>0n&&r===0n?1n:r}function T(e,t,r){let i=e.amountOut*BigInt(r)/10000n,a=e.amountOut-i,o=[...D(e.fees),{type:`partner`,name:`Core Fee`,amount:i,chainId:t.targetChain.chainId,token:O(t.targetAsset)}];return{aggregator:{id:e.aggregator.id,logoUrl:e.aggregator.logo_url,name:e.aggregator.name},amountIn:e.amountIn,amountOut:a,assetIn:t.sourceAsset,assetOut:t.targetAsset,expiresAt:e.expiredAt,fees:o,fromAddress:t.fromAddress,gasEstimate:e.gasEstimate,id:e.uuid,partnerFeeBps:r,serviceType:n.MARKR,slippageBps:t.slippageBps??e.recommendedSlippage,sourceChain:t.sourceChain,targetChain:t.targetChain,toAddress:t.toAddress}}async function E(e){try{return(await f(e)).fee}catch(e){throw new o(a.UNKNOWN,i.INITIALIZATION_FAILED,{cause:e,details:`Failed to fetch partner info from Markr API.`})}}function D(e){if(!e)return[];let t=[];for(let n of e){let e=typeof n.token.chainId==`number`?s(n.token.chainId):n.token.chainId,i;S(n.token.address)?i={type:r.NATIVE}:l(n.token.address)?i={type:r.ERC20,address:n.token.address}:m(n.token.address)&&(i={type:r.SPL,address:n.token.address}),i&&t.push({type:n.type,name:n.name,amount:n.amount,chainId:e,token:i})}return t}function O(e){return e.type===r.NATIVE?{type:r.NATIVE}:e.type===r.SPL?{type:r.SPL,address:e.address}:{type:r.ERC20,address:e.address}}async function k(e){return e?(await import(`./_abis/cross-chain-swap-wrapper-abi.js`)).MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI:(await import(`./_abis/swap-wrapper-abi.js`)).MARKR_SWAP_WRAPPER_ABI}function A(e){if(e instanceof h){let t=e.data;if(_(t))return t;let n;if(e.walk(e=>{let t=e.data;return!n&&_(t)&&(n=t),!1}),n)return n;let r=e.cause?.data;if(_(r))return r}if(!e||typeof e!=`object`)return;let t=e;if(_(t.data))return t.data;if(_(t.error?.data))return t.error.data;if(_(t.cause?.data))return t.cause.data;if(_(t.response?.data))return t.response.data;if(_(t.body?.error?.data))return t.body.error.data}function j(e,t){let n=A(t);if(!n)return null;try{let t=g({abi:e,data:n}),r=t.args.length>0?`(${t.args.map(String).join(`, `)})`:`()`;return`${t.errorName}${r}`}catch{let t=n.slice(0,10).toLowerCase();for(let n of e)if(n.type===`error`&&v(`${n.name}(${n.inputs.map(e=>e.type).join(`,`)})`).toLowerCase()===t)return`${n.name}()`}return null}export{C as assetToAddressString,w as calculateMarkrMinimumAmountOut,j as decodeMarkrRevertError,k as getMarkrSwapWrapperAbi,E as getPartnerFeeBps,b as getSupportedChains,x as getSupportedTokens,y as isRouteSupported,S as isTokenAddressNative,T as quoteFromMarkrQuoteResponseData};
|
|
2
2
|
//# sourceMappingURL=_utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_utils.js","names":[],"sources":["../../../src/transfer-service/markr/_utils.ts"],"sourcesContent":["import { ErrorCode, ErrorReason, SdkError } from '../../errors';\nimport { BaseError, decodeErrorResult, type Hex, isHex, toFunctionSelector } from 'viem';\nimport {\n type QuoteResponseData,\n type SupportedChainsResponseItemEvm,\n type SupportedChainsResponseItemSvm,\n type TokenListResponse,\n} from './_schema';\nimport { ERC_ZERO_ADDRESS, SOL_MINT_ADDRESS, ServiceType, TokenType } from '../../constants';\nimport { isSolanaNamespace } from '../../_utils/chain';\nimport { calculateMinimumAmountOut } from '../../_utils/math';\nimport { eip155ChainIdToCaip2 } from '../../utils/caip';\nimport type { Asset } from '../../types/asset';\nimport type { Caip2ChainId } from '../../types/caip';\nimport type { Quote, QuoteFee, QuoteFees, QuoteFeeToken, QuoterProps } from '../../types/quote';\nimport { markrGetInfoChains, markrGetPartnerInfo, markrGetTokenList, type ApiOptions } from './_api';\nimport { isEvmAddress } from '../../utils/evm-address';\nimport { isSolAddress } from '../../utils/sol-address';\n\nexport type SupportedChainsMap = Map<\n Caip2ChainId,\n {\n /** `number` for EVM, `Caip2ChainId` for SVM */\n chainId: number | Caip2ChainId;\n crossChainSwapEnabled: boolean;\n crossChainTargetChainIds: ReadonlySet<Caip2ChainId>;\n swapEnabled: boolean;\n tokenList: boolean;\n }\n>;\n\n/**\n * Checks whether the given source → target chain route is supported by Markr.\n */\nexport function isRouteSupported(\n supportedChains: SupportedChainsMap,\n sourceChainId: Caip2ChainId,\n targetChainId: Caip2ChainId,\n): boolean {\n const sourceChain = supportedChains.get(sourceChainId);\n const targetChain = supportedChains.get(targetChainId);\n\n if (!sourceChain || !targetChain) return false;\n\n if (sourceChainId === targetChainId) {\n return sourceChain.swapEnabled;\n }\n\n return sourceChain.crossChainSwapEnabled && sourceChain.crossChainTargetChainIds.has(targetChainId);\n}\n\nexport async function getSupportedChains(\n apiOptions: ApiOptions,\n disableCrossChainSwaps = false,\n): Promise<SupportedChainsMap> {\n const supportedChains: SupportedChainsMap = new Map();\n\n try {\n const chains = await markrGetInfoChains(apiOptions);\n const filteredSupportedChains = chains.filter(\n (chain): chain is SupportedChainsResponseItemEvm | SupportedChainsResponseItemSvm => {\n // Only include chains types that we support in the SDK (EVM and Solana for now).\n return chain.chainType === 'evm' || chain.chainType === 'svm';\n },\n );\n\n for (const chain of filteredSupportedChains) {\n const key: Caip2ChainId = typeof chain.chainId === 'number' ? eip155ChainIdToCaip2(chain.chainId) : chain.chainId;\n\n const isCrossChainSwapEnabled =\n chain.enabled_services.includes('cross-chain-quote') && chain.enabled_services.includes('cross-chain-swap');\n const isSwapEnabled = chain.enabled_services.includes('quote') && chain.enabled_services.includes('swap');\n const normalizedLaneChainIds = new Set<Caip2ChainId>();\n\n for (const lane of chain.lanes) {\n const laneChainId = typeof lane === 'number' ? eip155ChainIdToCaip2(lane) : lane;\n\n if (laneChainId !== key) {\n normalizedLaneChainIds.add(laneChainId);\n }\n }\n\n const crossChainSwapEnabled = disableCrossChainSwaps ? false : isCrossChainSwapEnabled;\n const crossChainTargetChainIds = crossChainSwapEnabled ? normalizedLaneChainIds : new Set<Caip2ChainId>();\n\n if (!isSwapEnabled && crossChainTargetChainIds.size === 0) {\n continue;\n }\n\n supportedChains.set(key, {\n chainId: chain.chainId,\n crossChainSwapEnabled,\n crossChainTargetChainIds,\n swapEnabled: isSwapEnabled,\n tokenList: chain.enabled_services.includes('token-list'),\n });\n }\n } catch (error) {\n throw new SdkError(ErrorReason.UNKNOWN, ErrorCode.INITIALIZATION_FAILED, {\n cause: error,\n details: 'Failed to fetch supported chains from Markr API.',\n });\n }\n\n return supportedChains;\n}\n\nexport async function getSupportedTokens(\n apiOptions: ApiOptions,\n supportedChains: SupportedChainsMap,\n): Promise<Map<Caip2ChainId, Promise<TokenListResponse>>> {\n // Parallel fetch token lists for all supported chains.\n const supportedTokens: Map<Caip2ChainId, Promise<TokenListResponse>> = new Map();\n\n for (const [caip2ChainId, chainInfo] of supportedChains.entries()) {\n // Only fetch token list for EVM chains that support swaps.\n if (\n typeof chainInfo.chainId === 'number' &&\n chainInfo.tokenList &&\n (chainInfo.crossChainSwapEnabled || chainInfo.swapEnabled)\n ) {\n try {\n const tokenListPromise = markrGetTokenList(apiOptions, chainInfo.chainId);\n supportedTokens.set(caip2ChainId, tokenListPromise);\n } catch {\n // Ignore errors for individual token list fetches.\n // TODO: Logger?\n }\n }\n }\n\n return supportedTokens;\n}\n\n/**\n * Determine if the provided token address represents the native token for its chain.\n *\n * Markr represents EVM native tokens as the zero address and Solana native SOL\n * as the wrapped SOL mint address.\n */\nexport function isTokenAddressNative(address: string): boolean {\n return address === ERC_ZERO_ADDRESS || address === SOL_MINT_ADDRESS;\n}\n\n/**\n * Convert an `Asset` to the address string expected by the Markr API.\n *\n * For NATIVE assets the representation depends on the chain:\n * - EVM chains: `0x0000...0000` (ERC zero address)\n * - Solana chains: `So11111111111111111111111111111111111111112` (wrapped SOL mint)\n *\n * @param asset The asset to convert.\n * @param chainId CAIP-2 chain ID used to disambiguate NATIVE assets across chain types.\n */\nexport function assetToAddressString(asset: Asset, chainId: Caip2ChainId): string {\n if (asset.type === TokenType.NATIVE) {\n if (isSolanaNamespace(chainId)) {\n return SOL_MINT_ADDRESS;\n }\n\n return ERC_ZERO_ADDRESS;\n }\n\n return asset.address;\n}\n\n/**\n * Markr rejects `minAmountOut=0` for non-zero quotes.\n *\n * For very small quotes, integer truncation after slippage can produce `0`.\n * Clamp to `1` in that edge case to satisfy Markr API validation while\n * preserving normal slippage behavior for larger quotes.\n */\nexport function calculateMarkrMinimumAmountOut({\n amountOut,\n assetOut,\n slippageBps,\n}: Pick<Quote, 'amountOut' | 'assetOut' | 'slippageBps'>): bigint {\n const minAmountOut = calculateMinimumAmountOut({ amountOut, assetOut, slippageBps });\n\n if (amountOut > 0n && minAmountOut === 0n) {\n return 1n;\n }\n\n return minAmountOut;\n}\n\nexport function quoteFromMarkrQuoteResponseData(\n data: QuoteResponseData,\n quoterProps: QuoterProps,\n partnerFeeBps: number,\n): Quote {\n const partnerFee: bigint = (data.amountOut * BigInt(partnerFeeBps)) / 10_000n;\n const amountOutAfterFees: bigint = data.amountOut - partnerFee;\n\n const fees: QuoteFees = [\n ...mapMarkrQuoteResponseDataFeesToQuoteFees(data.fees),\n // Add the partner fee as a QuoteFee component for Markr quotes.\n {\n type: 'partner',\n name: 'Core Fee',\n amount: partnerFee,\n chainId: quoterProps.targetChain.chainId,\n token: assetToFeeToken(quoterProps.targetAsset),\n },\n ];\n\n return {\n aggregator: {\n id: data.aggregator.id,\n logoUrl: data.aggregator.logo_url,\n name: data.aggregator.name,\n },\n amountIn: data.amountIn,\n amountOut: amountOutAfterFees,\n assetIn: quoterProps.sourceAsset,\n assetOut: quoterProps.targetAsset,\n expiresAt: data.expiredAt, // Markr returns `expiredAt` as Unix time in seconds; use as-is.\n fees,\n fromAddress: quoterProps.fromAddress,\n /**\n * This gasEstimate is rough or may be missing.\n * Consumers should use TransferManager.estimateGas for a more accurate estimate.\n */\n gasEstimate: data.gasEstimate,\n id: data.uuid,\n partnerFeeBps,\n serviceType: ServiceType.MARKR,\n slippageBps: quoterProps.slippageBps ?? data.recommendedSlippage,\n sourceChain: quoterProps.sourceChain,\n targetChain: quoterProps.targetChain,\n toAddress: quoterProps.toAddress,\n } satisfies Quote;\n}\n\nexport async function getPartnerFeeBps(apiOptions: ApiOptions): Promise<number> {\n try {\n const partnerInfo = await markrGetPartnerInfo(apiOptions);\n return partnerInfo.fee;\n } catch (error) {\n throw new SdkError(ErrorReason.UNKNOWN, ErrorCode.INITIALIZATION_FAILED, {\n cause: error,\n details: 'Failed to fetch partner info from Markr API.',\n });\n }\n}\n\nexport function mapMarkrQuoteResponseDataFeesToQuoteFees(markrFees: QuoteResponseData['fees']): QuoteFees {\n if (!markrFees) {\n return [];\n }\n\n const fees: QuoteFee[] = [];\n\n for (const fee of markrFees) {\n const chainId = typeof fee.token.chainId === 'number' ? eip155ChainIdToCaip2(fee.token.chainId) : fee.token.chainId;\n\n let token: QuoteFeeToken | undefined;\n\n if (isTokenAddressNative(fee.token.address)) {\n token = { type: TokenType.NATIVE };\n } else if (isEvmAddress(fee.token.address)) {\n token = { type: TokenType.ERC20, address: fee.token.address };\n } else if (isSolAddress(fee.token.address)) {\n token = { type: TokenType.SPL, address: fee.token.address };\n }\n\n if (!token) {\n // Skip fee if we can't determine token type.\n continue;\n }\n\n fees.push({\n type: fee.type,\n name: fee.name,\n amount: fee.amount,\n chainId,\n token,\n });\n }\n\n return fees;\n}\n\nfunction assetToFeeToken(asset: Asset): QuoteFeeToken {\n if (asset.type === TokenType.NATIVE) {\n return { type: TokenType.NATIVE };\n }\n\n if (asset.type === TokenType.SPL) {\n return { type: TokenType.SPL, address: asset.address };\n }\n\n return { type: TokenType.ERC20, address: asset.address };\n}\n\nexport type MarkrRouterAbi =\n | (typeof import('./_abis/swap-wrapper-abi'))['MARKR_SWAP_WRAPPER_ABI']\n | (typeof import('./_abis/cross-chain-swap-wrapper-abi'))['MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI'];\n\nexport async function getMarkrSwapWrapperAbi(crossChain: boolean): Promise<MarkrRouterAbi> {\n if (crossChain) {\n return (await import('./_abis/cross-chain-swap-wrapper-abi')).MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI;\n }\n\n return (await import('./_abis/swap-wrapper-abi')).MARKR_SWAP_WRAPPER_ABI;\n}\n\nexport function extractHexDataFromError(error: unknown): Hex | undefined {\n if (error instanceof BaseError) {\n const directData = (error as { data?: unknown }).data;\n if (isHex(directData)) {\n return directData;\n }\n\n let walkedData: Hex | undefined;\n error.walk((walkedError) => {\n const nestedData = (walkedError as { data?: unknown }).data;\n if (!walkedData && isHex(nestedData)) {\n walkedData = nestedData;\n }\n return false;\n });\n\n if (walkedData) {\n return walkedData;\n }\n\n const causeData = (error as { cause?: { data?: unknown } }).cause?.data;\n if (isHex(causeData)) {\n return causeData;\n }\n }\n\n if (!error || typeof error !== 'object') {\n return undefined;\n }\n\n const genericError = error as {\n data?: unknown;\n error?: { data?: unknown };\n cause?: { data?: unknown };\n response?: { data?: unknown };\n body?: { error?: { data?: unknown } };\n };\n\n if (isHex(genericError.data)) {\n return genericError.data;\n }\n\n if (isHex(genericError.error?.data)) {\n return genericError.error.data;\n }\n\n if (isHex(genericError.cause?.data)) {\n return genericError.cause.data;\n }\n\n if (isHex(genericError.response?.data)) {\n return genericError.response.data;\n }\n\n if (isHex(genericError.body?.error?.data)) {\n return genericError.body.error.data;\n }\n\n return undefined;\n}\n\nexport function decodeMarkrRevertError(abi: MarkrRouterAbi, error: unknown): string | null {\n const revertData = extractHexDataFromError(error);\n\n if (!revertData) {\n return null;\n }\n\n try {\n const decoded = decodeErrorResult({ abi, data: revertData });\n const decodedArgs = decoded.args.length > 0 ? `(${decoded.args.map(String).join(', ')})` : '()';\n\n return `${decoded.errorName}${decodedArgs}`;\n } catch {\n const selector = revertData.slice(0, 10).toLowerCase();\n\n for (const abiItem of abi) {\n if (abiItem.type !== 'error') {\n continue;\n }\n\n const signature = `${abiItem.name}(${abiItem.inputs.map((input) => input.type).join(',')})`;\n if (toFunctionSelector(signature).toLowerCase() === selector) {\n return `${abiItem.name}()`;\n }\n }\n }\n\n return null;\n}\n"],"mappings":"2pBAkCA,SAAgB,EACd,EACA,EACA,EACS,CACT,IAAM,EAAc,EAAgB,IAAI,EAAc,CAChD,EAAc,EAAgB,IAAI,EAAc,CAQtD,MANI,CAAC,GAAe,CAAC,EAAoB,GAErC,IAAkB,EACb,EAAY,YAGd,EAAY,uBAAyB,EAAY,yBAAyB,IAAI,EAAc,CAGrG,eAAsB,EACpB,EACA,EAAyB,GACI,CAC7B,IAAM,EAAsC,IAAI,IAEhD,GAAI,CAEF,IAAM,GADS,MAAM,EAAmB,EAAW,EACZ,OACpC,GAEQ,EAAM,YAAc,OAAS,EAAM,YAAc,MAE3D,CAED,IAAK,IAAM,KAAS,EAAyB,CAC3C,IAAM,EAAoB,OAAO,EAAM,SAAY,SAAW,EAAqB,EAAM,QAAQ,CAAG,EAAM,QAEpG,EACJ,EAAM,iBAAiB,SAAS,oBAAoB,EAAI,EAAM,iBAAiB,SAAS,mBAAmB,CACvG,EAAgB,EAAM,iBAAiB,SAAS,QAAQ,EAAI,EAAM,iBAAiB,SAAS,OAAO,CACnG,EAAyB,IAAI,IAEnC,IAAK,IAAM,KAAQ,EAAM,MAAO,CAC9B,IAAM,EAAc,OAAO,GAAS,SAAW,EAAqB,EAAK,CAAG,EAExE,IAAgB,GAClB,EAAuB,IAAI,EAAY,CAI3C,IAAM,EAAwB,EAAyB,GAAQ,EACzD,EAA2B,EAAwB,EAAyB,IAAI,IAElF,CAAC,GAAiB,EAAyB,OAAS,GAIxD,EAAgB,IAAI,EAAK,CACvB,QAAS,EAAM,QACf,wBACA,2BACA,YAAa,EACb,UAAW,EAAM,iBAAiB,SAAS,aAAa,CACzD,CAAC,QAEG,EAAO,CACd,MAAM,IAAI,EAAS,EAAY,QAAS,EAAU,sBAAuB,CACvE,MAAO,EACP,QAAS,mDACV,CAAC,CAGJ,OAAO,EAGT,eAAsB,EACpB,EACA,EACwD,CAExD,IAAM,EAAiE,IAAI,IAE3E,IAAK,GAAM,CAAC,EAAc,KAAc,EAAgB,SAAS,CAE/D,GACE,OAAO,EAAU,SAAY,UAC7B,EAAU,YACT,EAAU,uBAAyB,EAAU,aAE9C,GAAI,CACF,IAAM,EAAmB,EAAkB,EAAY,EAAU,QAAQ,CACzE,EAAgB,IAAI,EAAc,EAAiB,MAC7C,EAOZ,OAAO,EAST,SAAgB,EAAqB,EAA0B,CAC7D,OAAO,IAAY,GAAoB,IAAY,EAarD,SAAgB,EAAqB,EAAc,EAA+B,CAShF,OARI,EAAM,OAAS,EAAU,OACvB,EAAkB,EAAQ,CACrB,EAGF,EAGF,EAAM,QAUf,SAAgB,EAA+B,CAC7C,YACA,WACA,eACgE,CAChE,IAAM,EAAe,EAA0B,CAAE,YAAW,WAAU,cAAa,CAAC,CAMpF,OAJI,EAAY,IAAM,IAAiB,GAC9B,GAGF,EAGT,SAAgB,EACd,EACA,EACA,EACO,CACP,IAAM,EAAsB,EAAK,UAAY,OAAO,EAAc,CAAI,OAChE,EAA6B,EAAK,UAAY,EAE9C,EAAkB,CACtB,GAAG,EAAyC,EAAK,KAAK,CAEtD,CACE,KAAM,UACN,KAAM,WACN,OAAQ,EACR,QAAS,EAAY,YAAY,QACjC,MAAO,EAAgB,EAAY,YAAY,CAChD,CACF,CAED,MAAO,CACL,WAAY,CACV,GAAI,EAAK,WAAW,GACpB,QAAS,EAAK,WAAW,SACzB,KAAM,EAAK,WAAW,KACvB,CACD,SAAU,EAAK,SACf,UAAW,EACX,QAAS,EAAY,YACrB,SAAU,EAAY,YACtB,UAAW,EAAK,UAChB,OACA,YAAa,EAAY,YAKzB,YAAa,EAAK,YAClB,GAAI,EAAK,KACT,gBACA,YAAa,EAAY,MACzB,YAAa,EAAY,aAAe,EAAK,oBAC7C,YAAa,EAAY,YACzB,YAAa,EAAY,YACzB,UAAW,EAAY,UACxB,CAGH,eAAsB,EAAiB,EAAyC,CAC9E,GAAI,CAEF,OADoB,MAAM,EAAoB,EAAW,EACtC,UACZ,EAAO,CACd,MAAM,IAAI,EAAS,EAAY,QAAS,EAAU,sBAAuB,CACvE,MAAO,EACP,QAAS,+CACV,CAAC,EAIN,SAAgB,EAAyC,EAAiD,CACxG,GAAI,CAAC,EACH,MAAO,EAAE,CAGX,IAAM,EAAmB,EAAE,CAE3B,IAAK,IAAM,KAAO,EAAW,CAC3B,IAAM,EAAU,OAAO,EAAI,MAAM,SAAY,SAAW,EAAqB,EAAI,MAAM,QAAQ,CAAG,EAAI,MAAM,QAExG,EAEA,EAAqB,EAAI,MAAM,QAAQ,CACzC,EAAQ,CAAE,KAAM,EAAU,OAAQ,CACzB,EAAa,EAAI,MAAM,QAAQ,CACxC,EAAQ,CAAE,KAAM,EAAU,MAAO,QAAS,EAAI,MAAM,QAAS,CACpD,EAAa,EAAI,MAAM,QAAQ,GACxC,EAAQ,CAAE,KAAM,EAAU,IAAK,QAAS,EAAI,MAAM,QAAS,EAGxD,GAKL,EAAK,KAAK,CACR,KAAM,EAAI,KACV,KAAM,EAAI,KACV,OAAQ,EAAI,OACZ,UACA,QACD,CAAC,CAGJ,OAAO,EAGT,SAAS,EAAgB,EAA6B,CASpD,OARI,EAAM,OAAS,EAAU,OACpB,CAAE,KAAM,EAAU,OAAQ,CAG/B,EAAM,OAAS,EAAU,IACpB,CAAE,KAAM,EAAU,IAAK,QAAS,EAAM,QAAS,CAGjD,CAAE,KAAM,EAAU,MAAO,QAAS,EAAM,QAAS,CAO1D,eAAsB,EAAuB,EAA8C,CAKzF,OAJI,GACM,MAAM,OAAO,4CAAyC,oCAGxD,MAAM,OAAO,gCAA6B,uBAGpD,SAAgB,EAAwB,EAAiC,CACvE,GAAI,aAAiB,EAAW,CAC9B,IAAM,EAAc,EAA6B,KACjD,GAAI,EAAM,EAAW,CACnB,OAAO,EAGT,IAAI,EASJ,GARA,EAAM,KAAM,GAAgB,CAC1B,IAAM,EAAc,EAAmC,KAIvD,MAHI,CAAC,GAAc,EAAM,EAAW,GAClC,EAAa,GAER,IACP,CAEE,EACF,OAAO,EAGT,IAAM,EAAa,EAAyC,OAAO,KACnE,GAAI,EAAM,EAAU,CAClB,OAAO,EAIX,GAAI,CAAC,GAAS,OAAO,GAAU,SAC7B,OAGF,IAAM,EAAe,EAQrB,GAAI,EAAM,EAAa,KAAK,CAC1B,OAAO,EAAa,KAGtB,GAAI,EAAM,EAAa,OAAO,KAAK,CACjC,OAAO,EAAa,MAAM,KAG5B,GAAI,EAAM,EAAa,OAAO,KAAK,CACjC,OAAO,EAAa,MAAM,KAG5B,GAAI,EAAM,EAAa,UAAU,KAAK,CACpC,OAAO,EAAa,SAAS,KAG/B,GAAI,EAAM,EAAa,MAAM,OAAO,KAAK,CACvC,OAAO,EAAa,KAAK,MAAM,KAMnC,SAAgB,EAAuB,EAAqB,EAA+B,CACzF,IAAM,EAAa,EAAwB,EAAM,CAEjD,GAAI,CAAC,EACH,OAAO,KAGT,GAAI,CACF,IAAM,EAAU,EAAkB,CAAE,MAAK,KAAM,EAAY,CAAC,CACtD,EAAc,EAAQ,KAAK,OAAS,EAAI,IAAI,EAAQ,KAAK,IAAI,OAAO,CAAC,KAAK,KAAK,CAAC,GAAK,KAE3F,MAAO,GAAG,EAAQ,YAAY,SACxB,CACN,IAAM,EAAW,EAAW,MAAM,EAAG,GAAG,CAAC,aAAa,CAEtD,IAAK,IAAM,KAAW,EAChB,KAAQ,OAAS,SAKjB,EADc,GAAG,EAAQ,KAAK,GAAG,EAAQ,OAAO,IAAK,GAAU,EAAM,KAAK,CAAC,KAAK,IAAI,CAAC,GACxD,CAAC,aAAa,GAAK,EAClD,MAAO,GAAG,EAAQ,KAAK,IAK7B,OAAO"}
|
|
1
|
+
{"version":3,"file":"_utils.js","names":[],"sources":["../../../src/transfer-service/markr/_utils.ts"],"sourcesContent":["import { ErrorCode, ErrorReason, SdkError } from '../../errors';\nimport { BaseError, decodeErrorResult, type Hex, isHex, toFunctionSelector } from 'viem';\nimport {\n type QuoteResponseData,\n type SupportedChainsResponseItemEvm,\n type SupportedChainsResponseItemSvm,\n type TokenListResponse,\n} from './_schema';\nimport { ERC_ZERO_ADDRESS, NATIVE_SOL_ADDRESS, ServiceType, TokenType } from '../../constants';\nimport { isSolanaNamespace } from '../../_utils/chain';\nimport { calculateMinimumAmountOut } from '../../_utils/math';\nimport { eip155ChainIdToCaip2 } from '../../utils/caip';\nimport type { Asset } from '../../types/asset';\nimport type { Caip2ChainId } from '../../types/caip';\nimport type { Quote, QuoteFee, QuoteFees, QuoteFeeToken, QuoterProps } from '../../types/quote';\nimport { markrGetInfoChains, markrGetPartnerInfo, markrGetTokenList, type ApiOptions } from './_api';\nimport { isEvmAddress } from '../../utils/evm-address';\nimport { isSolAddress } from '../../utils/sol-address';\n\nexport type SupportedChainsMap = Map<\n Caip2ChainId,\n {\n /** `number` for EVM, `Caip2ChainId` for SVM */\n chainId: number | Caip2ChainId;\n crossChainSwapEnabled: boolean;\n crossChainTargetChainIds: ReadonlySet<Caip2ChainId>;\n swapEnabled: boolean;\n tokenList: boolean;\n }\n>;\n\n/**\n * Checks whether the given source → target chain route is supported by Markr.\n */\nexport function isRouteSupported(\n supportedChains: SupportedChainsMap,\n sourceChainId: Caip2ChainId,\n targetChainId: Caip2ChainId,\n): boolean {\n const sourceChain = supportedChains.get(sourceChainId);\n const targetChain = supportedChains.get(targetChainId);\n\n if (!sourceChain || !targetChain) return false;\n\n if (sourceChainId === targetChainId) {\n return sourceChain.swapEnabled;\n }\n\n return sourceChain.crossChainSwapEnabled && sourceChain.crossChainTargetChainIds.has(targetChainId);\n}\n\nexport async function getSupportedChains(\n apiOptions: ApiOptions,\n disableCrossChainSwaps = false,\n): Promise<SupportedChainsMap> {\n const supportedChains: SupportedChainsMap = new Map();\n\n try {\n const chains = await markrGetInfoChains(apiOptions);\n const filteredSupportedChains = chains.filter(\n (chain): chain is SupportedChainsResponseItemEvm | SupportedChainsResponseItemSvm => {\n // Only include chains types that we support in the SDK (EVM and Solana for now).\n return chain.chainType === 'evm' || chain.chainType === 'svm';\n },\n );\n\n for (const chain of filteredSupportedChains) {\n const key: Caip2ChainId = typeof chain.chainId === 'number' ? eip155ChainIdToCaip2(chain.chainId) : chain.chainId;\n\n const isCrossChainSwapEnabled =\n chain.enabled_services.includes('cross-chain-quote') && chain.enabled_services.includes('cross-chain-swap');\n const isSwapEnabled = chain.enabled_services.includes('quote') && chain.enabled_services.includes('swap');\n const normalizedLaneChainIds = new Set<Caip2ChainId>();\n\n for (const lane of chain.lanes) {\n const laneChainId = typeof lane === 'number' ? eip155ChainIdToCaip2(lane) : lane;\n\n if (laneChainId !== key) {\n normalizedLaneChainIds.add(laneChainId);\n }\n }\n\n const crossChainSwapEnabled = disableCrossChainSwaps ? false : isCrossChainSwapEnabled;\n const crossChainTargetChainIds = crossChainSwapEnabled ? normalizedLaneChainIds : new Set<Caip2ChainId>();\n\n if (!isSwapEnabled && crossChainTargetChainIds.size === 0) {\n continue;\n }\n\n supportedChains.set(key, {\n chainId: chain.chainId,\n crossChainSwapEnabled,\n crossChainTargetChainIds,\n swapEnabled: isSwapEnabled,\n tokenList: chain.enabled_services.includes('token-list'),\n });\n }\n } catch (error) {\n throw new SdkError(ErrorReason.UNKNOWN, ErrorCode.INITIALIZATION_FAILED, {\n cause: error,\n details: 'Failed to fetch supported chains from Markr API.',\n });\n }\n\n return supportedChains;\n}\n\nexport async function getSupportedTokens(\n apiOptions: ApiOptions,\n supportedChains: SupportedChainsMap,\n): Promise<Map<Caip2ChainId, Promise<TokenListResponse>>> {\n // Parallel fetch token lists for all supported chains.\n const supportedTokens: Map<Caip2ChainId, Promise<TokenListResponse>> = new Map();\n\n for (const [caip2ChainId, chainInfo] of supportedChains.entries()) {\n // Only fetch token list for EVM chains that support swaps.\n if (\n typeof chainInfo.chainId === 'number' &&\n chainInfo.tokenList &&\n (chainInfo.crossChainSwapEnabled || chainInfo.swapEnabled)\n ) {\n try {\n const tokenListPromise = markrGetTokenList(apiOptions, chainInfo.chainId);\n supportedTokens.set(caip2ChainId, tokenListPromise);\n } catch {\n // Ignore errors for individual token list fetches.\n // TODO: Logger?\n }\n }\n }\n\n return supportedTokens;\n}\n\n/**\n * Determine if the provided token address represents the native token for its chain.\n *\n * Markr represents EVM native tokens as the zero address and Solana native SOL\n * as the wrapped SOL mint address.\n */\nexport function isTokenAddressNative(address: string): boolean {\n return address === ERC_ZERO_ADDRESS || address === NATIVE_SOL_ADDRESS;\n}\n\n/**\n * Convert an `Asset` to the address string expected by the Markr API.\n *\n * For NATIVE assets the representation depends on the chain:\n * - EVM chains: `0x0000...0000` (ERC zero address)\n * - Solana chains: `So11111111111111111111111111111111111111112` (wrapped SOL mint)\n *\n * @param asset The asset to convert.\n * @param chainId CAIP-2 chain ID used to disambiguate NATIVE assets across chain types.\n */\nexport function assetToAddressString(asset: Asset, chainId: Caip2ChainId): string {\n if (asset.type === TokenType.NATIVE) {\n if (isSolanaNamespace(chainId)) {\n return NATIVE_SOL_ADDRESS;\n }\n\n return ERC_ZERO_ADDRESS;\n }\n\n return asset.address;\n}\n\n/**\n * Markr rejects `minAmountOut=0` for non-zero quotes.\n *\n * For very small quotes, integer truncation after slippage can produce `0`.\n * Clamp to `1` in that edge case to satisfy Markr API validation while\n * preserving normal slippage behavior for larger quotes.\n */\nexport function calculateMarkrMinimumAmountOut({\n amountOut,\n assetOut,\n slippageBps,\n}: Pick<Quote, 'amountOut' | 'assetOut' | 'slippageBps'>): bigint {\n const minAmountOut = calculateMinimumAmountOut({ amountOut, assetOut, slippageBps });\n\n if (amountOut > 0n && minAmountOut === 0n) {\n return 1n;\n }\n\n return minAmountOut;\n}\n\nexport function quoteFromMarkrQuoteResponseData(\n data: QuoteResponseData,\n quoterProps: QuoterProps,\n partnerFeeBps: number,\n): Quote {\n const partnerFee: bigint = (data.amountOut * BigInt(partnerFeeBps)) / 10_000n;\n const amountOutAfterFees: bigint = data.amountOut - partnerFee;\n\n const fees: QuoteFees = [\n ...mapMarkrQuoteResponseDataFeesToQuoteFees(data.fees),\n // Add the partner fee as a QuoteFee component for Markr quotes.\n {\n type: 'partner',\n name: 'Core Fee',\n amount: partnerFee,\n chainId: quoterProps.targetChain.chainId,\n token: assetToFeeToken(quoterProps.targetAsset),\n },\n ];\n\n return {\n aggregator: {\n id: data.aggregator.id,\n logoUrl: data.aggregator.logo_url,\n name: data.aggregator.name,\n },\n amountIn: data.amountIn,\n amountOut: amountOutAfterFees,\n assetIn: quoterProps.sourceAsset,\n assetOut: quoterProps.targetAsset,\n expiresAt: data.expiredAt, // Markr returns `expiredAt` as Unix time in seconds; use as-is.\n fees,\n fromAddress: quoterProps.fromAddress,\n /**\n * This gasEstimate is rough or may be missing.\n * Consumers should use TransferManager.estimateGas for a more accurate estimate.\n */\n gasEstimate: data.gasEstimate,\n id: data.uuid,\n partnerFeeBps,\n serviceType: ServiceType.MARKR,\n slippageBps: quoterProps.slippageBps ?? data.recommendedSlippage,\n sourceChain: quoterProps.sourceChain,\n targetChain: quoterProps.targetChain,\n toAddress: quoterProps.toAddress,\n } satisfies Quote;\n}\n\nexport async function getPartnerFeeBps(apiOptions: ApiOptions): Promise<number> {\n try {\n const partnerInfo = await markrGetPartnerInfo(apiOptions);\n return partnerInfo.fee;\n } catch (error) {\n throw new SdkError(ErrorReason.UNKNOWN, ErrorCode.INITIALIZATION_FAILED, {\n cause: error,\n details: 'Failed to fetch partner info from Markr API.',\n });\n }\n}\n\nexport function mapMarkrQuoteResponseDataFeesToQuoteFees(markrFees: QuoteResponseData['fees']): QuoteFees {\n if (!markrFees) {\n return [];\n }\n\n const fees: QuoteFee[] = [];\n\n for (const fee of markrFees) {\n const chainId = typeof fee.token.chainId === 'number' ? eip155ChainIdToCaip2(fee.token.chainId) : fee.token.chainId;\n\n let token: QuoteFeeToken | undefined;\n\n if (isTokenAddressNative(fee.token.address)) {\n token = { type: TokenType.NATIVE };\n } else if (isEvmAddress(fee.token.address)) {\n token = { type: TokenType.ERC20, address: fee.token.address };\n } else if (isSolAddress(fee.token.address)) {\n token = { type: TokenType.SPL, address: fee.token.address };\n }\n\n if (!token) {\n // Skip fee if we can't determine token type.\n continue;\n }\n\n fees.push({\n type: fee.type,\n name: fee.name,\n amount: fee.amount,\n chainId,\n token,\n });\n }\n\n return fees;\n}\n\nfunction assetToFeeToken(asset: Asset): QuoteFeeToken {\n if (asset.type === TokenType.NATIVE) {\n return { type: TokenType.NATIVE };\n }\n\n if (asset.type === TokenType.SPL) {\n return { type: TokenType.SPL, address: asset.address };\n }\n\n return { type: TokenType.ERC20, address: asset.address };\n}\n\nexport type MarkrRouterAbi =\n | (typeof import('./_abis/swap-wrapper-abi'))['MARKR_SWAP_WRAPPER_ABI']\n | (typeof import('./_abis/cross-chain-swap-wrapper-abi'))['MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI'];\n\nexport async function getMarkrSwapWrapperAbi(crossChain: boolean): Promise<MarkrRouterAbi> {\n if (crossChain) {\n return (await import('./_abis/cross-chain-swap-wrapper-abi')).MARKR_CROSS_CHAIN_SWAP_WRAPPER_ABI;\n }\n\n return (await import('./_abis/swap-wrapper-abi')).MARKR_SWAP_WRAPPER_ABI;\n}\n\nexport function extractHexDataFromError(error: unknown): Hex | undefined {\n if (error instanceof BaseError) {\n const directData = (error as { data?: unknown }).data;\n if (isHex(directData)) {\n return directData;\n }\n\n let walkedData: Hex | undefined;\n error.walk((walkedError) => {\n const nestedData = (walkedError as { data?: unknown }).data;\n if (!walkedData && isHex(nestedData)) {\n walkedData = nestedData;\n }\n return false;\n });\n\n if (walkedData) {\n return walkedData;\n }\n\n const causeData = (error as { cause?: { data?: unknown } }).cause?.data;\n if (isHex(causeData)) {\n return causeData;\n }\n }\n\n if (!error || typeof error !== 'object') {\n return undefined;\n }\n\n const genericError = error as {\n data?: unknown;\n error?: { data?: unknown };\n cause?: { data?: unknown };\n response?: { data?: unknown };\n body?: { error?: { data?: unknown } };\n };\n\n if (isHex(genericError.data)) {\n return genericError.data;\n }\n\n if (isHex(genericError.error?.data)) {\n return genericError.error.data;\n }\n\n if (isHex(genericError.cause?.data)) {\n return genericError.cause.data;\n }\n\n if (isHex(genericError.response?.data)) {\n return genericError.response.data;\n }\n\n if (isHex(genericError.body?.error?.data)) {\n return genericError.body.error.data;\n }\n\n return undefined;\n}\n\nexport function decodeMarkrRevertError(abi: MarkrRouterAbi, error: unknown): string | null {\n const revertData = extractHexDataFromError(error);\n\n if (!revertData) {\n return null;\n }\n\n try {\n const decoded = decodeErrorResult({ abi, data: revertData });\n const decodedArgs = decoded.args.length > 0 ? `(${decoded.args.map(String).join(', ')})` : '()';\n\n return `${decoded.errorName}${decodedArgs}`;\n } catch {\n const selector = revertData.slice(0, 10).toLowerCase();\n\n for (const abiItem of abi) {\n if (abiItem.type !== 'error') {\n continue;\n }\n\n const signature = `${abiItem.name}(${abiItem.inputs.map((input) => input.type).join(',')})`;\n if (toFunctionSelector(signature).toLowerCase() === selector) {\n return `${abiItem.name}()`;\n }\n }\n }\n\n return null;\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.cjs`),r=require(`../../_evm-gas.cjs`),i=require(`../_utils.cjs`);let a=require(`viem`);function o({chainConfigs:o}){return async(s,c)=>{if(s.serviceType!==e.ServiceType.WRAP_UNWRAP)throw new t.SdkError(t.ErrorReason.INCORRECT_PROVIDER_PROVIDED,t.ErrorCode.INVALID_PARAMS);let l=s.fromAddress;if(!(0,a.isAddress)(l))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let u=s.sourceChain.chainId,d=i.getWrapDirection(s.assetIn,s.assetOut,u,o);if(!d)throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`Quote does not represent a valid wrap/unwrap pair.`});let f=n.getEvmClientForChain({chain:s.sourceChain}),p=await i.estimateWrapUnwrapGas({direction:d,amountIn:s.amountIn,contractAddress:i.getWrapperContractAddress(u,o),fromAddress:l,client:f,estimateGasMarginBps:c?.feeUnitsMarginBps}),m=await r.estimateEvmFeesPerGas(f,s.sourceChain,c?.overrides?.feeRateTier),h=c?.overrides?.maxFeePerGas??m.maxFeePerGas,g=c?.overrides?.maxPriorityFeePerGas??m.maxPriorityFeePerGas,_=p*h;return{asset:s.sourceChain.networkToken,totalFee:_,meta:{maxFeePerGas:h,maxPriorityFeePerGas:g}}}}exports.estimateNativeFeeFactory=o;
|
|
1
|
+
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../_utils.cjs`),r=require(`../../_evm-gas.cjs`),i=require(`../_utils.cjs`);let a=require(`viem`);function o({chainConfigs:o}){return async(s,c)=>{if(s.serviceType!==e.ServiceType.WRAP_UNWRAP)throw new t.SdkError(t.ErrorReason.INCORRECT_PROVIDER_PROVIDED,t.ErrorCode.INVALID_PARAMS);let l=s.fromAddress;if(!(0,a.isAddress)(l))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let u=s.sourceChain.chainId,d=i.getWrapDirection(s.assetIn,s.assetOut,u,o);if(!d)throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`Quote does not represent a valid wrap/unwrap pair.`});let f=n.getEvmClientForChain({chain:s.sourceChain}),p=await i.estimateWrapUnwrapGas({direction:d,amountIn:s.amountIn,contractAddress:i.getWrapperContractAddress(u,o),fromAddress:l,client:f,estimateGasMarginBps:c?.feeUnitsMarginBps}),m=await r.estimateEvmFeesPerGas(f,s.sourceChain,c?.overrides?.feeRateTier),h=c?.overrides?.maxFeePerGas??m.maxFeePerGas,g=c?.overrides?.maxPriorityFeePerGas??m.maxPriorityFeePerGas,_=p*h;return{asset:s.sourceChain.networkToken,totalFee:_,totalUpfrontFee:_,meta:{maxFeePerGas:h,maxPriorityFeePerGas:g}}}}exports.estimateNativeFeeFactory=o;
|
|
2
2
|
//# sourceMappingURL=estimate-native-fee.cjs.map
|