@rhea-finance/confidential-swap 0.2.4 → 0.2.5

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,"sources":["../../src/adapters/index.ts","../../src/errors.ts","../../src/identity.ts","../../src/utils.ts","../../src/signatures.ts","../../src/validation.ts"],"sourcesContent":["import { base58 } from \"@scure/base\";\nimport { assert, ConfidentialSwapError, isUserRejectedError, responseAssert, throwIfAborted, userRejectedError } from \"../errors\";\nimport { sameLinking } from \"../identity\";\nimport { decodeEd25519, decodeNep413Nonce, normalizeSecpSignature, toSignatureBytes } from \"../signatures\";\nimport { clone } from \"../utils\";\nimport { validateSigned } from \"../validation\";\nimport type { HttpConfidentialApi } from \"../api\";\nimport type { LinkingIdentity, SignedData, SigningAdapter, UnsignedData } from \"../types\";\n\nexport interface EvmMessageSigner { getAddress(): Promise<string>; signMessage(message: string): Promise<string> }\nexport function createEvmSigningAdapter(getSigner: () => Promise<EvmMessageSigner> | EvmMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"evm\", accountId: await (await getSigner()).getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"erc191\", \"Expected ERC-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await (await getSigner()).signMessage(data.payload)) };\n },\n });\n}\nexport interface SolanaMessageSigner { publicKey: { toBase58(): string }; signMessage(message: Uint8Array): Promise<unknown> }\nexport function createSolanaSigningAdapter(getWallet: () => SolanaMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"solana\", accountId: getWallet().publicKey.toBase58(), publicKey: `ed25519:${getWallet().publicKey.toBase58()}` }),\n sign: async (data) => {\n assert(data.standard === \"raw_ed25519\", \"Expected raw Ed25519 payload.\");\n const wallet = getWallet();\n const signature = toSignatureBytes(await wallet.signMessage(new TextEncoder().encode(data.payload)));\n return { ...data, public_key: `ed25519:${wallet.publicKey.toBase58()}`, signature: `ed25519:${base58.encode(decodeEd25519(signature, 64))}` };\n },\n });\n}\nexport interface TronMessageSigner { getAddress(): Promise<string> | string; signMessageV2(message: string): Promise<string> }\nexport function createTronSigningAdapter(getWallet: () => TronMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"tron\", accountId: await getWallet().getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"tip191\", \"Expected TIP-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await getWallet().signMessageV2(data.payload)) };\n },\n });\n}\nexport interface NearMessageSigner {\n getIdentity(): Promise<{ accountId: string; publicKey: string }>;\n signMessage(params: { message: string; recipient: string; nonce: Uint8Array; callbackUrl?: string }): Promise<{ accountId: string; publicKey: string; signature: string }>;\n /** Explicit user-approved NEAR transaction: add_public_key on the configured Intents contract. */\n registerPublicKey?(accountId: string, publicKey: string, contract: string, signal?: AbortSignal): Promise<void>;\n}\nexport function createNearSigningAdapter(wallet: NearMessageSigner, api: Pick<HttpConfidentialApi, \"viewIntents\" | \"intentsContract\">): SigningAdapter {\n const getIdentity = async (): Promise<LinkingIdentity> => {\n const identity = await wallet.getIdentity();\n return { kind: \"near\", accountId: identity.accountId, publicKey: `ed25519:${base58.encode(decodeEd25519(identity.publicKey, 32))}` };\n };\n return createCheckedAdapter({\n getIdentity,\n prepare: async (signal) => {\n const identity = await getIdentity();\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) {\n const keyHex = Array.from(decodeEd25519(identity.publicKey!, 32), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n assert(keyHex === identity.accountId, \"Implicit NEAR account does not match its signing public key.\");\n } else {\n const registered = await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal);\n responseAssert(typeof registered === \"boolean\", \"Invalid key registration response.\");\n if (!registered) {\n assert(wallet.registerPublicKey, \"NEAR key registration requires an explicit registerPublicKey callback.\");\n throwIfAborted(signal);\n await wallet.registerPublicKey(identity.accountId, identity.publicKey!, api.intentsContract, signal);\n responseAssert(await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal) === true, \"NEAR signing key registration is not confirmed.\");\n }\n }\n },\n sign: async (data) => {\n assert(data.standard === \"nep413\", \"Expected NEP-413 payload.\");\n const result = await wallet.signMessage({ ...data.payload, nonce: decodeNep413Nonce(data.payload.nonce) });\n responseAssert(result.accountId === (await getIdentity()).accountId, \"NEAR wallet returned a different account.\");\n return { ...data, public_key: `ed25519:${base58.encode(decodeEd25519(result.publicKey, 32))}`, signature: `ed25519:${base58.encode(decodeEd25519(result.signature, 64))}` };\n },\n });\n}\nexport function createCheckedAdapter(adapter: SigningAdapter): SigningAdapter {\n return {\n getIdentity: () => adapter.getIdentity(),\n prepare: adapter.prepare?.bind(adapter),\n sign: async (data: UnsignedData, signal?: AbortSignal): Promise<SignedData> => {\n throwIfAborted(signal);\n const identity = await adapter.getIdentity();\n let signed: SignedData;\n try {\n signed = await adapter.sign(clone(data), signal);\n } catch (error) {\n if (isUserRejectedError(error)) throw userRejectedError();\n throw error;\n }\n throwIfAborted(signal);\n if (!sameLinking(identity, await adapter.getIdentity())) throw new ConfidentialSwapError(\"WALLET_CHANGED\", \"Wallet identity changed while signing.\");\n validateSigned(data, signed, identity);\n return signed;\n },\n };\n}\n","export type ErrorCode =\n | \"INVALID_INPUT\" | \"INVALID_RESPONSE\" | \"HTTP_ERROR\" | \"UNAUTHORIZED\"\n | \"WALLET_CHANGED\" | \"MISSING_WALLET\" | \"QUOTE_EXPIRED\" | \"BUSY\"\n | \"CONFIRMATION_REQUIRED\" | \"USER_REJECTED\" | \"TIMEOUT\" | \"ABORTED\" | \"TERMINAL_FAILURE\";\n\nexport class ConfidentialSwapError extends Error {\n readonly name = \"ConfidentialSwapError\";\n constructor(\n readonly code: ErrorCode,\n message: string,\n readonly status?: number,\n readonly executionId?: string,\n ) { super(message); }\n}\n\nexport function assert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_INPUT\", message);\n}\n\nexport function responseAssert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_RESPONSE\", message);\n}\n\nexport function isUserRejectedError(error: unknown): boolean {\n if (error instanceof ConfidentialSwapError) return error.code === \"USER_REJECTED\";\n if (!error || typeof error !== \"object\") return false;\n const value = error as { code?: unknown; message?: unknown; error?: unknown };\n const code = String(value.code ?? \"\").toUpperCase();\n const message = String(value.message ?? value.error ?? \"\");\n return (\n code === \"4001\" ||\n code === \"ACTION_REJECTED\" ||\n /user.*(reject|cancel|den(?:y|ied))|(?:reject|cancel|den(?:y|ied)).*user/i.test(message)\n );\n}\n\nexport function userRejectedError(executionId?: string): ConfidentialSwapError {\n return new ConfidentialSwapError(\n \"USER_REJECTED\",\n \"User rejected transaction.\",\n undefined,\n executionId,\n );\n}\n\nexport function throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted)\n throw new ConfidentialSwapError(\"ABORTED\", \"Trade cancelled.\");\n}\n","import { base16, base58, base58check } from \"@scure/base\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { assert } from \"./errors\";\nimport { text } from \"./utils\";\nimport type { FundingIdentity, LinkingIdentity, LinkingKind, SigningStandard } from \"./types\";\n\nexport const CONFIDENTIAL_LINKING_KINDS = [\"near\", \"evm\", \"solana\", \"tron\"] as const;\nexport const standards: Record<LinkingKind, SigningStandard> = { near: \"nep413\", evm: \"erc191\", solana: \"raw_ed25519\", tron: \"tip191\" };\nexport function deriveConfidentialAccountId(kind: LinkingKind, address: string): string {\n const account = text(address, \"Wallet account\");\n if (kind === \"near\") {\n assert(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(account) && account.length >= 2 && account.length <= 64, \"Invalid NEAR account.\");\n return account;\n }\n if (kind === \"evm\") { assert(/^0x[0-9a-f]{40}$/i.test(account), \"Invalid EVM address.\"); return account.toLowerCase(); }\n if (kind === \"solana\") {\n const bytes = base58.decode(account);\n assert(bytes.length === 32, \"Invalid Solana public key.\");\n return base16.encode(bytes).toLowerCase();\n }\n assert(kind === \"tron\", \"Unsupported linking wallet kind.\");\n const bytes = base58check(sha256).decode(account);\n assert(bytes.length === 21 && bytes[0] === 0x41, \"Invalid Tron address.\");\n return `0x${base16.encode(bytes.slice(1)).toLowerCase()}`;\n}\nexport function identityKey(identity: LinkingIdentity): string {\n // Session / linking identity is account-scoped — do not include publicKey.\n return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}`;\n}\nexport function sameLinking(a: LinkingIdentity, b: LinkingIdentity): boolean { return identityKey(a) === identityKey(b); }\nexport function sameFunding(a: FundingIdentity, b: FundingIdentity): boolean {\n return a.kind === b.kind && a.chain === b.chain && (a.kind === \"evm\" ? a.accountId.toLowerCase() === b.accountId.toLowerCase() : a.accountId === b.accountId);\n}\nexport function resolveLinkingWallet(input: { sourceKind?: string; wallets: readonly LinkingIdentity[]; preferred?: LinkingIdentity }): LinkingIdentity | null {\n const wallets = input.wallets.filter((w) => CONFIDENTIAL_LINKING_KINDS.includes(w.kind) && w.accountId.trim());\n if (input.preferred) return wallets.find((w) => sameLinking(w, input.preferred!)) ?? null;\n return wallets.find((w) => w.kind === input.sourceKind) ?? CONFIDENTIAL_LINKING_KINDS.map((kind) => wallets.find((w) => w.kind === kind)).find(Boolean) ?? null;\n}\n","import { sha256 } from \"@noble/hashes/sha256\";\nimport { bytesToHex } from \"@noble/hashes/utils\";\nimport { assert, throwIfAborted } from \"./errors\";\nimport type { Balance, QuotePlan } from \"./types\";\n\nexport function raw(value: unknown, field = \"Amount\", allowZero = false): bigint {\n assert(typeof value === \"string\" && /^(0|[1-9]\\d*)$/.test(value), `${field} must be a canonical integer string.`);\n const result = BigInt(value);\n assert(allowZero || result > 0n, `${field} must be positive.`);\n return result;\n}\n/** Rescale a raw integer between token decimals (floor when shrinking). */\nexport function rescaleRawAmount(amount: string, fromDecimals: number, toDecimals: number): string {\n assert(Number.isInteger(fromDecimals) && fromDecimals >= 0 && fromDecimals <= 255, \"Invalid source decimals.\");\n assert(Number.isInteger(toDecimals) && toDecimals >= 0 && toDecimals <= 255, \"Invalid target decimals.\");\n const value = raw(amount);\n if (fromDecimals === toDecimals) return value.toString();\n if (toDecimals > fromDecimals) {\n return (value * 10n ** BigInt(toDecimals - fromDecimals)).toString();\n }\n const scaled = value / 10n ** BigInt(fromDecimals - toDecimals);\n assert(scaled > 0n, \"Amount too small after decimal conversion.\");\n return scaled.toString();\n}\nexport function text(value: unknown, field: string): string {\n assert(typeof value === \"string\" && value.trim().length > 0, `${field} is required.`);\n return value.trim();\n}\nexport function clone<T>(value: T): T { return structuredClone(value); }\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value).filter(([, v]) => v !== undefined).sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${JSON.stringify(k)}:${canonical(v)}`).join(\",\")}}`;\n }\n assert(value === null || [\"string\", \"boolean\", \"number\"].includes(typeof value), \"Plan data must be JSON-serializable.\");\n if (typeof value === \"number\") assert(Number.isFinite(value), \"Plan numbers must be finite.\");\n return JSON.stringify(value);\n}\nexport function planDigest(plan: Omit<QuotePlan, \"digest\"> | QuotePlan): string {\n const { digest: _digest, ...body } = plan as QuotePlan;\n return bytesToHex(sha256(new TextEncoder().encode(canonical(body))));\n}\nexport function randomFraction(): number {\n return crypto.getRandomValues(new Uint32Array(1))[0]! / 0xffffffff;\n}\nexport function splitConfidentialRawAmount(totalRaw: string, count: number, values?: readonly number[]): string[] {\n assert(Number.isInteger(count) && count >= 1 && count <= 10, \"A batch requires 1 to 10 recipients.\");\n const total = raw(totalRaw);\n assert(total >= BigInt(count), \"Amount too small for every recipient.\");\n const minimum = total * 80n / (100n * BigInt(count));\n const lowBound = minimum > 0n ? minimum : 1n;\n const denominator = 100n * BigInt(count);\n const maximum = (total * 120n + denominator - 1n) / denominator;\n const highBound = maximum > lowBound ? maximum : lowBound;\n const shares: bigint[] = [];\n let remaining = total;\n for (let i = 0; i < count - 1; i++) {\n const left = BigInt(count - i - 1);\n const low = remaining - highBound * left > lowBound ? remaining - highBound * left : lowBound;\n const high = remaining - lowBound * left < highBound ? remaining - lowBound * left : highBound;\n assert(low <= high, \"Amount cannot be split safely.\");\n const fraction = values?.[i] ?? randomFraction();\n assert(Number.isFinite(fraction) && fraction >= 0 && fraction <= 1, \"Random fractions must be within [0, 1].\");\n const share = low + (high - low) * BigInt(Math.floor(fraction * 1_000_000)) / 1_000_000n;\n shares.push(share);\n remaining -= share;\n }\n assert(remaining >= lowBound && remaining <= highBound, \"Final share outside safe bounds.\");\n return [...shares, remaining].map(String);\n}\n/**\n * Quote / route assetIds (especially `1cs_v1:…`) may differ from the tokenId\n * returned by `/account/balances`. Native assets often settle as\n * `nep141:<symbol>.omft.near` (ZEC/BTC/XRP/SOL/…), not the per-chain 1cs id.\n */\nfunction balanceLookupIds(assetId: string, symbol?: string): string[] {\n const ids = [assetId];\n const near1cs = /^1cs_v1:near:(nep141:.+)$/i.exec(assetId);\n if (near1cs) ids.push(near1cs[1]!);\n const nep = /^(nep141:.+)$/i.exec(assetId);\n if (nep) ids.push(`1cs_v1:near:${nep[1]}`);\n const sym = symbol?.trim().toLowerCase();\n if (sym && /^[a-z0-9]+$/i.test(sym)) {\n const omft = `nep141:${sym}.omft.near`;\n ids.push(omft, `1cs_v1:near:${omft}`);\n }\n return [...new Set(ids)];\n}\n\nexport function availableForAsset(\n balances: readonly Balance[],\n assetId: string,\n symbol?: string,\n): string {\n for (const id of balanceLookupIds(assetId, symbol)) {\n const exact = balances.find((b) => b.tokenId === id);\n const entry =\n exact ??\n balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${id}`));\n if (entry) return raw(entry.available ?? \"0\", \"Available balance\", true).toString();\n }\n return \"0\";\n}\nexport async function delay(ms: number, signal?: AbortSignal): Promise<void> {\n throwIfAborted(signal);\n await new Promise<void>((resolve, reject) => {\n const finish = () => { signal?.removeEventListener(\"abort\", abort); resolve(); };\n const timer = setTimeout(finish, ms);\n const abort = () => { clearTimeout(timer); signal?.removeEventListener(\"abort\", abort); try { throwIfAborted(signal); } catch (e) { reject(e); } };\n signal?.addEventListener(\"abort\", abort, { once: true });\n });\n}\n","import { ed25519 } from \"@noble/curves/ed25519\";\nimport { secp256k1 } from \"@noble/curves/secp256k1\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport { concatBytes } from \"@noble/hashes/utils\";\nimport { base16, base58, base64, base64nopad, base64urlnopad } from \"@scure/base\";\nimport { responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId } from \"./identity\";\nimport type { LinkingIdentity, SignedData, UnsignedData } from \"./types\";\n\nconst encode = (s: string) => new TextEncoder().encode(s);\nfunction u32(value: number): Uint8Array { const b = new Uint8Array(4); new DataView(b.buffer).setUint32(0, value, true); return b; }\nfunction borshString(s: string): Uint8Array { const b = encode(s); return concatBytes(u32(b.length), b); }\nexport function decodeNep413Nonce(value: string): Uint8Array {\n responseAssert(typeof value === \"string\", \"Invalid NEP-413 nonce.\");\n const normalized = value.trim();\n let nonce: Uint8Array;\n try { nonce = base64.decode(normalized); }\n catch {\n const unpadded = normalized.replace(/=+$/, \"\");\n try { nonce = base64urlnopad.decode(unpadded); }\n catch {\n try { nonce = base64nopad.decode(unpadded); }\n catch { responseAssert(false, \"Invalid NEP-413 nonce encoding.\"); }\n }\n }\n responseAssert(nonce.length === 32, \"The NEP-413 nonce must be 32 bytes.\");\n return nonce;\n}\nexport function nep413Hash(payload: Extract<UnsignedData, { standard: \"nep413\" }>[\"payload\"]): Uint8Array {\n const nonce = decodeNep413Nonce(payload.nonce);\n return sha256(concatBytes(u32(2 ** 31 + 413), borshString(payload.message), nonce, borshString(payload.recipient), payload.callbackUrl === undefined ? new Uint8Array([0]) : concatBytes(new Uint8Array([1]), borshString(payload.callbackUrl))));\n}\nexport function personalMessageHash(message: string, kind: \"evm\" | \"tron\"): Uint8Array {\n const bytes = encode(message);\n return keccak_256(concatBytes(encode(`\\x19${kind === \"evm\" ? \"Ethereum\" : \"TRON\"} Signed Message:\\n${bytes.length}`), bytes));\n}\nexport function toSignatureBytes(value: unknown): Uint8Array {\n if (value instanceof Uint8Array) return value;\n if (value && typeof value === \"object\" && \"signature\" in value) {\n return toSignatureBytes((value as { signature: unknown }).signature);\n }\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n throw new Error(\"The wallet returned an invalid Ed25519 signature.\");\n}\nexport function decodeEd25519(value: string | Uint8Array, length: number): Uint8Array {\n if (value instanceof Uint8Array) { responseAssert(value.length === length, \"Invalid Ed25519 byte length.\"); return new Uint8Array(value); }\n const raw = value.replace(/^ed25519:/, \"\");\n for (const decoder of [() => base58.decode(raw), () => base64.decode(raw), () => base16.decode(raw.replace(/^0x/, \"\").toUpperCase())]) {\n try { const b = decoder(); if (b.length === length) return b; } catch { /* Wallets use base58, base64, or hex. */ }\n }\n responseAssert(false, \"Invalid Ed25519 encoding.\");\n}\nexport function normalizeSecpSignature(value: string): string {\n const hex = value.replace(/^0x/i, \"\");\n responseAssert(/^[0-9a-f]{130}$/i.test(hex), \"Expected a 65-byte signature.\");\n const bytes = base16.decode(hex.toUpperCase());\n const v = bytes[64]!;\n responseAssert([0, 1, 27, 28].includes(v), \"Invalid recovery id.\");\n bytes[64] = v < 27 ? v + 27 : v;\n return `0x${base16.encode(bytes).toLowerCase()}`;\n}\nexport function verifyWalletSignature(data: SignedData, identity: LinkingIdentity): void {\n let valid = false;\n try {\n if (identity.kind === \"near\" && data.standard === \"nep413\") {\n const key = decodeEd25519(identity.publicKey ?? \"\", 32);\n valid = ed25519.verify(decodeEd25519(data.signature, 64), nep413Hash(data.payload), key);\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) valid = valid && base16.encode(key).toLowerCase() === identity.accountId;\n } else if (identity.kind === \"solana\" && data.standard === \"raw_ed25519\") {\n valid = ed25519.verify(decodeEd25519(data.signature, 64), encode(data.payload), base58.decode(identity.accountId));\n } else if ((identity.kind === \"evm\" || identity.kind === \"tron\") && typeof data.payload === \"string\") {\n const bytes = base16.decode(normalizeSecpSignature(data.signature).slice(2).toUpperCase());\n const sig = secp256k1.Signature.fromCompact(bytes.slice(0, 64)).addRecoveryBit(bytes[64]! - 27);\n const publicKey = sig.recoverPublicKey(personalMessageHash(data.payload, identity.kind)).toRawBytes(false);\n const address = `0x${base16.encode(keccak_256(publicKey.slice(1)).slice(-20)).toLowerCase()}`;\n valid = address === deriveConfidentialAccountId(identity.kind, identity.accountId);\n }\n } catch { valid = false; }\n responseAssert(valid, \"Signature does not verify against the frozen wallet identity.\");\n}\n","import { base58, base64 } from \"@scure/base\";\nimport { assert, responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId, standards } from \"./identity\";\nimport { normalizeChain } from \"./routing\";\nimport { raw, text } from \"./utils\";\nimport { decodeNep413Nonce, verifyWalletSignature } from \"./signatures\";\nimport type { LinkingIdentity, QuoteResponse, SignedData, Token, UnsignedData } from \"./types\";\n\nconst evmChains = new Set([\"eth\", \"arb\", \"avax\", \"op\", \"pol\", \"bsc\", \"base\", \"gnosis\", \"aurora\", \"bera\", \"berachain\", \"monad\", \"hypercore\", \"hyperliquid\", \"linea\", \"scroll\", \"zksync\", \"mantle\", \"celo\", \"sonic\"]);\nexport type AddressValidator = (address: string, token: Token) => boolean;\nexport function validateRecipients(addresses: readonly string[], token: Token, custom?: AddressValidator): string[] {\n assert(addresses.length >= 1 && addresses.length <= 10, \"A batch requires 1 to 10 recipients.\");\n const chain = normalizeChain(token.blockchain);\n const evm = evmChains.has(chain) || /^\\d+$/.test(token.swapChain ?? chain);\n const seen = new Set<string>();\n return addresses.map((value) => {\n const address = text(value, \"Recipient address\");\n let valid = false;\n try {\n if (custom) valid = custom(address, token);\n else if (evm) valid = /^0x[0-9a-f]{40}$/i.test(address);\n else if (chain === \"near\") { deriveConfidentialAccountId(\"near\", address); valid = true; }\n else if (chain === \"sol\") valid = base58.decode(address).length === 32;\n else if (chain === \"tron\") { deriveConfidentialAccountId(\"tron\", address); valid = true; }\n else if (chain === \"aptos\") valid = /^0x[0-9a-f]{1,64}$/i.test(address);\n else if (chain === \"sui\") valid = /^0x[0-9a-f]{64}$/i.test(address);\n else assert(false, \"Supply an address validator for this destination chain (including BTC/Zcash).\");\n } catch (error) { if (!custom && !evm && ![\"near\", \"sol\", \"tron\", \"aptos\", \"sui\"].includes(chain)) throw error; }\n assert(valid, \"Invalid recipient address for the destination chain.\");\n const key = evm || [\"aptos\", \"sui\"].includes(chain) ? address.toLowerCase() : address;\n assert(!seen.has(key), \"Duplicate recipient address.\");\n seen.add(key);\n return address;\n });\n}\nexport function validateToken(token: Token): void {\n text(token.assetId, \"Asset id\"); text(token.blockchain, \"Blockchain\"); text(token.symbol, \"Symbol\");\n assert(Number.isInteger(token.decimals) && token.decimals >= 0 && token.decimals <= 255, \"Invalid token decimals.\");\n}\nexport function validateQuote(q: QuoteResponse, requireDeposit: boolean): void {\n responseAssert(q && typeof q.quote === \"object\" && q.quote, \"Missing quote.\");\n raw(q.quote.amountIn, \"Quoted input\"); raw(q.quote.amountOut, \"Quoted output\");\n if (q.quote.minAmountOut !== undefined) assert(raw(q.quote.minAmountOut) <= raw(q.quote.amountOut), \"Minimum output exceeds quoted output.\");\n if (q.quote.minAmountIn !== undefined) raw(q.quote.minAmountIn);\n if (q.quoteRequest?.appFees !== undefined) {\n raw(q.quoteRequest.amount, \"Quote request amount\");\n responseAssert(Array.isArray(q.quoteRequest.appFees), \"Invalid quote app fees.\");\n for (const fee of q.quoteRequest.appFees) {\n responseAssert(fee && Number.isInteger(fee.fee) && fee.fee >= 0, \"Invalid quote app fee rate.\");\n }\n }\n if (requireDeposit) text(q.quote.depositAddress, \"Deposit address\");\n}\nexport function payloadMessage(data: UnsignedData): Record<string, unknown> {\n let message: unknown;\n try { message = JSON.parse(typeof data.payload === \"string\" ? data.payload : data.payload.message); }\n catch { responseAssert(false, \"Invalid intent JSON.\"); }\n responseAssert(message && typeof message === \"object\" && !Array.isArray(message), \"Invalid intent payload.\");\n return message as Record<string, unknown>;\n}\nexport function validatePayload(data: UnsignedData, identity: LinkingIdentity, signerId: string, contract: string, now: number, purpose: \"authorization\" | \"withdrawal\" = \"authorization\"): Record<string, unknown> {\n responseAssert(data.standard === standards[identity.kind], \"Signing standard does not match wallet.\");\n const msg = payloadMessage(data);\n responseAssert(msg.signer_id === signerId, \"Intent signer does not match the frozen identity.\");\n const deadline = Date.parse(String(msg.deadline ?? \"\"));\n responseAssert(Number.isFinite(deadline) && deadline > now, \"Intent deadline expired or invalid.\");\n responseAssert(Array.isArray(msg.intents), \"Intent list is missing.\");\n if (data.standard === \"nep413\") {\n text(data.payload.recipient, \"NEP-413 recipient\");\n // Generated withdrawals carry their own signed recipient; only login binds the configured verifier.\n if (purpose === \"authorization\") responseAssert(data.payload.recipient === contract, \"Invalid NEP-413 authorization verifier.\");\n decodeNep413Nonce(data.payload.nonce);\n } else if (purpose === \"authorization\") {\n responseAssert(msg.verifying_contract === contract && typeof msg.nonce === \"string\" && base64.decode(msg.nonce).length === 32, \"Invalid verifier or nonce.\");\n }\n return msg;\n}\nexport function validateSigned(unsigned: UnsignedData, signed: SignedData, identity: LinkingIdentity): void {\n responseAssert(signed.standard === unsigned.standard && JSON.stringify(signed.payload) === JSON.stringify(unsigned.payload), \"Wallet changed the payload.\");\n text(signed.signature, \"Signature\");\n if (identity.kind === \"near\" || identity.kind === \"solana\") {\n const expected = identity.publicKey ?? (identity.kind === \"solana\" ? `ed25519:${identity.accountId}` : \"\");\n responseAssert(expected && signed.public_key === expected, \"Signing public key changed.\");\n }\n verifyWalletSignature(signed, identity);\n}\n"],"mappings":"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","names":["import_base","import_sha256","bytes","import_sha256","import_utils","import_base","raw","import_base"]}
1
+ {"version":3,"sources":["../../src/adapters/index.ts","../../src/errors.ts","../../src/identity.ts","../../src/utils.ts","../../src/signatures.ts","../../src/validation.ts"],"sourcesContent":["import { base58 } from \"@scure/base\";\nimport { assert, ConfidentialSwapError, isUserRejectedError, responseAssert, throwIfAborted, userRejectedError } from \"../errors\";\nimport { sameLinking } from \"../identity\";\nimport { decodeEd25519, decodeNep413Nonce, normalizeSecpSignature, toSignatureBytes } from \"../signatures\";\nimport { clone } from \"../utils\";\nimport { validateSigned } from \"../validation\";\nimport type { HttpConfidentialApi } from \"../api\";\nimport type { LinkingIdentity, SignedData, SigningAdapter, UnsignedData } from \"../types\";\n\nexport interface EvmMessageSigner { getAddress(): Promise<string>; signMessage(message: string): Promise<string> }\nexport function createEvmSigningAdapter(getSigner: () => Promise<EvmMessageSigner> | EvmMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"evm\", accountId: await (await getSigner()).getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"erc191\", \"Expected ERC-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await (await getSigner()).signMessage(data.payload)) };\n },\n });\n}\nexport interface SolanaMessageSigner { publicKey: { toBase58(): string }; signMessage(message: Uint8Array): Promise<unknown> }\nexport function createSolanaSigningAdapter(getWallet: () => SolanaMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"solana\", accountId: getWallet().publicKey.toBase58(), publicKey: `ed25519:${getWallet().publicKey.toBase58()}` }),\n sign: async (data) => {\n assert(data.standard === \"raw_ed25519\", \"Expected raw Ed25519 payload.\");\n const wallet = getWallet();\n const signature = toSignatureBytes(await wallet.signMessage(new TextEncoder().encode(data.payload)));\n return { ...data, public_key: `ed25519:${wallet.publicKey.toBase58()}`, signature: `ed25519:${base58.encode(decodeEd25519(signature, 64))}` };\n },\n });\n}\nexport interface TronMessageSigner { getAddress(): Promise<string> | string; signMessageV2(message: string): Promise<string> }\nexport function createTronSigningAdapter(getWallet: () => TronMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"tron\", accountId: await getWallet().getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"tip191\", \"Expected TIP-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await getWallet().signMessageV2(data.payload)) };\n },\n });\n}\nexport interface NearMessageSigner {\n getIdentity(): Promise<{ accountId: string; publicKey: string }>;\n signMessage(params: { message: string; recipient: string; nonce: Uint8Array; callbackUrl?: string }): Promise<{ accountId: string; publicKey: string; signature: string }>;\n /** Explicit user-approved NEAR transaction: add_public_key on the configured Intents contract. */\n registerPublicKey?(accountId: string, publicKey: string, contract: string, signal?: AbortSignal): Promise<void>;\n}\nexport function createNearSigningAdapter(wallet: NearMessageSigner, api: Pick<HttpConfidentialApi, \"viewIntents\" | \"intentsContract\">): SigningAdapter {\n const getIdentity = async (): Promise<LinkingIdentity> => {\n const identity = await wallet.getIdentity();\n return { kind: \"near\", accountId: identity.accountId, publicKey: `ed25519:${base58.encode(decodeEd25519(identity.publicKey, 32))}` };\n };\n return createCheckedAdapter({\n getIdentity,\n prepare: async (signal) => {\n const identity = await getIdentity();\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) {\n const keyHex = Array.from(decodeEd25519(identity.publicKey!, 32), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n assert(keyHex === identity.accountId, \"Implicit NEAR account does not match its signing public key.\");\n } else {\n const registered = await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal);\n responseAssert(typeof registered === \"boolean\", \"Invalid key registration response.\");\n if (!registered) {\n assert(wallet.registerPublicKey, \"NEAR key registration requires an explicit registerPublicKey callback.\");\n throwIfAborted(signal);\n await wallet.registerPublicKey(identity.accountId, identity.publicKey!, api.intentsContract, signal);\n responseAssert(await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal) === true, \"NEAR signing key registration is not confirmed.\");\n }\n }\n },\n sign: async (data) => {\n assert(data.standard === \"nep413\", \"Expected NEP-413 payload.\");\n const result = await wallet.signMessage({ ...data.payload, nonce: decodeNep413Nonce(data.payload.nonce) });\n responseAssert(result.accountId === (await getIdentity()).accountId, \"NEAR wallet returned a different account.\");\n return { ...data, public_key: `ed25519:${base58.encode(decodeEd25519(result.publicKey, 32))}`, signature: `ed25519:${base58.encode(decodeEd25519(result.signature, 64))}` };\n },\n });\n}\nexport function createCheckedAdapter(adapter: SigningAdapter): SigningAdapter {\n return {\n getIdentity: () => adapter.getIdentity(),\n prepare: adapter.prepare?.bind(adapter),\n sign: async (data: UnsignedData, signal?: AbortSignal): Promise<SignedData> => {\n throwIfAborted(signal);\n const identity = await adapter.getIdentity();\n let signed: SignedData;\n try {\n signed = await adapter.sign(clone(data), signal);\n } catch (error) {\n if (isUserRejectedError(error)) throw userRejectedError();\n throw error;\n }\n throwIfAborted(signal);\n if (!sameLinking(identity, await adapter.getIdentity())) throw new ConfidentialSwapError(\"WALLET_CHANGED\", \"Wallet identity changed while signing.\");\n validateSigned(data, signed, identity);\n return signed;\n },\n };\n}\n","export type ErrorCode =\n | \"INVALID_INPUT\" | \"INVALID_RESPONSE\" | \"HTTP_ERROR\" | \"UNAUTHORIZED\"\n | \"WALLET_CHANGED\" | \"MISSING_WALLET\" | \"QUOTE_EXPIRED\" | \"BUSY\"\n | \"CONFIRMATION_REQUIRED\" | \"USER_REJECTED\" | \"TIMEOUT\" | \"ABORTED\" | \"TERMINAL_FAILURE\";\n\nexport class ConfidentialSwapError extends Error {\n readonly name = \"ConfidentialSwapError\";\n constructor(\n readonly code: ErrorCode,\n message: string,\n readonly status?: number,\n readonly executionId?: string,\n ) { super(message); }\n}\n\nexport function assert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_INPUT\", message);\n}\n\nexport function responseAssert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_RESPONSE\", message);\n}\n\nexport function isUserRejectedError(error: unknown): boolean {\n if (error instanceof ConfidentialSwapError) return error.code === \"USER_REJECTED\";\n if (!error || typeof error !== \"object\") return false;\n const value = error as { code?: unknown; message?: unknown; error?: unknown };\n const code = String(value.code ?? \"\").toUpperCase();\n const message = String(value.message ?? value.error ?? \"\");\n return (\n code === \"4001\" ||\n code === \"ACTION_REJECTED\" ||\n /user.*(reject|cancel|den(?:y|ied))|(?:reject|cancel|den(?:y|ied)).*user/i.test(message)\n );\n}\n\nexport function userRejectedError(executionId?: string): ConfidentialSwapError {\n return new ConfidentialSwapError(\n \"USER_REJECTED\",\n \"User rejected transaction.\",\n undefined,\n executionId,\n );\n}\n\nexport function throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted)\n throw new ConfidentialSwapError(\"ABORTED\", \"Trade cancelled.\");\n}\n","import { base16, base58, base58check } from \"@scure/base\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { assert } from \"./errors\";\nimport { text } from \"./utils\";\nimport type { FundingIdentity, LinkingIdentity, LinkingKind, SigningStandard } from \"./types\";\n\nexport const CONFIDENTIAL_LINKING_KINDS = [\"near\", \"evm\", \"solana\", \"tron\"] as const;\nexport const standards: Record<LinkingKind, SigningStandard> = { near: \"nep413\", evm: \"erc191\", solana: \"raw_ed25519\", tron: \"tip191\" };\nexport function deriveConfidentialAccountId(kind: LinkingKind, address: string): string {\n const account = text(address, \"Wallet account\");\n if (kind === \"near\") {\n assert(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(account) && account.length >= 2 && account.length <= 64, \"Invalid NEAR account.\");\n return account;\n }\n if (kind === \"evm\") { assert(/^0x[0-9a-f]{40}$/i.test(account), \"Invalid EVM address.\"); return account.toLowerCase(); }\n if (kind === \"solana\") {\n const bytes = base58.decode(account);\n assert(bytes.length === 32, \"Invalid Solana public key.\");\n return base16.encode(bytes).toLowerCase();\n }\n assert(kind === \"tron\", \"Unsupported linking wallet kind.\");\n const bytes = base58check(sha256).decode(account);\n assert(bytes.length === 21 && bytes[0] === 0x41, \"Invalid Tron address.\");\n return `0x${base16.encode(bytes.slice(1)).toLowerCase()}`;\n}\nexport function identityKey(identity: LinkingIdentity): string {\n // Session / linking identity is account-scoped — do not include publicKey.\n return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}`;\n}\nexport function sameLinking(a: LinkingIdentity, b: LinkingIdentity): boolean { return identityKey(a) === identityKey(b); }\nexport function sameFunding(a: FundingIdentity, b: FundingIdentity): boolean {\n return a.kind === b.kind && a.chain === b.chain && (a.kind === \"evm\" ? a.accountId.toLowerCase() === b.accountId.toLowerCase() : a.accountId === b.accountId);\n}\nexport function resolveLinkingWallet(input: { sourceKind?: string; wallets: readonly LinkingIdentity[]; preferred?: LinkingIdentity }): LinkingIdentity | null {\n const wallets = input.wallets.filter((w) => CONFIDENTIAL_LINKING_KINDS.includes(w.kind) && w.accountId.trim());\n if (input.preferred) return wallets.find((w) => sameLinking(w, input.preferred!)) ?? null;\n return wallets.find((w) => w.kind === input.sourceKind) ?? CONFIDENTIAL_LINKING_KINDS.map((kind) => wallets.find((w) => w.kind === kind)).find(Boolean) ?? null;\n}\n","import { sha256 } from \"@noble/hashes/sha256\";\nimport { bytesToHex } from \"@noble/hashes/utils\";\nimport { assert, throwIfAborted } from \"./errors\";\nimport type { Balance, BalanceSnapshotEntry, QuotePlan } from \"./types\";\n\nexport function raw(value: unknown, field = \"Amount\", allowZero = false): bigint {\n assert(typeof value === \"string\" && /^(0|[1-9]\\d*)$/.test(value), `${field} must be a canonical integer string.`);\n const result = BigInt(value);\n assert(allowZero || result > 0n, `${field} must be positive.`);\n return result;\n}\n/** Rescale a raw integer between token decimals (floor when shrinking). */\nexport function rescaleRawAmount(amount: string, fromDecimals: number, toDecimals: number): string {\n assert(Number.isInteger(fromDecimals) && fromDecimals >= 0 && fromDecimals <= 255, \"Invalid source decimals.\");\n assert(Number.isInteger(toDecimals) && toDecimals >= 0 && toDecimals <= 255, \"Invalid target decimals.\");\n const value = raw(amount);\n if (fromDecimals === toDecimals) return value.toString();\n if (toDecimals > fromDecimals) {\n return (value * 10n ** BigInt(toDecimals - fromDecimals)).toString();\n }\n const scaled = value / 10n ** BigInt(fromDecimals - toDecimals);\n assert(scaled > 0n, \"Amount too small after decimal conversion.\");\n return scaled.toString();\n}\nexport function text(value: unknown, field: string): string {\n assert(typeof value === \"string\" && value.trim().length > 0, `${field} is required.`);\n return value.trim();\n}\nexport function clone<T>(value: T): T { return structuredClone(value); }\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value).filter(([, v]) => v !== undefined).sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${JSON.stringify(k)}:${canonical(v)}`).join(\",\")}}`;\n }\n assert(value === null || [\"string\", \"boolean\", \"number\"].includes(typeof value), \"Plan data must be JSON-serializable.\");\n if (typeof value === \"number\") assert(Number.isFinite(value), \"Plan numbers must be finite.\");\n return JSON.stringify(value);\n}\nexport function planDigest(plan: Omit<QuotePlan, \"digest\"> | QuotePlan): string {\n const { digest: _digest, ...body } = plan as QuotePlan;\n return bytesToHex(sha256(new TextEncoder().encode(canonical(body))));\n}\nexport function randomFraction(): number {\n return crypto.getRandomValues(new Uint32Array(1))[0]! / 0xffffffff;\n}\nexport function splitConfidentialRawAmount(totalRaw: string, count: number, values?: readonly number[]): string[] {\n assert(Number.isInteger(count) && count >= 1 && count <= 10, \"A batch requires 1 to 10 recipients.\");\n const total = raw(totalRaw);\n assert(total >= BigInt(count), \"Amount too small for every recipient.\");\n const minimum = total * 80n / (100n * BigInt(count));\n const lowBound = minimum > 0n ? minimum : 1n;\n const denominator = 100n * BigInt(count);\n const maximum = (total * 120n + denominator - 1n) / denominator;\n const highBound = maximum > lowBound ? maximum : lowBound;\n const shares: bigint[] = [];\n let remaining = total;\n for (let i = 0; i < count - 1; i++) {\n const left = BigInt(count - i - 1);\n const low = remaining - highBound * left > lowBound ? remaining - highBound * left : lowBound;\n const high = remaining - lowBound * left < highBound ? remaining - lowBound * left : highBound;\n assert(low <= high, \"Amount cannot be split safely.\");\n const fraction = values?.[i] ?? randomFraction();\n assert(Number.isFinite(fraction) && fraction >= 0 && fraction <= 1, \"Random fractions must be within [0, 1].\");\n const share = low + (high - low) * BigInt(Math.floor(fraction * 1_000_000)) / 1_000_000n;\n shares.push(share);\n remaining -= share;\n }\n assert(remaining >= lowBound && remaining <= highBound, \"Final share outside safe bounds.\");\n return [...shares, remaining].map(String);\n}\n/**\n * Quote / route assetIds (especially `1cs_v1:…`) may differ from the tokenId\n * returned by `/account/balances`. Native assets often settle as\n * `nep141:<symbol>.omft.near` (ZEC/BTC/XRP/SOL/…), not the per-chain 1cs id.\n */\nfunction balanceLookupIds(assetId: string, symbol?: string): string[] {\n const ids = [assetId];\n const near1cs = /^1cs_v1:near:(nep141:.+)$/i.exec(assetId);\n if (near1cs) ids.push(near1cs[1]!);\n const nep = /^(nep141:.+)$/i.exec(assetId);\n if (nep) ids.push(`1cs_v1:near:${nep[1]}`);\n const sym = symbol?.trim().toLowerCase();\n if (sym && /^[a-z0-9]+$/i.test(sym)) {\n const omft = `nep141:${sym}.omft.near`;\n ids.push(omft, `1cs_v1:near:${omft}`);\n }\n return [...new Set(ids)];\n}\n\nexport function availableForAsset(\n balances: readonly Balance[],\n assetId: string,\n symbol?: string,\n): string {\n for (const id of balanceLookupIds(assetId, symbol)) {\n const exact = balances.find((b) => b.tokenId === id);\n const entry =\n exact ??\n balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${id}`));\n if (entry) return raw(entry.available ?? \"0\", \"Available balance\", true).toString();\n }\n return \"0\";\n}\n\n/** Strip `imt:<account>:` so the same asset compares across API shapes. */\nexport function balanceCanonicalKey(tokenId: string): string {\n const imt = /^imt:[^:]+:(.+)$/.exec(tokenId);\n return imt?.[1] ?? tokenId;\n}\n\nexport function snapshotBalances(balances: readonly Balance[]): BalanceSnapshotEntry[] {\n return balances.map((b) => ({\n tokenId: b.tokenId,\n available: raw(b.available ?? \"0\", \"Available balance\", true).toString(),\n }));\n}\n\nexport interface CreditedBalanceChange {\n tokenId: string;\n baseline: string;\n available: string;\n delta: string;\n}\n\n/**\n * Find which account token increased by at least `credited` vs the baseline snapshot.\n * Prefers an exact delta match, then the largest qualifying increase.\n */\nexport function findCreditedBalanceChange(\n baseline: readonly BalanceSnapshotEntry[] | undefined,\n current: readonly Balance[],\n credited: string,\n): CreditedBalanceChange | null {\n const creditedBn = raw(credited);\n if (creditedBn <= 0n) return null;\n\n const baseByKey = new Map<string, bigint>();\n for (const row of baseline ?? []) {\n const key = balanceCanonicalKey(row.tokenId);\n const amount = raw(row.available, \"Baseline\", true);\n const prev = baseByKey.get(key);\n if (prev === undefined || amount > prev) baseByKey.set(key, amount);\n }\n\n const increases: CreditedBalanceChange[] = [];\n const seen = new Set<string>();\n for (const row of current) {\n const key = balanceCanonicalKey(row.tokenId);\n if (seen.has(key)) continue;\n seen.add(key);\n const availableBn = raw(row.available ?? \"0\", \"Available\", true);\n const baselineBn = baseByKey.get(key) ?? 0n;\n const delta = availableBn - baselineBn;\n if (delta >= creditedBn) {\n increases.push({\n tokenId: row.tokenId.startsWith(\"imt:\") ? key : row.tokenId,\n baseline: baselineBn.toString(),\n available: availableBn.toString(),\n delta: delta.toString(),\n });\n }\n }\n if (increases.length === 0) return null;\n const exact = increases.find((row) => row.delta === credited);\n if (exact) return exact;\n return increases.reduce((best, row) =>\n BigInt(row.delta) > BigInt(best.delta) ? row : best,\n );\n}\nexport async function delay(ms: number, signal?: AbortSignal): Promise<void> {\n throwIfAborted(signal);\n await new Promise<void>((resolve, reject) => {\n const finish = () => { signal?.removeEventListener(\"abort\", abort); resolve(); };\n const timer = setTimeout(finish, ms);\n const abort = () => { clearTimeout(timer); signal?.removeEventListener(\"abort\", abort); try { throwIfAborted(signal); } catch (e) { reject(e); } };\n signal?.addEventListener(\"abort\", abort, { once: true });\n });\n}\n","import { ed25519 } from \"@noble/curves/ed25519\";\nimport { secp256k1 } from \"@noble/curves/secp256k1\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport { concatBytes } from \"@noble/hashes/utils\";\nimport { base16, base58, base64, base64nopad, base64urlnopad } from \"@scure/base\";\nimport { responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId } from \"./identity\";\nimport type { LinkingIdentity, SignedData, UnsignedData } from \"./types\";\n\nconst encode = (s: string) => new TextEncoder().encode(s);\nfunction u32(value: number): Uint8Array { const b = new Uint8Array(4); new DataView(b.buffer).setUint32(0, value, true); return b; }\nfunction borshString(s: string): Uint8Array { const b = encode(s); return concatBytes(u32(b.length), b); }\nexport function decodeNep413Nonce(value: string): Uint8Array {\n responseAssert(typeof value === \"string\", \"Invalid NEP-413 nonce.\");\n const normalized = value.trim();\n let nonce: Uint8Array;\n try { nonce = base64.decode(normalized); }\n catch {\n const unpadded = normalized.replace(/=+$/, \"\");\n try { nonce = base64urlnopad.decode(unpadded); }\n catch {\n try { nonce = base64nopad.decode(unpadded); }\n catch { responseAssert(false, \"Invalid NEP-413 nonce encoding.\"); }\n }\n }\n responseAssert(nonce.length === 32, \"The NEP-413 nonce must be 32 bytes.\");\n return nonce;\n}\nexport function nep413Hash(payload: Extract<UnsignedData, { standard: \"nep413\" }>[\"payload\"]): Uint8Array {\n const nonce = decodeNep413Nonce(payload.nonce);\n return sha256(concatBytes(u32(2 ** 31 + 413), borshString(payload.message), nonce, borshString(payload.recipient), payload.callbackUrl === undefined ? new Uint8Array([0]) : concatBytes(new Uint8Array([1]), borshString(payload.callbackUrl))));\n}\nexport function personalMessageHash(message: string, kind: \"evm\" | \"tron\"): Uint8Array {\n const bytes = encode(message);\n return keccak_256(concatBytes(encode(`\\x19${kind === \"evm\" ? \"Ethereum\" : \"TRON\"} Signed Message:\\n${bytes.length}`), bytes));\n}\nexport function toSignatureBytes(value: unknown): Uint8Array {\n if (value instanceof Uint8Array) return value;\n if (value && typeof value === \"object\" && \"signature\" in value) {\n return toSignatureBytes((value as { signature: unknown }).signature);\n }\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n throw new Error(\"The wallet returned an invalid Ed25519 signature.\");\n}\nexport function decodeEd25519(value: string | Uint8Array, length: number): Uint8Array {\n if (value instanceof Uint8Array) { responseAssert(value.length === length, \"Invalid Ed25519 byte length.\"); return new Uint8Array(value); }\n const raw = value.replace(/^ed25519:/, \"\");\n for (const decoder of [() => base58.decode(raw), () => base64.decode(raw), () => base16.decode(raw.replace(/^0x/, \"\").toUpperCase())]) {\n try { const b = decoder(); if (b.length === length) return b; } catch { /* Wallets use base58, base64, or hex. */ }\n }\n responseAssert(false, \"Invalid Ed25519 encoding.\");\n}\nexport function normalizeSecpSignature(value: string): string {\n const hex = value.replace(/^0x/i, \"\");\n responseAssert(/^[0-9a-f]{130}$/i.test(hex), \"Expected a 65-byte signature.\");\n const bytes = base16.decode(hex.toUpperCase());\n const v = bytes[64]!;\n responseAssert([0, 1, 27, 28].includes(v), \"Invalid recovery id.\");\n bytes[64] = v < 27 ? v + 27 : v;\n return `0x${base16.encode(bytes).toLowerCase()}`;\n}\nexport function verifyWalletSignature(data: SignedData, identity: LinkingIdentity): void {\n let valid = false;\n try {\n if (identity.kind === \"near\" && data.standard === \"nep413\") {\n const key = decodeEd25519(identity.publicKey ?? \"\", 32);\n valid = ed25519.verify(decodeEd25519(data.signature, 64), nep413Hash(data.payload), key);\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) valid = valid && base16.encode(key).toLowerCase() === identity.accountId;\n } else if (identity.kind === \"solana\" && data.standard === \"raw_ed25519\") {\n valid = ed25519.verify(decodeEd25519(data.signature, 64), encode(data.payload), base58.decode(identity.accountId));\n } else if ((identity.kind === \"evm\" || identity.kind === \"tron\") && typeof data.payload === \"string\") {\n const bytes = base16.decode(normalizeSecpSignature(data.signature).slice(2).toUpperCase());\n const sig = secp256k1.Signature.fromCompact(bytes.slice(0, 64)).addRecoveryBit(bytes[64]! - 27);\n const publicKey = sig.recoverPublicKey(personalMessageHash(data.payload, identity.kind)).toRawBytes(false);\n const address = `0x${base16.encode(keccak_256(publicKey.slice(1)).slice(-20)).toLowerCase()}`;\n valid = address === deriveConfidentialAccountId(identity.kind, identity.accountId);\n }\n } catch { valid = false; }\n responseAssert(valid, \"Signature does not verify against the frozen wallet identity.\");\n}\n","import { base58, base64 } from \"@scure/base\";\nimport { assert, responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId, standards } from \"./identity\";\nimport { normalizeChain } from \"./routing\";\nimport { raw, text } from \"./utils\";\nimport { decodeNep413Nonce, verifyWalletSignature } from \"./signatures\";\nimport type { LinkingIdentity, QuoteResponse, SignedData, Token, UnsignedData } from \"./types\";\n\nconst evmChains = new Set([\"eth\", \"arb\", \"avax\", \"op\", \"pol\", \"bsc\", \"base\", \"gnosis\", \"aurora\", \"bera\", \"berachain\", \"monad\", \"hypercore\", \"hyperliquid\", \"linea\", \"scroll\", \"zksync\", \"mantle\", \"celo\", \"sonic\"]);\nexport type AddressValidator = (address: string, token: Token) => boolean;\nexport function validateRecipients(addresses: readonly string[], token: Token, custom?: AddressValidator): string[] {\n assert(addresses.length >= 1 && addresses.length <= 10, \"A batch requires 1 to 10 recipients.\");\n const chain = normalizeChain(token.blockchain);\n const evm = evmChains.has(chain) || /^\\d+$/.test(token.swapChain ?? chain);\n const seen = new Set<string>();\n return addresses.map((value) => {\n const address = text(value, \"Recipient address\");\n let valid = false;\n try {\n if (custom) valid = custom(address, token);\n else if (evm) valid = /^0x[0-9a-f]{40}$/i.test(address);\n else if (chain === \"near\") { deriveConfidentialAccountId(\"near\", address); valid = true; }\n else if (chain === \"sol\") valid = base58.decode(address).length === 32;\n else if (chain === \"tron\") { deriveConfidentialAccountId(\"tron\", address); valid = true; }\n else if (chain === \"aptos\") valid = /^0x[0-9a-f]{1,64}$/i.test(address);\n else if (chain === \"sui\") valid = /^0x[0-9a-f]{64}$/i.test(address);\n else assert(false, \"Supply an address validator for this destination chain (including BTC/Zcash).\");\n } catch (error) { if (!custom && !evm && ![\"near\", \"sol\", \"tron\", \"aptos\", \"sui\"].includes(chain)) throw error; }\n assert(valid, \"Invalid recipient address for the destination chain.\");\n const key = evm || [\"aptos\", \"sui\"].includes(chain) ? address.toLowerCase() : address;\n assert(!seen.has(key), \"Duplicate recipient address.\");\n seen.add(key);\n return address;\n });\n}\nexport function validateToken(token: Token): void {\n text(token.assetId, \"Asset id\"); text(token.blockchain, \"Blockchain\"); text(token.symbol, \"Symbol\");\n assert(Number.isInteger(token.decimals) && token.decimals >= 0 && token.decimals <= 255, \"Invalid token decimals.\");\n}\nexport function validateQuote(q: QuoteResponse, requireDeposit: boolean): void {\n responseAssert(q && typeof q.quote === \"object\" && q.quote, \"Missing quote.\");\n raw(q.quote.amountIn, \"Quoted input\"); raw(q.quote.amountOut, \"Quoted output\");\n if (q.quote.minAmountOut !== undefined) assert(raw(q.quote.minAmountOut) <= raw(q.quote.amountOut), \"Minimum output exceeds quoted output.\");\n if (q.quote.minAmountIn !== undefined) raw(q.quote.minAmountIn);\n if (q.quoteRequest?.appFees !== undefined) {\n raw(q.quoteRequest.amount, \"Quote request amount\");\n responseAssert(Array.isArray(q.quoteRequest.appFees), \"Invalid quote app fees.\");\n for (const fee of q.quoteRequest.appFees) {\n responseAssert(fee && Number.isInteger(fee.fee) && fee.fee >= 0, \"Invalid quote app fee rate.\");\n }\n }\n if (requireDeposit) text(q.quote.depositAddress, \"Deposit address\");\n}\nexport function payloadMessage(data: UnsignedData): Record<string, unknown> {\n let message: unknown;\n try { message = JSON.parse(typeof data.payload === \"string\" ? data.payload : data.payload.message); }\n catch { responseAssert(false, \"Invalid intent JSON.\"); }\n responseAssert(message && typeof message === \"object\" && !Array.isArray(message), \"Invalid intent payload.\");\n return message as Record<string, unknown>;\n}\nexport function validatePayload(data: UnsignedData, identity: LinkingIdentity, signerId: string, contract: string, now: number, purpose: \"authorization\" | \"withdrawal\" = \"authorization\"): Record<string, unknown> {\n responseAssert(data.standard === standards[identity.kind], \"Signing standard does not match wallet.\");\n const msg = payloadMessage(data);\n responseAssert(msg.signer_id === signerId, \"Intent signer does not match the frozen identity.\");\n const deadline = Date.parse(String(msg.deadline ?? \"\"));\n responseAssert(Number.isFinite(deadline) && deadline > now, \"Intent deadline expired or invalid.\");\n responseAssert(Array.isArray(msg.intents), \"Intent list is missing.\");\n if (data.standard === \"nep413\") {\n text(data.payload.recipient, \"NEP-413 recipient\");\n // Generated withdrawals carry their own signed recipient; only login binds the configured verifier.\n if (purpose === \"authorization\") responseAssert(data.payload.recipient === contract, \"Invalid NEP-413 authorization verifier.\");\n decodeNep413Nonce(data.payload.nonce);\n } else if (purpose === \"authorization\") {\n responseAssert(msg.verifying_contract === contract && typeof msg.nonce === \"string\" && base64.decode(msg.nonce).length === 32, \"Invalid verifier or nonce.\");\n }\n return msg;\n}\nexport function validateSigned(unsigned: UnsignedData, signed: SignedData, identity: LinkingIdentity): void {\n responseAssert(signed.standard === unsigned.standard && JSON.stringify(signed.payload) === JSON.stringify(unsigned.payload), \"Wallet changed the payload.\");\n text(signed.signature, \"Signature\");\n if (identity.kind === \"near\" || identity.kind === \"solana\") {\n const expected = identity.publicKey ?? (identity.kind === \"solana\" ? `ed25519:${identity.accountId}` : \"\");\n responseAssert(expected && signed.public_key === expected, \"Signing public key changed.\");\n }\n verifyWalletSignature(signed, identity);\n}\n"],"mappings":"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","names":["import_base","import_sha256","bytes","import_sha256","import_utils","import_base","raw","import_base"]}
@@ -1,4 +1,4 @@
1
- import { S as SigningAdapter, H as HttpConfidentialApi } from '../api-DuPBsPnx.cjs';
1
+ import { S as SigningAdapter, H as HttpConfidentialApi } from '../api-xFv7YgFM.cjs';
2
2
 
