{"_id":"@cardanotech/walletproof","_rev":"2-357c2847c92e5834fcc6eac25cd2c53e","name":"@cardanotech/walletproof","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.0":{"name":"@cardanotech/walletproof","version":"1.0.0","keywords":["cardano","cip-8","cip-19","cip-30","wallet-proof","typescript"],"author":"Task Venture Capital GmbH","license":"MIT","_id":"@cardanotech/walletproof@1.0.0","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"homepage":"https://code.foss.global/cardano.tech/walletproof#readme","bugs":{"url":"https://code.foss.global/cardano.tech/walletproof/issues"},"dist":{"shasum":"e9df58d3f131e6489848f992bcf2229241572b0f","tarball":"https://registry.npmjs.org/@cardanotech/walletproof/-/walletproof-1.0.0.tgz","fileCount":46,"integrity":"sha512-b2Xz97tPRybYzvNOZeCMH90X59PCnGNLFieXinOghUUXLRsmoCYbOLsUpWI4bsH0Lp8f2QvT+3O430nqqyl65A==","signatures":[{"sig":"MEUCIQDDRmrm5zdiu6GD8k8oINjNWywqDd3eAFSwfhCeoxGiPAIgPFxT+vQUT7sBK2xwQSxRI+L47Z7l7rKHVEOq2+ntL1s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":177128},"main":"dist_ts/index.js","type":"module","exports":{".":{"types":"./dist_ts/index.d.ts","import":"./dist_ts/index.js"},"./server":{"types":"./dist_ts/server.d.ts","import":"./dist_ts/server.js"},"./browser":{"types":"./dist_ts/browser.d.ts","import":"./dist_ts/browser.js"}},"private":false,"scripts":{"test":"tstest test/ --verbose","build":"tsbuild"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"repository":{"url":"git+ssh://git@code.foss.global:29419/cardano.tech/walletproof.git","type":"git"},"description":"Non-custodial Cardano wallet-control proofs using CIP-30, CIP-8, and CIP-19.","directories":{},"_nodeVersion":"25.2.1","browserslist":["last 1 chrome versions"],"dependencies":{"@scure/base":"^2.2.0","@stricahq/cbors":"^1.1.0","@cardano-foundation/cardano-verify-datasignature":"^1.0.11"},"_hasShrinkwrap":false,"devDependencies":{"blakejs":"^1.2.1","@types/node":"^26.1.1","@git.zone/tsrun":"^2.0.5","@git.zone/tstest":"^3.6.7","@git.zone/tsbuild":"^4.4.2"},"_npmOperationalInternal":{"tmp":"tmp/walletproof_1.0.0_1785176726233_0.5123598210215257","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@cardanotech/walletproof","version":"1.1.0","private":false,"description":"Non-custodial Cardano wallet-control proofs using CIP-30, CIP-8, and CIP-19.","main":"dist_ts/index.js","typings":"dist_ts/index.d.ts","type":"module","exports":{".":{"types":"./dist_ts/index.d.ts","import":"./dist_ts/index.js"},"./browser":{"types":"./dist_ts/browser.d.ts","import":"./dist_ts/browser.js"},"./server":{"types":"./dist_ts/server.d.ts","import":"./dist_ts/server.js"}},"author":"Task Venture Capital GmbH","license":"MIT","dependencies":{"@cardano-foundation/cardano-verify-datasignature":"^1.0.11","@scure/base":"^2.2.0","@stricahq/cbors":"^1.1.0"},"devDependencies":{"@git.zone/tsbuild":"^4.4.2","@git.zone/tsrun":"^2.0.5","@git.zone/tstest":"^3.6.7","@types/node":"^26.1.1","blakejs":"^1.2.1"},"repository":{"type":"git","url":"git+ssh://git@code.foss.global:29419/cardano.tech/walletproof.git"},"bugs":{"url":"https://code.foss.global/cardano.tech/walletproof/issues"},"homepage":"https://code.foss.global/cardano.tech/walletproof#readme","keywords":["cardano","cip-8","cip-19","cip-30","wallet-proof","typescript"],"browserslist":["last 1 chrome versions"],"scripts":{"test":"tstest test/ --verbose","build":"tsbuild"},"_nodeVersion":"25.2.1","_id":"@cardanotech/walletproof@1.1.0","dist":{"integrity":"sha512-aJ+g/ov7ZOWHomRaHvyWAJ54D0IdTsVBDCMv0iGxYKDXuI3Exj/gSCHjJAfT1eMQT3g+K7FvNhWn2VWLmOlyFw==","shasum":"90e8d57c60cd7f4bb3258833ce53d0973bd08a86","tarball":"https://registry.npmjs.org/@cardanotech/walletproof/-/walletproof-1.1.0.tgz","fileCount":46,"unpackedSize":182195,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCMNQH0W30JVjvGVS120Vby+QKQ8LM0OSUTJKzdMap9JgIgGYq0VeW125oR9fol02GmraXlSjTLpcLfb8DdwvLpqg4="}]},"_npmUser":{"name":"lossless","email":"hello@lossless.com"},"directories":{},"maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/walletproof_1.1.0_1785182463459_0.5688125733312528"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-27T18:25:26.085Z","modified":"2026-07-27T20:01:03.843Z","1.0.0":"2026-07-27T18:25:26.410Z","1.1.0":"2026-07-27T20:01:03.676Z"},"bugs":{"url":"https://code.foss.global/cardano.tech/walletproof/issues"},"author":"Task Venture Capital GmbH","license":"MIT","homepage":"https://code.foss.global/cardano.tech/walletproof#readme","keywords":["cardano","cip-8","cip-19","cip-30","wallet-proof","typescript"],"repository":{"type":"git","url":"git+ssh://git@code.foss.global:29419/cardano.tech/walletproof.git"},"description":"Non-custodial Cardano wallet-control proofs using CIP-30, CIP-8, and CIP-19.","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"readme":"# @cardanotech/walletproof\n\n`@cardanotech/walletproof` provides a non-custodial Cardano wallet-control proof\nprotocol. It creates short-lived, audience-bound challenges, signs their exact\nUTF-8 payload through a CIP-30 browser wallet, validates CIP-19 reward addresses,\nand verifies CIP-8 COSE signatures on the server.\n\nThe v1 profile proves control of one key-backed reward address at one moment. It\ndoes not establish personhood, authenticate an account by itself, recover an\naccount, provide MFA, or grant an entitlement.\n\n## Issue Reporting and Security\n\nFor reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.\n\n## Install\n\n```sh\npnpm add @cardanotech/walletproof\n```\n\n## Protocol profile\n\nWallet Proof v1 accepts only canonical, key-backed CIP-19 reward addresses:\n\n- `stake` addresses on mainnet;\n- `stake_test` addresses on test networks;\n- exactly 29 bytes with header type `14`;\n- the exact address used for CIP-30 `signData`.\n\nPayment addresses, script-backed reward addresses, malformed addresses, and\nnetwork mismatches fail closed. CIP-30 distinguishes mainnet from testnet but\ndoes not distinguish preview from pre-production.\n\nThe server stores the exact challenge message and verifies that payload. It does\nnot reconstruct a message from completion-time browser input. Challenge claims\nare single-use: the repository atomically moves a matching pending challenge to\n`verifying`, and an invalid completion burns it. Claims carry an expiring,\nattempt-specific token so an abandoned verification can be reclaimed without a\nstale attempt terminalizing the newer claim.\n\nTenant, subject, and credential identifiers are keyed HMAC-SHA-256 values. The\nservice requires a stable deployment binding secret of at least 32 random bytes.\nSubject and credential identifiers are tenant-scoped, so the default receipt does\nnot provide a cross-tenant correlation key.\n\nThe server verifier applies a strict CIP-30 profile before cryptographic\nverification:\n\n- protected `alg` is EdDSA (`-8`) and protected `address` equals the submitted\n  raw reward address;\n- unprotected `hashed` is present and `false`;\n- embedded payloads equal the exact challenge message; detached payloads are\n  verified against that message;\n- the COSE key is OKP/Ed25519 with a 32-byte public key and no private-key\n  material;\n- optional key identifiers are byte strings present on both structures and equal;\n- duplicate or conflicting header labels, malformed lengths, and non-minimal\n  protected-map encodings fail closed.\n\nUnknown well-formed extension headers remain permitted. The protected map must use\nthe minimal definite-length encoding accepted by the underlying Cardano Foundation\nverifier; this explicit v1 compatibility constraint avoids silently verifying\ndifferent bytes than the wallet signed.\n\n## Browser usage\n\nThe consuming application obtains a CIP-30 API from the wallet extension and\npasses it to `WalletProofBrowserClient`. Wallet discovery and user consent remain\nthe host application's responsibility.\n\n```ts\nimport { WalletProofBrowserClient } from '@cardanotech/walletproof/browser';\nimport type { IWalletProofChallenge } from '@cardanotech/walletproof';\n\nconst challenge: IWalletProofChallenge = await response.json();\nconst walletApi = await window.cardano.eternl.enable();\n\nconst browserClient = new WalletProofBrowserClient();\nconst submission = await browserClient.createSubmission(walletApi, challenge);\n\nawait fetch('/wallet-proof/complete', {\n  method: 'POST',\n  headers: { 'content-type': 'application/json' },\n  body: JSON.stringify(submission),\n});\n```\n\nThe challenge contains both authoritative structured `messageData` and its\ncanonical `message`. Before any wallet access, `createSubmission()` validates the\nenvelope against `messageData`, re-encodes and compares the exact message, and\nrejects expiry or an origin mismatch. The expected origin defaults to the executing\nbrowser's `location.origin`; non-browser tests must pass `expectedOrigin`\nexplicitly. It then checks the wallet network, selects from a bounded reward-address\nset, encodes the challenge message as UTF-8 hexadecimal, calls `signData`, and\nreturns the canonical address with bounded COSE signature and key values.\n\n## Server usage\n\nThe server must derive the trusted context from authenticated application state.\nNever accept tenant, subject, issuer, audience, origin, or purpose authority from\nthe browser.\n\n```ts\nimport {\n  InMemoryWalletProofRepository,\n  WalletProofService,\n} from '@cardanotech/walletproof/server';\nimport type {\n  IWalletProofSubmission,\n  IWalletProofTrustedContext,\n} from '@cardanotech/walletproof';\n\nconst repository = new InMemoryWalletProofRepository();\ndeclare const bindingSecret: Uint8Array; // Stable 32+ random bytes from a secret boundary.\nconst walletProofService = new WalletProofService({\n  repository,\n  bindingSecret,\n});\n\nconst trustedContext: IWalletProofTrustedContext = {\n  tenantId: 'tenant_01J...',\n  subjectId: 'subject_01J...',\n  issuer: 'https://cardano.example',\n  audience: 'my-application',\n  origin: 'https://app.example',\n  purpose: 'link-wallet',\n};\n\nconst challenge = await walletProofService.createChallenge(\n  trustedContext,\n  'testnet',\n);\n\nconst submission: IWalletProofSubmission = await receiveBrowserSubmission();\nconst receipt = await walletProofService.completeChallenge(\n  trustedContext,\n  submission,\n);\n\n// During application/service shutdown, after admission of new work has stopped:\nwalletProofService.dispose();\n```\n\n`InMemoryWalletProofRepository` is explicitly for tests and local development.\nIt is not durable and must not be used by a hosted or production service. It has a\nconfigurable hard record bound (10,000 by default), evicts retained terminal records\nunder capacity pressure, and exposes `clear()` for explicit disposal.\nProduction integration requires an `IWalletProofRepository` implementation with\ndurable, tenant-scoped atomic claim, claim-lease, and token-guarded terminal\ntransitions, such as SmartData on MongoDB. Verification has a configurable deadline\n(10 seconds by default, one minute maximum) and supplies an `AbortSignal` to custom\nverifiers.\n\n`dispose()` is idempotent, rejects new operations, and zeroes the service-owned\nbinding-secret copy. Operations already in flight finish using isolated copies\nthat are zeroed in `finally`. The repository and verifier remain caller-owned and\nare not stopped or disposed by the service.\n\n## Receipt privacy\n\nThe default receipt contains a domain-separated credential identifier, bindings\nto the trusted tenant and subject, protocol context, timestamps, and verifier\nprofile. It intentionally excludes the raw reward address, COSE key, signature,\nand challenge message. With the same binding secret, tenant, network, and reward\naddress, `credentialId` is stable so a tenant can recognize an existing link. It is\nnot stable across tenants or binding-secret rotation.\n\n## Production boundary\n\nThis package is a protocol and library foundation, not a production gateway. A\nhosted integration must additionally provide authenticated start and completion\nmethods, authorization, tenant policy, rate limits, durable persistence, audit,\nretention, and operational controls. Mainnet enablement should remain a separate\npolicy decision. The binding secret belongs in an injected managed-secret boundary;\nrotation requires an explicit identifier-migration plan.\n\nThe broader component and service design is documented in the cardano.tech\n`target-architecture.md`.\n\n## License and Legal Information\n\nThis repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository license file.\n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.\n\nUse of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.\n\n### Company Information\n\nTask Venture Capital GmbH<br>\nRegistered at District Court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n","readmeFilename":""}