@avalabs/fusion-sdk 0.14.2 → 0.14.4

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.
@@ -1,2 +1,2 @@
1
- require(`../../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../../errors.cjs`),t=require(`../../../_utils.cjs`);let n=require(`viem`),r=require(`@lombard.finance/sdk`);function i({bitcoinFunctions:e,config:n}){return({transfer:r,updateListener:i})=>{let s=new AbortController,c=()=>{s.abort()};return r.status===`completed`||r.status===`failed`?{cancel:c,result:Promise.resolve(r)}:{cancel:c,result:(async()=>{let c=structuredClone(r),l=t.getEvmClientForChain({chain:r.sourceChain});for(;!s.signal.aborted;){let r=c.status;switch(c.status){case`source-pending`:c=await a({currentTransfer:c,signal:s.signal,sourceClient:l}),s.signal.aborted||i(c);break;case`source-completed`:case`target-pending`:c=await o({bitcoinFunctions:e,config:n,currentTransfer:c,signal:s.signal}),s.signal.aborted||i(c);break;default:return c}c.status===r&&await t.waitForTimeoutOrAbort({timeoutMs:6e4,signal:s.signal})}return c})()}}}async function a({currentTransfer:r,signal:i,sourceClient:a}){let{confirmationCount:o,requiredConfirmationCount:s,txHash:c}=r.source;if(!(0,n.isHash)(c))return{...r,errorCode:e.ErrorCode.INVALID_PARAMS,errorReason:`Invalid source transaction hash`,failedAtMs:Date.now(),status:`failed`};if(o>=s)return{...r,status:`source-completed`};try{let n=await t.awaitOrAbort(a.waitForTransactionReceipt({confirmations:Math.min(o+1,s),hash:c}),i);if(n.status===`aborted`)return r;let l=n.value;if(l.status===`reverted`)return{...r,errorCode:e.ErrorCode.TRANSACTION_REVERTED,errorReason:`Source transaction was reverted`,failedAtMs:Date.now(),status:`failed`};let u=await a.getTransactionConfirmations({transactionReceipt:l}).then(e=>Number(e)).catch(()=>o+1);return u<s?{...r,source:{...r.source,confirmationCount:u}}:{...r,source:{...r.source,confirmationCount:u},status:`source-completed`}}catch{return r}}async function o({bitcoinFunctions:n,config:i,currentTransfer:a,signal:o}){switch(a.status){case`source-completed`:try{let e=await t.awaitOrAbort((0,r.getUnstakesByAddress)({address:a.fromAddress,env:i.env}),o);if(e.status===`aborted`)return a;let n=e.value.find(e=>e.txHash.toLowerCase()===a.source.txHash.toLowerCase());return n?.payoutTxHash?{...a,status:`target-pending`,target:{confirmationCount:0,requiredConfirmationCount:1,startedAtMs:Date.now(),txHash:n.payoutTxHash}}:a}catch{return a}default:if(!a.target?.txHash)return{...a,errorCode:e.ErrorCode.UNKNOWN,errorReason:`Missing target transaction hash`,failedAtMs:Date.now(),status:`failed`};try{let e=await t.awaitOrAbort(n.getTransaction(a.target.txHash),o);if(e.status===`aborted`)return a;let r=e.value.confirmations;return r<a.target.requiredConfirmationCount?{...a,target:{...a.target,confirmationCount:r}}:{...a,completedAtMs:Date.now(),target:{...a.target,confirmationCount:r},status:`completed`}}catch{return a}}}exports.trackTransferFactory=i;
1
+ require(`../../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../../errors.cjs`),t=require(`../../../_utils.cjs`);let n=require(`viem`),r=require(`@lombard.finance/sdk`);function i({bitcoinFunctions:e,config:n}){return({transfer:r,updateListener:i})=>{let s=new AbortController,c=()=>{s.abort()};return r.status===`completed`||r.status===`failed`?{cancel:c,result:Promise.resolve(r)}:{cancel:c,result:(async()=>{let c=structuredClone(r),l=t.getEvmClientForChain({chain:r.sourceChain});for(;!s.signal.aborted;){let r=c.status;switch(c.status){case`source-pending`:c=await a({currentTransfer:c,signal:s.signal,sourceClient:l}),s.signal.aborted||i(c);break;case`source-completed`:case`target-pending`:c=await o({bitcoinFunctions:e,config:n,currentTransfer:c,signal:s.signal}),s.signal.aborted||i(c);break;default:return c}c.status===r&&await t.waitForTimeoutOrAbort({timeoutMs:6e4,signal:s.signal})}return c})()}}}async function a({currentTransfer:r,signal:i,sourceClient:a}){let{confirmationCount:o,requiredConfirmationCount:s,txHash:c}=r.source;if(!(0,n.isHash)(c))return{...r,errorCode:e.ErrorCode.INVALID_PARAMS,errorReason:`Invalid source transaction hash`,failedAtMs:Date.now(),status:`failed`};if(o>=s)return{...r,status:`source-completed`};try{let n=await t.awaitOrAbort(a.waitForTransactionReceipt({hash:c}),i);if(n.status===`aborted`)return r;let l=n.value;if(l.status===`reverted`)return{...r,errorCode:e.ErrorCode.TRANSACTION_REVERTED,errorReason:`Source transaction was reverted`,failedAtMs:Date.now(),status:`failed`};let u=await t.awaitOrAbort(a.getTransactionConfirmations({transactionReceipt:l}).then(e=>Math.max(Number(e),0)).catch(()=>Math.max(o,0)),i);if(u.status===`aborted`)return r;let d=u.value;return d<s?{...r,source:{...r.source,confirmationCount:d}}:{...r,source:{...r.source,confirmationCount:d},status:`source-completed`}}catch{return r}}async function o({bitcoinFunctions:n,config:i,currentTransfer:a,signal:o}){switch(a.status){case`source-completed`:try{let e=await t.awaitOrAbort((0,r.getUnstakesByAddress)({address:a.fromAddress,env:i.env}),o);if(e.status===`aborted`)return a;let n=e.value.find(e=>e.txHash.toLowerCase()===a.source.txHash.toLowerCase());return n?.payoutTxHash?{...a,status:`target-pending`,target:{confirmationCount:0,requiredConfirmationCount:1,startedAtMs:Date.now(),txHash:n.payoutTxHash}}:a}catch{return a}default:if(!a.target?.txHash)return{...a,errorCode:e.ErrorCode.UNKNOWN,errorReason:`Missing target transaction hash`,failedAtMs:Date.now(),status:`failed`};try{let e=await t.awaitOrAbort(n.getTransaction(a.target.txHash),o);if(e.status===`aborted`)return a;let r=e.value.confirmations;return r<a.target.requiredConfirmationCount?{...a,target:{...a.target,confirmationCount:r}}:{...a,completedAtMs:Date.now(),target:{...a.target,confirmationCount:r},status:`completed`}}catch{return a}}}exports.trackTransferFactory=i;
2
2
  //# sourceMappingURL=track-transfer.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"track-transfer.cjs","names":["getEvmClientForChain","waitForTimeoutOrAbort","ErrorCode","awaitOrAbort"],"sources":["../../../../../src/transfer-service/lombard/btcb-to-btc/_handlers/track-transfer.ts"],"sourcesContent":["import { isHash } from 'viem';\nimport { ErrorCode } from '../../../../errors';\nimport type { BitcoinFunctions } from '../../../../types/bitcoin';\nimport type { TransferService } from '../../../../types/service';\nimport type {\n CompletedTransfer,\n FailedTransfer,\n SourceCompletedTransfer,\n SourcePendingTransfer,\n TargetPendingTransfer,\n Transfer,\n} from '../../../../types/transfer';\nimport type { BtcbToBtcConfig } from '../../types';\nimport { awaitOrAbort, getEvmClientForChain, waitForTimeoutOrAbort } from '../../../_utils';\nimport { getUnstakesByAddress } from '@lombard.finance/sdk';\n\n// Polling interval for BTC redemptions (60 seconds - BTC confirmations are slow)\nconst REDEMPTION_POLLING_INTERVAL_MS = 1000 * 60;\n\nexport interface TrackTransferFactoryOptions {\n bitcoinFunctions: BitcoinFunctions;\n config: BtcbToBtcConfig;\n}\n\nexport function trackTransferFactory({\n bitcoinFunctions,\n config,\n}: TrackTransferFactoryOptions): TransferService['trackTransfer'] {\n return ({ transfer, updateListener }) => {\n const ac = new AbortController();\n const cancel = () => {\n ac.abort();\n };\n\n if (transfer.status === 'completed' || transfer.status === 'failed') {\n return {\n cancel,\n result: Promise.resolve(transfer),\n };\n }\n\n const executeTracking = async (): Promise<Transfer> => {\n let currentTransfer: Transfer = structuredClone(transfer);\n\n const sourceClient = getEvmClientForChain({ chain: transfer.sourceChain });\n\n while (!ac.signal.aborted) {\n const statusBeforeTracking = currentTransfer.status;\n\n switch (currentTransfer.status) {\n case 'source-pending': {\n currentTransfer = await _trackSourceTx({\n currentTransfer,\n signal: ac.signal,\n sourceClient,\n });\n\n if (!ac.signal.aborted) {\n updateListener(currentTransfer);\n }\n\n break;\n }\n case 'source-completed':\n case 'target-pending': {\n currentTransfer = await _trackTargetTx({\n bitcoinFunctions,\n config,\n currentTransfer,\n signal: ac.signal,\n });\n\n if (!ac.signal.aborted) {\n updateListener(currentTransfer);\n }\n\n break;\n }\n default: {\n return currentTransfer;\n }\n }\n\n const hasStatusChanged = currentTransfer.status !== statusBeforeTracking;\n\n if (!hasStatusChanged) {\n await waitForTimeoutOrAbort({ timeoutMs: REDEMPTION_POLLING_INTERVAL_MS, signal: ac.signal });\n }\n }\n\n return currentTransfer;\n };\n\n return {\n cancel,\n result: executeTracking(),\n };\n };\n}\n\nexport interface TrackBaseParams {\n currentTransfer: Transfer;\n signal: AbortSignal;\n}\n\nexport interface TrackSourceTxParams extends TrackBaseParams {\n currentTransfer: SourcePendingTransfer;\n sourceClient: ReturnType<typeof getEvmClientForChain>;\n}\n\nexport interface TrackTargetTxParams extends TrackBaseParams {\n bitcoinFunctions: BitcoinFunctions;\n config: BtcbToBtcConfig;\n currentTransfer: SourceCompletedTransfer | TargetPendingTransfer;\n}\n\nexport async function _trackSourceTx({\n currentTransfer,\n signal,\n sourceClient,\n}: TrackSourceTxParams): Promise<SourcePendingTransfer | SourceCompletedTransfer | FailedTransfer> {\n const { confirmationCount, requiredConfirmationCount, txHash } = currentTransfer.source;\n\n if (!isHash(txHash)) {\n const failedTransfer: FailedTransfer = {\n ...currentTransfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n\n return failedTransfer;\n }\n\n if (confirmationCount >= requiredConfirmationCount) {\n // Move to next stage\n\n const updatedTransfer: SourceCompletedTransfer = {\n ...currentTransfer,\n status: 'source-completed',\n };\n\n return updatedTransfer;\n }\n\n try {\n const receiptResult = await awaitOrAbort(\n sourceClient.waitForTransactionReceipt({\n confirmations: Math.min(confirmationCount + 1, requiredConfirmationCount),\n hash: txHash,\n }),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const transactionReceipt = receiptResult.value;\n\n if (transactionReceipt.status === 'reverted') {\n return {\n ...currentTransfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n } satisfies FailedTransfer;\n }\n\n const newConfirmationCount: number = await sourceClient\n .getTransactionConfirmations({\n transactionReceipt,\n })\n .then((count) => Number(count))\n .catch(() => confirmationCount + 1);\n\n // If still not enough confirmations, update the count\n if (newConfirmationCount < requiredConfirmationCount) {\n return {\n ...currentTransfer,\n source: {\n ...currentTransfer.source,\n confirmationCount: newConfirmationCount,\n },\n } satisfies SourcePendingTransfer;\n }\n\n // Move to next stage\n return {\n ...currentTransfer,\n source: {\n ...currentTransfer.source,\n confirmationCount: newConfirmationCount,\n },\n status: 'source-completed',\n } satisfies SourceCompletedTransfer;\n } catch {\n return currentTransfer;\n }\n}\n\nexport async function _trackTargetTx({\n bitcoinFunctions,\n config,\n currentTransfer,\n signal,\n}: TrackTargetTxParams): Promise<SourceCompletedTransfer | TargetPendingTransfer | FailedTransfer | CompletedTransfer> {\n switch (currentTransfer.status) {\n case 'source-completed': {\n try {\n const unstakesResult = await awaitOrAbort(\n getUnstakesByAddress({ address: currentTransfer.fromAddress, env: config.env }),\n signal,\n );\n\n if (unstakesResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const transferUnstake = unstakesResult.value.find(\n (d) => d.txHash.toLowerCase() === currentTransfer.source.txHash.toLowerCase(),\n );\n\n if (transferUnstake?.payoutTxHash) {\n const updatedTransfer: TargetPendingTransfer = {\n ...currentTransfer,\n status: 'target-pending',\n target: {\n confirmationCount: 0,\n requiredConfirmationCount: 1,\n startedAtMs: Date.now(),\n txHash: transferUnstake.payoutTxHash,\n },\n };\n\n return updatedTransfer;\n }\n\n return currentTransfer;\n } catch {\n return currentTransfer;\n }\n }\n default: {\n // target-pending\n if (!currentTransfer.target?.txHash) {\n // Fail if no target tx hash, should not reach here\n return {\n ...currentTransfer,\n errorCode: ErrorCode.UNKNOWN,\n errorReason: 'Missing target transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n } satisfies FailedTransfer;\n }\n\n try {\n const receiptResult = await awaitOrAbort(\n bitcoinFunctions.getTransaction(currentTransfer.target.txHash),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const targetConfirmationCount = receiptResult.value.confirmations;\n\n if (targetConfirmationCount < currentTransfer.target.requiredConfirmationCount) {\n return {\n ...currentTransfer,\n target: {\n ...currentTransfer.target,\n confirmationCount: targetConfirmationCount,\n },\n } satisfies TargetPendingTransfer;\n }\n\n // Completed\n return {\n ...currentTransfer,\n completedAtMs: Date.now(),\n target: {\n ...currentTransfer.target,\n confirmationCount: targetConfirmationCount,\n },\n status: 'completed',\n } satisfies CompletedTransfer;\n } catch {\n return currentTransfer;\n }\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"track-transfer.cjs","names":["getEvmClientForChain","waitForTimeoutOrAbort","ErrorCode","awaitOrAbort"],"sources":["../../../../../src/transfer-service/lombard/btcb-to-btc/_handlers/track-transfer.ts"],"sourcesContent":["import { isHash } from 'viem';\nimport { ErrorCode } from '../../../../errors';\nimport type { BitcoinFunctions } from '../../../../types/bitcoin';\nimport type { TransferService } from '../../../../types/service';\nimport type {\n CompletedTransfer,\n FailedTransfer,\n SourceCompletedTransfer,\n SourcePendingTransfer,\n TargetPendingTransfer,\n Transfer,\n} from '../../../../types/transfer';\nimport type { BtcbToBtcConfig } from '../../types';\nimport { awaitOrAbort, getEvmClientForChain, waitForTimeoutOrAbort } from '../../../_utils';\nimport { getUnstakesByAddress } from '@lombard.finance/sdk';\n\n// Polling interval for BTC redemptions (60 seconds - BTC confirmations are slow)\nconst REDEMPTION_POLLING_INTERVAL_MS = 1000 * 60;\n\nexport interface TrackTransferFactoryOptions {\n bitcoinFunctions: BitcoinFunctions;\n config: BtcbToBtcConfig;\n}\n\nexport function trackTransferFactory({\n bitcoinFunctions,\n config,\n}: TrackTransferFactoryOptions): TransferService['trackTransfer'] {\n return ({ transfer, updateListener }) => {\n const ac = new AbortController();\n const cancel = () => {\n ac.abort();\n };\n\n if (transfer.status === 'completed' || transfer.status === 'failed') {\n return {\n cancel,\n result: Promise.resolve(transfer),\n };\n }\n\n const executeTracking = async (): Promise<Transfer> => {\n let currentTransfer: Transfer = structuredClone(transfer);\n\n const sourceClient = getEvmClientForChain({ chain: transfer.sourceChain });\n\n while (!ac.signal.aborted) {\n const statusBeforeTracking = currentTransfer.status;\n\n switch (currentTransfer.status) {\n case 'source-pending': {\n currentTransfer = await _trackSourceTx({\n currentTransfer,\n signal: ac.signal,\n sourceClient,\n });\n\n if (!ac.signal.aborted) {\n updateListener(currentTransfer);\n }\n\n break;\n }\n case 'source-completed':\n case 'target-pending': {\n currentTransfer = await _trackTargetTx({\n bitcoinFunctions,\n config,\n currentTransfer,\n signal: ac.signal,\n });\n\n if (!ac.signal.aborted) {\n updateListener(currentTransfer);\n }\n\n break;\n }\n default: {\n return currentTransfer;\n }\n }\n\n const hasStatusChanged = currentTransfer.status !== statusBeforeTracking;\n\n if (!hasStatusChanged) {\n await waitForTimeoutOrAbort({ timeoutMs: REDEMPTION_POLLING_INTERVAL_MS, signal: ac.signal });\n }\n }\n\n return currentTransfer;\n };\n\n return {\n cancel,\n result: executeTracking(),\n };\n };\n}\n\nexport interface TrackBaseParams {\n currentTransfer: Transfer;\n signal: AbortSignal;\n}\n\nexport interface TrackSourceTxParams extends TrackBaseParams {\n currentTransfer: SourcePendingTransfer;\n sourceClient: ReturnType<typeof getEvmClientForChain>;\n}\n\nexport interface TrackTargetTxParams extends TrackBaseParams {\n bitcoinFunctions: BitcoinFunctions;\n config: BtcbToBtcConfig;\n currentTransfer: SourceCompletedTransfer | TargetPendingTransfer;\n}\n\nexport async function _trackSourceTx({\n currentTransfer,\n signal,\n sourceClient,\n}: TrackSourceTxParams): Promise<SourcePendingTransfer | SourceCompletedTransfer | FailedTransfer> {\n const { confirmationCount, requiredConfirmationCount, txHash } = currentTransfer.source;\n\n if (!isHash(txHash)) {\n const failedTransfer: FailedTransfer = {\n ...currentTransfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n\n return failedTransfer;\n }\n\n if (confirmationCount >= requiredConfirmationCount) {\n // Move to next stage\n\n const updatedTransfer: SourceCompletedTransfer = {\n ...currentTransfer,\n status: 'source-completed',\n };\n\n return updatedTransfer;\n }\n\n try {\n const receiptResult = await awaitOrAbort(\n sourceClient.waitForTransactionReceipt({\n hash: txHash,\n }),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const transactionReceipt = receiptResult.value;\n\n if (transactionReceipt.status === 'reverted') {\n return {\n ...currentTransfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n } satisfies FailedTransfer;\n }\n\n const newConfirmationCountResult = await awaitOrAbort(\n sourceClient\n .getTransactionConfirmations({\n transactionReceipt,\n })\n .then((count) => Math.max(Number(count), 0))\n .catch(() => Math.max(confirmationCount, 0)),\n signal,\n );\n\n if (newConfirmationCountResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const newConfirmationCount = newConfirmationCountResult.value;\n\n // If still not enough confirmations, update the count\n if (newConfirmationCount < requiredConfirmationCount) {\n return {\n ...currentTransfer,\n source: {\n ...currentTransfer.source,\n confirmationCount: newConfirmationCount,\n },\n } satisfies SourcePendingTransfer;\n }\n\n // Move to next stage\n return {\n ...currentTransfer,\n source: {\n ...currentTransfer.source,\n confirmationCount: newConfirmationCount,\n },\n status: 'source-completed',\n } satisfies SourceCompletedTransfer;\n } catch {\n return currentTransfer;\n }\n}\n\nexport async function _trackTargetTx({\n bitcoinFunctions,\n config,\n currentTransfer,\n signal,\n}: TrackTargetTxParams): Promise<SourceCompletedTransfer | TargetPendingTransfer | FailedTransfer | CompletedTransfer> {\n switch (currentTransfer.status) {\n case 'source-completed': {\n try {\n const unstakesResult = await awaitOrAbort(\n getUnstakesByAddress({ address: currentTransfer.fromAddress, env: config.env }),\n signal,\n );\n\n if (unstakesResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const transferUnstake = unstakesResult.value.find(\n (d) => d.txHash.toLowerCase() === currentTransfer.source.txHash.toLowerCase(),\n );\n\n if (transferUnstake?.payoutTxHash) {\n const updatedTransfer: TargetPendingTransfer = {\n ...currentTransfer,\n status: 'target-pending',\n target: {\n confirmationCount: 0,\n requiredConfirmationCount: 1,\n startedAtMs: Date.now(),\n txHash: transferUnstake.payoutTxHash,\n },\n };\n\n return updatedTransfer;\n }\n\n return currentTransfer;\n } catch {\n return currentTransfer;\n }\n }\n default: {\n // target-pending\n if (!currentTransfer.target?.txHash) {\n // Fail if no target tx hash, should not reach here\n return {\n ...currentTransfer,\n errorCode: ErrorCode.UNKNOWN,\n errorReason: 'Missing target transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n } satisfies FailedTransfer;\n }\n\n try {\n const receiptResult = await awaitOrAbort(\n bitcoinFunctions.getTransaction(currentTransfer.target.txHash),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const targetConfirmationCount = receiptResult.value.confirmations;\n\n if (targetConfirmationCount < currentTransfer.target.requiredConfirmationCount) {\n return {\n ...currentTransfer,\n target: {\n ...currentTransfer.target,\n confirmationCount: targetConfirmationCount,\n },\n } satisfies TargetPendingTransfer;\n }\n\n // Completed\n return {\n ...currentTransfer,\n completedAtMs: Date.now(),\n target: {\n ...currentTransfer.target,\n confirmationCount: targetConfirmationCount,\n },\n status: 'completed',\n } satisfies CompletedTransfer;\n } catch {\n return currentTransfer;\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{ErrorCode as e}from"../../../../errors.js";import{awaitOrAbort as t,getEvmClientForChain as n,waitForTimeoutOrAbort as r}from"../../../_utils.js";import{isHash as i}from"viem";import{getUnstakesByAddress as a}from"@lombard.finance/sdk";function o({bitcoinFunctions:e,config:t}){return({transfer:i,updateListener:a})=>{let o=new AbortController,l=()=>{o.abort()};return i.status===`completed`||i.status===`failed`?{cancel:l,result:Promise.resolve(i)}:{cancel:l,result:(async()=>{let l=structuredClone(i),u=n({chain:i.sourceChain});for(;!o.signal.aborted;){let n=l.status;switch(l.status){case`source-pending`:l=await s({currentTransfer:l,signal:o.signal,sourceClient:u}),o.signal.aborted||a(l);break;case`source-completed`:case`target-pending`:l=await c({bitcoinFunctions:e,config:t,currentTransfer:l,signal:o.signal}),o.signal.aborted||a(l);break;default:return l}l.status===n&&await r({timeoutMs:6e4,signal:o.signal})}return l})()}}}async function s({currentTransfer:n,signal:r,sourceClient:a}){let{confirmationCount:o,requiredConfirmationCount:s,txHash:c}=n.source;if(!i(c))return{...n,errorCode:e.INVALID_PARAMS,errorReason:`Invalid source transaction hash`,failedAtMs:Date.now(),status:`failed`};if(o>=s)return{...n,status:`source-completed`};try{let i=await t(a.waitForTransactionReceipt({confirmations:Math.min(o+1,s),hash:c}),r);if(i.status===`aborted`)return n;let l=i.value;if(l.status===`reverted`)return{...n,errorCode:e.TRANSACTION_REVERTED,errorReason:`Source transaction was reverted`,failedAtMs:Date.now(),status:`failed`};let u=await a.getTransactionConfirmations({transactionReceipt:l}).then(e=>Number(e)).catch(()=>o+1);return u<s?{...n,source:{...n.source,confirmationCount:u}}:{...n,source:{...n.source,confirmationCount:u},status:`source-completed`}}catch{return n}}async function c({bitcoinFunctions:n,config:r,currentTransfer:i,signal:o}){switch(i.status){case`source-completed`:try{let e=await t(a({address:i.fromAddress,env:r.env}),o);if(e.status===`aborted`)return i;let n=e.value.find(e=>e.txHash.toLowerCase()===i.source.txHash.toLowerCase());return n?.payoutTxHash?{...i,status:`target-pending`,target:{confirmationCount:0,requiredConfirmationCount:1,startedAtMs:Date.now(),txHash:n.payoutTxHash}}:i}catch{return i}default:if(!i.target?.txHash)return{...i,errorCode:e.UNKNOWN,errorReason:`Missing target transaction hash`,failedAtMs:Date.now(),status:`failed`};try{let e=await t(n.getTransaction(i.target.txHash),o);if(e.status===`aborted`)return i;let r=e.value.confirmations;return r<i.target.requiredConfirmationCount?{...i,target:{...i.target,confirmationCount:r}}:{...i,completedAtMs:Date.now(),target:{...i.target,confirmationCount:r},status:`completed`}}catch{return i}}}export{o as trackTransferFactory};
