@zkproofport-app/sdk 0.3.3 → 0.4.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.
- package/README.md +9 -82
- package/dist/circuits.d.ts +6 -11
- package/dist/circuits.esm.js +8 -20
- package/dist/circuits.esm.js.map +1 -1
- package/dist/circuits.js +8 -20
- package/dist/circuits.js.map +1 -1
- package/dist/circuits.mjs +8 -20
- package/dist/circuits.mjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +24 -63
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +24 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +24 -63
- package/dist/index.mjs.map +1 -1
- package/dist/typedAction.d.ts +1 -1
- package/dist/typedAction.esm.js +1 -1
- package/dist/typedAction.esm.js.map +1 -1
- package/dist/typedAction.js +1 -1
- package/dist/typedAction.js.map +1 -1
- package/dist/typedAction.mjs +1 -1
- package/dist/typedAction.mjs.map +1 -1
- package/dist/types.d.ts +8 -21
- package/package.json +1 -1
package/dist/circuits.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"circuits.mjs","sources":["../src/circuits.ts"],"sourcesContent":["/**\n * Canonical ZKProofport circuit identifiers.\n *\n * This module is the single source of truth for circuit IDs. Every other layer\n * — the mobile app, the demo, the relay, server-side provers — reads its list\n * from here instead of keeping a private copy that silently drifts.\n *\n * It has **no imports and no dependencies**, so it can be pulled in on its own:\n *\n * ```typescript\n * import { CIRCUIT_IDS, isCircuitId } from '@zkproofport-app/sdk/circuits';\n * ```\n *\n * The same names are also re-exported from the package root\n * (`@zkproofport-app/sdk`) for callers that already import the SDK.\n *\n * ## Identifiers are canonical and case-sensitive\n *\n * Each ID is the circuit's `name` in its `Nargo.toml`, verbatim. The format is\n * lowercase with underscores. Hyphenated spellings (`coinbase-kyc`,\n * `mdl-kr-age`) are directory or UI route names in other repositories — they\n * are **not** circuit IDs, and passing one produces a nullifier mismatch or a\n * failed on-chain lookup rather than a clear error.\n */\n\n/**\n * Whether a circuit is officially supported today or still on the roadmap.\n *\n * - `supported` — generally available. Safe to build a product on.\n * - `planned` — the identifier is reserved and the circuit exists, but it is\n * not officially supported yet. Availability, inputs and public-input layout\n * may change without a major version bump.\n */\nexport type CircuitSupportStatus = 'supported' | 'experimental' | 'planned';\n\n/**\n * Canonical circuit identifiers, keyed by a stable constant name.\n *\n * Prefer these constants over string literals so a rename is a compile error\n * rather than a runtime surprise.\n *\n * @example\n * ```typescript\n * import { CIRCUIT_IDS } from '@zkproofport-app/sdk/circuits';\n *\n * const relay = await sdk.createRelayRequest(CIRCUIT_IDS.COINBASE_ATTESTATION, {\n * scope: 'myapp.com',\n * });\n * ```\n */\nexport const CIRCUIT_IDS = Object.freeze({\n /** Coinbase KYC attestation. Officially supported. */\n COINBASE_ATTESTATION: 'coinbase_attestation',\n /** Coinbase country attestation (inclusion / exclusion). Officially supported. */\n COINBASE_COUNTRY_ATTESTATION: 'coinbase_country_attestation',\n /** OIDC email-domain attestation. Officially supported. */\n OIDC_DOMAIN_ATTESTATION: 'oidc_domain_attestation',\n /** Arc eligibility: exact EIP-712 action authorization. Experimental on Arc Testnet. */\n ARC_ELIGIBILITY: 'arc_eligibility',\n /** GIWA attestation. Planned — not officially supported yet. */\n GIWA_ATTESTATION: 'giwa_attestation',\n /** Korea Mobile ID ownership. Planned — not officially supported yet. */\n MDL_KR_OWNERSHIP: 'mdl_kr_ownership',\n /** Korea Mobile ID age threshold. Planned — not officially supported yet. */\n MDL_KR_AGE: 'mdl_kr_age',\n /** Korea Mobile ID si/do region. Planned — not officially supported yet. */\n MDL_KR_REGION: 'mdl_kr_region',\n} as const);\n\n/**\n * Union of every canonical circuit identifier.\n *\n * `CircuitType` (exported from the package root) is an alias of this type — the\n * two names refer to the same union, and this module is where it is defined.\n */\nexport type CircuitId = (typeof CIRCUIT_IDS)[keyof typeof CIRCUIT_IDS];\n\n/**\n * Support status for every circuit.\n *\n * The record is exhaustive over {@link CircuitId}: adding an identifier without\n * giving it a status is a compile error, so this list cannot drift from\n * {@link CIRCUIT_IDS}.\n *\n * @example\n * ```typescript\n * import { CIRCUIT_SUPPORT_STATUS } from '@zkproofport-app/sdk/circuits';\n *\n * CIRCUIT_SUPPORT_STATUS.coinbase_attestation; // 'supported'\n * CIRCUIT_SUPPORT_STATUS.mdl_kr_age; // 'planned'\n * ```\n */\nexport const CIRCUIT_SUPPORT_STATUS: Readonly<Record<CircuitId, CircuitSupportStatus>> =\n Object.freeze({\n coinbase_attestation: 'supported',\n coinbase_country_attestation: 'supported',\n oidc_domain_attestation: 'supported',\n arc_eligibility: 'experimental',\n // Experimental, not planned: the circuit is built, its verifier is\n // deployed on GIWA Sepolia and the demo requests it. What keeps it out of\n // 'supported' is that it is testnet-only, so the app offers it behind\n // Developer Mode and reads its files from main rather than a release tag.\n giwa_attestation: 'experimental',\n mdl_kr_ownership: 'planned',\n mdl_kr_age: 'planned',\n mdl_kr_region: 'planned',\n } as const);\n\n/**\n * Where each circuit's verification key FILE lives inside the\n * `zkproofport/circuits` repository, relative to its root.\n *\n * Off-chain verification needs the verification key and nothing else — no\n * circuit bytecode, no witness. The key is public by nature: it is what anyone\n * checking a proof must already have, and the Solidity verifiers deployed\n * on-chain embed the same key.\n *\n * NOTE THE TRAILING `/vk` TWICE. In that repository `target/vk` is a DIRECTORY\n * holding `vk`, `vk_hash` and `SHA256SUMS`; the key itself is `target/vk/vk`.\n * These paths were first copied here from the mobile app, which keeps the\n * directory and the filename as two fields and joins them — so taking only the\n * directory produced a URL that answers 404, and the first browser to try\n * off-chain verification said \"Could not fetch the verification key (HTTP 404)\".\n *\n * Exhaustive over {@link CircuitId} on purpose. A new circuit whose key path is\n * not listed here fails to compile rather than failing at verification time,\n * where the only symptom would be a proof that cannot be checked.\n */\nexport const CIRCUIT_VK_PATHS: Readonly<Record<CircuitId, string>> = Object.freeze({\n coinbase_attestation: 'coinbase-attestation/target/vk/vk',\n coinbase_country_attestation: 'coinbase-country-attestation/target/vk/vk',\n oidc_domain_attestation: 'oidc-domain-attestation/target/vk/vk',\n arc_eligibility: 'arc-eligibility/target/vk/vk',\n giwa_attestation: 'giwa-attestation/target/vk/vk',\n mdl_kr_ownership: 'mdl/kr-ownership/target/vk/vk',\n mdl_kr_age: 'mdl/kr-age/target/vk/vk',\n mdl_kr_region: 'mdl/kr-region/target/vk/vk',\n} as const);\n\n/**\n * Every canonical circuit identifier, in declaration order.\n *\n * Includes circuits that are still `planned`. Use {@link SUPPORTED_CIRCUIT_IDS}\n * when you only want the ones that are officially supported today.\n */\nexport const ALL_CIRCUIT_IDS: readonly CircuitId[] = Object.freeze(\n Object.values(CIRCUIT_IDS) as CircuitId[]\n);\n\n/**\n * Circuits that are officially supported today: the two Coinbase circuits and\n * OIDC domain attestation.\n *\n * Derived from {@link CIRCUIT_SUPPORT_STATUS}, so it cannot fall out of sync.\n */\nexport const SUPPORTED_CIRCUIT_IDS: readonly CircuitId[] = Object.freeze(\n ALL_CIRCUIT_IDS.filter((id) => CIRCUIT_SUPPORT_STATUS[id] === 'supported')\n);\n\n/**\n * Circuits whose identifiers are reserved but which are not officially\n * supported yet: GIWA attestation and the three Korea Mobile ID circuits.\n *\n * Derived from {@link CIRCUIT_SUPPORT_STATUS}, so it cannot fall out of sync.\n */\n/**\n * Circuits you can prove today, on a testnet, with everything subject to change.\n *\n * `arc_eligibility` is the reason this status exists. Calling it `planned`\n * would be wrong — the circuit compiles, the verifier is deployed and a proof\n * verifies against it — and calling it `supported` would be worse, because the\n * only deployment is Arc Testnet, Circle has not published a mainnet chain id,\n * and the public-input layout is still open. Neither existing word was true, so\n * the honest move was a third word rather than picking the closer lie.\n */\nexport const EXPERIMENTAL_CIRCUIT_IDS: readonly CircuitId[] = Object.freeze(\n ALL_CIRCUIT_IDS.filter(id => CIRCUIT_SUPPORT_STATUS[id] === 'experimental'),\n);\n\nexport const PLANNED_CIRCUIT_IDS: readonly CircuitId[] = Object.freeze(\n ALL_CIRCUIT_IDS.filter((id) => CIRCUIT_SUPPORT_STATUS[id] === 'planned')\n);\n\n/**\n * Narrows an unknown value to a canonical circuit identifier.\n *\n * Returns `false` for hyphenated route names such as `'coinbase-kyc'`, which\n * are not circuit IDs.\n *\n * @example\n * ```typescript\n * isCircuitId('coinbase_attestation'); // true\n * isCircuitId('coinbase-kyc'); // false\n * ```\n */\nexport function isCircuitId(value: unknown): value is CircuitId {\n return typeof value === 'string' && (ALL_CIRCUIT_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Narrows an unknown value to a circuit identifier that is officially supported\n * today. Planned circuits return `false`.\n *\n * @example\n * ```typescript\n * isSupportedCircuitId('oidc_domain_attestation'); // true\n * isSupportedCircuitId('mdl_kr_age'); // false — planned\n * ```\n */\nexport function isSupportedCircuitId(value: unknown): value is CircuitId {\n return isCircuitId(value) && CIRCUIT_SUPPORT_STATUS[value] === 'supported';\n}\n\n/**\n * Returns the support status of a circuit.\n *\n * @param circuit - A canonical circuit identifier.\n * @throws Error when the value is not a canonical circuit identifier.\n *\n * @example\n * ```typescript\n * getCircuitSupportStatus('giwa_attestation'); // 'planned'\n * ```\n */\nexport function getCircuitSupportStatus(circuit: CircuitId): CircuitSupportStatus {\n if (!isCircuitId(circuit)) {\n throw new Error(\n `Unknown circuit '${String(circuit)}'. Expected one of: ${ALL_CIRCUIT_IDS.join(', ')}`\n );\n }\n return CIRCUIT_SUPPORT_STATUS[circuit];\n}\n\n/**\n * Whether a circuit's relay request must carry a wallet signature.\n *\n * The SDK checks this to fail fast — \"Signer not set\" locally beats a 401 from\n * the relay two round trips later, with nothing saying which circuit needed\n * what. The relay declares its OWN copy on purpose and does not import this\n * one: it is a security boundary, and an auth policy that a published package\n * can change is not a policy. A test in the relay asserts the two agree.\n *\n * `satisfies` and not an annotation, so a circuit added above is a compile\n * error here until somebody decides which it is.\n */\n/**\n * Whether a circuit's proof can bind an EIP-712 action, and whether it must.\n *\n * ONE TABLE, because the answer was becoming a chain of `circuit === '...'`\n * tests. It was asked in the deep-link validator and again in\n * `createRelayRequest`, both spelling out `arc_eligibility`, and a second\n * action-capable circuit would have made each of them a two-branch chain that\n * ends on whatever the last test happens to be.\n *\n * 'required' the circuit proves nothing without an action -- the wallet\n * signs the typed data and there is no other message.\n * 'optional' the circuit signs the action when one is supplied and\n * personal_signs its signal hash when one is not. The circuit\n * itself branches; see giwa-attestation/src/main.nr.\n * 'none' the circuit has no action inputs. An action sent anyway is a\n * caller misunderstanding, and is refused rather than dropped:\n * silently ignoring it would let a dapp believe a proof\n * authorized something it never mentioned.\n */\nexport type CircuitActionBinding = 'none' | 'required' | 'optional';\n\nexport const CIRCUIT_ACTION_BINDING = {\n coinbase_attestation: 'none',\n coinbase_country_attestation: 'none',\n // The signature lives inside the identity token; no wallet, no action.\n oidc_domain_attestation: 'none',\n // Both branch in-circuit: with an action the wallet signs the typed data,\n // without one it personal_signs the request's signal hash. Arc read\n // 'required' until 2026-09-22 because its circuit had no second path -- a\n // request without an action built a vector 64 bytes short and died inside\n // the prover. The circuit gained the branch; the table follows it.\n arc_eligibility: 'optional',\n giwa_attestation: 'optional',\n mdl_kr_ownership: 'none',\n mdl_kr_age: 'none',\n mdl_kr_region: 'none',\n} satisfies Record<CircuitId, CircuitActionBinding>;\n\n/*\n * The union is declared above rather than derived from the table's values.\n *\n * Deriving it narrowed the type to whatever the table happens to hold today --\n * 'none' | 'optional' -- and TypeScript then called every `=== 'required'`\n * check impossible. The publish typecheck caught it; `rollup` and `vitest` did\n * not. 'required' is a state a circuit can legitimately be in (an EIP-712 path\n * and nothing else), so the union says so and the table is checked against it.\n */\n\n/**\n * How this circuit treats an action, or an error naming the id that is not one.\n *\n * No default: a circuit nobody has classified must not inherit 'none', which\n * would silently drop an action a dapp meant to bind.\n */\nexport function circuitActionBinding(circuit: string): CircuitActionBinding {\n const binding = (CIRCUIT_ACTION_BINDING as Record<string, CircuitActionBinding | undefined>)[circuit];\n if (!binding) {\n throw new Error(\n `Unknown circuit '${circuit}'. Expected: ${ALL_CIRCUIT_IDS.join(', ')}`,\n );\n }\n return binding;\n}\n\nexport const CIRCUIT_NEEDS_WALLET_SIGNATURE = {\n coinbase_attestation: true,\n coinbase_country_attestation: true,\n // Same Coinbase-attested wallet as above; what changes is that it signs an\n // EIP-712 action rather than signal_hash.\n arc_eligibility: true,\n // The signature is inside the OIDC identity token, checked by the prover.\n oidc_domain_attestation: false,\n // Web2 (OmniOne CX) flows with no wallet binding at all.\n mdl_kr_ownership: false,\n mdl_kr_age: false,\n mdl_kr_region: false,\n // A GIWA-attested wallet signing an EIP-712 action, the same shape as Arc.\n // This read `false` while the circuit had always verified a wallet signature\n // -- it sat under the Web2 comment above and was never revisited. A request\n // for it would have reached the relay with no signer.\n giwa_attestation: true,\n} satisfies Record<CircuitId, boolean>;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"circuits.mjs","sources":["../src/circuits.ts"],"sourcesContent":["/**\n * Canonical ZKProofport circuit identifiers.\n *\n * This module is the single source of truth for circuit IDs. Every other layer\n * — the mobile app, the demo, the relay, server-side provers — reads its list\n * from here instead of keeping a private copy that silently drifts.\n *\n * It has **no imports and no dependencies**, so it can be pulled in on its own:\n *\n * ```typescript\n * import { CIRCUIT_IDS, isCircuitId } from '@zkproofport-app/sdk/circuits';\n * ```\n *\n * The same names are also re-exported from the package root\n * (`@zkproofport-app/sdk`) for callers that already import the SDK.\n *\n * ## Identifiers are canonical and case-sensitive\n *\n * Each ID is the circuit's `name` in its `Nargo.toml`, verbatim. The format is\n * lowercase with underscores. Hyphenated spellings (`coinbase-kyc`,\n * `mdl-kr-age`) are directory or UI route names in other repositories — they\n * are **not** circuit IDs, and passing one produces a nullifier mismatch or a\n * failed on-chain lookup rather than a clear error.\n */\n\n/**\n * Whether a circuit is officially supported today or still on the roadmap.\n *\n * - `supported` — generally available. Safe to build a product on.\n * - `planned` — the identifier is reserved and the circuit exists, but it is\n * not officially supported yet. Availability, inputs and public-input layout\n * may change without a major version bump.\n */\nexport type CircuitSupportStatus = 'supported' | 'experimental' | 'planned';\n\n/**\n * Canonical circuit identifiers, keyed by a stable constant name.\n *\n * Prefer these constants over string literals so a rename is a compile error\n * rather than a runtime surprise.\n *\n * @example\n * ```typescript\n * import { CIRCUIT_IDS } from '@zkproofport-app/sdk/circuits';\n *\n * const relay = await sdk.createRelayRequest(CIRCUIT_IDS.COINBASE_ATTESTATION, {\n * scope: 'myapp.com',\n * });\n * ```\n */\nexport const CIRCUIT_IDS = Object.freeze({\n /** Coinbase KYC attestation. Officially supported. */\n COINBASE_ATTESTATION: 'coinbase_attestation',\n /** Coinbase country attestation (inclusion / exclusion). Officially supported. */\n COINBASE_COUNTRY_ATTESTATION: 'coinbase_country_attestation',\n /** OIDC email-domain attestation. Officially supported. */\n OIDC_DOMAIN_ATTESTATION: 'oidc_domain_attestation',\n /** GIWA attestation. Planned — not officially supported yet. */\n GIWA_ATTESTATION: 'giwa_attestation',\n /** Korea Mobile ID ownership. Planned — not officially supported yet. */\n MDL_KR_OWNERSHIP: 'mdl_kr_ownership',\n /** Korea Mobile ID age threshold. Planned — not officially supported yet. */\n MDL_KR_AGE: 'mdl_kr_age',\n /** Korea Mobile ID si/do region. Planned — not officially supported yet. */\n MDL_KR_REGION: 'mdl_kr_region',\n} as const);\n\n/**\n * Union of every canonical circuit identifier.\n *\n * `CircuitType` (exported from the package root) is an alias of this type — the\n * two names refer to the same union, and this module is where it is defined.\n */\nexport type CircuitId = (typeof CIRCUIT_IDS)[keyof typeof CIRCUIT_IDS];\n\n/**\n * Support status for every circuit.\n *\n * The record is exhaustive over {@link CircuitId}: adding an identifier without\n * giving it a status is a compile error, so this list cannot drift from\n * {@link CIRCUIT_IDS}.\n *\n * @example\n * ```typescript\n * import { CIRCUIT_SUPPORT_STATUS } from '@zkproofport-app/sdk/circuits';\n *\n * CIRCUIT_SUPPORT_STATUS.coinbase_attestation; // 'supported'\n * CIRCUIT_SUPPORT_STATUS.mdl_kr_age; // 'planned'\n * ```\n */\nexport const CIRCUIT_SUPPORT_STATUS: Readonly<Record<CircuitId, CircuitSupportStatus>> =\n Object.freeze({\n coinbase_attestation: 'supported',\n coinbase_country_attestation: 'supported',\n oidc_domain_attestation: 'supported',\n // Experimental, not planned: the circuit is built, its verifier is\n // deployed on GIWA Sepolia and the demo requests it. What keeps it out of\n // 'supported' is that it is testnet-only, so the app offers it behind\n // Developer Mode and reads its files from main rather than a release tag.\n giwa_attestation: 'experimental',\n mdl_kr_ownership: 'planned',\n mdl_kr_age: 'planned',\n mdl_kr_region: 'planned',\n } as const);\n\n/**\n * Where each circuit's verification key FILE lives inside the\n * `zkproofport/circuits` repository, relative to its root.\n *\n * Off-chain verification needs the verification key and nothing else — no\n * circuit bytecode, no witness. The key is public by nature: it is what anyone\n * checking a proof must already have, and the Solidity verifiers deployed\n * on-chain embed the same key.\n *\n * NOTE THE TRAILING `/vk` TWICE. In that repository `target/vk` is a DIRECTORY\n * holding `vk`, `vk_hash` and `SHA256SUMS`; the key itself is `target/vk/vk`.\n * These paths were first copied here from the mobile app, which keeps the\n * directory and the filename as two fields and joins them — so taking only the\n * directory produced a URL that answers 404, and the first browser to try\n * off-chain verification said \"Could not fetch the verification key (HTTP 404)\".\n *\n * Exhaustive over {@link CircuitId} on purpose. A new circuit whose key path is\n * not listed here fails to compile rather than failing at verification time,\n * where the only symptom would be a proof that cannot be checked.\n */\nexport const CIRCUIT_VK_PATHS: Readonly<Record<CircuitId, string>> = Object.freeze({\n coinbase_attestation: 'coinbase-attestation/target/vk/vk',\n coinbase_country_attestation: 'coinbase-country-attestation/target/vk/vk',\n oidc_domain_attestation: 'oidc-domain-attestation/target/vk/vk',\n giwa_attestation: 'giwa-attestation/target/vk/vk',\n mdl_kr_ownership: 'mdl/kr-ownership/target/vk/vk',\n mdl_kr_age: 'mdl/kr-age/target/vk/vk',\n mdl_kr_region: 'mdl/kr-region/target/vk/vk',\n} as const);\n\n/**\n * Every canonical circuit identifier, in declaration order.\n *\n * Includes circuits that are still `planned`. Use {@link SUPPORTED_CIRCUIT_IDS}\n * when you only want the ones that are officially supported today.\n */\nexport const ALL_CIRCUIT_IDS: readonly CircuitId[] = Object.freeze(\n Object.values(CIRCUIT_IDS) as CircuitId[]\n);\n\n/**\n * Circuits that are officially supported today: the two Coinbase circuits and\n * OIDC domain attestation.\n *\n * Derived from {@link CIRCUIT_SUPPORT_STATUS}, so it cannot fall out of sync.\n */\nexport const SUPPORTED_CIRCUIT_IDS: readonly CircuitId[] = Object.freeze(\n ALL_CIRCUIT_IDS.filter((id) => CIRCUIT_SUPPORT_STATUS[id] === 'supported')\n);\n\n/**\n * Circuits whose identifiers are reserved but which are not officially\n * supported yet: GIWA attestation and the three Korea Mobile ID circuits.\n *\n * Derived from {@link CIRCUIT_SUPPORT_STATUS}, so it cannot fall out of sync.\n */\n/**\n * Circuits you can prove today, on a testnet, with everything subject to change.\n *\n * `giwa_attestation` is in this state. Calling it `planned` would be wrong —\n * the circuit compiles, the verifier is deployed and a proof verifies against\n * it — and calling it `supported` would be worse, because the only deployment\n * is a testnet (GIWA Sepolia). Neither existing word was true, so the honest\n * move was a third word rather than picking the closer lie.\n */\nexport const EXPERIMENTAL_CIRCUIT_IDS: readonly CircuitId[] = Object.freeze(\n ALL_CIRCUIT_IDS.filter(id => CIRCUIT_SUPPORT_STATUS[id] === 'experimental'),\n);\n\nexport const PLANNED_CIRCUIT_IDS: readonly CircuitId[] = Object.freeze(\n ALL_CIRCUIT_IDS.filter((id) => CIRCUIT_SUPPORT_STATUS[id] === 'planned')\n);\n\n/**\n * Narrows an unknown value to a canonical circuit identifier.\n *\n * Returns `false` for hyphenated route names such as `'coinbase-kyc'`, which\n * are not circuit IDs.\n *\n * @example\n * ```typescript\n * isCircuitId('coinbase_attestation'); // true\n * isCircuitId('coinbase-kyc'); // false\n * ```\n */\nexport function isCircuitId(value: unknown): value is CircuitId {\n return typeof value === 'string' && (ALL_CIRCUIT_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Narrows an unknown value to a circuit identifier that is officially supported\n * today. Planned circuits return `false`.\n *\n * @example\n * ```typescript\n * isSupportedCircuitId('oidc_domain_attestation'); // true\n * isSupportedCircuitId('mdl_kr_age'); // false — planned\n * ```\n */\nexport function isSupportedCircuitId(value: unknown): value is CircuitId {\n return isCircuitId(value) && CIRCUIT_SUPPORT_STATUS[value] === 'supported';\n}\n\n/**\n * Returns the support status of a circuit.\n *\n * @param circuit - A canonical circuit identifier.\n * @throws Error when the value is not a canonical circuit identifier.\n *\n * @example\n * ```typescript\n * getCircuitSupportStatus('giwa_attestation'); // 'planned'\n * ```\n */\nexport function getCircuitSupportStatus(circuit: CircuitId): CircuitSupportStatus {\n if (!isCircuitId(circuit)) {\n throw new Error(\n `Unknown circuit '${String(circuit)}'. Expected one of: ${ALL_CIRCUIT_IDS.join(', ')}`\n );\n }\n return CIRCUIT_SUPPORT_STATUS[circuit];\n}\n\n/**\n * Whether a circuit's relay request must carry a wallet signature.\n *\n * The SDK checks this to fail fast — \"Signer not set\" locally beats a 401 from\n * the relay two round trips later, with nothing saying which circuit needed\n * what. The relay declares its OWN copy on purpose and does not import this\n * one: it is a security boundary, and an auth policy that a published package\n * can change is not a policy. A test in the relay asserts the two agree.\n *\n * `satisfies` and not an annotation, so a circuit added above is a compile\n * error here until somebody decides which it is.\n */\n/**\n * Whether a circuit's proof can bind an EIP-712 action, and whether it must.\n *\n * ONE TABLE, because the answer was becoming a chain of `circuit === '...'`\n * tests. It was asked in the deep-link validator and again in\n * `createRelayRequest`, both spelling out one circuit id, and a second\n * action-capable circuit would have made each of them a two-branch chain that\n * ends on whatever the last test happens to be.\n *\n * 'required' the circuit proves nothing without an action -- the wallet\n * signs the typed data and there is no other message.\n * 'optional' the circuit signs the action when one is supplied and\n * personal_signs its signal hash when one is not. The circuit\n * itself branches; see giwa-attestation/src/main.nr.\n * 'none' the circuit has no action inputs. An action sent anyway is a\n * caller misunderstanding, and is refused rather than dropped:\n * silently ignoring it would let a dapp believe a proof\n * authorized something it never mentioned.\n */\nexport type CircuitActionBinding = 'none' | 'required' | 'optional';\n\nexport const CIRCUIT_ACTION_BINDING = {\n coinbase_attestation: 'none',\n coinbase_country_attestation: 'none',\n // The signature lives inside the identity token; no wallet, no action.\n oidc_domain_attestation: 'none',\n // Branches in-circuit: with an action the wallet signs the typed data,\n // without one it personal_signs the request's signal hash.\n giwa_attestation: 'optional',\n mdl_kr_ownership: 'none',\n mdl_kr_age: 'none',\n mdl_kr_region: 'none',\n} satisfies Record<CircuitId, CircuitActionBinding>;\n\n/*\n * The union is declared above rather than derived from the table's values.\n *\n * Deriving it narrowed the type to whatever the table happens to hold today --\n * 'none' | 'optional' -- and TypeScript then called every `=== 'required'`\n * check impossible. The publish typecheck caught it; `rollup` and `vitest` did\n * not. 'required' is a state a circuit can legitimately be in (an EIP-712 path\n * and nothing else), so the union says so and the table is checked against it.\n */\n\n/**\n * How this circuit treats an action, or an error naming the id that is not one.\n *\n * No default: a circuit nobody has classified must not inherit 'none', which\n * would silently drop an action a dapp meant to bind.\n */\nexport function circuitActionBinding(circuit: string): CircuitActionBinding {\n const binding = (CIRCUIT_ACTION_BINDING as Record<string, CircuitActionBinding | undefined>)[circuit];\n if (!binding) {\n throw new Error(\n `Unknown circuit '${circuit}'. Expected: ${ALL_CIRCUIT_IDS.join(', ')}`,\n );\n }\n return binding;\n}\n\nexport const CIRCUIT_NEEDS_WALLET_SIGNATURE = {\n coinbase_attestation: true,\n coinbase_country_attestation: true,\n // The signature is inside the OIDC identity token, checked by the prover.\n oidc_domain_attestation: false,\n // Web2 (OmniOne CX) flows with no wallet binding at all.\n mdl_kr_ownership: false,\n mdl_kr_age: false,\n mdl_kr_region: false,\n // A GIWA-attested wallet signing an EIP-712 action (or its signal hash).\n // This read `false` while the circuit had always verified a wallet signature\n // -- it sat under the Web2 comment above and was never revisited. A request\n // for it would have reached the relay with no signer.\n giwa_attestation: true,\n} satisfies Record<CircuitId, boolean>;\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -34,5 +34,5 @@ export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT
|
|
|
34
34
|
export type { CircuitId, CircuitSupportStatus } from './circuits';
|
|
35
35
|
export { CIRCUIT_ACTION_BINDING, circuitActionBinding, } from './circuits';
|
|
36
36
|
export type { CircuitActionBinding } from './circuits';
|
|
37
|
-
export type { CircuitType, ProofRequestStatus, CoinbaseKycInputs, ActionBoundInputs,
|
|
37
|
+
export type { CircuitType, ProofRequestStatus, CoinbaseKycInputs, ActionBoundInputs, GiwaAttestationInputs, TypedAction, CoinbaseCountryInputs, OidcDomainInputs, MdlKrOwnershipInputs, MdlKrAgeInputs, MdlKrRegionInputs, CircuitInputs, ProofRequest, ProofResponse, QRCodeOptions, VerifierContract, ProofportConfig, ChallengeResponse, WalletSigner, RelayProofRequest, RelayProofResult, SDKEnvironment, } from './types';
|
|
38
38
|
export { validateTypedAction, parseTypedAction } from './typedAction';
|
package/dist/index.esm.js
CHANGED
|
@@ -79,16 +79,6 @@ const CIRCUIT_METADATA = {
|
|
|
79
79
|
publicInputsCount: 148,
|
|
80
80
|
publicInputNames: ['pubkey_modulus_limbs', 'domain', 'scope', 'nullifier', 'provider'],
|
|
81
81
|
},
|
|
82
|
-
arc_eligibility: {
|
|
83
|
-
name: 'Arc Eligibility',
|
|
84
|
-
description: 'Prove eligibility and authorize one EIP-712 action, for an Arc gate',
|
|
85
|
-
// 6 x `pub [u8; 32]` in arc-eligibility/src/main.nr, flattened to bytes.
|
|
86
|
-
// Read off the compiled ABI rather than counted: signal_hash 0-31,
|
|
87
|
-
// domain_separator 32-63, action_hash 64-95, signer_list_merkle_root
|
|
88
|
-
// 96-127, scope 128-159, nullifier 160-191.
|
|
89
|
-
publicInputsCount: 192,
|
|
90
|
-
publicInputNames: ['signal_hash', 'domain_separator', 'action_hash', 'signer_list_merkle_root'],
|
|
91
|
-
},
|
|
92
82
|
// Planned circuit — the identifier is reserved and the circuit exists, but it
|
|
93
83
|
// is not officially supported yet. See CIRCUIT_SUPPORT_STATUS in ./circuits.
|
|
94
84
|
// Forked from coinbase_attestation, then given the EIP-712 pair and a
|
|
@@ -96,12 +86,12 @@ const CIRCUIT_METADATA = {
|
|
|
96
86
|
// zero; without one it signs signal_hash and the pair is zero. Read off the
|
|
97
87
|
// compiled ABI (6 x [u8; 32] = 192): signal_hash 0-31, domain_separator
|
|
98
88
|
// 32-63, action_hash 64-95, signer_list_merkle_root 96-127, scope 128-159,
|
|
99
|
-
// nullifier 160-191
|
|
89
|
+
// nullifier 160-191.
|
|
100
90
|
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
91
|
+
// signal_hash is NOT part of this circuit's nullifier: a nullifier derived
|
|
92
|
+
// from a public input nobody signs and nothing constrains would let one
|
|
93
|
+
// wallet mint as many nullifiers as it likes; here the secret is the address
|
|
94
|
+
// plus a constant compiled into the circuit.
|
|
105
95
|
giwa_attestation: {
|
|
106
96
|
name: 'GIWA Attestation',
|
|
107
97
|
description: 'Prove GIWA identity verification, optionally authorizing one EIP-712 action (planned — not officially supported yet)',
|
|
@@ -173,11 +163,6 @@ const RPC_ENDPOINTS = {
|
|
|
173
163
|
84532: 'https://sepolia.base.org', // Base Sepolia
|
|
174
164
|
8453: 'https://mainnet.base.org', // Base Mainnet
|
|
175
165
|
91342: 'https://sepolia-rpc.giwa.io', // GIWA Sepolia
|
|
176
|
-
// Arc Testnet. The arc_eligibility verifier is deployed here and nowhere
|
|
177
|
-
// else, and this line was missing on 2026-09-12 — the circuit shipped, a
|
|
178
|
-
// phone produced a valid proof, and on-chain verification answered "No RPC
|
|
179
|
-
// endpoint configured for chain 5042002", which reads like the proof's fault.
|
|
180
|
-
5042002: 'https://rpc.testnet.arc.io', // Arc Testnet
|
|
181
166
|
};
|
|
182
167
|
/**
|
|
183
168
|
* Default proof request expiration time in milliseconds.
|
|
@@ -385,8 +370,6 @@ const CIRCUIT_IDS = Object.freeze({
|
|
|
385
370
|
COINBASE_COUNTRY_ATTESTATION: 'coinbase_country_attestation',
|
|
386
371
|
/** OIDC email-domain attestation. Officially supported. */
|
|
387
372
|
OIDC_DOMAIN_ATTESTATION: 'oidc_domain_attestation',
|
|
388
|
-
/** Arc eligibility: exact EIP-712 action authorization. Experimental on Arc Testnet. */
|
|
389
|
-
ARC_ELIGIBILITY: 'arc_eligibility',
|
|
390
373
|
/** GIWA attestation. Planned — not officially supported yet. */
|
|
391
374
|
GIWA_ATTESTATION: 'giwa_attestation',
|
|
392
375
|
/** Korea Mobile ID ownership. Planned — not officially supported yet. */
|
|
@@ -415,7 +398,6 @@ const CIRCUIT_SUPPORT_STATUS = Object.freeze({
|
|
|
415
398
|
coinbase_attestation: 'supported',
|
|
416
399
|
coinbase_country_attestation: 'supported',
|
|
417
400
|
oidc_domain_attestation: 'supported',
|
|
418
|
-
arc_eligibility: 'experimental',
|
|
419
401
|
// Experimental, not planned: the circuit is built, its verifier is
|
|
420
402
|
// deployed on GIWA Sepolia and the demo requests it. What keeps it out of
|
|
421
403
|
// 'supported' is that it is testnet-only, so the app offers it behind
|
|
@@ -449,7 +431,6 @@ const CIRCUIT_VK_PATHS = Object.freeze({
|
|
|
449
431
|
coinbase_attestation: 'coinbase-attestation/target/vk/vk',
|
|
450
432
|
coinbase_country_attestation: 'coinbase-country-attestation/target/vk/vk',
|
|
451
433
|
oidc_domain_attestation: 'oidc-domain-attestation/target/vk/vk',
|
|
452
|
-
arc_eligibility: 'arc-eligibility/target/vk/vk',
|
|
453
434
|
giwa_attestation: 'giwa-attestation/target/vk/vk',
|
|
454
435
|
mdl_kr_ownership: 'mdl/kr-ownership/target/vk/vk',
|
|
455
436
|
mdl_kr_age: 'mdl/kr-age/target/vk/vk',
|
|
@@ -478,12 +459,11 @@ const SUPPORTED_CIRCUIT_IDS = Object.freeze(ALL_CIRCUIT_IDS.filter((id) => CIRCU
|
|
|
478
459
|
/**
|
|
479
460
|
* Circuits you can prove today, on a testnet, with everything subject to change.
|
|
480
461
|
*
|
|
481
|
-
* `
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
* the honest move was a third word rather than picking the closer lie.
|
|
462
|
+
* `giwa_attestation` is in this state. Calling it `planned` would be wrong —
|
|
463
|
+
* the circuit compiles, the verifier is deployed and a proof verifies against
|
|
464
|
+
* it — and calling it `supported` would be worse, because the only deployment
|
|
465
|
+
* is a testnet (GIWA Sepolia). Neither existing word was true, so the honest
|
|
466
|
+
* move was a third word rather than picking the closer lie.
|
|
487
467
|
*/
|
|
488
468
|
const EXPERIMENTAL_CIRCUIT_IDS = Object.freeze(ALL_CIRCUIT_IDS.filter(id => CIRCUIT_SUPPORT_STATUS[id] === 'experimental'));
|
|
489
469
|
const PLANNED_CIRCUIT_IDS = Object.freeze(ALL_CIRCUIT_IDS.filter((id) => CIRCUIT_SUPPORT_STATUS[id] === 'planned'));
|
|
@@ -537,12 +517,8 @@ const CIRCUIT_ACTION_BINDING = {
|
|
|
537
517
|
coinbase_country_attestation: 'none',
|
|
538
518
|
// The signature lives inside the identity token; no wallet, no action.
|
|
539
519
|
oidc_domain_attestation: 'none',
|
|
540
|
-
//
|
|
541
|
-
// without one it personal_signs the request's signal hash.
|
|
542
|
-
// 'required' until 2026-09-22 because its circuit had no second path -- a
|
|
543
|
-
// request without an action built a vector 64 bytes short and died inside
|
|
544
|
-
// the prover. The circuit gained the branch; the table follows it.
|
|
545
|
-
arc_eligibility: 'optional',
|
|
520
|
+
// Branches in-circuit: with an action the wallet signs the typed data,
|
|
521
|
+
// without one it personal_signs the request's signal hash.
|
|
546
522
|
giwa_attestation: 'optional',
|
|
547
523
|
mdl_kr_ownership: 'none',
|
|
548
524
|
mdl_kr_age: 'none',
|
|
@@ -573,16 +549,13 @@ function circuitActionBinding(circuit) {
|
|
|
573
549
|
const CIRCUIT_NEEDS_WALLET_SIGNATURE = {
|
|
574
550
|
coinbase_attestation: true,
|
|
575
551
|
coinbase_country_attestation: true,
|
|
576
|
-
// Same Coinbase-attested wallet as above; what changes is that it signs an
|
|
577
|
-
// EIP-712 action rather than signal_hash.
|
|
578
|
-
arc_eligibility: true,
|
|
579
552
|
// The signature is inside the OIDC identity token, checked by the prover.
|
|
580
553
|
oidc_domain_attestation: false,
|
|
581
554
|
// Web2 (OmniOne CX) flows with no wallet binding at all.
|
|
582
555
|
mdl_kr_ownership: false,
|
|
583
556
|
mdl_kr_age: false,
|
|
584
557
|
mdl_kr_region: false,
|
|
585
|
-
// A GIWA-attested wallet signing an EIP-712 action
|
|
558
|
+
// A GIWA-attested wallet signing an EIP-712 action (or its signal hash).
|
|
586
559
|
// This read `false` while the circuit had always verified a wallet signature
|
|
587
560
|
// -- it sat under the Web2 comment above and was never revisited. A request
|
|
588
561
|
// for it would have reached the relay with no signer.
|
|
@@ -604,7 +577,7 @@ const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
|
604
577
|
*/
|
|
605
578
|
function validateTypedAction(value) {
|
|
606
579
|
if (value === undefined || value === null) {
|
|
607
|
-
return 'action is required
|
|
580
|
+
return 'action is required. The circuit proves that a wallet authorised ONE EIP-712 action; there is nothing to prove without it.';
|
|
608
581
|
}
|
|
609
582
|
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
610
583
|
return 'action must be an object.';
|
|
@@ -1160,8 +1133,7 @@ function validateProofRequest(request) {
|
|
|
1160
1133
|
return { valid: false, error: 'Missing circuit type' };
|
|
1161
1134
|
}
|
|
1162
1135
|
// The list is the SDK's own, not a copy. The copy that used to sit here
|
|
1163
|
-
//
|
|
1164
|
-
// `arc_eligibility` — so a link for either was refused as an invalid type
|
|
1136
|
+
// had missed circuits, so a link for one was refused as an invalid type
|
|
1165
1137
|
// while every other layer accepted it.
|
|
1166
1138
|
if (!isCircuitId(request.circuit)) {
|
|
1167
1139
|
return {
|
|
@@ -1216,15 +1188,8 @@ function validateProofRequest(request) {
|
|
|
1216
1188
|
return { valid: false, error: mdlError };
|
|
1217
1189
|
}
|
|
1218
1190
|
}
|
|
1219
|
-
else if (request.circuit === 'arc_eligibility') {
|
|
1220
|
-
const inputs = request.inputs;
|
|
1221
|
-
if (inputs.userAddress && !/^0x[a-fA-F0-9]{40}$/.test(inputs.userAddress)) {
|
|
1222
|
-
return { valid: false, error: 'Invalid userAddress format' };
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
1191
|
// The action, decided by the circuit's own entry rather than by naming a
|
|
1226
|
-
// circuit here
|
|
1227
|
-
// which is why a second action-capable circuit had nowhere to be checked.
|
|
1192
|
+
// circuit here, so every action-capable circuit is checked the same way.
|
|
1228
1193
|
{
|
|
1229
1194
|
const action = request.inputs?.action;
|
|
1230
1195
|
const binding = circuitActionBinding(request.circuit);
|
|
@@ -4383,7 +4348,7 @@ function getVerifierContract(providerOrSigner, verifier) {
|
|
|
4383
4348
|
function getDefaultProvider(chainId) {
|
|
4384
4349
|
const rpcUrl = RPC_ENDPOINTS[chainId];
|
|
4385
4350
|
if (!rpcUrl) {
|
|
4386
|
-
throw new Error(`No RPC endpoint configured for chain ${chainId}`);
|
|
4351
|
+
throw new Error(`No RPC endpoint configured for chain ${chainId}. Known chains: ${Object.keys(RPC_ENDPOINTS).join(', ')}`);
|
|
4387
4352
|
}
|
|
4388
4353
|
return createJsonRpcProvider(rpcUrl);
|
|
4389
4354
|
}
|
|
@@ -4532,7 +4497,7 @@ function getVerifierChainId(circuit, customVerifier) {
|
|
|
4532
4497
|
*
|
|
4533
4498
|
* It replaced an `if / else if / else` chain whose final `else` handed every
|
|
4534
4499
|
* unrecognised circuit — and every call that named no circuit at all —
|
|
4535
|
-
* Coinbase's offsets. For `
|
|
4500
|
+
* Coinbase's offsets. For `giwa_attestation` that is not a near miss: its
|
|
4536
4501
|
* public inputs are signal_hash, domain_separator, action_hash, merkle root,
|
|
4537
4502
|
* scope, nullifier, so the nullifier slot under Coinbase's offsets holds the
|
|
4538
4503
|
* MERKLE ROOT, a value identical for every user. Duplicate detection built on
|
|
@@ -4542,15 +4507,13 @@ const PUBLIC_INPUT_OFFSETS = Object.freeze({
|
|
|
4542
4507
|
// signal_hash, signer_list_merkle_root, scope, nullifier
|
|
4543
4508
|
coinbase_attestation: { scope: [64, 95], nullifier: [96, 127] },
|
|
4544
4509
|
// No longer Coinbase's layout. The GIWA circuit gained the EIP-712 pair, so
|
|
4545
|
-
// it reads
|
|
4546
|
-
//
|
|
4510
|
+
// it reads: signal_hash, domain_separator, action_hash, merkle root, then
|
|
4511
|
+
// scope and nullifier 64 bytes further along than Coinbase.
|
|
4547
4512
|
giwa_attestation: { scope: [128, 159], nullifier: [160, 191] },
|
|
4548
4513
|
// country_list, country_list_length and is_included sit before scope.
|
|
4549
4514
|
coinbase_country_attestation: { scope: [86, 117], nullifier: [118, 149] },
|
|
4550
4515
|
// pubkey_modulus_limbs and the bounded domain sit before scope.
|
|
4551
4516
|
oidc_domain_attestation: { scope: [83, 114], nullifier: [115, 146] },
|
|
4552
|
-
// signal_hash, domain_separator, action_hash, merkle root, then the pair.
|
|
4553
|
-
arc_eligibility: { scope: [128, 159], nullifier: [160, 191] },
|
|
4554
4517
|
// The Korea mDL circuits open with the pair; signal_hash is commented out.
|
|
4555
4518
|
mdl_kr_ownership: { scope: [0, 31], nullifier: [32, 63] },
|
|
4556
4519
|
mdl_kr_age: { scope: [0, 31], nullifier: [32, 63] },
|
|
@@ -5931,9 +5894,9 @@ class ProofportSDK {
|
|
|
5931
5894
|
* ```
|
|
5932
5895
|
*/
|
|
5933
5896
|
// Which circuits need a wallet signature, from the one record in
|
|
5934
|
-
// src/circuits.ts.
|
|
5935
|
-
//
|
|
5936
|
-
//
|
|
5897
|
+
// src/circuits.ts. A typed-out list here once missed a circuit, so a dapp
|
|
5898
|
+
// calling createRelayRequest() for it with no signer got no local error and
|
|
5899
|
+
// a relay 401 two round trips later.
|
|
5937
5900
|
static needsWalletSignature(circuit) {
|
|
5938
5901
|
return CIRCUIT_NEEDS_WALLET_SIGNATURE[circuit] === true;
|
|
5939
5902
|
}
|
|
@@ -5958,9 +5921,7 @@ class ProofportSDK {
|
|
|
5958
5921
|
// from inside the mobile app -- a screen the dapp developer never sees,
|
|
5959
5922
|
// reached after the person has already scanned a QR code.
|
|
5960
5923
|
//
|
|
5961
|
-
//
|
|
5962
|
-
// second circuit that can carry an action; the id belongs in the table,
|
|
5963
|
-
// not in the check.
|
|
5924
|
+
// The circuit id belongs in the table, not in the check.
|
|
5964
5925
|
{
|
|
5965
5926
|
const action = inputs.action;
|
|
5966
5927
|
const binding = circuitActionBinding(circuit);
|