@t2000/cli 5.6.0 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,8 @@
1
1
  import { createRequire as __createRequire } from 'module'; import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const require = __createRequire(import.meta.url); const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename);
2
- import "./chunk-OCLKPYUU.js";
3
2
  import {
4
3
  Transaction
5
- } from "./chunk-ITIKLNK5.js";
6
- import "./chunk-MPXYF2CX.js";
4
+ } from "./chunk-TP3M7BAU.js";
5
+ import "./chunk-X6ON6NN5.js";
7
6
  import {
8
7
  fromBase64,
9
8
  normalizeSuiAddress,
@@ -284,4 +283,4 @@ export {
284
283
  verifyX402Payment,
285
284
  x402Network
286
285
  };
287
- //# sourceMappingURL=x402-EMQGKUTK.js.map
286
+ //# sourceMappingURL=x402-UYN72OS3.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../node_modules/.pnpm/@suimpp+mpp@0.8.1_@modelcontextprotocol+sdk@1.28.0_zod@3.25.76__express@5.2.1_hono@4.12_f78e9d565196b7d48429724cce956455/node_modules/@suimpp/mpp/src/utils.ts","../../../node_modules/.pnpm/@suimpp+mpp@0.8.1_@modelcontextprotocol+sdk@1.28.0_zod@3.25.76__express@5.2.1_hono@4.12_f78e9d565196b7d48429724cce956455/node_modules/@suimpp/mpp/src/x402.ts"],"sourcesContent":["/**\n * Parse a string amount to raw bigint units without floating-point math.\n * \"0.01\" with 6 decimals → 10000n\n */\nexport function parseAmountToRaw(amount: string, decimals: number): bigint {\n const [whole = '0', frac = ''] = amount.split('.');\n const paddedFrac = frac.padEnd(decimals, '0').slice(0, decimals);\n return BigInt(whole + paddedFrac);\n}\n\n/**\n * Retry an async function with linear backoff.\n * Throws the last error if all attempts fail.\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n {\n attempts = 5,\n baseDelayMs = 1000,\n }: { attempts?: number; baseDelayMs?: number } = {},\n): Promise<T> {\n let lastError: unknown;\n for (let i = 0; i < attempts; i++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (i < attempts - 1) {\n await new Promise((r) => setTimeout(r, baseDelayMs * (i + 1)));\n }\n }\n }\n throw lastError;\n}\n","import type { ClientWithCoreApi } from '@mysten/sui/client';\nimport type { Signer } from '@mysten/sui/cryptography';\nimport { Transaction } from '@mysten/sui/transactions';\nimport {\n fromBase64,\n normalizeSuiAddress,\n toBase64,\n toHex,\n} from '@mysten/sui/utils';\nimport type { Currency } from './constants.js';\nimport type { DigestStore, PaymentReport } from './server.js';\nimport { parseAmountToRaw, withRetry } from './utils.js';\n\n// ---------------------------------------------------------------------------\n// x402 dialect for the suimpp rail — scheme `exact` on network `sui:*`.\n//\n// Canonical design doc: t2000-internal `spec/active/SUIMPP_X402_SCHEME.md`\n// (v0.3, APPROVED). The settlement rail is identical to the legacy digest\n// dialect — a gasless stablecoin transfer (`0x2::balance::send_funds`,\n// gasPrice = 0, no gas payment, protocol-level gasless). The ONLY change is\n// choreography: the client SIGNS but does not submit; the server (gateway /\n// facilitator) submits at serve time. This makes no-charge-on-failure\n// structural and clients sign-only.\n//\n// Replay binding (on-chain): the stateless address-balance form requires\n// `ValidDuring { minEpoch, maxEpoch, chain, nonce }` expiration — we derive\n// the nonce from the challenge id, which cryptographically binds the signed\n// payment to the specific 402 challenge and guarantees two same-amount\n// payments in the same epoch produce distinct digests. The nonce carries\n// UNIQUENESS, not secrecy (challenge ids are already unguessable HMAC\n// outputs); replay safety = challenge-once + digest-once + the 1-epoch\n// window, enforced server-side.\n// ---------------------------------------------------------------------------\n\nexport const X402_SCHEME = 'exact' as const;\nexport const X402_VERSION = 1 as const;\n/** Request header carrying the signed payment (x402 standard). */\nexport const X402_PAYMENT_HEADER = 'X-PAYMENT';\n/** Response header carrying the settlement result (x402 standard). */\nexport const X402_PAYMENT_RESPONSE_HEADER = 'X-PAYMENT-RESPONSE';\n\n/** The Sui framework package — the ONLY package a payment PTB may call. */\nconst FRAMEWORK_PACKAGE = normalizeSuiAddress('0x2');\n/** `module::function` pairs that move funds to the recipient. */\nconst SEND_FUNDS_FNS = new Set(['balance::send_funds', 'coin::send_funds']);\n/** Every `module::function` permitted in a payment PTB (the gasless trio). */\nconst ALLOWED_FNS = new Set([\n ...SEND_FUNDS_FNS,\n 'balance::redeem_funds',\n 'coin::redeem_funds',\n 'balance::withdrawal_split',\n 'coin::into_balance',\n]);\n\nexport type X402Network =\n `sui:${'mainnet' | 'testnet' | 'devnet' | 'localnet'}`;\n\nexport interface X402Requirements {\n scheme: typeof X402_SCHEME;\n network: X402Network;\n /** Full Sui coin type of the payment asset. */\n asset: string;\n /** Atomic units (e.g. USDC 6dp) as a decimal string. */\n maxAmountRequired: string;\n payTo: string;\n resource: string;\n maxTimeoutSeconds: number;\n extra: {\n suimpp: {\n /** The mppx challenge id this payment must bind to (single-use). */\n challengeId: string;\n /** u32 derived from challengeId — goes into ValidDuring.nonce. */\n nonce: number;\n /** Chain identifier string for ValidDuring (genesis digest). */\n chain: string;\n minEpoch: string;\n maxEpoch: string;\n };\n };\n}\n\nexport interface X402PaymentPayload {\n x402Version: typeof X402_VERSION;\n scheme: typeof X402_SCHEME;\n network: X402Network;\n payload: {\n senderAddress: string;\n /** base64 BCS TransactionData — fully signed-ready bytes. */\n txBytes: string;\n /** Sender signature over txBytes (Ed25519 / secp / zkLogin). */\n senderSignature: string;\n challengeId: string;\n };\n}\n\nexport interface X402SettleResponse {\n success: boolean;\n network: X402Network;\n /** Settled transaction digest. */\n transaction: string;\n payer: string;\n}\n\n/**\n * Derive the ValidDuring nonce (u32) from a challenge id. FNV-1a 32-bit —\n * dependency-free and browser-safe. The nonce provides per-challenge\n * UNIQUENESS (distinct digests for otherwise-identical payments); it is not\n * a secret and carries no security on its own.\n */\nexport function challengeNonce(challengeId: string): number {\n let hash = 0x811c9dc5;\n for (let i = 0; i < challengeId.length; i++) {\n hash ^= challengeId.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return hash >>> 0;\n}\n\nexport function x402Network(\n network: 'mainnet' | 'testnet' | 'devnet' | 'localnet',\n): X402Network {\n return `sui:${network}`;\n}\n\n// ---------------------------------------------------------------------------\n// Server half — build the `accepts[]` entry for a 402 response\n// ---------------------------------------------------------------------------\n\nexport interface CreateRequirementsOptions {\n challengeId: string;\n /** Human-units amount string from the challenge (e.g. \"0.02\"). */\n amount: string;\n currency: Currency;\n recipient: string;\n resource: string;\n network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';\n /** Chain identifier string (genesis digest) for ValidDuring. */\n chain: string;\n /** Current epoch — requirements are valid for [epoch, epoch + 1]. */\n currentEpoch: bigint | number | string;\n maxTimeoutSeconds?: number;\n}\n\nexport function createX402Requirements(\n options: CreateRequirementsOptions,\n): X402Requirements {\n const amountRaw = parseAmountToRaw(options.amount, options.currency.decimals);\n const minEpoch = BigInt(options.currentEpoch);\n return {\n scheme: X402_SCHEME,\n network: x402Network(options.network),\n asset: options.currency.type,\n maxAmountRequired: amountRaw.toString(),\n payTo: options.recipient,\n resource: options.resource,\n maxTimeoutSeconds: options.maxTimeoutSeconds ?? 60,\n extra: {\n suimpp: {\n challengeId: options.challengeId,\n nonce: challengeNonce(options.challengeId),\n chain: options.chain,\n minEpoch: minEpoch.toString(),\n maxEpoch: (minEpoch + 1n).toString(),\n },\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Client half — build + sign the payment WITHOUT submitting\n// ---------------------------------------------------------------------------\n\nexport interface BuildSignedPaymentOptions {\n requirements: X402Requirements;\n signer: Signer;\n /**\n * Optional client for build-time resolution. The canonical stateless\n * shape (address-balance withdrawal → redeem_funds → send_funds) has no\n * object inputs, so the build is offline when omitted.\n */\n client?: ClientWithCoreApi;\n}\n\n/**\n * Build the canonical stateless payment transaction, sign it, and return the\n * `X-PAYMENT` header value + parsed payload. Never submits — settlement is\n * the server's job (`settleX402Payment`).\n */\nexport async function buildX402SignedPayment(\n options: BuildSignedPaymentOptions,\n): Promise<{ header: string; payment: X402PaymentPayload }> {\n const { requirements, signer } = options;\n const { suimpp } = requirements.extra;\n const sender = signer.toSuiAddress();\n const amountRaw = BigInt(requirements.maxAmountRequired);\n\n const tx = new Transaction();\n tx.setSender(sender);\n\n const [balance] = tx.moveCall({\n target: '0x2::balance::redeem_funds',\n typeArguments: [requirements.asset],\n arguments: [tx.withdrawal({ amount: amountRaw, type: requirements.asset })],\n });\n tx.moveCall({\n target: '0x2::balance::send_funds',\n typeArguments: [requirements.asset],\n arguments: [balance, tx.pure.address(requirements.payTo)],\n });\n\n // Gasless stablecoin transfer: empty gas payment + zero price/budget.\n tx.setGasPrice(0);\n tx.setGasBudget(0);\n tx.setGasPayment([]);\n tx.setExpiration({\n ValidDuring: {\n minEpoch: suimpp.minEpoch,\n maxEpoch: suimpp.maxEpoch,\n minTimestamp: null,\n maxTimestamp: null,\n chain: suimpp.chain,\n nonce: suimpp.nonce,\n },\n });\n\n const bytes = options.client\n ? await tx.build({ client: options.client })\n : await tx.build();\n const { signature } = await signer.signTransaction(bytes);\n\n const payment: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: X402_SCHEME,\n network: requirements.network,\n payload: {\n senderAddress: sender,\n txBytes: toBase64(bytes),\n senderSignature: signature,\n challengeId: suimpp.challengeId,\n },\n };\n return { header: encodeX402Header(payment), payment };\n}\n\nexport function encodeX402Header(payment: X402PaymentPayload): string {\n return toBase64(new TextEncoder().encode(JSON.stringify(payment)));\n}\n\nexport function parseX402Header(headerValue: string): X402PaymentPayload {\n let parsed: X402PaymentPayload;\n try {\n parsed = JSON.parse(new TextDecoder().decode(fromBase64(headerValue)));\n } catch {\n throw new Error('[suimpp/x402] X-PAYMENT header is not base64 JSON');\n }\n if (parsed.scheme !== X402_SCHEME) {\n throw new Error(`[suimpp/x402] Unsupported scheme: ${parsed.scheme}`);\n }\n const p = parsed.payload;\n if (\n !p?.txBytes ||\n !p?.senderSignature ||\n !p?.challengeId ||\n !p?.senderAddress\n ) {\n throw new Error('[suimpp/x402] X-PAYMENT payload missing required fields');\n }\n return parsed;\n}\n\n// ---------------------------------------------------------------------------\n// Server half — verify (pre-settle, structural) + settle (submit + confirm)\n// ---------------------------------------------------------------------------\n\nexport interface VerifyX402Options {\n payment: X402PaymentPayload;\n /** The terms this payment must match (from the original challenge). */\n expected: {\n challengeId: string;\n amount: string;\n currency: Currency;\n recipient: string;\n network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';\n };\n}\n\n/**\n * Structural pre-settle verification: the signed bytes must be the canonical\n * gasless payment for OUR terms before we relay them. Catches wrong-terms /\n * relay-abuse payloads without an RPC call.\n *\n * SCOPE (Phase 1): this is a STRUCTURAL check — it does NOT verify\n * `senderSignature`. Signature authority is the chain at `settleX402Payment`\n * (a bad signature fails `executeTransaction`, and under settle-then-serve\n * the upstream is never called), plus the post-settle balance-change check.\n * A standalone Phase-3 public `/verify` endpoint adds an explicit async\n * signature check (needs a client for zkLogin) on top of this.\n */\nexport function verifyX402Payment(options: VerifyX402Options): {\n txBytes: Uint8Array;\n nonce: number;\n} {\n const { payment, expected } = options;\n\n if (payment.network !== x402Network(expected.network)) {\n throw new Error(`[suimpp/x402] Network mismatch: ${payment.network}`);\n }\n if (payment.payload.challengeId !== expected.challengeId) {\n throw new Error('[suimpp/x402] Payment is bound to a different challenge');\n }\n\n const txBytes = fromBase64(payment.payload.txBytes);\n const tx = Transaction.from(txBytes);\n const data = tx.getData();\n\n if (\n !data.sender ||\n normalizeSuiAddress(data.sender) !==\n normalizeSuiAddress(payment.payload.senderAddress)\n ) {\n throw new Error('[suimpp/x402] Transaction sender mismatch');\n }\n\n // Gasless shape: zero price, no gas payment objects.\n const gas = data.gasData;\n if (BigInt(gas.price ?? 1) !== 0n || (gas.payment?.length ?? 0) > 0) {\n throw new Error('[suimpp/x402] Transaction is not a gasless transfer');\n }\n\n // ValidDuring nonce = the on-chain challenge binding.\n const expiration = data.expiration;\n const validDuring =\n expiration && 'ValidDuring' in expiration ? expiration.ValidDuring : null;\n if (!validDuring) {\n throw new Error(\n '[suimpp/x402] Transaction must use ValidDuring expiration',\n );\n }\n const expectedNonce = challengeNonce(expected.challengeId);\n if (Number(validDuring.nonce) !== expectedNonce) {\n throw new Error(\n '[suimpp/x402] ValidDuring nonce does not bind to the challenge',\n );\n }\n\n // Command allowlist: only the gasless transfer trio on the FRAMEWORK\n // package (0x2) may appear, and at least one send_funds must pay the\n // expected recipient. The package check is load-bearing — a malicious\n // `0xEVIL::balance::send_funds` must NOT pass as `0x2::balance::send_funds`.\n const normalizedRecipient = normalizeSuiAddress(expected.recipient);\n let paysRecipient = false;\n for (const command of data.commands) {\n if (!('MoveCall' in command) || !command.MoveCall) {\n throw new Error('[suimpp/x402] Only MoveCall commands are permitted');\n }\n const call = command.MoveCall;\n const fn = `${call.module}::${call.function}`;\n if (normalizeSuiAddress(call.package) !== FRAMEWORK_PACKAGE) {\n throw new Error(\n `[suimpp/x402] Non-framework package call: ${call.package}::${fn}`,\n );\n }\n if (!ALLOWED_FNS.has(fn)) {\n throw new Error(`[suimpp/x402] Disallowed Move call: 0x2::${fn}`);\n }\n if (SEND_FUNDS_FNS.has(fn)) {\n const recipientArg = call.arguments[call.arguments.length - 1];\n if (\n recipientArg &&\n typeof recipientArg === 'object' &&\n 'Input' in recipientArg\n ) {\n const input = data.inputs[recipientArg.Input as number];\n if (input && 'Pure' in input && input.Pure?.bytes) {\n const addr = `0x${toHex(fromBase64(input.Pure.bytes))}`;\n if (normalizeSuiAddress(addr) === normalizedRecipient) {\n paysRecipient = true;\n }\n }\n }\n }\n }\n if (!paysRecipient) {\n throw new Error(\n '[suimpp/x402] Transaction does not pay the expected recipient',\n );\n }\n\n return { txBytes, nonce: expectedNonce };\n}\n\nexport interface SettleX402Options {\n payment: X402PaymentPayload;\n client: ClientWithCoreApi;\n /** Digest replay store — shared with the legacy dialect. */\n store: DigestStore;\n expected: VerifyX402Options['expected'];\n onPayment?: (report: PaymentReport) => void;\n}\n\n/**\n * Settle-then-serve: verify structurally, submit the client-signed bytes,\n * confirm the on-chain balance change, record the digest. Throws (and the\n * host returns 402) without serving if anything fails — and because the\n * host only calls the upstream AFTER this resolves, a failed upstream can\n * void/refund before any service value is lost.\n */\nexport async function settleX402Payment(\n options: SettleX402Options,\n): Promise<X402SettleResponse> {\n const { payment, client, store, expected } = options;\n const { txBytes } = verifyX402Payment({ payment, expected });\n\n const result = await withRetry(\n () =>\n client.core.executeTransaction({\n transaction: txBytes,\n signatures: [payment.payload.senderSignature],\n include: { balanceChanges: true, transaction: true },\n }),\n { attempts: 3, baseDelayMs: 500 },\n );\n\n const resolved = result.Transaction ?? result.FailedTransaction;\n if (!resolved?.status.success) {\n throw new Error(\n `[suimpp/x402] Settlement failed on-chain: ${\n resolved?.status.error?.message ?? 'unknown'\n }`,\n );\n }\n\n const digest = resolved.digest;\n if (await store.has(digest)) {\n throw new Error(`[suimpp/x402] Digest already used: ${digest}`);\n }\n\n // Post-settle enforcement (same checks as the legacy dialect).\n const normalizedRecipient = normalizeSuiAddress(expected.recipient);\n const paid = resolved.balanceChanges.find(\n (bc) =>\n bc.coinType === expected.currency.type &&\n normalizeSuiAddress(bc.address) === normalizedRecipient &&\n BigInt(bc.amount) > 0n,\n );\n const requestedRaw = parseAmountToRaw(\n expected.amount,\n expected.currency.decimals,\n );\n if (!paid || BigInt(paid.amount) < requestedRaw) {\n throw new Error('[suimpp/x402] Settled amount does not satisfy the terms');\n }\n\n await store.set(digest);\n\n const report: PaymentReport = {\n digest,\n sender: payment.payload.senderAddress,\n recipient: expected.recipient,\n amount: expected.amount,\n currency: expected.currency.type,\n network: expected.network,\n };\n if (options.onPayment) {\n try {\n options.onPayment(report);\n } catch {}\n }\n\n return {\n success: true,\n network: payment.network,\n transaction: digest,\n payer: payment.payload.senderAddress,\n };\n}\n\nexport function encodeX402Response(response: X402SettleResponse): string {\n return toBase64(new TextEncoder().encode(JSON.stringify(response)));\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/@suimpp+mpp@0.8.1_@modelcontextprotocol+sdk@1.28.0_zod@3.25.76__express@5.2.1_hono@4.12_f78e9d565196b7d48429724cce956455/node_modules/@suimpp/mpp/src/utils.ts","../../../node_modules/.pnpm/@suimpp+mpp@0.8.1_@modelcontextprotocol+sdk@1.28.0_zod@3.25.76__express@5.2.1_hono@4.12_f78e9d565196b7d48429724cce956455/node_modules/@suimpp/mpp/src/x402.ts"],"sourcesContent":["/**\n * Parse a string amount to raw bigint units without floating-point math.\n * \"0.01\" with 6 decimals → 10000n\n */\nexport function parseAmountToRaw(amount: string, decimals: number): bigint {\n const [whole = '0', frac = ''] = amount.split('.');\n const paddedFrac = frac.padEnd(decimals, '0').slice(0, decimals);\n return BigInt(whole + paddedFrac);\n}\n\n/**\n * Retry an async function with linear backoff.\n * Throws the last error if all attempts fail.\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n {\n attempts = 5,\n baseDelayMs = 1000,\n }: { attempts?: number; baseDelayMs?: number } = {},\n): Promise<T> {\n let lastError: unknown;\n for (let i = 0; i < attempts; i++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (i < attempts - 1) {\n await new Promise((r) => setTimeout(r, baseDelayMs * (i + 1)));\n }\n }\n }\n throw lastError;\n}\n","import type { ClientWithCoreApi } from '@mysten/sui/client';\nimport type { Signer } from '@mysten/sui/cryptography';\nimport { Transaction } from '@mysten/sui/transactions';\nimport {\n fromBase64,\n normalizeSuiAddress,\n toBase64,\n toHex,\n} from '@mysten/sui/utils';\nimport type { Currency } from './constants.js';\nimport type { DigestStore, PaymentReport } from './server.js';\nimport { parseAmountToRaw, withRetry } from './utils.js';\n\n// ---------------------------------------------------------------------------\n// x402 dialect for the suimpp rail — scheme `exact` on network `sui:*`.\n//\n// Canonical design doc: t2000-internal `spec/active/SUIMPP_X402_SCHEME.md`\n// (v0.3, APPROVED). The settlement rail is identical to the legacy digest\n// dialect — a gasless stablecoin transfer (`0x2::balance::send_funds`,\n// gasPrice = 0, no gas payment, protocol-level gasless). The ONLY change is\n// choreography: the client SIGNS but does not submit; the server (gateway /\n// facilitator) submits at serve time. This makes no-charge-on-failure\n// structural and clients sign-only.\n//\n// Replay binding (on-chain): the stateless address-balance form requires\n// `ValidDuring { minEpoch, maxEpoch, chain, nonce }` expiration — we derive\n// the nonce from the challenge id, which cryptographically binds the signed\n// payment to the specific 402 challenge and guarantees two same-amount\n// payments in the same epoch produce distinct digests. The nonce carries\n// UNIQUENESS, not secrecy (challenge ids are already unguessable HMAC\n// outputs); replay safety = challenge-once + digest-once + the 1-epoch\n// window, enforced server-side.\n// ---------------------------------------------------------------------------\n\nexport const X402_SCHEME = 'exact' as const;\nexport const X402_VERSION = 1 as const;\n/** Request header carrying the signed payment (x402 standard). */\nexport const X402_PAYMENT_HEADER = 'X-PAYMENT';\n/** Response header carrying the settlement result (x402 standard). */\nexport const X402_PAYMENT_RESPONSE_HEADER = 'X-PAYMENT-RESPONSE';\n\n/** The Sui framework package — the ONLY package a payment PTB may call. */\nconst FRAMEWORK_PACKAGE = normalizeSuiAddress('0x2');\n/** `module::function` pairs that move funds to the recipient. */\nconst SEND_FUNDS_FNS = new Set(['balance::send_funds', 'coin::send_funds']);\n/** Every `module::function` permitted in a payment PTB (the gasless trio). */\nconst ALLOWED_FNS = new Set([\n ...SEND_FUNDS_FNS,\n 'balance::redeem_funds',\n 'coin::redeem_funds',\n 'balance::withdrawal_split',\n 'coin::into_balance',\n]);\n\nexport type X402Network =\n `sui:${'mainnet' | 'testnet' | 'devnet' | 'localnet'}`;\n\nexport interface X402Requirements {\n scheme: typeof X402_SCHEME;\n network: X402Network;\n /** Full Sui coin type of the payment asset. */\n asset: string;\n /** Atomic units (e.g. USDC 6dp) as a decimal string. */\n maxAmountRequired: string;\n payTo: string;\n resource: string;\n maxTimeoutSeconds: number;\n extra: {\n suimpp: {\n /** The mppx challenge id this payment must bind to (single-use). */\n challengeId: string;\n /** u32 derived from challengeId — goes into ValidDuring.nonce. */\n nonce: number;\n /** Chain identifier string for ValidDuring (genesis digest). */\n chain: string;\n minEpoch: string;\n maxEpoch: string;\n };\n };\n}\n\nexport interface X402PaymentPayload {\n x402Version: typeof X402_VERSION;\n scheme: typeof X402_SCHEME;\n network: X402Network;\n payload: {\n senderAddress: string;\n /** base64 BCS TransactionData — fully signed-ready bytes. */\n txBytes: string;\n /** Sender signature over txBytes (Ed25519 / secp / zkLogin). */\n senderSignature: string;\n challengeId: string;\n };\n}\n\nexport interface X402SettleResponse {\n success: boolean;\n network: X402Network;\n /** Settled transaction digest. */\n transaction: string;\n payer: string;\n}\n\n/**\n * Derive the ValidDuring nonce (u32) from a challenge id. FNV-1a 32-bit —\n * dependency-free and browser-safe. The nonce provides per-challenge\n * UNIQUENESS (distinct digests for otherwise-identical payments); it is not\n * a secret and carries no security on its own.\n */\nexport function challengeNonce(challengeId: string): number {\n let hash = 0x811c9dc5;\n for (let i = 0; i < challengeId.length; i++) {\n hash ^= challengeId.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return hash >>> 0;\n}\n\nexport function x402Network(\n network: 'mainnet' | 'testnet' | 'devnet' | 'localnet',\n): X402Network {\n return `sui:${network}`;\n}\n\n// ---------------------------------------------------------------------------\n// Server half — build the `accepts[]` entry for a 402 response\n// ---------------------------------------------------------------------------\n\nexport interface CreateRequirementsOptions {\n challengeId: string;\n /** Human-units amount string from the challenge (e.g. \"0.02\"). */\n amount: string;\n currency: Currency;\n recipient: string;\n resource: string;\n network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';\n /** Chain identifier string (genesis digest) for ValidDuring. */\n chain: string;\n /** Current epoch — requirements are valid for [epoch, epoch + 1]. */\n currentEpoch: bigint | number | string;\n maxTimeoutSeconds?: number;\n}\n\nexport function createX402Requirements(\n options: CreateRequirementsOptions,\n): X402Requirements {\n const amountRaw = parseAmountToRaw(options.amount, options.currency.decimals);\n const minEpoch = BigInt(options.currentEpoch);\n return {\n scheme: X402_SCHEME,\n network: x402Network(options.network),\n asset: options.currency.type,\n maxAmountRequired: amountRaw.toString(),\n payTo: options.recipient,\n resource: options.resource,\n maxTimeoutSeconds: options.maxTimeoutSeconds ?? 60,\n extra: {\n suimpp: {\n challengeId: options.challengeId,\n nonce: challengeNonce(options.challengeId),\n chain: options.chain,\n minEpoch: minEpoch.toString(),\n maxEpoch: (minEpoch + 1n).toString(),\n },\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Client half — build + sign the payment WITHOUT submitting\n// ---------------------------------------------------------------------------\n\nexport interface BuildSignedPaymentOptions {\n requirements: X402Requirements;\n signer: Signer;\n /**\n * Optional client for build-time resolution. The canonical stateless\n * shape (address-balance withdrawal → redeem_funds → send_funds) has no\n * object inputs, so the build is offline when omitted.\n */\n client?: ClientWithCoreApi;\n}\n\n/**\n * Build the canonical stateless payment transaction, sign it, and return the\n * `X-PAYMENT` header value + parsed payload. Never submits — settlement is\n * the server's job (`settleX402Payment`).\n */\nexport async function buildX402SignedPayment(\n options: BuildSignedPaymentOptions,\n): Promise<{ header: string; payment: X402PaymentPayload }> {\n const { requirements, signer } = options;\n const { suimpp } = requirements.extra;\n const sender = signer.toSuiAddress();\n const amountRaw = BigInt(requirements.maxAmountRequired);\n\n const tx = new Transaction();\n tx.setSender(sender);\n\n const [balance] = tx.moveCall({\n target: '0x2::balance::redeem_funds',\n typeArguments: [requirements.asset],\n arguments: [tx.withdrawal({ amount: amountRaw, type: requirements.asset })],\n });\n tx.moveCall({\n target: '0x2::balance::send_funds',\n typeArguments: [requirements.asset],\n arguments: [balance, tx.pure.address(requirements.payTo)],\n });\n\n // Gasless stablecoin transfer: empty gas payment + zero price/budget.\n tx.setGasPrice(0);\n tx.setGasBudget(0);\n tx.setGasPayment([]);\n tx.setExpiration({\n ValidDuring: {\n minEpoch: suimpp.minEpoch,\n maxEpoch: suimpp.maxEpoch,\n minTimestamp: null,\n maxTimestamp: null,\n chain: suimpp.chain,\n nonce: suimpp.nonce,\n },\n });\n\n const bytes = options.client\n ? await tx.build({ client: options.client })\n : await tx.build();\n const { signature } = await signer.signTransaction(bytes);\n\n const payment: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: X402_SCHEME,\n network: requirements.network,\n payload: {\n senderAddress: sender,\n txBytes: toBase64(bytes),\n senderSignature: signature,\n challengeId: suimpp.challengeId,\n },\n };\n return { header: encodeX402Header(payment), payment };\n}\n\nexport function encodeX402Header(payment: X402PaymentPayload): string {\n return toBase64(new TextEncoder().encode(JSON.stringify(payment)));\n}\n\nexport function parseX402Header(headerValue: string): X402PaymentPayload {\n let parsed: X402PaymentPayload;\n try {\n parsed = JSON.parse(new TextDecoder().decode(fromBase64(headerValue)));\n } catch {\n throw new Error('[suimpp/x402] X-PAYMENT header is not base64 JSON');\n }\n if (parsed.scheme !== X402_SCHEME) {\n throw new Error(`[suimpp/x402] Unsupported scheme: ${parsed.scheme}`);\n }\n const p = parsed.payload;\n if (\n !p?.txBytes ||\n !p?.senderSignature ||\n !p?.challengeId ||\n !p?.senderAddress\n ) {\n throw new Error('[suimpp/x402] X-PAYMENT payload missing required fields');\n }\n return parsed;\n}\n\n// ---------------------------------------------------------------------------\n// Server half — verify (pre-settle, structural) + settle (submit + confirm)\n// ---------------------------------------------------------------------------\n\nexport interface VerifyX402Options {\n payment: X402PaymentPayload;\n /** The terms this payment must match (from the original challenge). */\n expected: {\n challengeId: string;\n amount: string;\n currency: Currency;\n recipient: string;\n network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';\n };\n}\n\n/**\n * Structural pre-settle verification: the signed bytes must be the canonical\n * gasless payment for OUR terms before we relay them. Catches wrong-terms /\n * relay-abuse payloads without an RPC call.\n *\n * SCOPE (Phase 1): this is a STRUCTURAL check — it does NOT verify\n * `senderSignature`. Signature authority is the chain at `settleX402Payment`\n * (a bad signature fails `executeTransaction`, and under settle-then-serve\n * the upstream is never called), plus the post-settle balance-change check.\n * A standalone Phase-3 public `/verify` endpoint adds an explicit async\n * signature check (needs a client for zkLogin) on top of this.\n */\nexport function verifyX402Payment(options: VerifyX402Options): {\n txBytes: Uint8Array;\n nonce: number;\n} {\n const { payment, expected } = options;\n\n if (payment.network !== x402Network(expected.network)) {\n throw new Error(`[suimpp/x402] Network mismatch: ${payment.network}`);\n }\n if (payment.payload.challengeId !== expected.challengeId) {\n throw new Error('[suimpp/x402] Payment is bound to a different challenge');\n }\n\n const txBytes = fromBase64(payment.payload.txBytes);\n const tx = Transaction.from(txBytes);\n const data = tx.getData();\n\n if (\n !data.sender ||\n normalizeSuiAddress(data.sender) !==\n normalizeSuiAddress(payment.payload.senderAddress)\n ) {\n throw new Error('[suimpp/x402] Transaction sender mismatch');\n }\n\n // Gasless shape: zero price, no gas payment objects.\n const gas = data.gasData;\n if (BigInt(gas.price ?? 1) !== 0n || (gas.payment?.length ?? 0) > 0) {\n throw new Error('[suimpp/x402] Transaction is not a gasless transfer');\n }\n\n // ValidDuring nonce = the on-chain challenge binding.\n const expiration = data.expiration;\n const validDuring =\n expiration && 'ValidDuring' in expiration ? expiration.ValidDuring : null;\n if (!validDuring) {\n throw new Error(\n '[suimpp/x402] Transaction must use ValidDuring expiration',\n );\n }\n const expectedNonce = challengeNonce(expected.challengeId);\n if (Number(validDuring.nonce) !== expectedNonce) {\n throw new Error(\n '[suimpp/x402] ValidDuring nonce does not bind to the challenge',\n );\n }\n\n // Command allowlist: only the gasless transfer trio on the FRAMEWORK\n // package (0x2) may appear, and at least one send_funds must pay the\n // expected recipient. The package check is load-bearing — a malicious\n // `0xEVIL::balance::send_funds` must NOT pass as `0x2::balance::send_funds`.\n const normalizedRecipient = normalizeSuiAddress(expected.recipient);\n let paysRecipient = false;\n for (const command of data.commands) {\n if (!('MoveCall' in command) || !command.MoveCall) {\n throw new Error('[suimpp/x402] Only MoveCall commands are permitted');\n }\n const call = command.MoveCall;\n const fn = `${call.module}::${call.function}`;\n if (normalizeSuiAddress(call.package) !== FRAMEWORK_PACKAGE) {\n throw new Error(\n `[suimpp/x402] Non-framework package call: ${call.package}::${fn}`,\n );\n }\n if (!ALLOWED_FNS.has(fn)) {\n throw new Error(`[suimpp/x402] Disallowed Move call: 0x2::${fn}`);\n }\n if (SEND_FUNDS_FNS.has(fn)) {\n const recipientArg = call.arguments[call.arguments.length - 1];\n if (\n recipientArg &&\n typeof recipientArg === 'object' &&\n 'Input' in recipientArg\n ) {\n const input = data.inputs[recipientArg.Input as number];\n if (input && 'Pure' in input && input.Pure?.bytes) {\n const addr = `0x${toHex(fromBase64(input.Pure.bytes))}`;\n if (normalizeSuiAddress(addr) === normalizedRecipient) {\n paysRecipient = true;\n }\n }\n }\n }\n }\n if (!paysRecipient) {\n throw new Error(\n '[suimpp/x402] Transaction does not pay the expected recipient',\n );\n }\n\n return { txBytes, nonce: expectedNonce };\n}\n\nexport interface SettleX402Options {\n payment: X402PaymentPayload;\n client: ClientWithCoreApi;\n /** Digest replay store — shared with the legacy dialect. */\n store: DigestStore;\n expected: VerifyX402Options['expected'];\n onPayment?: (report: PaymentReport) => void;\n}\n\n/**\n * Settle-then-serve: verify structurally, submit the client-signed bytes,\n * confirm the on-chain balance change, record the digest. Throws (and the\n * host returns 402) without serving if anything fails — and because the\n * host only calls the upstream AFTER this resolves, a failed upstream can\n * void/refund before any service value is lost.\n */\nexport async function settleX402Payment(\n options: SettleX402Options,\n): Promise<X402SettleResponse> {\n const { payment, client, store, expected } = options;\n const { txBytes } = verifyX402Payment({ payment, expected });\n\n const result = await withRetry(\n () =>\n client.core.executeTransaction({\n transaction: txBytes,\n signatures: [payment.payload.senderSignature],\n include: { balanceChanges: true, transaction: true },\n }),\n { attempts: 3, baseDelayMs: 500 },\n );\n\n const resolved = result.Transaction ?? result.FailedTransaction;\n if (!resolved?.status.success) {\n throw new Error(\n `[suimpp/x402] Settlement failed on-chain: ${\n resolved?.status.error?.message ?? 'unknown'\n }`,\n );\n }\n\n const digest = resolved.digest;\n if (await store.has(digest)) {\n throw new Error(`[suimpp/x402] Digest already used: ${digest}`);\n }\n\n // Post-settle enforcement (same checks as the legacy dialect).\n const normalizedRecipient = normalizeSuiAddress(expected.recipient);\n const paid = resolved.balanceChanges.find(\n (bc) =>\n bc.coinType === expected.currency.type &&\n normalizeSuiAddress(bc.address) === normalizedRecipient &&\n BigInt(bc.amount) > 0n,\n );\n const requestedRaw = parseAmountToRaw(\n expected.amount,\n expected.currency.decimals,\n );\n if (!paid || BigInt(paid.amount) < requestedRaw) {\n throw new Error('[suimpp/x402] Settled amount does not satisfy the terms');\n }\n\n await store.set(digest);\n\n const report: PaymentReport = {\n digest,\n sender: payment.payload.senderAddress,\n recipient: expected.recipient,\n amount: expected.amount,\n currency: expected.currency.type,\n network: expected.network,\n };\n if (options.onPayment) {\n try {\n options.onPayment(report);\n } catch {}\n }\n\n return {\n success: true,\n network: payment.network,\n transaction: digest,\n payer: payment.payload.senderAddress,\n };\n}\n\nexport function encodeX402Response(response: X402SettleResponse): string {\n return toBase64(new TextEncoder().encode(JSON.stringify(response)));\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t2000/cli",
3
- "version": "5.6.0",
3
+ "version": "5.7.0",
4
4
  "description": "Agent Wallet for AI agents on Sui — gasless USDC + USDsui sends, Cetus swap, MPP paid API access, MCP integration, scriptable from any shell.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -45,8 +45,8 @@
45
45
  "typescript": "^5",
46
46
  "typescript-eslint": "^8.58.0",
47
47
  "vitest": "^3",
48
- "@t2000/mcp": "5.6.0",
49
- "@t2000/sdk": "5.6.0"
48
+ "@t2000/mcp": "5.7.0",
49
+ "@t2000/sdk": "5.7.0"
50
50
  },
51
51
  "license": "MIT",
52
52
  "dependencies": {