@avalabs/fusion-sdk 0.20.0 → 0.21.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.
@@ -1 +1 @@
1
- {"version":3,"file":"_api.cjs","names":["fetchJson","combineUrlPathnames","SupportedChainsResponseSchema","ResponseValidationError","TokenListResponseSchema","fetchEventStream","QuoteResponseSchema","SwapResponseSchema","PartnerInfoResponseSchema","AbortedError","CrossChainStatusResponseSchema","SpenderAddressResponseSchema","MarkrAuthorizeResponseSchema"],"sources":["../../../src/transfer-service/markr/_api.ts"],"sourcesContent":["import type { Address as SolanaAddress } from '@solana/kit';\nimport type { Address as EvmAddress } from 'viem';\nimport { AbortedError, ResponseValidationError } from '../../errors';\nimport { combineUrlPathnames, fetchEventStream, fetchJson } from '../fetch-utilities';\nimport {\n CrossChainStatusResponseSchema,\n MarkrAuthorizeResponseSchema,\n PartnerInfoResponseSchema,\n QuoteResponseSchema,\n SpenderAddressResponseSchema,\n SupportedChainsResponseSchema,\n SwapResponseSchema,\n TokenListResponseSchema,\n type CrossChainStatusResponse,\n type PartnerInfoResponse,\n type QuoteResponseData,\n type SpenderAddressResponse,\n type SupportedChainsResponse,\n type SwapResponse,\n type TokenListResponse,\n} from './_schema';\nimport type { Caip2ChainId } from '../../types/caip';\nimport type { Fetch } from '../../types/utility-types';\n\nexport interface ApiOptions {\n apiBaseUrl: URL;\n apiToken?: string;\n fetch?: Fetch;\n}\n\nfunction getAuthHeaders(apiToken?: string): Record<string, string> | undefined {\n if (!apiToken) {\n return undefined;\n }\n\n return { Authorization: `Bearer ${apiToken}` };\n}\n\nexport async function markrGetInfoChains({\n apiBaseUrl,\n apiToken,\n fetch: customFetch,\n}: ApiOptions): Promise<SupportedChainsResponse> {\n const endpoint = '/info/chains';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = SupportedChainsResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetTokenList(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n chainId: number,\n): Promise<TokenListResponse> {\n const endpoint = `/tokens/${chainId}/list`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = TokenListResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport interface MarkrStreamQuoteParams {\n amount: string;\n appId: string;\n chainId: number | Caip2ChainId;\n destinationChainId?: number | Caip2ChainId;\n slippage?: number;\n tokenIn: string;\n tokenInDecimals: number;\n tokenOut: string;\n tokenOutDecimals: number;\n /**\n * Required ONLY for cross-chain swaps involving EVM.\n *\n * EVM -> EVM (different chains)\n * EVM -> Solana\n * Solana -> EVM\n */\n userEvmAddress?: EvmAddress;\n /**\n * Required ONLY for cross-chain swaps involving Solana.\n *\n * Solana -> EVM\n * EVM -> Solana\n * Solana -> Solana\n */\n userSolanaAddress?: SolanaAddress;\n}\n\nexport interface MarkrStreamQuoteOptions {\n onDone: () => void;\n onError: (error: Error) => void;\n onQuote: (data: QuoteResponseData) => void;\n signal?: AbortSignal;\n}\n\nexport async function markrStreamQuote(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrStreamQuoteParams,\n { onDone, onError, onQuote, signal }: MarkrStreamQuoteOptions,\n): Promise<ReadonlyArray<QuoteResponseData>> {\n const endpoint = '/quote';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const quotes: QuoteResponseData[] = [];\n\n try {\n for await (const event of fetchEventStream(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n signal,\n })) {\n const parsedData = QuoteResponseSchema.safeParse(JSON.parse(event.data));\n\n if (!parsedData.success) {\n onError(\n new ResponseValidationError(\n `Invalid quote data received from Markr \"${endpoint}\" endpoint.`,\n parsedData.error.issues,\n ),\n );\n continue;\n }\n\n if (!('done' in parsedData.data)) {\n onQuote(parsedData.data);\n quotes.push(parsedData.data);\n } else {\n onDone();\n }\n }\n } catch (error) {\n if (error instanceof Error) {\n onError(error);\n } else {\n onError(new Error('An unknown error occurred during the quote stream.', { cause: error }));\n }\n\n onDone();\n }\n\n return quotes;\n}\n\nexport interface MarkrGetSwapParams {\n appId: string;\n /** Input amount in token's smallest unit */\n amountIn: string;\n /** Return raw transaction data alongside wrapped data */\n debug?: boolean;\n /** Minimum expected output amount */\n minAmountOut: string;\n /** Input token contract address */\n tokenIn: string;\n /** Output token contract address */\n tokenOut: string;\n /** Solana wallet public key (required for Solana swaps) */\n userPublicKey?: string;\n /** Quote UUID from previous quote request */\n uuid: string;\n}\n\nexport async function markrSwap(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrGetSwapParams,\n): Promise<SwapResponse> {\n const endpoint = '/swap';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n });\n\n const parsed = SwapResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetPartnerInfo({\n apiBaseUrl,\n apiToken,\n fetch: customFetch,\n}: ApiOptions): Promise<PartnerInfoResponse> {\n const endpoint = '/info/partner';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = PartnerInfoResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetCrossChainStatus(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n sourceTxHash: string,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<CrossChainStatusResponse> {\n const endpoint = `/cross-chain/status/${sourceTxHash}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n headers: getAuthHeaders(apiToken),\n fetch: customFetch,\n retries: 10,\n retryOn(ctx) {\n const method = (ctx.init.method ?? 'GET').toUpperCase();\n\n if (!['GET', 'HEAD', 'OPTIONS', 'TRACE'].includes(method)) {\n return false;\n }\n\n if (ctx.error) {\n if (ctx.error instanceof AbortedError) {\n return false;\n }\n\n return true;\n }\n\n const status = ctx.response?.status ?? 0;\n\n // Retry on 404 requests since the endpoint may not return a result immediately after the source transaction is executed.\n if (status === 404 || status === 408 || status === 425 || status === 429 || (status >= 500 && status <= 599)) {\n return true;\n }\n\n return false;\n },\n signal,\n });\n\n const parsed = CrossChainStatusResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Returns the spender address (wrapped contract) that needs to be approved\n * for token swaps on the specified chain.\n *\n * Not applicable for Solana.\n */\nexport async function markrGetSpenderAddress(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n {\n chainId,\n crossChainSwap,\n quoteId,\n }: {\n chainId: number;\n crossChainSwap?: boolean;\n quoteId: string;\n },\n): Promise<SpenderAddressResponse> {\n const endpoint = `/spender-address?chainId=${chainId}&cross=${crossChainSwap ? 'true' : 'false'}&uuid=${quoteId}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = SpenderAddressResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\n// ---------------------------------------------------------------------------\n// Hyperliquid 2-phase withdrawal: nonce-mapping authorize\n// ---------------------------------------------------------------------------\n\n/**\n * Legacy (`protocolVersion: 1`) authorize body — Markr rebuilds the upstream\n * Relay request from a fixed schema. Kept for back-compat; new integrations\n * should use {@link MarkrPostAuthorizeParamsV2}.\n *\n * **Caveat:** when Relay adds a required field (as it did with `depositor` in\n * v2), the rebuilt body silently omits it and the order is orphaned upstream.\n */\nexport interface MarkrPostAuthorizeParamsV1 {\n /** Quote uuid — lets Markr correlate the authorize call with the cached Relay step. */\n readonly uuid: string;\n /** User's EIP-712 signature over the `RelayNonceMapping` typed data (`0x{r}{s}{v}`, 65 bytes hex). */\n readonly signature: `0x${string}`;\n /** EVM address of the signer. */\n readonly wallet: EvmAddress;\n /** Always `1337` (Hyperliquid). */\n readonly walletChainId: 1337;\n /** EIP-712 domain.chainId used in the signature — the wallet's active chain. */\n readonly signatureChainId: number;\n /**\n * Shared nonce — JSON number, matching Relay's upstream `/authorize` contract\n * and HL `/exchange`. HL nonces are millisecond timestamps, well under\n * `Number.MAX_SAFE_INTEGER`. Sending it as a string makes Relay reject the\n * payload (strict type validation), so we coerce here at the wire boundary.\n */\n readonly nonce: number;\n /** Relay request id (`0x{64hex}`). */\n readonly id: `0x${string}`;\n}\n\n/**\n * Pass-through (`protocolVersion: 2`) authorize body. The SDK forwards Relay's\n * `authorize.body` envelope from the `/swap` response **verbatim**. Markr only\n * normalizes `nonce` to a JSON number and defaults `referrer`; every other\n * field is untouched, so additive Relay schema changes don't break SDKs.\n */\nexport interface MarkrPostAuthorizeParamsV2 {\n /** Quote uuid — lets Markr correlate the authorize call with the cached Relay step. */\n readonly uuid: string;\n /** User's EIP-712 signature over `swap.sign.value` using `swap.sign.domain` / `swap.sign.types`. */\n readonly signature: `0x${string}`;\n /** Relay's `/authorize` POST body, taken from `swap.authorize.body`. Forwarded verbatim. */\n readonly body: Record<string, unknown>;\n}\n\nexport type MarkrPostAuthorizeParams = MarkrPostAuthorizeParamsV1 | MarkrPostAuthorizeParamsV2;\n\n/**\n * Submit the user's signed nonce-mapping to Markr's `/authorize` endpoint.\n *\n * Markr proxies the request to Relay's upstream `/authorize`. Returns on any\n * 2xx; throws `HttpError` otherwise.\n */\nexport async function markrPostAuthorize(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrPostAuthorizeParams,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<void> {\n const endpoint = '/authorize';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n // `fetchJson` throws `HttpError` on non-2xx; the schema additionally rejects\n // upstream error envelopes that come back with a 200 (Relay sometimes does\n // this when authorize is rejected after HTTP success).\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n signal,\n });\n\n const parsed = MarkrAuthorizeResponseSchema.safeParse(rawJson);\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_api.cjs","names":["fetchJson","combineUrlPathnames","SupportedChainsResponseSchema","ResponseValidationError","TokenListResponseSchema","fetchEventStream","QuoteResponseSchema","SwapResponseSchema","PartnerInfoResponseSchema","AbortedError","CrossChainStatusResponseSchema","SpenderAddressResponseSchema","MarkrAuthorizeResponseSchema"],"sources":["../../../src/transfer-service/markr/_api.ts"],"sourcesContent":["import type { Address as SolanaAddress } from '@solana/kit';\nimport type { Address as EvmAddress } from 'viem';\nimport { AbortedError, ResponseValidationError } from '../../errors';\nimport { combineUrlPathnames, fetchEventStream, fetchJson } from '../fetch-utilities';\nimport {\n CrossChainStatusResponseSchema,\n MarkrAuthorizeResponseSchema,\n PartnerInfoResponseSchema,\n QuoteResponseSchema,\n SpenderAddressResponseSchema,\n SupportedChainsResponseSchema,\n SwapResponseSchema,\n TokenListResponseSchema,\n type CrossChainStatusResponse,\n type PartnerInfoResponse,\n type QuoteResponseData,\n type SpenderAddressResponse,\n type SupportedChainsResponse,\n type SwapResponse,\n type TokenListResponse,\n} from './_schema';\nimport type { Caip2ChainId } from '../../types/caip';\nimport type { Fetch } from '../../types/utility-types';\n\nexport interface ApiOptions {\n apiBaseUrl: URL;\n apiToken?: string;\n fetch?: Fetch;\n}\n\nfunction getAuthHeaders(apiToken?: string): Record<string, string> | undefined {\n if (!apiToken) {\n return undefined;\n }\n\n return { Authorization: `Bearer ${apiToken}` };\n}\n\nexport async function markrGetInfoChains({\n apiBaseUrl,\n apiToken,\n fetch: customFetch,\n}: ApiOptions): Promise<SupportedChainsResponse> {\n const endpoint = '/info/chains';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = SupportedChainsResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetTokenList(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n chainId: number,\n): Promise<TokenListResponse> {\n const endpoint = `/tokens/${chainId}/list`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = TokenListResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport interface MarkrStreamQuoteParams {\n amount: string;\n /**\n * Pin the quote to a single upstream aggregator (e.g. `\"relay\"`). When\n * omitted, Markr races every eligible aggregator. Used to obtain\n * native-fee-free routes that only a specific aggregator supports.\n */\n aggregator?: string;\n appId: string;\n chainId: number | Caip2ChainId;\n destinationChainId?: number | Caip2ChainId;\n slippage?: number;\n tokenIn: string;\n tokenInDecimals: number;\n tokenOut: string;\n tokenOutDecimals: number;\n /**\n * Required ONLY for cross-chain swaps involving EVM.\n *\n * EVM -> EVM (different chains)\n * EVM -> Solana\n * Solana -> EVM\n */\n userEvmAddress?: EvmAddress;\n /**\n * Required ONLY for cross-chain swaps involving Solana.\n *\n * Solana -> EVM\n * EVM -> Solana\n * Solana -> Solana\n */\n userSolanaAddress?: SolanaAddress;\n}\n\nexport interface MarkrStreamQuoteOptions {\n onDone: () => void;\n onError: (error: Error) => void;\n onQuote: (data: QuoteResponseData) => void;\n signal?: AbortSignal;\n}\n\nexport async function markrStreamQuote(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrStreamQuoteParams,\n { onDone, onError, onQuote, signal }: MarkrStreamQuoteOptions,\n): Promise<ReadonlyArray<QuoteResponseData>> {\n const endpoint = '/quote';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const quotes: QuoteResponseData[] = [];\n\n try {\n for await (const event of fetchEventStream(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n signal,\n })) {\n const parsedData = QuoteResponseSchema.safeParse(JSON.parse(event.data));\n\n if (!parsedData.success) {\n onError(\n new ResponseValidationError(\n `Invalid quote data received from Markr \"${endpoint}\" endpoint.`,\n parsedData.error.issues,\n ),\n );\n continue;\n }\n\n if (!('done' in parsedData.data)) {\n onQuote(parsedData.data);\n quotes.push(parsedData.data);\n } else {\n onDone();\n }\n }\n } catch (error) {\n if (error instanceof Error) {\n onError(error);\n } else {\n onError(new Error('An unknown error occurred during the quote stream.', { cause: error }));\n }\n\n onDone();\n }\n\n return quotes;\n}\n\nexport interface MarkrGetSwapParams {\n appId: string;\n /** Input amount in token's smallest unit */\n amountIn: string;\n /** Return raw transaction data alongside wrapped data */\n debug?: boolean;\n /** Minimum expected output amount */\n minAmountOut: string;\n /** Input token contract address */\n tokenIn: string;\n /** Output token contract address */\n tokenOut: string;\n /** Solana wallet public key (required for Solana swaps) */\n userPublicKey?: string;\n /** Quote UUID from previous quote request */\n uuid: string;\n}\n\nexport async function markrSwap(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrGetSwapParams,\n): Promise<SwapResponse> {\n const endpoint = '/swap';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n });\n\n const parsed = SwapResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetPartnerInfo({\n apiBaseUrl,\n apiToken,\n fetch: customFetch,\n}: ApiOptions): Promise<PartnerInfoResponse> {\n const endpoint = '/info/partner';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = PartnerInfoResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetCrossChainStatus(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n sourceTxHash: string,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<CrossChainStatusResponse> {\n const endpoint = `/cross-chain/status/${sourceTxHash}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n headers: getAuthHeaders(apiToken),\n fetch: customFetch,\n retries: 10,\n retryOn(ctx) {\n const method = (ctx.init.method ?? 'GET').toUpperCase();\n\n if (!['GET', 'HEAD', 'OPTIONS', 'TRACE'].includes(method)) {\n return false;\n }\n\n if (ctx.error) {\n if (ctx.error instanceof AbortedError) {\n return false;\n }\n\n return true;\n }\n\n const status = ctx.response?.status ?? 0;\n\n // Retry on 404 requests since the endpoint may not return a result immediately after the source transaction is executed.\n if (status === 404 || status === 408 || status === 425 || status === 429 || (status >= 500 && status <= 599)) {\n return true;\n }\n\n return false;\n },\n signal,\n });\n\n const parsed = CrossChainStatusResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Returns the spender address (wrapped contract) that needs to be approved\n * for token swaps on the specified chain.\n *\n * Not applicable for Solana.\n */\nexport async function markrGetSpenderAddress(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n {\n chainId,\n crossChainSwap,\n quoteId,\n }: {\n chainId: number;\n crossChainSwap?: boolean;\n quoteId: string;\n },\n): Promise<SpenderAddressResponse> {\n const endpoint = `/spender-address?chainId=${chainId}&cross=${crossChainSwap ? 'true' : 'false'}&uuid=${quoteId}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = SpenderAddressResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\n// ---------------------------------------------------------------------------\n// Hyperliquid 2-phase withdrawal: nonce-mapping authorize\n// ---------------------------------------------------------------------------\n\n/**\n * Legacy (`protocolVersion: 1`) authorize body — Markr rebuilds the upstream\n * Relay request from a fixed schema. Kept for back-compat; new integrations\n * should use {@link MarkrPostAuthorizeParamsV2}.\n *\n * **Caveat:** when Relay adds a required field (as it did with `depositor` in\n * v2), the rebuilt body silently omits it and the order is orphaned upstream.\n */\nexport interface MarkrPostAuthorizeParamsV1 {\n /** Quote uuid — lets Markr correlate the authorize call with the cached Relay step. */\n readonly uuid: string;\n /** User's EIP-712 signature over the `RelayNonceMapping` typed data (`0x{r}{s}{v}`, 65 bytes hex). */\n readonly signature: `0x${string}`;\n /** EVM address of the signer. */\n readonly wallet: EvmAddress;\n /** Always `1337` (Hyperliquid). */\n readonly walletChainId: 1337;\n /** EIP-712 domain.chainId used in the signature — the wallet's active chain. */\n readonly signatureChainId: number;\n /**\n * Shared nonce — JSON number, matching Relay's upstream `/authorize` contract\n * and HL `/exchange`. HL nonces are millisecond timestamps, well under\n * `Number.MAX_SAFE_INTEGER`. Sending it as a string makes Relay reject the\n * payload (strict type validation), so we coerce here at the wire boundary.\n */\n readonly nonce: number;\n /** Relay request id (`0x{64hex}`). */\n readonly id: `0x${string}`;\n}\n\n/**\n * Pass-through (`protocolVersion: 2`) authorize body. The SDK forwards Relay's\n * `authorize.body` envelope from the `/swap` response **verbatim**. Markr only\n * normalizes `nonce` to a JSON number and defaults `referrer`; every other\n * field is untouched, so additive Relay schema changes don't break SDKs.\n */\nexport interface MarkrPostAuthorizeParamsV2 {\n /** Quote uuid — lets Markr correlate the authorize call with the cached Relay step. */\n readonly uuid: string;\n /** User's EIP-712 signature over `swap.sign.value` using `swap.sign.domain` / `swap.sign.types`. */\n readonly signature: `0x${string}`;\n /** Relay's `/authorize` POST body, taken from `swap.authorize.body`. Forwarded verbatim. */\n readonly body: Record<string, unknown>;\n}\n\nexport type MarkrPostAuthorizeParams = MarkrPostAuthorizeParamsV1 | MarkrPostAuthorizeParamsV2;\n\n/**\n * Submit the user's signed nonce-mapping to Markr's `/authorize` endpoint.\n *\n * Markr proxies the request to Relay's upstream `/authorize`. Returns on any\n * 2xx; throws `HttpError` otherwise.\n */\nexport async function markrPostAuthorize(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrPostAuthorizeParams,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<void> {\n const endpoint = '/authorize';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n // `fetchJson` throws `HttpError` on non-2xx; the schema additionally rejects\n // upstream error envelopes that come back with a 200 (Relay sometimes does\n // this when authorize is rejected after HTTP success).\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n signal,\n });\n\n const parsed = MarkrAuthorizeResponseSchema.safeParse(rawJson);\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"_api.js","names":[],"sources":["../../../src/transfer-service/markr/_api.ts"],"sourcesContent":["import type { Address as SolanaAddress } from '@solana/kit';\nimport type { Address as EvmAddress } from 'viem';\nimport { AbortedError, ResponseValidationError } from '../../errors';\nimport { combineUrlPathnames, fetchEventStream, fetchJson } from '../fetch-utilities';\nimport {\n CrossChainStatusResponseSchema,\n MarkrAuthorizeResponseSchema,\n PartnerInfoResponseSchema,\n QuoteResponseSchema,\n SpenderAddressResponseSchema,\n SupportedChainsResponseSchema,\n SwapResponseSchema,\n TokenListResponseSchema,\n type CrossChainStatusResponse,\n type PartnerInfoResponse,\n type QuoteResponseData,\n type SpenderAddressResponse,\n type SupportedChainsResponse,\n type SwapResponse,\n type TokenListResponse,\n} from './_schema';\nimport type { Caip2ChainId } from '../../types/caip';\nimport type { Fetch } from '../../types/utility-types';\n\nexport interface ApiOptions {\n apiBaseUrl: URL;\n apiToken?: string;\n fetch?: Fetch;\n}\n\nfunction getAuthHeaders(apiToken?: string): Record<string, string> | undefined {\n if (!apiToken) {\n return undefined;\n }\n\n return { Authorization: `Bearer ${apiToken}` };\n}\n\nexport async function markrGetInfoChains({\n apiBaseUrl,\n apiToken,\n fetch: customFetch,\n}: ApiOptions): Promise<SupportedChainsResponse> {\n const endpoint = '/info/chains';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = SupportedChainsResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetTokenList(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n chainId: number,\n): Promise<TokenListResponse> {\n const endpoint = `/tokens/${chainId}/list`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = TokenListResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport interface MarkrStreamQuoteParams {\n amount: string;\n appId: string;\n chainId: number | Caip2ChainId;\n destinationChainId?: number | Caip2ChainId;\n slippage?: number;\n tokenIn: string;\n tokenInDecimals: number;\n tokenOut: string;\n tokenOutDecimals: number;\n /**\n * Required ONLY for cross-chain swaps involving EVM.\n *\n * EVM -> EVM (different chains)\n * EVM -> Solana\n * Solana -> EVM\n */\n userEvmAddress?: EvmAddress;\n /**\n * Required ONLY for cross-chain swaps involving Solana.\n *\n * Solana -> EVM\n * EVM -> Solana\n * Solana -> Solana\n */\n userSolanaAddress?: SolanaAddress;\n}\n\nexport interface MarkrStreamQuoteOptions {\n onDone: () => void;\n onError: (error: Error) => void;\n onQuote: (data: QuoteResponseData) => void;\n signal?: AbortSignal;\n}\n\nexport async function markrStreamQuote(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrStreamQuoteParams,\n { onDone, onError, onQuote, signal }: MarkrStreamQuoteOptions,\n): Promise<ReadonlyArray<QuoteResponseData>> {\n const endpoint = '/quote';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const quotes: QuoteResponseData[] = [];\n\n try {\n for await (const event of fetchEventStream(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n signal,\n })) {\n const parsedData = QuoteResponseSchema.safeParse(JSON.parse(event.data));\n\n if (!parsedData.success) {\n onError(\n new ResponseValidationError(\n `Invalid quote data received from Markr \"${endpoint}\" endpoint.`,\n parsedData.error.issues,\n ),\n );\n continue;\n }\n\n if (!('done' in parsedData.data)) {\n onQuote(parsedData.data);\n quotes.push(parsedData.data);\n } else {\n onDone();\n }\n }\n } catch (error) {\n if (error instanceof Error) {\n onError(error);\n } else {\n onError(new Error('An unknown error occurred during the quote stream.', { cause: error }));\n }\n\n onDone();\n }\n\n return quotes;\n}\n\nexport interface MarkrGetSwapParams {\n appId: string;\n /** Input amount in token's smallest unit */\n amountIn: string;\n /** Return raw transaction data alongside wrapped data */\n debug?: boolean;\n /** Minimum expected output amount */\n minAmountOut: string;\n /** Input token contract address */\n tokenIn: string;\n /** Output token contract address */\n tokenOut: string;\n /** Solana wallet public key (required for Solana swaps) */\n userPublicKey?: string;\n /** Quote UUID from previous quote request */\n uuid: string;\n}\n\nexport async function markrSwap(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrGetSwapParams,\n): Promise<SwapResponse> {\n const endpoint = '/swap';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n });\n\n const parsed = SwapResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetPartnerInfo({\n apiBaseUrl,\n apiToken,\n fetch: customFetch,\n}: ApiOptions): Promise<PartnerInfoResponse> {\n const endpoint = '/info/partner';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = PartnerInfoResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetCrossChainStatus(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n sourceTxHash: string,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<CrossChainStatusResponse> {\n const endpoint = `/cross-chain/status/${sourceTxHash}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n headers: getAuthHeaders(apiToken),\n fetch: customFetch,\n retries: 10,\n retryOn(ctx) {\n const method = (ctx.init.method ?? 'GET').toUpperCase();\n\n if (!['GET', 'HEAD', 'OPTIONS', 'TRACE'].includes(method)) {\n return false;\n }\n\n if (ctx.error) {\n if (ctx.error instanceof AbortedError) {\n return false;\n }\n\n return true;\n }\n\n const status = ctx.response?.status ?? 0;\n\n // Retry on 404 requests since the endpoint may not return a result immediately after the source transaction is executed.\n if (status === 404 || status === 408 || status === 425 || status === 429 || (status >= 500 && status <= 599)) {\n return true;\n }\n\n return false;\n },\n signal,\n });\n\n const parsed = CrossChainStatusResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Returns the spender address (wrapped contract) that needs to be approved\n * for token swaps on the specified chain.\n *\n * Not applicable for Solana.\n */\nexport async function markrGetSpenderAddress(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n {\n chainId,\n crossChainSwap,\n quoteId,\n }: {\n chainId: number;\n crossChainSwap?: boolean;\n quoteId: string;\n },\n): Promise<SpenderAddressResponse> {\n const endpoint = `/spender-address?chainId=${chainId}&cross=${crossChainSwap ? 'true' : 'false'}&uuid=${quoteId}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = SpenderAddressResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\n// ---------------------------------------------------------------------------\n// Hyperliquid 2-phase withdrawal: nonce-mapping authorize\n// ---------------------------------------------------------------------------\n\n/**\n * Legacy (`protocolVersion: 1`) authorize body — Markr rebuilds the upstream\n * Relay request from a fixed schema. Kept for back-compat; new integrations\n * should use {@link MarkrPostAuthorizeParamsV2}.\n *\n * **Caveat:** when Relay adds a required field (as it did with `depositor` in\n * v2), the rebuilt body silently omits it and the order is orphaned upstream.\n */\nexport interface MarkrPostAuthorizeParamsV1 {\n /** Quote uuid — lets Markr correlate the authorize call with the cached Relay step. */\n readonly uuid: string;\n /** User's EIP-712 signature over the `RelayNonceMapping` typed data (`0x{r}{s}{v}`, 65 bytes hex). */\n readonly signature: `0x${string}`;\n /** EVM address of the signer. */\n readonly wallet: EvmAddress;\n /** Always `1337` (Hyperliquid). */\n readonly walletChainId: 1337;\n /** EIP-712 domain.chainId used in the signature — the wallet's active chain. */\n readonly signatureChainId: number;\n /**\n * Shared nonce — JSON number, matching Relay's upstream `/authorize` contract\n * and HL `/exchange`. HL nonces are millisecond timestamps, well under\n * `Number.MAX_SAFE_INTEGER`. Sending it as a string makes Relay reject the\n * payload (strict type validation), so we coerce here at the wire boundary.\n */\n readonly nonce: number;\n /** Relay request id (`0x{64hex}`). */\n readonly id: `0x${string}`;\n}\n\n/**\n * Pass-through (`protocolVersion: 2`) authorize body. The SDK forwards Relay's\n * `authorize.body` envelope from the `/swap` response **verbatim**. Markr only\n * normalizes `nonce` to a JSON number and defaults `referrer`; every other\n * field is untouched, so additive Relay schema changes don't break SDKs.\n */\nexport interface MarkrPostAuthorizeParamsV2 {\n /** Quote uuid — lets Markr correlate the authorize call with the cached Relay step. */\n readonly uuid: string;\n /** User's EIP-712 signature over `swap.sign.value` using `swap.sign.domain` / `swap.sign.types`. */\n readonly signature: `0x${string}`;\n /** Relay's `/authorize` POST body, taken from `swap.authorize.body`. Forwarded verbatim. */\n readonly body: Record<string, unknown>;\n}\n\nexport type MarkrPostAuthorizeParams = MarkrPostAuthorizeParamsV1 | MarkrPostAuthorizeParamsV2;\n\n/**\n * Submit the user's signed nonce-mapping to Markr's `/authorize` endpoint.\n *\n * Markr proxies the request to Relay's upstream `/authorize`. Returns on any\n * 2xx; throws `HttpError` otherwise.\n */\nexport async function markrPostAuthorize(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrPostAuthorizeParams,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<void> {\n const endpoint = '/authorize';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n // `fetchJson` throws `HttpError` on non-2xx; the schema additionally rejects\n // upstream error envelopes that come back with a 200 (Relay sometimes does\n // this when authorize is rejected after HTTP success).\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n signal,\n });\n\n const parsed = MarkrAuthorizeResponseSchema.safeParse(rawJson);\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_api.js","names":[],"sources":["../../../src/transfer-service/markr/_api.ts"],"sourcesContent":["import type { Address as SolanaAddress } from '@solana/kit';\nimport type { Address as EvmAddress } from 'viem';\nimport { AbortedError, ResponseValidationError } from '../../errors';\nimport { combineUrlPathnames, fetchEventStream, fetchJson } from '../fetch-utilities';\nimport {\n CrossChainStatusResponseSchema,\n MarkrAuthorizeResponseSchema,\n PartnerInfoResponseSchema,\n QuoteResponseSchema,\n SpenderAddressResponseSchema,\n SupportedChainsResponseSchema,\n SwapResponseSchema,\n TokenListResponseSchema,\n type CrossChainStatusResponse,\n type PartnerInfoResponse,\n type QuoteResponseData,\n type SpenderAddressResponse,\n type SupportedChainsResponse,\n type SwapResponse,\n type TokenListResponse,\n} from './_schema';\nimport type { Caip2ChainId } from '../../types/caip';\nimport type { Fetch } from '../../types/utility-types';\n\nexport interface ApiOptions {\n apiBaseUrl: URL;\n apiToken?: string;\n fetch?: Fetch;\n}\n\nfunction getAuthHeaders(apiToken?: string): Record<string, string> | undefined {\n if (!apiToken) {\n return undefined;\n }\n\n return { Authorization: `Bearer ${apiToken}` };\n}\n\nexport async function markrGetInfoChains({\n apiBaseUrl,\n apiToken,\n fetch: customFetch,\n}: ApiOptions): Promise<SupportedChainsResponse> {\n const endpoint = '/info/chains';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = SupportedChainsResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetTokenList(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n chainId: number,\n): Promise<TokenListResponse> {\n const endpoint = `/tokens/${chainId}/list`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = TokenListResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport interface MarkrStreamQuoteParams {\n amount: string;\n /**\n * Pin the quote to a single upstream aggregator (e.g. `\"relay\"`). When\n * omitted, Markr races every eligible aggregator. Used to obtain\n * native-fee-free routes that only a specific aggregator supports.\n */\n aggregator?: string;\n appId: string;\n chainId: number | Caip2ChainId;\n destinationChainId?: number | Caip2ChainId;\n slippage?: number;\n tokenIn: string;\n tokenInDecimals: number;\n tokenOut: string;\n tokenOutDecimals: number;\n /**\n * Required ONLY for cross-chain swaps involving EVM.\n *\n * EVM -> EVM (different chains)\n * EVM -> Solana\n * Solana -> EVM\n */\n userEvmAddress?: EvmAddress;\n /**\n * Required ONLY for cross-chain swaps involving Solana.\n *\n * Solana -> EVM\n * EVM -> Solana\n * Solana -> Solana\n */\n userSolanaAddress?: SolanaAddress;\n}\n\nexport interface MarkrStreamQuoteOptions {\n onDone: () => void;\n onError: (error: Error) => void;\n onQuote: (data: QuoteResponseData) => void;\n signal?: AbortSignal;\n}\n\nexport async function markrStreamQuote(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrStreamQuoteParams,\n { onDone, onError, onQuote, signal }: MarkrStreamQuoteOptions,\n): Promise<ReadonlyArray<QuoteResponseData>> {\n const endpoint = '/quote';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const quotes: QuoteResponseData[] = [];\n\n try {\n for await (const event of fetchEventStream(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n signal,\n })) {\n const parsedData = QuoteResponseSchema.safeParse(JSON.parse(event.data));\n\n if (!parsedData.success) {\n onError(\n new ResponseValidationError(\n `Invalid quote data received from Markr \"${endpoint}\" endpoint.`,\n parsedData.error.issues,\n ),\n );\n continue;\n }\n\n if (!('done' in parsedData.data)) {\n onQuote(parsedData.data);\n quotes.push(parsedData.data);\n } else {\n onDone();\n }\n }\n } catch (error) {\n if (error instanceof Error) {\n onError(error);\n } else {\n onError(new Error('An unknown error occurred during the quote stream.', { cause: error }));\n }\n\n onDone();\n }\n\n return quotes;\n}\n\nexport interface MarkrGetSwapParams {\n appId: string;\n /** Input amount in token's smallest unit */\n amountIn: string;\n /** Return raw transaction data alongside wrapped data */\n debug?: boolean;\n /** Minimum expected output amount */\n minAmountOut: string;\n /** Input token contract address */\n tokenIn: string;\n /** Output token contract address */\n tokenOut: string;\n /** Solana wallet public key (required for Solana swaps) */\n userPublicKey?: string;\n /** Quote UUID from previous quote request */\n uuid: string;\n}\n\nexport async function markrSwap(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrGetSwapParams,\n): Promise<SwapResponse> {\n const endpoint = '/swap';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n });\n\n const parsed = SwapResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetPartnerInfo({\n apiBaseUrl,\n apiToken,\n fetch: customFetch,\n}: ApiOptions): Promise<PartnerInfoResponse> {\n const endpoint = '/info/partner';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = PartnerInfoResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\nexport async function markrGetCrossChainStatus(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n sourceTxHash: string,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<CrossChainStatusResponse> {\n const endpoint = `/cross-chain/status/${sourceTxHash}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n headers: getAuthHeaders(apiToken),\n fetch: customFetch,\n retries: 10,\n retryOn(ctx) {\n const method = (ctx.init.method ?? 'GET').toUpperCase();\n\n if (!['GET', 'HEAD', 'OPTIONS', 'TRACE'].includes(method)) {\n return false;\n }\n\n if (ctx.error) {\n if (ctx.error instanceof AbortedError) {\n return false;\n }\n\n return true;\n }\n\n const status = ctx.response?.status ?? 0;\n\n // Retry on 404 requests since the endpoint may not return a result immediately after the source transaction is executed.\n if (status === 404 || status === 408 || status === 425 || status === 429 || (status >= 500 && status <= 599)) {\n return true;\n }\n\n return false;\n },\n signal,\n });\n\n const parsed = CrossChainStatusResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Returns the spender address (wrapped contract) that needs to be approved\n * for token swaps on the specified chain.\n *\n * Not applicable for Solana.\n */\nexport async function markrGetSpenderAddress(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n {\n chainId,\n crossChainSwap,\n quoteId,\n }: {\n chainId: number;\n crossChainSwap?: boolean;\n quoteId: string;\n },\n): Promise<SpenderAddressResponse> {\n const endpoint = `/spender-address?chainId=${chainId}&cross=${crossChainSwap ? 'true' : 'false'}&uuid=${quoteId}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = SpenderAddressResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n\n return parsed.data;\n}\n\n// ---------------------------------------------------------------------------\n// Hyperliquid 2-phase withdrawal: nonce-mapping authorize\n// ---------------------------------------------------------------------------\n\n/**\n * Legacy (`protocolVersion: 1`) authorize body — Markr rebuilds the upstream\n * Relay request from a fixed schema. Kept for back-compat; new integrations\n * should use {@link MarkrPostAuthorizeParamsV2}.\n *\n * **Caveat:** when Relay adds a required field (as it did with `depositor` in\n * v2), the rebuilt body silently omits it and the order is orphaned upstream.\n */\nexport interface MarkrPostAuthorizeParamsV1 {\n /** Quote uuid — lets Markr correlate the authorize call with the cached Relay step. */\n readonly uuid: string;\n /** User's EIP-712 signature over the `RelayNonceMapping` typed data (`0x{r}{s}{v}`, 65 bytes hex). */\n readonly signature: `0x${string}`;\n /** EVM address of the signer. */\n readonly wallet: EvmAddress;\n /** Always `1337` (Hyperliquid). */\n readonly walletChainId: 1337;\n /** EIP-712 domain.chainId used in the signature — the wallet's active chain. */\n readonly signatureChainId: number;\n /**\n * Shared nonce — JSON number, matching Relay's upstream `/authorize` contract\n * and HL `/exchange`. HL nonces are millisecond timestamps, well under\n * `Number.MAX_SAFE_INTEGER`. Sending it as a string makes Relay reject the\n * payload (strict type validation), so we coerce here at the wire boundary.\n */\n readonly nonce: number;\n /** Relay request id (`0x{64hex}`). */\n readonly id: `0x${string}`;\n}\n\n/**\n * Pass-through (`protocolVersion: 2`) authorize body. The SDK forwards Relay's\n * `authorize.body` envelope from the `/swap` response **verbatim**. Markr only\n * normalizes `nonce` to a JSON number and defaults `referrer`; every other\n * field is untouched, so additive Relay schema changes don't break SDKs.\n */\nexport interface MarkrPostAuthorizeParamsV2 {\n /** Quote uuid — lets Markr correlate the authorize call with the cached Relay step. */\n readonly uuid: string;\n /** User's EIP-712 signature over `swap.sign.value` using `swap.sign.domain` / `swap.sign.types`. */\n readonly signature: `0x${string}`;\n /** Relay's `/authorize` POST body, taken from `swap.authorize.body`. Forwarded verbatim. */\n readonly body: Record<string, unknown>;\n}\n\nexport type MarkrPostAuthorizeParams = MarkrPostAuthorizeParamsV1 | MarkrPostAuthorizeParamsV2;\n\n/**\n * Submit the user's signed nonce-mapping to Markr's `/authorize` endpoint.\n *\n * Markr proxies the request to Relay's upstream `/authorize`. Returns on any\n * 2xx; throws `HttpError` otherwise.\n */\nexport async function markrPostAuthorize(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: MarkrPostAuthorizeParams,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<void> {\n const endpoint = '/authorize';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n // `fetchJson` throws `HttpError` on non-2xx; the schema additionally rejects\n // upstream error envelopes that come back with a 200 (Relay sometimes does\n // this when authorize is rejected after HTTP success).\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n signal,\n });\n\n const parsed = MarkrAuthorizeResponseSchema.safeParse(rawJson);\n if (!parsed.success) {\n throw new ResponseValidationError(`Invalid response from Markr \"${endpoint}\" endpoint.`, parsed.error.issues);\n }\n}\n"],"mappings":"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"}
@@ -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(`../../../_utils/chain.cjs`),i=require(`../../_evm-gas.cjs`),a=require(`../../_evm-errors.cjs`),o=require(`../_api.cjs`),s=require(`../_utils.cjs`),c=require(`../_type-guards.cjs`),l=require(`../../../utils/solana.cjs`);let u=require(`viem`),d=require(`@solana/kit`);function f(t){return async(n,i)=>{if(r.isEvmNamespace(n.sourceChain.chainId))return await p(n,i,t);if(r.isSolanaNamespace(n.sourceChain.chainId))return await m(n,i,t);throw new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Unsupported source chain namespace for estimateNativeFee: ${n.sourceChain.chainId}`)}}async function p(r,l,{apiOptions:d,appId:f}){if(!(0,u.isAddress)(r.fromAddress))throw new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid fromAddress: ${r.fromAddress}`);let p=n.getEvmClientForChain({chain:r.sourceChain}),m=s.assetToAddressString(r.assetIn,r.sourceChain.chainId);if(!(0,u.isAddress)(m))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 g=s.isTokenAddressNative(m),_=r.sourceChain.chainId.toLowerCase()!==r.targetChain.chainId.toLowerCase(),v=r.amountIn+s.getAdditiveSourceAssetFeeAmount(r),y=0n;if(!g){let n,{address:i}=await o.markrGetSpenderAddress(d,{chainId:t.caip2ToEip155ChainId(r.sourceChain.chainId),crossChainSwap:_,quoteId:r.id});try{n=await p.readContract({address:m,abi:u.erc20Abi,functionName:`allowance`,args:[r.fromAddress,i]})}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<v&&(y=await a.estimateGasWithRevert(p,{account:r.fromAddress,to:m,data:(0,u.encodeFunctionData)({abi:u.erc20Abi,functionName:`approve`,args:[i,v]})},u.erc20Abi,`Failed to estimate gas for ERC20 approval transaction.`))}let b=y>0n,x=s.calculateMarkrMinimumAmountOut({amountOut:r.amountOut,assetOut:r.assetOut,slippageBps:r.slippageBps}),S=await o.markrSwap(d,{amountIn:r.amountIn.toString(),appId:f,minAmountOut:x.toString(),tokenIn:m,tokenOut:s.assetToAddressString(r.assetOut,r.targetChain.chainId),uuid:r.id});if(!c.isEvmSwapResponse(S)){let t=c.isSolanaSwapResponse(S)?S.chainType:c.isHyperliquidWithdrawSwapResponse(S)?S.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 C=0n;C=b?r.gasEstimate?r.gasEstimate:r.fees.filter(e=>e.type===`gas`&&e.chainId===r.sourceChain.chainId).reduce((e,t)=>e+t.amount,0n)||700000n:await h({crossChain:_,fromAddress:r.fromAddress,sourceClient:p,swap:S});let w=await i.estimateEvmFeesPerGas(p,r.sourceChain,l?.overrides?.feeRateTier),T=l?.overrides?.maxFeePerGas??w.maxFeePerGas,E=l?.overrides?.maxPriorityFeePerGas??w.maxPriorityFeePerGas,D=(C+y)*T;return{asset:r.sourceChain.networkToken,totalFee:n.applyFeeUnitsBpsMargin(D,l?.feeUnitsMarginBps),totalFeeWithoutMargin:D,meta:{approvalFee:b?y*T:void 0,maxFeePerGas:T,maxPriorityFeePerGas:E}}}async function m(t,r,{apiOptions:i,appId:a}){let u=s.assetToAddressString(t.assetIn,t.sourceChain.chainId);if(!(0,d.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 f=s.getAdditiveSourceNativeAssetFeeAmount(t),p=t.amountIn+f,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 h({crossChain:e,feeUnitsMarginBps:t,fromAddress:r,sourceClient:i,swap:o}){let c=await s.getMarkrSwapWrapperAbi(e);return n.applyFeeUnitsBpsMargin(await a.estimateGasWithRevert(i,{account:r,to:o.to,data:o.data,value:o.value},c,`Failed to estimate gas for Markr swap transaction.`),t)}exports._estimateGasFromSwapResponse=h,exports.estimateNativeFeeFactory=f;
1
+ require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../errors.cjs`),t=require(`../../../utils/caip.cjs`),n=require(`../../_utils.cjs`),r=require(`../../../_utils/chain.cjs`),i=require(`../../_evm-gas.cjs`),a=require(`../../_evm-errors.cjs`),o=require(`../_api.cjs`),s=require(`../_utils.cjs`),c=require(`../_type-guards.cjs`),l=require(`../../../utils/solana.cjs`);let u=require(`viem`),d=require(`@solana/kit`);function f(t){return async(n,i)=>{if(r.isEvmNamespace(n.sourceChain.chainId))return await p(n,i,t);if(r.isSolanaNamespace(n.sourceChain.chainId))return await m(n,i,t);throw new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Unsupported source chain namespace for estimateNativeFee: ${n.sourceChain.chainId}`)}}async function p(r,l,{apiOptions:d,appId:f}){if(!(0,u.isAddress)(r.fromAddress))throw new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid fromAddress: ${r.fromAddress}`);let p=n.getEvmClientForChain({chain:r.sourceChain}),m=s.assetToAddressString(r.assetIn,r.sourceChain.chainId);if(!(0,u.isAddress)(m))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 g=s.isTokenAddressNative(m),_=r.sourceChain.chainId.toLowerCase()!==r.targetChain.chainId.toLowerCase(),v=r.amountIn+s.getAdditiveSourceAssetFeeAmount(r),y=0n;if(!g){let n,{address:i}=await o.markrGetSpenderAddress(d,{chainId:t.caip2ToEip155ChainId(r.sourceChain.chainId),crossChainSwap:_,quoteId:r.id});try{n=await p.readContract({address:m,abi:u.erc20Abi,functionName:`allowance`,args:[r.fromAddress,i]})}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<v&&(y=await a.estimateGasWithRevert(p,{account:r.fromAddress,to:m,data:(0,u.encodeFunctionData)({abi:u.erc20Abi,functionName:`approve`,args:[i,v]})},u.erc20Abi,`Failed to estimate gas for ERC20 approval transaction.`))}let b=y>0n,x=s.calculateMarkrMinimumAmountOut({amountOut:r.amountOut,assetOut:r.assetOut,slippageBps:r.slippageBps}),S=await o.markrSwap(d,{amountIn:r.amountIn.toString(),appId:f,minAmountOut:x.toString(),tokenIn:m,tokenOut:s.assetToAddressString(r.assetOut,r.targetChain.chainId),uuid:r.id});if(!c.isEvmSwapResponse(S)){let t=c.isSolanaSwapResponse(S)?S.chainType:c.isHyperliquidWithdrawSwapResponse(S)?S.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 C=0n;C=b?r.gasEstimate||700000n:await h({crossChain:_,fromAddress:r.fromAddress,sourceClient:p,swap:S});let w=await i.estimateEvmFeesPerGas(p,r.sourceChain,l?.overrides?.feeRateTier),T=l?.overrides?.maxFeePerGas??w.maxFeePerGas,E=l?.overrides?.maxPriorityFeePerGas??w.maxPriorityFeePerGas,D=(C+y)*T;return{asset:r.sourceChain.networkToken,totalFee:n.applyFeeUnitsBpsMargin(D,l?.feeUnitsMarginBps),totalFeeWithoutMargin:D,meta:{approvalFee:b?y*T:void 0,maxFeePerGas:T,maxPriorityFeePerGas:E}}}async function m(t,r,{apiOptions:i,appId:a}){let u=s.assetToAddressString(t.assetIn,t.sourceChain.chainId);if(!(0,d.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 f=s.getAdditiveSourceNativeAssetFeeAmount(t),p=t.amountIn+f,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 h({crossChain:e,feeUnitsMarginBps:t,fromAddress:r,sourceClient:i,swap:o}){let c=await s.getMarkrSwapWrapperAbi(e);return n.applyFeeUnitsBpsMargin(await a.estimateGasWithRevert(i,{account:r,to:o.to,data:o.data,value:o.value},c,`Failed to estimate gas for Markr swap transaction.`),t)}exports._estimateGasFromSwapResponse=h,exports.estimateNativeFeeFactory=f;
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 // Attempt to use the Markr provided `gasEstimate` first if available.\n // Otherwise we attempt to get the gas from the `fees` component that are applicable\n // to the source chain. If neither of those are available, we fall back to a hardcoded value.\n if (quote.gasEstimate) {\n gas = quote.gasEstimate;\n } else {\n const sourceGasFee = quote.fees\n .filter((fee) => fee.type === 'gas' && fee.chainId === quote.sourceChain.chainId)\n .reduce((acc, fee) => acc + fee.amount, 0n);\n\n gas = sourceGasFee || EVM_SWAP_FALLBACK_GAS_ESTIMATE;\n }\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","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,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{isEvmNamespace as c,isSolanaNamespace as l}from"../../../_utils/chain.js";import{estimateEvmFeesPerGas as u}from"../../_evm-gas.js";import{estimateGasWithRevert as d}from"../../_evm-errors.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 w,erc20Abi as T,isAddress as E}from"viem";import{isAddress as D}from"@solana/kit";function O(e){return async(r,i)=>{if(c(r.sourceChain.chainId))return await k(r,i,e);if(l(r.sourceChain.chainId))return await A(r,i,e);throw new n(t.INVALID_PARAMS,`Unsupported source chain namespace for estimateNativeFee: ${r.sourceChain.chainId}`)}}async function k(s,c,{apiOptions:l,appId:_}){if(!E(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(!E(C))throw new r(t.INVALID_PARAMS,e.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address. Can not call estimateGas.`});let D=y(C),O=s.sourceChain.chainId.toLowerCase()!==s.targetChain.chainId.toLowerCase(),k=s.amountIn+g(s),A=0n;if(!D){let t,{address:n}=await f(l,{chainId:i(s.sourceChain.chainId),crossChainSwap:O,quoteId:s.id});try{t=await v.readContract({address:C,abi:T,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<k&&(A=await d(v,{account:s.fromAddress,to:C,data:w({abi:T,functionName:`approve`,args:[n,k]})},T,`Failed to estimate gas for ERC20 approval transaction.`))}let M=A>0n,N=h({amountOut:s.amountOut,assetOut:s.assetOut,slippageBps:s.slippageBps}),P=await p(l,{amountIn:s.amountIn.toString(),appId:_,minAmountOut:N.toString(),tokenIn:C,tokenOut:m(s.assetOut,s.targetChain.chainId),uuid:s.id});if(!b(P)){let n=S(P)?P.chainType:x(P)?P.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 F=0n;F=M?s.gasEstimate?s.gasEstimate:s.fees.filter(e=>e.type===`gas`&&e.chainId===s.sourceChain.chainId).reduce((e,t)=>e+t.amount,0n)||700000n:await j({crossChain:O,fromAddress:s.fromAddress,sourceClient:v,swap:P});let I=await u(v,s.sourceChain,c?.overrides?.feeRateTier),L=c?.overrides?.maxFeePerGas??I.maxFeePerGas,R=c?.overrides?.maxPriorityFeePerGas??I.maxPriorityFeePerGas,z=(F+A)*L;return{asset:s.sourceChain.networkToken,totalFee:a(z,c?.feeUnitsMarginBps),totalFeeWithoutMargin:z,meta:{approvalFee:M?A*L:void 0,maxFeePerGas:L,maxPriorityFeePerGas:R}}}async function A(n,i,{apiOptions:o,appId:c}){let l=m(n.assetIn,n.sourceChain.chainId);if(!D(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 j({crossChain:e,feeUnitsMarginBps:t,fromAddress:n,sourceClient:r,swap:i}){let o=await v(e);return a(await d(r,{account:n,to:i.to,data:i.data,value:i.value},o,`Failed to estimate gas for Markr swap transaction.`),t)}export{j as _estimateGasFromSwapResponse,O as estimateNativeFeeFactory};
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{isEvmNamespace as c,isSolanaNamespace as l}from"../../../_utils/chain.js";import{estimateEvmFeesPerGas as u}from"../../_evm-gas.js";import{estimateGasWithRevert as d}from"../../_evm-errors.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 w,erc20Abi as T,isAddress as E}from"viem";import{isAddress as D}from"@solana/kit";function O(e){return async(r,i)=>{if(c(r.sourceChain.chainId))return await k(r,i,e);if(l(r.sourceChain.chainId))return await A(r,i,e);throw new n(t.INVALID_PARAMS,`Unsupported source chain namespace for estimateNativeFee: ${r.sourceChain.chainId}`)}}async function k(s,c,{apiOptions:l,appId:_}){if(!E(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(!E(C))throw new r(t.INVALID_PARAMS,e.INVALID_PARAMS,{details:`assetIn address is not a valid EVM address. Can not call estimateGas.`});let D=y(C),O=s.sourceChain.chainId.toLowerCase()!==s.targetChain.chainId.toLowerCase(),k=s.amountIn+g(s),A=0n;if(!D){let t,{address:n}=await f(l,{chainId:i(s.sourceChain.chainId),crossChainSwap:O,quoteId:s.id});try{t=await v.readContract({address:C,abi:T,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<k&&(A=await d(v,{account:s.fromAddress,to:C,data:w({abi:T,functionName:`approve`,args:[n,k]})},T,`Failed to estimate gas for ERC20 approval transaction.`))}let M=A>0n,N=h({amountOut:s.amountOut,assetOut:s.assetOut,slippageBps:s.slippageBps}),P=await p(l,{amountIn:s.amountIn.toString(),appId:_,minAmountOut:N.toString(),tokenIn:C,tokenOut:m(s.assetOut,s.targetChain.chainId),uuid:s.id});if(!b(P)){let n=S(P)?P.chainType:x(P)?P.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 F=0n;F=M?s.gasEstimate||700000n:await j({crossChain:O,fromAddress:s.fromAddress,sourceClient:v,swap:P});let I=await u(v,s.sourceChain,c?.overrides?.feeRateTier),L=c?.overrides?.maxFeePerGas??I.maxFeePerGas,R=c?.overrides?.maxPriorityFeePerGas??I.maxPriorityFeePerGas,z=(F+A)*L;return{asset:s.sourceChain.networkToken,totalFee:a(z,c?.feeUnitsMarginBps),totalFeeWithoutMargin:z,meta:{approvalFee:M?A*L:void 0,maxFeePerGas:L,maxPriorityFeePerGas:R}}}async function A(n,i,{apiOptions:o,appId:c}){let l=m(n.assetIn,n.sourceChain.chainId);if(!D(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 j({crossChain:e,feeUnitsMarginBps:t,fromAddress:n,sourceClient:r,swap:i}){let o=await v(e);return a(await d(r,{account:n,to:i.to,data:i.data,value:i.value},o,`Failed to estimate gas for Markr swap transaction.`),t)}export{j as _estimateGasFromSwapResponse,O 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 // Attempt to use the Markr provided `gasEstimate` first if available.\n // Otherwise we attempt to get the gas from the `fees` component that are applicable\n // to the source chain. If neither of those are available, we fall back to a hardcoded value.\n if (quote.gasEstimate) {\n gas = quote.gasEstimate;\n } else {\n const sourceGasFee = quote.fees\n .filter((fee) => fee.type === 'gas' && fee.chainId === quote.sourceChain.chainId)\n .reduce((acc, fee) => acc + fee.amount, 0n);\n\n gas = sourceGasFee || EVM_SWAP_FALLBACK_GAS_ESTIMATE;\n }\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';\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,2 +1,2 @@
1
- const e=require(`../../../errors.cjs`),t=require(`../../../utils/caip.cjs`),n=require(`../../../_utils/chain.cjs`),r=require(`../../../utils/evm-address.cjs`),i=require(`../_api.cjs`),a=require(`../../../utils/sol-address.cjs`),o=require(`../_utils.cjs`);function s({apiOptions:e,appId:r,partnerFeeBps:a}){return(s,l,u)=>{let d=new AbortController,{userEvmAddress:f,userSolanaAddress:p,validationError:m}=c(s,u);return m?(l(`error`,m),l(`done`),{cancel:()=>{}}):(i.markrStreamQuote(e,{amount:s.amount.toString(),appId:r,chainId:n.isEvmNamespace(s.sourceChain.chainId)?t.caip2ToEip155ChainId(s.sourceChain.chainId):s.sourceChain.chainId,destinationChainId:s.sourceChain.chainId===s.targetChain.chainId?void 0:n.isEvmNamespace(s.targetChain.chainId)?t.caip2ToEip155ChainId(s.targetChain.chainId):s.targetChain.chainId,slippage:s.slippageBps,tokenIn:o.assetToAddressString(s.sourceAsset,s.sourceChain.chainId),tokenInDecimals:s.sourceAsset.decimals,tokenOut:o.assetToAddressString(s.targetAsset,s.targetChain.chainId),tokenOutDecimals:s.targetAsset.decimals,userEvmAddress:f,userSolanaAddress:p},{onDone:()=>{d.signal.aborted||l(`done`)},onError:e=>{d.signal.aborted||(l(`error`,e),l(`done`))},onQuote:e=>{d.signal.aborted||l(`quote`,o.quoteFromMarkrQuoteResponseData(e,s,a))},signal:d.signal}),{cancel:()=>{d.abort()}})}}function c(t,i){let o=t.sourceChain.chainId!==t.targetChain.chainId,s=n.isEvmNamespace(t.sourceChain.chainId),c=n.isEvmNamespace(t.targetChain.chainId),l=n.isSolanaNamespace(t.sourceChain.chainId),u=n.isSolanaNamespace(t.targetChain.chainId);return s&&!r.isEvmAddress(t.fromAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid fromAddress for EVM source chain.`)}:c&&!r.isEvmAddress(t.toAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid toAddress for EVM target chain.`)}:l&&!a.isSolAddress(t.fromAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid fromAddress for Solana source chain.`)}:u&&!a.isSolAddress(t.toAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid toAddress for Solana target chain.`)}:o&&(s&&c||l&&u)&&!i?.dangerouslyAllowAddressMismatch&&t.fromAddress!==t.toAddress?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`fromAddress and toAddress must match for same-namespace cross-chain swaps.`)}:o?{userEvmAddress:c&&r.isEvmAddress(t.toAddress)?t.toAddress:s&&r.isEvmAddress(t.fromAddress)?t.fromAddress:void 0,userSolanaAddress:u&&a.isSolAddress(t.toAddress)?t.toAddress:l&&a.isSolAddress(t.fromAddress)?t.fromAddress:void 0}:t.fromAddress===t.toAddress?{userEvmAddress:void 0,userSolanaAddress:void 0}:{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`fromAddress and toAddress must match for same-chain swaps.`)}}exports.streamQuotesFactory=s;
1
+ const e=require(`../../../errors.cjs`),t=require(`../../../utils/caip.cjs`),n=require(`../../../_utils/chain.cjs`),r=require(`../../../utils/evm-address.cjs`),i=require(`../_api.cjs`),a=require(`../../../utils/sol-address.cjs`),o=require(`../_utils.cjs`);function s({apiOptions:e,appId:r,partnerFeeBps:a}){return(s,l,u)=>{let d=new AbortController,{userEvmAddress:f,userSolanaAddress:p,validationError:m}=c(s,u);return m?(l(`error`,m),l(`done`),{cancel:()=>{}}):(i.markrStreamQuote(e,{amount:s.amount.toString(),aggregator:s.aggregator,appId:r,chainId:n.isEvmNamespace(s.sourceChain.chainId)?t.caip2ToEip155ChainId(s.sourceChain.chainId):s.sourceChain.chainId,destinationChainId:s.sourceChain.chainId===s.targetChain.chainId?void 0:n.isEvmNamespace(s.targetChain.chainId)?t.caip2ToEip155ChainId(s.targetChain.chainId):s.targetChain.chainId,slippage:s.slippageBps,tokenIn:o.assetToAddressString(s.sourceAsset,s.sourceChain.chainId),tokenInDecimals:s.sourceAsset.decimals,tokenOut:o.assetToAddressString(s.targetAsset,s.targetChain.chainId),tokenOutDecimals:s.targetAsset.decimals,userEvmAddress:f,userSolanaAddress:p},{onDone:()=>{d.signal.aborted||l(`done`)},onError:e=>{d.signal.aborted||(l(`error`,e),l(`done`))},onQuote:e=>{d.signal.aborted||l(`quote`,o.quoteFromMarkrQuoteResponseData(e,s,a))},signal:d.signal}),{cancel:()=>{d.abort()}})}}function c(t,i){let o=t.sourceChain.chainId!==t.targetChain.chainId,s=n.isEvmNamespace(t.sourceChain.chainId),c=n.isEvmNamespace(t.targetChain.chainId),l=n.isSolanaNamespace(t.sourceChain.chainId),u=n.isSolanaNamespace(t.targetChain.chainId);return s&&!r.isEvmAddress(t.fromAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid fromAddress for EVM source chain.`)}:c&&!r.isEvmAddress(t.toAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid toAddress for EVM target chain.`)}:l&&!a.isSolAddress(t.fromAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid fromAddress for Solana source chain.`)}:u&&!a.isSolAddress(t.toAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`Invalid toAddress for Solana target chain.`)}:o&&(s&&c||l&&u)&&!i?.dangerouslyAllowAddressMismatch&&t.fromAddress!==t.toAddress?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`fromAddress and toAddress must match for same-namespace cross-chain swaps.`)}:o?{userEvmAddress:c&&r.isEvmAddress(t.toAddress)?t.toAddress:s&&r.isEvmAddress(t.fromAddress)?t.fromAddress:void 0,userSolanaAddress:u&&a.isSolAddress(t.toAddress)?t.toAddress:l&&a.isSolAddress(t.fromAddress)?t.fromAddress:void 0}:t.fromAddress===t.toAddress?{userEvmAddress:void 0,userSolanaAddress:void 0}:{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new e.InvalidParamsError(e.ErrorReason.INVALID_PARAMS,`fromAddress and toAddress must match for same-chain swaps.`)}}exports.streamQuotesFactory=s;
2
2
  //# sourceMappingURL=stream-quotes.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream-quotes.cjs","names":["markrStreamQuote","isEvmNamespace","caip2ToEip155ChainId","assetToAddressString","quoteFromMarkrQuoteResponseData","isSolanaNamespace","isEvmAddress","InvalidParamsError","ErrorReason","isSolAddress"],"sources":["../../../../src/transfer-service/markr/_handlers/stream-quotes.ts"],"sourcesContent":["import { caip2ToEip155ChainId } from '../../../utils/caip';\nimport type { ServiceQuoteOptions, TransferService } from '../../../types/service';\nimport { markrStreamQuote, type ApiOptions, type MarkrStreamQuoteParams } from '../_api';\nimport { assetToAddressString, quoteFromMarkrQuoteResponseData } from '../_utils';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { isEvmAddress } from '../../../utils/evm-address';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport { ErrorReason, InvalidParamsError } from '../../../errors';\n\nexport interface StreamQuotesFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n partnerFeeBps: number;\n}\n\nexport function streamQuotesFactory({\n apiOptions,\n appId,\n partnerFeeBps,\n}: StreamQuotesFactoryConfig): TransferService['streamQuotes'] {\n return (props, handler, options) => {\n const ac = new AbortController();\n const { userEvmAddress, userSolanaAddress, validationError } = _validateAndGetUserAddresses(props, options);\n\n if (validationError) {\n handler('error', validationError);\n handler('done');\n\n return {\n cancel: () => {},\n };\n }\n\n void markrStreamQuote(\n apiOptions,\n {\n amount: props.amount.toString(),\n appId,\n chainId: isEvmNamespace(props.sourceChain.chainId)\n ? caip2ToEip155ChainId(props.sourceChain.chainId)\n : props.sourceChain.chainId,\n // For cross-chain requests, destinationChainId is required.\n // Use EVM numeric chain IDs for EVM targets and CAIP-2 IDs for non-EVM targets.\n destinationChainId:\n props.sourceChain.chainId !== props.targetChain.chainId\n ? isEvmNamespace(props.targetChain.chainId)\n ? caip2ToEip155ChainId(props.targetChain.chainId)\n : props.targetChain.chainId\n : undefined,\n slippage: props.slippageBps,\n tokenIn: assetToAddressString(props.sourceAsset, props.sourceChain.chainId),\n tokenInDecimals: props.sourceAsset.decimals,\n tokenOut: assetToAddressString(props.targetAsset, props.targetChain.chainId),\n tokenOutDecimals: props.targetAsset.decimals,\n userEvmAddress,\n userSolanaAddress,\n },\n {\n onDone: () => {\n if (!ac.signal.aborted) {\n handler('done');\n }\n },\n onError: (error) => {\n if (!ac.signal.aborted) {\n handler('error', error);\n handler('done');\n }\n },\n onQuote: (data) => {\n if (!ac.signal.aborted) {\n handler('quote', quoteFromMarkrQuoteResponseData(data, props, partnerFeeBps));\n }\n },\n signal: ac.signal,\n },\n );\n\n return {\n cancel: () => {\n ac.abort();\n },\n };\n };\n}\n\nexport function _validateAndGetUserAddresses(\n props: Parameters<TransferService['streamQuotes']>[0],\n options?: ServiceQuoteOptions,\n): Pick<MarkrStreamQuoteParams, 'userEvmAddress' | 'userSolanaAddress'> & { validationError?: InvalidParamsError } {\n const isCrossChainSwap = props.sourceChain.chainId !== props.targetChain.chainId;\n const sourceIsEvm = isEvmNamespace(props.sourceChain.chainId);\n const targetIsEvm = isEvmNamespace(props.targetChain.chainId);\n const sourceIsSolana = isSolanaNamespace(props.sourceChain.chainId);\n const targetIsSolana = isSolanaNamespace(props.targetChain.chainId);\n\n if (sourceIsEvm && !isEvmAddress(props.fromAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid fromAddress for EVM source chain.'),\n };\n }\n\n if (targetIsEvm && !isEvmAddress(props.toAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid toAddress for EVM target chain.'),\n };\n }\n\n if (sourceIsSolana && !isSolAddress(props.fromAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'Invalid fromAddress for Solana source chain.',\n ),\n };\n }\n\n if (targetIsSolana && !isSolAddress(props.toAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid toAddress for Solana target chain.'),\n };\n }\n\n if (\n isCrossChainSwap &&\n ((sourceIsEvm && targetIsEvm) || (sourceIsSolana && targetIsSolana)) &&\n !options?.dangerouslyAllowAddressMismatch\n ) {\n if (props.fromAddress !== props.toAddress) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'fromAddress and toAddress must match for same-namespace cross-chain swaps.',\n ),\n };\n }\n }\n\n if (!isCrossChainSwap) {\n if (props.fromAddress !== props.toAddress) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'fromAddress and toAddress must match for same-chain swaps.',\n ),\n };\n }\n\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n };\n }\n\n const userEvmAddress =\n targetIsEvm && isEvmAddress(props.toAddress)\n ? props.toAddress\n : sourceIsEvm && isEvmAddress(props.fromAddress)\n ? props.fromAddress\n : undefined;\n\n const userSolanaAddress =\n targetIsSolana && isSolAddress(props.toAddress)\n ? props.toAddress\n : sourceIsSolana && isSolAddress(props.fromAddress)\n ? props.fromAddress\n : undefined;\n\n return {\n userEvmAddress,\n userSolanaAddress,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stream-quotes.cjs","names":["markrStreamQuote","isEvmNamespace","caip2ToEip155ChainId","assetToAddressString","quoteFromMarkrQuoteResponseData","isSolanaNamespace","isEvmAddress","InvalidParamsError","ErrorReason","isSolAddress"],"sources":["../../../../src/transfer-service/markr/_handlers/stream-quotes.ts"],"sourcesContent":["import { caip2ToEip155ChainId } from '../../../utils/caip';\nimport type { ServiceQuoteOptions, TransferService } from '../../../types/service';\nimport { markrStreamQuote, type ApiOptions, type MarkrStreamQuoteParams } from '../_api';\nimport { assetToAddressString, quoteFromMarkrQuoteResponseData } from '../_utils';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { isEvmAddress } from '../../../utils/evm-address';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport { ErrorReason, InvalidParamsError } from '../../../errors';\n\nexport interface StreamQuotesFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n partnerFeeBps: number;\n}\n\nexport function streamQuotesFactory({\n apiOptions,\n appId,\n partnerFeeBps,\n}: StreamQuotesFactoryConfig): TransferService['streamQuotes'] {\n return (props, handler, options) => {\n const ac = new AbortController();\n const { userEvmAddress, userSolanaAddress, validationError } = _validateAndGetUserAddresses(props, options);\n\n if (validationError) {\n handler('error', validationError);\n handler('done');\n\n return {\n cancel: () => {},\n };\n }\n\n void markrStreamQuote(\n apiOptions,\n {\n amount: props.amount.toString(),\n // Forwarded only when the caller pins one; otherwise Markr races every aggregator.\n aggregator: props.aggregator,\n appId,\n chainId: isEvmNamespace(props.sourceChain.chainId)\n ? caip2ToEip155ChainId(props.sourceChain.chainId)\n : props.sourceChain.chainId,\n // For cross-chain requests, destinationChainId is required.\n // Use EVM numeric chain IDs for EVM targets and CAIP-2 IDs for non-EVM targets.\n destinationChainId:\n props.sourceChain.chainId !== props.targetChain.chainId\n ? isEvmNamespace(props.targetChain.chainId)\n ? caip2ToEip155ChainId(props.targetChain.chainId)\n : props.targetChain.chainId\n : undefined,\n slippage: props.slippageBps,\n tokenIn: assetToAddressString(props.sourceAsset, props.sourceChain.chainId),\n tokenInDecimals: props.sourceAsset.decimals,\n tokenOut: assetToAddressString(props.targetAsset, props.targetChain.chainId),\n tokenOutDecimals: props.targetAsset.decimals,\n userEvmAddress,\n userSolanaAddress,\n },\n {\n onDone: () => {\n if (!ac.signal.aborted) {\n handler('done');\n }\n },\n onError: (error) => {\n if (!ac.signal.aborted) {\n handler('error', error);\n handler('done');\n }\n },\n onQuote: (data) => {\n if (!ac.signal.aborted) {\n handler('quote', quoteFromMarkrQuoteResponseData(data, props, partnerFeeBps));\n }\n },\n signal: ac.signal,\n },\n );\n\n return {\n cancel: () => {\n ac.abort();\n },\n };\n };\n}\n\nexport function _validateAndGetUserAddresses(\n props: Parameters<TransferService['streamQuotes']>[0],\n options?: ServiceQuoteOptions,\n): Pick<MarkrStreamQuoteParams, 'userEvmAddress' | 'userSolanaAddress'> & { validationError?: InvalidParamsError } {\n const isCrossChainSwap = props.sourceChain.chainId !== props.targetChain.chainId;\n const sourceIsEvm = isEvmNamespace(props.sourceChain.chainId);\n const targetIsEvm = isEvmNamespace(props.targetChain.chainId);\n const sourceIsSolana = isSolanaNamespace(props.sourceChain.chainId);\n const targetIsSolana = isSolanaNamespace(props.targetChain.chainId);\n\n if (sourceIsEvm && !isEvmAddress(props.fromAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid fromAddress for EVM source chain.'),\n };\n }\n\n if (targetIsEvm && !isEvmAddress(props.toAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid toAddress for EVM target chain.'),\n };\n }\n\n if (sourceIsSolana && !isSolAddress(props.fromAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'Invalid fromAddress for Solana source chain.',\n ),\n };\n }\n\n if (targetIsSolana && !isSolAddress(props.toAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid toAddress for Solana target chain.'),\n };\n }\n\n if (\n isCrossChainSwap &&\n ((sourceIsEvm && targetIsEvm) || (sourceIsSolana && targetIsSolana)) &&\n !options?.dangerouslyAllowAddressMismatch\n ) {\n if (props.fromAddress !== props.toAddress) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'fromAddress and toAddress must match for same-namespace cross-chain swaps.',\n ),\n };\n }\n }\n\n if (!isCrossChainSwap) {\n if (props.fromAddress !== props.toAddress) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'fromAddress and toAddress must match for same-chain swaps.',\n ),\n };\n }\n\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n };\n }\n\n const userEvmAddress =\n targetIsEvm && isEvmAddress(props.toAddress)\n ? props.toAddress\n : sourceIsEvm && isEvmAddress(props.fromAddress)\n ? props.fromAddress\n : undefined;\n\n const userSolanaAddress =\n targetIsSolana && isSolAddress(props.toAddress)\n ? props.toAddress\n : sourceIsSolana && isSolAddress(props.fromAddress)\n ? props.fromAddress\n : undefined;\n\n return {\n userEvmAddress,\n userSolanaAddress,\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{ErrorReason as e,InvalidParamsError as t}from"../../../errors.js";import{caip2ToEip155ChainId as n}from"../../../utils/caip.js";import{isEvmNamespace as r,isSolanaNamespace as i}from"../../../_utils/chain.js";import{isEvmAddress as a}from"../../../utils/evm-address.js";import{markrStreamQuote as o}from"../_api.js";import{isSolAddress as s}from"../../../utils/sol-address.js";import{assetToAddressString as c,quoteFromMarkrQuoteResponseData as l}from"../_utils.js";function u({apiOptions:e,appId:t,partnerFeeBps:i}){return(a,s,u)=>{let f=new AbortController,{userEvmAddress:p,userSolanaAddress:m,validationError:h}=d(a,u);return h?(s(`error`,h),s(`done`),{cancel:()=>{}}):(o(e,{amount:a.amount.toString(),appId:t,chainId:r(a.sourceChain.chainId)?n(a.sourceChain.chainId):a.sourceChain.chainId,destinationChainId:a.sourceChain.chainId===a.targetChain.chainId?void 0:r(a.targetChain.chainId)?n(a.targetChain.chainId):a.targetChain.chainId,slippage:a.slippageBps,tokenIn:c(a.sourceAsset,a.sourceChain.chainId),tokenInDecimals:a.sourceAsset.decimals,tokenOut:c(a.targetAsset,a.targetChain.chainId),tokenOutDecimals:a.targetAsset.decimals,userEvmAddress:p,userSolanaAddress:m},{onDone:()=>{f.signal.aborted||s(`done`)},onError:e=>{f.signal.aborted||(s(`error`,e),s(`done`))},onQuote:e=>{f.signal.aborted||s(`quote`,l(e,a,i))},signal:f.signal}),{cancel:()=>{f.abort()}})}}function d(n,o){let c=n.sourceChain.chainId!==n.targetChain.chainId,l=r(n.sourceChain.chainId),u=r(n.targetChain.chainId),d=i(n.sourceChain.chainId),f=i(n.targetChain.chainId);return l&&!a(n.fromAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`Invalid fromAddress for EVM source chain.`)}:u&&!a(n.toAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`Invalid toAddress for EVM target chain.`)}:d&&!s(n.fromAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`Invalid fromAddress for Solana source chain.`)}:f&&!s(n.toAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`Invalid toAddress for Solana target chain.`)}:c&&(l&&u||d&&f)&&!o?.dangerouslyAllowAddressMismatch&&n.fromAddress!==n.toAddress?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`fromAddress and toAddress must match for same-namespace cross-chain swaps.`)}:c?{userEvmAddress:u&&a(n.toAddress)?n.toAddress:l&&a(n.fromAddress)?n.fromAddress:void 0,userSolanaAddress:f&&s(n.toAddress)?n.toAddress:d&&s(n.fromAddress)?n.fromAddress:void 0}:n.fromAddress===n.toAddress?{userEvmAddress:void 0,userSolanaAddress:void 0}:{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`fromAddress and toAddress must match for same-chain swaps.`)}}export{u as streamQuotesFactory};
1
+ import{ErrorReason as e,InvalidParamsError as t}from"../../../errors.js";import{caip2ToEip155ChainId as n}from"../../../utils/caip.js";import{isEvmNamespace as r,isSolanaNamespace as i}from"../../../_utils/chain.js";import{isEvmAddress as a}from"../../../utils/evm-address.js";import{markrStreamQuote as o}from"../_api.js";import{isSolAddress as s}from"../../../utils/sol-address.js";import{assetToAddressString as c,quoteFromMarkrQuoteResponseData as l}from"../_utils.js";function u({apiOptions:e,appId:t,partnerFeeBps:i}){return(a,s,u)=>{let f=new AbortController,{userEvmAddress:p,userSolanaAddress:m,validationError:h}=d(a,u);return h?(s(`error`,h),s(`done`),{cancel:()=>{}}):(o(e,{amount:a.amount.toString(),aggregator:a.aggregator,appId:t,chainId:r(a.sourceChain.chainId)?n(a.sourceChain.chainId):a.sourceChain.chainId,destinationChainId:a.sourceChain.chainId===a.targetChain.chainId?void 0:r(a.targetChain.chainId)?n(a.targetChain.chainId):a.targetChain.chainId,slippage:a.slippageBps,tokenIn:c(a.sourceAsset,a.sourceChain.chainId),tokenInDecimals:a.sourceAsset.decimals,tokenOut:c(a.targetAsset,a.targetChain.chainId),tokenOutDecimals:a.targetAsset.decimals,userEvmAddress:p,userSolanaAddress:m},{onDone:()=>{f.signal.aborted||s(`done`)},onError:e=>{f.signal.aborted||(s(`error`,e),s(`done`))},onQuote:e=>{f.signal.aborted||s(`quote`,l(e,a,i))},signal:f.signal}),{cancel:()=>{f.abort()}})}}function d(n,o){let c=n.sourceChain.chainId!==n.targetChain.chainId,l=r(n.sourceChain.chainId),u=r(n.targetChain.chainId),d=i(n.sourceChain.chainId),f=i(n.targetChain.chainId);return l&&!a(n.fromAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`Invalid fromAddress for EVM source chain.`)}:u&&!a(n.toAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`Invalid toAddress for EVM target chain.`)}:d&&!s(n.fromAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`Invalid fromAddress for Solana source chain.`)}:f&&!s(n.toAddress)?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`Invalid toAddress for Solana target chain.`)}:c&&(l&&u||d&&f)&&!o?.dangerouslyAllowAddressMismatch&&n.fromAddress!==n.toAddress?{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`fromAddress and toAddress must match for same-namespace cross-chain swaps.`)}:c?{userEvmAddress:u&&a(n.toAddress)?n.toAddress:l&&a(n.fromAddress)?n.fromAddress:void 0,userSolanaAddress:f&&s(n.toAddress)?n.toAddress:d&&s(n.fromAddress)?n.fromAddress:void 0}:n.fromAddress===n.toAddress?{userEvmAddress:void 0,userSolanaAddress:void 0}:{userEvmAddress:void 0,userSolanaAddress:void 0,validationError:new t(e.INVALID_PARAMS,`fromAddress and toAddress must match for same-chain swaps.`)}}export{u as streamQuotesFactory};
2
2
  //# sourceMappingURL=stream-quotes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream-quotes.js","names":[],"sources":["../../../../src/transfer-service/markr/_handlers/stream-quotes.ts"],"sourcesContent":["import { caip2ToEip155ChainId } from '../../../utils/caip';\nimport type { ServiceQuoteOptions, TransferService } from '../../../types/service';\nimport { markrStreamQuote, type ApiOptions, type MarkrStreamQuoteParams } from '../_api';\nimport { assetToAddressString, quoteFromMarkrQuoteResponseData } from '../_utils';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { isEvmAddress } from '../../../utils/evm-address';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport { ErrorReason, InvalidParamsError } from '../../../errors';\n\nexport interface StreamQuotesFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n partnerFeeBps: number;\n}\n\nexport function streamQuotesFactory({\n apiOptions,\n appId,\n partnerFeeBps,\n}: StreamQuotesFactoryConfig): TransferService['streamQuotes'] {\n return (props, handler, options) => {\n const ac = new AbortController();\n const { userEvmAddress, userSolanaAddress, validationError } = _validateAndGetUserAddresses(props, options);\n\n if (validationError) {\n handler('error', validationError);\n handler('done');\n\n return {\n cancel: () => {},\n };\n }\n\n void markrStreamQuote(\n apiOptions,\n {\n amount: props.amount.toString(),\n appId,\n chainId: isEvmNamespace(props.sourceChain.chainId)\n ? caip2ToEip155ChainId(props.sourceChain.chainId)\n : props.sourceChain.chainId,\n // For cross-chain requests, destinationChainId is required.\n // Use EVM numeric chain IDs for EVM targets and CAIP-2 IDs for non-EVM targets.\n destinationChainId:\n props.sourceChain.chainId !== props.targetChain.chainId\n ? isEvmNamespace(props.targetChain.chainId)\n ? caip2ToEip155ChainId(props.targetChain.chainId)\n : props.targetChain.chainId\n : undefined,\n slippage: props.slippageBps,\n tokenIn: assetToAddressString(props.sourceAsset, props.sourceChain.chainId),\n tokenInDecimals: props.sourceAsset.decimals,\n tokenOut: assetToAddressString(props.targetAsset, props.targetChain.chainId),\n tokenOutDecimals: props.targetAsset.decimals,\n userEvmAddress,\n userSolanaAddress,\n },\n {\n onDone: () => {\n if (!ac.signal.aborted) {\n handler('done');\n }\n },\n onError: (error) => {\n if (!ac.signal.aborted) {\n handler('error', error);\n handler('done');\n }\n },\n onQuote: (data) => {\n if (!ac.signal.aborted) {\n handler('quote', quoteFromMarkrQuoteResponseData(data, props, partnerFeeBps));\n }\n },\n signal: ac.signal,\n },\n );\n\n return {\n cancel: () => {\n ac.abort();\n },\n };\n };\n}\n\nexport function _validateAndGetUserAddresses(\n props: Parameters<TransferService['streamQuotes']>[0],\n options?: ServiceQuoteOptions,\n): Pick<MarkrStreamQuoteParams, 'userEvmAddress' | 'userSolanaAddress'> & { validationError?: InvalidParamsError } {\n const isCrossChainSwap = props.sourceChain.chainId !== props.targetChain.chainId;\n const sourceIsEvm = isEvmNamespace(props.sourceChain.chainId);\n const targetIsEvm = isEvmNamespace(props.targetChain.chainId);\n const sourceIsSolana = isSolanaNamespace(props.sourceChain.chainId);\n const targetIsSolana = isSolanaNamespace(props.targetChain.chainId);\n\n if (sourceIsEvm && !isEvmAddress(props.fromAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid fromAddress for EVM source chain.'),\n };\n }\n\n if (targetIsEvm && !isEvmAddress(props.toAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid toAddress for EVM target chain.'),\n };\n }\n\n if (sourceIsSolana && !isSolAddress(props.fromAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'Invalid fromAddress for Solana source chain.',\n ),\n };\n }\n\n if (targetIsSolana && !isSolAddress(props.toAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid toAddress for Solana target chain.'),\n };\n }\n\n if (\n isCrossChainSwap &&\n ((sourceIsEvm && targetIsEvm) || (sourceIsSolana && targetIsSolana)) &&\n !options?.dangerouslyAllowAddressMismatch\n ) {\n if (props.fromAddress !== props.toAddress) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'fromAddress and toAddress must match for same-namespace cross-chain swaps.',\n ),\n };\n }\n }\n\n if (!isCrossChainSwap) {\n if (props.fromAddress !== props.toAddress) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'fromAddress and toAddress must match for same-chain swaps.',\n ),\n };\n }\n\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n };\n }\n\n const userEvmAddress =\n targetIsEvm && isEvmAddress(props.toAddress)\n ? props.toAddress\n : sourceIsEvm && isEvmAddress(props.fromAddress)\n ? props.fromAddress\n : undefined;\n\n const userSolanaAddress =\n targetIsSolana && isSolAddress(props.toAddress)\n ? props.toAddress\n : sourceIsSolana && isSolAddress(props.fromAddress)\n ? props.fromAddress\n : undefined;\n\n return {\n userEvmAddress,\n userSolanaAddress,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stream-quotes.js","names":[],"sources":["../../../../src/transfer-service/markr/_handlers/stream-quotes.ts"],"sourcesContent":["import { caip2ToEip155ChainId } from '../../../utils/caip';\nimport type { ServiceQuoteOptions, TransferService } from '../../../types/service';\nimport { markrStreamQuote, type ApiOptions, type MarkrStreamQuoteParams } from '../_api';\nimport { assetToAddressString, quoteFromMarkrQuoteResponseData } from '../_utils';\nimport { isEvmNamespace, isSolanaNamespace } from '../../../_utils/chain';\nimport { isEvmAddress } from '../../../utils/evm-address';\nimport { isSolAddress } from '../../../utils/sol-address';\nimport { ErrorReason, InvalidParamsError } from '../../../errors';\n\nexport interface StreamQuotesFactoryConfig {\n apiOptions: ApiOptions;\n appId: string;\n partnerFeeBps: number;\n}\n\nexport function streamQuotesFactory({\n apiOptions,\n appId,\n partnerFeeBps,\n}: StreamQuotesFactoryConfig): TransferService['streamQuotes'] {\n return (props, handler, options) => {\n const ac = new AbortController();\n const { userEvmAddress, userSolanaAddress, validationError } = _validateAndGetUserAddresses(props, options);\n\n if (validationError) {\n handler('error', validationError);\n handler('done');\n\n return {\n cancel: () => {},\n };\n }\n\n void markrStreamQuote(\n apiOptions,\n {\n amount: props.amount.toString(),\n // Forwarded only when the caller pins one; otherwise Markr races every aggregator.\n aggregator: props.aggregator,\n appId,\n chainId: isEvmNamespace(props.sourceChain.chainId)\n ? caip2ToEip155ChainId(props.sourceChain.chainId)\n : props.sourceChain.chainId,\n // For cross-chain requests, destinationChainId is required.\n // Use EVM numeric chain IDs for EVM targets and CAIP-2 IDs for non-EVM targets.\n destinationChainId:\n props.sourceChain.chainId !== props.targetChain.chainId\n ? isEvmNamespace(props.targetChain.chainId)\n ? caip2ToEip155ChainId(props.targetChain.chainId)\n : props.targetChain.chainId\n : undefined,\n slippage: props.slippageBps,\n tokenIn: assetToAddressString(props.sourceAsset, props.sourceChain.chainId),\n tokenInDecimals: props.sourceAsset.decimals,\n tokenOut: assetToAddressString(props.targetAsset, props.targetChain.chainId),\n tokenOutDecimals: props.targetAsset.decimals,\n userEvmAddress,\n userSolanaAddress,\n },\n {\n onDone: () => {\n if (!ac.signal.aborted) {\n handler('done');\n }\n },\n onError: (error) => {\n if (!ac.signal.aborted) {\n handler('error', error);\n handler('done');\n }\n },\n onQuote: (data) => {\n if (!ac.signal.aborted) {\n handler('quote', quoteFromMarkrQuoteResponseData(data, props, partnerFeeBps));\n }\n },\n signal: ac.signal,\n },\n );\n\n return {\n cancel: () => {\n ac.abort();\n },\n };\n };\n}\n\nexport function _validateAndGetUserAddresses(\n props: Parameters<TransferService['streamQuotes']>[0],\n options?: ServiceQuoteOptions,\n): Pick<MarkrStreamQuoteParams, 'userEvmAddress' | 'userSolanaAddress'> & { validationError?: InvalidParamsError } {\n const isCrossChainSwap = props.sourceChain.chainId !== props.targetChain.chainId;\n const sourceIsEvm = isEvmNamespace(props.sourceChain.chainId);\n const targetIsEvm = isEvmNamespace(props.targetChain.chainId);\n const sourceIsSolana = isSolanaNamespace(props.sourceChain.chainId);\n const targetIsSolana = isSolanaNamespace(props.targetChain.chainId);\n\n if (sourceIsEvm && !isEvmAddress(props.fromAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid fromAddress for EVM source chain.'),\n };\n }\n\n if (targetIsEvm && !isEvmAddress(props.toAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid toAddress for EVM target chain.'),\n };\n }\n\n if (sourceIsSolana && !isSolAddress(props.fromAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'Invalid fromAddress for Solana source chain.',\n ),\n };\n }\n\n if (targetIsSolana && !isSolAddress(props.toAddress)) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'Invalid toAddress for Solana target chain.'),\n };\n }\n\n if (\n isCrossChainSwap &&\n ((sourceIsEvm && targetIsEvm) || (sourceIsSolana && targetIsSolana)) &&\n !options?.dangerouslyAllowAddressMismatch\n ) {\n if (props.fromAddress !== props.toAddress) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'fromAddress and toAddress must match for same-namespace cross-chain swaps.',\n ),\n };\n }\n }\n\n if (!isCrossChainSwap) {\n if (props.fromAddress !== props.toAddress) {\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n validationError: new InvalidParamsError(\n ErrorReason.INVALID_PARAMS,\n 'fromAddress and toAddress must match for same-chain swaps.',\n ),\n };\n }\n\n return {\n userEvmAddress: undefined,\n userSolanaAddress: undefined,\n };\n }\n\n const userEvmAddress =\n targetIsEvm && isEvmAddress(props.toAddress)\n ? props.toAddress\n : sourceIsEvm && isEvmAddress(props.fromAddress)\n ? props.fromAddress\n : undefined;\n\n const userSolanaAddress =\n targetIsSolana && isSolAddress(props.toAddress)\n ? props.toAddress\n : sourceIsSolana && isSolAddress(props.fromAddress)\n ? props.fromAddress\n : undefined;\n\n return {\n userEvmAddress,\n userSolanaAddress,\n };\n}\n"],"mappings":"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"}
@@ -147,6 +147,15 @@ interface QuoterProps {
147
147
  readonly targetChain: Chain;
148
148
  /** Recipient address on target chain. */
149
149
  readonly toAddress: string;
150
+ /**
151
+ * Pin quoting to a single upstream aggregator (Markr only).
152
+ *
153
+ * Markr otherwise races every eligible aggregator. Passing an id (e.g.
154
+ * `"relay"`) restricts the quote to that aggregator — used to obtain
155
+ * native-fee-free routes that only a specific aggregator supports.
156
+ *
157
+ */
158
+ readonly aggregator?: string;
150
159
  }
151
160
  interface QuoterInterface {
152
161
  /**
@@ -147,6 +147,15 @@ interface QuoterProps {
147
147
  readonly targetChain: Chain;
148
148
  /** Recipient address on target chain. */
149
149
  readonly toAddress: string;
150
+ /**
151
+ * Pin quoting to a single upstream aggregator (Markr only).
152
+ *
153
+ * Markr otherwise races every eligible aggregator. Passing an id (e.g.
154
+ * `"relay"`) restricts the quote to that aggregator — used to obtain
155
+ * native-fee-free routes that only a specific aggregator supports.
156
+ *
157
+ */
158
+ readonly aggregator?: string;
150
159
  }
151
160
  interface QuoterInterface {
152
161
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@avalabs/fusion-sdk",
3
3
  "license": "Limited Ecosystem License",
4
- "version": "0.20.0",
4
+ "version": "0.21.0",
5
5
  "type": "module",
6
6
  "main": "./dist/mod.cjs",
7
7
  "module": "./dist/mod.js",