1
+ import{ErrorCode as e}from"../../../../errors.js";import{awaitOrAbort as t,getEvmClientForChain as n,waitForTimeoutOrAbort as r}from"../../../_utils.js";import{isHash as i}from"viem";import{getUnstakesByAddress as a}from"@lombard.finance/sdk";function o({bitcoinFunctions:e,config:t}){return({transfer:i,updateListener:a})=>{let o=new AbortController,l=()=>{o.abort()};return i.status===`completed`||i.status===`failed`?{cancel:l,result:Promise.resolve(i)}:{cancel:l,result:(async()=>{let l=structuredClone(i),u=n({chain:i.sourceChain});for(;!o.signal.aborted;){let n=l.status;switch(l.status){case`source-pending`:l=await s({currentTransfer:l,signal:o.signal,sourceClient:u}),o.signal.aborted||a(l);break;case`source-completed`:case`target-pending`:l=await c({bitcoinFunctions:e,config:t,currentTransfer:l,signal:o.signal}),o.signal.aborted||a(l);break;default:return l}l.status===n&&await r({timeoutMs:6e4,signal:o.signal})}return l})()}}}async function s({currentTransfer:n,signal:r,sourceClient:a}){let{confirmationCount:o,requiredConfirmationCount:s,txHash:c}=n.source;if(!i(c))return{...n,errorCode:e.INVALID_PARAMS,errorReason:`Invalid source transaction hash`,failedAtMs:Date.now(),status:`failed`};if(o>=s)return{...n,status:`source-completed`};try{let i=await t(a.waitForTransactionReceipt({hash:c}),r);if(i.status===`aborted`)return n;let l=i.value;if(l.status===`reverted`)return{...n,errorCode:e.TRANSACTION_REVERTED,errorReason:`Source transaction was reverted`,failedAtMs:Date.now(),status:`failed`};let u=await t(a.getTransactionConfirmations({transactionReceipt:l}).then(e=>Math.max(Number(e),0)).catch(()=>Math.max(o,0)),r);if(u.status===`aborted`)return n;let d=u.value;return d<s?{...n,source:{...n.source,confirmationCount:d}}:{...n,source:{...n.source,confirmationCount:d},status:`source-completed`}}catch{return n}}async function c({bitcoinFunctions:n,config:r,currentTransfer:i,signal:o}){switch(i.status){case`source-completed`:try{let e=await t(a({address:i.fromAddress,env:r.env}),o);if(e.status===`aborted`)return i;let n=e.value.find(e=>e.txHash.toLowerCase()===i.source.txHash.toLowerCase());return n?.payoutTxHash?{...i,status:`target-pending`,target:{confirmationCount:0,requiredConfirmationCount:1,startedAtMs:Date.now(),txHash:n.payoutTxHash}}:i}catch{return i}default:if(!i.target?.txHash)return{...i,errorCode:e.UNKNOWN,errorReason:`Missing target transaction hash`,failedAtMs:Date.now(),status:`failed`};try{let e=await t(n.getTransaction(i.target.txHash),o);if(e.status===`aborted`)return i;let r=e.value.confirmations;return r<i.target.requiredConfirmationCount?{...i,target:{...i.target,confirmationCount:r}}:{...i,completedAtMs:Date.now(),target:{...i.target,confirmationCount:r},status:`completed`}}catch{return i}}}export{o as trackTransferFactory};
2
2
  //# sourceMappingURL=track-transfer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"track-transfer.js","names":[],"sources":["../../../../../src/transfer-service/lombard/btcb-to-btc/_handlers/track-transfer.ts"],"sourcesContent":["import { isHash } from 'viem';\nimport { ErrorCode } from '../../../../errors';\nimport type { BitcoinFunctions } from '../../../../types/bitcoin';\nimport type { TransferService } from '../../../../types/service';\nimport type {\n CompletedTransfer,\n FailedTransfer,\n SourceCompletedTransfer,\n SourcePendingTransfer,\n TargetPendingTransfer,\n Transfer,\n} from '../../../../types/transfer';\nimport type { BtcbToBtcConfig } from '../../types';\nimport { awaitOrAbort, getEvmClientForChain, waitForTimeoutOrAbort } from '../../../_utils';\nimport { getUnstakesByAddress } from '@lombard.finance/sdk';\n\n// Polling interval for BTC redemptions (60 seconds - BTC confirmations are slow)\nconst REDEMPTION_POLLING_INTERVAL_MS = 1000 * 60;\n\nexport interface TrackTransferFactoryOptions {\n bitcoinFunctions: BitcoinFunctions;\n config: BtcbToBtcConfig;\n}\n\nexport function trackTransferFactory({\n bitcoinFunctions,\n config,\n}: TrackTransferFactoryOptions): TransferService['trackTransfer'] {\n return ({ transfer, updateListener }) => {\n const ac = new AbortController();\n const cancel = () => {\n ac.abort();\n };\n\n if (transfer.status === 'completed' || transfer.status === 'failed') {\n return {\n cancel,\n result: Promise.resolve(transfer),\n };\n }\n\n const executeTracking = async (): Promise<Transfer> => {\n let currentTransfer: Transfer = structuredClone(transfer);\n\n const sourceClient = getEvmClientForChain({ chain: transfer.sourceChain });\n\n while (!ac.signal.aborted) {\n const statusBeforeTracking = currentTransfer.status;\n\n switch (currentTransfer.status) {\n case 'source-pending': {\n currentTransfer = await _trackSourceTx({\n currentTransfer,\n signal: ac.signal,\n sourceClient,\n });\n\n if (!ac.signal.aborted) {\n updateListener(currentTransfer);\n }\n\n break;\n }\n case 'source-completed':\n case 'target-pending': {\n currentTransfer = await _trackTargetTx({\n bitcoinFunctions,\n config,\n currentTransfer,\n signal: ac.signal,\n });\n\n if (!ac.signal.aborted) {\n updateListener(currentTransfer);\n }\n\n break;\n }\n default: {\n return currentTransfer;\n }\n }\n\n const hasStatusChanged = currentTransfer.status !== statusBeforeTracking;\n\n if (!hasStatusChanged) {\n await waitForTimeoutOrAbort({ timeoutMs: REDEMPTION_POLLING_INTERVAL_MS, signal: ac.signal });\n }\n }\n\n return currentTransfer;\n };\n\n return {\n cancel,\n result: executeTracking(),\n };\n };\n}\n\nexport interface TrackBaseParams {\n currentTransfer: Transfer;\n signal: AbortSignal;\n}\n\nexport interface TrackSourceTxParams extends TrackBaseParams {\n currentTransfer: SourcePendingTransfer;\n sourceClient: ReturnType<typeof getEvmClientForChain>;\n}\n\nexport interface TrackTargetTxParams extends TrackBaseParams {\n bitcoinFunctions: BitcoinFunctions;\n config: BtcbToBtcConfig;\n currentTransfer: SourceCompletedTransfer | TargetPendingTransfer;\n}\n\nexport async function _trackSourceTx({\n currentTransfer,\n signal,\n sourceClient,\n}: TrackSourceTxParams): Promise<SourcePendingTransfer | SourceCompletedTransfer | FailedTransfer> {\n const { confirmationCount, requiredConfirmationCount, txHash } = currentTransfer.source;\n\n if (!isHash(txHash)) {\n const failedTransfer: FailedTransfer = {\n ...currentTransfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n\n return failedTransfer;\n }\n\n if (confirmationCount >= requiredConfirmationCount) {\n // Move to next stage\n\n const updatedTransfer: SourceCompletedTransfer = {\n ...currentTransfer,\n status: 'source-completed',\n };\n\n return updatedTransfer;\n }\n\n try {\n const receiptResult = await awaitOrAbort(\n sourceClient.waitForTransactionReceipt({\n confirmations: Math.min(confirmationCount + 1, requiredConfirmationCount),\n hash: txHash,\n }),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const transactionReceipt = receiptResult.value;\n\n if (transactionReceipt.status === 'reverted') {\n return {\n ...currentTransfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n } satisfies FailedTransfer;\n }\n\n const newConfirmationCount: number = await sourceClient\n .getTransactionConfirmations({\n transactionReceipt,\n })\n .then((count) => Number(count))\n .catch(() => confirmationCount + 1);\n\n // If still not enough confirmations, update the count\n if (newConfirmationCount < requiredConfirmationCount) {\n return {\n ...currentTransfer,\n source: {\n ...currentTransfer.source,\n confirmationCount: newConfirmationCount,\n },\n } satisfies SourcePendingTransfer;\n }\n\n // Move to next stage\n return {\n ...currentTransfer,\n source: {\n ...currentTransfer.source,\n confirmationCount: newConfirmationCount,\n },\n status: 'source-completed',\n } satisfies SourceCompletedTransfer;\n } catch {\n return currentTransfer;\n }\n}\n\nexport async function _trackTargetTx({\n bitcoinFunctions,\n config,\n currentTransfer,\n signal,\n}: TrackTargetTxParams): Promise<SourceCompletedTransfer | TargetPendingTransfer | FailedTransfer | CompletedTransfer> {\n switch (currentTransfer.status) {\n case 'source-completed': {\n try {\n const unstakesResult = await awaitOrAbort(\n getUnstakesByAddress({ address: currentTransfer.fromAddress, env: config.env }),\n signal,\n );\n\n if (unstakesResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const transferUnstake = unstakesResult.value.find(\n (d) => d.txHash.toLowerCase() === currentTransfer.source.txHash.toLowerCase(),\n );\n\n if (transferUnstake?.payoutTxHash) {\n const updatedTransfer: TargetPendingTransfer = {\n ...currentTransfer,\n status: 'target-pending',\n target: {\n confirmationCount: 0,\n requiredConfirmationCount: 1,\n startedAtMs: Date.now(),\n txHash: transferUnstake.payoutTxHash,\n },\n };\n\n return updatedTransfer;\n }\n\n return currentTransfer;\n } catch {\n return currentTransfer;\n }\n }\n default: {\n // target-pending\n if (!currentTransfer.target?.txHash) {\n // Fail if no target tx hash, should not reach here\n return {\n ...currentTransfer,\n errorCode: ErrorCode.UNKNOWN,\n errorReason: 'Missing target transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n } satisfies FailedTransfer;\n }\n\n try {\n const receiptResult = await awaitOrAbort(\n bitcoinFunctions.getTransaction(currentTransfer.target.txHash),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const targetConfirmationCount = receiptResult.value.confirmations;\n\n if (targetConfirmationCount < currentTransfer.target.requiredConfirmationCount) {\n return {\n ...currentTransfer,\n target: {\n ...currentTransfer.target,\n confirmationCount: targetConfirmationCount,\n },\n } satisfies TargetPendingTransfer;\n }\n\n // Completed\n return {\n ...currentTransfer,\n completedAtMs: Date.now(),\n target: {\n ...currentTransfer.target,\n confirmationCount: targetConfirmationCount,\n },\n status: 'completed',\n } satisfies CompletedTransfer;\n } catch {\n return currentTransfer;\n }\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"track-transfer.js","names":[],"sources":["../../../../../src/transfer-service/lombard/btcb-to-btc/_handlers/track-transfer.ts"],"sourcesContent":["import { isHash } from 'viem';\nimport { ErrorCode } from '../../../../errors';\nimport type { BitcoinFunctions } from '../../../../types/bitcoin';\nimport type { TransferService } from '../../../../types/service';\nimport type {\n CompletedTransfer,\n FailedTransfer,\n SourceCompletedTransfer,\n SourcePendingTransfer,\n TargetPendingTransfer,\n Transfer,\n} from '../../../../types/transfer';\nimport type { BtcbToBtcConfig } from '../../types';\nimport { awaitOrAbort, getEvmClientForChain, waitForTimeoutOrAbort } from '../../../_utils';\nimport { getUnstakesByAddress } from '@lombard.finance/sdk';\n\n// Polling interval for BTC redemptions (60 seconds - BTC confirmations are slow)\nconst REDEMPTION_POLLING_INTERVAL_MS = 1000 * 60;\n\nexport interface TrackTransferFactoryOptions {\n bitcoinFunctions: BitcoinFunctions;\n config: BtcbToBtcConfig;\n}\n\nexport function trackTransferFactory({\n bitcoinFunctions,\n config,\n}: TrackTransferFactoryOptions): TransferService['trackTransfer'] {\n return ({ transfer, updateListener }) => {\n const ac = new AbortController();\n const cancel = () => {\n ac.abort();\n };\n\n if (transfer.status === 'completed' || transfer.status === 'failed') {\n return {\n cancel,\n result: Promise.resolve(transfer),\n };\n }\n\n const executeTracking = async (): Promise<Transfer> => {\n let currentTransfer: Transfer = structuredClone(transfer);\n\n const sourceClient = getEvmClientForChain({ chain: transfer.sourceChain });\n\n while (!ac.signal.aborted) {\n const statusBeforeTracking = currentTransfer.status;\n\n switch (currentTransfer.status) {\n case 'source-pending': {\n currentTransfer = await _trackSourceTx({\n currentTransfer,\n signal: ac.signal,\n sourceClient,\n });\n\n if (!ac.signal.aborted) {\n updateListener(currentTransfer);\n }\n\n break;\n }\n case 'source-completed':\n case 'target-pending': {\n currentTransfer = await _trackTargetTx({\n bitcoinFunctions,\n config,\n currentTransfer,\n signal: ac.signal,\n });\n\n if (!ac.signal.aborted) {\n updateListener(currentTransfer);\n }\n\n break;\n }\n default: {\n return currentTransfer;\n }\n }\n\n const hasStatusChanged = currentTransfer.status !== statusBeforeTracking;\n\n if (!hasStatusChanged) {\n await waitForTimeoutOrAbort({ timeoutMs: REDEMPTION_POLLING_INTERVAL_MS, signal: ac.signal });\n }\n }\n\n return currentTransfer;\n };\n\n return {\n cancel,\n result: executeTracking(),\n };\n };\n}\n\nexport interface TrackBaseParams {\n currentTransfer: Transfer;\n signal: AbortSignal;\n}\n\nexport interface TrackSourceTxParams extends TrackBaseParams {\n currentTransfer: SourcePendingTransfer;\n sourceClient: ReturnType<typeof getEvmClientForChain>;\n}\n\nexport interface TrackTargetTxParams extends TrackBaseParams {\n bitcoinFunctions: BitcoinFunctions;\n config: BtcbToBtcConfig;\n currentTransfer: SourceCompletedTransfer | TargetPendingTransfer;\n}\n\nexport async function _trackSourceTx({\n currentTransfer,\n signal,\n sourceClient,\n}: TrackSourceTxParams): Promise<SourcePendingTransfer | SourceCompletedTransfer | FailedTransfer> {\n const { confirmationCount, requiredConfirmationCount, txHash } = currentTransfer.source;\n\n if (!isHash(txHash)) {\n const failedTransfer: FailedTransfer = {\n ...currentTransfer,\n errorCode: ErrorCode.INVALID_PARAMS,\n errorReason: 'Invalid source transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n };\n\n return failedTransfer;\n }\n\n if (confirmationCount >= requiredConfirmationCount) {\n // Move to next stage\n\n const updatedTransfer: SourceCompletedTransfer = {\n ...currentTransfer,\n status: 'source-completed',\n };\n\n return updatedTransfer;\n }\n\n try {\n const receiptResult = await awaitOrAbort(\n sourceClient.waitForTransactionReceipt({\n hash: txHash,\n }),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const transactionReceipt = receiptResult.value;\n\n if (transactionReceipt.status === 'reverted') {\n return {\n ...currentTransfer,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'Source transaction was reverted',\n failedAtMs: Date.now(),\n status: 'failed',\n } satisfies FailedTransfer;\n }\n\n const newConfirmationCountResult = await awaitOrAbort(\n sourceClient\n .getTransactionConfirmations({\n transactionReceipt,\n })\n .then((count) => Math.max(Number(count), 0))\n .catch(() => Math.max(confirmationCount, 0)),\n signal,\n );\n\n if (newConfirmationCountResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const newConfirmationCount = newConfirmationCountResult.value;\n\n // If still not enough confirmations, update the count\n if (newConfirmationCount < requiredConfirmationCount) {\n return {\n ...currentTransfer,\n source: {\n ...currentTransfer.source,\n confirmationCount: newConfirmationCount,\n },\n } satisfies SourcePendingTransfer;\n }\n\n // Move to next stage\n return {\n ...currentTransfer,\n source: {\n ...currentTransfer.source,\n confirmationCount: newConfirmationCount,\n },\n status: 'source-completed',\n } satisfies SourceCompletedTransfer;\n } catch {\n return currentTransfer;\n }\n}\n\nexport async function _trackTargetTx({\n bitcoinFunctions,\n config,\n currentTransfer,\n signal,\n}: TrackTargetTxParams): Promise<SourceCompletedTransfer | TargetPendingTransfer | FailedTransfer | CompletedTransfer> {\n switch (currentTransfer.status) {\n case 'source-completed': {\n try {\n const unstakesResult = await awaitOrAbort(\n getUnstakesByAddress({ address: currentTransfer.fromAddress, env: config.env }),\n signal,\n );\n\n if (unstakesResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const transferUnstake = unstakesResult.value.find(\n (d) => d.txHash.toLowerCase() === currentTransfer.source.txHash.toLowerCase(),\n );\n\n if (transferUnstake?.payoutTxHash) {\n const updatedTransfer: TargetPendingTransfer = {\n ...currentTransfer,\n status: 'target-pending',\n target: {\n confirmationCount: 0,\n requiredConfirmationCount: 1,\n startedAtMs: Date.now(),\n txHash: transferUnstake.payoutTxHash,\n },\n };\n\n return updatedTransfer;\n }\n\n return currentTransfer;\n } catch {\n return currentTransfer;\n }\n }\n default: {\n // target-pending\n if (!currentTransfer.target?.txHash) {\n // Fail if no target tx hash, should not reach here\n return {\n ...currentTransfer,\n errorCode: ErrorCode.UNKNOWN,\n errorReason: 'Missing target transaction hash',\n failedAtMs: Date.now(),\n status: 'failed',\n } satisfies FailedTransfer;\n }\n\n try {\n const receiptResult = await awaitOrAbort(\n bitcoinFunctions.getTransaction(currentTransfer.target.txHash),\n signal,\n );\n\n if (receiptResult.status === 'aborted') {\n return currentTransfer;\n }\n\n const targetConfirmationCount = receiptResult.value.confirmations;\n\n if (targetConfirmationCount < currentTransfer.target.requiredConfirmationCount) {\n return {\n ...currentTransfer,\n target: {\n ...currentTransfer.target,\n confirmationCount: targetConfirmationCount,\n },\n } satisfies TargetPendingTransfer;\n }\n\n // Completed\n return {\n ...currentTransfer,\n completedAtMs: Date.now(),\n target: {\n ...currentTransfer.target,\n confirmationCount: targetConfirmationCount,\n },\n status: 'completed',\n } satisfies CompletedTransfer;\n } catch {\n return currentTransfer;\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../constants.cjs`),t=require(`../../errors.cjs`),n=require(`../../utils/caip.cjs`),r=require(`../../_utils/chain.cjs`),i=require(`../../utils/evm-address.cjs`),a=require(`../../_utils/math.cjs`),o=require(`./_api.cjs`),s=require(`../../utils/sol-address.cjs`);let c=require(`viem`);function l(e,t,n){let r=e.get(t),i=e.get(n);return!r||!i?!1:t===n?r.swapEnabled:r.crossChainSwapEnabled&&r.crossChainTargetChainIds.has(n)}async function u(e,r=!1){let i=new Map;try{let t=(await o.markrGetInfoChains(e)).filter(e=>e.chainType===`evm`||e.chainType===`svm`);for(let e of t){let t=typeof e.chainId==`number`?n.eip155ChainIdToCaip2(e.chainId):e.chainId,a=e.enabled_services.includes(`cross-chain-quote`)&&e.enabled_services.includes(`cross-chain-swap`),o=e.enabled_services.includes(`quote`)&&e.enabled_services.includes(`swap`),s=new Set;for(let r of e.lanes){let e=typeof r==`number`?n.eip155ChainIdToCaip2(r):r;e!==t&&s.add(e)}let c=r?!1:a,l=c?s:new Set;!o&&l.size===0||i.set(t,{chainId:e.chainId,crossChainSwapEnabled:c,crossChainTargetChainIds:l,swapEnabled:o,tokenList:e.enabled_services.includes(`token-list`)})}}catch(e){throw new t.SdkError(t.ErrorReason.UNKNOWN,t.ErrorCode.INITIALIZATION_FAILED,{cause:e,details:`Failed to fetch supported chains from Markr API.`})}return i}async function d(e,t){let n=new Map;for(let[r,i]of t.entries())if(typeof i.chainId==`number`&&i.tokenList&&(i.crossChainSwapEnabled||i.swapEnabled))try{let t=o.markrGetTokenList(e,i.chainId);n.set(r,t)}catch{}return n}function f(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({assetIn:t,fees:n,sourceChain:r}){return n.reduce((n,i)=>i.fundingModel!==`additive`||i.chainId!==r.chainId?n:t.type===e.TokenType.NATIVE?i.token.type===e.TokenType.NATIVE?n+i.amount:n:t.type===e.TokenType.ERC20?i.token.type===e.TokenType.ERC20&&(0,c.isAddressEqual)(i.token.address,t.address)?n+i.amount:n:i.token.type===e.TokenType.SPL&&i.token.address===t.address?n+i.amount:n,0n)}function g(t,n,r){let i=t.amountOut*BigInt(r)/10000n,a=t.amountOut-i,o=[...v(t.fees),{type:`partner`,fundingModel:`included`,name:`Core Fee`,amount:i,chainId:n.targetChain.chainId,token:y(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 _(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 v(t){if(!t)return[];let r=[];for(let a of t){let t=typeof a.token.chainId==`number`?n.eip155ChainIdToCaip2(a.token.chainId):a.token.chainId,o;f(a.token.address)?o={type:e.TokenType.NATIVE}:i.isEvmAddress(a.token.address)?o={type:e.TokenType.ERC20,address:a.token.address}:s.isSolAddress(a.token.address)&&(o={type:e.TokenType.SPL,address:a.token.address}),o&&r.push({type:a.type,fundingModel:a.extra?`additive`:`included`,name:a.name,amount:a.amount,chainId:t,token:o})}return r}function y(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 b(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 x(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 S(e,t){let n=x(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=S,exports.getAdditiveSourceAssetFeeAmount=h,exports.getMarkrSwapWrapperAbi=b,exports.getPartnerFeeBps=_,exports.getSupportedChains=u,exports.getSupportedTokens=d,exports.isRouteSupported=l,exports.isTokenAddressNative=f,exports.quoteFromMarkrQuoteResponseData=g;
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({assetIn:t,fees:n,sourceChain:r},i=3e3){return n.reduce((n,i)=>i.fundingModel!==`additive`||i.chainId!==r.chainId?n:t.type===e.TokenType.NATIVE?i.token.type===e.TokenType.NATIVE?n+i.amount:n:t.type===e.TokenType.ERC20?i.token.type===e.TokenType.ERC20&&(0,c.isAddressEqual)(i.token.address,t.address)?n+i.amount:n:i.token.type===e.TokenType.SPL&&i.token.address===t.address?n+i.amount:n,0n)*BigInt(1e4+i)/10000n}function g(t,n,r){let i=t.amountOut*BigInt(r)/10000n,a=t.amountOut-i,o=[...v(t.fees),{type:`partner`,fundingModel:`included`,name:`Core Fee`,amount:i,chainId:n.targetChain.chainId,token:y(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 _(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 v(t){if(!t)return[];let r=[];for(let a of t){let t=typeof a.token.chainId==`number`?n.eip155ChainIdToCaip2(a.token.chainId):a.token.chainId,o;f(a.token.address)?o={type:e.TokenType.NATIVE}:i.isEvmAddress(a.token.address)?o={type:e.TokenType.ERC20,address:a.token.address}:s.isSolAddress(a.token.address)&&(o={type:e.TokenType.SPL,address:a.token.address}),o&&r.push({type:a.type,fundingModel:a.extra?`additive`:`included`,name:a.name,amount:a.amount,chainId:t,token:o})}return r}function y(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 b(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 x(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 S(e,t){let n=x(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=S,exports.getAdditiveSourceAssetFeeAmount=h,exports.getMarkrSwapWrapperAbi=b,exports.getPartnerFeeBps=_,exports.getSupportedChains=u,exports.getSupportedTokens=d,exports.isRouteSupported=l,exports.isTokenAddressNative=f,exports.quoteFromMarkrQuoteResponseData=g;
2
2
  //# sourceMappingURL=_utils.cjs.map
@@ -1 +1 @@
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, isAddressEqual, 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\n/**\n * Returns additive fee amount charged in the source asset on the source chain.\n *\n * This is used for allowance/balance checks where users must fund both the\n * transfer input and any additive source-asset fee components.\n */\nexport function getAdditiveSourceAssetFeeAmount({\n assetIn,\n fees,\n sourceChain,\n}: Pick<Quote, 'assetIn' | 'fees' | 'sourceChain'>): bigint {\n return fees.reduce((total, fee) => {\n if (fee.fundingModel !== 'additive' || fee.chainId !== sourceChain.chainId) {\n return total;\n }\n\n if (assetIn.type === TokenType.NATIVE) {\n return fee.token.type === TokenType.NATIVE ? total + fee.amount : total;\n }\n\n if (assetIn.type === TokenType.ERC20) {\n return fee.token.type === TokenType.ERC20 && isAddressEqual(fee.token.address, assetIn.address)\n ? total + fee.amount\n : total;\n }\n\n return fee.token.type === TokenType.SPL && fee.token.address === assetIn.address ? total + fee.amount : total;\n }, 0n);\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 fundingModel: 'included',\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 fundingModel: fee.extra ? 'additive' : 'included',\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,EAST,SAAgB,EAAgC,CAC9C,UACA,OACA,eAC0D,CAC1D,OAAO,EAAK,QAAQ,EAAO,IACrB,EAAI,eAAiB,YAAc,EAAI,UAAY,EAAY,QAC1D,EAGL,EAAQ,OAASF,EAAAA,UAAU,OACtB,EAAI,MAAM,OAASA,EAAAA,UAAU,OAAS,EAAQ,EAAI,OAAS,EAGhE,EAAQ,OAASA,EAAAA,UAAU,MACtB,EAAI,MAAM,OAASA,EAAAA,UAAU,QAAA,EAAA,EAAA,gBAAwB,EAAI,MAAM,QAAS,EAAQ,QAAQ,CAC3F,EAAQ,EAAI,OACZ,EAGC,EAAI,MAAM,OAASA,EAAAA,UAAU,KAAO,EAAI,MAAM,UAAY,EAAQ,QAAU,EAAQ,EAAI,OAAS,EACvG,GAAG,CAGR,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,aAAc,WACd,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,YAAaG,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,aAAc,EAAI,MAAQ,WAAa,WACvC,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
+ {"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, isAddressEqual, 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\n/**\n * Returns additive fee amount charged in the source asset on the source chain.\n *\n * This is used for allowance/balance checks where users must fund both the\n * transfer input and any additive source-asset fee components. A safety buffer\n * is applied to the additive fee total to reduce the chance of under-approvals.\n *\n * @see https://docs.debridge.com/dln-details/overview/fee-structure#best-practice-checklist-for-integrators\n *\n * @param quote The quote containing the fees to analyze.\n * @param bufferBps Buffer in basis points applied to the additive fee total.\n * Defaults to 3000 bps (30%).\n */\nexport function getAdditiveSourceAssetFeeAmount(\n { assetIn, fees, sourceChain }: Pick<Quote, 'assetIn' | 'fees' | 'sourceChain'>,\n bufferBps = 3_000,\n): bigint {\n const additiveSourceAssetFeeAmount = fees.reduce((total, fee) => {\n if (fee.fundingModel !== 'additive' || fee.chainId !== sourceChain.chainId) {\n return total;\n }\n\n if (assetIn.type === TokenType.NATIVE) {\n return fee.token.type === TokenType.NATIVE ? total + fee.amount : total;\n }\n\n if (assetIn.type === TokenType.ERC20) {\n return fee.token.type === TokenType.ERC20 && isAddressEqual(fee.token.address, assetIn.address)\n ? total + fee.amount\n : total;\n }\n\n return fee.token.type === TokenType.SPL && fee.token.address === assetIn.address ? total + fee.amount : total;\n }, 0n);\n\n return (additiveSourceAssetFeeAmount * BigInt(10_000 + bufferBps)) / 10_000n;\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 fundingModel: 'included',\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 fundingModel: fee.extra ? 'additive' : 'included',\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,EAgBT,SAAgB,EACd,CAAE,UAAS,OAAM,eACjB,EAAY,IACJ,CAmBR,OAlBqC,EAAK,QAAQ,EAAO,IACnD,EAAI,eAAiB,YAAc,EAAI,UAAY,EAAY,QAC1D,EAGL,EAAQ,OAASF,EAAAA,UAAU,OACtB,EAAI,MAAM,OAASA,EAAAA,UAAU,OAAS,EAAQ,EAAI,OAAS,EAGhE,EAAQ,OAASA,EAAAA,UAAU,MACtB,EAAI,MAAM,OAASA,EAAAA,UAAU,QAAA,EAAA,EAAA,gBAAwB,EAAI,MAAM,QAAS,EAAQ,QAAQ,CAC3F,EAAQ,EAAI,OACZ,EAGC,EAAI,MAAM,OAASA,EAAAA,UAAU,KAAO,EAAI,MAAM,UAAY,EAAQ,QAAU,EAAQ,EAAI,OAAS,EACvG,GAAG,CAEiC,OAAO,IAAS,EAAU,CAAI,OAGvE,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,aAAc,WACd,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,YAAaG,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,aAAc,EAAI,MAAQ,WAAa,WACvC,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,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,isAddressEqual as _,isHex as v,toFunctionSelector as y}from"viem";function b(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 x(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 S(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 C(n){return n===e||n===t}function w(n,i){return n.type===r.NATIVE?c(i)?t:e:n.address}function T({amountOut:e,assetOut:t,slippageBps:n}){let r=u({amountOut:e,assetOut:t,slippageBps:n});return e>0n&&r===0n?1n:r}function E({assetIn:e,fees:t,sourceChain:n}){return t.reduce((t,i)=>i.fundingModel!==`additive`||i.chainId!==n.chainId?t:e.type===r.NATIVE?i.token.type===r.NATIVE?t+i.amount:t:e.type===r.ERC20?i.token.type===r.ERC20&&_(i.token.address,e.address)?t+i.amount:t:i.token.type===r.SPL&&i.token.address===e.address?t+i.amount:t,0n)}function D(e,t,r){let i=e.amountOut*BigInt(r)/10000n,a=e.amountOut-i,o=[...k(e.fees),{type:`partner`,fundingModel:`included`,name:`Core Fee`,amount:i,chainId:t.targetChain.chainId,token:A(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 O(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 k(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;C(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,fundingModel:n.extra?`additive`:`included`,name:n.name,amount:n.amount,chainId:e,token:i})}return t}function A(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 j(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 M(e){if(e instanceof h){let t=e.data;if(v(t))return t;let n;if(e.walk(e=>{let t=e.data;return!n&&v(t)&&(n=t),!1}),n)return n;let r=e.cause?.data;if(v(r))return r}if(!e||typeof e!=`object`)return;let t=e;if(v(t.data))return t.data;if(v(t.error?.data))return t.error.data;if(v(t.cause?.data))return t.cause.data;if(v(t.response?.data))return t.response.data;if(v(t.body?.error?.data))return t.body.error.data}function N(e,t){let n=M(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`&&y(`${n.name}(${n.inputs.map(e=>e.type).join(`,`)})`).toLowerCase()===t)return`${n.name}()`}return null}export{w as assetToAddressString,T as calculateMarkrMinimumAmountOut,N as decodeMarkrRevertError,E as getAdditiveSourceAssetFeeAmount,j as getMarkrSwapWrapperAbi,O as getPartnerFeeBps,x as getSupportedChains,S as getSupportedTokens,b as isRouteSupported,C as isTokenAddressNative,D as quoteFromMarkrQuoteResponseData};
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,isAddressEqual as _,isHex as v,toFunctionSelector as y}from"viem";function b(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 x(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 S(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 C(n){return n===e||n===t}function w(n,i){return n.type===r.NATIVE?c(i)?t:e:n.address}function T({amountOut:e,assetOut:t,slippageBps:n}){let r=u({amountOut:e,assetOut:t,slippageBps:n});return e>0n&&r===0n?1n:r}function E({assetIn:e,fees:t,sourceChain:n},i=3e3){return t.reduce((t,i)=>i.fundingModel!==`additive`||i.chainId!==n.chainId?t:e.type===r.NATIVE?i.token.type===r.NATIVE?t+i.amount:t:e.type===r.ERC20?i.token.type===r.ERC20&&_(i.token.address,e.address)?t+i.amount:t:i.token.type===r.SPL&&i.token.address===e.address?t+i.amount:t,0n)*BigInt(1e4+i)/10000n}function D(e,t,r){let i=e.amountOut*BigInt(r)/10000n,a=e.amountOut-i,o=[...k(e.fees),{type:`partner`,fundingModel:`included`,name:`Core Fee`,amount:i,chainId:t.targetChain.chainId,token:A(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 O(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 k(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;C(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,fundingModel:n.extra?`additive`:`included`,name:n.name,amount:n.amount,chainId:e,token:i})}return t}function A(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 j(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 M(e){if(e instanceof h){let t=e.data;if(v(t))return t;let n;if(e.walk(e=>{let t=e.data;return!n&&v(t)&&(n=t),!1}),n)return n;let r=e.cause?.data;if(v(r))return r}if(!e||typeof e!=`object`)return;let t=e;if(v(t.data))return t.data;if(v(t.error?.data))return t.error.data;if(v(t.cause?.data))return t.cause.data;if(v(t.response?.data))return t.response.data;if(v(t.body?.error?.data))return t.body.error.data}function N(e,t){let n=M(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`&&y(`${n.name}(${n.inputs.map(e=>e.type).join(`,`)})`).toLowerCase()===t)return`${n.name}()`}return null}export{w as assetToAddressString,T as calculateMarkrMinimumAmountOut,N as decodeMarkrRevertError,E as getAdditiveSourceAssetFeeAmount,j as getMarkrSwapWrapperAbi,O as getPartnerFeeBps,x as getSupportedChains,S as getSupportedTokens,b as isRouteSupported,C as isTokenAddressNative,D 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, isAddressEqual, 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\n/**\n * Returns additive fee amount charged in the source asset on the source chain.\n *\n * This is used for allowance/balance checks where users must fund both the\n * transfer input and any additive source-asset fee components.\n */\nexport function getAdditiveSourceAssetFeeAmount({\n assetIn,\n fees,\n sourceChain,\n}: Pick<Quote, 'assetIn' | 'fees' | 'sourceChain'>): bigint {\n return fees.reduce((total, fee) => {\n if (fee.fundingModel !== 'additive' || fee.chainId !== sourceChain.chainId) {\n return total;\n }\n\n if (assetIn.type === TokenType.NATIVE) {\n return fee.token.type === TokenType.NATIVE ? total + fee.amount : total;\n }\n\n if (assetIn.type === TokenType.ERC20) {\n return fee.token.type === TokenType.ERC20 && isAddressEqual(fee.token.address, assetIn.address)\n ? total + fee.amount\n : total;\n }\n\n return fee.token.type === TokenType.SPL && fee.token.address === assetIn.address ? total + fee.amount : total;\n }, 0n);\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 fundingModel: 'included',\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 fundingModel: fee.extra ? 'additive' : 'included',\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.js","names":[],"sources":["../../../src/transfer-service/markr/_utils.ts"],"sourcesContent":["import { ErrorCode, ErrorReason, SdkError } from '../../errors';\nimport { BaseError, decodeErrorResult, type Hex, isAddressEqual, 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\n/**\n * Returns additive fee amount charged in the source asset on the source chain.\n *\n * This is used for allowance/balance checks where users must fund both the\n * transfer input and any additive source-asset fee components. A safety buffer\n * is applied to the additive fee total to reduce the chance of under-approvals.\n *\n * @see https://docs.debridge.com/dln-details/overview/fee-structure#best-practice-checklist-for-integrators\n *\n * @param quote The quote containing the fees to analyze.\n * @param bufferBps Buffer in basis points applied to the additive fee total.\n * Defaults to 3000 bps (30%).\n */\nexport function getAdditiveSourceAssetFeeAmount(\n { assetIn, fees, sourceChain }: Pick<Quote, 'assetIn' | 'fees' | 'sourceChain'>,\n bufferBps = 3_000,\n): bigint {\n const additiveSourceAssetFeeAmount = fees.reduce((total, fee) => {\n if (fee.fundingModel !== 'additive' || fee.chainId !== sourceChain.chainId) {\n return total;\n }\n\n if (assetIn.type === TokenType.NATIVE) {\n return fee.token.type === TokenType.NATIVE ? total + fee.amount : total;\n }\n\n if (assetIn.type === TokenType.ERC20) {\n return fee.token.type === TokenType.ERC20 && isAddressEqual(fee.token.address, assetIn.address)\n ? total + fee.amount\n : total;\n }\n\n return fee.token.type === TokenType.SPL && fee.token.address === assetIn.address ? total + fee.amount : total;\n }, 0n);\n\n return (additiveSourceAssetFeeAmount * BigInt(10_000 + bufferBps)) / 10_000n;\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 fundingModel: 'included',\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 fundingModel: fee.extra ? 'additive' : 'included',\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":"irBAkCA,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,EAgBT,SAAgB,EACd,CAAE,UAAS,OAAM,eACjB,EAAY,IACJ,CAmBR,OAlBqC,EAAK,QAAQ,EAAO,IACnD,EAAI,eAAiB,YAAc,EAAI,UAAY,EAAY,QAC1D,EAGL,EAAQ,OAAS,EAAU,OACtB,EAAI,MAAM,OAAS,EAAU,OAAS,EAAQ,EAAI,OAAS,EAGhE,EAAQ,OAAS,EAAU,MACtB,EAAI,MAAM,OAAS,EAAU,OAAS,EAAe,EAAI,MAAM,QAAS,EAAQ,QAAQ,CAC3F,EAAQ,EAAI,OACZ,EAGC,EAAI,MAAM,OAAS,EAAU,KAAO,EAAI,MAAM,UAAY,EAAQ,QAAU,EAAQ,EAAI,OAAS,EACvG,GAAG,CAEiC,OAAO,IAAS,EAAU,CAAI,OAGvE,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,aAAc,WACd,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,aAAc,EAAI,MAAQ,WAAa,WACvC,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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@avalabs/fusion-sdk",
3
3
  "license": "Limited Ecosystem License",
4
- "version": "0.14.2",
4
+ "version": "0.14.4",
5
5
  "type": "module",
6
6
  "main": "./dist/mod.cjs",
7
7
  "module": "./dist/mod.js",
@@ -47,8 +47,8 @@
47
47
  "vitest": "4.0.6",
48
48
  "tsdown": "0.20.3",
49
49
  "zod": "4.1.12",
50
- "eslint-config-custom": "0.1.0",
51
- "@internal/tsdown-config": "0.0.1"
50
+ "@internal/tsdown-config": "0.0.1",
51
+ "eslint-config-custom": "0.1.0"
52
52
  },
53
53
  "sideEffects": false,
54
54
  "scripts": {