@rhea-finance/confidential-swap 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -71,7 +71,7 @@ The example assumes the application's existing wallet, asset, funding adapter an
71
71
 
72
72
  `Token.assetId` identifies the registry asset. `blockchain` names its chain. `contractAddress` identifies its actual on-chain token. For numeric EVM funding identities supply the matching token `swapChain` (e.g. `"1"`); `swapAddress` explicitly maps an asset to the aggregation SDK's token address/native sentinel. No arbitrary EVM chain is guessed from `evm` kind alone.
73
73
 
74
- `preview` accepts an optional linking identity and returns `executable: false`. A placeholder identity is display-only. Preview/quote may allocate deposit addresses on the backend, but neither signs nor broadcasts funds. `quote` requires a real linking identity. Default fees match the reference app: 2 bps to `crosschaindexfee.near`, referral `rhea`; supply `appFees: []` or your own fees explicitly when needed.
74
+ `preview` accepts an optional linking identity and returns `executable: false`. A placeholder identity is display-only. Preview/quote may allocate deposit addresses on the backend, but neither signs nor broadcasts funds. `quote` requires a real linking identity. Default withdrawal fees match the reference app: 2 bps to `dcl0001.near`, referral `rhea`. App fees are attached only to withdrawal quotes; funding deposit quotes do not include them. Configured `appFees` must contain at least one valid NEAR recipient and an integer fee from 1 to 10000.
75
75
 
76
76
  ## Funding adapters and paths
77
77
 
@@ -87,7 +87,7 @@ For non-DIRECT funding, the funding adapter still validates the source wallet an
87
87
 
88
88
  All paths authorize the linking identity before sending source funds. Routing prefers registered direct assets, then same-chain USDC/USDT/USDT0, then a NEAR asset or another registry asset. Native NEAR maps to wNEAR. FLEX minimum input is checked against the final aggregation minimum output, with bounded requotes.
89
89
 
90
- `fundingSource: 'balance'` spends only the requested amount from an existing registered confidential balance, without a source transaction. `mode: 'TRANSFER'` requires the same funding and destination asset; otherwise mode defaults to `SWAP`. A batch has 1-10 unique recipients on one destination chain and asset. Randomized positive shares preserve the exact raw total with roughly 80-120 percent equal-share bounds, allowing integer rounding. Frozen random fractions are reused against the actual credited amount.
90
+ `fundingSource: 'balance'` spends only the requested amount from an existing registered confidential balance, without a source transaction. These balance withdrawals are checkpointed in process memory only and are never written to the configured `executionStore`, so they are not recoverable after reload. `mode: 'TRANSFER'` requires the same funding and destination asset; otherwise mode defaults to `SWAP`. A batch has 1-10 unique recipients on one destination chain and asset. Randomized positive shares preserve the exact raw total with roughly 80-120 percent equal-share bounds, allowing integer rounding. Frozen random fractions are reused against the actual credited amount.
91
91
 
92
92
  Supply `addressValidator` for BTC/Zcash or unsupported destination chains, using an established chain library. Known EVM, NEAR, Solana, Tron, Aptos and Sui address formats are checked by default. Case-sensitive addresses are never lowercased or silently truncated.
93
93
 