3
3
  interface EvmMessageSigner {
4
4
  getAddress(): Promise<string>;
@@ -1,4 +1,4 @@
1
- import { S as SigningAdapter, H as HttpConfidentialApi } from '../api-DuPBsPnx.js';
1
+ import { S as SigningAdapter, H as HttpConfidentialApi } from '../api-xFv7YgFM.js';
2
2
 
3
3
  interface EvmMessageSigner {
4
4
  getAddress(): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/index.ts","../../src/errors.ts","../../src/identity.ts","../../src/utils.ts","../../src/signatures.ts","../../src/validation.ts"],"sourcesContent":["import { base58 } from \"@scure/base\";\nimport { assert, ConfidentialSwapError, isUserRejectedError, responseAssert, throwIfAborted, userRejectedError } from \"../errors\";\nimport { sameLinking } from \"../identity\";\nimport { decodeEd25519, decodeNep413Nonce, normalizeSecpSignature, toSignatureBytes } from \"../signatures\";\nimport { clone } from \"../utils\";\nimport { validateSigned } from \"../validation\";\nimport type { HttpConfidentialApi } from \"../api\";\nimport type { LinkingIdentity, SignedData, SigningAdapter, UnsignedData } from \"../types\";\n\nexport interface EvmMessageSigner { getAddress(): Promise<string>; signMessage(message: string): Promise<string> }\nexport function createEvmSigningAdapter(getSigner: () => Promise<EvmMessageSigner> | EvmMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"evm\", accountId: await (await getSigner()).getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"erc191\", \"Expected ERC-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await (await getSigner()).signMessage(data.payload)) };\n },\n });\n}\nexport interface SolanaMessageSigner { publicKey: { toBase58(): string }; signMessage(message: Uint8Array): Promise<unknown> }\nexport function createSolanaSigningAdapter(getWallet: () => SolanaMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"solana\", accountId: getWallet().publicKey.toBase58(), publicKey: `ed25519:${getWallet().publicKey.toBase58()}` }),\n sign: async (data) => {\n assert(data.standard === \"raw_ed25519\", \"Expected raw Ed25519 payload.\");\n const wallet = getWallet();\n const signature = toSignatureBytes(await wallet.signMessage(new TextEncoder().encode(data.payload)));\n return { ...data, public_key: `ed25519:${wallet.publicKey.toBase58()}`, signature: `ed25519:${base58.encode(decodeEd25519(signature, 64))}` };\n },\n });\n}\nexport interface TronMessageSigner { getAddress(): Promise<string> | string; signMessageV2(message: string): Promise<string> }\nexport function createTronSigningAdapter(getWallet: () => TronMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"tron\", accountId: await getWallet().getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"tip191\", \"Expected TIP-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await getWallet().signMessageV2(data.payload)) };\n },\n });\n}\nexport interface NearMessageSigner {\n getIdentity(): Promise<{ accountId: string; publicKey: string }>;\n signMessage(params: { message: string; recipient: string; nonce: Uint8Array; callbackUrl?: string }): Promise<{ accountId: string; publicKey: string; signature: string }>;\n /** Explicit user-approved NEAR transaction: add_public_key on the configured Intents contract. */\n registerPublicKey?(accountId: string, publicKey: string, contract: string, signal?: AbortSignal): Promise<void>;\n}\nexport function createNearSigningAdapter(wallet: NearMessageSigner, api: Pick<HttpConfidentialApi, \"viewIntents\" | \"intentsContract\">): SigningAdapter {\n const getIdentity = async (): Promise<LinkingIdentity> => {\n const identity = await wallet.getIdentity();\n return { kind: \"near\", accountId: identity.accountId, publicKey: `ed25519:${base58.encode(decodeEd25519(identity.publicKey, 32))}` };\n };\n return createCheckedAdapter({\n getIdentity,\n prepare: async (signal) => {\n const identity = await getIdentity();\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) {\n const keyHex = Array.from(decodeEd25519(identity.publicKey!, 32), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n assert(keyHex === identity.accountId, \"Implicit NEAR account does not match its signing public key.\");\n } else {\n const registered = await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal);\n responseAssert(typeof registered === \"boolean\", \"Invalid key registration response.\");\n if (!registered) {\n assert(wallet.registerPublicKey, \"NEAR key registration requires an explicit registerPublicKey callback.\");\n throwIfAborted(signal);\n await wallet.registerPublicKey(identity.accountId, identity.publicKey!, api.intentsContract, signal);\n responseAssert(await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal) === true, \"NEAR signing key registration is not confirmed.\");\n }\n }\n },\n sign: async (data) => {\n assert(data.standard === \"nep413\", \"Expected NEP-413 payload.\");\n const result = await wallet.signMessage({ ...data.payload, nonce: decodeNep413Nonce(data.payload.nonce) });\n responseAssert(result.accountId === (await getIdentity()).accountId, \"NEAR wallet returned a different account.\");\n return { ...data, public_key: `ed25519:${base58.encode(decodeEd25519(result.publicKey, 32))}`, signature: `ed25519:${base58.encode(decodeEd25519(result.signature, 64))}` };\n },\n });\n}\nexport function createCheckedAdapter(adapter: SigningAdapter): SigningAdapter {\n return {\n getIdentity: () => adapter.getIdentity(),\n prepare: adapter.prepare?.bind(adapter),\n sign: async (data: UnsignedData, signal?: AbortSignal): Promise<SignedData> => {\n throwIfAborted(signal);\n const identity = await adapter.getIdentity();\n let signed: SignedData;\n try {\n signed = await adapter.sign(clone(data), signal);\n } catch (error) {\n if (isUserRejectedError(error)) throw userRejectedError();\n throw error;\n }\n throwIfAborted(signal);\n if (!sameLinking(identity, await adapter.getIdentity())) throw new ConfidentialSwapError(\"WALLET_CHANGED\", \"Wallet identity changed while signing.\");\n validateSigned(data, signed, identity);\n return signed;\n },\n };\n}\n","export type ErrorCode =\n | \"INVALID_INPUT\" | \"INVALID_RESPONSE\" | \"HTTP_ERROR\" | \"UNAUTHORIZED\"\n | \"WALLET_CHANGED\" | \"MISSING_WALLET\" | \"QUOTE_EXPIRED\" | \"BUSY\"\n | \"CONFIRMATION_REQUIRED\" | \"USER_REJECTED\" | \"TIMEOUT\" | \"ABORTED\" | \"TERMINAL_FAILURE\";\n\nexport class ConfidentialSwapError extends Error {\n readonly name = \"ConfidentialSwapError\";\n constructor(\n readonly code: ErrorCode,\n message: string,\n readonly status?: number,\n readonly executionId?: string,\n ) { super(message); }\n}\n\nexport function assert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_INPUT\", message);\n}\n\nexport function responseAssert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_RESPONSE\", message);\n}\n\nexport function isUserRejectedError(error: unknown): boolean {\n if (error instanceof ConfidentialSwapError) return error.code === \"USER_REJECTED\";\n if (!error || typeof error !== \"object\") return false;\n const value = error as { code?: unknown; message?: unknown; error?: unknown };\n const code = String(value.code ?? \"\").toUpperCase();\n const message = String(value.message ?? value.error ?? \"\");\n return (\n code === \"4001\" ||\n code === \"ACTION_REJECTED\" ||\n /user.*(reject|cancel|den(?:y|ied))|(?:reject|cancel|den(?:y|ied)).*user/i.test(message)\n );\n}\n\nexport function userRejectedError(executionId?: string): ConfidentialSwapError {\n return new ConfidentialSwapError(\n \"USER_REJECTED\",\n \"User rejected transaction.\",\n undefined,\n executionId,\n );\n}\n\nexport function throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted)\n throw new ConfidentialSwapError(\"ABORTED\", \"Trade cancelled.\");\n}\n","import { base16, base58, base58check } from \"@scure/base\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { assert } from \"./errors\";\nimport { text } from \"./utils\";\nimport type { FundingIdentity, LinkingIdentity, LinkingKind, SigningStandard } from \"./types\";\n\nexport const CONFIDENTIAL_LINKING_KINDS = [\"near\", \"evm\", \"solana\", \"tron\"] as const;\nexport const standards: Record<LinkingKind, SigningStandard> = { near: \"nep413\", evm: \"erc191\", solana: \"raw_ed25519\", tron: \"tip191\" };\nexport function deriveConfidentialAccountId(kind: LinkingKind, address: string): string {\n const account = text(address, \"Wallet account\");\n if (kind === \"near\") {\n assert(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(account) && account.length >= 2 && account.length <= 64, \"Invalid NEAR account.\");\n return account;\n }\n if (kind === \"evm\") { assert(/^0x[0-9a-f]{40}$/i.test(account), \"Invalid EVM address.\"); return account.toLowerCase(); }\n if (kind === \"solana\") {\n const bytes = base58.decode(account);\n assert(bytes.length === 32, \"Invalid Solana public key.\");\n return base16.encode(bytes).toLowerCase();\n }\n assert(kind === \"tron\", \"Unsupported linking wallet kind.\");\n const bytes = base58check(sha256).decode(account);\n assert(bytes.length === 21 && bytes[0] === 0x41, \"Invalid Tron address.\");\n return `0x${base16.encode(bytes.slice(1)).toLowerCase()}`;\n}\nexport function identityKey(identity: LinkingIdentity): string {\n // Session / linking identity is account-scoped — do not include publicKey.\n return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}`;\n}\nexport function sameLinking(a: LinkingIdentity, b: LinkingIdentity): boolean { return identityKey(a) === identityKey(b); }\nexport function sameFunding(a: FundingIdentity, b: FundingIdentity): boolean {\n return a.kind === b.kind && a.chain === b.chain && (a.kind === \"evm\" ? a.accountId.toLowerCase() === b.accountId.toLowerCase() : a.accountId === b.accountId);\n}\nexport function resolveLinkingWallet(input: { sourceKind?: string; wallets: readonly LinkingIdentity[]; preferred?: LinkingIdentity }): LinkingIdentity | null {\n const wallets = input.wallets.filter((w) => CONFIDENTIAL_LINKING_KINDS.includes(w.kind) && w.accountId.trim());\n if (input.preferred) return wallets.find((w) => sameLinking(w, input.preferred!)) ?? null;\n return wallets.find((w) => w.kind === input.sourceKind) ?? CONFIDENTIAL_LINKING_KINDS.map((kind) => wallets.find((w) => w.kind === kind)).find(Boolean) ?? null;\n}\n","import { sha256 } from \"@noble/hashes/sha256\";\nimport { bytesToHex } from \"@noble/hashes/utils\";\nimport { assert, throwIfAborted } from \"./errors\";\nimport type { Balance, QuotePlan } from \"./types\";\n\nexport function raw(value: unknown, field = \"Amount\", allowZero = false): bigint {\n assert(typeof value === \"string\" && /^(0|[1-9]\\d*)$/.test(value), `${field} must be a canonical integer string.`);\n const result = BigInt(value);\n assert(allowZero || result > 0n, `${field} must be positive.`);\n return result;\n}\n/** Rescale a raw integer between token decimals (floor when shrinking). */\nexport function rescaleRawAmount(amount: string, fromDecimals: number, toDecimals: number): string {\n assert(Number.isInteger(fromDecimals) && fromDecimals >= 0 && fromDecimals <= 255, \"Invalid source decimals.\");\n assert(Number.isInteger(toDecimals) && toDecimals >= 0 && toDecimals <= 255, \"Invalid target decimals.\");\n const value = raw(amount);\n if (fromDecimals === toDecimals) return value.toString();\n if (toDecimals > fromDecimals) {\n return (value * 10n ** BigInt(toDecimals - fromDecimals)).toString();\n }\n const scaled = value / 10n ** BigInt(fromDecimals - toDecimals);\n assert(scaled > 0n, \"Amount too small after decimal conversion.\");\n return scaled.toString();\n}\nexport function text(value: unknown, field: string): string {\n assert(typeof value === \"string\" && value.trim().length > 0, `${field} is required.`);\n return value.trim();\n}\nexport function clone<T>(value: T): T { return structuredClone(value); }\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value).filter(([, v]) => v !== undefined).sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${JSON.stringify(k)}:${canonical(v)}`).join(\",\")}}`;\n }\n assert(value === null || [\"string\", \"boolean\", \"number\"].includes(typeof value), \"Plan data must be JSON-serializable.\");\n if (typeof value === \"number\") assert(Number.isFinite(value), \"Plan numbers must be finite.\");\n return JSON.stringify(value);\n}\nexport function planDigest(plan: Omit<QuotePlan, \"digest\"> | QuotePlan): string {\n const { digest: _digest, ...body } = plan as QuotePlan;\n return bytesToHex(sha256(new TextEncoder().encode(canonical(body))));\n}\nexport function randomFraction(): number {\n return crypto.getRandomValues(new Uint32Array(1))[0]! / 0xffffffff;\n}\nexport function splitConfidentialRawAmount(totalRaw: string, count: number, values?: readonly number[]): string[] {\n assert(Number.isInteger(count) && count >= 1 && count <= 10, \"A batch requires 1 to 10 recipients.\");\n const total = raw(totalRaw);\n assert(total >= BigInt(count), \"Amount too small for every recipient.\");\n const minimum = total * 80n / (100n * BigInt(count));\n const lowBound = minimum > 0n ? minimum : 1n;\n const denominator = 100n * BigInt(count);\n const maximum = (total * 120n + denominator - 1n) / denominator;\n const highBound = maximum > lowBound ? maximum : lowBound;\n const shares: bigint[] = [];\n let remaining = total;\n for (let i = 0; i < count - 1; i++) {\n const left = BigInt(count - i - 1);\n const low = remaining - highBound * left > lowBound ? remaining - highBound * left : lowBound;\n const high = remaining - lowBound * left < highBound ? remaining - lowBound * left : highBound;\n assert(low <= high, \"Amount cannot be split safely.\");\n const fraction = values?.[i] ?? randomFraction();\n assert(Number.isFinite(fraction) && fraction >= 0 && fraction <= 1, \"Random fractions must be within [0, 1].\");\n const share = low + (high - low) * BigInt(Math.floor(fraction * 1_000_000)) / 1_000_000n;\n shares.push(share);\n remaining -= share;\n }\n assert(remaining >= lowBound && remaining <= highBound, \"Final share outside safe bounds.\");\n return [...shares, remaining].map(String);\n}\n/**\n * Quote / route assetIds (especially `1cs_v1:…`) may differ from the tokenId\n * returned by `/account/balances`. Native assets often settle as\n * `nep141:<symbol>.omft.near` (ZEC/BTC/XRP/SOL/…), not the per-chain 1cs id.\n */\nfunction balanceLookupIds(assetId: string, symbol?: string): string[] {\n const ids = [assetId];\n const near1cs = /^1cs_v1:near:(nep141:.+)$/i.exec(assetId);\n if (near1cs) ids.push(near1cs[1]!);\n const nep = /^(nep141:.+)$/i.exec(assetId);\n if (nep) ids.push(`1cs_v1:near:${nep[1]}`);\n const sym = symbol?.trim().toLowerCase();\n if (sym && /^[a-z0-9]+$/i.test(sym)) {\n const omft = `nep141:${sym}.omft.near`;\n ids.push(omft, `1cs_v1:near:${omft}`);\n }\n return [...new Set(ids)];\n}\n\nexport function availableForAsset(\n balances: readonly Balance[],\n assetId: string,\n symbol?: string,\n): string {\n for (const id of balanceLookupIds(assetId, symbol)) {\n const exact = balances.find((b) => b.tokenId === id);\n const entry =\n exact ??\n balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${id}`));\n if (entry) return raw(entry.available ?? \"0\", \"Available balance\", true).toString();\n }\n return \"0\";\n}\nexport async function delay(ms: number, signal?: AbortSignal): Promise<void> {\n throwIfAborted(signal);\n await new Promise<void>((resolve, reject) => {\n const finish = () => { signal?.removeEventListener(\"abort\", abort); resolve(); };\n const timer = setTimeout(finish, ms);\n const abort = () => { clearTimeout(timer); signal?.removeEventListener(\"abort\", abort); try { throwIfAborted(signal); } catch (e) { reject(e); } };\n signal?.addEventListener(\"abort\", abort, { once: true });\n });\n}\n","import { ed25519 } from \"@noble/curves/ed25519\";\nimport { secp256k1 } from \"@noble/curves/secp256k1\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport { concatBytes } from \"@noble/hashes/utils\";\nimport { base16, base58, base64, base64nopad, base64urlnopad } from \"@scure/base\";\nimport { responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId } from \"./identity\";\nimport type { LinkingIdentity, SignedData, UnsignedData } from \"./types\";\n\nconst encode = (s: string) => new TextEncoder().encode(s);\nfunction u32(value: number): Uint8Array { const b = new Uint8Array(4); new DataView(b.buffer).setUint32(0, value, true); return b; }\nfunction borshString(s: string): Uint8Array { const b = encode(s); return concatBytes(u32(b.length), b); }\nexport function decodeNep413Nonce(value: string): Uint8Array {\n responseAssert(typeof value === \"string\", \"Invalid NEP-413 nonce.\");\n const normalized = value.trim();\n let nonce: Uint8Array;\n try { nonce = base64.decode(normalized); }\n catch {\n const unpadded = normalized.replace(/=+$/, \"\");\n try { nonce = base64urlnopad.decode(unpadded); }\n catch {\n try { nonce = base64nopad.decode(unpadded); }\n catch { responseAssert(false, \"Invalid NEP-413 nonce encoding.\"); }\n }\n }\n responseAssert(nonce.length === 32, \"The NEP-413 nonce must be 32 bytes.\");\n return nonce;\n}\nexport function nep413Hash(payload: Extract<UnsignedData, { standard: \"nep413\" }>[\"payload\"]): Uint8Array {\n const nonce = decodeNep413Nonce(payload.nonce);\n return sha256(concatBytes(u32(2 ** 31 + 413), borshString(payload.message), nonce, borshString(payload.recipient), payload.callbackUrl === undefined ? new Uint8Array([0]) : concatBytes(new Uint8Array([1]), borshString(payload.callbackUrl))));\n}\nexport function personalMessageHash(message: string, kind: \"evm\" | \"tron\"): Uint8Array {\n const bytes = encode(message);\n return keccak_256(concatBytes(encode(`\\x19${kind === \"evm\" ? \"Ethereum\" : \"TRON\"} Signed Message:\\n${bytes.length}`), bytes));\n}\nexport function toSignatureBytes(value: unknown): Uint8Array {\n if (value instanceof Uint8Array) return value;\n if (value && typeof value === \"object\" && \"signature\" in value) {\n return toSignatureBytes((value as { signature: unknown }).signature);\n }\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n throw new Error(\"The wallet returned an invalid Ed25519 signature.\");\n}\nexport function decodeEd25519(value: string | Uint8Array, length: number): Uint8Array {\n if (value instanceof Uint8Array) { responseAssert(value.length === length, \"Invalid Ed25519 byte length.\"); return new Uint8Array(value); }\n const raw = value.replace(/^ed25519:/, \"\");\n for (const decoder of [() => base58.decode(raw), () => base64.decode(raw), () => base16.decode(raw.replace(/^0x/, \"\").toUpperCase())]) {\n try { const b = decoder(); if (b.length === length) return b; } catch { /* Wallets use base58, base64, or hex. */ }\n }\n responseAssert(false, \"Invalid Ed25519 encoding.\");\n}\nexport function normalizeSecpSignature(value: string): string {\n const hex = value.replace(/^0x/i, \"\");\n responseAssert(/^[0-9a-f]{130}$/i.test(hex), \"Expected a 65-byte signature.\");\n const bytes = base16.decode(hex.toUpperCase());\n const v = bytes[64]!;\n responseAssert([0, 1, 27, 28].includes(v), \"Invalid recovery id.\");\n bytes[64] = v < 27 ? v + 27 : v;\n return `0x${base16.encode(bytes).toLowerCase()}`;\n}\nexport function verifyWalletSignature(data: SignedData, identity: LinkingIdentity): void {\n let valid = false;\n try {\n if (identity.kind === \"near\" && data.standard === \"nep413\") {\n const key = decodeEd25519(identity.publicKey ?? \"\", 32);\n valid = ed25519.verify(decodeEd25519(data.signature, 64), nep413Hash(data.payload), key);\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) valid = valid && base16.encode(key).toLowerCase() === identity.accountId;\n } else if (identity.kind === \"solana\" && data.standard === \"raw_ed25519\") {\n valid = ed25519.verify(decodeEd25519(data.signature, 64), encode(data.payload), base58.decode(identity.accountId));\n } else if ((identity.kind === \"evm\" || identity.kind === \"tron\") && typeof data.payload === \"string\") {\n const bytes = base16.decode(normalizeSecpSignature(data.signature).slice(2).toUpperCase());\n const sig = secp256k1.Signature.fromCompact(bytes.slice(0, 64)).addRecoveryBit(bytes[64]! - 27);\n const publicKey = sig.recoverPublicKey(personalMessageHash(data.payload, identity.kind)).toRawBytes(false);\n const address = `0x${base16.encode(keccak_256(publicKey.slice(1)).slice(-20)).toLowerCase()}`;\n valid = address === deriveConfidentialAccountId(identity.kind, identity.accountId);\n }\n } catch { valid = false; }\n responseAssert(valid, \"Signature does not verify against the frozen wallet identity.\");\n}\n","import { base58, base64 } from \"@scure/base\";\nimport { assert, responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId, standards } from \"./identity\";\nimport { normalizeChain } from \"./routing\";\nimport { raw, text } from \"./utils\";\nimport { decodeNep413Nonce, verifyWalletSignature } from \"./signatures\";\nimport type { LinkingIdentity, QuoteResponse, SignedData, Token, UnsignedData } from \"./types\";\n\nconst evmChains = new Set([\"eth\", \"arb\", \"avax\", \"op\", \"pol\", \"bsc\", \"base\", \"gnosis\", \"aurora\", \"bera\", \"berachain\", \"monad\", \"hypercore\", \"hyperliquid\", \"linea\", \"scroll\", \"zksync\", \"mantle\", \"celo\", \"sonic\"]);\nexport type AddressValidator = (address: string, token: Token) => boolean;\nexport function validateRecipients(addresses: readonly string[], token: Token, custom?: AddressValidator): string[] {\n assert(addresses.length >= 1 && addresses.length <= 10, \"A batch requires 1 to 10 recipients.\");\n const chain = normalizeChain(token.blockchain);\n const evm = evmChains.has(chain) || /^\\d+$/.test(token.swapChain ?? chain);\n const seen = new Set<string>();\n return addresses.map((value) => {\n const address = text(value, \"Recipient address\");\n let valid = false;\n try {\n if (custom) valid = custom(address, token);\n else if (evm) valid = /^0x[0-9a-f]{40}$/i.test(address);\n else if (chain === \"near\") { deriveConfidentialAccountId(\"near\", address); valid = true; }\n else if (chain === \"sol\") valid = base58.decode(address).length === 32;\n else if (chain === \"tron\") { deriveConfidentialAccountId(\"tron\", address); valid = true; }\n else if (chain === \"aptos\") valid = /^0x[0-9a-f]{1,64}$/i.test(address);\n else if (chain === \"sui\") valid = /^0x[0-9a-f]{64}$/i.test(address);\n else assert(false, \"Supply an address validator for this destination chain (including BTC/Zcash).\");\n } catch (error) { if (!custom && !evm && ![\"near\", \"sol\", \"tron\", \"aptos\", \"sui\"].includes(chain)) throw error; }\n assert(valid, \"Invalid recipient address for the destination chain.\");\n const key = evm || [\"aptos\", \"sui\"].includes(chain) ? address.toLowerCase() : address;\n assert(!seen.has(key), \"Duplicate recipient address.\");\n seen.add(key);\n return address;\n });\n}\nexport function validateToken(token: Token): void {\n text(token.assetId, \"Asset id\"); text(token.blockchain, \"Blockchain\"); text(token.symbol, \"Symbol\");\n assert(Number.isInteger(token.decimals) && token.decimals >= 0 && token.decimals <= 255, \"Invalid token decimals.\");\n}\nexport function validateQuote(q: QuoteResponse, requireDeposit: boolean): void {\n responseAssert(q && typeof q.quote === \"object\" && q.quote, \"Missing quote.\");\n raw(q.quote.amountIn, \"Quoted input\"); raw(q.quote.amountOut, \"Quoted output\");\n if (q.quote.minAmountOut !== undefined) assert(raw(q.quote.minAmountOut) <= raw(q.quote.amountOut), \"Minimum output exceeds quoted output.\");\n if (q.quote.minAmountIn !== undefined) raw(q.quote.minAmountIn);\n if (q.quoteRequest?.appFees !== undefined) {\n raw(q.quoteRequest.amount, \"Quote request amount\");\n responseAssert(Array.isArray(q.quoteRequest.appFees), \"Invalid quote app fees.\");\n for (const fee of q.quoteRequest.appFees) {\n responseAssert(fee && Number.isInteger(fee.fee) && fee.fee >= 0, \"Invalid quote app fee rate.\");\n }\n }\n if (requireDeposit) text(q.quote.depositAddress, \"Deposit address\");\n}\nexport function payloadMessage(data: UnsignedData): Record<string, unknown> {\n let message: unknown;\n try { message = JSON.parse(typeof data.payload === \"string\" ? data.payload : data.payload.message); }\n catch { responseAssert(false, \"Invalid intent JSON.\"); }\n responseAssert(message && typeof message === \"object\" && !Array.isArray(message), \"Invalid intent payload.\");\n return message as Record<string, unknown>;\n}\nexport function validatePayload(data: UnsignedData, identity: LinkingIdentity, signerId: string, contract: string, now: number, purpose: \"authorization\" | \"withdrawal\" = \"authorization\"): Record<string, unknown> {\n responseAssert(data.standard === standards[identity.kind], \"Signing standard does not match wallet.\");\n const msg = payloadMessage(data);\n responseAssert(msg.signer_id === signerId, \"Intent signer does not match the frozen identity.\");\n const deadline = Date.parse(String(msg.deadline ?? \"\"));\n responseAssert(Number.isFinite(deadline) && deadline > now, \"Intent deadline expired or invalid.\");\n responseAssert(Array.isArray(msg.intents), \"Intent list is missing.\");\n if (data.standard === \"nep413\") {\n text(data.payload.recipient, \"NEP-413 recipient\");\n // Generated withdrawals carry their own signed recipient; only login binds the configured verifier.\n if (purpose === \"authorization\") responseAssert(data.payload.recipient === contract, \"Invalid NEP-413 authorization verifier.\");\n decodeNep413Nonce(data.payload.nonce);\n } else if (purpose === \"authorization\") {\n responseAssert(msg.verifying_contract === contract && typeof msg.nonce === \"string\" && base64.decode(msg.nonce).length === 32, \"Invalid verifier or nonce.\");\n }\n return msg;\n}\nexport function validateSigned(unsigned: UnsignedData, signed: SignedData, identity: LinkingIdentity): void {\n responseAssert(signed.standard === unsigned.standard && JSON.stringify(signed.payload) === JSON.stringify(unsigned.payload), \"Wallet changed the payload.\");\n text(signed.signature, \"Signature\");\n if (identity.kind === \"near\" || identity.kind === \"solana\") {\n const expected = identity.publicKey ?? (identity.kind === \"solana\" ? `ed25519:${identity.accountId}` : \"\");\n responseAssert(expected && signed.public_key === expected, \"Signing public key changed.\");\n }\n verifyWalletSignature(signed, identity);\n}\n"],"mappings":";AAAA,SAAS,UAAAA,eAAc;;;ACKhB,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAE/C,YACW,MACT,SACS,QACA,aACT;AAAE,UAAM,OAAO;AAJN;AAEA;AACA;AAAA,EACS;AAAA,EAJT;AAAA,EAEA;AAAA,EACA;AAAA,EALF,OAAO;AAOlB;AAEO,SAAS,OAAO,WAAoB,SAAoC;AAC7E,MAAI,CAAC,UAAW,OAAM,IAAI,sBAAsB,iBAAiB,OAAO;AAC1E;AAEO,SAAS,eAAe,WAAoB,SAAoC;AACrF,MAAI,CAAC,UAAW,OAAM,IAAI,sBAAsB,oBAAoB,OAAO;AAC7E;AAEO,SAAS,oBAAoB,OAAyB;AAC3D,MAAI,iBAAiB,sBAAuB,QAAO,MAAM,SAAS;AAClE,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,QAAQ;AACd,QAAM,OAAO,OAAO,MAAM,QAAQ,EAAE,EAAE,YAAY;AAClD,QAAM,UAAU,OAAO,MAAM,WAAW,MAAM,SAAS,EAAE;AACzD,SACE,SAAS,UACT,SAAS,qBACT,2EAA2E,KAAK,OAAO;AAE3F;AAEO,SAAS,kBAAkB,aAA6C;AAC7E,SAAO,IAAI;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,eAAe,QAA4B;AACzD,MAAI,QAAQ;AACV,UAAM,IAAI,sBAAsB,WAAW,kBAAkB;AACjE;;;AChDA,SAAS,QAAQ,QAAQ,mBAAmB;AAC5C,SAAS,UAAAC,eAAc;;;ACDvB,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAuBpB,SAAS,KAAK,OAAgB,OAAuB;AAC1D,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,GAAG,GAAG,KAAK,eAAe;AACpF,SAAO,MAAM,KAAK;AACpB;AACO,SAAS,MAAS,OAAa;AAAE,SAAO,gBAAgB,KAAK;AAAG;;;ADpBhE,SAAS,4BAA4B,MAAmB,SAAyB;AACtF,QAAM,UAAU,KAAK,SAAS,gBAAgB;AAC9C,MAAI,SAAS,QAAQ;AACnB,WAAO,iCAAiC,KAAK,OAAO,KAAK,QAAQ,UAAU,KAAK,QAAQ,UAAU,IAAI,uBAAuB;AAC7H,WAAO;AAAA,EACT;AACA,MAAI,SAAS,OAAO;AAAE,WAAO,oBAAoB,KAAK,OAAO,GAAG,sBAAsB;AAAG,WAAO,QAAQ,YAAY;AAAA,EAAG;AACvH,MAAI,SAAS,UAAU;AACrB,UAAMC,SAAQ,OAAO,OAAO,OAAO;AACnC,WAAOA,OAAM,WAAW,IAAI,4BAA4B;AACxD,WAAO,OAAO,OAAOA,MAAK,EAAE,YAAY;AAAA,EAC1C;AACA,SAAO,SAAS,QAAQ,kCAAkC;AAC1D,QAAM,QAAQ,YAAYC,OAAM,EAAE,OAAO,OAAO;AAChD,SAAO,MAAM,WAAW,MAAM,MAAM,CAAC,MAAM,IAAM,uBAAuB;AACxE,SAAO,KAAK,OAAO,OAAO,MAAM,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC;AACzD;AACO,SAAS,YAAY,UAAmC;AAE7D,SAAO,GAAG,SAAS,IAAI,IAAI,4BAA4B,SAAS,MAAM,SAAS,SAAS,CAAC;AAC3F;AACO,SAAS,YAAY,GAAoB,GAA6B;AAAE,SAAO,YAAY,CAAC,MAAM,YAAY,CAAC;AAAG;;;AE7BzH,SAAS,eAAe;AACxB,SAAS,iBAAiB;AAC1B,SAAS,UAAAC,eAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,UAAAC,SAAQ,UAAAC,SAAQ,QAAQ,aAAa,sBAAsB;AAKpE,IAAM,SAAS,CAAC,MAAc,IAAI,YAAY,EAAE,OAAO,CAAC;AACxD,SAAS,IAAI,OAA2B;AAAE,QAAM,IAAI,IAAI,WAAW,CAAC;AAAG,MAAI,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,IAAI;AAAG,SAAO;AAAG;AACnI,SAAS,YAAY,GAAuB;AAAE,QAAM,IAAI,OAAO,CAAC;AAAG,SAAO,YAAY,IAAI,EAAE,MAAM,GAAG,CAAC;AAAG;AAClG,SAAS,kBAAkB,OAA2B;AAC3D,iBAAe,OAAO,UAAU,UAAU,wBAAwB;AAClE,QAAM,aAAa,MAAM,KAAK;AAC9B,MAAI;AACJ,MAAI;AAAE,YAAQ,OAAO,OAAO,UAAU;AAAA,EAAG,QACnC;AACJ,UAAM,WAAW,WAAW,QAAQ,OAAO,EAAE;AAC7C,QAAI;AAAE,cAAQ,eAAe,OAAO,QAAQ;AAAA,IAAG,QACzC;AACJ,UAAI;AAAE,gBAAQ,YAAY,OAAO,QAAQ;AAAA,MAAG,QACtC;AAAE,uBAAe,OAAO,iCAAiC;AAAA,MAAG;AAAA,IACpE;AAAA,EACF;AACA,iBAAe,MAAM,WAAW,IAAI,qCAAqC;AACzE,SAAO;AACT;AACO,SAAS,WAAW,SAA+E;AACxG,QAAM,QAAQ,kBAAkB,QAAQ,KAAK;AAC7C,SAAOC,QAAO,YAAY,IAAI,KAAK,KAAK,GAAG,GAAG,YAAY,QAAQ,OAAO,GAAG,OAAO,YAAY,QAAQ,SAAS,GAAG,QAAQ,gBAAgB,SAAY,IAAI,WAAW,CAAC,CAAC,CAAC,IAAI,YAAY,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,QAAQ,WAAW,CAAC,CAAC,CAAC;AAClP;AACO,SAAS,oBAAoB,SAAiB,MAAkC;AACrF,QAAM,QAAQ,OAAO,OAAO;AAC5B,SAAO,WAAW,YAAY,OAAO,IAAO,SAAS,QAAQ,aAAa,MAAM;AAAA,EAAqB,MAAM,MAAM,EAAE,GAAG,KAAK,CAAC;AAC9H;AACO,SAAS,iBAAiB,OAA4B;AAC3D,MAAI,iBAAiB,WAAY,QAAO;AACxC,MAAI,SAAS,OAAO,UAAU,YAAY,eAAe,OAAO;AAC9D,WAAO,iBAAkB,MAAiC,SAAS;AAAA,EACrE;AACA,MAAI,YAAY,OAAO,KAAK,GAAG;AAC7B,WAAO,IAAI,WAAW,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU;AAAA,EACxE;AACA,QAAM,IAAI,MAAM,mDAAmD;AACrE;AACO,SAAS,cAAc,OAA4B,QAA4B;AACpF,MAAI,iBAAiB,YAAY;AAAE,mBAAe,MAAM,WAAW,QAAQ,8BAA8B;AAAG,WAAO,IAAI,WAAW,KAAK;AAAA,EAAG;AAC1I,QAAMC,OAAM,MAAM,QAAQ,aAAa,EAAE;AACzC,aAAW,WAAW,CAAC,MAAMC,QAAO,OAAOD,IAAG,GAAG,MAAM,OAAO,OAAOA,IAAG,GAAG,MAAME,QAAO,OAAOF,KAAI,QAAQ,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC,GAAG;AACrI,QAAI;AAAE,YAAM,IAAI,QAAQ;AAAG,UAAI,EAAE,WAAW,OAAQ,QAAO;AAAA,IAAG,QAAQ;AAAA,IAA4C;AAAA,EACpH;AACA,iBAAe,OAAO,2BAA2B;AACnD;AACO,SAAS,uBAAuB,OAAuB;AAC5D,QAAM,MAAM,MAAM,QAAQ,QAAQ,EAAE;AACpC,iBAAe,mBAAmB,KAAK,GAAG,GAAG,+BAA+B;AAC5E,QAAM,QAAQE,QAAO,OAAO,IAAI,YAAY,CAAC;AAC7C,QAAM,IAAI,MAAM,EAAE;AAClB,iBAAe,CAAC,GAAG,GAAG,IAAI,EAAE,EAAE,SAAS,CAAC,GAAG,sBAAsB;AACjE,QAAM,EAAE,IAAI,IAAI,KAAK,IAAI,KAAK;AAC9B,SAAO,KAAKA,QAAO,OAAO,KAAK,EAAE,YAAY,CAAC;AAChD;AACO,SAAS,sBAAsB,MAAkB,UAAiC;AACvF,MAAI,QAAQ;AACZ,MAAI;AACF,QAAI,SAAS,SAAS,UAAU,KAAK,aAAa,UAAU;AAC1D,YAAM,MAAM,cAAc,SAAS,aAAa,IAAI,EAAE;AACtD,cAAQ,QAAQ,OAAO,cAAc,KAAK,WAAW,EAAE,GAAG,WAAW,KAAK,OAAO,GAAG,GAAG;AACvF,UAAI,iBAAiB,KAAK,SAAS,SAAS,EAAG,SAAQ,SAASA,QAAO,OAAO,GAAG,EAAE,YAAY,MAAM,SAAS;AAAA,IAChH,WAAW,SAAS,SAAS,YAAY,KAAK,aAAa,eAAe;AACxE,cAAQ,QAAQ,OAAO,cAAc,KAAK,WAAW,EAAE,GAAG,OAAO,KAAK,OAAO,GAAGD,QAAO,OAAO,SAAS,SAAS,CAAC;AAAA,IACnH,YAAY,SAAS,SAAS,SAAS,SAAS,SAAS,WAAW,OAAO,KAAK,YAAY,UAAU;AACpG,YAAM,QAAQC,QAAO,OAAO,uBAAuB,KAAK,SAAS,EAAE,MAAM,CAAC,EAAE,YAAY,CAAC;AACzF,YAAM,MAAM,UAAU,UAAU,YAAY,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,eAAe,MAAM,EAAE,IAAK,EAAE;AAC9F,YAAM,YAAY,IAAI,iBAAiB,oBAAoB,KAAK,SAAS,SAAS,IAAI,CAAC,EAAE,WAAW,KAAK;AACzG,YAAM,UAAU,KAAKA,QAAO,OAAO,WAAW,UAAU,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,YAAY,CAAC;AAC3F,cAAQ,YAAY,4BAA4B,SAAS,MAAM,SAAS,SAAS;AAAA,IACnF;AAAA,EACF,QAAQ;AAAE,YAAQ;AAAA,EAAO;AACzB,iBAAe,OAAO,+DAA+D;AACvF;;;AClFA,SAAS,UAAAC,SAAQ,UAAAC,eAAc;AA6ExB,SAAS,eAAe,UAAwB,QAAoB,UAAiC;AAC1G,iBAAe,OAAO,aAAa,SAAS,YAAY,KAAK,UAAU,OAAO,OAAO,MAAM,KAAK,UAAU,SAAS,OAAO,GAAG,6BAA6B;AAC1J,OAAK,OAAO,WAAW,WAAW;AAClC,MAAI,SAAS,SAAS,UAAU,SAAS,SAAS,UAAU;AAC1D,UAAM,WAAW,SAAS,cAAc,SAAS,SAAS,WAAW,WAAW,SAAS,SAAS,KAAK;AACvG,mBAAe,YAAY,OAAO,eAAe,UAAU,6BAA6B;AAAA,EAC1F;AACA,wBAAsB,QAAQ,QAAQ;AACxC;;;AL3EO,SAAS,wBAAwB,WAA+E;AACrH,SAAO,qBAAqB;AAAA,IAC1B,aAAa,aAAa,EAAE,MAAM,OAAO,WAAW,OAAO,MAAM,UAAU,GAAG,WAAW,EAAE;AAAA,IAC3F,MAAM,OAAO,SAAS;AACpB,aAAO,KAAK,aAAa,UAAU,2BAA2B;AAC9D,aAAO,EAAE,GAAG,MAAM,WAAW,uBAAuB,OAAO,MAAM,UAAU,GAAG,YAAY,KAAK,OAAO,CAAC,EAAE;AAAA,IAC3G;AAAA,EACF,CAAC;AACH;AAEO,SAAS,2BAA2B,WAAsD;AAC/F,SAAO,qBAAqB;AAAA,IAC1B,aAAa,aAAa,EAAE,MAAM,UAAU,WAAW,UAAU,EAAE,UAAU,SAAS,GAAG,WAAW,WAAW,UAAU,EAAE,UAAU,SAAS,CAAC,GAAG;AAAA,IAClJ,MAAM,OAAO,SAAS;AACpB,aAAO,KAAK,aAAa,eAAe,+BAA+B;AACvE,YAAM,SAAS,UAAU;AACzB,YAAM,YAAY,iBAAiB,MAAM,OAAO,YAAY,IAAI,YAAY,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;AACnG,aAAO,EAAE,GAAG,MAAM,YAAY,WAAW,OAAO,UAAU,SAAS,CAAC,IAAI,WAAW,WAAWC,QAAO,OAAO,cAAc,WAAW,EAAE,CAAC,CAAC,GAAG;AAAA,IAC9I;AAAA,EACF,CAAC;AACH;AAEO,SAAS,yBAAyB,WAAoD;AAC3F,SAAO,qBAAqB;AAAA,IAC1B,aAAa,aAAa,EAAE,MAAM,QAAQ,WAAW,MAAM,UAAU,EAAE,WAAW,EAAE;AAAA,IACpF,MAAM,OAAO,SAAS;AACpB,aAAO,KAAK,aAAa,UAAU,2BAA2B;AAC9D,aAAO,EAAE,GAAG,MAAM,WAAW,uBAAuB,MAAM,UAAU,EAAE,cAAc,KAAK,OAAO,CAAC,EAAE;AAAA,IACrG;AAAA,EACF,CAAC;AACH;AAOO,SAAS,yBAAyB,QAA2B,KAAmF;AACrJ,QAAM,cAAc,YAAsC;AACxD,UAAM,WAAW,MAAM,OAAO,YAAY;AAC1C,WAAO,EAAE,MAAM,QAAQ,WAAW,SAAS,WAAW,WAAW,WAAWA,QAAO,OAAO,cAAc,SAAS,WAAW,EAAE,CAAC,CAAC,GAAG;AAAA,EACrI;AACA,SAAO,qBAAqB;AAAA,IAC1B;AAAA,IACA,SAAS,OAAO,WAAW;AACzB,YAAM,WAAW,MAAM,YAAY;AACnC,UAAI,iBAAiB,KAAK,SAAS,SAAS,GAAG;AAC7C,cAAM,SAAS,MAAM,KAAK,cAAc,SAAS,WAAY,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AACjH,eAAO,WAAW,SAAS,WAAW,8DAA8D;AAAA,MACtG,OAAO;AACL,cAAM,aAAa,MAAM,IAAI,YAAqB,kBAAkB,EAAE,YAAY,SAAS,WAAW,YAAY,SAAS,UAAU,GAAG,MAAM;AAC9I,uBAAe,OAAO,eAAe,WAAW,oCAAoC;AACpF,YAAI,CAAC,YAAY;AACf,iBAAO,OAAO,mBAAmB,wEAAwE;AACzG,yBAAe,MAAM;AACrB,gBAAM,OAAO,kBAAkB,SAAS,WAAW,SAAS,WAAY,IAAI,iBAAiB,MAAM;AACnG,yBAAe,MAAM,IAAI,YAAqB,kBAAkB,EAAE,YAAY,SAAS,WAAW,YAAY,SAAS,UAAU,GAAG,MAAM,MAAM,MAAM,iDAAiD;AAAA,QACzM;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO,SAAS;AACpB,aAAO,KAAK,aAAa,UAAU,2BAA2B;AAC9D,YAAM,SAAS,MAAM,OAAO,YAAY,EAAE,GAAG,KAAK,SAAS,OAAO,kBAAkB,KAAK,QAAQ,KAAK,EAAE,CAAC;AACzG,qBAAe,OAAO,eAAe,MAAM,YAAY,GAAG,WAAW,2CAA2C;AAChH,aAAO,EAAE,GAAG,MAAM,YAAY,WAAWA,QAAO,OAAO,cAAc,OAAO,WAAW,EAAE,CAAC,CAAC,IAAI,WAAW,WAAWA,QAAO,OAAO,cAAc,OAAO,WAAW,EAAE,CAAC,CAAC,GAAG;AAAA,IAC5K;AAAA,EACF,CAAC;AACH;AACO,SAAS,qBAAqB,SAAyC;AAC5E,SAAO;AAAA,IACL,aAAa,MAAM,QAAQ,YAAY;AAAA,IACvC,SAAS,QAAQ,SAAS,KAAK,OAAO;AAAA,IACtC,MAAM,OAAO,MAAoB,WAA8C;AAC7E,qBAAe,MAAM;AACrB,YAAM,WAAW,MAAM,QAAQ,YAAY;AAC3C,UAAI;AACJ,UAAI;AACF,iBAAS,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG,MAAM;AAAA,MACjD,SAAS,OAAO;AACd,YAAI,oBAAoB,KAAK,EAAG,OAAM,kBAAkB;AACxD,cAAM;AAAA,MACR;AACA,qBAAe,MAAM;AACrB,UAAI,CAAC,YAAY,UAAU,MAAM,QAAQ,YAAY,CAAC,EAAG,OAAM,IAAI,sBAAsB,kBAAkB,wCAAwC;AACnJ,qBAAe,MAAM,QAAQ,QAAQ;AACrC,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":["base58","sha256","bytes","sha256","sha256","base16","base58","sha256","raw","base58","base16","base58","base64","base58"]}
