@bujius/checkout-sdk 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +924 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +133 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +891 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -4
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/program/pda.ts","../src/program/idl.json","../src/program/config.ts","../src/program/create-split.ts","../src/core/amounts.ts","../src/core/reference.ts","../src/core/url.ts","../src/core/split-math.ts","../src/strategies/transfers.ts","../src/strategies/program.ts","../src/verify/find-payment.ts","../src/verify/verify-payment.ts","../src/server/handler.ts"],"sourcesContent":["// Public exports — append-only; each track appends its own lines (PLAN.md §4).\nexport { BujiusCheckoutError, ErrorCode, isBujiusCheckoutError } from './errors';\nexport { findSplitConfig, PROGRAM_ID } from './program/pda';\nexport { fetchSplitConfig } from './program/config';\nexport type { Recipient, SplitConfig } from './program/config';\nexport { buildCreateSplit } from './program/create-split';\n// Track B — core helpers (B1)\nexport { toBaseUnits, fromBaseUnits } from './core/amounts';\nexport { newReference } from './core/reference';\nexport { paymentUrl } from './core/url';\nexport { computeSplit } from './core/split-math';\nexport { buildSplitPayment } from './strategies/transfers';\nexport type { PaymentStrategy } from './strategies/transfers';\nexport { findPayment } from './verify/find-payment';\nexport { verifySplitPayment } from './verify/verify-payment';\nexport type { Verification, VerifiedLeg } from './verify/verify-payment';\n// Track B — the transaction request handler (B2)\nexport { createTransactionRequestHandler } from './server/handler';\nexport type {\n ResolvedPayment,\n ResolveResult,\n TransactionRequestOptions,\n} from './server/handler';\n","// Typed error codes — contracts §3. Never a sentence: the caller maps a code to its copy.\n// Each track appends its own codes; existing codes never change meaning.\nexport const ErrorCode = {\n ORDER_NOT_FOUND: 'ORDER_NOT_FOUND',\n ORDER_EXPIRED: 'ORDER_EXPIRED',\n ORDER_PAID: 'ORDER_PAID',\n ORDER_HELD: 'ORDER_HELD',\n INVALID_ACCOUNT: 'INVALID_ACCOUNT',\n INVALID_AMOUNT: 'INVALID_AMOUNT',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n RPC_UNAVAILABLE: 'RPC_UNAVAILABLE',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\nexport class BujiusCheckoutError extends Error {\n readonly code: ErrorCode;\n\n constructor(code: ErrorCode, options?: { cause?: unknown }) {\n super(code, options);\n this.name = 'BujiusCheckoutError';\n this.code = code;\n }\n}\n\nexport function isBujiusCheckoutError(value: unknown): value is BujiusCheckoutError {\n return value instanceof BujiusCheckoutError;\n}\n","import { PublicKey } from '@solana/web3.js';\nimport idl from './idl.json';\n\nexport const PROGRAM_ID = new PublicKey(idl.address);\n\n/** The address of a merchant's split config. Seeds: [\"split\", authority, id as u16 LE]. */\nexport function findSplitConfig(authority: PublicKey, id: number): PublicKey {\n const idBytes = new Uint8Array(2);\n new DataView(idBytes.buffer).setUint16(0, id, true);\n return PublicKey.findProgramAddressSync(\n [new TextEncoder().encode('split'), authority.toBytes(), idBytes],\n PROGRAM_ID,\n )[0];\n}\n","{\n \"address\": \"LNv2EvYZFN1fBJeQPDGffRxVYPMCGpa99yCcWDSDdjN\",\n \"metadata\": {\n \"name\": \"bujius_checkout\",\n \"version\": \"0.1.0\",\n \"spec\": \"0.1.0\",\n \"description\": \"Created with Anchor\"\n },\n \"instructions\": [\n {\n \"name\": \"create_split\",\n \"discriminator\": [\n 196,\n 195,\n 250,\n 188,\n 17,\n 255,\n 10,\n 151\n ],\n \"accounts\": [\n {\n \"name\": \"authority\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"config\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 115,\n 112,\n 108,\n 105,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"authority\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"id\"\n }\n ]\n }\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"Classic SPL Token mint only (Token-2022 is out of scope).\"\n ]\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"id\",\n \"type\": \"u16\"\n },\n {\n \"name\": \"recipients\",\n \"type\": {\n \"vec\": {\n \"defined\": {\n \"name\": \"Recipient\"\n }\n }\n }\n }\n ]\n },\n {\n \"name\": \"pay\",\n \"discriminator\": [\n 119,\n 18,\n 216,\n 65,\n 192,\n 117,\n 122,\n 220\n ],\n \"accounts\": [\n {\n \"name\": \"payer\",\n \"signer\": true\n },\n {\n \"name\": \"payer_token\",\n \"writable\": true\n },\n {\n \"name\": \"config\"\n },\n {\n \"name\": \"mint\"\n },\n {\n \"name\": \"merchant_token\",\n \"writable\": true\n },\n {\n \"name\": \"reference\"\n },\n {\n \"name\": \"token_program\",\n \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n }\n ],\n \"args\": [\n {\n \"name\": \"amount\",\n \"type\": \"u64\"\n }\n ]\n }\n ],\n \"accounts\": [\n {\n \"name\": \"SplitConfig\",\n \"discriminator\": [\n 49,\n 201,\n 50,\n 228,\n 22,\n 142,\n 12,\n 222\n ]\n }\n ],\n \"events\": [\n {\n \"name\": \"SplitCreated\",\n \"discriminator\": [\n 87,\n 61,\n 160,\n 84,\n 73,\n 204,\n 93,\n 140\n ]\n },\n {\n \"name\": \"SplitPaid\",\n \"discriminator\": [\n 223,\n 17,\n 5,\n 250,\n 228,\n 37,\n 72,\n 80\n ]\n }\n ],\n \"errors\": [\n {\n \"code\": 6000,\n \"name\": \"InvalidRecipientCount\",\n \"msg\": \"A split config needs between 1 and 4 recipients\"\n },\n {\n \"code\": 6001,\n \"name\": \"ZeroBps\",\n \"msg\": \"Every recipient needs at least 1 bps\"\n },\n {\n \"code\": 6002,\n \"name\": \"SplitOverflow\",\n \"msg\": \"The recipients' bps add up to more than 10 000\"\n },\n {\n \"code\": 6003,\n \"name\": \"DuplicateRecipient\",\n \"msg\": \"Recipient wallets must be distinct and different from the merchant\"\n },\n {\n \"code\": 6004,\n \"name\": \"ZeroAmount\",\n \"msg\": \"The amount must be greater than zero\"\n },\n {\n \"code\": 6005,\n \"name\": \"MintMismatch\",\n \"msg\": \"The mint does not match the split config's mint\"\n },\n {\n \"code\": 6006,\n \"name\": \"BadTokenAccount\",\n \"msg\": \"A token account is not the expected associated token account\"\n },\n {\n \"code\": 6007,\n \"name\": \"RecipientCountMismatch\",\n \"msg\": \"The number of remaining accounts does not match the recipients\"\n },\n {\n \"code\": 6008,\n \"name\": \"MathOverflow\",\n \"msg\": \"Arithmetic overflow\"\n }\n ],\n \"types\": [\n {\n \"name\": \"Recipient\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"bps\",\n \"type\": \"u16\"\n }\n ]\n }\n },\n {\n \"name\": \"SplitConfig\",\n \"docs\": [\n \"One per merchant per `id`; immutable after creation.\"\n ],\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"authority\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"id\",\n \"type\": \"u16\"\n },\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"recipients\",\n \"type\": {\n \"vec\": {\n \"defined\": {\n \"name\": \"Recipient\"\n }\n }\n }\n },\n {\n \"name\": \"bump\",\n \"type\": \"u8\"\n }\n ]\n }\n },\n {\n \"name\": \"SplitCreated\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"config\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"authority\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"recipients\",\n \"type\": {\n \"vec\": {\n \"defined\": {\n \"name\": \"Recipient\"\n }\n }\n }\n }\n ]\n }\n },\n {\n \"name\": \"SplitPaid\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"config\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"payer\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"reference\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"amount\",\n \"type\": \"u64\"\n },\n {\n \"name\": \"merchant_amount\",\n \"type\": \"u64\"\n },\n {\n \"name\": \"shares\",\n \"type\": {\n \"vec\": \"u64\"\n }\n },\n {\n \"name\": \"ts\",\n \"type\": \"i64\"\n }\n ]\n }\n }\n ]\n}","import { BorshAccountsCoder, type Idl } from '@coral-xyz/anchor';\nimport { PublicKey, type Connection } from '@solana/web3.js';\nimport { BujiusCheckoutError, ErrorCode } from '../errors';\nimport idl from './idl.json';\nimport { PROGRAM_ID } from './pda';\n\nexport interface Recipient {\n wallet: PublicKey;\n bps: number;\n}\n\nexport interface SplitConfig {\n address: PublicKey;\n authority: PublicKey;\n id: number;\n mint: PublicKey;\n recipients: Recipient[];\n}\n\nconst coder = new BorshAccountsCoder(idl as Idl);\n\n/** Reads and decodes a split config; throws CONFIG_NOT_FOUND if it is not ours or absent. */\nexport async function fetchSplitConfig(\n connection: Connection,\n address: PublicKey,\n): Promise<SplitConfig> {\n let info;\n try {\n info = await connection.getAccountInfo(address, 'confirmed');\n } catch {\n throw new BujiusCheckoutError(ErrorCode.RPC_UNAVAILABLE);\n }\n if (!info || !info.owner.equals(PROGRAM_ID)) {\n throw new BujiusCheckoutError(ErrorCode.CONFIG_NOT_FOUND);\n }\n const decoded = coder.decode('SplitConfig', info.data);\n return {\n address,\n authority: decoded.authority,\n id: decoded.id,\n mint: decoded.mint,\n recipients: decoded.recipients.map((r: { wallet: PublicKey; bps: number }) => ({\n wallet: r.wallet,\n bps: r.bps,\n })),\n };\n}\n","import { BorshInstructionCoder, type Idl } from '@coral-xyz/anchor';\nimport {\n createAssociatedTokenAccountIdempotentInstruction,\n getAssociatedTokenAddressSync,\n} from '@solana/spl-token';\nimport {\n SystemProgram,\n Transaction,\n TransactionInstruction,\n type Connection,\n type PublicKey,\n} from '@solana/web3.js';\nimport type { Recipient } from './config';\nimport idl from './idl.json';\nimport { findSplitConfig, PROGRAM_ID } from './pda';\n\nconst coder = new BorshInstructionCoder(idl as Idl);\n\n/**\n * Unsigned transaction: creates every destination ATA (merchant and recipients, paid by the\n * merchant), then `create_split`. Fee payer = authority.\n */\nexport async function buildCreateSplit(\n connection: Connection,\n authority: PublicKey,\n id: number,\n mint: PublicKey,\n recipients: Recipient[],\n): Promise<Transaction> {\n const tx = new Transaction();\n for (const owner of [authority, ...recipients.map((r) => r.wallet)]) {\n tx.add(\n createAssociatedTokenAccountIdempotentInstruction(\n authority,\n getAssociatedTokenAddressSync(mint, owner),\n owner,\n mint,\n ),\n );\n }\n tx.add(\n new TransactionInstruction({\n programId: PROGRAM_ID,\n keys: [\n { pubkey: authority, isSigner: true, isWritable: true },\n { pubkey: findSplitConfig(authority, id), isSigner: false, isWritable: true },\n { pubkey: mint, isSigner: false, isWritable: false },\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\n ],\n data: coder.encode('create_split', { id, recipients }),\n }),\n );\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');\n tx.feePayer = authority;\n tx.recentBlockhash = blockhash;\n tx.lastValidBlockHeight = lastValidBlockHeight;\n return tx;\n}\n","import { BujiusCheckoutError, ErrorCode } from '../errors';\n\n/**\n * Parses a decimal string into base units. Rejects negatives, exponents, empty\n * strings, and more fractional digits than `decimals`.\n */\nexport function toBaseUnits(decimal: string, decimals: number): bigint {\n if (typeof decimal !== 'string' || decimal.length === 0) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_AMOUNT);\n }\n if (!Number.isInteger(decimals) || decimals < 0) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_AMOUNT);\n }\n // No sign, exponent, whitespace, or non-decimal characters.\n if (!/^\\d+(\\.\\d+)?$/.test(decimal)) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_AMOUNT);\n }\n\n const [wholePart, fractionPart = ''] = decimal.split('.');\n if (fractionPart.length > decimals) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_AMOUNT);\n }\n\n return BigInt(`${wholePart}${fractionPart.padEnd(decimals, '0')}`);\n}\n\n/** Formats base units as a decimal string; never uses scientific notation. */\nexport function fromBaseUnits(amount: bigint, decimals: number): string {\n if (typeof amount !== 'bigint' || amount < 0n) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_AMOUNT);\n }\n if (!Number.isInteger(decimals) || decimals < 0) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_AMOUNT);\n }\n\n const raw = amount.toString();\n if (decimals === 0) {\n return raw;\n }\n\n const padded = raw.padStart(decimals + 1, '0');\n const whole = padded.slice(0, -decimals);\n const fraction = padded.slice(-decimals);\n const trimmedFraction = fraction.replace(/0+$/, '');\n return trimmedFraction.length === 0 ? whole : `${whole}.${trimmedFraction}`;\n}\n","import { Keypair, type PublicKey } from '@solana/web3.js';\n\n/** A fresh public key used as the Solana Pay reference for one payment. */\nexport function newReference(): PublicKey {\n return Keypair.generate().publicKey;\n}\n","import { encodeURL } from '@solana/pay';\n\n/**\n * Builds a Solana Pay transaction-request URL (`solana:…`) from the handler's HTTPS URL.\n */\nexport function paymentUrl(handlerHttpsUrl: string): string {\n return encodeURL({ link: new URL(handlerHttpsUrl) }).toString();\n}\n","import { BujiusCheckoutError, ErrorCode } from '../errors';\n\n/**\n * One rule, three places (contracts §2): share[i] = floor(amount × bps[i] / 10_000);\n * merchant gets the remainder. bigint intermediates cover the u64 × bps product.\n * Bps that are negative, fractional or sum above 10_000 throw `CONFIG_NOT_FOUND`, so\n * merchant + Σ share = amount never holds through a negative merchant amount.\n */\nexport function computeSplit(\n amount: bigint,\n bps: readonly number[],\n): { shares: bigint[]; merchant: bigint } {\n if (amount < 0n) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_AMOUNT);\n }\n const validBps = bps.every((b) => Number.isInteger(b) && b >= 0);\n if (!validBps || bps.reduce((total, b) => total + b, 0) > 10_000) {\n throw new BujiusCheckoutError(ErrorCode.CONFIG_NOT_FOUND);\n }\n const shares = bps.map((b) => (amount * BigInt(b)) / 10_000n);\n let sum = 0n;\n for (const share of shares) {\n sum += share;\n }\n return { shares, merchant: amount - sum };\n}\n","import {\n createAssociatedTokenAccountIdempotentInstruction,\n createTransferCheckedInstruction,\n getAssociatedTokenAddressSync,\n unpackMint,\n} from '@solana/spl-token';\nimport { PublicKey, Transaction, type Connection } from '@solana/web3.js';\nimport { computeSplit } from '../core/split-math';\nimport { BujiusCheckoutError, ErrorCode } from '../errors';\nimport type { SplitConfig } from '../program/config';\nimport { buildProgramPayment } from './program';\n\nexport type PaymentStrategy = 'program' | 'transfers';\n\nconst U64_MAX = 18_446_744_073_709_551_615n;\n\n/**\n * Builds an unsigned legacy split payment. Fee payer = payer; blockhash at `confirmed`.\n * `'transfers'` is implemented here; `'program'` lives in `program.ts` (A4).\n * An amount outside 1..=u64::MAX throws `INVALID_AMOUNT` for either strategy.\n * A payer who is also a leg's wallet throws `INVALID_ACCOUNT` for either strategy: its balance\n * would not rise by that leg's amount, so the verifier could never mark the payment paid.\n * An off-curve payer throws `INVALID_ACCOUNT` too: it has no private key to sign with.\n */\nexport async function buildSplitPayment(\n connection: Connection,\n config: SplitConfig,\n payer: PublicKey,\n amount: bigint,\n reference: PublicKey,\n strategy: PaymentStrategy,\n): Promise<Transaction> {\n if (amount <= 0n || amount > U64_MAX) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_AMOUNT);\n }\n if (\n !PublicKey.isOnCurve(payer) ||\n payer.equals(config.authority) ||\n config.recipients.some((r) => r.wallet.equals(payer))\n ) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_ACCOUNT);\n }\n if (strategy === 'program') {\n return buildProgramPayment(connection, config, payer, amount, reference);\n }\n if (strategy !== 'transfers') {\n throw new Error(`unknown payment strategy: ${String(strategy)}`);\n }\n return buildTransfersPayment(connection, config, payer, amount, reference);\n}\n\nasync function buildTransfersPayment(\n connection: Connection,\n config: SplitConfig,\n payer: PublicKey,\n amount: bigint,\n reference: PublicKey,\n): Promise<Transaction> {\n const { shares, merchant } = computeSplit(\n amount,\n config.recipients.map((r) => r.bps),\n );\n\n const legs: { wallet: PublicKey; amount: bigint }[] = [];\n for (let i = 0; i < config.recipients.length; i++) {\n const share = shares[i]!;\n if (share > 0n) {\n legs.push({ wallet: config.recipients[i]!.wallet, amount: share });\n }\n }\n if (merchant > 0n) {\n legs.push({ wallet: config.authority, amount: merchant });\n }\n\n // A leg's wallet may be a PDA or a multisig vault: contracts §1 has no on-curve rule.\n const ataOf = (wallet: PublicKey) =>\n getAssociatedTokenAddressSync(config.mint, wallet, true);\n const destAtas = legs.map((leg) => ataOf(leg.wallet));\n const source = ataOf(payer);\n\n let infos;\n try {\n infos = await connection.getMultipleAccountsInfo(\n [...destAtas, config.mint, source],\n 'confirmed',\n );\n } catch {\n throw new BujiusCheckoutError(ErrorCode.RPC_UNAVAILABLE);\n }\n\n const mintInfo = infos[destAtas.length];\n const sourceInfo = infos[destAtas.length + 1];\n if (!mintInfo || !sourceInfo) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_ACCOUNT);\n }\n let decimals: number;\n try {\n decimals = unpackMint(config.mint, mintInfo).decimals;\n } catch (cause) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_ACCOUNT, { cause });\n }\n\n const tx = new Transaction();\n for (let i = 0; i < destAtas.length; i++) {\n if (infos[i] == null) {\n const leg = legs[i]!;\n const ata = destAtas[i]!;\n tx.add(\n createAssociatedTokenAccountIdempotentInstruction(\n payer,\n ata,\n leg.wallet,\n config.mint,\n ),\n );\n }\n }\n\n let firstTransfer = true;\n for (let i = 0; i < legs.length; i++) {\n const leg = legs[i]!;\n const destination = destAtas[i]!;\n const ix = createTransferCheckedInstruction(\n source,\n config.mint,\n destination,\n payer,\n leg.amount,\n decimals,\n );\n if (firstTransfer) {\n ix.keys.push({ pubkey: reference, isSigner: false, isWritable: false });\n firstTransfer = false;\n }\n tx.add(ix);\n }\n\n let blockhash: string;\n let lastValidBlockHeight: number;\n try {\n ({ blockhash, lastValidBlockHeight } =\n await connection.getLatestBlockhash('confirmed'));\n } catch {\n throw new BujiusCheckoutError(ErrorCode.RPC_UNAVAILABLE);\n }\n tx.feePayer = payer;\n tx.recentBlockhash = blockhash;\n tx.lastValidBlockHeight = lastValidBlockHeight;\n return tx;\n}\n","import anchor, { BorshInstructionCoder, type Idl } from '@coral-xyz/anchor';\nimport {\n createAssociatedTokenAccountIdempotentInstruction,\n getAssociatedTokenAddressSync,\n TOKEN_PROGRAM_ID,\n} from '@solana/spl-token';\nimport {\n Transaction,\n TransactionInstruction,\n type Connection,\n type PublicKey,\n} from '@solana/web3.js';\nimport { computeSplit } from '../core/split-math';\nimport { BujiusCheckoutError, ErrorCode } from '../errors';\nimport type { SplitConfig } from '../program/config';\nimport idl from '../program/idl.json';\nimport { PROGRAM_ID } from '../program/pda';\n\n// Node's ESM loader cannot see `BN` as a named export of this CommonJS package.\nconst { BN } = anchor;\nconst coder = new BorshInstructionCoder(idl as Idl);\n\n/**\n * The `'program'` strategy: an idempotent ATA create for each missing destination that\n * receives funds, then `pay`. The program creates no account itself. Amount and payer are\n * validated by `buildSplitPayment` before this runs.\n */\nexport async function buildProgramPayment(\n connection: Connection,\n config: SplitConfig,\n payer: PublicKey,\n amount: bigint,\n reference: PublicKey,\n): Promise<Transaction> {\n const { shares, merchant } = computeSplit(\n amount,\n config.recipients.map((r) => r.bps),\n );\n\n const ataOf = (wallet: PublicKey) =>\n getAssociatedTokenAddressSync(config.mint, wallet, true);\n const merchantToken = ataOf(config.authority);\n const recipientAtas = config.recipients.map((r) => ataOf(r.wallet));\n const source = ataOf(payer);\n\n // Destinations that receive funds (a zero leg is skipped by the program)\n const funded = [\n ...config.recipients\n .map((r, i) => ({ wallet: r.wallet, ata: recipientAtas[i]!, amount: shares[i]! }))\n .filter((leg) => leg.amount > 0n),\n ...(merchant > 0n\n ? [{ wallet: config.authority, ata: merchantToken, amount: merchant }]\n : []),\n ];\n\n let infos;\n try {\n infos = await connection.getMultipleAccountsInfo(\n [...funded.map((leg) => leg.ata), source],\n 'confirmed',\n );\n } catch {\n throw new BujiusCheckoutError(ErrorCode.RPC_UNAVAILABLE);\n }\n if (!infos[funded.length]) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_ACCOUNT);\n }\n\n const tx = new Transaction();\n for (let i = 0; i < funded.length; i++) {\n if (infos[i] == null) {\n const leg = funded[i]!;\n tx.add(\n createAssociatedTokenAccountIdempotentInstruction(payer, leg.ata, leg.wallet, config.mint),\n );\n }\n }\n\n tx.add(\n new TransactionInstruction({\n programId: PROGRAM_ID,\n keys: [\n { pubkey: payer, isSigner: true, isWritable: false },\n { pubkey: source, isSigner: false, isWritable: true },\n { pubkey: config.address, isSigner: false, isWritable: false },\n { pubkey: config.mint, isSigner: false, isWritable: false },\n { pubkey: merchantToken, isSigner: false, isWritable: true },\n { pubkey: reference, isSigner: false, isWritable: false },\n { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n // remaining accounts, in config.recipients order\n ...recipientAtas.map((pubkey) => ({ pubkey, isSigner: false, isWritable: true })),\n ],\n data: coder.encode('pay', { amount: new BN(amount.toString()) }),\n }),\n );\n\n let blockhash: string;\n let lastValidBlockHeight: number;\n try {\n ({ blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed'));\n } catch {\n throw new BujiusCheckoutError(ErrorCode.RPC_UNAVAILABLE);\n }\n tx.feePayer = payer;\n tx.recentBlockhash = blockhash;\n tx.lastValidBlockHeight = lastValidBlockHeight;\n return tx;\n}\n","import type { Connection, PublicKey } from '@solana/web3.js';\nimport { BujiusCheckoutError, ErrorCode } from '../errors';\n\n/**\n * The first successful signature that mentions `reference`, at `confirmed`, or `null`.\n * Finding a signature does not mean the amount is right: only `verifySplitPayment` decides.\n */\nexport async function findPayment(\n connection: Connection,\n reference: PublicKey,\n): Promise<string | null> {\n let signatures;\n try {\n signatures = await connection.getSignaturesForAddress(reference, undefined, 'confirmed');\n } catch {\n throw new BujiusCheckoutError(ErrorCode.RPC_UNAVAILABLE);\n }\n // Newest first: the earliest successful one is the last of them\n const successful = signatures.filter((s) => s.err === null);\n return successful.length > 0 ? successful[successful.length - 1]!.signature : null;\n}\n","import type { Connection, ParsedTransactionWithMeta, PublicKey } from '@solana/web3.js';\nimport { computeSplit } from '../core/split-math';\nimport { BujiusCheckoutError, ErrorCode } from '../errors';\nimport type { SplitConfig } from '../program/config';\n\nexport interface VerifiedLeg {\n wallet: PublicKey;\n /** What the wallet's token balance of `config.mint` actually rose by. */\n amount: bigint;\n}\n\nexport interface Verification {\n status: 'paid' | 'paid_late' | 'invalid';\n reason?: string;\n /** Recipients in config order, then the merchant. */\n legs: VerifiedLeg[];\n}\n\ntype TokenBalance = NonNullable<\n NonNullable<ParsedTransactionWithMeta['meta']>['preTokenBalances']\n>[number];\n\n/** Sum of the owner's balances of `mint`, in base units. */\nfunction totals(balances: readonly TokenBalance[] | null | undefined, mint: string) {\n const byOwner = new Map<string, bigint>();\n for (const b of balances ?? []) {\n if (b.mint !== mint || !b.owner) continue;\n byOwner.set(b.owner, (byOwner.get(b.owner) ?? 0n) + BigInt(b.uiTokenAmount.amount));\n }\n return byOwner;\n}\n\n/**\n * Judges a transaction by balances, not instructions, so both strategies pass: it succeeded,\n * the reference is among its account keys, and the balance of the merchant and of each\n * recipient (in `config.mint`) rose by exactly `computeSplit(amount)`. A `blockTime` after\n * `expiresAt` is `paid_late`. The program guarantees the split; this guarantees the amount.\n */\nexport async function verifySplitPayment(\n connection: Connection,\n signature: string,\n config: SplitConfig,\n amount: bigint,\n reference: PublicKey,\n expiresAt?: Date,\n): Promise<Verification> {\n const expected = computeSplit(\n amount,\n config.recipients.map((r) => r.bps),\n );\n const wallets = [...config.recipients.map((r) => r.wallet), config.authority];\n const expectedAmounts = [...expected.shares, expected.merchant];\n const invalid = (reason: string, legs: VerifiedLeg[] = []): Verification => ({\n status: 'invalid',\n reason,\n legs,\n });\n\n let tx: ParsedTransactionWithMeta | null;\n try {\n tx = await connection.getParsedTransaction(signature, {\n commitment: 'confirmed',\n maxSupportedTransactionVersion: 0,\n });\n } catch {\n throw new BujiusCheckoutError(ErrorCode.RPC_UNAVAILABLE);\n }\n if (!tx || !tx.meta) return invalid('transaction not found');\n if (tx.meta.err !== null) return invalid('transaction failed');\n\n const referenceKey = reference.toBase58();\n if (!tx.transaction.message.accountKeys.some((k) => String(k.pubkey) === referenceKey)) {\n return invalid('reference not in the transaction');\n }\n\n const mint = config.mint.toBase58();\n const pre = totals(tx.meta.preTokenBalances, mint);\n const post = totals(tx.meta.postTokenBalances, mint);\n const legs: VerifiedLeg[] = wallets.map((wallet) => {\n const key = wallet.toBase58();\n return { wallet, amount: (post.get(key) ?? 0n) - (pre.get(key) ?? 0n) };\n });\n\n for (let i = 0; i < legs.length; i++) {\n if (legs[i]!.amount !== expectedAmounts[i]!) {\n return invalid(\n `${legs[i]!.wallet.toBase58()} received ${legs[i]!.amount}, expected ${expectedAmounts[i]!}`,\n legs,\n );\n }\n }\n\n const late =\n expiresAt !== undefined &&\n tx.blockTime != null &&\n tx.blockTime * 1000 > expiresAt.getTime();\n return { status: late ? 'paid_late' : 'paid', legs };\n}\n","import { PublicKey, type Connection } from '@solana/web3.js';\nimport { BujiusCheckoutError, ErrorCode, isBujiusCheckoutError } from '../errors';\nimport type { SplitConfig } from '../program/config';\nimport { buildSplitPayment, type PaymentStrategy } from '../strategies/transfers';\n\nexport interface ResolvedPayment {\n config: SplitConfig;\n amount: bigint;\n reference: PublicKey;\n message: string;\n}\n\nexport type ResolveResult = ResolvedPayment | { error: ErrorCode };\n\nexport interface TransactionRequestOptions {\n connection: Connection;\n label: string;\n /** Absolute HTTPS URL, reachable without a session. */\n iconUrl: string;\n strategy: PaymentStrategy;\n /** Gets the last path segment of the request URL and the payer's account, already parsed. */\n resolve: (key: string, account: PublicKey) => ResolveResult | Promise<ResolveResult>;\n}\n\n// Without these on every response, the preflight fails and the wallet fails silently (contracts §4).\nconst CORS_HEADERS = {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type',\n};\n\nconst ERROR_RESPONSES: Partial<Record<ErrorCode, { status: number; sentence: string }>> = {\n [ErrorCode.INVALID_ACCOUNT]: { status: 400, sentence: 'We could not read your account. Try again.' },\n [ErrorCode.ORDER_NOT_FOUND]: { status: 404, sentence: 'This order does not exist.' },\n [ErrorCode.ORDER_HELD]: { status: 409, sentence: 'Someone else is already paying this order.' },\n [ErrorCode.ORDER_PAID]: { status: 409, sentence: 'This order is already paid.' },\n [ErrorCode.ORDER_EXPIRED]: {\n status: 410,\n sentence: 'This order expired. Go back to the store and start again.',\n },\n [ErrorCode.RPC_UNAVAILABLE]: { status: 503, sentence: 'The network is busy. Try again in a moment.' },\n};\n\nconst UNPAYABLE = { status: 500, sentence: 'This order cannot be paid. Go back to the store.' };\n\nfunction respond(status: number, body?: unknown): Response {\n const headers = new Headers(CORS_HEADERS);\n if (body === undefined) {\n return new Response(null, { status, headers });\n }\n headers.set('Content-Type', 'application/json');\n return new Response(JSON.stringify(body), { status, headers });\n}\n\n/** Safe to log: a message can carry the RPC URL and its key, so every URL is removed from it. */\nfunction describeFailure(error: unknown): string {\n if (isBujiusCheckoutError(error)) {\n return error.code;\n }\n if (error instanceof Error) {\n return `${error.name}: ${error.message.replace(/[a-z][a-z0-9+.-]*:\\/\\/\\S+/gi, '<url>')}`;\n }\n return typeof error;\n}\n\nfunction respondToError(error: unknown): Response {\n const known = isBujiusCheckoutError(error) ? ERROR_RESPONSES[error.code] : undefined;\n const { status, sentence } = known ?? UNPAYABLE;\n if (status >= 500) {\n console.error(`Transaction request failed: ${describeFailure(error)}`);\n }\n return respond(status, { error: sentence });\n}\n\nasync function readAccount(request: Request): Promise<PublicKey> {\n let body: unknown;\n try {\n body = await request.json();\n } catch (cause) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_ACCOUNT, { cause });\n }\n const account = (body as { account?: unknown } | null)?.account;\n if (typeof account !== 'string') {\n throw new BujiusCheckoutError(ErrorCode.INVALID_ACCOUNT);\n }\n try {\n return new PublicKey(account);\n } catch (cause) {\n throw new BujiusCheckoutError(ErrorCode.INVALID_ACCOUNT, { cause });\n }\n}\n\n/**\n * The Solana Pay transaction request endpoint (contracts §4). The account is read before\n * `resolve` runs, so a malformed request never reaches a `resolve` that holds an order.\n */\nexport function createTransactionRequestHandler(\n options: TransactionRequestOptions,\n): (request: Request) => Promise<Response> {\n const { connection, label, iconUrl, strategy, resolve } = options;\n\n return async (request) => {\n if (request.method === 'OPTIONS') {\n return respond(204);\n }\n if (request.method === 'GET') {\n return respond(200, { label, icon: iconUrl });\n }\n if (request.method !== 'POST') {\n return respond(405, { error: 'This request is not supported.' });\n }\n\n try {\n const account = await readAccount(request);\n const key = new URL(request.url).pathname.split('/').filter(Boolean).at(-1) ?? '';\n const resolved = await resolve(key, account);\n if ('error' in resolved) {\n throw new BujiusCheckoutError(resolved.error);\n }\n const { config, amount, reference, message } = resolved;\n const transaction = await buildSplitPayment(\n connection,\n config,\n account,\n amount,\n reference,\n strategy,\n );\n const serialized = transaction.serialize({\n requireAllSignatures: false,\n verifySignatures: false,\n });\n return respond(200, { transaction: serialized.toString('base64'), message });\n } catch (error) {\n return respondToError(error);\n }\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,YAAY;AAAA,EACvB,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,iBAAiB;AACnB;AAIO,IAAM,sBAAN,cAAkC,MAAM;AAAA,EACpC;AAAA,EAET,YAAY,MAAiB,SAA+B;AAC1D,UAAM,MAAM,OAAO;AACnB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,sBAAsB,OAA8C;AAClF,SAAO,iBAAiB;AAC1B;;;AC3BA,kBAA0B;;;ACA1B;AAAA,EACE,SAAW;AAAA,EACX,UAAY;AAAA,IACV,MAAQ;AAAA,IACR,SAAW;AAAA,IACX,MAAQ;AAAA,IACR,aAAe;AAAA,EACjB;AAAA,EACA,cAAgB;AAAA,IACd;AAAA,MACE,MAAQ;AAAA,MACR,eAAiB;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAY;AAAA,QACV;AAAA,UACE,MAAQ;AAAA,UACR,UAAY;AAAA,UACZ,QAAU;AAAA,QACZ;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,UACR,UAAY;AAAA,UACZ,KAAO;AAAA,YACL,OAAS;AAAA,cACP;AAAA,gBACE,MAAQ;AAAA,gBACR,OAAS;AAAA,kBACP;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF;AAAA,cACA;AAAA,gBACE,MAAQ;AAAA,gBACR,MAAQ;AAAA,cACV;AAAA,cACA;AAAA,gBACE,MAAQ;AAAA,gBACR,MAAQ;AAAA,cACV;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,UACR,MAAQ;AAAA,YACN;AAAA,UACF;AAAA,QACF;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,UACR,SAAW;AAAA,QACb;AAAA,MACF;AAAA,MACA,MAAQ;AAAA,QACN;AAAA,UACE,MAAQ;AAAA,UACR,MAAQ;AAAA,QACV;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,UACR,MAAQ;AAAA,YACN,KAAO;AAAA,cACL,SAAW;AAAA,gBACT,MAAQ;AAAA,cACV;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,eAAiB;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAY;AAAA,QACV;AAAA,UACE,MAAQ;AAAA,UACR,QAAU;AAAA,QACZ;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,UACR,UAAY;AAAA,QACd;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,QACV;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,QACV;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,UACR,UAAY;AAAA,QACd;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,QACV;AAAA,QACA;AAAA,UACE,MAAQ;AAAA,UACR,SAAW;AAAA,QACb;AAAA,MACF;AAAA,MACA,MAAQ;AAAA,QACN;AAAA,UACE,MAAQ;AAAA,UACR,MAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,UAAY;AAAA,IACV;AAAA,MACE,MAAQ;AAAA,MACR,eAAiB;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,QAAU;AAAA,IACR;AAAA,MACE,MAAQ;AAAA,MACR,eAAiB;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,eAAiB;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,QAAU;AAAA,IACR;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,OAAS;AAAA,IACP;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,QACN,MAAQ;AAAA,QACR,QAAU;AAAA,UACR;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,QACN;AAAA,MACF;AAAA,MACA,MAAQ;AAAA,QACN,MAAQ;AAAA,QACR,QAAU;AAAA,UACR;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,cACN,KAAO;AAAA,gBACL,SAAW;AAAA,kBACT,MAAQ;AAAA,gBACV;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,QACN,MAAQ;AAAA,QACR,QAAU;AAAA,UACR;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,cACN,KAAO;AAAA,gBACL,SAAW;AAAA,kBACT,MAAQ;AAAA,gBACV;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAQ;AAAA,MACR,MAAQ;AAAA,QACN,MAAQ;AAAA,QACR,QAAU;AAAA,UACR;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,cACN,KAAO;AAAA,YACT;AAAA,UACF;AAAA,UACA;AAAA,YACE,MAAQ;AAAA,YACR,MAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ADtVO,IAAM,aAAa,IAAI,sBAAU,YAAI,OAAO;AAG5C,SAAS,gBAAgB,WAAsB,IAAuB;AAC3E,QAAM,UAAU,IAAI,WAAW,CAAC;AAChC,MAAI,SAAS,QAAQ,MAAM,EAAE,UAAU,GAAG,IAAI,IAAI;AAClD,SAAO,sBAAU;AAAA,IACf,CAAC,IAAI,YAAY,EAAE,OAAO,OAAO,GAAG,UAAU,QAAQ,GAAG,OAAO;AAAA,IAChE;AAAA,EACF,EAAE,CAAC;AACL;;;AEbA,oBAA6C;AAC7C,IAAAA,eAA2C;AAkB3C,IAAM,QAAQ,IAAI,iCAAmB,WAAU;AAG/C,eAAsB,iBACpB,YACA,SACsB;AACtB,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,WAAW,eAAe,SAAS,WAAW;AAAA,EAC7D,QAAQ;AACN,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AACA,MAAI,CAAC,QAAQ,CAAC,KAAK,MAAM,OAAO,UAAU,GAAG;AAC3C,UAAM,IAAI,oBAAoB,UAAU,gBAAgB;AAAA,EAC1D;AACA,QAAM,UAAU,MAAM,OAAO,eAAe,KAAK,IAAI;AACrD,SAAO;AAAA,IACL;AAAA,IACA,WAAW,QAAQ;AAAA,IACnB,IAAI,QAAQ;AAAA,IACZ,MAAM,QAAQ;AAAA,IACd,YAAY,QAAQ,WAAW,IAAI,CAAC,OAA2C;AAAA,MAC7E,QAAQ,EAAE;AAAA,MACV,KAAK,EAAE;AAAA,IACT,EAAE;AAAA,EACJ;AACF;;;AC9CA,IAAAC,iBAAgD;AAChD,uBAGO;AACP,IAAAC,eAMO;AAKP,IAAMC,SAAQ,IAAI,qCAAsB,WAAU;AAMlD,eAAsB,iBACpB,YACA,WACA,IACA,MACA,YACsB;AACtB,QAAM,KAAK,IAAI,yBAAY;AAC3B,aAAW,SAAS,CAAC,WAAW,GAAG,WAAW,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG;AACnE,OAAG;AAAA,UACD;AAAA,QACE;AAAA,YACA,gDAA8B,MAAM,KAAK;AAAA,QACzC;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,KAAG;AAAA,IACD,IAAI,oCAAuB;AAAA,MACzB,WAAW;AAAA,MACX,MAAM;AAAA,QACJ,EAAE,QAAQ,WAAW,UAAU,MAAM,YAAY,KAAK;AAAA,QACtD,EAAE,QAAQ,gBAAgB,WAAW,EAAE,GAAG,UAAU,OAAO,YAAY,KAAK;AAAA,QAC5E,EAAE,QAAQ,MAAM,UAAU,OAAO,YAAY,MAAM;AAAA,QACnD,EAAE,QAAQ,2BAAc,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,MACxE;AAAA,MACA,MAAMA,OAAM,OAAO,gBAAgB,EAAE,IAAI,WAAW,CAAC;AAAA,IACvD,CAAC;AAAA,EACH;AACA,QAAM,EAAE,WAAW,qBAAqB,IAAI,MAAM,WAAW,mBAAmB,WAAW;AAC3F,KAAG,WAAW;AACd,KAAG,kBAAkB;AACrB,KAAG,uBAAuB;AAC1B,SAAO;AACT;;;ACnDO,SAAS,YAAY,SAAiB,UAA0B;AACrE,MAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG;AACvD,UAAM,IAAI,oBAAoB,UAAU,cAAc;AAAA,EACxD;AACA,MAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,GAAG;AAC/C,UAAM,IAAI,oBAAoB,UAAU,cAAc;AAAA,EACxD;AAEA,MAAI,CAAC,gBAAgB,KAAK,OAAO,GAAG;AAClC,UAAM,IAAI,oBAAoB,UAAU,cAAc;AAAA,EACxD;AAEA,QAAM,CAAC,WAAW,eAAe,EAAE,IAAI,QAAQ,MAAM,GAAG;AACxD,MAAI,aAAa,SAAS,UAAU;AAClC,UAAM,IAAI,oBAAoB,UAAU,cAAc;AAAA,EACxD;AAEA,SAAO,OAAO,GAAG,SAAS,GAAG,aAAa,OAAO,UAAU,GAAG,CAAC,EAAE;AACnE;AAGO,SAAS,cAAc,QAAgB,UAA0B;AACtE,MAAI,OAAO,WAAW,YAAY,SAAS,IAAI;AAC7C,UAAM,IAAI,oBAAoB,UAAU,cAAc;AAAA,EACxD;AACA,MAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,GAAG;AAC/C,UAAM,IAAI,oBAAoB,UAAU,cAAc;AAAA,EACxD;AAEA,QAAM,MAAM,OAAO,SAAS;AAC5B,MAAI,aAAa,GAAG;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,IAAI,SAAS,WAAW,GAAG,GAAG;AAC7C,QAAM,QAAQ,OAAO,MAAM,GAAG,CAAC,QAAQ;AACvC,QAAM,WAAW,OAAO,MAAM,CAAC,QAAQ;AACvC,QAAM,kBAAkB,SAAS,QAAQ,OAAO,EAAE;AAClD,SAAO,gBAAgB,WAAW,IAAI,QAAQ,GAAG,KAAK,IAAI,eAAe;AAC3E;;;AC7CA,IAAAC,eAAwC;AAGjC,SAAS,eAA0B;AACxC,SAAO,qBAAQ,SAAS,EAAE;AAC5B;;;ACLA,iBAA0B;AAKnB,SAAS,WAAW,iBAAiC;AAC1D,aAAO,sBAAU,EAAE,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC,EAAE,SAAS;AAChE;;;ACCO,SAAS,aACd,QACA,KACwC;AACxC,MAAI,SAAS,IAAI;AACf,UAAM,IAAI,oBAAoB,UAAU,cAAc;AAAA,EACxD;AACA,QAAM,WAAW,IAAI,MAAM,CAAC,MAAM,OAAO,UAAU,CAAC,KAAK,KAAK,CAAC;AAC/D,MAAI,CAAC,YAAY,IAAI,OAAO,CAAC,OAAO,MAAM,QAAQ,GAAG,CAAC,IAAI,KAAQ;AAChE,UAAM,IAAI,oBAAoB,UAAU,gBAAgB;AAAA,EAC1D;AACA,QAAM,SAAS,IAAI,IAAI,CAAC,MAAO,SAAS,OAAO,CAAC,IAAK,MAAO;AAC5D,MAAI,MAAM;AACV,aAAW,SAAS,QAAQ;AAC1B,WAAO;AAAA,EACT;AACA,SAAO,EAAE,QAAQ,UAAU,SAAS,IAAI;AAC1C;;;ACzBA,IAAAC,oBAKO;AACP,IAAAC,eAAwD;;;ACNxD,IAAAC,iBAAwD;AACxD,IAAAC,oBAIO;AACP,IAAAC,eAKO;AAQP,IAAM,EAAE,GAAG,IAAI,eAAAC;AACf,IAAMC,SAAQ,IAAI,qCAAsB,WAAU;AAOlD,eAAsB,oBACpB,YACA,QACA,OACA,QACA,WACsB;AACtB,QAAM,EAAE,QAAQ,SAAS,IAAI;AAAA,IAC3B;AAAA,IACA,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE,GAAG;AAAA,EACpC;AAEA,QAAM,QAAQ,CAAC,eACb,iDAA8B,OAAO,MAAM,QAAQ,IAAI;AACzD,QAAM,gBAAgB,MAAM,OAAO,SAAS;AAC5C,QAAM,gBAAgB,OAAO,WAAW,IAAI,CAAC,MAAM,MAAM,EAAE,MAAM,CAAC;AAClE,QAAM,SAAS,MAAM,KAAK;AAG1B,QAAM,SAAS;AAAA,IACb,GAAG,OAAO,WACP,IAAI,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,KAAK,cAAc,CAAC,GAAI,QAAQ,OAAO,CAAC,EAAG,EAAE,EAChF,OAAO,CAAC,QAAQ,IAAI,SAAS,EAAE;AAAA,IAClC,GAAI,WAAW,KACX,CAAC,EAAE,QAAQ,OAAO,WAAW,KAAK,eAAe,QAAQ,SAAS,CAAC,IACnE,CAAC;AAAA,EACP;AAEA,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,WAAW;AAAA,MACvB,CAAC,GAAG,OAAO,IAAI,CAAC,QAAQ,IAAI,GAAG,GAAG,MAAM;AAAA,MACxC;AAAA,IACF;AAAA,EACF,QAAQ;AACN,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AACA,MAAI,CAAC,MAAM,OAAO,MAAM,GAAG;AACzB,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AAEA,QAAM,KAAK,IAAI,yBAAY;AAC3B,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,QAAI,MAAM,CAAC,KAAK,MAAM;AACpB,YAAM,MAAM,OAAO,CAAC;AACpB,SAAG;AAAA,YACD,qEAAkD,OAAO,IAAI,KAAK,IAAI,QAAQ,OAAO,IAAI;AAAA,MAC3F;AAAA,IACF;AAAA,EACF;AAEA,KAAG;AAAA,IACD,IAAI,oCAAuB;AAAA,MACzB,WAAW;AAAA,MACX,MAAM;AAAA,QACJ,EAAE,QAAQ,OAAO,UAAU,MAAM,YAAY,MAAM;AAAA,QACnD,EAAE,QAAQ,QAAQ,UAAU,OAAO,YAAY,KAAK;AAAA,QACpD,EAAE,QAAQ,OAAO,SAAS,UAAU,OAAO,YAAY,MAAM;AAAA,QAC7D,EAAE,QAAQ,OAAO,MAAM,UAAU,OAAO,YAAY,MAAM;AAAA,QAC1D,EAAE,QAAQ,eAAe,UAAU,OAAO,YAAY,KAAK;AAAA,QAC3D,EAAE,QAAQ,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,QACxD,EAAE,QAAQ,oCAAkB,UAAU,OAAO,YAAY,MAAM;AAAA;AAAA,QAE/D,GAAG,cAAc,IAAI,CAAC,YAAY,EAAE,QAAQ,UAAU,OAAO,YAAY,KAAK,EAAE;AAAA,MAClF;AAAA,MACA,MAAMA,OAAM,OAAO,OAAO,EAAE,QAAQ,IAAI,GAAG,OAAO,SAAS,CAAC,EAAE,CAAC;AAAA,IACjE,CAAC;AAAA,EACH;AAEA,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,KAAC,EAAE,WAAW,qBAAqB,IAAI,MAAM,WAAW,mBAAmB,WAAW;AAAA,EACxF,QAAQ;AACN,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AACA,KAAG,WAAW;AACd,KAAG,kBAAkB;AACrB,KAAG,uBAAuB;AAC1B,SAAO;AACT;;;AD7FA,IAAM,UAAU;AAUhB,eAAsB,kBACpB,YACA,QACA,OACA,QACA,WACA,UACsB;AACtB,MAAI,UAAU,MAAM,SAAS,SAAS;AACpC,UAAM,IAAI,oBAAoB,UAAU,cAAc;AAAA,EACxD;AACA,MACE,CAAC,uBAAU,UAAU,KAAK,KAC1B,MAAM,OAAO,OAAO,SAAS,KAC7B,OAAO,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,KAAK,CAAC,GACpD;AACA,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AACA,MAAI,aAAa,WAAW;AAC1B,WAAO,oBAAoB,YAAY,QAAQ,OAAO,QAAQ,SAAS;AAAA,EACzE;AACA,MAAI,aAAa,aAAa;AAC5B,UAAM,IAAI,MAAM,6BAA6B,OAAO,QAAQ,CAAC,EAAE;AAAA,EACjE;AACA,SAAO,sBAAsB,YAAY,QAAQ,OAAO,QAAQ,SAAS;AAC3E;AAEA,eAAe,sBACb,YACA,QACA,OACA,QACA,WACsB;AACtB,QAAM,EAAE,QAAQ,SAAS,IAAI;AAAA,IAC3B;AAAA,IACA,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE,GAAG;AAAA,EACpC;AAEA,QAAM,OAAgD,CAAC;AACvD,WAAS,IAAI,GAAG,IAAI,OAAO,WAAW,QAAQ,KAAK;AACjD,UAAM,QAAQ,OAAO,CAAC;AACtB,QAAI,QAAQ,IAAI;AACd,WAAK,KAAK,EAAE,QAAQ,OAAO,WAAW,CAAC,EAAG,QAAQ,QAAQ,MAAM,CAAC;AAAA,IACnE;AAAA,EACF;AACA,MAAI,WAAW,IAAI;AACjB,SAAK,KAAK,EAAE,QAAQ,OAAO,WAAW,QAAQ,SAAS,CAAC;AAAA,EAC1D;AAGA,QAAM,QAAQ,CAAC,eACb,iDAA8B,OAAO,MAAM,QAAQ,IAAI;AACzD,QAAM,WAAW,KAAK,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,CAAC;AACpD,QAAM,SAAS,MAAM,KAAK;AAE1B,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,WAAW;AAAA,MACvB,CAAC,GAAG,UAAU,OAAO,MAAM,MAAM;AAAA,MACjC;AAAA,IACF;AAAA,EACF,QAAQ;AACN,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AAEA,QAAM,WAAW,MAAM,SAAS,MAAM;AACtC,QAAM,aAAa,MAAM,SAAS,SAAS,CAAC;AAC5C,MAAI,CAAC,YAAY,CAAC,YAAY;AAC5B,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AACA,MAAI;AACJ,MAAI;AACF,mBAAW,8BAAW,OAAO,MAAM,QAAQ,EAAE;AAAA,EAC/C,SAAS,OAAO;AACd,UAAM,IAAI,oBAAoB,UAAU,iBAAiB,EAAE,MAAM,CAAC;AAAA,EACpE;AAEA,QAAM,KAAK,IAAI,yBAAY;AAC3B,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,QAAI,MAAM,CAAC,KAAK,MAAM;AACpB,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,MAAM,SAAS,CAAC;AACtB,SAAG;AAAA,YACD;AAAA,UACE;AAAA,UACA;AAAA,UACA,IAAI;AAAA,UACJ,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB;AACpB,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,UAAM,cAAc,SAAS,CAAC;AAC9B,UAAM,SAAK;AAAA,MACT;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,IAAI;AAAA,MACJ;AAAA,IACF;AACA,QAAI,eAAe;AACjB,SAAG,KAAK,KAAK,EAAE,QAAQ,WAAW,UAAU,OAAO,YAAY,MAAM,CAAC;AACtE,sBAAgB;AAAA,IAClB;AACA,OAAG,IAAI,EAAE;AAAA,EACX;AAEA,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,KAAC,EAAE,WAAW,qBAAqB,IACjC,MAAM,WAAW,mBAAmB,WAAW;AAAA,EACnD,QAAQ;AACN,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AACA,KAAG,WAAW;AACd,KAAG,kBAAkB;AACrB,KAAG,uBAAuB;AAC1B,SAAO;AACT;;;AE9IA,eAAsB,YACpB,YACA,WACwB;AACxB,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,WAAW,wBAAwB,WAAW,QAAW,WAAW;AAAA,EACzF,QAAQ;AACN,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AAEA,QAAM,aAAa,WAAW,OAAO,CAAC,MAAM,EAAE,QAAQ,IAAI;AAC1D,SAAO,WAAW,SAAS,IAAI,WAAW,WAAW,SAAS,CAAC,EAAG,YAAY;AAChF;;;ACGA,SAAS,OAAO,UAAsD,MAAc;AAClF,QAAM,UAAU,oBAAI,IAAoB;AACxC,aAAW,KAAK,YAAY,CAAC,GAAG;AAC9B,QAAI,EAAE,SAAS,QAAQ,CAAC,EAAE,MAAO;AACjC,YAAQ,IAAI,EAAE,QAAQ,QAAQ,IAAI,EAAE,KAAK,KAAK,MAAM,OAAO,EAAE,cAAc,MAAM,CAAC;AAAA,EACpF;AACA,SAAO;AACT;AAQA,eAAsB,mBACpB,YACA,WACA,QACA,QACA,WACA,WACuB;AACvB,QAAM,WAAW;AAAA,IACf;AAAA,IACA,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE,GAAG;AAAA,EACpC;AACA,QAAM,UAAU,CAAC,GAAG,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,SAAS;AAC5E,QAAM,kBAAkB,CAAC,GAAG,SAAS,QAAQ,SAAS,QAAQ;AAC9D,QAAM,UAAU,CAAC,QAAgBC,QAAsB,CAAC,OAAqB;AAAA,IAC3E,QAAQ;AAAA,IACR;AAAA,IACA,MAAAA;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,SAAK,MAAM,WAAW,qBAAqB,WAAW;AAAA,MACpD,YAAY;AAAA,MACZ,gCAAgC;AAAA,IAClC,CAAC;AAAA,EACH,QAAQ;AACN,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AACA,MAAI,CAAC,MAAM,CAAC,GAAG,KAAM,QAAO,QAAQ,uBAAuB;AAC3D,MAAI,GAAG,KAAK,QAAQ,KAAM,QAAO,QAAQ,oBAAoB;AAE7D,QAAM,eAAe,UAAU,SAAS;AACxC,MAAI,CAAC,GAAG,YAAY,QAAQ,YAAY,KAAK,CAAC,MAAM,OAAO,EAAE,MAAM,MAAM,YAAY,GAAG;AACtF,WAAO,QAAQ,kCAAkC;AAAA,EACnD;AAEA,QAAM,OAAO,OAAO,KAAK,SAAS;AAClC,QAAM,MAAM,OAAO,GAAG,KAAK,kBAAkB,IAAI;AACjD,QAAM,OAAO,OAAO,GAAG,KAAK,mBAAmB,IAAI;AACnD,QAAM,OAAsB,QAAQ,IAAI,CAAC,WAAW;AAClD,UAAM,MAAM,OAAO,SAAS;AAC5B,WAAO,EAAE,QAAQ,SAAS,KAAK,IAAI,GAAG,KAAK,OAAO,IAAI,IAAI,GAAG,KAAK,IAAI;AAAA,EACxE,CAAC;AAED,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,EAAG,WAAW,gBAAgB,CAAC,GAAI;AAC3C,aAAO;AAAA,QACL,GAAG,KAAK,CAAC,EAAG,OAAO,SAAS,CAAC,aAAa,KAAK,CAAC,EAAG,MAAM,cAAc,gBAAgB,CAAC,CAAE;AAAA,QAC1F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OACJ,cAAc,UACd,GAAG,aAAa,QAChB,GAAG,YAAY,MAAO,UAAU,QAAQ;AAC1C,SAAO,EAAE,QAAQ,OAAO,cAAc,QAAQ,KAAK;AACrD;;;ACjGA,IAAAC,eAA2C;AAyB3C,IAAM,eAAe;AAAA,EACnB,+BAA+B;AAAA,EAC/B,gCAAgC;AAAA,EAChC,gCAAgC;AAClC;AAEA,IAAM,kBAAoF;AAAA,EACxF,CAAC,UAAU,eAAe,GAAG,EAAE,QAAQ,KAAK,UAAU,6CAA6C;AAAA,EACnG,CAAC,UAAU,eAAe,GAAG,EAAE,QAAQ,KAAK,UAAU,6BAA6B;AAAA,EACnF,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ,KAAK,UAAU,6CAA6C;AAAA,EAC9F,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ,KAAK,UAAU,8BAA8B;AAAA,EAC/E,CAAC,UAAU,aAAa,GAAG;AAAA,IACzB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA,CAAC,UAAU,eAAe,GAAG,EAAE,QAAQ,KAAK,UAAU,8CAA8C;AACtG;AAEA,IAAM,YAAY,EAAE,QAAQ,KAAK,UAAU,mDAAmD;AAE9F,SAAS,QAAQ,QAAgB,MAA0B;AACzD,QAAM,UAAU,IAAI,QAAQ,YAAY;AACxC,MAAI,SAAS,QAAW;AACtB,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,QAAQ,CAAC;AAAA,EAC/C;AACA,UAAQ,IAAI,gBAAgB,kBAAkB;AAC9C,SAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG,EAAE,QAAQ,QAAQ,CAAC;AAC/D;AAGA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,sBAAsB,KAAK,GAAG;AAChC,WAAO,MAAM;AAAA,EACf;AACA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,GAAG,MAAM,IAAI,KAAK,MAAM,QAAQ,QAAQ,+BAA+B,OAAO,CAAC;AAAA,EACxF;AACA,SAAO,OAAO;AAChB;AAEA,SAAS,eAAe,OAA0B;AAChD,QAAM,QAAQ,sBAAsB,KAAK,IAAI,gBAAgB,MAAM,IAAI,IAAI;AAC3E,QAAM,EAAE,QAAQ,SAAS,IAAI,SAAS;AACtC,MAAI,UAAU,KAAK;AACjB,YAAQ,MAAM,+BAA+B,gBAAgB,KAAK,CAAC,EAAE;AAAA,EACvE;AACA,SAAO,QAAQ,QAAQ,EAAE,OAAO,SAAS,CAAC;AAC5C;AAEA,eAAe,YAAY,SAAsC;AAC/D,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK;AAAA,EAC5B,SAAS,OAAO;AACd,UAAM,IAAI,oBAAoB,UAAU,iBAAiB,EAAE,MAAM,CAAC;AAAA,EACpE;AACA,QAAM,UAAW,MAAuC;AACxD,MAAI,OAAO,YAAY,UAAU;AAC/B,UAAM,IAAI,oBAAoB,UAAU,eAAe;AAAA,EACzD;AACA,MAAI;AACF,WAAO,IAAI,uBAAU,OAAO;AAAA,EAC9B,SAAS,OAAO;AACd,UAAM,IAAI,oBAAoB,UAAU,iBAAiB,EAAE,MAAM,CAAC;AAAA,EACpE;AACF;AAMO,SAAS,gCACd,SACyC;AACzC,QAAM,EAAE,YAAY,OAAO,SAAS,UAAU,QAAQ,IAAI;AAE1D,SAAO,OAAO,YAAY;AACxB,QAAI,QAAQ,WAAW,WAAW;AAChC,aAAO,QAAQ,GAAG;AAAA,IACpB;AACA,QAAI,QAAQ,WAAW,OAAO;AAC5B,aAAO,QAAQ,KAAK,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,IAC9C;AACA,QAAI,QAAQ,WAAW,QAAQ;AAC7B,aAAO,QAAQ,KAAK,EAAE,OAAO,iCAAiC,CAAC;AAAA,IACjE;AAEA,QAAI;AACF,YAAM,UAAU,MAAM,YAAY,OAAO;AACzC,YAAM,MAAM,IAAI,IAAI,QAAQ,GAAG,EAAE,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,GAAG,EAAE,KAAK;AAC/E,YAAM,WAAW,MAAM,QAAQ,KAAK,OAAO;AAC3C,UAAI,WAAW,UAAU;AACvB,cAAM,IAAI,oBAAoB,SAAS,KAAK;AAAA,MAC9C;AACA,YAAM,EAAE,QAAQ,QAAQ,WAAW,QAAQ,IAAI;AAC/C,YAAM,cAAc,MAAM;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,aAAa,YAAY,UAAU;AAAA,QACvC,sBAAsB;AAAA,QACtB,kBAAkB;AAAA,MACpB,CAAC;AACD,aAAO,QAAQ,KAAK,EAAE,aAAa,WAAW,SAAS,QAAQ,GAAG,QAAQ,CAAC;AAAA,IAC7E,SAAS,OAAO;AACd,aAAO,eAAe,KAAK;AAAA,IAC7B;AAAA,EACF;AACF;","names":["import_web3","import_anchor","import_web3","coder","import_web3","import_spl_token","import_web3","import_anchor","import_spl_token","import_web3","anchor","coder","legs","import_web3"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { PublicKey, Connection, Transaction } from '@solana/web3.js';
|
|
2
|
+
|
|
3
|
+
declare const ErrorCode: {
|
|
4
|
+
readonly ORDER_NOT_FOUND: "ORDER_NOT_FOUND";
|
|
5
|
+
readonly ORDER_EXPIRED: "ORDER_EXPIRED";
|
|
6
|
+
readonly ORDER_PAID: "ORDER_PAID";
|
|
7
|
+
readonly ORDER_HELD: "ORDER_HELD";
|
|
8
|
+
readonly INVALID_ACCOUNT: "INVALID_ACCOUNT";
|
|
9
|
+
readonly INVALID_AMOUNT: "INVALID_AMOUNT";
|
|
10
|
+
readonly CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND";
|
|
11
|
+
readonly RPC_UNAVAILABLE: "RPC_UNAVAILABLE";
|
|
12
|
+
};
|
|
13
|
+
type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
14
|
+
declare class BujiusCheckoutError extends Error {
|
|
15
|
+
readonly code: ErrorCode;
|
|
16
|
+
constructor(code: ErrorCode, options?: {
|
|
17
|
+
cause?: unknown;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
declare function isBujiusCheckoutError(value: unknown): value is BujiusCheckoutError;
|
|
21
|
+
|
|
22
|
+
declare const PROGRAM_ID: PublicKey;
|
|
23
|
+
/** The address of a merchant's split config. Seeds: ["split", authority, id as u16 LE]. */
|
|
24
|
+
declare function findSplitConfig(authority: PublicKey, id: number): PublicKey;
|
|
25
|
+
|
|
26
|
+
interface Recipient {
|
|
27
|
+
wallet: PublicKey;
|
|
28
|
+
bps: number;
|
|
29
|
+
}
|
|
30
|
+
interface SplitConfig {
|
|
31
|
+
address: PublicKey;
|
|
32
|
+
authority: PublicKey;
|
|
33
|
+
id: number;
|
|
34
|
+
mint: PublicKey;
|
|
35
|
+
recipients: Recipient[];
|
|
36
|
+
}
|
|
37
|
+
/** Reads and decodes a split config; throws CONFIG_NOT_FOUND if it is not ours or absent. */
|
|
38
|
+
declare function fetchSplitConfig(connection: Connection, address: PublicKey): Promise<SplitConfig>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Unsigned transaction: creates every destination ATA (merchant and recipients, paid by the
|
|
42
|
+
* merchant), then `create_split`. Fee payer = authority.
|
|
43
|
+
*/
|
|
44
|
+
declare function buildCreateSplit(connection: Connection, authority: PublicKey, id: number, mint: PublicKey, recipients: Recipient[]): Promise<Transaction>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parses a decimal string into base units. Rejects negatives, exponents, empty
|
|
48
|
+
* strings, and more fractional digits than `decimals`.
|
|
49
|
+
*/
|
|
50
|
+
declare function toBaseUnits(decimal: string, decimals: number): bigint;
|
|
51
|
+
/** Formats base units as a decimal string; never uses scientific notation. */
|
|
52
|
+
declare function fromBaseUnits(amount: bigint, decimals: number): string;
|
|
53
|
+
|
|
54
|
+
/** A fresh public key used as the Solana Pay reference for one payment. */
|
|
55
|
+
declare function newReference(): PublicKey;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Builds a Solana Pay transaction-request URL (`solana:…`) from the handler's HTTPS URL.
|
|
59
|
+
*/
|
|
60
|
+
declare function paymentUrl(handlerHttpsUrl: string): string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* One rule, three places (contracts §2): share[i] = floor(amount × bps[i] / 10_000);
|
|
64
|
+
* merchant gets the remainder. bigint intermediates cover the u64 × bps product.
|
|
65
|
+
* Bps that are negative, fractional or sum above 10_000 throw `CONFIG_NOT_FOUND`, so
|
|
66
|
+
* merchant + Σ share = amount never holds through a negative merchant amount.
|
|
67
|
+
*/
|
|
68
|
+
declare function computeSplit(amount: bigint, bps: readonly number[]): {
|
|
69
|
+
shares: bigint[];
|
|
70
|
+
merchant: bigint;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type PaymentStrategy = 'program' | 'transfers';
|
|
74
|
+
/**
|
|
75
|
+
* Builds an unsigned legacy split payment. Fee payer = payer; blockhash at `confirmed`.
|
|
76
|
+
* `'transfers'` is implemented here; `'program'` lives in `program.ts` (A4).
|
|
77
|
+
* An amount outside 1..=u64::MAX throws `INVALID_AMOUNT` for either strategy.
|
|
78
|
+
* A payer who is also a leg's wallet throws `INVALID_ACCOUNT` for either strategy: its balance
|
|
79
|
+
* would not rise by that leg's amount, so the verifier could never mark the payment paid.
|
|
80
|
+
* An off-curve payer throws `INVALID_ACCOUNT` too: it has no private key to sign with.
|
|
81
|
+
*/
|
|
82
|
+
declare function buildSplitPayment(connection: Connection, config: SplitConfig, payer: PublicKey, amount: bigint, reference: PublicKey, strategy: PaymentStrategy): Promise<Transaction>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The first successful signature that mentions `reference`, at `confirmed`, or `null`.
|
|
86
|
+
* Finding a signature does not mean the amount is right: only `verifySplitPayment` decides.
|
|
87
|
+
*/
|
|
88
|
+
declare function findPayment(connection: Connection, reference: PublicKey): Promise<string | null>;
|
|
89
|
+
|
|
90
|
+
interface VerifiedLeg {
|
|
91
|
+
wallet: PublicKey;
|
|
92
|
+
/** What the wallet's token balance of `config.mint` actually rose by. */
|
|
93
|
+
amount: bigint;
|
|
94
|
+
}
|
|
95
|
+
interface Verification {
|
|
96
|
+
status: 'paid' | 'paid_late' | 'invalid';
|
|
97
|
+
reason?: string;
|
|
98
|
+
/** Recipients in config order, then the merchant. */
|
|
99
|
+
legs: VerifiedLeg[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Judges a transaction by balances, not instructions, so both strategies pass: it succeeded,
|
|
103
|
+
* the reference is among its account keys, and the balance of the merchant and of each
|
|
104
|
+
* recipient (in `config.mint`) rose by exactly `computeSplit(amount)`. A `blockTime` after
|
|
105
|
+
* `expiresAt` is `paid_late`. The program guarantees the split; this guarantees the amount.
|
|
106
|
+
*/
|
|
107
|
+
declare function verifySplitPayment(connection: Connection, signature: string, config: SplitConfig, amount: bigint, reference: PublicKey, expiresAt?: Date): Promise<Verification>;
|
|
108
|
+
|
|
109
|
+
interface ResolvedPayment {
|
|
110
|
+
config: SplitConfig;
|
|
111
|
+
amount: bigint;
|
|
112
|
+
reference: PublicKey;
|
|
113
|
+
message: string;
|
|
114
|
+
}
|
|
115
|
+
type ResolveResult = ResolvedPayment | {
|
|
116
|
+
error: ErrorCode;
|
|
117
|
+
};
|
|
118
|
+
interface TransactionRequestOptions {
|
|
119
|
+
connection: Connection;
|
|
120
|
+
label: string;
|
|
121
|
+
/** Absolute HTTPS URL, reachable without a session. */
|
|
122
|
+
iconUrl: string;
|
|
123
|
+
strategy: PaymentStrategy;
|
|
124
|
+
/** Gets the last path segment of the request URL and the payer's account, already parsed. */
|
|
125
|
+
resolve: (key: string, account: PublicKey) => ResolveResult | Promise<ResolveResult>;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The Solana Pay transaction request endpoint (contracts §4). The account is read before
|
|
129
|
+
* `resolve` runs, so a malformed request never reaches a `resolve` that holds an order.
|
|
130
|
+
*/
|
|
131
|
+
declare function createTransactionRequestHandler(options: TransactionRequestOptions): (request: Request) => Promise<Response>;
|
|
132
|
+
|
|
133
|
+
export { BujiusCheckoutError, ErrorCode, PROGRAM_ID, type PaymentStrategy, type Recipient, type ResolveResult, type ResolvedPayment, type SplitConfig, type TransactionRequestOptions, type Verification, type VerifiedLeg, buildCreateSplit, buildSplitPayment, computeSplit, createTransactionRequestHandler, fetchSplitConfig, findPayment, findSplitConfig, fromBaseUnits, isBujiusCheckoutError, newReference, paymentUrl, toBaseUnits, verifySplitPayment };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { PublicKey, Connection, Transaction } from '@solana/web3.js';
|
|
2
|
+
|
|
3
|
+
declare const ErrorCode: {
|
|
4
|
+
readonly ORDER_NOT_FOUND: "ORDER_NOT_FOUND";
|
|
5
|
+
readonly ORDER_EXPIRED: "ORDER_EXPIRED";
|
|
6
|
+
readonly ORDER_PAID: "ORDER_PAID";
|
|
7
|
+
readonly ORDER_HELD: "ORDER_HELD";
|
|
8
|
+
readonly INVALID_ACCOUNT: "INVALID_ACCOUNT";
|
|
9
|
+
readonly INVALID_AMOUNT: "INVALID_AMOUNT";
|
|
10
|
+
readonly CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND";
|
|
11
|
+
readonly RPC_UNAVAILABLE: "RPC_UNAVAILABLE";
|
|
12
|
+
};
|
|
13
|
+
type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
14
|
+
declare class BujiusCheckoutError extends Error {
|
|
15
|
+
readonly code: ErrorCode;
|
|
16
|
+
constructor(code: ErrorCode, options?: {
|
|
17
|
+
cause?: unknown;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
declare function isBujiusCheckoutError(value: unknown): value is BujiusCheckoutError;
|
|
21
|
+
|
|
22
|
+
declare const PROGRAM_ID: PublicKey;
|
|
23
|
+
/** The address of a merchant's split config. Seeds: ["split", authority, id as u16 LE]. */
|
|
24
|
+
declare function findSplitConfig(authority: PublicKey, id: number): PublicKey;
|
|
25
|
+
|
|
26
|
+
interface Recipient {
|
|
27
|
+
wallet: PublicKey;
|
|
28
|
+
bps: number;
|
|
29
|
+
}
|
|
30
|
+
interface SplitConfig {
|
|
31
|
+
address: PublicKey;
|
|
32
|
+
authority: PublicKey;
|
|
33
|
+
id: number;
|
|
34
|
+
mint: PublicKey;
|
|
35
|
+
recipients: Recipient[];
|
|
36
|
+
}
|
|
37
|
+
/** Reads and decodes a split config; throws CONFIG_NOT_FOUND if it is not ours or absent. */
|
|
38
|
+
declare function fetchSplitConfig(connection: Connection, address: PublicKey): Promise<SplitConfig>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Unsigned transaction: creates every destination ATA (merchant and recipients, paid by the
|
|
42
|
+
* merchant), then `create_split`. Fee payer = authority.
|
|
43
|
+
*/
|
|
44
|
+
declare function buildCreateSplit(connection: Connection, authority: PublicKey, id: number, mint: PublicKey, recipients: Recipient[]): Promise<Transaction>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parses a decimal string into base units. Rejects negatives, exponents, empty
|
|
48
|
+
* strings, and more fractional digits than `decimals`.
|
|
49
|
+
*/
|
|
50
|
+
declare function toBaseUnits(decimal: string, decimals: number): bigint;
|
|
51
|
+
/** Formats base units as a decimal string; never uses scientific notation. */
|
|
52
|
+
declare function fromBaseUnits(amount: bigint, decimals: number): string;
|
|
53
|
+
|
|
54
|
+
/** A fresh public key used as the Solana Pay reference for one payment. */
|
|
55
|
+
declare function newReference(): PublicKey;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Builds a Solana Pay transaction-request URL (`solana:…`) from the handler's HTTPS URL.
|
|
59
|
+
*/
|
|
60
|
+
declare function paymentUrl(handlerHttpsUrl: string): string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* One rule, three places (contracts §2): share[i] = floor(amount × bps[i] / 10_000);
|
|
64
|
+
* merchant gets the remainder. bigint intermediates cover the u64 × bps product.
|
|
65
|
+
* Bps that are negative, fractional or sum above 10_000 throw `CONFIG_NOT_FOUND`, so
|
|
66
|
+
* merchant + Σ share = amount never holds through a negative merchant amount.
|
|
67
|
+
*/
|
|
68
|
+
declare function computeSplit(amount: bigint, bps: readonly number[]): {
|
|
69
|
+
shares: bigint[];
|
|
70
|
+
merchant: bigint;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type PaymentStrategy = 'program' | 'transfers';
|
|
74
|
+
/**
|
|
75
|
+
* Builds an unsigned legacy split payment. Fee payer = payer; blockhash at `confirmed`.
|
|
76
|
+
* `'transfers'` is implemented here; `'program'` lives in `program.ts` (A4).
|
|
77
|
+
* An amount outside 1..=u64::MAX throws `INVALID_AMOUNT` for either strategy.
|
|
78
|
+
* A payer who is also a leg's wallet throws `INVALID_ACCOUNT` for either strategy: its balance
|
|
79
|
+
* would not rise by that leg's amount, so the verifier could never mark the payment paid.
|
|
80
|
+
* An off-curve payer throws `INVALID_ACCOUNT` too: it has no private key to sign with.
|
|
81
|
+
*/
|
|
82
|
+
declare function buildSplitPayment(connection: Connection, config: SplitConfig, payer: PublicKey, amount: bigint, reference: PublicKey, strategy: PaymentStrategy): Promise<Transaction>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The first successful signature that mentions `reference`, at `confirmed`, or `null`.
|
|
86
|
+
* Finding a signature does not mean the amount is right: only `verifySplitPayment` decides.
|
|
87
|
+
*/
|
|
88
|
+
declare function findPayment(connection: Connection, reference: PublicKey): Promise<string | null>;
|
|
89
|
+
|
|
90
|
+
interface VerifiedLeg {
|
|
91
|
+
wallet: PublicKey;
|
|
92
|
+
/** What the wallet's token balance of `config.mint` actually rose by. */
|
|
93
|
+
amount: bigint;
|
|
94
|
+
}
|
|
95
|
+
interface Verification {
|
|
96
|
+
status: 'paid' | 'paid_late' | 'invalid';
|
|
97
|
+
reason?: string;
|
|
98
|
+
/** Recipients in config order, then the merchant. */
|
|
99
|
+
legs: VerifiedLeg[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Judges a transaction by balances, not instructions, so both strategies pass: it succeeded,
|
|
103
|
+
* the reference is among its account keys, and the balance of the merchant and of each
|
|
104
|
+
* recipient (in `config.mint`) rose by exactly `computeSplit(amount)`. A `blockTime` after
|
|
105
|
+
* `expiresAt` is `paid_late`. The program guarantees the split; this guarantees the amount.
|
|
106
|
+
*/
|
|
107
|
+
declare function verifySplitPayment(connection: Connection, signature: string, config: SplitConfig, amount: bigint, reference: PublicKey, expiresAt?: Date): Promise<Verification>;
|
|
108
|
+
|
|
109
|
+
interface ResolvedPayment {
|
|
110
|
+
config: SplitConfig;
|
|
111
|
+
amount: bigint;
|
|
112
|
+
reference: PublicKey;
|
|
113
|
+
message: string;
|
|
114
|
+
}
|
|
115
|
+
type ResolveResult = ResolvedPayment | {
|
|
116
|
+
error: ErrorCode;
|
|
117
|
+
};
|
|
118
|
+
interface TransactionRequestOptions {
|
|
119
|
+
connection: Connection;
|
|
120
|
+
label: string;
|
|
121
|
+
/** Absolute HTTPS URL, reachable without a session. */
|
|
122
|
+
iconUrl: string;
|
|
123
|
+
strategy: PaymentStrategy;
|
|
124
|
+
/** Gets the last path segment of the request URL and the payer's account, already parsed. */
|
|
125
|
+
resolve: (key: string, account: PublicKey) => ResolveResult | Promise<ResolveResult>;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The Solana Pay transaction request endpoint (contracts §4). The account is read before
|
|
129
|
+
* `resolve` runs, so a malformed request never reaches a `resolve` that holds an order.
|
|
130
|
+
*/
|
|
131
|
+
declare function createTransactionRequestHandler(options: TransactionRequestOptions): (request: Request) => Promise<Response>;
|
|
132
|
+
|
|
133
|
+
export { BujiusCheckoutError, ErrorCode, PROGRAM_ID, type PaymentStrategy, type Recipient, type ResolveResult, type ResolvedPayment, type SplitConfig, type TransactionRequestOptions, type Verification, type VerifiedLeg, buildCreateSplit, buildSplitPayment, computeSplit, createTransactionRequestHandler, fetchSplitConfig, findPayment, findSplitConfig, fromBaseUnits, isBujiusCheckoutError, newReference, paymentUrl, toBaseUnits, verifySplitPayment };
|