@avalabs/fusion-sdk 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.cjs +1 -1
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +32 -1
- package/dist/constants.d.ts +32 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +2 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/mod.cjs +1 -1
- package/dist/mod.d.cts +3 -2
- package/dist/mod.d.ts +3 -2
- package/dist/mod.js +1 -1
- package/dist/transfer-service/_evm-errors.cjs.map +1 -1
- package/dist/transfer-service/_evm-errors.js.map +1 -1
- package/dist/transfer-service/avalanche-cct/_handlers/estimate-native-fee.cjs +1 -1
- package/dist/transfer-service/avalanche-cct/_handlers/estimate-native-fee.js +1 -1
- package/dist/transfer-service/avalanche-cct/_handlers/track-transfer.cjs +1 -1
- package/dist/transfer-service/avalanche-cct/_handlers/track-transfer.js +1 -1
- package/dist/transfer-service/avalanche-cct/_handlers/transfer-asset.cjs +1 -1
- package/dist/transfer-service/avalanche-cct/_handlers/transfer-asset.js +1 -1
- package/dist/transfer-service/avalanche-cct/_utils/fees.cjs +1 -1
- package/dist/transfer-service/avalanche-cct/_utils/fees.js +1 -1
- package/dist/transfer-service/avalanche-cct/_utils/polling.cjs +1 -1
- package/dist/transfer-service/avalanche-cct/_utils/polling.js +1 -1
- package/dist/transfer-service/markr/_api.cjs +1 -1
- package/dist/transfer-service/markr/_api.js +1 -1
- package/dist/transfer-service/markr/_handlers/estimate-native-fee.cjs +1 -1
- package/dist/transfer-service/markr/_handlers/estimate-native-fee.cjs.map +1 -1
- package/dist/transfer-service/markr/_handlers/estimate-native-fee.js +1 -1
- package/dist/transfer-service/markr/_handlers/estimate-native-fee.js.map +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset-hyperliquid-withdraw.cjs +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset-hyperliquid-withdraw.js +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset.cjs +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset.cjs.map +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset.js +1 -1
- package/dist/transfer-service/markr/_handlers/transfer-asset.js.map +1 -1
- package/dist/transfer-service/markr/_hyperevm.cjs +2 -0
- package/dist/transfer-service/markr/_hyperevm.cjs.map +1 -0
- package/dist/transfer-service/markr/_hyperevm.js +2 -0
- package/dist/transfer-service/markr/_hyperevm.js.map +1 -0
- package/dist/transfer-service/markr/_hyperliquid-eip712.d.ts +1 -0
- package/dist/transfer-service/markr/_hyperliquid-l1-action.cjs +2 -0
- package/dist/transfer-service/markr/_hyperliquid-l1-action.cjs.map +1 -0
- package/dist/transfer-service/markr/_hyperliquid-l1-action.d.cts +60 -0
- package/dist/transfer-service/markr/_hyperliquid-l1-action.d.ts +60 -0
- package/dist/transfer-service/markr/_hyperliquid-l1-action.js +2 -0
- package/dist/transfer-service/markr/_hyperliquid-l1-action.js.map +1 -0
- package/dist/transfer-service/markr/_hyperliquid-schema.d.cts +8 -0
- package/dist/transfer-service/markr/_hyperliquid-schema.d.ts +10 -0
- package/dist/transfer-service/markr/_hyperliquid.d.ts +1 -0
- package/dist/transfer-service/markr/recurring/_api.cjs +1 -1
- package/dist/transfer-service/markr/recurring/_api.js +1 -1
- package/package.json +2 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{AbortedError as e,ResponseValidationError as t}from"../../errors.js";import{
|
|
1
|
+
import{AbortedError as e,ResponseValidationError as t}from"../../errors.js";import{combineUrlPathnames as n,fetchEventStream as r,fetchJson as i}from"../fetch-utilities.js";import{CrossChainStatusResponseSchema as a,MarkrAuthorizeResponseSchema as o,PartnerInfoResponseSchema as s,QuoteResponseSchema as c,SpenderAddressResponseSchema as l,SupportedChainsResponseSchema as u,SwapResponseSchema as d,TokenListResponseSchema as f}from"./_schema.js";function p(e){if(e)return{Authorization:`Bearer ${e}`}}async function m({apiBaseUrl:e,apiToken:r,fetch:a}){let o=`/info/chains`,s=await i(n(e,o),{headers:p(r),fetch:a}),c=u.safeParse(s);if(!c.success)throw new t(`Invalid response from Markr "${o}" endpoint.`,c.error.issues);return c.data}async function h({apiBaseUrl:e,apiToken:r,fetch:a},o){let s=`/tokens/${o}/list`,c=await i(n(e,s),{headers:p(r),fetch:a}),l=f.safeParse(c);if(!l.success)throw new t(`Invalid response from Markr "${s}" endpoint.`,l.error.issues);return l.data}async function g({apiBaseUrl:e,apiToken:i,fetch:a},o,{onDone:s,onError:l,onQuote:u,signal:d}){let f=`/quote`,m=n(e,f),h=[];try{for await(let e of r(m,{body:JSON.stringify(o),fetch:a,headers:p(i),signal:d})){let n=c.safeParse(JSON.parse(e.data));if(!n.success){l(new t(`Invalid quote data received from Markr "${f}" endpoint.`,n.error.issues));continue}`done`in n.data?s():(u(n.data),h.push(n.data))}}catch(e){e instanceof Error?l(e):l(Error(`An unknown error occurred during the quote stream.`,{cause:e})),s()}return h}async function _({apiBaseUrl:e,apiToken:r,fetch:a},o){let s=`/swap`,c=await i(n(e,s),{body:JSON.stringify(o),fetch:a,headers:p(r),method:`POST`}),l=d.safeParse(c);if(!l.success)throw new t(`Invalid response from Markr "${s}" endpoint.`,l.error.issues);return l.data}async function v({apiBaseUrl:e,apiToken:r,fetch:a}){let o=`/info/partner`,c=await i(n(e,o),{headers:p(r),fetch:a}),l=s.safeParse(c);if(!l.success)throw new t(`Invalid response from Markr "${o}" endpoint.`,l.error.issues);return l.data}async function y({apiBaseUrl:r,apiToken:o,fetch:s},c,{signal:l}={}){let u=`/cross-chain/status/${c}`,d=await i(n(r,u),{headers:p(o),fetch:s,retries:10,retryOn(t){let n=(t.init.method??`GET`).toUpperCase();if(![`GET`,`HEAD`,`OPTIONS`,`TRACE`].includes(n))return!1;if(t.error)return!(t.error instanceof e);let r=t.response?.status??0;return r===404||r===408||r===425||r===429||r>=500&&r<=599},signal:l}),f=a.safeParse(d);if(!f.success)throw new t(`Invalid response from Markr "${u}" endpoint.`,f.error.issues,d);return f.data}async function b({apiBaseUrl:e,apiToken:r,fetch:a},{chainId:o,crossChainSwap:s,quoteId:c}){let u=`/spender-address?${new URLSearchParams({chainId:String(o),cross:s?`true`:`false`,uuid:c}).toString()}`,d=await i(n(e,u),{headers:p(r),fetch:a}),f=l.safeParse(d);if(!f.success)throw new t(`Invalid response from Markr "${u}" endpoint.`,f.error.issues);return f.data}async function x({apiBaseUrl:e,apiToken:r,fetch:a},s,{signal:c}={}){let l=`/authorize`,u=await i(n(e,l),{body:JSON.stringify(s),fetch:a,headers:p(r),method:`POST`,signal:c}),d=o.safeParse(u);if(!d.success)throw new t(`Invalid response from Markr "${l}" endpoint.`,d.error.issues)}export{p as getAuthHeaders,y as markrGetCrossChainStatus,m as markrGetInfoChains,v as markrGetPartnerInfo,b as markrGetSpenderAddress,h as markrGetTokenList,x as markrPostAuthorize,g as markrStreamQuote,_ as markrSwap};
|
|
2
2
|
//# sourceMappingURL=_api.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../errors.cjs`),t=require(`../../../utils/caip.cjs`),n=require(`../../_utils.cjs`),r=require(`../../_evm-errors.cjs`),i=require(`../../../_utils/chain.cjs`),a=require(`../../_evm-gas.cjs`),o=require(`../_api.cjs`),s=require(`../_utils.cjs`),c=require(`../_type-guards.cjs`),l=require(`../../../utils/solana.cjs`);let
|
|
1
|
+
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../errors.cjs`),t=require(`../../../utils/caip.cjs`),n=require(`../../_utils.cjs`),r=require(`../../_evm-errors.cjs`),i=require(`../../../_utils/chain.cjs`),a=require(`../../_evm-gas.cjs`),o=require(`../_api.cjs`),s=require(`../_utils.cjs`),c=require(`../_type-guards.cjs`),l=require(`../../../utils/solana.cjs`),u=require(`../_hyperevm.cjs`);let d=require(`viem`),f=require(`@solana/kit`);function p(t){return async(n,r)=>{if(i.isEvmNamespace(n.sourceChain.chainId))return await m(n,r,t);if(i.isSolanaNamespace(n.sourceChain.chainId))return await h(n,r,t);throw new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Unsupported source chain namespace for estimateNativeFee: ${n.sourceChain.chainId}`)}}async function m(i,l,{apiOptions:f,appId:p}){if(!(0,d.isAddress)(i.fromAddress))throw new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid fromAddress: ${i.fromAddress}`);let m=n.getEvmClientForChain({chain:i.sourceChain}),h=s.assetToAddressString(i.assetIn,i.sourceChain.chainId);if(!(0,d.isAddress)(h))throw new e.SdkError(e.ErrorReason.INVALID_PARAMS,e.ErrorCode.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address. Can not call estimateGas.`});let _=s.isTokenAddressNative(h),v=i.sourceChain.chainId.toLowerCase()!==i.targetChain.chainId.toLowerCase(),y=i.amountIn+s.getAdditiveSourceAssetFeeAmount(i),b=0n;if(!_){let n,{address:a}=await o.markrGetSpenderAddress(f,{chainId:t.caip2ToEip155ChainId(i.sourceChain.chainId),crossChainSwap:v,quoteId:i.id});try{n=await m.readContract({address:h,abi:d.erc20Abi,functionName:`allowance`,args:[i.fromAddress,a]})}catch(t){throw new e.SdkError(`Error during allowance check`,e.ErrorCode.VIEM_ERROR,{cause:t,details:`Failed to read ERC20 allowance for Markr spender.`})}n<y&&(b=await r.estimateGasWithRevert(m,{account:i.fromAddress,to:h,data:(0,d.encodeFunctionData)({abi:d.erc20Abi,functionName:`approve`,args:[a,y]})},d.erc20Abi,`Failed to estimate gas for ERC20 approval transaction.`))}let x=b>0n,S=s.calculateMarkrMinimumAmountOut({amountOut:i.amountOut,assetOut:i.assetOut,slippageBps:i.slippageBps}),C=await o.markrSwap(f,{amountIn:i.amountIn.toString(),appId:p,minAmountOut:S.toString(),tokenIn:h,tokenOut:s.assetToAddressString(i.assetOut,i.targetChain.chainId),uuid:i.id});if(!c.isEvmSwapResponse(C)){let t=c.isSolanaSwapResponse(C)?C.chainType:c.isHyperliquidWithdrawSwapResponse(C)?C.type:`unknown`;throw new e.SdkError(e.ErrorReason.CHAIN_NOT_SUPPORTED,e.ErrorCode.INVALID_PARAMS,{details:`Received non-EVM swap response from Markr. Expected EVM transaction data for gas estimation, but got response variant "${t}".`})}let w=0n;w=x?i.gasEstimate||700000n:await g({crossChain:v,fromAddress:i.fromAddress,gasLimit:u._getGasLimit(i),sourceClient:m,swap:C});let T=await a.estimateEvmFeesPerGas(m,i.sourceChain,l?.overrides?.feeRateTier),E=l?.overrides?.maxFeePerGas??T.maxFeePerGas,D=l?.overrides?.maxPriorityFeePerGas??T.maxPriorityFeePerGas,O=(w+b)*E;return{asset:i.sourceChain.networkToken,totalFee:n.applyFeeUnitsBpsMargin(O,l?.feeUnitsMarginBps),totalFeeWithoutMargin:O,meta:{approvalFee:x?b*E:void 0,maxFeePerGas:E,maxPriorityFeePerGas:D}}}async function h(t,r,{apiOptions:i,appId:a}){let u=s.assetToAddressString(t.assetIn,t.sourceChain.chainId);if(!(0,f.isAddress)(u))throw new e.SdkError(e.ErrorReason.INVALID_PARAMS,e.ErrorCode.INVALID_PARAMS,{details:`assetIn address is not a valid Solana address. Can not call estimateGas.`});let d=s.getAdditiveSourceNativeAssetFeeAmount(t),p=t.amountIn+d,m=s.calculateMarkrMinimumAmountOut({amountOut:t.amountOut,assetOut:t.assetOut,slippageBps:t.slippageBps}),h=await o.markrSwap(i,{amountIn:t.amountIn.toString(),appId:a,minAmountOut:m.toString(),tokenIn:u,tokenOut:s.assetToAddressString(t.assetOut,t.targetChain.chainId),userPublicKey:t.fromAddress,uuid:t.id});if(!c.isSolanaSwapResponse(h))throw new e.SdkError(e.ErrorReason.CHAIN_NOT_SUPPORTED,e.ErrorCode.INVALID_PARAMS,{details:`Received non-Solana swap response from Markr. Expected Solana transaction data for fee estimation.`});let{baseFeeLamports:g,priorityFeeLamports:_,...v}=await l.estimateSolanaFee(n.getSolanaRpcForChain({chain:t.sourceChain}),h.swapTransaction),y=v.feePayerBalanceDiffLamports-p;return{asset:t.sourceChain.networkToken,totalFee:n.applyFeeUnitsBpsMargin(y,r?.feeUnitsMarginBps),totalFeeWithoutMargin:y,meta:{...v,baseFee:g,priorityFee:_}}}async function g({crossChain:e,feeUnitsMarginBps:t,fromAddress:i,gasLimit:a,sourceClient:o,swap:c}){let l=await s.getMarkrSwapWrapperAbi(e);return n.applyFeeUnitsBpsMargin(await r.estimateGasWithRevert(o,{account:i,to:c.to,data:c.data,value:c.value,...a===void 0?{}:{gas:a}},l,`Failed to estimate gas for Markr swap transaction.`),t)}exports._estimateGasFromSwapResponse=g,exports.estimateNativeFeeFactory=p;
|
|
2
2
|
//# sourceMappingURL=estimate-native-fee.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"estimate-native-fee.cjs","names":["isEvmNamespace","isSolanaNamespace","InvalidParamsError","ErrorReason","getEvmClientForChain","assetToAddressString","SdkError","ErrorCode","isTokenAddressNative","getAdditiveSourceAssetFeeAmount","markrGetSpenderAddress","caip2ToEip155ChainId","erc20Abi","estimateGasWithRevert","calculateMarkrMinimumAmountOut","markrSwap","isEvmSwapResponse","isSolanaSwapResponse","isHyperliquidWithdrawSwapResponse","estimateEvmFeesPerGas","applyFeeUnitsBpsMargin","getAdditiveSourceNativeAssetFeeAmount","estimateSolanaFee","getSolanaRpcForChain","getMarkrSwapWrapperAbi"],"sources":["../../../../src/transfer-service/markr/_handlers/estimate-native-fee.ts"],"sourcesContent":["import { isAddress as isSolanaAddress } from '@solana/kit';\nimport { encodeFunctionData, erc20Abi, type Address as EvmAddress, isAddress as isEvmAddress } from 'viem';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { EstimateNativeFeeOptions, NativeFeeEstimate, TransferService } from '../../../types/service';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, getSolanaRpcForChain } from '../../_utils';\nimport { estimateEvmFeesPerGas } from '../../_evm-gas';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n getAdditiveSourceNativeAssetFeeAmount,\n getMarkrSwapWrapperAbi,\n isTokenAddressNative,\n} from '../_utils';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { isEvmSwapResponse, isHyperliquidWithdrawSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { caip2ToEip155ChainId } from '../../../utils/caip';\nimport type { Quote } from '../../../types/quote';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { estimateSolanaFee } from '../../../utils/solana';\n\n/**\n * This is just a fallback value used in the case that an\n * allowance approval is needed, and Markr didn't return us any gas estimate data.\n *\n * Just based on my review of some quotes, I think this is a reasonable estimate\n * left on the higher end.\n *\n * Assume this could need to change.\n */\nconst EVM_SWAP_FALLBACK_GAS_ESTIMATE = 700_000n;\n\nexport interface EstimateNativeFeeFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n}\n\nexport function estimateNativeFeeFactory(config: EstimateNativeFeeFactoryConfig): TransferService['estimateNativeFee'] {\n return async (quote, options) => {\n // Either the source chain is EVM or Solana, we need to call different functions that\n // calculate the native fee depending on the chain kind.\n\n if (isEvmNamespace(quote.sourceChain.chainId)) {\n return await _estimateNativeFeeEvm(quote, options, config);\n }\n\n if (isSolanaNamespace(quote.sourceChain.chainId)) {\n return await _estimateNativeFeeSolana(quote, options, config);\n }\n\n throw new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n `Unsupported source chain namespace for estimateNativeFee: ${quote.sourceChain.chainId}`,\n );\n };\n}\n\n/** @internal */\nexport async function _estimateNativeFeeEvm(\n quote: Quote,\n options: EstimateNativeFeeOptions | undefined,\n { apiOptions, appId }: EstimateNativeFeeFactoryConfig,\n): Promise<NativeFeeEstimate> {\n if (!isEvmAddress(quote.fromAddress)) {\n throw new InvalidParamsError(ErrorReason.INVALID_PARAMS, `Invalid fromAddress: ${quote.fromAddress}`);\n }\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const assetInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n\n if (!isEvmAddress(assetInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: `assetIn address is not a valid EVM address. Can not call estimateGas.`,\n });\n }\n\n const isAssetInNative = isTokenAddressNative(assetInAddressString);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n let allowanceApprovalGas = 0n;\n if (!isAssetInNative) {\n // Check if approval is needed, and if so, calculate the gas cost for the approval.\n let allowance: bigint;\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n try {\n allowance = await sourceClient.readContract({\n address: assetInAddressString,\n abi: erc20Abi,\n functionName: 'allowance',\n args: [quote.fromAddress, spenderAddress],\n });\n } catch (error) {\n throw new SdkError('Error during allowance check', ErrorCode.VIEM_ERROR, {\n cause: error,\n details: 'Failed to read ERC20 allowance for Markr spender.',\n });\n }\n\n const approvalNeeded = allowance < allowanceAmount;\n\n if (approvalNeeded) {\n allowanceApprovalGas = await estimateGasWithRevert(\n sourceClient,\n {\n account: quote.fromAddress,\n to: assetInAddressString,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, allowanceAmount],\n }),\n },\n erc20Abi,\n 'Failed to estimate gas for ERC20 approval transaction.',\n );\n }\n }\n\n const allowanceApprovalIsNeeded = allowanceApprovalGas > 0n;\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: assetInAddressString,\n tokenOut: assetToAddressString(quote.assetOut, quote.targetChain.chainId),\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n // Should hopefully never happen.\n const variantTag = isSolanaSwapResponse(swap)\n ? swap.chainType\n : isHyperliquidWithdrawSwapResponse(swap)\n ? swap.type\n : 'unknown';\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Received non-EVM swap response from Markr. Expected EVM transaction data for gas estimation, but got response variant \"${variantTag}\".`,\n });\n }\n\n let gas = 0n;\n\n // If an approval is needed, we can't call `eth_estimateGas` on the\n // swap transaction because no actual allowance approval was performed yet,\n // so a gas estimation would fail due to needing allowance.\n //\n // So if an allowance approval is needed, we fall back to some other logic for\n // estimating the swap tx gas.\n if (allowanceApprovalIsNeeded) {\n // While the approval is still pending we can't `eth_estimateGas` the swap (it would\n // revert on the missing allowance), so use Markr's gas-unit estimate when present and\n // otherwise a fixed gas-unit fallback. `gasEstimate` is documented as optional and may\n // be 0/omitted for relay.\n //\n // We deliberately do NOT derive this from the `fees` array. A `type: 'gas'` fee is a\n // token-denominated *cost amount* (e.g. native wei), not a gas-unit count — feeding it\n // into the `gas * maxFeePerGas` formula below produces a nonsensical fee.\n gas = quote.gasEstimate || EVM_SWAP_FALLBACK_GAS_ESTIMATE;\n } else {\n gas = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress: quote.fromAddress,\n sourceClient,\n swap,\n });\n }\n\n const fees = await estimateEvmFeesPerGas(sourceClient, quote.sourceChain, options?.overrides?.feeRateTier);\n\n const maxFeePerGas = options?.overrides?.maxFeePerGas ?? fees.maxFeePerGas;\n const maxPriorityFeePerGas = options?.overrides?.maxPriorityFeePerGas ?? fees.maxPriorityFeePerGas;\n\n const totalFeeWithoutMargin = (gas + allowanceApprovalGas) * maxFeePerGas;\n\n return {\n asset: quote.sourceChain.networkToken,\n totalFee: applyFeeUnitsBpsMargin(totalFeeWithoutMargin, options?.feeUnitsMarginBps),\n totalFeeWithoutMargin,\n meta: {\n approvalFee: allowanceApprovalIsNeeded ? allowanceApprovalGas * maxFeePerGas : undefined,\n maxFeePerGas,\n maxPriorityFeePerGas,\n },\n };\n}\n\n/** @internal */\nexport async function _estimateNativeFeeSolana(\n quote: Quote,\n options: EstimateNativeFeeOptions | undefined,\n { apiOptions, appId }: EstimateNativeFeeFactoryConfig,\n): Promise<NativeFeeEstimate> {\n const assetInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n\n if (!isSolanaAddress(assetInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: `assetIn address is not a valid Solana address. Can not call estimateGas.`,\n });\n }\n\n const additiveNativeFee: bigint = getAdditiveSourceNativeAssetFeeAmount(quote);\n const totalInput: bigint = quote.amountIn + additiveNativeFee;\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: assetInAddressString,\n tokenOut: assetToAddressString(quote.assetOut, quote.targetChain.chainId),\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n // Should hopefully never happen.\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-Solana swap response from Markr. Expected Solana transaction data for fee estimation.',\n });\n }\n\n const rpc = getSolanaRpcForChain({ chain: quote.sourceChain });\n\n const { baseFeeLamports, priorityFeeLamports, ...rest } = await estimateSolanaFee(rpc, swap.swapTransaction);\n\n const totalFeeWithoutMargin = rest.feePayerBalanceDiffLamports - totalInput;\n\n return {\n asset: quote.sourceChain.networkToken,\n totalFee: applyFeeUnitsBpsMargin(totalFeeWithoutMargin, options?.feeUnitsMarginBps),\n totalFeeWithoutMargin,\n meta: {\n ...rest,\n baseFee: baseFeeLamports,\n priorityFee: priorityFeeLamports,\n },\n };\n}\n\n/** @internal */\nexport async function _estimateGasFromSwapResponse({\n crossChain,\n feeUnitsMarginBps,\n fromAddress,\n sourceClient,\n swap,\n}: {\n crossChain: boolean;\n feeUnitsMarginBps?: number;\n fromAddress: EvmAddress;\n sourceClient: ReturnType<typeof getEvmClientForChain>;\n swap: WrappedSwapTransactionResponse;\n}): Promise<bigint> {\n const markrAbi = await getMarkrSwapWrapperAbi(crossChain);\n\n // Use raw estimateGas — the calldata is pre-encoded and may target any\n // contract (Markr wrapper, deBridge, etc.). The ABI is only used for\n // best-effort error decoding on the failure path.\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n {\n account: fromAddress,\n to: swap.to,\n data: swap.data,\n value: swap.value,\n },\n markrAbi,\n 'Failed to estimate gas for Markr swap transaction.',\n );\n\n return applyFeeUnitsBpsMargin(gasEstimate, feeUnitsMarginBps);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"estimate-native-fee.cjs","names":["isEvmNamespace","isSolanaNamespace","InvalidParamsError","ErrorReason","getEvmClientForChain","assetToAddressString","SdkError","ErrorCode","isTokenAddressNative","getAdditiveSourceAssetFeeAmount","markrGetSpenderAddress","caip2ToEip155ChainId","erc20Abi","estimateGasWithRevert","calculateMarkrMinimumAmountOut","markrSwap","isEvmSwapResponse","isSolanaSwapResponse","isHyperliquidWithdrawSwapResponse","_getGasLimit","estimateEvmFeesPerGas","applyFeeUnitsBpsMargin","getAdditiveSourceNativeAssetFeeAmount","estimateSolanaFee","getSolanaRpcForChain","getMarkrSwapWrapperAbi"],"sources":["../../../../src/transfer-service/markr/_handlers/estimate-native-fee.ts"],"sourcesContent":["import { isAddress as isSolanaAddress } from '@solana/kit';\nimport { encodeFunctionData, erc20Abi, type Address as EvmAddress, isAddress as isEvmAddress } from 'viem';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { EstimateNativeFeeOptions, NativeFeeEstimate, TransferService } from '../../../types/service';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, getSolanaRpcForChain } from '../../_utils';\nimport { estimateEvmFeesPerGas } from '../../_evm-gas';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n getAdditiveSourceNativeAssetFeeAmount,\n getMarkrSwapWrapperAbi,\n isTokenAddressNative,\n} from '../_utils';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { isEvmSwapResponse, isHyperliquidWithdrawSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { caip2ToEip155ChainId } from '../../../utils/caip';\nimport type { Quote } from '../../../types/quote';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { estimateSolanaFee } from '../../../utils/solana';\nimport { _getGasLimit } from '../_hyperevm';\n\n/**\n * This is just a fallback value used in the case that an\n * allowance approval is needed, and Markr didn't return us any gas estimate data.\n *\n * Just based on my review of some quotes, I think this is a reasonable estimate\n * left on the higher end.\n *\n * Assume this could need to change.\n */\nconst EVM_SWAP_FALLBACK_GAS_ESTIMATE = 700_000n;\n\nexport interface EstimateNativeFeeFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n}\n\nexport function estimateNativeFeeFactory(config: EstimateNativeFeeFactoryConfig): TransferService['estimateNativeFee'] {\n return async (quote, options) => {\n // Either the source chain is EVM or Solana, we need to call different functions that\n // calculate the native fee depending on the chain kind.\n\n if (isEvmNamespace(quote.sourceChain.chainId)) {\n return await _estimateNativeFeeEvm(quote, options, config);\n }\n\n if (isSolanaNamespace(quote.sourceChain.chainId)) {\n return await _estimateNativeFeeSolana(quote, options, config);\n }\n\n throw new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n `Unsupported source chain namespace for estimateNativeFee: ${quote.sourceChain.chainId}`,\n );\n };\n}\n\n/** @internal */\nexport async function _estimateNativeFeeEvm(\n quote: Quote,\n options: EstimateNativeFeeOptions | undefined,\n { apiOptions, appId }: EstimateNativeFeeFactoryConfig,\n): Promise<NativeFeeEstimate> {\n if (!isEvmAddress(quote.fromAddress)) {\n throw new InvalidParamsError(ErrorReason.INVALID_PARAMS, `Invalid fromAddress: ${quote.fromAddress}`);\n }\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const assetInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n\n if (!isEvmAddress(assetInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: `assetIn address is not a valid EVM address. Can not call estimateGas.`,\n });\n }\n\n const isAssetInNative = isTokenAddressNative(assetInAddressString);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n let allowanceApprovalGas = 0n;\n if (!isAssetInNative) {\n // Check if approval is needed, and if so, calculate the gas cost for the approval.\n let allowance: bigint;\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n try {\n allowance = await sourceClient.readContract({\n address: assetInAddressString,\n abi: erc20Abi,\n functionName: 'allowance',\n args: [quote.fromAddress, spenderAddress],\n });\n } catch (error) {\n throw new SdkError('Error during allowance check', ErrorCode.VIEM_ERROR, {\n cause: error,\n details: 'Failed to read ERC20 allowance for Markr spender.',\n });\n }\n\n const approvalNeeded = allowance < allowanceAmount;\n\n if (approvalNeeded) {\n allowanceApprovalGas = await estimateGasWithRevert(\n sourceClient,\n {\n account: quote.fromAddress,\n to: assetInAddressString,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, allowanceAmount],\n }),\n },\n erc20Abi,\n 'Failed to estimate gas for ERC20 approval transaction.',\n );\n }\n }\n\n const allowanceApprovalIsNeeded = allowanceApprovalGas > 0n;\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: assetInAddressString,\n tokenOut: assetToAddressString(quote.assetOut, quote.targetChain.chainId),\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n // Should hopefully never happen.\n const variantTag = isSolanaSwapResponse(swap)\n ? swap.chainType\n : isHyperliquidWithdrawSwapResponse(swap)\n ? swap.type\n : 'unknown';\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Received non-EVM swap response from Markr. Expected EVM transaction data for gas estimation, but got response variant \"${variantTag}\".`,\n });\n }\n\n let gas = 0n;\n\n // If an approval is needed, we can't call `eth_estimateGas` on the\n // swap transaction because no actual allowance approval was performed yet,\n // so a gas estimation would fail due to needing allowance.\n //\n // So if an allowance approval is needed, we fall back to some other logic for\n // estimating the swap tx gas.\n if (allowanceApprovalIsNeeded) {\n // While the approval is still pending we can't `eth_estimateGas` the swap (it would\n // revert on the missing allowance), so use Markr's gas-unit estimate when present and\n // otherwise a fixed gas-unit fallback. `gasEstimate` is documented as optional and may\n // be 0/omitted for relay.\n //\n // We deliberately do NOT derive this from the `fees` array. A `type: 'gas'` fee is a\n // token-denominated *cost amount* (e.g. native wei), not a gas-unit count — feeding it\n // into the `gas * maxFeePerGas` formula below produces a nonsensical fee.\n gas = quote.gasEstimate || EVM_SWAP_FALLBACK_GAS_ESTIMATE;\n } else {\n gas = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress: quote.fromAddress,\n gasLimit: _getGasLimit(quote),\n sourceClient,\n swap,\n });\n }\n\n const fees = await estimateEvmFeesPerGas(sourceClient, quote.sourceChain, options?.overrides?.feeRateTier);\n\n const maxFeePerGas = options?.overrides?.maxFeePerGas ?? fees.maxFeePerGas;\n const maxPriorityFeePerGas = options?.overrides?.maxPriorityFeePerGas ?? fees.maxPriorityFeePerGas;\n\n const totalFeeWithoutMargin = (gas + allowanceApprovalGas) * maxFeePerGas;\n\n return {\n asset: quote.sourceChain.networkToken,\n totalFee: applyFeeUnitsBpsMargin(totalFeeWithoutMargin, options?.feeUnitsMarginBps),\n totalFeeWithoutMargin,\n meta: {\n approvalFee: allowanceApprovalIsNeeded ? allowanceApprovalGas * maxFeePerGas : undefined,\n maxFeePerGas,\n maxPriorityFeePerGas,\n },\n };\n}\n\n/** @internal */\nexport async function _estimateNativeFeeSolana(\n quote: Quote,\n options: EstimateNativeFeeOptions | undefined,\n { apiOptions, appId }: EstimateNativeFeeFactoryConfig,\n): Promise<NativeFeeEstimate> {\n const assetInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n\n if (!isSolanaAddress(assetInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: `assetIn address is not a valid Solana address. Can not call estimateGas.`,\n });\n }\n\n const additiveNativeFee: bigint = getAdditiveSourceNativeAssetFeeAmount(quote);\n const totalInput: bigint = quote.amountIn + additiveNativeFee;\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: assetInAddressString,\n tokenOut: assetToAddressString(quote.assetOut, quote.targetChain.chainId),\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n // Should hopefully never happen.\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-Solana swap response from Markr. Expected Solana transaction data for fee estimation.',\n });\n }\n\n const rpc = getSolanaRpcForChain({ chain: quote.sourceChain });\n\n const { baseFeeLamports, priorityFeeLamports, ...rest } = await estimateSolanaFee(rpc, swap.swapTransaction);\n\n const totalFeeWithoutMargin = rest.feePayerBalanceDiffLamports - totalInput;\n\n return {\n asset: quote.sourceChain.networkToken,\n totalFee: applyFeeUnitsBpsMargin(totalFeeWithoutMargin, options?.feeUnitsMarginBps),\n totalFeeWithoutMargin,\n meta: {\n ...rest,\n baseFee: baseFeeLamports,\n priorityFee: priorityFeeLamports,\n },\n };\n}\n\n/** @internal */\nexport async function _estimateGasFromSwapResponse({\n crossChain,\n feeUnitsMarginBps,\n fromAddress,\n gasLimit,\n sourceClient,\n swap,\n}: {\n crossChain: boolean;\n feeUnitsMarginBps?: number;\n fromAddress: EvmAddress;\n /**\n * Explicit gas limit upper bound for `eth_estimateGas` (maps to the RPC\n * `gas` field). Required on HyperEVM (pass `HYPEREVM_BIG_BLOCK_GAS_LIMIT`):\n * the node otherwise caps the estimation search at the current small-block gas\n * limit and any route heavier than a small block reverts during estimation.\n * Omit on chains with a single block-gas-limit regime. Prefer {@link _getGasLimit}.\n */\n gasLimit?: bigint;\n sourceClient: ReturnType<typeof getEvmClientForChain>;\n swap: WrappedSwapTransactionResponse;\n}): Promise<bigint> {\n const markrAbi = await getMarkrSwapWrapperAbi(crossChain);\n\n // Use raw estimateGas — the calldata is pre-encoded and may target any\n // contract (Markr wrapper, deBridge, etc.). The ABI is only used for\n // best-effort error decoding on the failure path.\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n {\n account: fromAddress,\n to: swap.to,\n data: swap.data,\n value: swap.value,\n ...(gasLimit === undefined ? {} : { gas: gasLimit }),\n },\n markrAbi,\n 'Failed to estimate gas for Markr swap transaction.',\n );\n\n return applyFeeUnitsBpsMargin(gasEstimate, feeUnitsMarginBps);\n}\n"],"mappings":"gdAwCA,SAAgB,EAAyB,EAA8E,CACrH,OAAO,MAAO,EAAO,IAAY,CAI/B,GAAIA,EAAAA,eAAe,EAAM,YAAY,QAAQ,CAC3C,OAAO,MAAM,EAAsB,EAAO,EAAS,EAAO,CAG5D,GAAIC,EAAAA,kBAAkB,EAAM,YAAY,QAAQ,CAC9C,OAAO,MAAM,EAAyB,EAAO,EAAS,EAAO,CAG/D,MAAM,IAAIC,EAAAA,mBACRC,EAAAA,YAAY,eACZ,6DAA6D,EAAM,YAAY,UAChF,EAKL,eAAsB,EACpB,EACA,EACA,CAAE,aAAY,SACc,CAC5B,GAAI,EAAA,EAAA,EAAA,WAAc,EAAM,YAAY,CAClC,MAAM,IAAID,EAAAA,mBAAmBC,EAAAA,YAAY,eAAgB,wBAAwB,EAAM,cAAc,CAGvG,IAAM,EAAeC,EAAAA,qBAAqB,CAAE,MAAO,EAAM,YAAa,CAAC,CAEjE,EAAuBC,EAAAA,qBAAqB,EAAM,QAAS,EAAM,YAAY,QAAQ,CAE3F,GAAI,EAAA,EAAA,EAAA,WAAc,EAAqB,CACrC,MAAM,IAAIC,EAAAA,SAASH,EAAAA,YAAY,eAAgBI,EAAAA,UAAU,eAAgB,CACvE,QAAS,wEACV,CAAC,CAGJ,IAAM,EAAkBC,EAAAA,qBAAqB,EAAqB,CAC5D,EAAmB,EAAM,YAAY,QAAQ,aAAa,GAAK,EAAM,YAAY,QAAQ,aAAa,CACtG,EAAkB,EAAM,SAAWC,EAAAA,gCAAgC,EAAM,CAE3E,EAAuB,GAC3B,GAAI,CAAC,EAAiB,CAEpB,IAAI,EAEE,CAAE,QAAS,GAAmB,MAAMC,EAAAA,uBAAuB,EAAY,CAC3E,QAASC,EAAAA,qBAAqB,EAAM,YAAY,QAAQ,CACxD,eAAgB,EAChB,QAAS,EAAM,GAChB,CAAC,CAEF,GAAI,CACF,EAAY,MAAM,EAAa,aAAa,CAC1C,QAAS,EACT,IAAKC,EAAAA,SACL,aAAc,YACd,KAAM,CAAC,EAAM,YAAa,EAAe,CAC1C,CAAC,OACK,EAAO,CACd,MAAM,IAAIN,EAAAA,SAAS,+BAAgCC,EAAAA,UAAU,WAAY,CACvE,MAAO,EACP,QAAS,oDACV,CAAC,CAGmB,EAAY,IAGjC,EAAuB,MAAMM,EAAAA,sBAC3B,EACA,CACE,QAAS,EAAM,YACf,GAAI,EACJ,MAAA,EAAA,EAAA,oBAAyB,CACvB,IAAKD,EAAAA,SACL,aAAc,UACd,KAAM,CAAC,EAAgB,EAAgB,CACxC,CAAC,CACH,CACDA,EAAAA,SACA,yDACD,EAIL,IAAM,EAA4B,EAAuB,GAEnD,EAAeE,EAAAA,+BAA+B,CAClD,UAAW,EAAM,UACjB,SAAU,EAAM,SAChB,YAAa,EAAM,YACpB,CAAC,CAEI,EAAO,MAAMC,EAAAA,UAAU,EAAY,CACvC,SAAU,EAAM,SAAS,UAAU,CACnC,QACA,aAAc,EAAa,UAAU,CACrC,QAAS,EACT,SAAUV,EAAAA,qBAAqB,EAAM,SAAU,EAAM,YAAY,QAAQ,CACzE,KAAM,EAAM,GACb,CAAC,CAEF,GAAI,CAACW,EAAAA,kBAAkB,EAAK,CAAE,CAE5B,IAAM,EAAaC,EAAAA,qBAAqB,EAAK,CACzC,EAAK,UACLC,EAAAA,kCAAkC,EAAK,CACvC,EAAK,KACL,UAEJ,MAAM,IAAIZ,EAAAA,SAASH,EAAAA,YAAY,oBAAqBI,EAAAA,UAAU,eAAgB,CAC5E,QAAS,0HAA0H,EAAW,IAC/I,CAAC,CAGJ,IAAI,EAAM,GAQV,AAWE,EAXE,EASI,EAAM,aAAe,QAErB,MAAM,EAA6B,CACvC,WAAY,EACZ,YAAa,EAAM,YACnB,SAAUY,EAAAA,aAAa,EAAM,CAC7B,eACA,OACD,CAAC,CAGJ,IAAM,EAAO,MAAMC,EAAAA,sBAAsB,EAAc,EAAM,YAAa,GAAS,WAAW,YAAY,CAEpG,EAAe,GAAS,WAAW,cAAgB,EAAK,aACxD,EAAuB,GAAS,WAAW,sBAAwB,EAAK,qBAExE,GAAyB,EAAM,GAAwB,EAE7D,MAAO,CACL,MAAO,EAAM,YAAY,aACzB,SAAUC,EAAAA,uBAAuB,EAAuB,GAAS,kBAAkB,CACnF,wBACA,KAAM,CACJ,YAAa,EAA4B,EAAuB,EAAe,IAAA,GAC/E,eACA,uBACD,CACF,CAIH,eAAsB,EACpB,EACA,EACA,CAAE,aAAY,SACc,CAC5B,IAAM,EAAuBhB,EAAAA,qBAAqB,EAAM,QAAS,EAAM,YAAY,QAAQ,CAE3F,GAAI,EAAA,EAAA,EAAA,WAAiB,EAAqB,CACxC,MAAM,IAAIC,EAAAA,SAASH,EAAAA,YAAY,eAAgBI,EAAAA,UAAU,eAAgB,CACvE,QAAS,2EACV,CAAC,CAGJ,IAAM,EAA4Be,EAAAA,sCAAsC,EAAM,CACxE,EAAqB,EAAM,SAAW,EAEtC,EAAeR,EAAAA,+BAA+B,CAClD,UAAW,EAAM,UACjB,SAAU,EAAM,SAChB,YAAa,EAAM,YACpB,CAAC,CAEI,EAAO,MAAMC,EAAAA,UAAU,EAAY,CACvC,SAAU,EAAM,SAAS,UAAU,CACnC,QACA,aAAc,EAAa,UAAU,CACrC,QAAS,EACT,SAAUV,EAAAA,qBAAqB,EAAM,SAAU,EAAM,YAAY,QAAQ,CACzE,cAAe,EAAM,YACrB,KAAM,EAAM,GACb,CAAC,CAEF,GAAI,CAACY,EAAAA,qBAAqB,EAAK,CAE7B,MAAM,IAAIX,EAAAA,SAASH,EAAAA,YAAY,oBAAqBI,EAAAA,UAAU,eAAgB,CAC5E,QAAS,qGACV,CAAC,CAKJ,GAAM,CAAE,kBAAiB,sBAAqB,GAAG,GAAS,MAAMgB,EAAAA,kBAFpDC,EAAAA,qBAAqB,CAAE,MAAO,EAAM,YAAa,CAAC,CAEyB,EAAK,gBAAgB,CAEtG,EAAwB,EAAK,4BAA8B,EAEjE,MAAO,CACL,MAAO,EAAM,YAAY,aACzB,SAAUH,EAAAA,uBAAuB,EAAuB,GAAS,kBAAkB,CACnF,wBACA,KAAM,CACJ,GAAG,EACH,QAAS,EACT,YAAa,EACd,CACF,CAIH,eAAsB,EAA6B,CACjD,aACA,oBACA,cACA,WACA,eACA,QAekB,CAClB,IAAM,EAAW,MAAMI,EAAAA,uBAAuB,EAAW,CAkBzD,OAAOJ,EAAAA,uBAba,MAAMR,EAAAA,sBACxB,EACA,CACE,QAAS,EACT,GAAI,EAAK,GACT,KAAM,EAAK,KACX,MAAO,EAAK,MACZ,GAAI,IAAa,IAAA,GAAY,EAAE,CAAG,CAAE,IAAK,EAAU,CACpD,CACD,EACA,qDACD,CAE0C,EAAkB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ErrorCode as e,ErrorReason as t,InvalidParamsError as n,SdkError as r}from"../../../errors.js";import{caip2ToEip155ChainId as i}from"../../../utils/caip.js";import{applyFeeUnitsBpsMargin as a,getEvmClientForChain as o,getSolanaRpcForChain as s}from"../../_utils.js";import{estimateGasWithRevert as c}from"../../_evm-errors.js";import{isEvmNamespace as l,isSolanaNamespace as u}from"../../../_utils/chain.js";import{estimateEvmFeesPerGas as d}from"../../_evm-gas.js";import{markrGetSpenderAddress as f,markrSwap as p}from"../_api.js";import{assetToAddressString as m,calculateMarkrMinimumAmountOut as h,getAdditiveSourceAssetFeeAmount as g,getAdditiveSourceNativeAssetFeeAmount as _,getMarkrSwapWrapperAbi as v,isTokenAddressNative as y}from"../_utils.js";import{isEvmSwapResponse as b,isHyperliquidWithdrawSwapResponse as x,isSolanaSwapResponse as S}from"../_type-guards.js";import{estimateSolanaFee as C}from"../../../utils/solana.js";import{encodeFunctionData as
|
|
1
|
+
import{ErrorCode as e,ErrorReason as t,InvalidParamsError as n,SdkError as r}from"../../../errors.js";import{caip2ToEip155ChainId as i}from"../../../utils/caip.js";import{applyFeeUnitsBpsMargin as a,getEvmClientForChain as o,getSolanaRpcForChain as s}from"../../_utils.js";import{estimateGasWithRevert as c}from"../../_evm-errors.js";import{isEvmNamespace as l,isSolanaNamespace as u}from"../../../_utils/chain.js";import{estimateEvmFeesPerGas as d}from"../../_evm-gas.js";import{markrGetSpenderAddress as f,markrSwap as p}from"../_api.js";import{assetToAddressString as m,calculateMarkrMinimumAmountOut as h,getAdditiveSourceAssetFeeAmount as g,getAdditiveSourceNativeAssetFeeAmount as _,getMarkrSwapWrapperAbi as v,isTokenAddressNative as y}from"../_utils.js";import{isEvmSwapResponse as b,isHyperliquidWithdrawSwapResponse as x,isSolanaSwapResponse as S}from"../_type-guards.js";import{estimateSolanaFee as C}from"../../../utils/solana.js";import{_getGasLimit as w}from"../_hyperevm.js";import{encodeFunctionData as T,erc20Abi as E,isAddress as D}from"viem";import{isAddress as O}from"@solana/kit";function k(e){return async(r,i)=>{if(l(r.sourceChain.chainId))return await A(r,i,e);if(u(r.sourceChain.chainId))return await j(r,i,e);throw new n(t.INVALID_PARAMS,`Unsupported source chain namespace for estimateNativeFee: ${r.sourceChain.chainId}`)}}async function A(s,l,{apiOptions:u,appId:_}){if(!D(s.fromAddress))throw new n(t.INVALID_PARAMS,`Invalid fromAddress: ${s.fromAddress}`);let v=o({chain:s.sourceChain}),C=m(s.assetIn,s.sourceChain.chainId);if(!D(C))throw new r(t.INVALID_PARAMS,e.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address. Can not call estimateGas.`});let O=y(C),k=s.sourceChain.chainId.toLowerCase()!==s.targetChain.chainId.toLowerCase(),A=s.amountIn+g(s),j=0n;if(!O){let t,{address:n}=await f(u,{chainId:i(s.sourceChain.chainId),crossChainSwap:k,quoteId:s.id});try{t=await v.readContract({address:C,abi:E,functionName:`allowance`,args:[s.fromAddress,n]})}catch(t){throw new r(`Error during allowance check`,e.VIEM_ERROR,{cause:t,details:`Failed to read ERC20 allowance for Markr spender.`})}t<A&&(j=await c(v,{account:s.fromAddress,to:C,data:T({abi:E,functionName:`approve`,args:[n,A]})},E,`Failed to estimate gas for ERC20 approval transaction.`))}let N=j>0n,P=h({amountOut:s.amountOut,assetOut:s.assetOut,slippageBps:s.slippageBps}),F=await p(u,{amountIn:s.amountIn.toString(),appId:_,minAmountOut:P.toString(),tokenIn:C,tokenOut:m(s.assetOut,s.targetChain.chainId),uuid:s.id});if(!b(F)){let n=S(F)?F.chainType:x(F)?F.type:`unknown`;throw new r(t.CHAIN_NOT_SUPPORTED,e.INVALID_PARAMS,{details:`Received non-EVM swap response from Markr. Expected EVM transaction data for gas estimation, but got response variant "${n}".`})}let I=0n;I=N?s.gasEstimate||700000n:await M({crossChain:k,fromAddress:s.fromAddress,gasLimit:w(s),sourceClient:v,swap:F});let L=await d(v,s.sourceChain,l?.overrides?.feeRateTier),R=l?.overrides?.maxFeePerGas??L.maxFeePerGas,z=l?.overrides?.maxPriorityFeePerGas??L.maxPriorityFeePerGas,B=(I+j)*R;return{asset:s.sourceChain.networkToken,totalFee:a(B,l?.feeUnitsMarginBps),totalFeeWithoutMargin:B,meta:{approvalFee:N?j*R:void 0,maxFeePerGas:R,maxPriorityFeePerGas:z}}}async function j(n,i,{apiOptions:o,appId:c}){let l=m(n.assetIn,n.sourceChain.chainId);if(!O(l))throw new r(t.INVALID_PARAMS,e.INVALID_PARAMS,{details:`assetIn address is not a valid Solana address. Can not call estimateGas.`});let u=_(n),d=n.amountIn+u,f=h({amountOut:n.amountOut,assetOut:n.assetOut,slippageBps:n.slippageBps}),g=await p(o,{amountIn:n.amountIn.toString(),appId:c,minAmountOut:f.toString(),tokenIn:l,tokenOut:m(n.assetOut,n.targetChain.chainId),userPublicKey:n.fromAddress,uuid:n.id});if(!S(g))throw new r(t.CHAIN_NOT_SUPPORTED,e.INVALID_PARAMS,{details:`Received non-Solana swap response from Markr. Expected Solana transaction data for fee estimation.`});let{baseFeeLamports:v,priorityFeeLamports:y,...b}=await C(s({chain:n.sourceChain}),g.swapTransaction),x=b.feePayerBalanceDiffLamports-d;return{asset:n.sourceChain.networkToken,totalFee:a(x,i?.feeUnitsMarginBps),totalFeeWithoutMargin:x,meta:{...b,baseFee:v,priorityFee:y}}}async function M({crossChain:e,feeUnitsMarginBps:t,fromAddress:n,gasLimit:r,sourceClient:i,swap:o}){let s=await v(e);return a(await c(i,{account:n,to:o.to,data:o.data,value:o.value,...r===void 0?{}:{gas:r}},s,`Failed to estimate gas for Markr swap transaction.`),t)}export{M as _estimateGasFromSwapResponse,k as estimateNativeFeeFactory};
|
|
2
2
|
//# sourceMappingURL=estimate-native-fee.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"estimate-native-fee.js","names":["isEvmAddress","isSolanaAddress"],"sources":["../../../../src/transfer-service/markr/_handlers/estimate-native-fee.ts"],"sourcesContent":["import { isAddress as isSolanaAddress } from '@solana/kit';\nimport { encodeFunctionData, erc20Abi, type Address as EvmAddress, isAddress as isEvmAddress } from 'viem';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { EstimateNativeFeeOptions, NativeFeeEstimate, TransferService } from '../../../types/service';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, getSolanaRpcForChain } from '../../_utils';\nimport { estimateEvmFeesPerGas } from '../../_evm-gas';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n getAdditiveSourceNativeAssetFeeAmount,\n getMarkrSwapWrapperAbi,\n isTokenAddressNative,\n} from '../_utils';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { isEvmSwapResponse, isHyperliquidWithdrawSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { caip2ToEip155ChainId } from '../../../utils/caip';\nimport type { Quote } from '../../../types/quote';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { estimateSolanaFee } from '../../../utils/solana';\n\n/**\n * This is just a fallback value used in the case that an\n * allowance approval is needed, and Markr didn't return us any gas estimate data.\n *\n * Just based on my review of some quotes, I think this is a reasonable estimate\n * left on the higher end.\n *\n * Assume this could need to change.\n */\nconst EVM_SWAP_FALLBACK_GAS_ESTIMATE = 700_000n;\n\nexport interface EstimateNativeFeeFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n}\n\nexport function estimateNativeFeeFactory(config: EstimateNativeFeeFactoryConfig): TransferService['estimateNativeFee'] {\n return async (quote, options) => {\n // Either the source chain is EVM or Solana, we need to call different functions that\n // calculate the native fee depending on the chain kind.\n\n if (isEvmNamespace(quote.sourceChain.chainId)) {\n return await _estimateNativeFeeEvm(quote, options, config);\n }\n\n if (isSolanaNamespace(quote.sourceChain.chainId)) {\n return await _estimateNativeFeeSolana(quote, options, config);\n }\n\n throw new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n `Unsupported source chain namespace for estimateNativeFee: ${quote.sourceChain.chainId}`,\n );\n };\n}\n\n/** @internal */\nexport async function _estimateNativeFeeEvm(\n quote: Quote,\n options: EstimateNativeFeeOptions | undefined,\n { apiOptions, appId }: EstimateNativeFeeFactoryConfig,\n): Promise<NativeFeeEstimate> {\n if (!isEvmAddress(quote.fromAddress)) {\n throw new InvalidParamsError(ErrorReason.INVALID_PARAMS, `Invalid fromAddress: ${quote.fromAddress}`);\n }\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const assetInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n\n if (!isEvmAddress(assetInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: `assetIn address is not a valid EVM address. Can not call estimateGas.`,\n });\n }\n\n const isAssetInNative = isTokenAddressNative(assetInAddressString);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n let allowanceApprovalGas = 0n;\n if (!isAssetInNative) {\n // Check if approval is needed, and if so, calculate the gas cost for the approval.\n let allowance: bigint;\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n try {\n allowance = await sourceClient.readContract({\n address: assetInAddressString,\n abi: erc20Abi,\n functionName: 'allowance',\n args: [quote.fromAddress, spenderAddress],\n });\n } catch (error) {\n throw new SdkError('Error during allowance check', ErrorCode.VIEM_ERROR, {\n cause: error,\n details: 'Failed to read ERC20 allowance for Markr spender.',\n });\n }\n\n const approvalNeeded = allowance < allowanceAmount;\n\n if (approvalNeeded) {\n allowanceApprovalGas = await estimateGasWithRevert(\n sourceClient,\n {\n account: quote.fromAddress,\n to: assetInAddressString,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, allowanceAmount],\n }),\n },\n erc20Abi,\n 'Failed to estimate gas for ERC20 approval transaction.',\n );\n }\n }\n\n const allowanceApprovalIsNeeded = allowanceApprovalGas > 0n;\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: assetInAddressString,\n tokenOut: assetToAddressString(quote.assetOut, quote.targetChain.chainId),\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n // Should hopefully never happen.\n const variantTag = isSolanaSwapResponse(swap)\n ? swap.chainType\n : isHyperliquidWithdrawSwapResponse(swap)\n ? swap.type\n : 'unknown';\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Received non-EVM swap response from Markr. Expected EVM transaction data for gas estimation, but got response variant \"${variantTag}\".`,\n });\n }\n\n let gas = 0n;\n\n // If an approval is needed, we can't call `eth_estimateGas` on the\n // swap transaction because no actual allowance approval was performed yet,\n // so a gas estimation would fail due to needing allowance.\n //\n // So if an allowance approval is needed, we fall back to some other logic for\n // estimating the swap tx gas.\n if (allowanceApprovalIsNeeded) {\n // While the approval is still pending we can't `eth_estimateGas` the swap (it would\n // revert on the missing allowance), so use Markr's gas-unit estimate when present and\n // otherwise a fixed gas-unit fallback. `gasEstimate` is documented as optional and may\n // be 0/omitted for relay.\n //\n // We deliberately do NOT derive this from the `fees` array. A `type: 'gas'` fee is a\n // token-denominated *cost amount* (e.g. native wei), not a gas-unit count — feeding it\n // into the `gas * maxFeePerGas` formula below produces a nonsensical fee.\n gas = quote.gasEstimate || EVM_SWAP_FALLBACK_GAS_ESTIMATE;\n } else {\n gas = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress: quote.fromAddress,\n sourceClient,\n swap,\n });\n }\n\n const fees = await estimateEvmFeesPerGas(sourceClient, quote.sourceChain, options?.overrides?.feeRateTier);\n\n const maxFeePerGas = options?.overrides?.maxFeePerGas ?? fees.maxFeePerGas;\n const maxPriorityFeePerGas = options?.overrides?.maxPriorityFeePerGas ?? fees.maxPriorityFeePerGas;\n\n const totalFeeWithoutMargin = (gas + allowanceApprovalGas) * maxFeePerGas;\n\n return {\n asset: quote.sourceChain.networkToken,\n totalFee: applyFeeUnitsBpsMargin(totalFeeWithoutMargin, options?.feeUnitsMarginBps),\n totalFeeWithoutMargin,\n meta: {\n approvalFee: allowanceApprovalIsNeeded ? allowanceApprovalGas * maxFeePerGas : undefined,\n maxFeePerGas,\n maxPriorityFeePerGas,\n },\n };\n}\n\n/** @internal */\nexport async function _estimateNativeFeeSolana(\n quote: Quote,\n options: EstimateNativeFeeOptions | undefined,\n { apiOptions, appId }: EstimateNativeFeeFactoryConfig,\n): Promise<NativeFeeEstimate> {\n const assetInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n\n if (!isSolanaAddress(assetInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: `assetIn address is not a valid Solana address. Can not call estimateGas.`,\n });\n }\n\n const additiveNativeFee: bigint = getAdditiveSourceNativeAssetFeeAmount(quote);\n const totalInput: bigint = quote.amountIn + additiveNativeFee;\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: assetInAddressString,\n tokenOut: assetToAddressString(quote.assetOut, quote.targetChain.chainId),\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n // Should hopefully never happen.\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-Solana swap response from Markr. Expected Solana transaction data for fee estimation.',\n });\n }\n\n const rpc = getSolanaRpcForChain({ chain: quote.sourceChain });\n\n const { baseFeeLamports, priorityFeeLamports, ...rest } = await estimateSolanaFee(rpc, swap.swapTransaction);\n\n const totalFeeWithoutMargin = rest.feePayerBalanceDiffLamports - totalInput;\n\n return {\n asset: quote.sourceChain.networkToken,\n totalFee: applyFeeUnitsBpsMargin(totalFeeWithoutMargin, options?.feeUnitsMarginBps),\n totalFeeWithoutMargin,\n meta: {\n ...rest,\n baseFee: baseFeeLamports,\n priorityFee: priorityFeeLamports,\n },\n };\n}\n\n/** @internal */\nexport async function _estimateGasFromSwapResponse({\n crossChain,\n feeUnitsMarginBps,\n fromAddress,\n sourceClient,\n swap,\n}: {\n crossChain: boolean;\n feeUnitsMarginBps?: number;\n fromAddress: EvmAddress;\n sourceClient: ReturnType<typeof getEvmClientForChain>;\n swap: WrappedSwapTransactionResponse;\n}): Promise<bigint> {\n const markrAbi = await getMarkrSwapWrapperAbi(crossChain);\n\n // Use raw estimateGas — the calldata is pre-encoded and may target any\n // contract (Markr wrapper, deBridge, etc.). The ABI is only used for\n // best-effort error decoding on the failure path.\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n {\n account: fromAddress,\n to: swap.to,\n data: swap.data,\n value: swap.value,\n },\n markrAbi,\n 'Failed to estimate gas for Markr swap transaction.',\n );\n\n return applyFeeUnitsBpsMargin(gasEstimate, feeUnitsMarginBps);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"estimate-native-fee.js","names":["isEvmAddress","isSolanaAddress"],"sources":["../../../../src/transfer-service/markr/_handlers/estimate-native-fee.ts"],"sourcesContent":["import { isAddress as isSolanaAddress } from '@solana/kit';\nimport { encodeFunctionData, erc20Abi, type Address as EvmAddress, isAddress as isEvmAddress } from 'viem';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { EstimateNativeFeeOptions, NativeFeeEstimate, TransferService } from '../../../types/service';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, getSolanaRpcForChain } from '../../_utils';\nimport { estimateEvmFeesPerGas } from '../../_evm-gas';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n getAdditiveSourceNativeAssetFeeAmount,\n getMarkrSwapWrapperAbi,\n isTokenAddressNative,\n} from '../_utils';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { isEvmSwapResponse, isHyperliquidWithdrawSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { caip2ToEip155ChainId } from '../../../utils/caip';\nimport type { Quote } from '../../../types/quote';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { estimateSolanaFee } from '../../../utils/solana';\nimport { _getGasLimit } from '../_hyperevm';\n\n/**\n * This is just a fallback value used in the case that an\n * allowance approval is needed, and Markr didn't return us any gas estimate data.\n *\n * Just based on my review of some quotes, I think this is a reasonable estimate\n * left on the higher end.\n *\n * Assume this could need to change.\n */\nconst EVM_SWAP_FALLBACK_GAS_ESTIMATE = 700_000n;\n\nexport interface EstimateNativeFeeFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n}\n\nexport function estimateNativeFeeFactory(config: EstimateNativeFeeFactoryConfig): TransferService['estimateNativeFee'] {\n return async (quote, options) => {\n // Either the source chain is EVM or Solana, we need to call different functions that\n // calculate the native fee depending on the chain kind.\n\n if (isEvmNamespace(quote.sourceChain.chainId)) {\n return await _estimateNativeFeeEvm(quote, options, config);\n }\n\n if (isSolanaNamespace(quote.sourceChain.chainId)) {\n return await _estimateNativeFeeSolana(quote, options, config);\n }\n\n throw new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n `Unsupported source chain namespace for estimateNativeFee: ${quote.sourceChain.chainId}`,\n );\n };\n}\n\n/** @internal */\nexport async function _estimateNativeFeeEvm(\n quote: Quote,\n options: EstimateNativeFeeOptions | undefined,\n { apiOptions, appId }: EstimateNativeFeeFactoryConfig,\n): Promise<NativeFeeEstimate> {\n if (!isEvmAddress(quote.fromAddress)) {\n throw new InvalidParamsError(ErrorReason.INVALID_PARAMS, `Invalid fromAddress: ${quote.fromAddress}`);\n }\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const assetInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n\n if (!isEvmAddress(assetInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: `assetIn address is not a valid EVM address. Can not call estimateGas.`,\n });\n }\n\n const isAssetInNative = isTokenAddressNative(assetInAddressString);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n let allowanceApprovalGas = 0n;\n if (!isAssetInNative) {\n // Check if approval is needed, and if so, calculate the gas cost for the approval.\n let allowance: bigint;\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n try {\n allowance = await sourceClient.readContract({\n address: assetInAddressString,\n abi: erc20Abi,\n functionName: 'allowance',\n args: [quote.fromAddress, spenderAddress],\n });\n } catch (error) {\n throw new SdkError('Error during allowance check', ErrorCode.VIEM_ERROR, {\n cause: error,\n details: 'Failed to read ERC20 allowance for Markr spender.',\n });\n }\n\n const approvalNeeded = allowance < allowanceAmount;\n\n if (approvalNeeded) {\n allowanceApprovalGas = await estimateGasWithRevert(\n sourceClient,\n {\n account: quote.fromAddress,\n to: assetInAddressString,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [spenderAddress, allowanceAmount],\n }),\n },\n erc20Abi,\n 'Failed to estimate gas for ERC20 approval transaction.',\n );\n }\n }\n\n const allowanceApprovalIsNeeded = allowanceApprovalGas > 0n;\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: assetInAddressString,\n tokenOut: assetToAddressString(quote.assetOut, quote.targetChain.chainId),\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n // Should hopefully never happen.\n const variantTag = isSolanaSwapResponse(swap)\n ? swap.chainType\n : isHyperliquidWithdrawSwapResponse(swap)\n ? swap.type\n : 'unknown';\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Received non-EVM swap response from Markr. Expected EVM transaction data for gas estimation, but got response variant \"${variantTag}\".`,\n });\n }\n\n let gas = 0n;\n\n // If an approval is needed, we can't call `eth_estimateGas` on the\n // swap transaction because no actual allowance approval was performed yet,\n // so a gas estimation would fail due to needing allowance.\n //\n // So if an allowance approval is needed, we fall back to some other logic for\n // estimating the swap tx gas.\n if (allowanceApprovalIsNeeded) {\n // While the approval is still pending we can't `eth_estimateGas` the swap (it would\n // revert on the missing allowance), so use Markr's gas-unit estimate when present and\n // otherwise a fixed gas-unit fallback. `gasEstimate` is documented as optional and may\n // be 0/omitted for relay.\n //\n // We deliberately do NOT derive this from the `fees` array. A `type: 'gas'` fee is a\n // token-denominated *cost amount* (e.g. native wei), not a gas-unit count — feeding it\n // into the `gas * maxFeePerGas` formula below produces a nonsensical fee.\n gas = quote.gasEstimate || EVM_SWAP_FALLBACK_GAS_ESTIMATE;\n } else {\n gas = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress: quote.fromAddress,\n gasLimit: _getGasLimit(quote),\n sourceClient,\n swap,\n });\n }\n\n const fees = await estimateEvmFeesPerGas(sourceClient, quote.sourceChain, options?.overrides?.feeRateTier);\n\n const maxFeePerGas = options?.overrides?.maxFeePerGas ?? fees.maxFeePerGas;\n const maxPriorityFeePerGas = options?.overrides?.maxPriorityFeePerGas ?? fees.maxPriorityFeePerGas;\n\n const totalFeeWithoutMargin = (gas + allowanceApprovalGas) * maxFeePerGas;\n\n return {\n asset: quote.sourceChain.networkToken,\n totalFee: applyFeeUnitsBpsMargin(totalFeeWithoutMargin, options?.feeUnitsMarginBps),\n totalFeeWithoutMargin,\n meta: {\n approvalFee: allowanceApprovalIsNeeded ? allowanceApprovalGas * maxFeePerGas : undefined,\n maxFeePerGas,\n maxPriorityFeePerGas,\n },\n };\n}\n\n/** @internal */\nexport async function _estimateNativeFeeSolana(\n quote: Quote,\n options: EstimateNativeFeeOptions | undefined,\n { apiOptions, appId }: EstimateNativeFeeFactoryConfig,\n): Promise<NativeFeeEstimate> {\n const assetInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n\n if (!isSolanaAddress(assetInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: `assetIn address is not a valid Solana address. Can not call estimateGas.`,\n });\n }\n\n const additiveNativeFee: bigint = getAdditiveSourceNativeAssetFeeAmount(quote);\n const totalInput: bigint = quote.amountIn + additiveNativeFee;\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: assetInAddressString,\n tokenOut: assetToAddressString(quote.assetOut, quote.targetChain.chainId),\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n // Should hopefully never happen.\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-Solana swap response from Markr. Expected Solana transaction data for fee estimation.',\n });\n }\n\n const rpc = getSolanaRpcForChain({ chain: quote.sourceChain });\n\n const { baseFeeLamports, priorityFeeLamports, ...rest } = await estimateSolanaFee(rpc, swap.swapTransaction);\n\n const totalFeeWithoutMargin = rest.feePayerBalanceDiffLamports - totalInput;\n\n return {\n asset: quote.sourceChain.networkToken,\n totalFee: applyFeeUnitsBpsMargin(totalFeeWithoutMargin, options?.feeUnitsMarginBps),\n totalFeeWithoutMargin,\n meta: {\n ...rest,\n baseFee: baseFeeLamports,\n priorityFee: priorityFeeLamports,\n },\n };\n}\n\n/** @internal */\nexport async function _estimateGasFromSwapResponse({\n crossChain,\n feeUnitsMarginBps,\n fromAddress,\n gasLimit,\n sourceClient,\n swap,\n}: {\n crossChain: boolean;\n feeUnitsMarginBps?: number;\n fromAddress: EvmAddress;\n /**\n * Explicit gas limit upper bound for `eth_estimateGas` (maps to the RPC\n * `gas` field). Required on HyperEVM (pass `HYPEREVM_BIG_BLOCK_GAS_LIMIT`):\n * the node otherwise caps the estimation search at the current small-block gas\n * limit and any route heavier than a small block reverts during estimation.\n * Omit on chains with a single block-gas-limit regime. Prefer {@link _getGasLimit}.\n */\n gasLimit?: bigint;\n sourceClient: ReturnType<typeof getEvmClientForChain>;\n swap: WrappedSwapTransactionResponse;\n}): Promise<bigint> {\n const markrAbi = await getMarkrSwapWrapperAbi(crossChain);\n\n // Use raw estimateGas — the calldata is pre-encoded and may target any\n // contract (Markr wrapper, deBridge, etc.). The ABI is only used for\n // best-effort error decoding on the failure path.\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n {\n account: fromAddress,\n to: swap.to,\n data: swap.data,\n value: swap.value,\n ...(gasLimit === undefined ? {} : { gas: gasLimit }),\n },\n markrAbi,\n 'Failed to estimate gas for Markr swap transaction.',\n );\n\n return applyFeeUnitsBpsMargin(gasEstimate, feeUnitsMarginBps);\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.cjs`),i=require(`../
|
|
1
|
+
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../../utils/caip.cjs`),r=require(`../../_utils.cjs`),i=require(`../_hyperliquid.cjs`),a=require(`../_api.cjs`),o=require(`../_hyperliquid-eip712.cjs`);let s=require(`viem`);function c(e){if(!/^\d+$/.test(e))throw new t.SdkError(`Hyperliquid swap response contained a malformed nonce.`,t.ErrorCode.INVALID_PARAMS);return BigInt(e)}function l(e,n,r){if(e.value.id!==n.id)throw new t.SdkError(`Relay sign.value.id does not match swap.id.`,t.ErrorCode.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`expected ${n.id}, got ${String(e.value.id)}`});if(String(e.value.nonce)!==n.nonce)throw new t.SdkError(`Relay sign.value.nonce does not match swap.nonce.`,t.ErrorCode.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`expected ${n.nonce}, got ${String(e.value.nonce)}`});if(e.value.wallet.toLowerCase()!==r.toLowerCase())throw new t.SdkError(`Relay sign.value.wallet does not match the signer address.`,t.ErrorCode.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`expected ${r}, got ${e.value.wallet}`})}async function u({apiOptions:u,environment:f,evmSigner:p,quote:m,swap:h,onStepChange:g}){if(!o.SUPPORTED_HL_PROTOCOL_VERSIONS.includes(h.protocolVersion))throw new t.SdkError(`Unsupported Hyperliquid withdrawal protocol version. Please update @avalabs/fusion-sdk.`,t.ErrorCode.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`Markr returned protocolVersion=${h.protocolVersion}; SDK supports [${o.SUPPORTED_HL_PROTOCOL_VERSIONS.join(`, `)}]`});if(!p.signTypedData)throw new t.SdkError(`Hyperliquid withdrawal requires an EIP-712 typed-data signer.`,t.ErrorCode.SIGNING_FAILED,{details:`EvmSigner.signTypedData is undefined. Wire it via wagmi useSignTypedData.`});if(!(0,s.isAddress)(m.fromAddress))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let _=m.fromAddress,v=n.caip2ToEip155ChainId(m.targetChain.chainId),y=c(h.nonce),b=h.protocolVersion>=2,x={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.HyperliquidAuthorize,quote:m,requiredSignatures:2};g?.(x);let S;if(b){if(!h.sign||!h.authorize)throw new t.SdkError("Hyperliquid v2 swap response is missing `sign` or `authorize` envelope.",t.ErrorCode.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`Required pass-through fields are absent — the upstream may have downgraded to v1.`});l(h.sign,h,_),S={domain:h.sign.domain,types:h.sign.types,primaryType:h.sign.primaryType,message:h.sign.value}}else S=o.buildRelayNonceMappingTypedData({signatureChainId:v,wallet:_,orderId:h.id,nonce:y});let C=await p.signTypedData({typedData:S,address:_,chainId:v},x);try{b&&h.authorize?await a.markrPostAuthorize(u,{uuid:m.id,signature:C,body:h.authorize.body}):await a.markrPostAuthorize(u,{uuid:m.id,signature:C,wallet:_,walletChainId:1337,signatureChainId:v,nonce:Number(y),id:h.id})}catch(e){if(e instanceof t.HttpError)return r.makeFailedTransferFromQuote(m,{environment:f,errorCode:t.ErrorCode.HL_EXCHANGE_REJECTED,errorReason:`Markr /authorize failed (HTTP ${e.status}). Please retry.`});throw e}let w=Number(h.parameters.amount),T=await i.hyperliquidGetWithdrawable({apiBaseUrl:i.hyperliquidApiBaseUrlForEnvironment(f),user:_});if(Number.isFinite(T)&&T<w)return r.makeFailedTransferFromQuote(m,{environment:f,errorCode:t.ErrorCode.HL_WITHDRAWABLE_DROPPED,errorReason:`Withdrawable balance changed during withdrawal (requested ${w}, available ${T}). Please retry with a smaller amount.`});let E={currentSignature:2,currentSignatureReason:e.TransferSignatureReason.HyperliquidSendAsset,quote:m,requiredSignatures:2};g?.(E);let D={signatureChainId:v,hyperliquidChain:h.parameters.hyperliquidChain,destination:h.parameters.destination,token:h.parameters.token,amount:h.parameters.amount,sourceDex:h.parameters.sourceDex,destinationDex:h.parameters.destinationDex,fromSubAccount:h.parameters.fromSubAccount,nonce:y},O=o.buildHyperliquidSendAssetTypedData(D),k=await p.signTypedData({typedData:O,address:_,chainId:v},E),A=o.buildHyperliquidExchangeAction(D),j=await i.hyperliquidExchangePost({apiBaseUrl:i.hyperliquidApiBaseUrlForEnvironment(f),signature:k,nonce:y,action:A});if(j.status!==`ok`)return r.makeFailedTransferFromQuote(m,{environment:f,errorCode:t.ErrorCode.HL_EXCHANGE_REJECTED,errorReason:d(j.response)});let M=Date.now();return{amountIn:m.amountIn,amountOut:m.amountOut,environment:f,fees:m.fees,fromAddress:m.fromAddress,id:m.id,partnerFeeBps:m.partnerFeeBps,sourceAsset:m.assetIn,sourceChain:m.sourceChain,status:`source-completed`,targetAsset:m.assetOut,targetChain:m.targetChain,toAddress:m.toAddress,type:m.serviceType,source:{confirmationCount:2,requiredConfirmationCount:2,startedAtMs:M,txHash:h.requestId}}}function d(e){return typeof e==`string`?`Hyperliquid /exchange rejected the transfer: ${e}`:e&&typeof e==`object`&&`error`in e&&typeof e.error==`string`?`Hyperliquid /exchange rejected the transfer: ${e.error}`:t.ErrorReason.UNKNOWN}exports._executeHyperliquidWithdraw=u;
|
|
2
2
|
//# sourceMappingURL=transfer-asset-hyperliquid-withdraw.cjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{TransferSignatureReason as e}from"../../../constants.js";import{ErrorCode as t,ErrorReason as n,HttpError as r,SdkError as i}from"../../../errors.js";import{caip2ToEip155ChainId as a}from"../../../utils/caip.js";import{makeFailedTransferFromQuote as o}from"../../_utils.js";import{
|
|
1
|
+
import{TransferSignatureReason as e}from"../../../constants.js";import{ErrorCode as t,ErrorReason as n,HttpError as r,SdkError as i}from"../../../errors.js";import{caip2ToEip155ChainId as a}from"../../../utils/caip.js";import{makeFailedTransferFromQuote as o}from"../../_utils.js";import{hyperliquidApiBaseUrlForEnvironment as s,hyperliquidExchangePost as c,hyperliquidGetWithdrawable as l}from"../_hyperliquid.js";import{markrPostAuthorize as u}from"../_api.js";import{SUPPORTED_HL_PROTOCOL_VERSIONS as d,buildHyperliquidExchangeAction as f,buildHyperliquidSendAssetTypedData as p,buildRelayNonceMappingTypedData as m}from"../_hyperliquid-eip712.js";import{isAddress as h}from"viem";function g(e){if(!/^\d+$/.test(e))throw new i(`Hyperliquid swap response contained a malformed nonce.`,t.INVALID_PARAMS);return BigInt(e)}function _(e,n,r){if(e.value.id!==n.id)throw new i(`Relay sign.value.id does not match swap.id.`,t.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`expected ${n.id}, got ${String(e.value.id)}`});if(String(e.value.nonce)!==n.nonce)throw new i(`Relay sign.value.nonce does not match swap.nonce.`,t.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`expected ${n.nonce}, got ${String(e.value.nonce)}`});if(e.value.wallet.toLowerCase()!==r.toLowerCase())throw new i(`Relay sign.value.wallet does not match the signer address.`,t.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`expected ${r}, got ${e.value.wallet}`})}async function v({apiOptions:v,environment:b,evmSigner:x,quote:S,swap:C,onStepChange:w}){if(!d.includes(C.protocolVersion))throw new i(`Unsupported Hyperliquid withdrawal protocol version. Please update @avalabs/fusion-sdk.`,t.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`Markr returned protocolVersion=${C.protocolVersion}; SDK supports [${d.join(`, `)}]`});if(!x.signTypedData)throw new i(`Hyperliquid withdrawal requires an EIP-712 typed-data signer.`,t.SIGNING_FAILED,{details:`EvmSigner.signTypedData is undefined. Wire it via wagmi useSignTypedData.`});if(!h(S.fromAddress))throw new i(n.INVALID_PARAMS,t.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let T=S.fromAddress,E=a(S.targetChain.chainId),D=g(C.nonce),O=C.protocolVersion>=2,k={currentSignature:1,currentSignatureReason:e.HyperliquidAuthorize,quote:S,requiredSignatures:2};w?.(k);let A;if(O){if(!C.sign||!C.authorize)throw new i("Hyperliquid v2 swap response is missing `sign` or `authorize` envelope.",t.HL_UNSUPPORTED_PROTOCOL_VERSION,{details:`Required pass-through fields are absent — the upstream may have downgraded to v1.`});_(C.sign,C,T),A={domain:C.sign.domain,types:C.sign.types,primaryType:C.sign.primaryType,message:C.sign.value}}else A=m({signatureChainId:E,wallet:T,orderId:C.id,nonce:D});let j=await x.signTypedData({typedData:A,address:T,chainId:E},k);try{O&&C.authorize?await u(v,{uuid:S.id,signature:j,body:C.authorize.body}):await u(v,{uuid:S.id,signature:j,wallet:T,walletChainId:1337,signatureChainId:E,nonce:Number(D),id:C.id})}catch(e){if(e instanceof r)return o(S,{environment:b,errorCode:t.HL_EXCHANGE_REJECTED,errorReason:`Markr /authorize failed (HTTP ${e.status}). Please retry.`});throw e}let M=Number(C.parameters.amount),N=await l({apiBaseUrl:s(b),user:T});if(Number.isFinite(N)&&N<M)return o(S,{environment:b,errorCode:t.HL_WITHDRAWABLE_DROPPED,errorReason:`Withdrawable balance changed during withdrawal (requested ${M}, available ${N}). Please retry with a smaller amount.`});let P={currentSignature:2,currentSignatureReason:e.HyperliquidSendAsset,quote:S,requiredSignatures:2};w?.(P);let F={signatureChainId:E,hyperliquidChain:C.parameters.hyperliquidChain,destination:C.parameters.destination,token:C.parameters.token,amount:C.parameters.amount,sourceDex:C.parameters.sourceDex,destinationDex:C.parameters.destinationDex,fromSubAccount:C.parameters.fromSubAccount,nonce:D},I=p(F),L=await x.signTypedData({typedData:I,address:T,chainId:E},P),R=f(F),z=await c({apiBaseUrl:s(b),signature:L,nonce:D,action:R});if(z.status!==`ok`)return o(S,{environment:b,errorCode:t.HL_EXCHANGE_REJECTED,errorReason:y(z.response)});let B=Date.now();return{amountIn:S.amountIn,amountOut:S.amountOut,environment:b,fees:S.fees,fromAddress:S.fromAddress,id:S.id,partnerFeeBps:S.partnerFeeBps,sourceAsset:S.assetIn,sourceChain:S.sourceChain,status:`source-completed`,targetAsset:S.assetOut,targetChain:S.targetChain,toAddress:S.toAddress,type:S.serviceType,source:{confirmationCount:2,requiredConfirmationCount:2,startedAtMs:B,txHash:C.requestId}}}function y(e){return typeof e==`string`?`Hyperliquid /exchange rejected the transfer: ${e}`:e&&typeof e==`object`&&`error`in e&&typeof e.error==`string`?`Hyperliquid /exchange rejected the transfer: ${e.error}`:n.UNKNOWN}export{v as _executeHyperliquidWithdraw};
|
|
2
2
|
//# sourceMappingURL=transfer-asset-hyperliquid-withdraw.js.map
|
|
@@ -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.cjs`),i=require(`../../_evm-approval.cjs`),a=require(`../../../_utils/chain.cjs`),o=require(`../_api.cjs`),s=require(`../../../utils/sol-address.cjs`),c=require(`../_utils.cjs`),l=require(`../_type-guards.cjs`),u=require(`../../../utils/solana.cjs`),d=require(`./estimate-native-fee.cjs`),
|
|
1
|
+
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../../utils/caip.cjs`),r=require(`../../_utils.cjs`),i=require(`../../_evm-approval.cjs`),a=require(`../../../_utils/chain.cjs`),o=require(`../_api.cjs`),s=require(`../../../utils/sol-address.cjs`),c=require(`../_utils.cjs`),l=require(`../_type-guards.cjs`),u=require(`../../../utils/solana.cjs`),d=require(`../_hyperevm.cjs`),f=require(`./estimate-native-fee.cjs`),p=require(`./transfer-asset-hyperliquid-withdraw.cjs`);let m=require(`viem`);function h({apiOptions:n,appId:r,environment:i,evmSigner:o,solanaSigner:s}){return async({quote:c,gasSettings:l,fallbackToDefaultOnBatchFailure:u,onStepChange:d})=>{if(c.serviceType!==e.ServiceType.MARKR)throw new t.SdkError(t.ErrorReason.INCORRECT_PROVIDER_PROVIDED,t.ErrorCode.INVALID_PARAMS);let f=Math.floor(Date.now()/1e3);if(c.expiresAt<=f)throw new t.SdkError(t.ErrorReason.QUOTE_EXPIRED,t.ErrorCode.INVALID_PARAMS);let p=c.sourceChain.chainId;if(p===e.HyperliquidChainIds.MAINNET)return g({apiOptions:n,appId:r,environment:i,evmSigner:o,quote:c,onStepChange:d});if(a.isSolanaNamespace(p))return v({apiOptions:n,appId:r,environment:i,solanaSigner:s,quote:c,onStepChange:d});if(a.isEvmNamespace(p))return _({apiOptions:n,appId:r,environment:i,evmSigner:o,quote:c,gasSettings:l,fallbackToDefaultOnBatchFailure:u,onStepChange:d});throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Unsupported source chain namespace: ${p}`})}}async function g({apiOptions:e,appId:n,environment:r,evmSigner:i,quote:a,onStepChange:s}){let u=c.calculateMarkrMinimumAmountOut({amountOut:a.amountOut,assetOut:a.assetOut,slippageBps:a.slippageBps}),d=c.assetToAddressString(a.assetIn,a.sourceChain.chainId),f=c.assetToAddressString(a.assetOut,a.targetChain.chainId),m=await o.markrSwap(e,{amountIn:a.amountIn.toString(),appId:n,minAmountOut:u.toString(),tokenIn:d,tokenOut:f,uuid:a.id});if(!l.isHyperliquidWithdrawSwapResponse(m))throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:"Expected `hyperliquid-withdraw` swap response from Markr for Hyperliquid source chain, but received a different variant."});return p._executeHyperliquidWithdraw({apiOptions:e,environment:r,evmSigner:i,quote:a,swap:m,onStepChange:s})}async function _({apiOptions:a,appId:s,environment:u,evmSigner:p,quote:h,gasSettings:g,fallbackToDefaultOnBatchFailure:_,onStepChange:v}){let b=h.fromAddress;if(!(0,m.isAddress)(b))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let x=c.calculateMarkrMinimumAmountOut({amountOut:h.amountOut,assetOut:h.assetOut,slippageBps:h.slippageBps}),S=r.getEvmClientForChain({chain:h.sourceChain}),C=c.assetToAddressString(h.assetIn,h.sourceChain.chainId),w=c.assetToAddressString(h.assetOut,h.targetChain.chainId);if(!(0,m.isAddress)(C))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address.`});let T=C,E=c.isTokenAddressNative(T),D=h.sourceChain.chainId.toLowerCase()!==h.targetChain.chainId.toLowerCase(),O=h.amountIn+c.getAdditiveSourceAssetFeeAmount(h),{address:k}=await o.markrGetSpenderAddress(a,{chainId:n.caip2ToEip155ChainId(h.sourceChain.chainId),crossChainSwap:D,quoteId:h.id});if(!E&&!k)throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${h.sourceChain.chainId}.`});let A=!E&&k?await i.buildErc20ApprovalRequest({chainIdHex:n.caip2ToEip155HexChainId(h.sourceChain.chainId),client:S,gasSettings:g,owner:b,requiredAllowance:O,spender:k,token:T}):void 0,j=A!==void 0,M=y({approvalRequest:A,requiresApprovalSignature:j,signBatch:p.signBatch,sourceChainId:h.sourceChain.chainId,targetChainId:h.targetChain.chainId}),N=await o.markrSwap(a,{amountIn:h.amountIn.toString(),appId:s,minAmountOut:x.toString(),tokenIn:C,tokenOut:w,uuid:h.id});if(!l.isEvmSwapResponse(N))throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.`});let P=(t,n=Date.now())=>{let r=h.sourceChain.chainId===h.targetChain.chainId;return{amountIn:h.amountIn,amountOut:h.amountOut,environment:u,fees:h.fees,fromAddress:h.fromAddress,id:h.id,partnerFeeBps:h.partnerFeeBps,sourceAsset:h.assetIn,sourceChain:h.sourceChain,status:`source-pending`,targetAsset:h.assetOut,targetChain:h.targetChain,toAddress:h.toAddress,type:e.ServiceType.MARKR,source:{confirmationCount:0,requiredConfirmationCount:r?1:2,startedAtMs:n,txHash:t}}};if(M&&A){let i={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.TokensTransfer,quote:h,requiredSignatures:1},a=p.signBatch;if(!a)throw new t.SdkError(`One-click batch signer is not available.`,t.ErrorCode.SIGNING_FAILED);let o={chainId:n.caip2ToEip155HexChainId(h.sourceChain.chainId),data:N.data,from:b,gas:void 0,to:N.to,value:N.value,...r.maybe1559(g)};v?.(i);try{let e=(await a([A,o],async e=>S.sendRawTransaction({serializedTransaction:e}),i)).at(-1);if(!e)throw new t.SdkError(`One-click batch signing returned no transaction hashes.`,t.ErrorCode.SIGNING_FAILED);return P(e)}catch(e){if(!_)throw e}}if(j&&A)try{await i.signApprovalAndAssertConfirmed({client:S,evmSigner:p,onStepChange:v,request:A,step:{currentSignature:1,currentSignatureReason:e.TransferSignatureReason.AllowanceApproval,quote:h,requiredSignatures:2}})}catch(e){if(e instanceof i.ApprovalRevertedError)return r.makeFailedTransferFromQuote(h,{environment:u,errorCode:t.ErrorCode.TRANSACTION_REVERTED,errorReason:`ERC20 approval transaction was reverted`});throw e}let F=await f._estimateGasFromSwapResponse({crossChain:D,fromAddress:b,feeUnitsMarginBps:g?.estimateGasMarginBps,gasLimit:d._getGasLimit(h),sourceClient:S,swap:N}),I=await d.maybeEnableHyperEvmBigBlocks({environment:u,evmSigner:p,fromAddress:b,onStepChange:v,quote:h,requiresApprovalSignature:j,swapGasWithMargin:F});if(!I.ok)return I.transfer;let{requiredSignatures:L}=I,R={chainId:n.caip2ToEip155HexChainId(h.sourceChain.chainId),data:N.data,from:b,gas:F,to:N.to,value:N.value,...r.maybe1559(g)},z={currentSignature:L,currentSignatureReason:e.TransferSignatureReason.TokensTransfer,quote:h,requiredSignatures:L};v?.(z);let B=Date.now();return P(await p.sign(R,async e=>S.sendRawTransaction({serializedTransaction:e}),z),B)}async function v({apiOptions:n,appId:i,environment:a,solanaSigner:d,quote:f,onStepChange:p}){if(!d)throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`solanaSigner is required for Solana transfers but was not provided.`});if(!s.isSolAddress(f.fromAddress))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid Solana address.`});let m=c.calculateMarkrMinimumAmountOut({amountOut:f.amountOut,assetOut:f.assetOut,slippageBps:f.slippageBps}),h=c.assetToAddressString(f.assetIn,f.sourceChain.chainId),g=c.assetToAddressString(f.assetOut,f.targetChain.chainId),_=await o.markrSwap(n,{amountIn:f.amountIn.toString(),appId:i,minAmountOut:m.toString(),tokenIn:h,tokenOut:g,userPublicKey:f.fromAddress,uuid:f.id});if(!l.isSolanaSwapResponse(_))throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.`});console.debug(`[Fusion SDK] Original swap transaction (base64):`,_.swapTransaction);let v=await u.refreshSolanaSwapTransactionBlockhash(_.swapTransaction,r.getSolanaRpcForChain({chain:f.sourceChain}));console.debug(`[Fusion SDK] Refreshed swap transaction with new blockhash (base64):`,v);let y={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.TokensTransfer,quote:f,requiredSignatures:1};p?.(y);let b=Date.now(),x=await d.signAndSend({account:f.fromAddress,serializedTx:v},y),S=f.sourceChain.chainId.toLowerCase()!==f.targetChain.chainId.toLowerCase();return{amountIn:f.amountIn,amountOut:f.amountOut,environment:a,fees:f.fees,fromAddress:f.fromAddress,id:f.id,partnerFeeBps:f.partnerFeeBps,sourceAsset:f.assetIn,sourceChain:f.sourceChain,status:`source-pending`,targetAsset:f.assetOut,targetChain:f.targetChain,toAddress:f.toAddress,type:e.ServiceType.MARKR,source:{confirmationCount:0,requiredConfirmationCount:S?2:32,startedAtMs:b,txHash:x}}}function y({approvalRequest:t,requiresApprovalSignature:n,signBatch:r,sourceChainId:i,targetChainId:o}){return a.isEvmNamespace(i)&&a.isEvmNamespace(o)&&i===o&&i!==e.HyperEvmChainIds.MAINNET&&n&&t!==void 0&&typeof r==`function`}exports.transferAssetFactory=h;
|
|
2
2
|
//# sourceMappingURL=transfer-asset.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer-asset.cjs","names":["ServiceType","SdkError","ErrorReason","ErrorCode","HyperliquidChainIds","isSolanaNamespace","isEvmNamespace","calculateMarkrMinimumAmountOut","assetToAddressString","markrSwap","isHyperliquidWithdrawSwapResponse","_executeHyperliquidWithdraw","getEvmClientForChain","isTokenAddressNative","getAdditiveSourceAssetFeeAmount","markrGetSpenderAddress","caip2ToEip155ChainId","buildErc20ApprovalRequest","caip2ToEip155HexChainId","isEvmSwapResponse","TransferSignatureReason","maybe1559","signApprovalAndAssertConfirmed","ApprovalRevertedError","makeFailedTransferFromQuote","_estimateGasFromSwapResponse","isSolAddress","isSolanaSwapResponse","refreshSolanaSwapTransactionBlockhash","getSolanaRpcForChain"],"sources":["../../../../src/transfer-service/markr/_handlers/transfer-asset.ts"],"sourcesContent":["import { isAddress } from 'viem';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { HyperliquidChainIds, ServiceType, TransferSignatureReason } from '../../../constants';\nimport type { Environment } from '../../../constants';\nimport { ErrorCode, ErrorReason, SdkError } from '../../../errors';\nimport type { TransferService } from '../../../types/service';\nimport type { EvmSigner, EvmTransactionRequest, SolanaSigner } from '../../../types/signer';\nimport type { Transfer, TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport { getEvmClientForChain, getSolanaRpcForChain, makeFailedTransferFromQuote, maybe1559 } from '../../_utils';\nimport { ApprovalRevertedError, buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n isTokenAddressNative,\n} from '../_utils';\nimport { isEvmSwapResponse, isHyperliquidWithdrawSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { SOLANA_REQUIRED_CONFIRMATIONS } from '../constants';\nimport { _estimateGasFromSwapResponse } from './estimate-native-fee';\nimport { _executeHyperliquidWithdraw } from './transfer-asset-hyperliquid-withdraw';\nimport type { Caip2ChainId } from '../../../types/caip';\nimport { refreshSolanaSwapTransactionBlockhash } from '../../../utils/solana';\n\nexport interface TransferAssetFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n solanaSigner?: SolanaSigner;\n}\n\nexport function transferAssetFactory({\n apiOptions,\n appId,\n environment,\n evmSigner,\n solanaSigner,\n}: TransferAssetFactoryConfig): TransferService['transferAsset'] {\n return async ({ quote, gasSettings, fallbackToDefaultOnBatchFailure, onStepChange }) => {\n if (quote.serviceType !== ServiceType.MARKR) {\n throw new SdkError(ErrorReason.INCORRECT_PROVIDER_PROVIDED, ErrorCode.INVALID_PARAMS);\n }\n\n const now = Math.floor(Date.now() / 1_000);\n\n if (quote.expiresAt <= now) {\n throw new SdkError(ErrorReason.QUOTE_EXPIRED, ErrorCode.INVALID_PARAMS);\n }\n\n const sourceChainId = quote.sourceChain.chainId;\n\n if (sourceChainId === HyperliquidChainIds.MAINNET) {\n return _executeHyperliquidWithdrawTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n onStepChange,\n });\n }\n\n if (isSolanaNamespace(sourceChainId)) {\n return _executeSvmTransfer({ apiOptions, appId, environment, solanaSigner, quote, onStepChange });\n }\n\n if (isEvmNamespace(sourceChainId)) {\n return _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n });\n }\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Unsupported source chain namespace: ${sourceChainId}`,\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// Hyperliquid withdrawal path — wires `markrSwap` → HL handler\n// ---------------------------------------------------------------------------\n\ninterface HyperliquidWithdrawTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeHyperliquidWithdrawTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n onStepChange,\n}: HyperliquidWithdrawTransferParams): Promise<Transfer> {\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n uuid: quote.id,\n });\n\n if (!isHyperliquidWithdrawSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details:\n 'Expected `hyperliquid-withdraw` swap response from Markr for Hyperliquid source chain, but received a different variant.',\n });\n }\n\n return _executeHyperliquidWithdraw({\n apiOptions,\n environment,\n evmSigner,\n quote,\n swap,\n onStepChange,\n });\n}\n\n// ---------------------------------------------------------------------------\n// EVM transfer path\n// ---------------------------------------------------------------------------\n\ninterface EvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n gasSettings?: Parameters<TransferService['transferAsset']>[0]['gasSettings'];\n fallbackToDefaultOnBatchFailure?: Parameters<TransferService['transferAsset']>[0]['fallbackToDefaultOnBatchFailure'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n}: EvmTransferParams): Promise<Transfer> {\n const fromAddress = quote.fromAddress;\n\n if (!isAddress(fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid EVM address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n if (!isAddress(tokenInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'assetIn address is not a valid EVM address.',\n });\n }\n\n const tokenInAddress = tokenInAddressString;\n const isTokenInNative = isTokenAddressNative(tokenInAddress);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n if (!isTokenInNative && !spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${quote.sourceChain.chainId}.`,\n });\n }\n\n const approvalRequest: EvmTransactionRequest | undefined =\n !isTokenInNative && spenderAddress\n ? await buildErc20ApprovalRequest({\n chainIdHex: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: allowanceAmount,\n spender: spenderAddress,\n token: tokenInAddress,\n })\n : undefined;\n const requiresApprovalSignature = approvalRequest !== undefined;\n\n const maybeOneClickBatch = isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch: evmSigner.signBatch,\n sourceChainId: quote.sourceChain.chainId,\n targetChainId: quote.targetChain.chainId,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.',\n });\n }\n\n const makePendingTransfer = (txHash: `0x${string}`, startedAtMs: number = Date.now()): Transfer => {\n const isSameChainTransfer = quote.sourceChain.chainId === quote.targetChain.chainId;\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isSameChainTransfer ? 1 : 2,\n startedAtMs,\n txHash,\n },\n };\n };\n\n if (maybeOneClickBatch && approvalRequest) {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n const signBatch = evmSigner.signBatch;\n\n if (!signBatch) {\n throw new SdkError('One-click batch signer is not available.', ErrorCode.SIGNING_FAILED);\n }\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n // Gas is purposely left undefined here.\n // We can't estimate the gas because we aren't executing the\n // approval tx. It's up to the wallet to correctly handle gas estimation.\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n onStepChange?.(batchStep);\n\n try {\n const txHashes = await signBatch(\n [approvalRequest, swapRequest],\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n\n const swapTxHash = txHashes.at(-1);\n\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n\n return makePendingTransfer(swapTxHash);\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n }\n }\n\n if (requiresApprovalSignature && approvalRequest) {\n try {\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n onStepChange,\n request: approvalRequest,\n step: {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote,\n requiredSignatures: 2,\n },\n });\n } catch (error) {\n // Match the original behavior of \"branch only on the confirmed-then-\n // reverted receipt status\" by discriminating on the dedicated error\n // class — signer rejection / RPC errors fall through to the rethrow.\n if (error instanceof ApprovalRevertedError) {\n return makeFailedTransferFromQuote(quote, {\n environment,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'ERC20 approval transaction was reverted',\n });\n }\n throw error;\n }\n }\n\n const swapGasWithMargin = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress,\n feeUnitsMarginBps: gasSettings?.estimateGasMarginBps,\n sourceClient,\n swap,\n });\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n gas: swapGasWithMargin,\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: requiresApprovalSignature ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: requiresApprovalSignature ? 2 : 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await evmSigner.sign(\n swapRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return makePendingTransfer(txHash, startedAtMs);\n}\n\n// ---------------------------------------------------------------------------\n// SVM (Solana) transfer path\n// ---------------------------------------------------------------------------\n\ninterface SvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n solanaSigner?: SolanaSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeSvmTransfer({\n apiOptions,\n appId,\n environment,\n solanaSigner,\n quote,\n onStepChange,\n}: SvmTransferParams): Promise<Transfer> {\n if (!solanaSigner) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'solanaSigner is required for Solana transfers but was not provided.',\n });\n }\n\n if (!isSolAddress(quote.fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid Solana address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.',\n });\n }\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Original swap transaction (base64):', swap.swapTransaction);\n\n const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Refreshed swap transaction with new blockhash (base64):', swapTransactionBase64);\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await solanaSigner.signAndSend(\n {\n account: quote.fromAddress,\n serializedTx: swapTransactionBase64,\n },\n step,\n );\n\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isCrossChainSwap ? 2 : SOLANA_REQUIRED_CONFIRMATIONS,\n startedAtMs,\n txHash,\n },\n };\n}\n\n/**\n * Determines whether one-click swap eligibility criteria is met.\n *\n * Only same-chain EVM swaps are currently eligible.\n */\nfunction isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch,\n sourceChainId,\n targetChainId,\n}: {\n approvalRequest?: EvmTransactionRequest;\n requiresApprovalSignature: boolean;\n signBatch?: EvmSigner['signBatch'];\n sourceChainId: Caip2ChainId;\n targetChainId: Caip2ChainId;\n}): boolean {\n return (\n isEvmNamespace(sourceChainId) &&\n isEvmNamespace(targetChainId) &&\n sourceChainId === targetChainId &&\n requiresApprovalSignature &&\n approvalRequest !== undefined &&\n typeof signBatch === 'function'\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transfer-asset.cjs","names":["ServiceType","SdkError","ErrorReason","ErrorCode","HyperliquidChainIds","isSolanaNamespace","isEvmNamespace","calculateMarkrMinimumAmountOut","assetToAddressString","markrSwap","isHyperliquidWithdrawSwapResponse","_executeHyperliquidWithdraw","getEvmClientForChain","isTokenAddressNative","getAdditiveSourceAssetFeeAmount","markrGetSpenderAddress","caip2ToEip155ChainId","buildErc20ApprovalRequest","caip2ToEip155HexChainId","isEvmSwapResponse","TransferSignatureReason","maybe1559","signApprovalAndAssertConfirmed","ApprovalRevertedError","makeFailedTransferFromQuote","_estimateGasFromSwapResponse","_getGasLimit","maybeEnableHyperEvmBigBlocks","isSolAddress","isSolanaSwapResponse","refreshSolanaSwapTransactionBlockhash","getSolanaRpcForChain","HyperEvmChainIds"],"sources":["../../../../src/transfer-service/markr/_handlers/transfer-asset.ts"],"sourcesContent":["import { isAddress } from 'viem';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { HyperEvmChainIds, HyperliquidChainIds, ServiceType, TransferSignatureReason } from '../../../constants';\nimport type { Environment } from '../../../constants';\nimport { ErrorCode, ErrorReason, SdkError } from '../../../errors';\nimport type { TransferService } from '../../../types/service';\nimport type { EvmSigner, EvmTransactionRequest, SolanaSigner } from '../../../types/signer';\nimport type { Transfer, TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport { getEvmClientForChain, getSolanaRpcForChain, makeFailedTransferFromQuote, maybe1559 } from '../../_utils';\nimport { ApprovalRevertedError, buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { markrGetSpenderAddress, markrSwap, type ApiOptions } from '../_api';\nimport { _getGasLimit, maybeEnableHyperEvmBigBlocks } from '../_hyperevm';\nimport {\n assetToAddressString,\n calculateMarkrMinimumAmountOut,\n getAdditiveSourceAssetFeeAmount,\n isTokenAddressNative,\n} from '../_utils';\nimport { isEvmSwapResponse, isHyperliquidWithdrawSwapResponse, isSolanaSwapResponse } from '../_type-guards';\nimport { SOLANA_REQUIRED_CONFIRMATIONS } from '../constants';\nimport { _estimateGasFromSwapResponse } from './estimate-native-fee';\nimport { _executeHyperliquidWithdraw } from './transfer-asset-hyperliquid-withdraw';\nimport type { Caip2ChainId } from '../../../types/caip';\nimport { refreshSolanaSwapTransactionBlockhash } from '../../../utils/solana';\n\nexport interface TransferAssetFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n solanaSigner?: SolanaSigner;\n}\n\nexport function transferAssetFactory({\n apiOptions,\n appId,\n environment,\n evmSigner,\n solanaSigner,\n}: TransferAssetFactoryConfig): TransferService['transferAsset'] {\n return async ({ quote, gasSettings, fallbackToDefaultOnBatchFailure, onStepChange }) => {\n if (quote.serviceType !== ServiceType.MARKR) {\n throw new SdkError(ErrorReason.INCORRECT_PROVIDER_PROVIDED, ErrorCode.INVALID_PARAMS);\n }\n\n const now = Math.floor(Date.now() / 1_000);\n\n if (quote.expiresAt <= now) {\n throw new SdkError(ErrorReason.QUOTE_EXPIRED, ErrorCode.INVALID_PARAMS);\n }\n\n const sourceChainId = quote.sourceChain.chainId;\n\n if (sourceChainId === HyperliquidChainIds.MAINNET) {\n return _executeHyperliquidWithdrawTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n onStepChange,\n });\n }\n\n if (isSolanaNamespace(sourceChainId)) {\n return _executeSvmTransfer({ apiOptions, appId, environment, solanaSigner, quote, onStepChange });\n }\n\n if (isEvmNamespace(sourceChainId)) {\n return _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n });\n }\n\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Unsupported source chain namespace: ${sourceChainId}`,\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// Hyperliquid withdrawal path — wires `markrSwap` → HL handler\n// ---------------------------------------------------------------------------\n\ninterface HyperliquidWithdrawTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeHyperliquidWithdrawTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n onStepChange,\n}: HyperliquidWithdrawTransferParams): Promise<Transfer> {\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n uuid: quote.id,\n });\n\n if (!isHyperliquidWithdrawSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details:\n 'Expected `hyperliquid-withdraw` swap response from Markr for Hyperliquid source chain, but received a different variant.',\n });\n }\n\n return _executeHyperliquidWithdraw({\n apiOptions,\n environment,\n evmSigner,\n quote,\n swap,\n onStepChange,\n });\n}\n\n// ---------------------------------------------------------------------------\n// EVM transfer path\n// ---------------------------------------------------------------------------\n\ninterface EvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n evmSigner: EvmSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n gasSettings?: Parameters<TransferService['transferAsset']>[0]['gasSettings'];\n fallbackToDefaultOnBatchFailure?: Parameters<TransferService['transferAsset']>[0]['fallbackToDefaultOnBatchFailure'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeEvmTransfer({\n apiOptions,\n appId,\n environment,\n evmSigner,\n quote,\n gasSettings,\n fallbackToDefaultOnBatchFailure,\n onStepChange,\n}: EvmTransferParams): Promise<Transfer> {\n const fromAddress = quote.fromAddress;\n\n if (!isAddress(fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid EVM address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const sourceClient = getEvmClientForChain({ chain: quote.sourceChain });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n if (!isAddress(tokenInAddressString)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'assetIn address is not a valid EVM address.',\n });\n }\n\n const tokenInAddress = tokenInAddressString;\n const isTokenInNative = isTokenAddressNative(tokenInAddress);\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n const allowanceAmount = quote.amountIn + getAdditiveSourceAssetFeeAmount(quote);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: caip2ToEip155ChainId(quote.sourceChain.chainId),\n crossChainSwap: isCrossChainSwap,\n quoteId: quote.id,\n });\n\n if (!isTokenInNative && !spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${quote.sourceChain.chainId}.`,\n });\n }\n\n const approvalRequest: EvmTransactionRequest | undefined =\n !isTokenInNative && spenderAddress\n ? await buildErc20ApprovalRequest({\n chainIdHex: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: allowanceAmount,\n spender: spenderAddress,\n token: tokenInAddress,\n })\n : undefined;\n const requiresApprovalSignature = approvalRequest !== undefined;\n\n const maybeOneClickBatch = isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch: evmSigner.signBatch,\n sourceChainId: quote.sourceChain.chainId,\n targetChainId: quote.targetChain.chainId,\n });\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n uuid: quote.id,\n });\n\n if (!isEvmSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.',\n });\n }\n\n const makePendingTransfer = (txHash: `0x${string}`, startedAtMs: number = Date.now()): Transfer => {\n const isSameChainTransfer = quote.sourceChain.chainId === quote.targetChain.chainId;\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isSameChainTransfer ? 1 : 2,\n startedAtMs,\n txHash,\n },\n };\n };\n\n if (maybeOneClickBatch && approvalRequest) {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n const signBatch = evmSigner.signBatch;\n\n if (!signBatch) {\n throw new SdkError('One-click batch signer is not available.', ErrorCode.SIGNING_FAILED);\n }\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n // Gas is purposely left undefined here.\n // We can't estimate the gas because we aren't executing the\n // approval tx. It's up to the wallet to correctly handle gas estimation.\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n onStepChange?.(batchStep);\n\n try {\n const txHashes = await signBatch(\n [approvalRequest, swapRequest],\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n\n const swapTxHash = txHashes.at(-1);\n\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n\n return makePendingTransfer(swapTxHash);\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n }\n }\n\n if (requiresApprovalSignature && approvalRequest) {\n try {\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n onStepChange,\n request: approvalRequest,\n step: {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote,\n requiredSignatures: 2,\n },\n });\n } catch (error) {\n // Match the original behavior of \"branch only on the confirmed-then-\n // reverted receipt status\" by discriminating on the dedicated error\n // class — signer rejection / RPC errors fall through to the rethrow.\n if (error instanceof ApprovalRevertedError) {\n return makeFailedTransferFromQuote(quote, {\n environment,\n errorCode: ErrorCode.TRANSACTION_REVERTED,\n errorReason: 'ERC20 approval transaction was reverted',\n });\n }\n throw error;\n }\n }\n\n const swapGasWithMargin = await _estimateGasFromSwapResponse({\n crossChain: isCrossChainSwap,\n fromAddress,\n feeUnitsMarginBps: gasSettings?.estimateGasMarginBps,\n gasLimit: _getGasLimit(quote),\n sourceClient,\n swap,\n });\n\n const bigBlocksResult = await maybeEnableHyperEvmBigBlocks({\n environment,\n evmSigner,\n fromAddress,\n onStepChange,\n quote,\n requiresApprovalSignature,\n swapGasWithMargin,\n });\n\n if (!bigBlocksResult.ok) {\n return bigBlocksResult.transfer;\n }\n\n const { requiredSignatures } = bigBlocksResult;\n\n const swapRequest: EvmTransactionRequest = {\n chainId: caip2ToEip155HexChainId(quote.sourceChain.chainId),\n data: swap.data,\n from: fromAddress,\n gas: swapGasWithMargin,\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: requiredSignatures,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await evmSigner.sign(\n swapRequest,\n async (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return makePendingTransfer(txHash, startedAtMs);\n}\n\n// ---------------------------------------------------------------------------\n// SVM (Solana) transfer path\n// ---------------------------------------------------------------------------\n\ninterface SvmTransferParams {\n apiOptions: ApiOptions;\n appId: string;\n environment: Environment;\n solanaSigner?: SolanaSigner;\n quote: Parameters<TransferService['transferAsset']>[0]['quote'];\n onStepChange?: Parameters<TransferService['transferAsset']>[0]['onStepChange'];\n}\n\nasync function _executeSvmTransfer({\n apiOptions,\n appId,\n environment,\n solanaSigner,\n quote,\n onStepChange,\n}: SvmTransferParams): Promise<Transfer> {\n if (!solanaSigner) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'solanaSigner is required for Solana transfers but was not provided.',\n });\n }\n\n if (!isSolAddress(quote.fromAddress)) {\n throw new SdkError(ErrorReason.INVALID_PARAMS, ErrorCode.INVALID_PARAMS, {\n details: 'fromAddress is not a valid Solana address.',\n });\n }\n\n const minAmountOut = calculateMarkrMinimumAmountOut({\n amountOut: quote.amountOut,\n assetOut: quote.assetOut,\n slippageBps: quote.slippageBps,\n });\n\n const tokenInAddressString = assetToAddressString(quote.assetIn, quote.sourceChain.chainId);\n const tokenOutAddressString = assetToAddressString(quote.assetOut, quote.targetChain.chainId);\n\n const swap = await markrSwap(apiOptions, {\n amountIn: quote.amountIn.toString(),\n appId,\n minAmountOut: minAmountOut.toString(),\n tokenIn: tokenInAddressString,\n tokenOut: tokenOutAddressString,\n userPublicKey: quote.fromAddress,\n uuid: quote.id,\n });\n\n if (!isSolanaSwapResponse(swap)) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: 'Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.',\n });\n }\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Original swap transaction (base64):', swap.swapTransaction);\n\n const swapTransactionBase64 = await refreshSolanaSwapTransactionBlockhash(\n swap.swapTransaction,\n getSolanaRpcForChain({ chain: quote.sourceChain }),\n );\n\n // TODO: Cleanup\n console.debug('[Fusion SDK] Refreshed swap transaction with new blockhash (base64):', swapTransactionBase64);\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.TokensTransfer,\n quote,\n requiredSignatures: 1,\n };\n\n onStepChange?.(step);\n\n const startedAtMs = Date.now();\n\n const txHash = await solanaSigner.signAndSend(\n {\n account: quote.fromAddress,\n serializedTx: swapTransactionBase64,\n },\n step,\n );\n\n const isCrossChainSwap = quote.sourceChain.chainId.toLowerCase() !== quote.targetChain.chainId.toLowerCase();\n\n return {\n amountIn: quote.amountIn,\n amountOut: quote.amountOut,\n environment,\n fees: quote.fees,\n fromAddress: quote.fromAddress,\n id: quote.id,\n partnerFeeBps: quote.partnerFeeBps,\n sourceAsset: quote.assetIn,\n sourceChain: quote.sourceChain,\n status: 'source-pending',\n targetAsset: quote.assetOut,\n targetChain: quote.targetChain,\n toAddress: quote.toAddress,\n type: ServiceType.MARKR,\n source: {\n confirmationCount: 0,\n requiredConfirmationCount: isCrossChainSwap ? 2 : SOLANA_REQUIRED_CONFIRMATIONS,\n startedAtMs,\n txHash,\n },\n };\n}\n\n/**\n * Determines whether one-click swap eligibility criteria is met.\n *\n * Only same-chain EVM swaps are currently eligible. HyperEVM is excluded:\n * heavy routes may need a prior `evmUserModify` big-blocks signature that\n * cannot be folded into `signBatch`, and the batch path returns before gas\n * estimation / big-block enablement.\n */\nfunction isOneClickBatchEligible({\n approvalRequest,\n requiresApprovalSignature,\n signBatch,\n sourceChainId,\n targetChainId,\n}: {\n approvalRequest?: EvmTransactionRequest;\n requiresApprovalSignature: boolean;\n signBatch?: EvmSigner['signBatch'];\n sourceChainId: Caip2ChainId;\n targetChainId: Caip2ChainId;\n}): boolean {\n return (\n isEvmNamespace(sourceChainId) &&\n isEvmNamespace(targetChainId) &&\n sourceChainId === targetChainId &&\n sourceChainId !== HyperEvmChainIds.MAINNET &&\n requiresApprovalSignature &&\n approvalRequest !== undefined &&\n typeof signBatch === 'function'\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{HyperEvmChainIds as e,HyperliquidChainIds as t,ServiceType as n,TransferSignatureReason as r}from"../../../constants.js";import{ErrorCode as i,ErrorReason as a,SdkError as o}from"../../../errors.js";import{caip2ToEip155ChainId as s,caip2ToEip155HexChainId as c}from"../../../utils/caip.js";import{getEvmClientForChain as l,getSolanaRpcForChain as u,makeFailedTransferFromQuote as d,maybe1559 as f}from"../../_utils.js";import{ApprovalRevertedError as p,buildErc20ApprovalRequest as m,signApprovalAndAssertConfirmed as h}from"../../_evm-approval.js";import{isEvmNamespace as g,isSolanaNamespace as _}from"../../../_utils/chain.js";import{markrGetSpenderAddress as v,markrSwap as y}from"../_api.js";import{isSolAddress as b}from"../../../utils/sol-address.js";import{assetToAddressString as x,calculateMarkrMinimumAmountOut as S,getAdditiveSourceAssetFeeAmount as C,isTokenAddressNative as w}from"../_utils.js";import{isEvmSwapResponse as T,isHyperliquidWithdrawSwapResponse as E,isSolanaSwapResponse as D}from"../_type-guards.js";import{refreshSolanaSwapTransactionBlockhash as O}from"../../../utils/solana.js";import{_getGasLimit as k,maybeEnableHyperEvmBigBlocks as A}from"../_hyperevm.js";import{_estimateGasFromSwapResponse as j}from"./estimate-native-fee.js";import{_executeHyperliquidWithdraw as M}from"./transfer-asset-hyperliquid-withdraw.js";import{isAddress as N}from"viem";function P({apiOptions:e,appId:r,environment:s,evmSigner:c,solanaSigner:l}){return async({quote:u,gasSettings:d,fallbackToDefaultOnBatchFailure:f,onStepChange:p})=>{if(u.serviceType!==n.MARKR)throw new o(a.INCORRECT_PROVIDER_PROVIDED,i.INVALID_PARAMS);let m=Math.floor(Date.now()/1e3);if(u.expiresAt<=m)throw new o(a.QUOTE_EXPIRED,i.INVALID_PARAMS);let h=u.sourceChain.chainId;if(h===t.MAINNET)return F({apiOptions:e,appId:r,environment:s,evmSigner:c,quote:u,onStepChange:p});if(_(h))return L({apiOptions:e,appId:r,environment:s,solanaSigner:l,quote:u,onStepChange:p});if(g(h))return I({apiOptions:e,appId:r,environment:s,evmSigner:c,quote:u,gasSettings:d,fallbackToDefaultOnBatchFailure:f,onStepChange:p});throw new o(a.CHAIN_NOT_SUPPORTED,i.INVALID_PARAMS,{details:`Unsupported source chain namespace: ${h}`})}}async function F({apiOptions:e,appId:t,environment:n,evmSigner:r,quote:s,onStepChange:c}){let l=S({amountOut:s.amountOut,assetOut:s.assetOut,slippageBps:s.slippageBps}),u=x(s.assetIn,s.sourceChain.chainId),d=x(s.assetOut,s.targetChain.chainId),f=await y(e,{amountIn:s.amountIn.toString(),appId:t,minAmountOut:l.toString(),tokenIn:u,tokenOut:d,uuid:s.id});if(!E(f))throw new o(a.CHAIN_NOT_SUPPORTED,i.INVALID_PARAMS,{details:"Expected `hyperliquid-withdraw` swap response from Markr for Hyperliquid source chain, but received a different variant."});return M({apiOptions:e,environment:n,evmSigner:r,quote:s,swap:f,onStepChange:c})}async function I({apiOptions:e,appId:t,environment:u,evmSigner:g,quote:_,gasSettings:b,fallbackToDefaultOnBatchFailure:E,onStepChange:D}){let O=_.fromAddress;if(!N(O))throw new o(a.INVALID_PARAMS,i.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let M=S({amountOut:_.amountOut,assetOut:_.assetOut,slippageBps:_.slippageBps}),P=l({chain:_.sourceChain}),F=x(_.assetIn,_.sourceChain.chainId),I=x(_.assetOut,_.targetChain.chainId);if(!N(F))throw new o(a.INVALID_PARAMS,i.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address.`});let L=F,z=w(L),B=_.sourceChain.chainId.toLowerCase()!==_.targetChain.chainId.toLowerCase(),V=_.amountIn+C(_),{address:H}=await v(e,{chainId:s(_.sourceChain.chainId),crossChainSwap:B,quoteId:_.id});if(!z&&!H)throw new o(a.CHAIN_NOT_SUPPORTED,i.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${_.sourceChain.chainId}.`});let U=!z&&H?await m({chainIdHex:c(_.sourceChain.chainId),client:P,gasSettings:b,owner:O,requiredAllowance:V,spender:H,token:L}):void 0,W=U!==void 0,G=R({approvalRequest:U,requiresApprovalSignature:W,signBatch:g.signBatch,sourceChainId:_.sourceChain.chainId,targetChainId:_.targetChain.chainId}),K=await y(e,{amountIn:_.amountIn.toString(),appId:t,minAmountOut:M.toString(),tokenIn:F,tokenOut:I,uuid:_.id});if(!T(K))throw new o(a.CHAIN_NOT_SUPPORTED,i.INVALID_PARAMS,{details:`Received non-EVM swap response from Markr, but only EVM swaps are supported for this source chain.`});let q=(e,t=Date.now())=>{let r=_.sourceChain.chainId===_.targetChain.chainId;return{amountIn:_.amountIn,amountOut:_.amountOut,environment:u,fees:_.fees,fromAddress:_.fromAddress,id:_.id,partnerFeeBps:_.partnerFeeBps,sourceAsset:_.assetIn,sourceChain:_.sourceChain,status:`source-pending`,targetAsset:_.assetOut,targetChain:_.targetChain,toAddress:_.toAddress,type:n.MARKR,source:{confirmationCount:0,requiredConfirmationCount:r?1:2,startedAtMs:t,txHash:e}}};if(G&&U){let e={currentSignature:1,currentSignatureReason:r.TokensTransfer,quote:_,requiredSignatures:1},t=g.signBatch;if(!t)throw new o(`One-click batch signer is not available.`,i.SIGNING_FAILED);let n={chainId:c(_.sourceChain.chainId),data:K.data,from:O,gas:void 0,to:K.to,value:K.value,...f(b)};D?.(e);try{let r=(await t([U,n],async e=>P.sendRawTransaction({serializedTransaction:e}),e)).at(-1);if(!r)throw new o(`One-click batch signing returned no transaction hashes.`,i.SIGNING_FAILED);return q(r)}catch(e){if(!E)throw e}}if(W&&U)try{await h({client:P,evmSigner:g,onStepChange:D,request:U,step:{currentSignature:1,currentSignatureReason:r.AllowanceApproval,quote:_,requiredSignatures:2}})}catch(e){if(e instanceof p)return d(_,{environment:u,errorCode:i.TRANSACTION_REVERTED,errorReason:`ERC20 approval transaction was reverted`});throw e}let J=await j({crossChain:B,fromAddress:O,feeUnitsMarginBps:b?.estimateGasMarginBps,gasLimit:k(_),sourceClient:P,swap:K}),Y=await A({environment:u,evmSigner:g,fromAddress:O,onStepChange:D,quote:_,requiresApprovalSignature:W,swapGasWithMargin:J});if(!Y.ok)return Y.transfer;let{requiredSignatures:X}=Y,Z={chainId:c(_.sourceChain.chainId),data:K.data,from:O,gas:J,to:K.to,value:K.value,...f(b)},Q={currentSignature:X,currentSignatureReason:r.TokensTransfer,quote:_,requiredSignatures:X};D?.(Q);let $=Date.now();return q(await g.sign(Z,async e=>P.sendRawTransaction({serializedTransaction:e}),Q),$)}async function L({apiOptions:e,appId:t,environment:s,solanaSigner:c,quote:l,onStepChange:d}){if(!c)throw new o(a.INVALID_PARAMS,i.INVALID_PARAMS,{details:`solanaSigner is required for Solana transfers but was not provided.`});if(!b(l.fromAddress))throw new o(a.INVALID_PARAMS,i.INVALID_PARAMS,{details:`fromAddress is not a valid Solana address.`});let f=S({amountOut:l.amountOut,assetOut:l.assetOut,slippageBps:l.slippageBps}),p=x(l.assetIn,l.sourceChain.chainId),m=x(l.assetOut,l.targetChain.chainId),h=await y(e,{amountIn:l.amountIn.toString(),appId:t,minAmountOut:f.toString(),tokenIn:p,tokenOut:m,userPublicKey:l.fromAddress,uuid:l.id});if(!D(h))throw new o(a.CHAIN_NOT_SUPPORTED,i.INVALID_PARAMS,{details:`Received non-SVM swap response from Markr, but only SVM swaps are supported for this source chain.`});console.debug(`[Fusion SDK] Original swap transaction (base64):`,h.swapTransaction);let g=await O(h.swapTransaction,u({chain:l.sourceChain}));console.debug(`[Fusion SDK] Refreshed swap transaction with new blockhash (base64):`,g);let _={currentSignature:1,currentSignatureReason:r.TokensTransfer,quote:l,requiredSignatures:1};d?.(_);let v=Date.now(),C=await c.signAndSend({account:l.fromAddress,serializedTx:g},_),w=l.sourceChain.chainId.toLowerCase()!==l.targetChain.chainId.toLowerCase();return{amountIn:l.amountIn,amountOut:l.amountOut,environment:s,fees:l.fees,fromAddress:l.fromAddress,id:l.id,partnerFeeBps:l.partnerFeeBps,sourceAsset:l.assetIn,sourceChain:l.sourceChain,status:`source-pending`,targetAsset:l.assetOut,targetChain:l.targetChain,toAddress:l.toAddress,type:n.MARKR,source:{confirmationCount:0,requiredConfirmationCount:w?2:32,startedAtMs:v,txHash:C}}}function R({approvalRequest:t,requiresApprovalSignature:n,signBatch:r,sourceChainId:i,targetChainId:a}){return g(i)&&g(a)&&i===a&&i!==e.MAINNET&&n&&t!==void 0&&typeof r==`function`}export{P as transferAssetFactory};
|
|
2
2
|
//# sourceMappingURL=transfer-asset.js.map
|