1
+ {"version":3,"sources":["../../src/adapters/index.ts","../../src/errors.ts","../../src/identity.ts","../../src/utils.ts","../../src/signatures.ts","../../src/validation.ts"],"sourcesContent":["import { base58 } from \"@scure/base\";\nimport { assert, ConfidentialSwapError, isUserRejectedError, responseAssert, throwIfAborted, userRejectedError } from \"../errors\";\nimport { sameLinking } from \"../identity\";\nimport { decodeEd25519, decodeNep413Nonce, normalizeSecpSignature, toSignatureBytes } from \"../signatures\";\nimport { clone } from \"../utils\";\nimport { validateSigned } from \"../validation\";\nimport type { HttpConfidentialApi } from \"../api\";\nimport type { LinkingIdentity, SignedData, SigningAdapter, UnsignedData } from \"../types\";\n\nexport interface EvmMessageSigner { getAddress(): Promise<string>; signMessage(message: string): Promise<string> }\nexport function createEvmSigningAdapter(getSigner: () => Promise<EvmMessageSigner> | EvmMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"evm\", accountId: await (await getSigner()).getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"erc191\", \"Expected ERC-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await (await getSigner()).signMessage(data.payload)) };\n },\n });\n}\nexport interface SolanaMessageSigner { publicKey: { toBase58(): string }; signMessage(message: Uint8Array): Promise<unknown> }\nexport function createSolanaSigningAdapter(getWallet: () => SolanaMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"solana\", accountId: getWallet().publicKey.toBase58(), publicKey: `ed25519:${getWallet().publicKey.toBase58()}` }),\n sign: async (data) => {\n assert(data.standard === \"raw_ed25519\", \"Expected raw Ed25519 payload.\");\n const wallet = getWallet();\n const signature = toSignatureBytes(await wallet.signMessage(new TextEncoder().encode(data.payload)));\n return { ...data, public_key: `ed25519:${wallet.publicKey.toBase58()}`, signature: `ed25519:${base58.encode(decodeEd25519(signature, 64))}` };\n },\n });\n}\nexport interface TronMessageSigner { getAddress(): Promise<string> | string; signMessageV2(message: string): Promise<string> }\nexport function createTronSigningAdapter(getWallet: () => TronMessageSigner): SigningAdapter {\n return createCheckedAdapter({\n getIdentity: async () => ({ kind: \"tron\", accountId: await getWallet().getAddress() }),\n sign: async (data) => {\n assert(data.standard === \"tip191\", \"Expected TIP-191 payload.\");\n return { ...data, signature: normalizeSecpSignature(await getWallet().signMessageV2(data.payload)) };\n },\n });\n}\nexport interface NearMessageSigner {\n getIdentity(): Promise<{ accountId: string; publicKey: string }>;\n signMessage(params: { message: string; recipient: string; nonce: Uint8Array; callbackUrl?: string }): Promise<{ accountId: string; publicKey: string; signature: string }>;\n /** Explicit user-approved NEAR transaction: add_public_key on the configured Intents contract. */\n registerPublicKey?(accountId: string, publicKey: string, contract: string, signal?: AbortSignal): Promise<void>;\n}\nexport function createNearSigningAdapter(wallet: NearMessageSigner, api: Pick<HttpConfidentialApi, \"viewIntents\" | \"intentsContract\">): SigningAdapter {\n const getIdentity = async (): Promise<LinkingIdentity> => {\n const identity = await wallet.getIdentity();\n return { kind: \"near\", accountId: identity.accountId, publicKey: `ed25519:${base58.encode(decodeEd25519(identity.publicKey, 32))}` };\n };\n return createCheckedAdapter({\n getIdentity,\n prepare: async (signal) => {\n const identity = await getIdentity();\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) {\n const keyHex = Array.from(decodeEd25519(identity.publicKey!, 32), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n assert(keyHex === identity.accountId, \"Implicit NEAR account does not match its signing public key.\");\n } else {\n const registered = await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal);\n responseAssert(typeof registered === \"boolean\", \"Invalid key registration response.\");\n if (!registered) {\n assert(wallet.registerPublicKey, \"NEAR key registration requires an explicit registerPublicKey callback.\");\n throwIfAborted(signal);\n await wallet.registerPublicKey(identity.accountId, identity.publicKey!, api.intentsContract, signal);\n responseAssert(await api.viewIntents<boolean>(\"has_public_key\", { account_id: identity.accountId, public_key: identity.publicKey }, signal) === true, \"NEAR signing key registration is not confirmed.\");\n }\n }\n },\n sign: async (data) => {\n assert(data.standard === \"nep413\", \"Expected NEP-413 payload.\");\n const result = await wallet.signMessage({ ...data.payload, nonce: decodeNep413Nonce(data.payload.nonce) });\n responseAssert(result.accountId === (await getIdentity()).accountId, \"NEAR wallet returned a different account.\");\n return { ...data, public_key: `ed25519:${base58.encode(decodeEd25519(result.publicKey, 32))}`, signature: `ed25519:${base58.encode(decodeEd25519(result.signature, 64))}` };\n },\n });\n}\nexport function createCheckedAdapter(adapter: SigningAdapter): SigningAdapter {\n return {\n getIdentity: () => adapter.getIdentity(),\n prepare: adapter.prepare?.bind(adapter),\n sign: async (data: UnsignedData, signal?: AbortSignal): Promise<SignedData> => {\n throwIfAborted(signal);\n const identity = await adapter.getIdentity();\n let signed: SignedData;\n try {\n signed = await adapter.sign(clone(data), signal);\n } catch (error) {\n if (isUserRejectedError(error)) throw userRejectedError();\n throw error;\n }\n throwIfAborted(signal);\n if (!sameLinking(identity, await adapter.getIdentity())) throw new ConfidentialSwapError(\"WALLET_CHANGED\", \"Wallet identity changed while signing.\");\n validateSigned(data, signed, identity);\n return signed;\n },\n };\n}\n","export type ErrorCode =\n | \"INVALID_INPUT\" | \"INVALID_RESPONSE\" | \"HTTP_ERROR\" | \"UNAUTHORIZED\"\n | \"WALLET_CHANGED\" | \"MISSING_WALLET\" | \"QUOTE_EXPIRED\" | \"BUSY\"\n | \"CONFIRMATION_REQUIRED\" | \"USER_REJECTED\" | \"TIMEOUT\" | \"ABORTED\" | \"TERMINAL_FAILURE\";\n\nexport class ConfidentialSwapError extends Error {\n readonly name = \"ConfidentialSwapError\";\n constructor(\n readonly code: ErrorCode,\n message: string,\n readonly status?: number,\n readonly executionId?: string,\n ) { super(message); }\n}\n\nexport function assert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_INPUT\", message);\n}\n\nexport function responseAssert(condition: unknown, message: string): asserts condition {\n if (!condition) throw new ConfidentialSwapError(\"INVALID_RESPONSE\", message);\n}\n\nexport function isUserRejectedError(error: unknown): boolean {\n if (error instanceof ConfidentialSwapError) return error.code === \"USER_REJECTED\";\n if (!error || typeof error !== \"object\") return false;\n const value = error as { code?: unknown; message?: unknown; error?: unknown };\n const code = String(value.code ?? \"\").toUpperCase();\n const message = String(value.message ?? value.error ?? \"\");\n return (\n code === \"4001\" ||\n code === \"ACTION_REJECTED\" ||\n /user.*(reject|cancel|den(?:y|ied))|(?:reject|cancel|den(?:y|ied)).*user/i.test(message)\n );\n}\n\nexport function userRejectedError(executionId?: string): ConfidentialSwapError {\n return new ConfidentialSwapError(\n \"USER_REJECTED\",\n \"User rejected transaction.\",\n undefined,\n executionId,\n );\n}\n\nexport function throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted)\n throw new ConfidentialSwapError(\"ABORTED\", \"Trade cancelled.\");\n}\n","import { base16, base58, base58check } from \"@scure/base\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { assert } from \"./errors\";\nimport { text } from \"./utils\";\nimport type { FundingIdentity, LinkingIdentity, LinkingKind, SigningStandard } from \"./types\";\n\nexport const CONFIDENTIAL_LINKING_KINDS = [\"near\", \"evm\", \"solana\", \"tron\"] as const;\nexport const standards: Record<LinkingKind, SigningStandard> = { near: \"nep413\", evm: \"erc191\", solana: \"raw_ed25519\", tron: \"tip191\" };\nexport function deriveConfidentialAccountId(kind: LinkingKind, address: string): string {\n const account = text(address, \"Wallet account\");\n if (kind === \"near\") {\n assert(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(account) && account.length >= 2 && account.length <= 64, \"Invalid NEAR account.\");\n return account;\n }\n if (kind === \"evm\") { assert(/^0x[0-9a-f]{40}$/i.test(account), \"Invalid EVM address.\"); return account.toLowerCase(); }\n if (kind === \"solana\") {\n const bytes = base58.decode(account);\n assert(bytes.length === 32, \"Invalid Solana public key.\");\n return base16.encode(bytes).toLowerCase();\n }\n assert(kind === \"tron\", \"Unsupported linking wallet kind.\");\n const bytes = base58check(sha256).decode(account);\n assert(bytes.length === 21 && bytes[0] === 0x41, \"Invalid Tron address.\");\n return `0x${base16.encode(bytes.slice(1)).toLowerCase()}`;\n}\nexport function identityKey(identity: LinkingIdentity): string {\n // Session / linking identity is account-scoped — do not include publicKey.\n return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}`;\n}\nexport function sameLinking(a: LinkingIdentity, b: LinkingIdentity): boolean { return identityKey(a) === identityKey(b); }\nexport function sameFunding(a: FundingIdentity, b: FundingIdentity): boolean {\n return a.kind === b.kind && a.chain === b.chain && (a.kind === \"evm\" ? a.accountId.toLowerCase() === b.accountId.toLowerCase() : a.accountId === b.accountId);\n}\nexport function resolveLinkingWallet(input: { sourceKind?: string; wallets: readonly LinkingIdentity[]; preferred?: LinkingIdentity }): LinkingIdentity | null {\n const wallets = input.wallets.filter((w) => CONFIDENTIAL_LINKING_KINDS.includes(w.kind) && w.accountId.trim());\n if (input.preferred) return wallets.find((w) => sameLinking(w, input.preferred!)) ?? null;\n return wallets.find((w) => w.kind === input.sourceKind) ?? CONFIDENTIAL_LINKING_KINDS.map((kind) => wallets.find((w) => w.kind === kind)).find(Boolean) ?? null;\n}\n","import { sha256 } from \"@noble/hashes/sha256\";\nimport { bytesToHex } from \"@noble/hashes/utils\";\nimport { assert, throwIfAborted } from \"./errors\";\nimport type { Balance, BalanceSnapshotEntry, QuotePlan } from \"./types\";\n\nexport function raw(value: unknown, field = \"Amount\", allowZero = false): bigint {\n assert(typeof value === \"string\" && /^(0|[1-9]\\d*)$/.test(value), `${field} must be a canonical integer string.`);\n const result = BigInt(value);\n assert(allowZero || result > 0n, `${field} must be positive.`);\n return result;\n}\n/** Rescale a raw integer between token decimals (floor when shrinking). */\nexport function rescaleRawAmount(amount: string, fromDecimals: number, toDecimals: number): string {\n assert(Number.isInteger(fromDecimals) && fromDecimals >= 0 && fromDecimals <= 255, \"Invalid source decimals.\");\n assert(Number.isInteger(toDecimals) && toDecimals >= 0 && toDecimals <= 255, \"Invalid target decimals.\");\n const value = raw(amount);\n if (fromDecimals === toDecimals) return value.toString();\n if (toDecimals > fromDecimals) {\n return (value * 10n ** BigInt(toDecimals - fromDecimals)).toString();\n }\n const scaled = value / 10n ** BigInt(fromDecimals - toDecimals);\n assert(scaled > 0n, \"Amount too small after decimal conversion.\");\n return scaled.toString();\n}\nexport function text(value: unknown, field: string): string {\n assert(typeof value === \"string\" && value.trim().length > 0, `${field} is required.`);\n return value.trim();\n}\nexport function clone<T>(value: T): T { return structuredClone(value); }\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value).filter(([, v]) => v !== undefined).sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${JSON.stringify(k)}:${canonical(v)}`).join(\",\")}}`;\n }\n assert(value === null || [\"string\", \"boolean\", \"number\"].includes(typeof value), \"Plan data must be JSON-serializable.\");\n if (typeof value === \"number\") assert(Number.isFinite(value), \"Plan numbers must be finite.\");\n return JSON.stringify(value);\n}\nexport function planDigest(plan: Omit<QuotePlan, \"digest\"> | QuotePlan): string {\n const { digest: _digest, ...body } = plan as QuotePlan;\n return bytesToHex(sha256(new TextEncoder().encode(canonical(body))));\n}\nexport function randomFraction(): number {\n return crypto.getRandomValues(new Uint32Array(1))[0]! / 0xffffffff;\n}\nexport function splitConfidentialRawAmount(totalRaw: string, count: number, values?: readonly number[]): string[] {\n assert(Number.isInteger(count) && count >= 1 && count <= 10, \"A batch requires 1 to 10 recipients.\");\n const total = raw(totalRaw);\n assert(total >= BigInt(count), \"Amount too small for every recipient.\");\n const minimum = total * 80n / (100n * BigInt(count));\n const lowBound = minimum > 0n ? minimum : 1n;\n const denominator = 100n * BigInt(count);\n const maximum = (total * 120n + denominator - 1n) / denominator;\n const highBound = maximum > lowBound ? maximum : lowBound;\n const shares: bigint[] = [];\n let remaining = total;\n for (let i = 0; i < count - 1; i++) {\n const left = BigInt(count - i - 1);\n const low = remaining - highBound * left > lowBound ? remaining - highBound * left : lowBound;\n const high = remaining - lowBound * left < highBound ? remaining - lowBound * left : highBound;\n assert(low <= high, \"Amount cannot be split safely.\");\n const fraction = values?.[i] ?? randomFraction();\n assert(Number.isFinite(fraction) && fraction >= 0 && fraction <= 1, \"Random fractions must be within [0, 1].\");\n const share = low + (high - low) * BigInt(Math.floor(fraction * 1_000_000)) / 1_000_000n;\n shares.push(share);\n remaining -= share;\n }\n assert(remaining >= lowBound && remaining <= highBound, \"Final share outside safe bounds.\");\n return [...shares, remaining].map(String);\n}\n/**\n * Quote / route assetIds (especially `1cs_v1:…`) may differ from the tokenId\n * returned by `/account/balances`. Native assets often settle as\n * `nep141:<symbol>.omft.near` (ZEC/BTC/XRP/SOL/…), not the per-chain 1cs id.\n */\nfunction balanceLookupIds(assetId: string, symbol?: string): string[] {\n const ids = [assetId];\n const near1cs = /^1cs_v1:near:(nep141:.+)$/i.exec(assetId);\n if (near1cs) ids.push(near1cs[1]!);\n const nep = /^(nep141:.+)$/i.exec(assetId);\n if (nep) ids.push(`1cs_v1:near:${nep[1]}`);\n const sym = symbol?.trim().toLowerCase();\n if (sym && /^[a-z0-9]+$/i.test(sym)) {\n const omft = `nep141:${sym}.omft.near`;\n ids.push(omft, `1cs_v1:near:${omft}`);\n }\n return [...new Set(ids)];\n}\n\nexport function availableForAsset(\n balances: readonly Balance[],\n assetId: string,\n symbol?: string,\n): string {\n for (const id of balanceLookupIds(assetId, symbol)) {\n const exact = balances.find((b) => b.tokenId === id);\n const entry =\n exact ??\n balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${id}`));\n if (entry) return raw(entry.available ?? \"0\", \"Available balance\", true).toString();\n }\n return \"0\";\n}\n\n/** Strip `imt:<account>:` so the same asset compares across API shapes. */\nexport function balanceCanonicalKey(tokenId: string): string {\n const imt = /^imt:[^:]+:(.+)$/.exec(tokenId);\n return imt?.[1] ?? tokenId;\n}\n\nexport function snapshotBalances(balances: readonly Balance[]): BalanceSnapshotEntry[] {\n return balances.map((b) => ({\n tokenId: b.tokenId,\n available: raw(b.available ?? \"0\", \"Available balance\", true).toString(),\n }));\n}\n\nexport interface CreditedBalanceChange {\n tokenId: string;\n baseline: string;\n available: string;\n delta: string;\n}\n\n/**\n * Find which account token increased by at least `credited` vs the baseline snapshot.\n * Prefers an exact delta match, then the largest qualifying increase.\n */\nexport function findCreditedBalanceChange(\n baseline: readonly BalanceSnapshotEntry[] | undefined,\n current: readonly Balance[],\n credited: string,\n): CreditedBalanceChange | null {\n const creditedBn = raw(credited);\n if (creditedBn <= 0n) return null;\n\n const baseByKey = new Map<string, bigint>();\n for (const row of baseline ?? []) {\n const key = balanceCanonicalKey(row.tokenId);\n const amount = raw(row.available, \"Baseline\", true);\n const prev = baseByKey.get(key);\n if (prev === undefined || amount > prev) baseByKey.set(key, amount);\n }\n\n const increases: CreditedBalanceChange[] = [];\n const seen = new Set<string>();\n for (const row of current) {\n const key = balanceCanonicalKey(row.tokenId);\n if (seen.has(key)) continue;\n seen.add(key);\n const availableBn = raw(row.available ?? \"0\", \"Available\", true);\n const baselineBn = baseByKey.get(key) ?? 0n;\n const delta = availableBn - baselineBn;\n if (delta >= creditedBn) {\n increases.push({\n tokenId: row.tokenId.startsWith(\"imt:\") ? key : row.tokenId,\n baseline: baselineBn.toString(),\n available: availableBn.toString(),\n delta: delta.toString(),\n });\n }\n }\n if (increases.length === 0) return null;\n const exact = increases.find((row) => row.delta === credited);\n if (exact) return exact;\n return increases.reduce((best, row) =>\n BigInt(row.delta) > BigInt(best.delta) ? row : best,\n );\n}\nexport async function delay(ms: number, signal?: AbortSignal): Promise<void> {\n throwIfAborted(signal);\n await new Promise<void>((resolve, reject) => {\n const finish = () => { signal?.removeEventListener(\"abort\", abort); resolve(); };\n const timer = setTimeout(finish, ms);\n const abort = () => { clearTimeout(timer); signal?.removeEventListener(\"abort\", abort); try { throwIfAborted(signal); } catch (e) { reject(e); } };\n signal?.addEventListener(\"abort\", abort, { once: true });\n });\n}\n","import { ed25519 } from \"@noble/curves/ed25519\";\nimport { secp256k1 } from \"@noble/curves/secp256k1\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport { concatBytes } from \"@noble/hashes/utils\";\nimport { base16, base58, base64, base64nopad, base64urlnopad } from \"@scure/base\";\nimport { responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId } from \"./identity\";\nimport type { LinkingIdentity, SignedData, UnsignedData } from \"./types\";\n\nconst encode = (s: string) => new TextEncoder().encode(s);\nfunction u32(value: number): Uint8Array { const b = new Uint8Array(4); new DataView(b.buffer).setUint32(0, value, true); return b; }\nfunction borshString(s: string): Uint8Array { const b = encode(s); return concatBytes(u32(b.length), b); }\nexport function decodeNep413Nonce(value: string): Uint8Array {\n responseAssert(typeof value === \"string\", \"Invalid NEP-413 nonce.\");\n const normalized = value.trim();\n let nonce: Uint8Array;\n try { nonce = base64.decode(normalized); }\n catch {\n const unpadded = normalized.replace(/=+$/, \"\");\n try { nonce = base64urlnopad.decode(unpadded); }\n catch {\n try { nonce = base64nopad.decode(unpadded); }\n catch { responseAssert(false, \"Invalid NEP-413 nonce encoding.\"); }\n }\n }\n responseAssert(nonce.length === 32, \"The NEP-413 nonce must be 32 bytes.\");\n return nonce;\n}\nexport function nep413Hash(payload: Extract<UnsignedData, { standard: \"nep413\" }>[\"payload\"]): Uint8Array {\n const nonce = decodeNep413Nonce(payload.nonce);\n return sha256(concatBytes(u32(2 ** 31 + 413), borshString(payload.message), nonce, borshString(payload.recipient), payload.callbackUrl === undefined ? new Uint8Array([0]) : concatBytes(new Uint8Array([1]), borshString(payload.callbackUrl))));\n}\nexport function personalMessageHash(message: string, kind: \"evm\" | \"tron\"): Uint8Array {\n const bytes = encode(message);\n return keccak_256(concatBytes(encode(`\\x19${kind === \"evm\" ? \"Ethereum\" : \"TRON\"} Signed Message:\\n${bytes.length}`), bytes));\n}\nexport function toSignatureBytes(value: unknown): Uint8Array {\n if (value instanceof Uint8Array) return value;\n if (value && typeof value === \"object\" && \"signature\" in value) {\n return toSignatureBytes((value as { signature: unknown }).signature);\n }\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n throw new Error(\"The wallet returned an invalid Ed25519 signature.\");\n}\nexport function decodeEd25519(value: string | Uint8Array, length: number): Uint8Array {\n if (value instanceof Uint8Array) { responseAssert(value.length === length, \"Invalid Ed25519 byte length.\"); return new Uint8Array(value); }\n const raw = value.replace(/^ed25519:/, \"\");\n for (const decoder of [() => base58.decode(raw), () => base64.decode(raw), () => base16.decode(raw.replace(/^0x/, \"\").toUpperCase())]) {\n try { const b = decoder(); if (b.length === length) return b; } catch { /* Wallets use base58, base64, or hex. */ }\n }\n responseAssert(false, \"Invalid Ed25519 encoding.\");\n}\nexport function normalizeSecpSignature(value: string): string {\n const hex = value.replace(/^0x/i, \"\");\n responseAssert(/^[0-9a-f]{130}$/i.test(hex), \"Expected a 65-byte signature.\");\n const bytes = base16.decode(hex.toUpperCase());\n const v = bytes[64]!;\n responseAssert([0, 1, 27, 28].includes(v), \"Invalid recovery id.\");\n bytes[64] = v < 27 ? v + 27 : v;\n return `0x${base16.encode(bytes).toLowerCase()}`;\n}\nexport function verifyWalletSignature(data: SignedData, identity: LinkingIdentity): void {\n let valid = false;\n try {\n if (identity.kind === \"near\" && data.standard === \"nep413\") {\n const key = decodeEd25519(identity.publicKey ?? \"\", 32);\n valid = ed25519.verify(decodeEd25519(data.signature, 64), nep413Hash(data.payload), key);\n if (/^[0-9a-f]{64}$/.test(identity.accountId)) valid = valid && base16.encode(key).toLowerCase() === identity.accountId;\n } else if (identity.kind === \"solana\" && data.standard === \"raw_ed25519\") {\n valid = ed25519.verify(decodeEd25519(data.signature, 64), encode(data.payload), base58.decode(identity.accountId));\n } else if ((identity.kind === \"evm\" || identity.kind === \"tron\") && typeof data.payload === \"string\") {\n const bytes = base16.decode(normalizeSecpSignature(data.signature).slice(2).toUpperCase());\n const sig = secp256k1.Signature.fromCompact(bytes.slice(0, 64)).addRecoveryBit(bytes[64]! - 27);\n const publicKey = sig.recoverPublicKey(personalMessageHash(data.payload, identity.kind)).toRawBytes(false);\n const address = `0x${base16.encode(keccak_256(publicKey.slice(1)).slice(-20)).toLowerCase()}`;\n valid = address === deriveConfidentialAccountId(identity.kind, identity.accountId);\n }\n } catch { valid = false; }\n responseAssert(valid, \"Signature does not verify against the frozen wallet identity.\");\n}\n","import { base58, base64 } from \"@scure/base\";\nimport { assert, responseAssert } from \"./errors\";\nimport { deriveConfidentialAccountId, standards } from \"./identity\";\nimport { normalizeChain } from \"./routing\";\nimport { raw, text } from \"./utils\";\nimport { decodeNep413Nonce, verifyWalletSignature } from \"./signatures\";\nimport type { LinkingIdentity, QuoteResponse, SignedData, Token, UnsignedData } from \"./types\";\n\nconst evmChains = new Set([\"eth\", \"arb\", \"avax\", \"op\", \"pol\", \"bsc\", \"base\", \"gnosis\", \"aurora\", \"bera\", \"berachain\", \"monad\", \"hypercore\", \"hyperliquid\", \"linea\", \"scroll\", \"zksync\", \"mantle\", \"celo\", \"sonic\"]);\nexport type AddressValidator = (address: string, token: Token) => boolean;\nexport function validateRecipients(addresses: readonly string[], token: Token, custom?: AddressValidator): string[] {\n assert(addresses.length >= 1 && addresses.length <= 10, \"A batch requires 1 to 10 recipients.\");\n const chain = normalizeChain(token.blockchain);\n const evm = evmChains.has(chain) || /^\\d+$/.test(token.swapChain ?? chain);\n const seen = new Set<string>();\n return addresses.map((value) => {\n const address = text(value, \"Recipient address\");\n let valid = false;\n try {\n if (custom) valid = custom(address, token);\n else if (evm) valid = /^0x[0-9a-f]{40}$/i.test(address);\n else if (chain === \"near\") { deriveConfidentialAccountId(\"near\", address); valid = true; }\n else if (chain === \"sol\") valid = base58.decode(address).length === 32;\n else if (chain === \"tron\") { deriveConfidentialAccountId(\"tron\", address); valid = true; }\n else if (chain === \"aptos\") valid = /^0x[0-9a-f]{1,64}$/i.test(address);\n else if (chain === \"sui\") valid = /^0x[0-9a-f]{64}$/i.test(address);\n else assert(false, \"Supply an address validator for this destination chain (including BTC/Zcash).\");\n } catch (error) { if (!custom && !evm && ![\"near\", \"sol\", \"tron\", \"aptos\", \"sui\"].includes(chain)) throw error; }\n assert(valid, \"Invalid recipient address for the destination chain.\");\n const key = evm || [\"aptos\", \"sui\"].includes(chain) ? address.toLowerCase() : address;\n assert(!seen.has(key), \"Duplicate recipient address.\");\n seen.add(key);\n return address;\n });\n}\nexport function validateToken(token: Token): void {\n text(token.assetId, \"Asset id\"); text(token.blockchain, \"Blockchain\"); text(token.symbol, \"Symbol\");\n assert(Number.isInteger(token.decimals) && token.decimals >= 0 && token.decimals <= 255, \"Invalid token decimals.\");\n}\nexport function validateQuote(q: QuoteResponse, requireDeposit: boolean): void {\n responseAssert(q && typeof q.quote === \"object\" && q.quote, \"Missing quote.\");\n raw(q.quote.amountIn, \"Quoted input\"); raw(q.quote.amountOut, \"Quoted output\");\n if (q.quote.minAmountOut !== undefined) assert(raw(q.quote.minAmountOut) <= raw(q.quote.amountOut), \"Minimum output exceeds quoted output.\");\n if (q.quote.minAmountIn !== undefined) raw(q.quote.minAmountIn);\n if (q.quoteRequest?.appFees !== undefined) {\n raw(q.quoteRequest.amount, \"Quote request amount\");\n responseAssert(Array.isArray(q.quoteRequest.appFees), \"Invalid quote app fees.\");\n for (const fee of q.quoteRequest.appFees) {\n responseAssert(fee && Number.isInteger(fee.fee) && fee.fee >= 0, \"Invalid quote app fee rate.\");\n }\n }\n if (requireDeposit) text(q.quote.depositAddress, \"Deposit address\");\n}\nexport function payloadMessage(data: UnsignedData): Record<string, unknown> {\n let message: unknown;\n try { message = JSON.parse(typeof data.payload === \"string\" ? data.payload : data.payload.message); }\n catch { responseAssert(false, \"Invalid intent JSON.\"); }\n responseAssert(message && typeof message === \"object\" && !Array.isArray(message), \"Invalid intent payload.\");\n return message as Record<string, unknown>;\n}\nexport function validatePayload(data: UnsignedData, identity: LinkingIdentity, signerId: string, contract: string, now: number, purpose: \"authorization\" | \"withdrawal\" = \"authorization\"): Record<string, unknown> {\n responseAssert(data.standard === standards[identity.kind], \"Signing standard does not match wallet.\");\n const msg = payloadMessage(data);\n responseAssert(msg.signer_id === signerId, \"Intent signer does not match the frozen identity.\");\n const deadline = Date.parse(String(msg.deadline ?? \"\"));\n responseAssert(Number.isFinite(deadline) && deadline > now, \"Intent deadline expired or invalid.\");\n responseAssert(Array.isArray(msg.intents), \"Intent list is missing.\");\n if (data.standard === \"nep413\") {\n text(data.payload.recipient, \"NEP-413 recipient\");\n // Generated withdrawals carry their own signed recipient; only login binds the configured verifier.\n if (purpose === \"authorization\") responseAssert(data.payload.recipient === contract, \"Invalid NEP-413 authorization verifier.\");\n decodeNep413Nonce(data.payload.nonce);\n } else if (purpose === \"authorization\") {\n responseAssert(msg.verifying_contract === contract && typeof msg.nonce === \"string\" && base64.decode(msg.nonce).length === 32, \"Invalid verifier or nonce.\");\n }\n return msg;\n}\nexport function validateSigned(unsigned: UnsignedData, signed: SignedData, identity: LinkingIdentity): void {\n responseAssert(signed.standard === unsigned.standard && JSON.stringify(signed.payload) === JSON.stringify(unsigned.payload), \"Wallet changed the payload.\");\n text(signed.signature, \"Signature\");\n if (identity.kind === \"near\" || identity.kind === \"solana\") {\n const expected = identity.publicKey ?? (identity.kind === \"solana\" ? `ed25519:${identity.accountId}` : \"\");\n responseAssert(expected && signed.public_key === expected, \"Signing public key changed.\");\n }\n verifyWalletSignature(signed, identity);\n}\n"],"mappings":";AAAA,SAAS,UAAAA,eAAc;;;ACKhB,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAE/C,YACW,MACT,SACS,QACA,aACT;AAAE,UAAM,OAAO;AAJN;AAEA;AACA;AAAA,EACS;AAAA,EAJT;AAAA,EAEA;AAAA,EACA;AAAA,EALF,OAAO;AAOlB;AAEO,SAAS,OAAO,WAAoB,SAAoC;AAC7E,MAAI,CAAC,UAAW,OAAM,IAAI,sBAAsB,iBAAiB,OAAO;AAC1E;AAEO,SAAS,eAAe,WAAoB,SAAoC;AACrF,MAAI,CAAC,UAAW,OAAM,IAAI,sBAAsB,oBAAoB,OAAO;AAC7E;AAEO,SAAS,oBAAoB,OAAyB;AAC3D,MAAI,iBAAiB,sBAAuB,QAAO,MAAM,SAAS;AAClE,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,QAAQ;AACd,QAAM,OAAO,OAAO,MAAM,QAAQ,EAAE,EAAE,YAAY;AAClD,QAAM,UAAU,OAAO,MAAM,WAAW,MAAM,SAAS,EAAE;AACzD,SACE,SAAS,UACT,SAAS,qBACT,2EAA2E,KAAK,OAAO;AAE3F;AAEO,SAAS,kBAAkB,aAA6C;AAC7E,SAAO,IAAI;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,eAAe,QAA4B;AACzD,MAAI,QAAQ;AACV,UAAM,IAAI,sBAAsB,WAAW,kBAAkB;AACjE;;;AChDA,SAAS,QAAQ,QAAQ,mBAAmB;AAC5C,SAAS,UAAAC,eAAc;;;ACDvB,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAuBpB,SAAS,KAAK,OAAgB,OAAuB;AAC1D,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,GAAG,GAAG,KAAK,eAAe;AACpF,SAAO,MAAM,KAAK;AACpB;AACO,SAAS,MAAS,OAAa;AAAE,SAAO,gBAAgB,KAAK;AAAG;;;ADpBhE,SAAS,4BAA4B,MAAmB,SAAyB;AACtF,QAAM,UAAU,KAAK,SAAS,gBAAgB;AAC9C,MAAI,SAAS,QAAQ;AACnB,WAAO,iCAAiC,KAAK,OAAO,KAAK,QAAQ,UAAU,KAAK,QAAQ,UAAU,IAAI,uBAAuB;AAC7H,WAAO;AAAA,EACT;AACA,MAAI,SAAS,OAAO;AAAE,WAAO,oBAAoB,KAAK,OAAO,GAAG,sBAAsB;AAAG,WAAO,QAAQ,YAAY;AAAA,EAAG;AACvH,MAAI,SAAS,UAAU;AACrB,UAAMC,SAAQ,OAAO,OAAO,OAAO;AACnC,WAAOA,OAAM,WAAW,IAAI,4BAA4B;AACxD,WAAO,OAAO,OAAOA,MAAK,EAAE,YAAY;AAAA,EAC1C;AACA,SAAO,SAAS,QAAQ,kCAAkC;AAC1D,QAAM,QAAQ,YAAYC,OAAM,EAAE,OAAO,OAAO;AAChD,SAAO,MAAM,WAAW,MAAM,MAAM,CAAC,MAAM,IAAM,uBAAuB;AACxE,SAAO,KAAK,OAAO,OAAO,MAAM,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC;AACzD;AACO,SAAS,YAAY,UAAmC;AAE7D,SAAO,GAAG,SAAS,IAAI,IAAI,4BAA4B,SAAS,MAAM,SAAS,SAAS,CAAC;AAC3F;AACO,SAAS,YAAY,GAAoB,GAA6B;AAAE,SAAO,YAAY,CAAC,MAAM,YAAY,CAAC;AAAG;;;AE7BzH,SAAS,eAAe;AACxB,SAAS,iBAAiB;AAC1B,SAAS,UAAAC,eAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,UAAAC,SAAQ,UAAAC,SAAQ,QAAQ,aAAa,sBAAsB;AAKpE,IAAM,SAAS,CAAC,MAAc,IAAI,YAAY,EAAE,OAAO,CAAC;AACxD,SAAS,IAAI,OAA2B;AAAE,QAAM,IAAI,IAAI,WAAW,CAAC;AAAG,MAAI,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,IAAI;AAAG,SAAO;AAAG;AACnI,SAAS,YAAY,GAAuB;AAAE,QAAM,IAAI,OAAO,CAAC;AAAG,SAAO,YAAY,IAAI,EAAE,MAAM,GAAG,CAAC;AAAG;AAClG,SAAS,kBAAkB,OAA2B;AAC3D,iBAAe,OAAO,UAAU,UAAU,wBAAwB;AAClE,QAAM,aAAa,MAAM,KAAK;AAC9B,MAAI;AACJ,MAAI;AAAE,YAAQ,OAAO,OAAO,UAAU;AAAA,EAAG,QACnC;AACJ,UAAM,WAAW,WAAW,QAAQ,OAAO,EAAE;AAC7C,QAAI;AAAE,cAAQ,eAAe,OAAO,QAAQ;AAAA,IAAG,QACzC;AACJ,UAAI;AAAE,gBAAQ,YAAY,OAAO,QAAQ;AAAA,MAAG,QACtC;AAAE,uBAAe,OAAO,iCAAiC;AAAA,MAAG;AAAA,IACpE;AAAA,EACF;AACA,iBAAe,MAAM,WAAW,IAAI,qCAAqC;AACzE,SAAO;AACT;AACO,SAAS,WAAW,SAA+E;AACxG,QAAM,QAAQ,kBAAkB,QAAQ,KAAK;AAC7C,SAAOC,QAAO,YAAY,IAAI,KAAK,KAAK,GAAG,GAAG,YAAY,QAAQ,OAAO,GAAG,OAAO,YAAY,QAAQ,SAAS,GAAG,QAAQ,gBAAgB,SAAY,IAAI,WAAW,CAAC,CAAC,CAAC,IAAI,YAAY,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,QAAQ,WAAW,CAAC,CAAC,CAAC;AAClP;AACO,SAAS,oBAAoB,SAAiB,MAAkC;AACrF,QAAM,QAAQ,OAAO,OAAO;AAC5B,SAAO,WAAW,YAAY,OAAO,IAAO,SAAS,QAAQ,aAAa,MAAM;AAAA,EAAqB,MAAM,MAAM,EAAE,GAAG,KAAK,CAAC;AAC9H;AACO,SAAS,iBAAiB,OAA4B;AAC3D,MAAI,iBAAiB,WAAY,QAAO;AACxC,MAAI,SAAS,OAAO,UAAU,YAAY,eAAe,OAAO;AAC9D,WAAO,iBAAkB,MAAiC,SAAS;AAAA,EACrE;AACA,MAAI,YAAY,OAAO,KAAK,GAAG;AAC7B,WAAO,IAAI,WAAW,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU;AAAA,EACxE;AACA,QAAM,IAAI,MAAM,mDAAmD;AACrE;AACO,SAAS,cAAc,OAA4B,QAA4B;AACpF,MAAI,iBAAiB,YAAY;AAAE,mBAAe,MAAM,WAAW,QAAQ,8BAA8B;AAAG,WAAO,IAAI,WAAW,KAAK;AAAA,EAAG;AAC1I,QAAMC,OAAM,MAAM,QAAQ,aAAa,EAAE;AACzC,aAAW,WAAW,CAAC,MAAMC,QAAO,OAAOD,IAAG,GAAG,MAAM,OAAO,OAAOA,IAAG,GAAG,MAAME,QAAO,OAAOF,KAAI,QAAQ,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC,GAAG;AACrI,QAAI;AAAE,YAAM,IAAI,QAAQ;AAAG,UAAI,EAAE,WAAW,OAAQ,QAAO;AAAA,IAAG,QAAQ;AAAA,IAA4C;AAAA,EACpH;AACA,iBAAe,OAAO,2BAA2B;AACnD;AACO,SAAS,uBAAuB,OAAuB;AAC5D,QAAM,MAAM,MAAM,QAAQ,QAAQ,EAAE;AACpC,iBAAe,mBAAmB,KAAK,GAAG,GAAG,+BAA+B;AAC5E,QAAM,QAAQE,QAAO,OAAO,IAAI,YAAY,CAAC;AAC7C,QAAM,IAAI,MAAM,EAAE;AAClB,iBAAe,CAAC,GAAG,GAAG,IAAI,EAAE,EAAE,SAAS,CAAC,GAAG,sBAAsB;AACjE,QAAM,EAAE,IAAI,IAAI,KAAK,IAAI,KAAK;AAC9B,SAAO,KAAKA,QAAO,OAAO,KAAK,EAAE,YAAY,CAAC;AAChD;AACO,SAAS,sBAAsB,MAAkB,UAAiC;AACvF,MAAI,QAAQ;AACZ,MAAI;AACF,QAAI,SAAS,SAAS,UAAU,KAAK,aAAa,UAAU;AAC1D,YAAM,MAAM,cAAc,SAAS,aAAa,IAAI,EAAE;AACtD,cAAQ,QAAQ,OAAO,cAAc,KAAK,WAAW,EAAE,GAAG,WAAW,KAAK,OAAO,GAAG,GAAG;AACvF,UAAI,iBAAiB,KAAK,SAAS,SAAS,EAAG,SAAQ,SAASA,QAAO,OAAO,GAAG,EAAE,YAAY,MAAM,SAAS;AAAA,IAChH,WAAW,SAAS,SAAS,YAAY,KAAK,aAAa,eAAe;AACxE,cAAQ,QAAQ,OAAO,cAAc,KAAK,WAAW,EAAE,GAAG,OAAO,KAAK,OAAO,GAAGD,QAAO,OAAO,SAAS,SAAS,CAAC;AAAA,IACnH,YAAY,SAAS,SAAS,SAAS,SAAS,SAAS,WAAW,OAAO,KAAK,YAAY,UAAU;AACpG,YAAM,QAAQC,QAAO,OAAO,uBAAuB,KAAK,SAAS,EAAE,MAAM,CAAC,EAAE,YAAY,CAAC;AACzF,YAAM,MAAM,UAAU,UAAU,YAAY,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,eAAe,MAAM,EAAE,IAAK,EAAE;AAC9F,YAAM,YAAY,IAAI,iBAAiB,oBAAoB,KAAK,SAAS,SAAS,IAAI,CAAC,EAAE,WAAW,KAAK;AACzG,YAAM,UAAU,KAAKA,QAAO,OAAO,WAAW,UAAU,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,YAAY,CAAC;AAC3F,cAAQ,YAAY,4BAA4B,SAAS,MAAM,SAAS,SAAS;AAAA,IACnF;AAAA,EACF,QAAQ;AAAE,YAAQ;AAAA,EAAO;AACzB,iBAAe,OAAO,+DAA+D;AACvF;;;AClFA,SAAS,UAAAC,SAAQ,UAAAC,eAAc;AA6ExB,SAAS,eAAe,UAAwB,QAAoB,UAAiC;AAC1G,iBAAe,OAAO,aAAa,SAAS,YAAY,KAAK,UAAU,OAAO,OAAO,MAAM,KAAK,UAAU,SAAS,OAAO,GAAG,6BAA6B;AAC1J,OAAK,OAAO,WAAW,WAAW;AAClC,MAAI,SAAS,SAAS,UAAU,SAAS,SAAS,UAAU;AAC1D,UAAM,WAAW,SAAS,cAAc,SAAS,SAAS,WAAW,WAAW,SAAS,SAAS,KAAK;AACvG,mBAAe,YAAY,OAAO,eAAe,UAAU,6BAA6B;AAAA,EAC1F;AACA,wBAAsB,QAAQ,QAAQ;AACxC;;;AL3EO,SAAS,wBAAwB,WAA+E;AACrH,SAAO,qBAAqB;AAAA,IAC1B,aAAa,aAAa,EAAE,MAAM,OAAO,WAAW,OAAO,MAAM,UAAU,GAAG,WAAW,EAAE;AAAA,IAC3F,MAAM,OAAO,SAAS;AACpB,aAAO,KAAK,aAAa,UAAU,2BAA2B;AAC9D,aAAO,EAAE,GAAG,MAAM,WAAW,uBAAuB,OAAO,MAAM,UAAU,GAAG,YAAY,KAAK,OAAO,CAAC,EAAE;AAAA,IAC3G;AAAA,EACF,CAAC;AACH;AAEO,SAAS,2BAA2B,WAAsD;AAC/F,SAAO,qBAAqB;AAAA,IAC1B,aAAa,aAAa,EAAE,MAAM,UAAU,WAAW,UAAU,EAAE,UAAU,SAAS,GAAG,WAAW,WAAW,UAAU,EAAE,UAAU,SAAS,CAAC,GAAG;AAAA,IAClJ,MAAM,OAAO,SAAS;AACpB,aAAO,KAAK,aAAa,eAAe,+BAA+B;AACvE,YAAM,SAAS,UAAU;AACzB,YAAM,YAAY,iBAAiB,MAAM,OAAO,YAAY,IAAI,YAAY,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;AACnG,aAAO,EAAE,GAAG,MAAM,YAAY,WAAW,OAAO,UAAU,SAAS,CAAC,IAAI,WAAW,WAAWC,QAAO,OAAO,cAAc,WAAW,EAAE,CAAC,CAAC,GAAG;AAAA,IAC9I;AAAA,EACF,CAAC;AACH;AAEO,SAAS,yBAAyB,WAAoD;AAC3F,SAAO,qBAAqB;AAAA,IAC1B,aAAa,aAAa,EAAE,MAAM,QAAQ,WAAW,MAAM,UAAU,EAAE,WAAW,EAAE;AAAA,IACpF,MAAM,OAAO,SAAS;AACpB,aAAO,KAAK,aAAa,UAAU,2BAA2B;AAC9D,aAAO,EAAE,GAAG,MAAM,WAAW,uBAAuB,MAAM,UAAU,EAAE,cAAc,KAAK,OAAO,CAAC,EAAE;AAAA,IACrG;AAAA,EACF,CAAC;AACH;AAOO,SAAS,yBAAyB,QAA2B,KAAmF;AACrJ,QAAM,cAAc,YAAsC;AACxD,UAAM,WAAW,MAAM,OAAO,YAAY;AAC1C,WAAO,EAAE,MAAM,QAAQ,WAAW,SAAS,WAAW,WAAW,WAAWA,QAAO,OAAO,cAAc,SAAS,WAAW,EAAE,CAAC,CAAC,GAAG;AAAA,EACrI;AACA,SAAO,qBAAqB;AAAA,IAC1B;AAAA,IACA,SAAS,OAAO,WAAW;AACzB,YAAM,WAAW,MAAM,YAAY;AACnC,UAAI,iBAAiB,KAAK,SAAS,SAAS,GAAG;AAC7C,cAAM,SAAS,MAAM,KAAK,cAAc,SAAS,WAAY,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AACjH,eAAO,WAAW,SAAS,WAAW,8DAA8D;AAAA,MACtG,OAAO;AACL,cAAM,aAAa,MAAM,IAAI,YAAqB,kBAAkB,EAAE,YAAY,SAAS,WAAW,YAAY,SAAS,UAAU,GAAG,MAAM;AAC9I,uBAAe,OAAO,eAAe,WAAW,oCAAoC;AACpF,YAAI,CAAC,YAAY;AACf,iBAAO,OAAO,mBAAmB,wEAAwE;AACzG,yBAAe,MAAM;AACrB,gBAAM,OAAO,kBAAkB,SAAS,WAAW,SAAS,WAAY,IAAI,iBAAiB,MAAM;AACnG,yBAAe,MAAM,IAAI,YAAqB,kBAAkB,EAAE,YAAY,SAAS,WAAW,YAAY,SAAS,UAAU,GAAG,MAAM,MAAM,MAAM,iDAAiD;AAAA,QACzM;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO,SAAS;AACpB,aAAO,KAAK,aAAa,UAAU,2BAA2B;AAC9D,YAAM,SAAS,MAAM,OAAO,YAAY,EAAE,GAAG,KAAK,SAAS,OAAO,kBAAkB,KAAK,QAAQ,KAAK,EAAE,CAAC;AACzG,qBAAe,OAAO,eAAe,MAAM,YAAY,GAAG,WAAW,2CAA2C;AAChH,aAAO,EAAE,GAAG,MAAM,YAAY,WAAWA,QAAO,OAAO,cAAc,OAAO,WAAW,EAAE,CAAC,CAAC,IAAI,WAAW,WAAWA,QAAO,OAAO,cAAc,OAAO,WAAW,EAAE,CAAC,CAAC,GAAG;AAAA,IAC5K;AAAA,EACF,CAAC;AACH;AACO,SAAS,qBAAqB,SAAyC;AAC5E,SAAO;AAAA,IACL,aAAa,MAAM,QAAQ,YAAY;AAAA,IACvC,SAAS,QAAQ,SAAS,KAAK,OAAO;AAAA,IACtC,MAAM,OAAO,MAAoB,WAA8C;AAC7E,qBAAe,MAAM;AACrB,YAAM,WAAW,MAAM,QAAQ,YAAY;AAC3C,UAAI;AACJ,UAAI;AACF,iBAAS,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG,MAAM;AAAA,MACjD,SAAS,OAAO;AACd,YAAI,oBAAoB,KAAK,EAAG,OAAM,kBAAkB;AACxD,cAAM;AAAA,MACR;AACA,qBAAe,MAAM;AACrB,UAAI,CAAC,YAAY,UAAU,MAAM,QAAQ,YAAY,CAAC,EAAG,OAAM,IAAI,sBAAsB,kBAAkB,wCAAwC;AACnJ,qBAAe,MAAM,QAAQ,QAAQ;AACrC,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":["base58","sha256","bytes","sha256","sha256","base16","base58","sha256","raw","base58","base16","base58","base64","base58"]}
@@ -266,13 +266,23 @@ interface WithdrawProgress {
266
266
  amount: string;
267
267
  status: string;
268
268
  }