@@ -125,7 +125,7 @@ Applications may opt into additional protocol-specific validation using `verifyW
125
125
 
126
126
  ## Recovery and safety
127
127
 
128
- Use `getExecution(id)` to inspect checkpoints and `resume(id)` to continue polling or signing. Reusing `execute(plan)` for a saved ID resumes it instead of sending another transfer. Default memory stores last only for the client lifetime; supply `ExecutionStore` and `SessionStore` for your own storage.
128
+ Use `getExecution(id)` to inspect one checkpoint and `listRecoverableExecutions()` to read credited unfinished executions in recovery order. Call `resume(id)` to continue; it refreshes an expired withdrawal review before polling or signing. Reusing `execute(plan)` for a saved ID resumes it instead of sending another transfer. Default memory stores last only for the client lifetime; supply `ExecutionStore` and `SessionStore` for your own storage.
129
129
 
130
130
  Checkpoints are saved **before** funding broadcast, report submission and withdrawal submission. A lost response leaves an `*_unknown` stage. Such writes are never automatically retried, including on 401. Supply read-only `reconcile`/`reconcileFunding` and `reconcileReport` lookups keyed by execution ID/transaction/deposit. An unknown batch is recovered only by finding the existing signer-scoped order with all saved withdrawal deposit addresses; a missing match remains unknown.
131
131
 
@@ -48,6 +48,22 @@ function assert(condition, message) {
48
48
  function responseAssert(condition, message) {
49
49
  if (!condition) throw new ConfidentialSwapError("INVALID_RESPONSE", message);
50
50
  }
51
+ function isUserRejectedError(error) {
52
+ if (error instanceof ConfidentialSwapError) return error.code === "USER_REJECTED";
53
+ if (!error || typeof error !== "object") return false;
54
+ const value = error;
55
+ const code = String(value.code ?? "").toUpperCase();
56
+ const message = String(value.message ?? value.error ?? "");
57
+ return code === "4001" || code === "ACTION_REJECTED" || /user.*(reject|cancel|den(?:y|ied))|(?:reject|cancel|den(?:y|ied)).*user/i.test(message);
58
+ }
59
+ function userRejectedError(executionId) {
60
+ return new ConfidentialSwapError(
61
+ "USER_REJECTED",
62
+ "User rejected transaction.",
63
+ void 0,
64
+ executionId
65
+ );
66
+ }
51
67
  function throwIfAborted(signal) {
52
68
  if (signal?.aborted) throw new ConfidentialSwapError("ABORTED", "Local operation cancelled; submitted transactions are not cancelled.");
53
69
  }
@@ -278,7 +294,13 @@ function createCheckedAdapter(adapter) {
278
294
  sign: async (data, signal) => {
279
295
  throwIfAborted(signal);
280
296
  const identity = await adapter.getIdentity();
281
- const signed = await adapter.sign(clone(data), signal);
297
+ let signed;
298
+ try {
299
+ signed = await adapter.sign(clone(data), signal);
300
+ } catch (error) {
301
+ if (isUserRejectedError(error)) throw userRejectedError();
302
+ throw error;
303
+ }
282
304
  throwIfAborted(signal);
283
305
  if (!sameLinking(identity, await adapter.getIdentity())) throw new ConfidentialSwapError("WALLET_CHANGED", "Wallet identity changed while signing.");
284
306
  validateSigned(data, signed, identity);
@@ -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, responseAssert, throwIfAborted } 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 const signed = await adapter.sign(clone(data), signal);\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\" | \"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 throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) throw new ConfidentialSwapError(\"ABORTED\", \"Local operation cancelled; submitted transactions are not 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 return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}:${identity.publicKey ?? \"\"}`;\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}\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}\nexport function availableForAsset(balances: readonly Balance[], assetId: string): string {\n const exact = balances.find((b) => b.tokenId === assetId);\n const entry = exact ?? balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${assetId}`));\n return raw(entry?.available ?? \"0\", \"Available balance\", true).toString();\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 (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) throw new ConfidentialSwapError(\"ABORTED\", \"Local operation cancelled; submitted transactions are not 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 return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}:${identity.publicKey ?? \"\"}`;\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}\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}\nexport function availableForAsset(balances: readonly Balance[], assetId: string): string {\n const exact = balances.find((b) => b.tokenId === assetId);\n const entry = exact ?? balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${assetId}`));\n return raw(entry?.available ?? \"0\", \"Available balance\", true).toString();\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 (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,5 +1,5 @@
1
- import { H as HttpConfidentialApi } from '../api-DenG9sWp.cjs';
2
- import { S as SigningAdapter } from '../types-Bq8OZRUK.cjs';
1
+ import { H as HttpConfidentialApi } from '../api-CePMDtO_.cjs';
2
+ import { S as SigningAdapter } from '../types-DaD5YFS0.cjs';
3
3
 
4
4
  interface EvmMessageSigner {
5
5
  getAddress(): Promise<string>;
@@ -1,5 +1,5 @@
1
- import { H as HttpConfidentialApi } from '../api-cazA5IdP.js';
2
- import { S as SigningAdapter } from '../types-Bq8OZRUK.js';
1
+ import { H as HttpConfidentialApi } from '../api-BaVq3D0G.js';
2
+ import { S as SigningAdapter } from '../types-DaD5YFS0.js';
3
3
 
4
4
  interface EvmMessageSigner {
5
5
  getAddress(): Promise<string>;
@@ -20,6 +20,22 @@ function assert(condition, message) {
20
20
  function responseAssert(condition, message) {
21
21
  if (!condition) throw new ConfidentialSwapError("INVALID_RESPONSE", message);
22
22
  }
23
+ function isUserRejectedError(error) {
24
+ if (error instanceof ConfidentialSwapError) return error.code === "USER_REJECTED";
25
+ if (!error || typeof error !== "object") return false;
26
+ const value = error;
27
+ const code = String(value.code ?? "").toUpperCase();
28
+ const message = String(value.message ?? value.error ?? "");
29
+ return code === "4001" || code === "ACTION_REJECTED" || /user.*(reject|cancel|den(?:y|ied))|(?:reject|cancel|den(?:y|ied)).*user/i.test(message);
30
+ }
31
+ function userRejectedError(executionId) {
32
+ return new ConfidentialSwapError(
33
+ "USER_REJECTED",
34
+ "User rejected transaction.",
35
+ void 0,
36
+ executionId
37
+ );
38
+ }
23
39
  function throwIfAborted(signal) {
24
40
  if (signal?.aborted) throw new ConfidentialSwapError("ABORTED", "Local operation cancelled; submitted transactions are not cancelled.");
25
41
  }
@@ -250,7 +266,13 @@ function createCheckedAdapter(adapter) {
250
266
  sign: async (data, signal) => {
251
267
  throwIfAborted(signal);
252
268
  const identity = await adapter.getIdentity();
253
- const signed = await adapter.sign(clone(data), signal);
269
+ let signed;
270
+ try {
271
+ signed = await adapter.sign(clone(data), signal);
272
+ } catch (error) {
273
+ if (isUserRejectedError(error)) throw userRejectedError();
274
+ throw error;
275
+ }
254
276
  throwIfAborted(signal);
255
277
  if (!sameLinking(identity, await adapter.getIdentity())) throw new ConfidentialSwapError("WALLET_CHANGED", "Wallet identity changed while signing.");
256
278
  validateSigned(data, signed, identity);
@@ -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, responseAssert, throwIfAborted } 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 const signed = await adapter.sign(clone(data), signal);\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\" | \"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 throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) throw new ConfidentialSwapError(\"ABORTED\", \"Local operation cancelled; submitted transactions are not 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 return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}:${identity.publicKey ?? \"\"}`;\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}\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}\nexport function availableForAsset(balances: readonly Balance[], assetId: string): string {\n const exact = balances.find((b) => b.tokenId === assetId);\n const entry = exact ?? balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${assetId}`));\n return raw(entry?.available ?? \"0\", \"Available balance\", true).toString();\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 (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":["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) throw new ConfidentialSwapError(\"ABORTED\", \"Local operation cancelled; submitted transactions are not 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 return `${identity.kind}:${deriveConfidentialAccountId(identity.kind, identity.accountId)}:${identity.publicKey ?? \"\"}`;\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}\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}\nexport function availableForAsset(balances: readonly Balance[], assetId: string): string {\n const exact = balances.find((b) => b.tokenId === assetId);\n const entry = exact ?? balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${assetId}`));\n return raw(entry?.available ?? \"0\", \"Available balance\", true).toString();\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 (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,QAAS,OAAM,IAAI,sBAAsB,WAAW,sEAAsE;AACxI;;;AC/CA,SAAS,QAAQ,QAAQ,mBAAmB;AAC5C,SAAS,UAAAC,eAAc;;;ACDvB,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAUpB,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;;;ADPhE,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;AAC7D,SAAO,GAAG,SAAS,IAAI,IAAI,4BAA4B,SAAS,MAAM,SAAS,SAAS,CAAC,IAAI,SAAS,aAAa,EAAE;AACvH;AACO,SAAS,YAAY,GAAoB,GAA6B;AAAE,SAAO,YAAY,CAAC,MAAM,YAAY,CAAC;AAAG;;;AE5BzH,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;AAsExB,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;;;ALpEO,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 +1 @@
1
- {"version":3,"sources":["../src/aggregation.ts","../src/errors.ts","../src/routing.ts","../src/utils.ts"],"sourcesContent":["import type { AssetRef, ChainRef, Quote, QuoteRequest, SwapClient } from \"@rhea-finance/cross-chain-aggregation-dex\";\nimport { assert, ConfidentialSwapError, responseAssert, throwIfAborted } from \"./errors\";\nimport { normalizeChain } from \"./routing\";\nimport { clone, raw, text } from \"./utils\";\nimport type { ExecutionSnapshot, FundingSwapAdapter, SwapFundingRequest, Token } from \"./types\";\n\nexport interface FundingReporter {\n report(snapshot: ExecutionSnapshot, signal?: AbortSignal): Promise<string>;\n getStatus(recordId: string, snapshot: ExecutionSnapshot, signal?: AbortSignal): Promise<string>;\n reconcileReport?(snapshot: ExecutionSnapshot, signal?: AbortSignal): Promise<string | undefined>;\n}\nexport interface AggregationAdapterConfig {\n /** Construct this client with reportMode: \"manual\" to avoid duplicate reports. */\n client: Pick<SwapClient, \"quote\" | \"buildSwap\" | \"executeSwap\">;\n reporter: FundingReporter;\n /** Explicit mapping avoids conflating registry asset IDs and aggregation token addresses. */\n mapAsset: (token: Token) => AssetRef;\n reconcileFunding?: FundingSwapAdapter[\"reconcileFunding\"];\n}\nfunction serialize(request: SwapFundingRequest, map: AggregationAdapterConfig[\"mapAsset\"]): QuoteRequest {\n const tokenIn = map(clone(request.sourceToken));\n const tokenOut = map(clone(request.fundingToken));\n assert(tokenIn.chain === request.wallet.chain, \"Aggregation source chain differs from the frozen wallet chain.\");\n text(tokenIn.address, \"Mapped source token address\"); text(tokenOut.address, \"Mapped funding token address\");\n return { fromChain: tokenIn.chain, toChain: tokenOut.chain, tokenIn, tokenOut, amountIn: request.amount, slippageBps: request.slippageBps, sender: request.wallet.accountId, recipient: request.recipient };\n}\nfunction equalAddress(a: string | undefined, b: string, chain: string): boolean {\n return /^\\d+$/.test(chain) ? a?.toLowerCase() === b.toLowerCase() : a === b;\n}\nexport function createAggregationFundingAdapter(config: AggregationAdapterConfig): FundingSwapAdapter {\n return {\n quote: async (request, signal) => {\n const quote = await config.client.quote(serialize(request, config.mapAsset), { signal });\n return { amountOut: quote.estimatedOut, minAmountOut: quote.minAmountOut, expiresAt: quote.expiresAt, data: clone(quote) };\n },\n execute: async (input, request, _id, signal) => {\n throwIfAborted(signal);\n const quote = clone(input.data) as Quote;\n const expected = serialize(request, config.mapAsset);\n responseAssert(quote.amountIn === request.amount && quote.fromChain === expected.fromChain && quote.toChain === expected.toChain\n && equalAddress(quote.buildContext.request.sender, request.wallet.accountId, expected.fromChain)\n && quote.buildContext.request.recipient === request.recipient\n && equalAddress(quote.tokenIn.address, expected.tokenIn.address, expected.fromChain)\n && equalAddress(quote.tokenOut.address, expected.tokenOut.address, expected.toChain)\n && equalAddress(quote.buildContext.request.tokenIn, expected.tokenIn.address, expected.fromChain)\n && equalAddress(quote.buildContext.request.tokenOut, expected.tokenOut.address, expected.toChain), \"Funding quote does not match the frozen execution request.\");\n const build = await config.client.buildSwap({ quote, signal });\n responseAssert(raw(build.minAmountOut) >= raw(input.minAmountOut), \"Built swap minimum output fell below its funding quote.\");\n responseAssert(build.fromChain === expected.fromChain && build.toChain === expected.toChain && build.amountIn === request.amount\n && equalAddress(build.tokenIn.address, expected.tokenIn.address, expected.fromChain)\n && equalAddress(build.tokenOut.address, expected.tokenOut.address, expected.toChain), \"Built swap asset or chain differs from its funding request.\");\n const result = await config.client.executeSwap({ build, signal, waitFor: \"submitted\" });\n responseAssert(result.txHash, \"Funding swap did not return a source transaction hash.\");\n return { txHash: result.txHash, orderId: result.orderId, router: result.router };\n },\n report: config.reporter.report.bind(config.reporter),\n getStatus: config.reporter.getStatus.bind(config.reporter),\n reconcileReport: config.reporter.reconcileReport?.bind(config.reporter),\n reconcileFunding: config.reconcileFunding,\n };\n}\nexport interface HttpFundingReporterConfig {\n baseUrl: string;\n bearerToken?: string;\n fetch?: typeof fetch;\n requestTimeoutMs?: number;\n}\nexport class HttpFundingReporter implements FundingReporter {\n private readonly base: string;\n private readonly fetcher: typeof fetch;\n constructor(private readonly config: HttpFundingReporterConfig) {\n const url = new URL(config.baseUrl);\n assert([\"http:\", \"https:\"].includes(url.protocol) && !url.username && !url.password, \"Invalid report service URL.\");\n this.base = config.baseUrl.replace(/\\/+$/, \"\");\n this.fetcher = config.fetch ?? globalThis.fetch;\n assert(Number.isFinite(config.requestTimeoutMs ?? 30_000) && (config.requestTimeoutMs ?? 30_000) > 0, \"Invalid report timeout.\");\n }\n private async request(path: string, body?: unknown, signal?: AbortSignal): Promise<Record<string, unknown>> {\n throwIfAborted(signal);\n const timeout = AbortSignal.timeout(this.config.requestTimeoutMs ?? 30_000);\n try {\n const response = await this.fetcher(`${this.base}/api/swap/${path}`, {\n method: body ? \"POST\" : \"GET\", signal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n headers: { Accept: \"application/json\", ...(body ? { \"Content-Type\": \"application/json\" } : {}), ...(this.config.bearerToken ? { Authorization: `Bearer ${this.config.bearerToken}` } : {}) },\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n if (!response.ok) throw new ConfidentialSwapError(\"HTTP_ERROR\", `Funding report request failed (${response.status}).`, response.status);\n let result: unknown;\n try { result = await response.json(); } catch { throw new ConfidentialSwapError(\"INVALID_RESPONSE\", \"Invalid funding report JSON.\"); }\n responseAssert(result && typeof result === \"object\", \"Invalid funding report response.\");\n const envelope = result as Record<string, unknown>;\n responseAssert(envelope.code === 0 && envelope.data && typeof envelope.data === \"object\", \"Invalid funding report envelope.\");\n return envelope.data as Record<string, unknown>;\n } catch (error) {\n throwIfAborted(signal);\n if (timeout.aborted) throw new ConfidentialSwapError(\"TIMEOUT\", \"Funding report request timed out; reconcile before resubmitting.\");\n throw error;\n }\n }\n async report(s: ExecutionSnapshot, signal?: AbortSignal): Promise<string> {\n const plan = s.plan;\n const quoted = plan.swapQuote?.data as Partial<Quote> | undefined;\n assert(s.receipt, \"Cannot report without a funding receipt.\");\n const data = await this.request(\"report\", {\n sender: plan.request.sourceWallet.accountId, recipient: plan.request.recipients[0], from_hash: s.receipt.txHash,\n deposit_address: plan.depositQuote!.quote.depositAddress, from_token: quoted?.tokenIn?.address ?? plan.request.sourceToken.swapAddress ?? plan.request.sourceToken.contractAddress ?? plan.request.sourceToken.assetId,\n to_token: quoted?.tokenOut?.address ?? plan.route.fundingAsset.swapAddress ?? plan.route.fundingAsset.contractAddress ?? plan.route.fundingAsset.assetId,\n from_chain: quoted?.fromChain ?? plan.request.sourceWallet.chain, to_chain: quoted?.toChain ?? plan.swapRequest?.fundingToken.swapChain ?? normalizeChain(plan.route.fundingAsset.blockchain),\n amount_in: plan.request.amount, estimated_out: plan.fundingAmount, router: s.receipt.router ?? \"rhea\", is_cross_chain: plan.route.kind === \"CROSS_CHAIN_SWAP\",\n tx_type: \"confidential-batch-withdraw\", confidentiality: \"advanced\", ...(s.receipt.orderId ? { swapId: s.receipt.orderId } : {}),\n extra: { recipient_count: plan.request.recipients.length, funding_route: plan.route.kind, execution_id: s.id },\n }, signal);\n responseAssert((typeof data.id === \"number\" && Number.isSafeInteger(data.id) && data.id > 0) || (typeof data.id === \"string\" && /^\\d+$/.test(data.id)), \"Report returned no record id.\");\n return String(data.id);\n }\n async getStatus(recordId: string, _s: ExecutionSnapshot, signal?: AbortSignal): Promise<string> {\n const query = new URLSearchParams({ recordId: text(recordId, \"Record id\") });\n const data = await this.request(`order-status?${query}`, undefined, signal);\n return text(data.status ?? data.state, \"Funding status\");\n }\n}\nexport type { AssetRef, ChainRef };\n","export type ErrorCode =\n | \"INVALID_INPUT\" | \"INVALID_RESPONSE\" | \"HTTP_ERROR\" | \"UNAUTHORIZED\"\n | \"WALLET_CHANGED\" | \"MISSING_WALLET\" | \"QUOTE_EXPIRED\" | \"BUSY\"\n | \"CONFIRMATION_REQUIRED\" | \"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 throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) throw new ConfidentialSwapError(\"ABORTED\", \"Local operation cancelled; submitted transactions are not cancelled.\");\n}\n","import { assert } from \"./errors\";\nimport type { FundingRoute, Token } from \"./types\";\n\nconst aliases: Record<string, string> = { ethereum: \"eth\", arbitrum: \"arb\", avalanche: \"avax\", optimism: \"op\", polygon: \"pol\", bitcoin: \"btc\", solana: \"sol\", zcash: \"zec\", bnb: \"bsc\", \"bnb chain\": \"bsc\", hyperevm: \"hypercore\" };\nexport function normalizeChain(value: string): string { const chain = value.trim().toLowerCase(); return aliases[chain] ?? chain; }\nfunction contract(value?: string | null): string { const v = value?.trim() ?? \"\"; return /^0x/i.test(v) ? v.toLowerCase() : v; }\nfunction nativeNear(t: Token): boolean {\n return !t.assetId.startsWith(\"mca:\") && normalizeChain(t.blockchain) === \"near\" &&\n ([\"near\", \"nep141:near\"].includes(t.assetId) || t.contractAddress === \"near\" || Boolean(t.isNative && !t.contractAddress));\n}\nfunction matches(source: Token, registered: Token): boolean {\n if (normalizeChain(source.blockchain) !== normalizeChain(registered.blockchain)) return false;\n if (source.assetId && source.assetId === registered.assetId) return true;\n if (nativeNear(source)) return [\"nep141:wrap.near\", \"wrap.near\"].includes(registered.assetId) || registered.contractAddress === \"wrap.near\";\n const src = contract(source.contractAddress);\n const target = contract(registered.contractAddress);\n if (src && target) return src === target;\n return Boolean(source.isNative && !src && !target && source.symbol.toUpperCase() === registered.symbol.toUpperCase());\n}\nexport function resolveRegistryToken(token: Token, registry: readonly Token[]): Token | null {\n return registry.find((t) => matches(token, t)) ?? null;\n}\nexport function resolveFundingRoute(source: Token, registry: readonly Token[]): FundingRoute {\n const tokens = registry.filter((t, i) => t.blockchain && t.assetId && registry.findIndex((other) => normalizeChain(other.blockchain) === normalizeChain(t.blockchain) && (contract(other.contractAddress) || other.assetId) === (contract(t.contractAddress) || t.assetId)) === i);\n const direct = resolveRegistryToken(source, tokens);\n if (direct) return { kind: \"DIRECT\", fundingAsset: direct };\n const rank = (t: Token) => { const i = [\"USDC\", \"USDT\", \"USDT0\"].indexOf(t.symbol.toUpperCase()); return i < 0 ? 3 : i; };\n const prefer = (ts: Token[]) => [...ts].sort((a, b) => rank(a) - rank(b))[0];\n const same = prefer(tokens.filter((t) => normalizeChain(t.blockchain) === normalizeChain(source.blockchain)));\n if (same) return { kind: \"SAME_CHAIN_SWAP\", fundingAsset: same };\n const cross = prefer(tokens.filter((t) => normalizeChain(t.blockchain) === \"near\")) ?? prefer(tokens);\n assert(cross, \"No registry funding asset available.\");\n return { kind: \"CROSS_CHAIN_SWAP\", fundingAsset: cross };\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}\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}\nexport function availableForAsset(balances: readonly Balance[], assetId: string): string {\n const exact = balances.find((b) => b.tokenId === assetId);\n const entry = exact ?? balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${assetId}`));\n return raw(entry?.available ?? \"0\", \"Available balance\", true).toString();\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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/aggregation.ts","../src/errors.ts","../src/routing.ts","../src/utils.ts"],"sourcesContent":["import type { AssetRef, ChainRef, Quote, QuoteRequest, SwapClient } from \"@rhea-finance/cross-chain-aggregation-dex\";\nimport { assert, ConfidentialSwapError, responseAssert, throwIfAborted } from \"./errors\";\nimport { normalizeChain } from \"./routing\";\nimport { clone, raw, text } from \"./utils\";\nimport type { ExecutionSnapshot, FundingSwapAdapter, SwapFundingRequest, Token } from \"./types\";\n\nexport interface FundingReporter {\n report(snapshot: ExecutionSnapshot, signal?: AbortSignal): Promise<string>;\n getStatus(recordId: string, snapshot: ExecutionSnapshot, signal?: AbortSignal): Promise<string>;\n reconcileReport?(snapshot: ExecutionSnapshot, signal?: AbortSignal): Promise<string | undefined>;\n}\nexport interface AggregationAdapterConfig {\n /** Construct this client with reportMode: \"manual\" to avoid duplicate reports. */\n client: Pick<SwapClient, \"quote\" | \"buildSwap\" | \"executeSwap\">;\n reporter: FundingReporter;\n /** Explicit mapping avoids conflating registry asset IDs and aggregation token addresses. */\n mapAsset: (token: Token) => AssetRef;\n reconcileFunding?: FundingSwapAdapter[\"reconcileFunding\"];\n}\nfunction serialize(request: SwapFundingRequest, map: AggregationAdapterConfig[\"mapAsset\"]): QuoteRequest {\n const tokenIn = map(clone(request.sourceToken));\n const tokenOut = map(clone(request.fundingToken));\n assert(tokenIn.chain === request.wallet.chain, \"Aggregation source chain differs from the frozen wallet chain.\");\n text(tokenIn.address, \"Mapped source token address\"); text(tokenOut.address, \"Mapped funding token address\");\n return { fromChain: tokenIn.chain, toChain: tokenOut.chain, tokenIn, tokenOut, amountIn: request.amount, slippageBps: request.slippageBps, sender: request.wallet.accountId, recipient: request.recipient };\n}\nfunction equalAddress(a: string | undefined, b: string, chain: string): boolean {\n return /^\\d+$/.test(chain) ? a?.toLowerCase() === b.toLowerCase() : a === b;\n}\nexport function createAggregationFundingAdapter(config: AggregationAdapterConfig): FundingSwapAdapter {\n return {\n quote: async (request, signal) => {\n const quote = await config.client.quote(serialize(request, config.mapAsset), { signal });\n return { amountOut: quote.estimatedOut, minAmountOut: quote.minAmountOut, expiresAt: quote.expiresAt, data: clone(quote) };\n },\n execute: async (input, request, _id, signal) => {\n throwIfAborted(signal);\n const quote = clone(input.data) as Quote;\n const expected = serialize(request, config.mapAsset);\n responseAssert(quote.amountIn === request.amount && quote.fromChain === expected.fromChain && quote.toChain === expected.toChain\n && equalAddress(quote.buildContext.request.sender, request.wallet.accountId, expected.fromChain)\n && quote.buildContext.request.recipient === request.recipient\n && equalAddress(quote.tokenIn.address, expected.tokenIn.address, expected.fromChain)\n && equalAddress(quote.tokenOut.address, expected.tokenOut.address, expected.toChain)\n && equalAddress(quote.buildContext.request.tokenIn, expected.tokenIn.address, expected.fromChain)\n && equalAddress(quote.buildContext.request.tokenOut, expected.tokenOut.address, expected.toChain), \"Funding quote does not match the frozen execution request.\");\n const build = await config.client.buildSwap({ quote, signal });\n responseAssert(raw(build.minAmountOut) >= raw(input.minAmountOut), \"Built swap minimum output fell below its funding quote.\");\n responseAssert(build.fromChain === expected.fromChain && build.toChain === expected.toChain && build.amountIn === request.amount\n && equalAddress(build.tokenIn.address, expected.tokenIn.address, expected.fromChain)\n && equalAddress(build.tokenOut.address, expected.tokenOut.address, expected.toChain), \"Built swap asset or chain differs from its funding request.\");\n const result = await config.client.executeSwap({ build, signal, waitFor: \"submitted\" });\n responseAssert(result.txHash, \"Funding swap did not return a source transaction hash.\");\n return { txHash: result.txHash, orderId: result.orderId, router: result.router };\n },\n report: config.reporter.report.bind(config.reporter),\n getStatus: config.reporter.getStatus.bind(config.reporter),\n reconcileReport: config.reporter.reconcileReport?.bind(config.reporter),\n reconcileFunding: config.reconcileFunding,\n };\n}\nexport interface HttpFundingReporterConfig {\n baseUrl: string;\n bearerToken?: string;\n fetch?: typeof fetch;\n requestTimeoutMs?: number;\n}\nexport class HttpFundingReporter implements FundingReporter {\n private readonly base: string;\n private readonly fetcher: typeof fetch;\n constructor(private readonly config: HttpFundingReporterConfig) {\n const url = new URL(config.baseUrl);\n assert([\"http:\", \"https:\"].includes(url.protocol) && !url.username && !url.password, \"Invalid report service URL.\");\n this.base = config.baseUrl.replace(/\\/+$/, \"\");\n this.fetcher = config.fetch ?? globalThis.fetch;\n assert(Number.isFinite(config.requestTimeoutMs ?? 30_000) && (config.requestTimeoutMs ?? 30_000) > 0, \"Invalid report timeout.\");\n }\n private async request(path: string, body?: unknown, signal?: AbortSignal): Promise<Record<string, unknown>> {\n throwIfAborted(signal);\n const timeout = AbortSignal.timeout(this.config.requestTimeoutMs ?? 30_000);\n try {\n const response = await this.fetcher(`${this.base}/api/swap/${path}`, {\n method: body ? \"POST\" : \"GET\", signal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n headers: { Accept: \"application/json\", ...(body ? { \"Content-Type\": \"application/json\" } : {}), ...(this.config.bearerToken ? { Authorization: `Bearer ${this.config.bearerToken}` } : {}) },\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n if (!response.ok) throw new ConfidentialSwapError(\"HTTP_ERROR\", `Funding report request failed (${response.status}).`, response.status);\n let result: unknown;\n try { result = await response.json(); } catch { throw new ConfidentialSwapError(\"INVALID_RESPONSE\", \"Invalid funding report JSON.\"); }\n responseAssert(result && typeof result === \"object\", \"Invalid funding report response.\");\n const envelope = result as Record<string, unknown>;\n responseAssert(envelope.code === 0 && envelope.data && typeof envelope.data === \"object\", \"Invalid funding report envelope.\");\n return envelope.data as Record<string, unknown>;\n } catch (error) {\n throwIfAborted(signal);\n if (timeout.aborted) throw new ConfidentialSwapError(\"TIMEOUT\", \"Funding report request timed out; reconcile before resubmitting.\");\n throw error;\n }\n }\n async report(s: ExecutionSnapshot, signal?: AbortSignal): Promise<string> {\n const plan = s.plan;\n const quoted = plan.swapQuote?.data as Partial<Quote> | undefined;\n assert(s.receipt, \"Cannot report without a funding receipt.\");\n const data = await this.request(\"report\", {\n sender: plan.request.sourceWallet.accountId, recipient: plan.request.recipients[0], from_hash: s.receipt.txHash,\n deposit_address: plan.depositQuote!.quote.depositAddress, from_token: quoted?.tokenIn?.address ?? plan.request.sourceToken.swapAddress ?? plan.request.sourceToken.contractAddress ?? plan.request.sourceToken.assetId,\n to_token: quoted?.tokenOut?.address ?? plan.route.fundingAsset.swapAddress ?? plan.route.fundingAsset.contractAddress ?? plan.route.fundingAsset.assetId,\n from_chain: quoted?.fromChain ?? plan.request.sourceWallet.chain, to_chain: quoted?.toChain ?? plan.swapRequest?.fundingToken.swapChain ?? normalizeChain(plan.route.fundingAsset.blockchain),\n amount_in: plan.request.amount, estimated_out: plan.fundingAmount, router: s.receipt.router ?? \"rhea\", is_cross_chain: plan.route.kind === \"CROSS_CHAIN_SWAP\",\n tx_type: \"confidential-batch-withdraw\", confidentiality: \"advanced\", ...(s.receipt.orderId ? { swapId: s.receipt.orderId } : {}),\n extra: { recipient_count: plan.request.recipients.length, funding_route: plan.route.kind, execution_id: s.id },\n }, signal);\n responseAssert((typeof data.id === \"number\" && Number.isSafeInteger(data.id) && data.id > 0) || (typeof data.id === \"string\" && /^\\d+$/.test(data.id)), \"Report returned no record id.\");\n return String(data.id);\n }\n async getStatus(recordId: string, _s: ExecutionSnapshot, signal?: AbortSignal): Promise<string> {\n const query = new URLSearchParams({ recordId: text(recordId, \"Record id\") });\n const data = await this.request(`order-status?${query}`, undefined, signal);\n return text(data.status ?? data.state, \"Funding status\");\n }\n}\nexport type { AssetRef, ChainRef };\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) throw new ConfidentialSwapError(\"ABORTED\", \"Local operation cancelled; submitted transactions are not cancelled.\");\n}\n","import { assert } from \"./errors\";\nimport type { FundingRoute, Token } from \"./types\";\n\nconst aliases: Record<string, string> = { ethereum: \"eth\", arbitrum: \"arb\", avalanche: \"avax\", optimism: \"op\", polygon: \"pol\", bitcoin: \"btc\", solana: \"sol\", zcash: \"zec\", bnb: \"bsc\", \"bnb chain\": \"bsc\", hyperevm: \"hypercore\" };\nexport function normalizeChain(value: string): string { const chain = value.trim().toLowerCase(); return aliases[chain] ?? chain; }\nfunction contract(value?: string | null): string { const v = value?.trim() ?? \"\"; return /^0x/i.test(v) ? v.toLowerCase() : v; }\nfunction nativeNear(t: Token): boolean {\n return !t.assetId.startsWith(\"mca:\") && normalizeChain(t.blockchain) === \"near\" &&\n ([\"near\", \"nep141:near\"].includes(t.assetId) || t.contractAddress === \"near\" || Boolean(t.isNative && !t.contractAddress));\n}\nfunction matches(source: Token, registered: Token): boolean {\n if (normalizeChain(source.blockchain) !== normalizeChain(registered.blockchain)) return false;\n if (source.assetId && source.assetId === registered.assetId) return true;\n if (nativeNear(source)) return [\"nep141:wrap.near\", \"wrap.near\"].includes(registered.assetId) || registered.contractAddress === \"wrap.near\";\n const src = contract(source.contractAddress);\n const target = contract(registered.contractAddress);\n if (src && target) return src === target;\n return Boolean(source.isNative && !src && !target && source.symbol.toUpperCase() === registered.symbol.toUpperCase());\n}\nexport function resolveRegistryToken(token: Token, registry: readonly Token[]): Token | null {\n return registry.find((t) => matches(token, t)) ?? null;\n}\nexport function resolveFundingRoute(source: Token, registry: readonly Token[]): FundingRoute {\n const tokens = registry.filter((t, i) => t.blockchain && t.assetId && registry.findIndex((other) => normalizeChain(other.blockchain) === normalizeChain(t.blockchain) && (contract(other.contractAddress) || other.assetId) === (contract(t.contractAddress) || t.assetId)) === i);\n const direct = resolveRegistryToken(source, tokens);\n if (direct) return { kind: \"DIRECT\", fundingAsset: direct };\n const rank = (t: Token) => { const i = [\"USDC\", \"USDT\", \"USDT0\"].indexOf(t.symbol.toUpperCase()); return i < 0 ? 3 : i; };\n const prefer = (ts: Token[]) => [...ts].sort((a, b) => rank(a) - rank(b))[0];\n const same = prefer(tokens.filter((t) => normalizeChain(t.blockchain) === normalizeChain(source.blockchain)));\n if (same) return { kind: \"SAME_CHAIN_SWAP\", fundingAsset: same };\n const cross = prefer(tokens.filter((t) => normalizeChain(t.blockchain) === \"near\")) ?? prefer(tokens);\n assert(cross, \"No registry funding asset available.\");\n return { kind: \"CROSS_CHAIN_SWAP\", fundingAsset: cross };\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}\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}\nexport function availableForAsset(balances: readonly Balance[], assetId: string): string {\n const exact = balances.find((b) => b.tokenId === assetId);\n const entry = exact ?? balances.find((b) => b.tokenId.startsWith(\"imt:\") && b.tokenId.endsWith(`:${assetId}`));\n return raw(entry?.available ?? \"0\", \"Available balance\", true).toString();\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"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import { SwapClient, AssetRef } from '@rhea-finance/cross-chain-aggregation-dex';
2
2
  export { AssetRef, ChainRef } from '@rhea-finance/cross-chain-aggregation-dex';
3
- import { E as ExecutionSnapshot, T as Token, F as FundingSwapAdapter } from './types-Bq8OZRUK.cjs';
3
+ import { E as ExecutionSnapshot, T as Token, F as FundingSwapAdapter } from './types-DaD5YFS0.cjs';
4
4
 
5
5
  interface FundingReporter {
6
6
  report(snapshot: ExecutionSnapshot, signal?: AbortSignal): Promise<string>;