{"_id":"@abstraxn/warrant-verifier","name":"@abstraxn/warrant-verifier","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@abstraxn/warrant-verifier","version":"0.1.0","description":"KYI Warrant receipt verifier — offline Ed25519 + optional on-chain MandateRegistry / ReceiptLog checks","main":"./dist/src/index.js","types":"./dist/src/index.d.ts","bin":{"warrant-verify":"dist/src/cli.js"},"exports":{".":{"types":"./dist/src/index.d.ts","import":"./dist/src/index.js","require":"./dist/src/index.js","default":"./dist/src/index.js"}},"scripts":{"build":"rimraf dist && tsc","warrant-verify":"node dist/src/cli.js","prepublishOnly":"npm run build","prepack":"npm run build"},"keywords":["abstraxn","kyi","warrant","verifier","ed25519","receipt","audit","web3","on-chain"],"author":{"name":"Abstraxn Labs"},"license":"MIT","homepage":"https://docs.abstraxn.com/guides/kyi/verify-receipts","engines":{"node":">=18"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"dependencies":{"@noble/ed25519":"^2.2.3","ethers":"^6.17.0"},"devDependencies":{"@types/node":"^25.0.3","rimraf":"^6.1.2","typescript":"^5.9.3"},"gitHead":"f1e0cdd3333706c1ce3c87067504a500f799ab8e","_id":"@abstraxn/warrant-verifier@0.1.0","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-komTI/IYLTAph+1dgSp/w569q0aiSRHIu5z1hO6TvuZNpYdTqjDPfz23fWh65LcyTVMU1wfRuINJ/rjTNydtfw==","shasum":"e33f2585329eed1bb1288b7454c7a623e1c54428","tarball":"https://registry.npmjs.org/@abstraxn/warrant-verifier/-/warrant-verifier-0.1.0.tgz","fileCount":13,"unpackedSize":26421,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICLz75MumLn+odv/FwBEJSn/Mlq0jCCCuYpQ98DfXfRcAiBk6lGYq53O3IKugy4igN8IGlIaPfORRvFTlPnD7g3nJw=="}]},"_npmUser":{"name":"sandeep_sj","email":"sandeepsj26899@gmail.com"},"directories":{},"maintainers":[{"name":"shubham.antier","email":"shubham.singla@antiersolutions.com"},{"name":"sandeep_sj","email":"sandeepsj26899@gmail.com"},{"name":"abhi883","email":"abhishek.upadhyay@antiersolutions.com"},{"name":"pankaj829","email":"pankajdogra829@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/warrant-verifier_0.1.0_1788161427317_0.025246906407247582"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T07:30:27.129Z","0.1.0":"2026-08-31T07:30:27.453Z","modified":"2026-08-31T07:30:27.813Z"},"maintainers":[{"name":"shubham.antier","email":"shubham.singla@antiersolutions.com"},{"name":"sandeep_sj","email":"sandeepsj26899@gmail.com"},{"name":"abhi883","email":"abhishek.upadhyay@antiersolutions.com"},{"name":"pankaj829","email":"pankajdogra829@gmail.com"}],"description":"KYI Warrant receipt verifier — offline Ed25519 + optional on-chain MandateRegistry / ReceiptLog checks","homepage":"https://docs.abstraxn.com/guides/kyi/verify-receipts","keywords":["abstraxn","kyi","warrant","verifier","ed25519","receipt","audit","web3","on-chain"],"author":{"name":"Abstraxn Labs"},"license":"MIT","readme":"# @abstraxn/warrant-verifier\n\nOffline verification for **KYI Warrant** decision receipts. **Zero network calls to Warrant** — auditors only need the signed receipt JSON and Warrant’s public key.\n\nRelated packages:\n\n| Package | Role |\n|---------|------|\n| `@abstraxn/warrant` | Server / Node client |\n| `@abstraxn/warrant-react` | MandateForm + Readback |\n| `@abstraxn/warrant-verifier` | Offline receipt verify + CLI |\n\n## Installation\n\n```bash\nnpm install @abstraxn/warrant-verifier\n```\n\n```bash\nyarn add @abstraxn/warrant-verifier\n```\n\n```bash\npnpm add @abstraxn/warrant-verifier\n```\n\n## Prerequisites\n\n- **Node.js** >= 18\n- Warrant **Ed25519 public key** (hex file, base64, or JSON `{ \"publicKey\": \"…\" }`)\n  - From KYI: `GET /v1/warrant/keys/receipt` (or your deployed key material)\n\n---\n\n## Library\n\n```typescript\nimport {\n  verifyReceiptJson,\n  verifyReceiptsJsonl,\n  canonicalize,\n  tamperReceiptsJsonl,\n} from '@abstraxn/warrant-verifier';\nimport { readFileSync } from 'node:fs';\n\nfunction hexToBytes(hex: string): Uint8Array {\n  const clean = hex.trim().replace(/^0x/i, '');\n  const out = new Uint8Array(clean.length / 2);\n  for (let i = 0; i < out.length; i++) {\n    out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n  }\n  return out;\n}\n\nconst publicKey = hexToBytes(readFileSync('public.key', 'utf8').trim());\nconst jsonl = readFileSync('receipts.jsonl', 'utf8');\n\nconst rows = await verifyReceiptsJsonl(jsonl, publicKey);\nfor (const row of rows) {\n  console.log(row.receipt_id, row.verdict, row.valid ? 'VALID' : row.error);\n}\n```\n\n### Single receipt\n\n```typescript\nconst result = await verifyReceiptJson(receiptObjectOrJsonString, publicKey);\n// { receipt_id, verdict, reasons, valid, error? }\n```\n\n---\n\n## CLI\n\nThe package ships a `warrant-verify` binary:\n\n```bash\nnpx warrant-verify receipts.jsonl --public-key=./public.key\n```\n\n### Options\n\n| Flag | Description |\n|------|-------------|\n| `--public-key=<path>` | Path to hex / base64 / JSON public key (default: `config/keys/public.key`) |\n| `--tamper` | Demo mode: mutate amount on the last receipt, write `*.tamper.jsonl`, then verify (signature stays intact → fails) |\n\nExit code `0` if all receipts are valid; `1` otherwise.\n\n### Tamper demo\n\n```bash\nnpx warrant-verify receipts.jsonl --public-key=./public.key --tamper\n```\n\nShows that changing receipt content without resigning fails verification.\n\n---\n\n## API reference\n\n| Export | Description |\n|--------|-------------|\n| `verifyReceiptJson(lineOrObject, publicKey)` | Verify one receipt (JSON string or object) |\n| `verifyReceiptsJsonl(content, publicKey)` | Verify each non-empty JSONL line |\n| `canonicalize(value)` | Deterministic JSON canonicalize used for the signed message |\n| `tamperReceiptsJsonl(content)` | Demo helper — mutates amount on the last receipt |\n| `verifyMandateOnchain(…)` | RPC: MandateRegistry content hash + active |\n| `verifyReceiptOnchain(…)` | RPC: ReceiptLog Merkle inclusion |\n| `verifyMerkleProof(…)` | Offline Merkle inclusion (sorted pairs) |\n\n```typescript\ntype VerifyResult = {\n  receipt_id: string;\n  verdict: string;\n  reasons: string;\n  valid: boolean;\n  error?: string;\n};\n```\n\n---\n\n## How verification works\n\n1. Strip `signature` from the receipt object\n2. Canonicalize the unsigned payload\n3. Ed25519-verify `signature.sig` (hex) against Warrant’s public key\n\nOn-chain Merkle / STH checks are planned when MandateRegistry / ReceiptLog contracts are live; this package already verifies cryptographic integrity offline.\n\n## On-chain helpers (optional RPC)\n\nAuditors can also check MandateRegistry / ReceiptLog without calling the Warrant API:\n\n```typescript\nimport {\n  verifyMandateOnchain,\n  verifyReceiptOnchain,\n  verifyMerkleProof,\n  receiptLeafBytes32,\n  canonicalize,\n} from '@abstraxn/warrant-verifier';\n\nconst mandate = await verifyMandateOnchain({\n  rpcUrl: process.env.RPC_URL!,\n  mandateRegistry: '0x9f13744Cd7ca5b7851Aa21C9607617a83904A3b5',\n  mandateId: 'mnd_sha256:…',\n  contentHashHex: '…', // mandate.hash\n  chainId: 80002,\n});\n\n// Offline Merkle (no RPC)\nconst leaf = receiptLeafBytes32(canonicalize(unsignedOrSignedReceipt));\nconst merkleOk = verifyMerkleProof({ leaf, proof, root });\n\nconst receipt = await verifyReceiptOnchain({\n  rpcUrl: process.env.RPC_URL!,\n  receiptLog: '0x65eDCae32a92eCCC47b7f0CBa06f2F924ce3A45E',\n  leaf,\n  proof,\n  batchId: '1',\n  root,\n  chainId: 80002,\n});\n```\n\n| Export | Description |\n|--------|-------------|\n| `verifyMandateOnchain(…)` | `MandateRegistry.verifyMandate` + `isActive` |\n| `verifyReceiptOnchain(…)` | `ReceiptLog.verifyReceipt` / `verifyReceiptAgainstAnyBatch` |\n| `verifyMerkleProof(…)` | Offline sorted-pair Merkle inclusion |\n| `mandateIdBytes32` / `contentHashBytes32` / `receiptLeafBytes32` | Same encodings as KYI |\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-a8b5f4cb79e061fc0852b59be2bdf005"}