269
+ /** Pre-funding balance row persisted for delta-based deposit credit detection. */
270
+ interface BalanceSnapshotEntry {
271
+ tokenId: string;
272
+ available: string;
273
+ }
269
274
  interface ExecutionSnapshot {
270
275
  version: 1;
271
276
  id: string;
272
277
  environment: string;
273
278
  plan: QuotePlan;
274
279
  stage: ExecutionStage;
280
+ /** Funding-asset available at baseline (legacy / balance-source checks). */
275
281
  baseline?: string;
282
+ /** Full account balance snapshot at baseline; credit poll compares against this. */
283
+ baselineBalances?: BalanceSnapshotEntry[];
284
+ /** Token that actually received the deposit credit (from balance delta). */
285
+ creditedTokenId?: string;
276
286
  creditedAmount?: string;
277
287
  receipt?: FundingReceipt;
278
288
  recordId?: string;
@@ -347,4 +357,4 @@ declare class HttpConfidentialApi implements ConfidentialApi {
347
357
  getOrders(token: string, signerId: string, limit: number, offset: number, signal?: AbortSignal): Promise<OrderPage>;
348
358
  }
349
359
 
350
- export { type AppFee as A, type Balance as B, type ConfidentialApi as C, type WithdrawPreview as D, type ExecutionStore as E, type FundingIdentity as F, type WithdrawProgress as G, HttpConfidentialApi as H, type LinkingKind as L, type OrderPage as O, type PollingOptions as P, type QuotePlan as Q, type SigningAdapter as S, type Token as T, type UnsignedData as U, type WalletKind as W, type LinkingIdentity as a, type SigningStandard as b, type FundingRoute as c, type FundingAdapter as d, type FundingSwapAdapter as e, type SessionStore as f, type QuoteResponse as g, type QuoteRequest as h, type Login as i, type ExecutionSnapshot as j, type ExecuteOptions as k, type AppFeeEstimate as l, type ExecutionStage as m, type FundingReceipt as n, type FundingRouteKind as o, type FundingSwapQuote as p, type HttpApiConfig as q, type PrivateOrder as r, type PrivateWithdrawRequest as s, type PrivateWithdrawRow as t, type QuoteParams as u, type Session as v, type SignatureProgress as w, type SignedData as x, type StatusResponse as y, type SwapFundingRequest as z };
360
+ export { type AppFee as A, type Balance as B, type ConfidentialApi as C, type SwapFundingRequest as D, type ExecutionStore as E, type FundingIdentity as F, type WithdrawPreview as G, HttpConfidentialApi as H, type WithdrawProgress as I, type LinkingKind as L, type OrderPage as O, type PollingOptions as P, type QuotePlan as Q, type SigningAdapter as S, type Token as T, type UnsignedData as U, type WalletKind as W, type LinkingIdentity as a, type SigningStandard as b, type FundingRoute as c, type FundingAdapter as d, type FundingSwapAdapter as e, type SessionStore as f, type QuoteResponse as g, type QuoteRequest as h, type Login as i, type ExecutionSnapshot as j, type ExecuteOptions as k, type BalanceSnapshotEntry as l, type AppFeeEstimate as m, type ExecutionStage as n, type FundingReceipt as o, type FundingRouteKind as p, type FundingSwapQuote as q, type HttpApiConfig as r, type PrivateOrder as s, type PrivateWithdrawRequest as t, type PrivateWithdrawRow as u, type QuoteParams as v, type Session as w, type SignatureProgress as x, type SignedData as y, type StatusResponse as z };
@@ -266,13 +266,23 @@ interface WithdrawProgress {
266
266
  amount: string;
267
267
  status: string;
268
268
  }
269
+ /** Pre-funding balance row persisted for delta-based deposit credit detection. */
270
+ interface BalanceSnapshotEntry {
271
+ tokenId: string;
272
+ available: string;
273
+ }
269
274
  interface ExecutionSnapshot {
270
275
  version: 1;
271
276
  id: string;
272
277
  environment: string;
273
278
  plan: QuotePlan;
274
279
  stage: ExecutionStage;
280
+ /** Funding-asset available at baseline (legacy / balance-source checks). */
275
281
  baseline?: string;
282
+ /** Full account balance snapshot at baseline; credit poll compares against this. */
283
+ baselineBalances?: BalanceSnapshotEntry[];
284
+ /** Token that actually received the deposit credit (from balance delta). */
285
+ creditedTokenId?: string;
276
286
  creditedAmount?: string;
277
287
  receipt?: FundingReceipt;
278
288
  recordId?: string;
@@ -347,4 +357,4 @@ declare class HttpConfidentialApi implements ConfidentialApi {
347
357
  getOrders(token: string, signerId: string, limit: number, offset: number, signal?: AbortSignal): Promise<OrderPage>;
348
358
  }
349
359
 
350
- export { type AppFee as A, type Balance as B, type ConfidentialApi as C, type WithdrawPreview as D, type ExecutionStore as E, type FundingIdentity as F, type WithdrawProgress as G, HttpConfidentialApi as H, type LinkingKind as L, type OrderPage as O, type PollingOptions as P, type QuotePlan as Q, type SigningAdapter as S, type Token as T, type UnsignedData as U, type WalletKind as W, type LinkingIdentity as a, type SigningStandard as b, type FundingRoute as c, type FundingAdapter as d, type FundingSwapAdapter as e, type SessionStore as f, type QuoteResponse as g, type QuoteRequest as h, type Login as i, type ExecutionSnapshot as j, type ExecuteOptions as k, type AppFeeEstimate as l, type ExecutionStage as m, type FundingReceipt as n, type FundingRouteKind as o, type FundingSwapQuote as p, type HttpApiConfig as q, type PrivateOrder as r, type PrivateWithdrawRequest as s, type PrivateWithdrawRow as t, type QuoteParams as u, type Session as v, type SignatureProgress as w, type SignedData as x, type StatusResponse as y, type SwapFundingRequest as z };
360
+ export { type AppFee as A, type Balance as B, type ConfidentialApi as C, type SwapFundingRequest as D, type ExecutionStore as E, type FundingIdentity as F, type WithdrawPreview as G, HttpConfidentialApi as H, type WithdrawProgress as I, type LinkingKind as L, type OrderPage as O, type PollingOptions as P, type QuotePlan as Q, type SigningAdapter as S, type Token as T, type UnsignedData as U, type WalletKind as W, type LinkingIdentity as a, type SigningStandard as b, type FundingRoute as c, type FundingAdapter as d, type FundingSwapAdapter as e, type SessionStore as f, type QuoteResponse as g, type QuoteRequest as h, type Login as i, type ExecutionSnapshot as j, type ExecuteOptions as k, type BalanceSnapshotEntry as l, type AppFeeEstimate as m, type ExecutionStage as n, type FundingReceipt as o, type FundingRouteKind as p, type FundingSwapQuote as q, type HttpApiConfig as r, type PrivateOrder as s, type PrivateWithdrawRequest as t, type PrivateWithdrawRow as u, type QuoteParams as v, type Session as w, type SignatureProgress as x, type SignedData as y, type StatusResponse as z };