@@ -101,9 +101,45 @@ export type Condition = | RatioToAmountCondition | RatioToSupplyCondition
Show 7 hidden lines
+/** Wallet family for a proven payer. */+export type WalletType = 'evm' | 'solana' | 'xrpl' | 'bitcoin'++/**+ * A payer the caller has cryptographically proven for this request.+ *+ * Accepts a `did:pkh:...` string, a bare `0x` EVM address, or an explicit
+ * `{ address, type }` pair. Bare non-EVM addresses are rejected because their+ * wallet family cannot be inferred unambiguously — pass the object form.+ */+export type ProvenPayer =+ | string+ | { address: string; type: WalletType }+ | null
Show 18 hidden lines
+ | undefined+ export type ConditionGateOptions = { /** InsumerAPI key. Falls back to INSUMER_API_KEY env var. */ apiKey?: string+ /**+ * Resolves the payer that the payment method has PROVEN controls this+ * request. Required for free access — without it every request takes the+ * paid path.+ *+ * It receives only mppx's method-specific validation `details` (for example+ * a recovered payer address). It is deliberately NOT given the credential or+ * the declared `source`: mppx documents `source` as "an asserted identity,+ * not independent proof of control", and granting on it is the vulnerability+ * fixed in 3.0.0 (GHSA-jg6q-3qfh-r9f8).+ *+ * Return `null` when no payer has been proven. Returning an address you have+ * not proven reintroduces that vulnerability.
+ *+ * @example+ * ```ts+ * provenPayer: (details) => (details as { payer?: string }).payer ?? null+ * ```+ */+ provenPayer?: (details: unknown) => ProvenPayer | Promise<ProvenPayer> /** One or more conditions to evaluate. Mix any of the six types. */ conditions: Condition[] /** Whether the wallet must satisfy "any" (default) or "all" conditions. */
Show 7 hidden lines
@@ -343,20 +379,60 @@ async function callAttest( // conditionGate adapter // --------------------------------------------------------------------------- +/**+ * Normalizes a caller-supplied proven payer into an address + wallet family.+ *
+ * Fail-closed: anything it cannot resolve unambiguously returns null, which+ * sends the request to the paid path.+ */+export function normalizeProvenPayer(+ payer: ProvenPayer,+): { address: string; type: WalletType } | null {+ if (!payer) return null+
Show 22 hidden lines
+ if (typeof payer === 'object') {+ const { address, type } = payer+ if (!address || !type) return null+ return { address, type }+ }++ if (typeof payer !== 'string') return null++ const evm = parseDid(payer)+ if (evm) return { address: evm, type: 'evm' }+ const sol = parseSolanaDid(payer)+ if (sol) return { address: sol, type: 'solana' }+ const xrpl = parseXrplDid(payer)+ if (xrpl) return { address: xrpl, type: 'xrpl' }+ const btc = parseBitcoinDid(payer)+ if (btc) return { address: btc, type: 'bitcoin' }++ // Bare EVM address is unambiguous; anything else needs the object form.+ if (payer.startsWith('0x')) return { address: payer, type: 'evm' }+ return null+}+
/** * Wraps an mppx Method.Server with condition-based access using signed attestations. *- * Extracts the payer address from credential.source (DID), calls /v1/attest to- * evaluate conditions across the 35 chains this adapter reaches (32 EVM + Solana + XRPL + Bitcoin; the engine itself covers 38), and returns a free-access receipt for- * wallets that meet the conditions. Wallets that do not meet them fall through- * to the original payment method.
Adds provenPayer and normalizeProvenPayer so free access requires a payer proven by the payment method. The resolver receives only validation details, not credential.source, and unresolved payers fail closed to the paid path.