@babylonlabs-io/ts-sdk 3.0.0 → 3.0.2
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/dist/{PeginManager-CKf7Bjmj.js → PeginManager-D8WGB8eN.js} +2 -2
- package/dist/{PeginManager-CKf7Bjmj.js.map → PeginManager-D8WGB8eN.js.map} +1 -1
- package/dist/{PeginManager-Dt2Z5ljw.cjs → PeginManager-IgDHy_eU.cjs} +2 -2
- package/dist/{PeginManager-Dt2Z5ljw.cjs.map → PeginManager-IgDHy_eU.cjs.map} +1 -1
- package/dist/buildAndBroadcastReclaim-B8aFMGf-.cjs +2 -0
- package/dist/buildAndBroadcastReclaim-B8aFMGf-.cjs.map +1 -0
- package/dist/{buildAndBroadcastReclaim-T5ZFPUpM.js → buildAndBroadcastReclaim-D5520lbL.js} +1015 -935
- package/dist/buildAndBroadcastReclaim-D5520lbL.js.map +1 -0
- package/dist/index-D2mybjXD.js +522 -0
- package/dist/index-D2mybjXD.js.map +1 -0
- package/dist/index-MRdle0fs.cjs +2 -0
- package/dist/index-MRdle0fs.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +215 -214
- package/dist/pegin-registration-client-B0j6ugt9.cjs +2 -0
- package/dist/pegin-registration-client-B0j6ugt9.cjs.map +1 -0
- package/dist/{pegin-registration-client-C5Hktrja.js → pegin-registration-client-ilkV1mLP.js} +103 -88
- package/dist/pegin-registration-client-ilkV1mLP.js.map +1 -0
- package/dist/primeVpAuth-BDWBKYhv.cjs +2 -0
- package/dist/primeVpAuth-BDWBKYhv.cjs.map +1 -0
- package/dist/primeVpAuth-D0ZnsjRi.js +805 -0
- package/dist/primeVpAuth-D0ZnsjRi.js.map +1 -0
- package/dist/state-C4WoNCy1.cjs +2 -0
- package/dist/state-C4WoNCy1.cjs.map +1 -0
- package/dist/{state-mE-QfITd.js → state-CFn1rT74.js} +128 -101
- package/dist/state-CFn1rT74.js.map +1 -0
- package/dist/tbv/core/clients/eth/index.cjs +1 -1
- package/dist/tbv/core/clients/eth/index.js +2 -2
- package/dist/tbv/core/clients/eth/types.d.ts +12 -5
- package/dist/tbv/core/clients/eth/types.d.ts.map +1 -1
- package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts +12 -3
- package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts.map +1 -1
- package/dist/tbv/core/clients/index.cjs +1 -1
- package/dist/tbv/core/clients/index.js +52 -51
- package/dist/tbv/core/clients/mempool/index.cjs +1 -1
- package/dist/tbv/core/clients/mempool/index.cjs.map +1 -1
- package/dist/tbv/core/clients/mempool/index.d.ts +1 -1
- package/dist/tbv/core/clients/mempool/index.d.ts.map +1 -1
- package/dist/tbv/core/clients/mempool/index.js +85 -71
- package/dist/tbv/core/clients/mempool/index.js.map +1 -1
- package/dist/tbv/core/clients/mempool/mempoolApi.d.ts +10 -0
- package/dist/tbv/core/clients/mempool/mempoolApi.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/api.d.ts +17 -14
- package/dist/tbv/core/clients/vault-provider/api.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/auth/createAuthenticatedVpClient.d.ts +8 -0
- package/dist/tbv/core/clients/vault-provider/auth/createAuthenticatedVpClient.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/auth/index.d.ts +1 -1
- package/dist/tbv/core/clients/vault-provider/auth/index.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/auth/primeVpAuth.d.ts +8 -0
- package/dist/tbv/core/clients/vault-provider/auth/primeVpAuth.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/auth/tokenProvider.d.ts +18 -2
- package/dist/tbv/core/clients/vault-provider/auth/tokenProvider.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/auth/tokenRegistry.d.ts +26 -6
- package/dist/tbv/core/clients/vault-provider/auth/tokenRegistry.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/batchAttribution.d.ts +17 -15
- package/dist/tbv/core/clients/vault-provider/batchAttribution.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/batchPoll.d.ts +15 -9
- package/dist/tbv/core/clients/vault-provider/batchPoll.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/json-rpc-client.d.ts +3 -2
- package/dist/tbv/core/clients/vault-provider/json-rpc-client.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/status/index.cjs +1 -1
- package/dist/tbv/core/clients/vault-provider/status/index.js +2 -2
- package/dist/tbv/core/clients/vault-provider/types.d.ts +36 -23
- package/dist/tbv/core/clients/vault-provider/types.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/validators.d.ts +12 -4
- package/dist/tbv/core/clients/vault-provider/validators.d.ts.map +1 -1
- package/dist/tbv/core/index.cjs +1 -1
- package/dist/tbv/core/index.js +213 -212
- package/dist/tbv/core/managers/index.cjs +1 -1
- package/dist/tbv/core/managers/index.js +1 -1
- package/dist/tbv/core/services/deposit/graphFingerprint.d.ts +39 -0
- package/dist/tbv/core/services/deposit/graphFingerprint.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/interfaces.d.ts +2 -2
- package/dist/tbv/core/services/deposit/interfaces.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/runDepositorPresignFlow.d.ts +3 -1
- package/dist/tbv/core/services/deposit/runDepositorPresignFlow.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/signDepositorGraph.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/submitWotsPublicKey.d.ts +3 -1
- package/dist/tbv/core/services/deposit/submitWotsPublicKey.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/waitForPeginStatus.d.ts +11 -2
- package/dist/tbv/core/services/deposit/waitForPeginStatus.d.ts.map +1 -1
- package/dist/tbv/core/services/index.cjs +1 -1
- package/dist/tbv/core/services/index.js +2 -2
- package/dist/tbv/core/services/pegout/state.d.ts +2 -2
- package/dist/tbv/index.cjs +1 -1
- package/dist/tbv/index.js +213 -212
- package/dist/{toRefundInputs-DIIdhjvu.js → toRefundInputs-10RYIfh1.js} +2 -2
- package/dist/{toRefundInputs-DIIdhjvu.js.map → toRefundInputs-10RYIfh1.js.map} +1 -1
- package/dist/{toRefundInputs-B_GlIXjk.cjs → toRefundInputs-a-0HRyrl.cjs} +2 -2
- package/dist/{toRefundInputs-B_GlIXjk.cjs.map → toRefundInputs-a-0HRyrl.cjs.map} +1 -1
- package/dist/{types-DJxOEU3P.cjs → types-BueQoMjO.cjs} +2 -2
- package/dist/{types-DJxOEU3P.cjs.map → types-BueQoMjO.cjs.map} +1 -1
- package/dist/{types-Dz1kVqn6.js → types-DGkejGZH.js} +2 -2
- package/dist/{types-Dz1kVqn6.js.map → types-DGkejGZH.js.map} +1 -1
- package/package.json +3 -3
- package/dist/buildAndBroadcastReclaim-BDc-SK9i.cjs +0 -2
- package/dist/buildAndBroadcastReclaim-BDc-SK9i.cjs.map +0 -1
- package/dist/buildAndBroadcastReclaim-T5ZFPUpM.js.map +0 -1
- package/dist/index-B6w5MM-8.js +0 -528
- package/dist/index-B6w5MM-8.js.map +0 -1
- package/dist/index-EHLYplSd.cjs +0 -2
- package/dist/index-EHLYplSd.cjs.map +0 -1
- package/dist/pegin-registration-client-BdJ6c7si.cjs +0 -2
- package/dist/pegin-registration-client-BdJ6c7si.cjs.map +0 -1
- package/dist/pegin-registration-client-C5Hktrja.js.map +0 -1
- package/dist/primeVpAuth-Bdy_B_Sq.js +0 -745
- package/dist/primeVpAuth-Bdy_B_Sq.js.map +0 -1
- package/dist/primeVpAuth-CQRsu6VB.cjs +0 -2
- package/dist/primeVpAuth-CQRsu6VB.cjs.map +0 -1
- package/dist/state-DMFlvLL3.cjs +0 -2
- package/dist/state-DMFlvLL3.cjs.map +0 -1
- package/dist/state-mE-QfITd.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pegin-registration-client-ilkV1mLP.js","sources":["../src/tbv/core/deposit-terms/commissionCeiling.ts","../../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/legacy.js","../src/tbv/core/clients/eth/payout-script.ts","../src/tbv/core/clients/eth/protocol-params-validation.ts","../src/tbv/core/clients/eth/registration-logs-error.ts","../src/tbv/core/clients/eth/vault-registry-reader.ts","../src/tbv/core/clients/eth/pegin-registration-client.ts"],"sourcesContent":["/**\n * The depositor's commission ceiling (`maxAcceptableCommissionBps`) policy:\n * quoted VP commission + drift headroom, capped below the contract's\n * exclusive bound. Shared by `PeginManager` (the approved terms) and the\n * registration calldata so both carry the same ceiling; a resume rebuild reads\n * that submitted value back from the `PegInSubmittedV2` log instead.\n *\n * @module deposit-terms/commissionCeiling\n */\n\n/*\n * Commission-check map (each guards a DIFFERENT boundary — do not consolidate):\n * 1. assertVpCommissionInProtocolRange (vault app, vaultPayoutSignatureService)\n * — chain-read trust boundary; mirrors VPKeyRegistryLogic.sol bounds.\n * 2. capMaxAcceptableCommissionBps (here) — depositor quote → ceiling policy;\n * mirrors PeginLogic.sol's strict > check via the +25bps headroom.\n * 3. buildDepositTerms range check — public-API precondition on the projection\n * that mints the device-enforced commissionFee.\n * 4. payout.ts commission cap — the VP-built tx's output value vs bps at the\n * signing site (CLAUDE.md Critical Path #3).\n * 5. envelope.ts dust/cross-field gates (ledger-vault-signer) — firmware-only\n * constants, pre-device-I/O (Critical Path #7).\n */\n\nimport { MAX_VP_COMMISSION_BPS_EXCLUSIVE } from \"../primitives/psbt/constants\";\n\n/**\n * Headroom (in basis points) added to the current VP commission to compute\n * `maxAcceptableCommissionBps` at submit time. Lets the VP raise its\n * commission by up to this amount between read and submit without forcing\n * a re-quote. Capped by {@link MAX_ACCEPTABLE_COMMISSION_BPS_CAP}.\n *\n * Contract check is strict `>` (PeginLogic.sol `VaultProviderCommissionExceeded`\n * revert), so +25 allows up\n * to +25 bps of drift.\n */\nexport const COMMISSION_BPS_HEADROOM = 25;\n\n/**\n * Hard ceiling for `maxAcceptableCommissionBps`. The contract enforces\n * `commissionBps < 10000`, so any value at/above that is unreachable;\n * `9999` is the maximum useful cap.\n */\nexport const MAX_ACCEPTABLE_COMMISSION_BPS_CAP = 9999;\n\n/**\n * The commission ceiling submitted as registration calldata and mirrored\n * into `DepositTerms.commissionFee`: quoted + drift headroom, capped.\n * Single source for both consumers — feed it the SAME quoted bps at prepare\n * and register time so device-accept stays coextensive with contract-accept.\n */\nexport function capMaxAcceptableCommissionBps(bps: number): number {\n // Validate the raw quote before headroom shifts its domain — a negative\n // quote must throw here, not become a small \"legal\" ceiling.\n // Reject an out-of-range quote outright — clamping it to 9999 would turn a\n // bad read into a 99.99% ceiling, the exact failure the cap exists to stop.\n if (\n !Number.isInteger(bps) ||\n bps < 0 ||\n bps >= MAX_VP_COMMISSION_BPS_EXCLUSIVE\n ) {\n throw new Error(\n `Quoted commissionBps must be an integer in ` +\n `[0, ${MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${bps}`,\n );\n }\n return Math.min(\n bps + COMMISSION_BPS_HEADROOM,\n MAX_ACCEPTABLE_COMMISSION_BPS_CAP,\n );\n}\n","/**\n\nSHA1 (RFC 3174), MD5 (RFC 1321) and RIPEMD160 (RFC 2286) legacy, weak hash functions.\nDon't use them in a new protocol. What \"weak\" means:\n\n- Collisions can be made with 2^18 effort in MD5, 2^60 in SHA1, 2^80 in RIPEMD160.\n- No practical pre-image attacks (only theoretical, 2^123.4)\n- HMAC seems kinda ok: https://www.rfc-editor.org/rfc/rfc6151\n * @module\n */\nimport { Chi, HashMD, Maj } from \"./_md.js\";\nimport { clean, createHasher, rotl } from \"./utils.js\";\n/** Initial SHA1 state */\nconst SHA1_IV = /* @__PURE__ */ Uint32Array.from([\n 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0,\n]);\n// Reusable temporary buffer\nconst SHA1_W = /* @__PURE__ */ new Uint32Array(80);\n/** Internal SHA1 legacy hash class. */\nexport class _SHA1 extends HashMD {\n A = SHA1_IV[0] | 0;\n B = SHA1_IV[1] | 0;\n C = SHA1_IV[2] | 0;\n D = SHA1_IV[3] | 0;\n E = SHA1_IV[4] | 0;\n constructor() {\n super(64, 20, 8, false);\n }\n get() {\n const { A, B, C, D, E } = this;\n return [A, B, C, D, E];\n }\n set(A, B, C, D, E) {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n this.E = E | 0;\n }\n process(view, offset) {\n for (let i = 0; i < 16; i++, offset += 4)\n SHA1_W[i] = view.getUint32(offset, false);\n for (let i = 16; i < 80; i++)\n SHA1_W[i] = rotl(SHA1_W[i - 3] ^ SHA1_W[i - 8] ^ SHA1_W[i - 14] ^ SHA1_W[i - 16], 1);\n // Compression function main loop, 80 rounds\n let { A, B, C, D, E } = this;\n for (let i = 0; i < 80; i++) {\n let F, K;\n if (i < 20) {\n F = Chi(B, C, D);\n K = 0x5a827999;\n }\n else if (i < 40) {\n F = B ^ C ^ D;\n K = 0x6ed9eba1;\n }\n else if (i < 60) {\n F = Maj(B, C, D);\n K = 0x8f1bbcdc;\n }\n else {\n F = B ^ C ^ D;\n K = 0xca62c1d6;\n }\n const T = (rotl(A, 5) + F + E + K + SHA1_W[i]) | 0;\n E = D;\n D = C;\n C = rotl(B, 30);\n B = A;\n A = T;\n }\n // Add the compressed chunk to the current hash value\n A = (A + this.A) | 0;\n B = (B + this.B) | 0;\n C = (C + this.C) | 0;\n D = (D + this.D) | 0;\n E = (E + this.E) | 0;\n this.set(A, B, C, D, E);\n }\n roundClean() {\n clean(SHA1_W);\n }\n destroy() {\n this.set(0, 0, 0, 0, 0);\n clean(this.buffer);\n }\n}\n/** SHA1 (RFC 3174) legacy hash function. It was cryptographically broken. */\nexport const sha1 = /* @__PURE__ */ createHasher(() => new _SHA1());\n/** Per-round constants */\nconst p32 = /* @__PURE__ */ Math.pow(2, 32);\nconst K = /* @__PURE__ */ Array.from({ length: 64 }, (_, i) => Math.floor(p32 * Math.abs(Math.sin(i + 1))));\n/** md5 initial state: same as sha1, but 4 u32 instead of 5. */\nconst MD5_IV = /* @__PURE__ */ SHA1_IV.slice(0, 4);\n// Reusable temporary buffer\nconst MD5_W = /* @__PURE__ */ new Uint32Array(16);\n/** Internal MD5 legacy hash class. */\nexport class _MD5 extends HashMD {\n A = MD5_IV[0] | 0;\n B = MD5_IV[1] | 0;\n C = MD5_IV[2] | 0;\n D = MD5_IV[3] | 0;\n constructor() {\n super(64, 16, 8, true);\n }\n get() {\n const { A, B, C, D } = this;\n return [A, B, C, D];\n }\n set(A, B, C, D) {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n }\n process(view, offset) {\n for (let i = 0; i < 16; i++, offset += 4)\n MD5_W[i] = view.getUint32(offset, true);\n // Compression function main loop, 64 rounds\n let { A, B, C, D } = this;\n for (let i = 0; i < 64; i++) {\n let F, g, s;\n if (i < 16) {\n F = Chi(B, C, D);\n g = i;\n s = [7, 12, 17, 22];\n }\n else if (i < 32) {\n F = Chi(D, B, C);\n g = (5 * i + 1) % 16;\n s = [5, 9, 14, 20];\n }\n else if (i < 48) {\n F = B ^ C ^ D;\n g = (3 * i + 5) % 16;\n s = [4, 11, 16, 23];\n }\n else {\n F = C ^ (B | ~D);\n g = (7 * i) % 16;\n s = [6, 10, 15, 21];\n }\n F = F + A + K[i] + MD5_W[g];\n A = D;\n D = C;\n C = B;\n B = B + rotl(F, s[i % 4]);\n }\n // Add the compressed chunk to the current hash value\n A = (A + this.A) | 0;\n B = (B + this.B) | 0;\n C = (C + this.C) | 0;\n D = (D + this.D) | 0;\n this.set(A, B, C, D);\n }\n roundClean() {\n clean(MD5_W);\n }\n destroy() {\n this.set(0, 0, 0, 0);\n clean(this.buffer);\n }\n}\n/**\n * MD5 (RFC 1321) legacy hash function. It was cryptographically broken.\n * MD5 architecture is similar to SHA1, with some differences:\n * - Reduced output length: 16 bytes (128 bit) instead of 20\n * - 64 rounds, instead of 80\n * - Little-endian: could be faster, but will require more code\n * - Non-linear index selection: huge speed-up for unroll\n * - Per round constants: more memory accesses, additional speed-up for unroll\n */\nexport const md5 = /* @__PURE__ */ createHasher(() => new _MD5());\n// RIPEMD-160\nconst Rho160 = /* @__PURE__ */ Uint8Array.from([\n 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,\n]);\nconst Id160 = /* @__PURE__ */ (() => Uint8Array.from(new Array(16).fill(0).map((_, i) => i)))();\nconst Pi160 = /* @__PURE__ */ (() => Id160.map((i) => (9 * i + 5) % 16))();\nconst idxLR = /* @__PURE__ */ (() => {\n const L = [Id160];\n const R = [Pi160];\n const res = [L, R];\n for (let i = 0; i < 4; i++)\n for (let j of res)\n j.push(j[i].map((k) => Rho160[k]));\n return res;\n})();\nconst idxL = /* @__PURE__ */ (() => idxLR[0])();\nconst idxR = /* @__PURE__ */ (() => idxLR[1])();\n// const [idxL, idxR] = idxLR;\nconst shifts160 = /* @__PURE__ */ [\n [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],\n [12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7],\n [13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9],\n [14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6],\n [15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5],\n].map((i) => Uint8Array.from(i));\nconst shiftsL160 = /* @__PURE__ */ idxL.map((idx, i) => idx.map((j) => shifts160[i][j]));\nconst shiftsR160 = /* @__PURE__ */ idxR.map((idx, i) => idx.map((j) => shifts160[i][j]));\nconst Kl160 = /* @__PURE__ */ Uint32Array.from([\n 0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e,\n]);\nconst Kr160 = /* @__PURE__ */ Uint32Array.from([\n 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000,\n]);\n// It's called f() in spec.\nfunction ripemd_f(group, x, y, z) {\n if (group === 0)\n return x ^ y ^ z;\n if (group === 1)\n return (x & y) | (~x & z);\n if (group === 2)\n return (x | ~y) ^ z;\n if (group === 3)\n return (x & z) | (y & ~z);\n return x ^ (y | ~z);\n}\n// Reusable temporary buffer\nconst BUF_160 = /* @__PURE__ */ new Uint32Array(16);\nexport class _RIPEMD160 extends HashMD {\n h0 = 0x67452301 | 0;\n h1 = 0xefcdab89 | 0;\n h2 = 0x98badcfe | 0;\n h3 = 0x10325476 | 0;\n h4 = 0xc3d2e1f0 | 0;\n constructor() {\n super(64, 20, 8, true);\n }\n get() {\n const { h0, h1, h2, h3, h4 } = this;\n return [h0, h1, h2, h3, h4];\n }\n set(h0, h1, h2, h3, h4) {\n this.h0 = h0 | 0;\n this.h1 = h1 | 0;\n this.h2 = h2 | 0;\n this.h3 = h3 | 0;\n this.h4 = h4 | 0;\n }\n process(view, offset) {\n for (let i = 0; i < 16; i++, offset += 4)\n BUF_160[i] = view.getUint32(offset, true);\n // prettier-ignore\n let al = this.h0 | 0, ar = al, bl = this.h1 | 0, br = bl, cl = this.h2 | 0, cr = cl, dl = this.h3 | 0, dr = dl, el = this.h4 | 0, er = el;\n // Instead of iterating 0 to 80, we split it into 5 groups\n // And use the groups in constants, functions, etc. Much simpler\n for (let group = 0; group < 5; group++) {\n const rGroup = 4 - group;\n const hbl = Kl160[group], hbr = Kr160[group]; // prettier-ignore\n const rl = idxL[group], rr = idxR[group]; // prettier-ignore\n const sl = shiftsL160[group], sr = shiftsR160[group]; // prettier-ignore\n for (let i = 0; i < 16; i++) {\n const tl = (rotl(al + ripemd_f(group, bl, cl, dl) + BUF_160[rl[i]] + hbl, sl[i]) + el) | 0;\n al = el, el = dl, dl = rotl(cl, 10) | 0, cl = bl, bl = tl; // prettier-ignore\n }\n // 2 loops are 10% faster\n for (let i = 0; i < 16; i++) {\n const tr = (rotl(ar + ripemd_f(rGroup, br, cr, dr) + BUF_160[rr[i]] + hbr, sr[i]) + er) | 0;\n ar = er, er = dr, dr = rotl(cr, 10) | 0, cr = br, br = tr; // prettier-ignore\n }\n }\n // Add the compressed chunk to the current hash value\n this.set((this.h1 + cl + dr) | 0, (this.h2 + dl + er) | 0, (this.h3 + el + ar) | 0, (this.h4 + al + br) | 0, (this.h0 + bl + cr) | 0);\n }\n roundClean() {\n clean(BUF_160);\n }\n destroy() {\n this.destroyed = true;\n clean(this.buffer);\n this.set(0, 0, 0, 0, 0);\n }\n}\n/**\n * RIPEMD-160 - a legacy hash function from 1990s.\n * * https://homes.esat.kuleuven.be/~bosselae/ripemd160.html\n * * https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf\n */\nexport const ripemd160 = /* @__PURE__ */ createHasher(() => new _RIPEMD160());\n//# sourceMappingURL=legacy.js.map","import { schnorr, secp256k1 } from \"@noble/curves/secp256k1.js\";\nimport { ripemd160 } from \"@noble/hashes/legacy.js\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { bytesToHex, hexToBytes } from \"@noble/hashes/utils.js\";\nimport type { Hex } from \"viem\";\n\nimport { MAX_PAYOUT_SCRIPT_LEN } from \"../../primitives/psbt/constants\";\nimport { assertOnChainBtcPubkey } from \"./onChainBtcPubkey\";\n\nconst P2TR_SCRIPT_PREFIX = \"5120\";\nconst P2WPKH_SCRIPT_PREFIX = \"0014\";\nconst HASH160_BYTES = 20;\nconst COMPRESSED_PUBKEY_BYTES = 33;\nconst UNCOMPRESSED_PUBKEY_BYTES = 65;\nconst SEC1_EVEN_Y_PREFIX = 0x02;\nconst SEC1_ODD_Y_PREFIX = 0x03;\nconst SEC1_UNCOMPRESSED_PREFIX = 0x04;\n\nfunction normalizeHex(value: string, label: string): Hex {\n const body =\n value.startsWith(\"0x\") || value.startsWith(\"0X\") ? value.slice(2) : value;\n if (!/^(?:[0-9a-fA-F]{2})+$/.test(body)) {\n throw new Error(`${label} must be non-empty, even-length hex`);\n }\n return `0x${body.toLowerCase()}`;\n}\n\nfunction deriveP2trScript(xOnlyPubkey: string): Hex {\n const pubkeyBytes = hexToBytes(xOnlyPubkey);\n const internalKey = schnorr.utils.lift_x(BigInt(`0x${xOnlyPubkey}`));\n const tweak = schnorr.utils.bytesToNumberBE(\n schnorr.utils.taggedHash(\"TapTweak\", pubkeyBytes),\n );\n if (tweak >= secp256k1.CURVE.n) {\n throw new Error(\"Proof of possession BTC pubkey has an invalid TapTweak\");\n }\n const outputKey =\n tweak === 0n\n ? internalKey\n : internalKey.add(schnorr.Point.BASE.multiply(tweak));\n return `0x${P2TR_SCRIPT_PREFIX}${bytesToHex(\n schnorr.utils.pointToBytes(outputKey),\n )}`;\n}\n\nfunction normalizePayoutPubkey(value: string): {\n xOnlyPubkey: string;\n compressedPubkey?: Uint8Array;\n} {\n const normalized = normalizeHex(value, \"depositorBtcPubkeyRaw\");\n const pubkey = hexToBytes(normalized.slice(2));\n if (pubkey.length === 32) {\n return {\n xOnlyPubkey: assertOnChainBtcPubkey(normalized, \"Payout BTC pubkey\"),\n };\n }\n const isCompressed =\n pubkey.length === COMPRESSED_PUBKEY_BYTES &&\n (pubkey[0] === SEC1_EVEN_Y_PREFIX || pubkey[0] === SEC1_ODD_Y_PREFIX);\n const isUncompressed =\n pubkey.length === UNCOMPRESSED_PUBKEY_BYTES &&\n pubkey[0] === SEC1_UNCOMPRESSED_PREFIX;\n if (!isCompressed && !isUncompressed) {\n throw new Error(\n \"depositorBtcPubkeyRaw must be x-only, compressed, or uncompressed\",\n );\n }\n try {\n secp256k1.Point.fromBytes(pubkey);\n } catch {\n throw new Error(\"depositorBtcPubkeyRaw is not a valid BTC pubkey\");\n }\n return {\n xOnlyPubkey: bytesToHex(pubkey.subarray(1, COMPRESSED_PUBKEY_BYTES)),\n compressedPubkey: isCompressed ? pubkey : undefined,\n };\n}\n\nfunction deriveP2wpkhScript(pubkey: Uint8Array): Hex {\n return `0x${P2WPKH_SCRIPT_PREFIX}${bytesToHex(ripemd160(sha256(pubkey)))}`;\n}\n\n/** Verify the irreversible payout script at the final submission boundary. */\nexport function assertPayoutScriptMatchesPopKey(\n scriptPubKey: string,\n depositorBtcPubkey: string,\n depositorBtcPubkeyRaw: string,\n): Hex {\n const payoutScript = normalizeHex(\n scriptPubKey,\n \"depositorPayoutScriptPubKey\",\n );\n if ((payoutScript.length - 2) / 2 > MAX_PAYOUT_SCRIPT_LEN) {\n throw new Error(\n `depositorPayoutScriptPubKey exceeds ${MAX_PAYOUT_SCRIPT_LEN} bytes`,\n );\n }\n const keyBody =\n depositorBtcPubkey.startsWith(\"0x\") || depositorBtcPubkey.startsWith(\"0X\")\n ? depositorBtcPubkey.slice(2)\n : depositorBtcPubkey;\n const xOnlyPubkey = assertOnChainBtcPubkey(\n `0x${keyBody}` as Hex,\n \"Proof of possession BTC pubkey\",\n );\n const payoutPubkey = normalizePayoutPubkey(depositorBtcPubkeyRaw);\n if (payoutPubkey.xOnlyPubkey !== xOnlyPubkey) {\n throw new Error(\n \"depositorBtcPubkeyRaw does not match the proof of possession BTC pubkey\",\n );\n }\n\n if (payoutScript === deriveP2trScript(xOnlyPubkey)) {\n return payoutScript;\n }\n if (\n payoutScript.startsWith(`0x${P2WPKH_SCRIPT_PREFIX}`) &&\n payoutScript.length ===\n 2 + P2WPKH_SCRIPT_PREFIX.length + HASH160_BYTES * 2\n ) {\n if (!payoutPubkey.compressedPubkey) {\n throw new Error(\"A P2WPKH payout requires a compressed BTC pubkey\");\n }\n if (payoutScript === deriveP2wpkhScript(payoutPubkey.compressedPubkey)) {\n return payoutScript;\n }\n }\n throw new Error(\n \"depositorPayoutScriptPubKey does not match the proof of possession BTC pubkey\",\n );\n}\n","/**\n * Validation for protocol parameters fetched from the ProtocolParams contract.\n *\n * These values feed Bitcoin script construction and deposit validation.\n * Invalid params must be caught before they reach transaction-building code,\n * since errors after wallet signing prompts are unrecoverable.\n *\n * The {@link ViemProtocolParamsReader} runs these on every read; consumers\n * implementing their own reader against the same `ProtocolParamsReader`\n * interface should call them too.\n */\n\nimport { assertValidVaultCoreVersion } from \"../../primitives/vaultCoreVersion\";\n\nimport type {\n PegInConfiguration,\n TBVProtocolParams,\n VersionedOffchainParams,\n} from \"./types\";\n\n/**\n * Maximum value for a Solidity uint16.\n * PeginLogic.sol casts timelockAssert to uint16, so values above this are invalid.\n */\nconst UINT16_MAX = 65535;\n\n/** Maximum valid value for basis points (100%) */\nconst MAX_BASIS_POINTS = 10000;\n\n/** Maximum value for a Solidity uint32. */\nconst UINT32_MAX = 4_294_967_295;\n\n/** Maximum valid value for a uint8 (e.g. maxHtlcOutputCount). */\nconst UINT8_MAX = 255;\n\n/**\n * Validate an `offchainParamsVersion` value sourced from a contract read.\n * `Number()` on a malformed payload yields `NaN` or a non-integer; both\n * silently break consumers that loop `1..version` or use the value as a\n * map key. Used by reader entry points that surface the version to JS.\n */\nexport function assertValidOffchainParamsVersion(version: number): void {\n if (\n !Number.isInteger(version) ||\n version < 0 ||\n version > UINT32_MAX\n ) {\n throw new Error(\n `Invalid offchainParamsVersion from contract: must be a uint32, got ${version}`,\n );\n }\n}\n\n/**\n * Validate offchain params consistency and bounds.\n * @throws Error on invalid values to prevent constructing invalid Bitcoin scripts.\n */\nexport function validateOffchainParams(params: VersionedOffchainParams): void {\n const errors: string[] = [];\n\n if (params.timelockAssert <= 0n) {\n errors.push(\n `timelockAssert must be positive, got ${params.timelockAssert}`,\n );\n }\n if (params.timelockAssert > BigInt(UINT16_MAX)) {\n errors.push(\n `timelockAssert ${params.timelockAssert} exceeds uint16 max (${UINT16_MAX})`,\n );\n }\n\n if (params.timelockChallengeAssert <= 0n) {\n errors.push(\n `timelockChallengeAssert must be positive, got ${params.timelockChallengeAssert}`,\n );\n }\n\n if (params.tRefund <= 0) {\n errors.push(`tRefund must be positive, got ${params.tRefund}`);\n }\n\n if (params.tStale <= 0) {\n errors.push(`tStale must be positive, got ${params.tStale}`);\n }\n\n if (params.securityCouncilKeys.length === 0) {\n errors.push(\"securityCouncilKeys must not be empty\");\n }\n\n if (params.councilQuorum <= 0) {\n errors.push(`councilQuorum must be positive, got ${params.councilQuorum}`);\n }\n if (params.councilQuorum > params.securityCouncilKeys.length) {\n errors.push(\n `councilQuorum (${params.councilQuorum}) exceeds securityCouncilKeys count (${params.securityCouncilKeys.length})`,\n );\n }\n\n if (params.feeRate <= 0n) {\n errors.push(`feeRate must be positive, got ${params.feeRate}`);\n }\n\n if (params.minPeginFeeRate <= 0n) {\n errors.push(\n `minPeginFeeRate must be positive, got ${params.minPeginFeeRate}`,\n );\n }\n\n if (\n !Number.isInteger(params.proverCircuitVersion) ||\n params.proverCircuitVersion < 0 ||\n params.proverCircuitVersion > UINT16_MAX\n ) {\n errors.push(\n `proverCircuitVersion must be a uint16, got ${params.proverCircuitVersion}`,\n );\n }\n\n if (\n !Number.isInteger(params.minPrepeginDepth) ||\n params.minPrepeginDepth <= 0 ||\n params.minPrepeginDepth > UINT32_MAX\n ) {\n errors.push(\n `minPrepeginDepth must be a uint32 in [1, ${UINT32_MAX}], got ${params.minPrepeginDepth}`,\n );\n }\n\n if (params.babeTotalInstances <= 0) {\n errors.push(\n `babeTotalInstances must be positive, got ${params.babeTotalInstances}`,\n );\n }\n if (params.babeInstancesToFinalize <= 0) {\n errors.push(\n `babeInstancesToFinalize must be positive, got ${params.babeInstancesToFinalize}`,\n );\n }\n if (params.babeInstancesToFinalize > params.babeTotalInstances) {\n errors.push(\n `babeInstancesToFinalize (${params.babeInstancesToFinalize}) exceeds babeTotalInstances (${params.babeTotalInstances})`,\n );\n }\n\n if (\n params.minVpCommissionBps < 0 ||\n params.minVpCommissionBps > MAX_BASIS_POINTS\n ) {\n errors.push(\n `minVpCommissionBps must be in [0, ${MAX_BASIS_POINTS}], got ${params.minVpCommissionBps}`,\n );\n }\n\n if (errors.length > 0) {\n throw new Error(\n `Invalid offchain protocol parameters: ${errors.join(\"; \")}`,\n );\n }\n}\n\n/**\n * Validate TBV protocol params returned from the contract.\n * @throws Error on invalid amounts or out-of-range bounded fields.\n */\nexport function validateTBVProtocolParams(params: TBVProtocolParams): void {\n const errors: string[] = [];\n\n if (params.minimumPegInAmount <= 0n) {\n errors.push(\n `minimumPegInAmount must be positive, got ${params.minimumPegInAmount}`,\n );\n }\n\n if (params.maxPegInAmount < params.minimumPegInAmount) {\n errors.push(\n `maxPegInAmount (${params.maxPegInAmount}) must be >= minimumPegInAmount (${params.minimumPegInAmount})`,\n );\n }\n\n if (params.pegInAckTimeout <= 0n) {\n errors.push(\n `pegInAckTimeout must be positive, got ${params.pegInAckTimeout}`,\n );\n }\n\n if (params.pegInActivationTimeout <= 0n) {\n errors.push(\n `pegInActivationTimeout must be positive, got ${params.pegInActivationTimeout}`,\n );\n }\n\n if (\n !Number.isInteger(params.maxHtlcOutputCount) ||\n params.maxHtlcOutputCount <= 0 ||\n params.maxHtlcOutputCount > UINT8_MAX\n ) {\n errors.push(\n `maxHtlcOutputCount must be an integer in [1, ${UINT8_MAX}], got ${params.maxHtlcOutputCount}`,\n );\n }\n\n if (\n typeof params.expiredPegInGraceBlocks !== \"bigint\" ||\n params.expiredPegInGraceBlocks <= 0n\n ) {\n errors.push(\n `expiredPegInGraceBlocks must be a positive bigint, got ${params.expiredPegInGraceBlocks}`,\n );\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid TBV protocol parameters: ${errors.join(\"; \")}`);\n }\n}\n\n/**\n * Validate the full peg-in configuration after assembly.\n * Checks both TBV params and offchain params consistency, and the\n * top-level `offchainParamsVersion` (which originates from a separate\n * multicall result and so must be range-checked alongside the params it\n * names).\n */\nexport function validatePegInConfiguration(config: PegInConfiguration): void {\n validateTBVProtocolParams(config);\n validateOffchainParams(config.offchainParams);\n\n if (\n !Number.isInteger(config.offchainParamsVersion) ||\n config.offchainParamsVersion < 0 ||\n config.offchainParamsVersion > UINT32_MAX\n ) {\n throw new Error(\n `Invalid peg-in configuration: offchainParamsVersion must be a uint32, got ${config.offchainParamsVersion}`,\n );\n }\n\n // The contract enforces ≥ 1 (setter rejects 0); a 0 here means a\n // mis-decoded read or a pre-vaultCoreVersion contract — fail closed.\n assertValidVaultCoreVersion(\n config.activeVaultCoreVersion,\n \"ProtocolParams.activeVaultCoreVersion()\",\n );\n}\n","/**\n * Transient failure of a registration-log read.\n *\n * Every registered vault has its `PegInSubmitted` log in its `createdAt`\n * block, so an Ethereum node answering that block's registration-log query\n * with no logs at all did not serve the block — load-balanced public RPCs\n * answer `[]` for a block a backend lacks instead of erroring, which viem's\n * transport retry cannot see (it retries errors only). Callers may retry.\n *\n * @module clients/eth/registration-logs-error\n */\n\n/** The `name` this error carries, so a foreign module instance still matches. */\nexport const REGISTRATION_LOGS_UNAVAILABLE_ERROR_NAME =\n \"RegistrationLogsUnavailableError\";\n\nexport class RegistrationLogsUnavailableError extends Error {\n readonly blockNumber: bigint;\n\n constructor(blockNumber: bigint) {\n super(\n `The Ethereum node returned no registration logs for block ${blockNumber}, ` +\n `which holds a vault registration; the node may not have indexed that ` +\n `block yet. Try again.`,\n );\n this.name = REGISTRATION_LOGS_UNAVAILABLE_ERROR_NAME;\n this.blockNumber = blockNumber;\n }\n}\n\n/** Matches `instanceof` OR the documented `name` (dual module instances). */\nexport function isRegistrationLogsUnavailableError(\n err: unknown,\n): err is RegistrationLogsUnavailableError {\n if (err instanceof RegistrationLogsUnavailableError) return true;\n if (typeof err !== \"object\" || err === null) return false;\n return (\n (err as { name?: unknown }).name ===\n REGISTRATION_LOGS_UNAVAILABLE_ERROR_NAME\n );\n}\n","/**\n * Concrete BTCVaultRegistry reader using viem's readContract.\n *\n * This is an optional utility — callers can use their own implementation\n * of the VaultRegistryReader interface.\n */\n\nimport type { Abi, Address, Hex, PublicClient } from \"viem\";\nimport { getAbiItem } from \"viem\";\n\nimport { BTCVaultRegistryABI } from \"../../contracts/abis/BTCVaultRegistry.abi\";\nimport { BTCVaultRegistryKeyEpochsABI } from \"../../contracts/abis/BTCVaultRegistryKeyEpochs.abi\";\nimport { assertOnChainBtcPubkey } from \"./onChainBtcPubkey\";\nimport { assertValidOffchainParamsVersion } from \"./protocol-params-validation\";\nimport { RegistrationLogsUnavailableError } from \"./registration-logs-error\";\nimport type {\n KeyEpochs,\n OnChainBtcPubkey,\n VaultBasicInfo,\n VaultData,\n VaultProtocolInfo,\n VaultRegistryReader,\n} from \"./types\";\n\n/**\n * Inclusive upper bound the BTCVaultRegistry contract enforces on a vault\n * provider's commission (the contract check is `< 10000`).\n */\nconst MAX_VP_COMMISSION_BPS = 9999;\n\n/** Raw `getBtcVaultBasicInfo` tuple as decoded by viem. */\ntype RawVaultBasicInfo = {\n depositor: Address;\n depositorBtcPubKey: Hex;\n amount: bigint;\n vaultProvider: Address;\n status: number;\n applicationEntryPoint: Address;\n createdAt: bigint;\n};\n\n/**\n * Raw `getBtcVaultProtocolInfo` tuple as decoded by viem.\n *\n * Mirrors the ABI's components except `claimExpiredUntil`, which nothing\n * consumes: it is the post-expiry grace deadline for `claimExpired`, scoped to\n * vaults that expired without activating, and it is not a deadline on the\n * depositor's claim right. The ABI still declares it — the decode is\n * positional, so removing it there would shift `vaultCoreVersion`.\n */\ntype RawVaultProtocolInfo = {\n depositorSignedPeginTx: Hex;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n offchainParamsVersion: number;\n verifiedAt: bigint;\n depositorWotsPkHash: Hex;\n hashlock: Hex;\n htlcVout: number;\n depositorPopSignature: Hex;\n prePeginTxHash: Hex;\n vaultProviderCommissionBps: number;\n vaultCoreVersion: number;\n};\n\nfunction mapVaultBasicInfo(result: RawVaultBasicInfo): VaultBasicInfo {\n return {\n depositor: result.depositor,\n depositorBtcPubKey: result.depositorBtcPubKey,\n amount: result.amount,\n vaultProvider: result.vaultProvider,\n status: result.status,\n applicationEntryPoint: result.applicationEntryPoint,\n createdAt: result.createdAt,\n };\n}\n\nfunction mapVaultProtocolInfo(result: RawVaultProtocolInfo): VaultProtocolInfo {\n const offchainParamsVersion = Number(result.offchainParamsVersion);\n assertValidOffchainParamsVersion(offchainParamsVersion);\n return {\n depositorSignedPeginTx: result.depositorSignedPeginTx,\n universalChallengersVersion: result.universalChallengersVersion,\n appVaultKeepersVersion: result.appVaultKeepersVersion,\n offchainParamsVersion,\n verifiedAt: result.verifiedAt,\n depositorWotsPkHash: result.depositorWotsPkHash,\n hashlock: result.hashlock,\n htlcVout: result.htlcVout,\n depositorPopSignature: result.depositorPopSignature,\n prePeginTxHash: result.prePeginTxHash,\n vaultProviderCommissionBps: result.vaultProviderCommissionBps,\n vaultCoreVersion: result.vaultCoreVersion,\n };\n}\n\n/**\n * Exclusive upper bound for a `uint64` epoch.\n *\n * viem does not range-check a decoded `uint64`, so a misaligned decode can\n * hand back a value far larger than the field can hold. Rejecting those is\n * cheap defence in depth against a mis-decode of the extended ABI.\n *\n * The state this is load-bearing for is narrower than \"a registry that predates\n * RFC-006\". Against a *fully* pre-RFC-006 registry the path fails closed on its\n * own: `resolveParticipantKeysAtEpochs` goes on to call\n * `getOperationBtcKeyAtEpochOrGenesis` on ApplicationRegistry and\n * ProtocolParams, which do not exist there, so the multicall reverts and these\n * epochs are never used. The reachable gap is a registry that *has* the\n * operation-key getters but whose `BTCVaultProtocolInfo` struct is not\n * extended — there the tail-data epochs resolve with no error at all, and this\n * range check is the only thing looking at them.\n *\n * Even for that case it is only a backstop, and a weak one: a misaligned decode\n * can land on a small, plausible-looking integer this range accepts. Correctness\n * rests on only ever pointing at an RFC-006 registry, which is a deployment\n * precondition rather than something this call can establish — see\n * https://github.com/babylonlabs-io/babylon-toolkit/issues/2192 for where that\n * check is owned, and `BTCVaultRegistryKeyEpochs.abi.ts` for the decode hazard.\n */\nconst UINT64_EXCLUSIVE_UPPER_BOUND = 1n << 64n;\n\n/**\n * The epoch a vault provider's registration key is bonded at.\n *\n * A provider's operation-key history is append-only and every appended version\n * is stamped at epoch 1 or later, so epoch 0 always resolves to the key set at\n * registration. This is what lets `getOperationBtcKeyAtEpoch` stand in for the\n * removed `getVaultProviderBTCKey` getter.\n */\nconst VP_GENESIS_KEY_EPOCH = 0n;\n\n/**\n * Both registration events, queried together so one answer settles whether a\n * vault's V2 log is missing (pre-upgrade registration) or the node served no\n * logs for the block at all.\n */\nconst PEGIN_SUBMITTED_EVENTS = [\n getAbiItem({ abi: BTCVaultRegistryABI, name: \"PegInSubmitted\" }),\n getAbiItem({ abi: BTCVaultRegistryABI, name: \"PegInSubmittedV2\" }),\n] as const;\n\nfunction assertEpochInRange(\n value: bigint,\n field: string,\n vaultId: Hex,\n): bigint {\n if (value < 0n || value >= UINT64_EXCLUSIVE_UPPER_BOUND) {\n throw new Error(\n `getBtcVaultProtocolInfo returned ${field}=${value} for vault ${vaultId}, ` +\n `outside the uint64 range — the registry may predate RFC-006`,\n );\n }\n return value;\n}\n\nfunction mapKeyEpochs(result: KeyEpochs, vaultId: Hex): KeyEpochs {\n return {\n vpKeyEpoch: assertEpochInRange(result.vpKeyEpoch, \"vpKeyEpoch\", vaultId),\n appKeeperKeyEpoch: assertEpochInRange(\n result.appKeeperKeyEpoch,\n \"appKeeperKeyEpoch\",\n vaultId,\n ),\n ucKeyEpoch: assertEpochInRange(result.ucKeyEpoch, \"ucKeyEpoch\", vaultId),\n };\n}\n\n/**\n * Concrete vault registry reader using viem.\n *\n * Usage:\n * ```ts\n * const reader = new ViemVaultRegistryReader(publicClient, registryAddress);\n * const data = await reader.getVaultData(vaultId);\n * ```\n */\nexport class ViemVaultRegistryReader implements VaultRegistryReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n /**\n * Read the VP's **genesis** (registration) x-only BTC pubkey — the key bonded\n * at version 0, which never moves when the operator rotates.\n *\n * Resolved as \"the operation key at epoch 0\" rather than through the\n * dedicated `getVaultProviderBTCKey` getter, which\n * https://github.com/babylonlabs-io/vault-contracts-aave-v4/pull/539 removes.\n * Epoch 0 predates any rotation — appended versions are stamped at epoch 1 or\n * later — so it resolves to the registration key, and the contracts team has\n * confirmed that is a property we can rely on rather than an implementation\n * detail. The devnet comparison behind that claim — both getters returning the\n * identical key for a provider that *has* rotated, while\n * `getCurrentOperationBtcKey` differed — is recorded in\n * https://github.com/babylonlabs-io/babylon-toolkit/issues/2188.\n *\n * This makes the read RFC-006-only, where the removed getter also existed on a\n * legacy registry. That costs nothing: every caller of this method already\n * resolves participant keys through `OperationKeyReader`, so all of them\n * require an RFC-006 registry regardless.\n *\n * Validates length, hex form, and secp256k1 curve membership before minting\n * the brand. Returns 64-char lowercase hex without the `0x` prefix.\n */\n async getVaultProviderGenesisBtcPubKey(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<OnChainBtcPubkey> {\n return this.getVaultProviderOperationBtcKeyAtEpoch(\n vpAddress,\n VP_GENESIS_KEY_EPOCH,\n blockNumber,\n );\n }\n\n /**\n * Read the VP operation key selected by `epoch`.\n *\n * This is public rather than hidden inside `OperationKeyReader` because\n * subject-specific VP authentication needs exactly one participant: the\n * gRPC bootstrap is signed by the key frozen into the vault, while the\n * JSON-RPC bootstrap is signed by the provider's live key.\n */\n async getVaultProviderOperationBtcKeyAtEpoch(\n vpAddress: Address,\n epoch: bigint,\n blockNumber?: bigint,\n ): Promise<OnChainBtcPubkey> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getOperationBtcKeyAtEpoch\",\n args: [vpAddress, epoch],\n blockNumber,\n })) as Hex;\n return assertOnChainBtcPubkey(\n result,\n `getOperationBtcKeyAtEpoch (vp=${vpAddress}, epoch=${epoch})`,\n );\n }\n\n /**\n * Read the application entry point a vault provider is registered for.\n *\n * This is the registry's own `vaultProviders[vp].applicationEntryPoint`, and\n * it is the value the peg-in submit path resolves internally — it selects\n * which application's vault-keeper roster, roster version and keeper key\n * epoch a deposit is bonded to. The dApp separately carries an entry point\n * from its own configuration; the two agree today, but they are different\n * sources of truth, so the build path reads this one and asserts the\n * configured value matches it rather than trusting either alone.\n */\n async getVaultProviderApplication(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<Address> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderApplication\",\n args: [vpAddress],\n blockNumber,\n })) as Address;\n }\n\n /**\n * Read a vault provider's *current* RFC-006 operation BTC key.\n *\n * Falls back on-chain to the registration key when the provider has never\n * rotated, so this returns the same value as\n * `getVaultProviderGenesisBtcPubKey` until the first rotation.\n *\n * This is the key the VP's server uses for JSON-RPC-subject authentication.\n * The gRPC-subject bootstrap is instead bound to the existing vault's frozen\n * epoch and resolves through `getVaultProviderOperationBtcKeyAtEpoch`.\n */\n async getCurrentVaultProviderOperationBtcKey(\n vpAddress: Address,\n ): Promise<OnChainBtcPubkey> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getCurrentOperationBtcKey\",\n args: [vpAddress],\n })) as Hex;\n return assertOnChainBtcPubkey(\n result,\n `getCurrentOperationBtcKey (vp=${vpAddress})`,\n );\n }\n\n /**\n * Read a vault's frozen RFC-006 operation-key epochs.\n *\n * Reads `getBtcVaultProtocolInfo` through the **extended** ABI, which is only\n * valid against an RFC-006 registry: against one whose `BTCVaultProtocolInfo`\n * struct is not extended this call does not fail for a populated vault, it\n * silently returns three words of tail data as epochs. Nothing here can detect\n * that, so the guarantee is a deployment one — every network this ships to has\n * the RFC-006 getters, and mainnet is a fresh RFC-006 deploy.\n *\n * A registry missing the operation-key getters entirely is the *safer* of the\n * two cases: `resolveParticipantKeysAtEpochs` reverts downstream and these\n * epochs never reach key resolution. See {@link UINT64_EXCLUSIVE_UPPER_BOUND}\n * for which state the range check actually guards, and\n * `BTCVaultRegistryKeyEpochs.abi.ts` for the decode hazard.\n */\n async getVaultKeyEpochs(vaultId: Hex): Promise<KeyEpochs> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as unknown as KeyEpochs;\n\n return mapKeyEpochs(result, vaultId);\n }\n\n async getVaultKeyEpochsBatch(vaultIds: readonly Hex[]): Promise<KeyEpochs[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) =>\n mapKeyEpochs(info as unknown as KeyEpochs, vaultIds[i]),\n );\n }\n\n async getVaultBasicInfo(vaultId: Hex): Promise<VaultBasicInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as RawVaultBasicInfo;\n\n return mapVaultBasicInfo(result);\n }\n\n async getVaultProtocolInfo(vaultId: Hex): Promise<VaultProtocolInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as RawVaultProtocolInfo;\n\n return mapVaultProtocolInfo(result);\n }\n\n async getProtocolInfoBatch(\n vaultIds: readonly Hex[],\n ): Promise<VaultProtocolInfo[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) => {\n const result = info as unknown as RawVaultProtocolInfo;\n if (\n !result.depositorSignedPeginTx ||\n result.depositorSignedPeginTx === \"0x\"\n ) {\n // An empty record is not proof the vault is absent: a lagging RPC\n // node returns HTTP 200 with a zero struct, so no retry below this\n // layer can see it. Single-shot is only safe because the finality\n // gate (`waitForPeginRegistrationDepth`) runs first on the deposit\n // path — move this ahead of it and the read-after-write race returns.\n // The vault app matches this message to render \"still confirming\".\n throw new Error(\n `Vault ${vaultIds[i]} not found on-chain or has no pegin transaction`,\n );\n }\n return mapVaultProtocolInfo(result);\n });\n }\n\n /**\n * Read the protocol pegin fee (in wei) for a given vault provider.\n * Mirrors the `getPegInFee(address)` view on BTCVaultRegistry.\n */\n async getPegInFee(vaultProvider: Address): Promise<bigint> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n }\n\n /**\n * Read a vault provider's current commission in basis points from\n * BTCVaultRegistry. The contract enforces `commissionBps < 10000`, so the\n * legitimate range is `[0, 9999]`; anything outside indicates a wrong\n * contract address or ABI drift and is surfaced as an error rather than\n * trusted.\n */\n async getVaultProviderCommission(vaultProvider: Address): Promise<number> {\n // viem infers `number` from the `uint16` return in the `as const` ABI.\n const bps = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderCommission\",\n args: [vaultProvider],\n });\n\n if (!Number.isInteger(bps) || bps < 0 || bps > MAX_VP_COMMISSION_BPS) {\n throw new Error(\n `getVaultProviderCommission returned ${bps} bps for ${vaultProvider}, ` +\n `outside the protocol range [0, ${MAX_VP_COMMISSION_BPS}]`,\n );\n }\n\n return bps;\n }\n\n async getVaultData(vaultId: Hex): Promise<VaultData> {\n // One round-trip for both structs (hard-fail): they feed signing/refund/\n // broadcast rebinds, so reading them in a single multicall also pins both\n // to the same block — no basic/protocol skew across two `eth_call`s.\n const [basicRaw, protocolRaw] = await this.publicClient.multicall({\n contracts: [\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n },\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n },\n ],\n allowFailure: false,\n });\n\n const basic = mapVaultBasicInfo(basicRaw);\n const protocol = mapVaultProtocolInfo(protocolRaw);\n\n if (\n !protocol.depositorSignedPeginTx ||\n protocol.depositorSignedPeginTx === \"0x\"\n ) {\n throw new Error(\n `Vault ${vaultId} not found on-chain or has no pegin transaction`,\n );\n }\n\n return { basic, protocol };\n }\n\n /**\n * Read the depositor's commission ceiling (`maxAcceptableCommissionBps`)\n * for vaults registered in the same block, from their `PegInSubmittedV2`\n * logs. Returned in `vaultIds` order.\n *\n * The contract bound-checks the ceiling and discards it (PeginLogic.sol,\n * `VaultProviderCommissionExceeded`), so the registration log is its only\n * on-chain source. One query at exactly `createdAt` — the `block.number`\n * stamped at registration — so no block-range scan is needed and public-RPC\n * range caps do not apply. Vault ids are matched case-insensitively.\n *\n * @throws {RegistrationLogsUnavailableError} (transient, retry) when the\n * node answers with no registration logs for the block at all.\n * @throws when a vault has only its `PegInSubmitted` log — registrations\n * that predate the V2 event (vault-contracts-aave-v4 #548) never emitted\n * the ceiling — no registration log in its own `createdAt` block, or more\n * than one V2 log.\n */\n async getMaxAcceptableCommissionBpsBatch(\n vaultIds: readonly Hex[],\n createdAt: bigint,\n ): Promise<number[]> {\n if (vaultIds.length === 0) return [];\n\n // Deliberately no `vaultId` topic filter: both events must come back in\n // ONE answer for the empty-vs-missing discriminator below to hold, and\n // viem's multi-event form takes no `args` — so the block's registration\n // logs are fetched whole and ids are matched client-side. strict: a log\n // whose data does not decode against the ABI is dropped (viem\n // parseEventLogs) instead of surfacing as `args: {}`.\n const logs = await this.publicClient.getLogs({\n address: this.contractAddress,\n events: PEGIN_SUBMITTED_EVENTS,\n fromBlock: createdAt,\n toBlock: createdAt,\n strict: true,\n });\n if (logs.length === 0) {\n throw new RegistrationLogsUnavailableError(createdAt);\n }\n\n return vaultIds.map((vaultId) => {\n const vaultIdLower = vaultId.toLowerCase();\n let registered = false;\n const ceilings: number[] = [];\n for (const log of logs) {\n if (log.args.vaultId.toLowerCase() !== vaultIdLower) continue;\n registered = true;\n if (log.eventName === \"PegInSubmittedV2\") {\n ceilings.push(log.args.maxAcceptableCommissionBps);\n }\n }\n\n if (ceilings.length === 1) return ceilings[0];\n if (ceilings.length > 1) {\n throw new Error(\n `Expected one PegInSubmittedV2 log for vault ${vaultId} at block ${createdAt}, ` +\n `found ${ceilings.length} PegInSubmittedV2 logs`,\n );\n }\n if (registered) {\n throw new Error(\n `Vault ${vaultId} was registered before the registry emitted the depositor's ` +\n `commission ceiling (no PegInSubmittedV2 log at block ${createdAt}), so the ` +\n `ceiling cannot be recovered on-chain`,\n );\n }\n throw new Error(\n `Vault ${vaultId} has no registration log at its on-chain registration block ${createdAt}`,\n );\n });\n }\n}\n","import {\n encodeFunctionData,\n isAddressEqual,\n zeroAddress,\n type Address,\n type Chain,\n type Hex,\n type PublicClient,\n type WalletClient,\n} from \"viem\";\n\nimport { BTCVaultRegistryABI } from \"../../contracts/abis/BTCVaultRegistry.abi\";\nimport { handleContractError } from \"../../contracts/errors\";\nimport {\n capMaxAcceptableCommissionBps,\n COMMISSION_BPS_HEADROOM,\n} from \"../../deposit-terms/commissionCeiling\";\nimport { waitForTransactionReceiptSmartAware } from \"../../utils/eth\";\nimport { assertOnChainBtcPubkey } from \"./onChainBtcPubkey\";\nimport { assertPayoutScriptMatchesPopKey } from \"./payout-script\";\nimport { calculateBtcTxHash, derivePeginVaultId } from \"./pegin-transaction\";\nimport { ViemVaultRegistryReader } from \"./vault-registry-reader\";\n\n/** Referral code sent with peg-in registration. Zero means no referral. */\nexport const NO_REFERRAL_CODE = 0;\nconst UINT8_MAX = 255;\n// Match the prior vault-service timeout. A dropped transaction must not wait forever.\nconst RECEIPT_TIMEOUT_MS = 120_000;\n\nfunction ensureHex(value: string, label: string): Hex {\n const prefixed = value.startsWith(\"0x\")\n ? value\n : value.startsWith(\"0X\")\n ? `0x${value.slice(2)}`\n : `0x${value}`;\n if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(prefixed)) {\n throw new Error(`${label} must be non-empty, even-length hex`);\n }\n return prefixed as Hex;\n}\n\nfunction assertBytes32(value: Hex, label: string): void {\n if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {\n throw new Error(`${label} must be a 32-byte hex value`);\n }\n}\n\n/** All-zero `bytes32` — the shape an unresolved fingerprint takes. */\nconst ZERO_BYTES32 =\n \"0x0000000000000000000000000000000000000000000000000000000000000000\";\n\n/**\n * The single validation point for `expectedFingerprint`, on both the singular\n * and batch paths.\n *\n * Zero is rejected separately from the shape check because it is a *well-formed*\n * `bytes32` that the registry can never accept — the live fingerprint is a\n * keccak256 over a domain-separated preimage — so it can only ever mean the\n * caller had no value and filled the slot. Catching it here turns a defaulted\n * field into a named error instead of an opaque on-chain revert with two\n * hashes and no hint.\n */\nfunction assertFingerprint(value: Hex): void {\n assertBytes32(value, \"expectedFingerprint\");\n if (value.toLowerCase() === ZERO_BYTES32) {\n throw new Error(\n \"expectedFingerprint must not be zero: the registry cannot resolve a \" +\n \"zero fingerprint, so this submission would always revert\",\n );\n }\n}\n\nfunction assertHtlcVout(value: number): void {\n if (!Number.isInteger(value) || value < 0 || value > UINT8_MAX) {\n throw new Error(`htlcVout must be a uint8, got ${value}`);\n }\n}\n\n/** A PoP prepared by a Bitcoin wallet, reusable by the ETH submit client. */\nexport interface PopSignature {\n btcPopSignature: Hex;\n depositorEthAddress: Address;\n /** x-only secp256k1 public key, 64 hex chars without `0x`. */\n depositorBtcPubkey: string;\n}\n\nexport interface ViemPeginRegistrationClientConfig {\n ethWallet: WalletClient;\n ethChain: Chain;\n publicClient: PublicClient;\n btcVaultRegistry: Address;\n receiptTimeoutMs?: number;\n /**\n * Refuse to register without a `quotedCommissionBps`. Set it to `true` when\n * the depositor approved deposit terms on a device: approval froze the\n * commission ceiling from the quote, so the chain-current fallback could\n * admit a commission the device would later refuse to pay out.\n *\n * Required, with no default: an omitted flag would silently pick the unsafe\n * direction for the integrator least able to probe the wallet capability.\n */\n requireQuotedCommissionBps: boolean;\n}\n\nexport interface RegisterPeginOnChainParams {\n unsignedPrePeginTx: string;\n depositorSignedPeginTx: string;\n vaultProvider: Address;\n hashlock: Hex;\n depositorWotsPkHash: Hex;\n popSignature: PopSignature;\n /** Raw x-only, compressed, or uncompressed BTC pubkey from the PoP wallet. */\n depositorBtcPubkeyRaw: string;\n htlcVout: number;\n /**\n * Bitcoin output script bytes, not an address. The client verifies that the\n * script pays the proof-of-possession key before it submits the transaction.\n */\n depositorPayoutScriptPubKey: string;\n quotedCommissionBps?: number;\n /**\n * `keccak256(abi.encode(...))` over the protocol state the Pre-PegIn was\n * built against — see the SDK's `pegin-fingerprint` module.\n *\n * The registry recomputes it live at inclusion and reverts with\n * `PeginFingerprintChanged` on any difference, so it must be computed from\n * the same block-pinned snapshot that shaped the Bitcoin scripts. Required,\n * with no default: a fingerprint the caller did not resolve is not a\n * fingerprint, and the registry has no way to tell the two apart.\n */\n expectedFingerprint: Hex;\n}\n\nexport interface PeginRegistrationResult {\n ethTxHash: Hex;\n vaultId: Hex;\n peginTxHash: Hex;\n}\n\nexport interface BatchPeginRegistrationItem {\n depositorSignedPeginTx: string;\n hashlock: Hex;\n htlcVout: number;\n /**\n * Bitcoin output script bytes, not an address. The client verifies that the\n * script pays the proof-of-possession key before it submits the transaction.\n */\n depositorPayoutScriptPubKey: string;\n depositorWotsPkHash: Hex;\n}\n\nexport interface RegisterPeginBatchOnChainParams {\n vaultProvider: Address;\n unsignedPrePeginTx: string;\n requests: BatchPeginRegistrationItem[];\n popSignature: PopSignature;\n /** Raw x-only, compressed, or uncompressed BTC pubkey from the PoP wallet. */\n depositorBtcPubkeyRaw: string;\n quotedCommissionBps?: number;\n /**\n * See {@link RegisterPeginOnChainParams.expectedFingerprint}. One value for\n * the whole batch: the fingerprint takes no per-request input and a batch\n * fixes one vault provider, so every entry would resolve the same value.\n */\n expectedFingerprint: Hex;\n}\n\nexport interface BatchPeginRegistrationResultItem {\n vaultId: Hex;\n peginTxHash: Hex;\n}\n\nexport interface PeginBatchRegistrationResult {\n ethTxHash: Hex;\n vaults: BatchPeginRegistrationResultItem[];\n}\n\n/**\n * Ethereum-only client for the on-chain half of peg-in registration.\n *\n * It consumes Bitcoin artifacts that were prepared earlier, but owns no BTC\n * wallet and imports neither Bitcoin libraries nor the Rust/WASM package.\n */\nexport class ViemPeginRegistrationClient {\n constructor(private readonly config: ViemPeginRegistrationClientConfig) {}\n\n async registerPeginOnChain(\n params: RegisterPeginOnChainParams,\n ): Promise<PeginRegistrationResult> {\n const request = {\n ...params,\n popSignature: { ...params.popSignature },\n };\n this.assertQuotedCommissionPresentWhenRequired(request.quotedCommissionBps);\n // Second, matching the batch path, so the two public entry points validate\n // in the same order and neither can drift behind a chain call.\n assertFingerprint(request.expectedFingerprint);\n const depositor = this.assertPopMatchesEthAccount(request.popSignature);\n const depositorBtcPubkey = this.normalizeBtcPubkey(request.popSignature);\n const btcPopSignature = ensureHex(\n request.popSignature.btcPopSignature,\n \"btcPopSignature\",\n );\n const normalized = this.normalizeRequest(\n request,\n depositor,\n depositorBtcPubkey,\n );\n\n await this.assertVaultDoesNotExist(\n normalized.vaultId,\n normalized.peginTxHash,\n );\n const peginFee = await this.readPeginFee(request.vaultProvider);\n const maxCommission = await this.resolveMaxAcceptableCommissionBps(\n request.vaultProvider,\n request.quotedCommissionBps,\n );\n const callData = encodeFunctionData({\n abi: BTCVaultRegistryABI,\n functionName: \"submitPeginRequest\",\n args: [\n depositor,\n depositorBtcPubkey,\n btcPopSignature,\n normalized.unsignedPrePeginTx,\n normalized.depositorSignedPeginTx,\n request.vaultProvider,\n maxCommission,\n request.hashlock,\n request.htlcVout,\n normalized.payoutScript,\n request.depositorWotsPkHash,\n // Appended last on the singular overload; the batch takes it at\n // position 4 instead. Order is the selector, so do not \"tidy\" either.\n request.expectedFingerprint,\n ],\n });\n\n const ethTxHash = await this.sendAndWait(\n callData,\n peginFee,\n false,\n depositor,\n );\n return {\n ethTxHash,\n vaultId: normalized.vaultId,\n peginTxHash: normalized.peginTxHash,\n };\n }\n\n async registerPeginBatchOnChain(\n params: RegisterPeginBatchOnChainParams,\n ): Promise<PeginBatchRegistrationResult> {\n const batch = {\n ...params,\n popSignature: { ...params.popSignature },\n requests: params.requests.map((request) => ({ ...request })),\n };\n if (batch.requests.length === 0) {\n throw new Error(\"Batch pegin requires at least one request\");\n }\n this.assertQuotedCommissionPresentWhenRequired(batch.quotedCommissionBps);\n assertFingerprint(batch.expectedFingerprint);\n const depositor = this.assertPopMatchesEthAccount(batch.popSignature);\n const unsignedPrePeginTx = ensureHex(\n batch.unsignedPrePeginTx,\n \"unsignedPrePeginTx\",\n );\n const depositorBtcPubkey = this.normalizeBtcPubkey(batch.popSignature);\n const btcPopSignature = ensureHex(\n batch.popSignature.btcPopSignature,\n \"btcPopSignature\",\n );\n\n const vaults: BatchPeginRegistrationResultItem[] = [];\n const requests = [];\n const seenVaultIds = new Set<string>();\n for (const request of batch.requests) {\n const normalized = this.normalizeRequest(\n {\n ...request,\n unsignedPrePeginTx: batch.unsignedPrePeginTx,\n vaultProvider: batch.vaultProvider,\n depositorBtcPubkeyRaw: batch.depositorBtcPubkeyRaw,\n },\n depositor,\n depositorBtcPubkey,\n );\n if (seenVaultIds.has(normalized.vaultId)) {\n throw new Error(`Duplicate vault in batch: ${normalized.vaultId}`);\n }\n seenVaultIds.add(normalized.vaultId);\n vaults.push({\n vaultId: normalized.vaultId,\n peginTxHash: normalized.peginTxHash,\n });\n requests.push({\n depositorBtcPubKey: depositorBtcPubkey,\n btcPopSignature,\n unsignedPrePeginTx,\n depositorSignedPeginTx: normalized.depositorSignedPeginTx,\n hashlock: request.hashlock,\n htlcVout: request.htlcVout,\n referralCode: NO_REFERRAL_CODE,\n depositorPayoutBtcAddress: normalized.payoutScript,\n depositorWotsPkHash: request.depositorWotsPkHash,\n });\n }\n for (const vault of vaults) {\n await this.assertVaultDoesNotExist(vault.vaultId, vault.peginTxHash);\n }\n\n const peginFee = await this.readPeginFee(batch.vaultProvider);\n const maxCommission = await this.resolveMaxAcceptableCommissionBps(\n batch.vaultProvider,\n batch.quotedCommissionBps,\n );\n const callData = encodeFunctionData({\n abi: BTCVaultRegistryABI,\n functionName: \"submitPeginRequestBatch\",\n // `expectedFingerprint` sits BEFORE `requests`, not appended. Reordering\n // these five changes the selector and the call stops existing.\n args: [\n depositor,\n batch.vaultProvider,\n maxCommission,\n batch.expectedFingerprint,\n requests,\n ],\n });\n const ethTxHash = await this.sendAndWait(\n callData,\n peginFee * BigInt(batch.requests.length),\n true,\n depositor,\n );\n return { ethTxHash, vaults };\n }\n\n private assertQuotedCommissionPresentWhenRequired(\n quotedCommissionBps?: number,\n ): void {\n if (\n quotedCommissionBps === undefined &&\n this.config.requireQuotedCommissionBps\n ) {\n throw new Error(\n \"quotedCommissionBps is required when the wallet approved deposit \" +\n \"terms: the registration ceiling must anchor to the approved quote.\",\n );\n }\n }\n\n private assertPopMatchesEthAccount(pop: PopSignature): Address {\n return this.assertEthAccount(pop.depositorEthAddress);\n }\n\n private assertEthAccount(expectedDepositor: Address): Address {\n const account = this.config.ethWallet.account;\n if (!account) throw new Error(\"Ethereum wallet account not found\");\n if (!isAddressEqual(expectedDepositor, account.address)) {\n throw new Error(\n `Proof of possession was signed for ${expectedDepositor} ` +\n `but the Ethereum wallet is currently connected to ${account.address}. ` +\n `Reconnect the original account or sign a new proof of possession.`,\n );\n }\n return account.address;\n }\n\n private normalizeBtcPubkey(pop: PopSignature): Hex {\n return `0x${assertOnChainBtcPubkey(\n ensureHex(pop.depositorBtcPubkey, \"Proof of possession BTC pubkey\"),\n \"Proof of possession BTC pubkey\",\n )}`;\n }\n\n // `expectedFingerprint` is omitted rather than accepted and ignored: nothing\n // here normalizes it, and requiring it would force the batch loop to thread a\n // value through a per-request helper that has no use for it. It is validated\n // once per call, at the top of each public method.\n private normalizeRequest(\n params: Omit<\n RegisterPeginOnChainParams,\n \"popSignature\" | \"expectedFingerprint\"\n >,\n depositor: Address,\n depositorBtcPubkey: Hex,\n ) {\n assertBytes32(params.hashlock, \"hashlock\");\n assertBytes32(params.depositorWotsPkHash, \"depositorWotsPkHash\");\n assertHtlcVout(params.htlcVout);\n const unsignedPrePeginTx = ensureHex(\n params.unsignedPrePeginTx,\n \"unsignedPrePeginTx\",\n );\n const depositorSignedPeginTx = ensureHex(\n params.depositorSignedPeginTx,\n \"depositorSignedPeginTx\",\n );\n const peginTxHash = calculateBtcTxHash(depositorSignedPeginTx);\n return {\n unsignedPrePeginTx,\n depositorSignedPeginTx,\n payoutScript: assertPayoutScriptMatchesPopKey(\n params.depositorPayoutScriptPubKey,\n depositorBtcPubkey,\n params.depositorBtcPubkeyRaw,\n ),\n peginTxHash,\n vaultId: ensureHex(derivePeginVaultId(peginTxHash, depositor), \"vaultId\"),\n };\n }\n\n private async assertVaultDoesNotExist(\n vaultId: Hex,\n peginTxHash: Hex,\n ): Promise<void> {\n const result = (await this.config.publicClient.readContract({\n address: this.config.btcVaultRegistry,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as { depositor: Address };\n if (result.depositor !== zeroAddress) {\n throw new Error(\n `Vault already exists (ID: ${vaultId}, peginTxHash: ${peginTxHash}). ` +\n `Vault IDs are derived from the pegin transaction hash and depositor address. ` +\n `To create a new vault, use different UTXOs or a different amount to generate a unique transaction.`,\n );\n }\n }\n\n private async readPeginFee(vaultProvider: Address): Promise<bigint> {\n try {\n return (await this.config.publicClient.readContract({\n address: this.config.btcVaultRegistry,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n } catch (error) {\n throw new Error(\n \"Failed to query pegin fee from the contract. \" +\n \"Please check your network connection and contract address.\",\n { cause: error },\n );\n }\n }\n\n private async resolveMaxAcceptableCommissionBps(\n vaultProvider: Address,\n quotedCommissionBps?: number,\n ): Promise<number> {\n let currentBps: number;\n try {\n currentBps = await new ViemVaultRegistryReader(\n this.config.publicClient,\n this.config.btcVaultRegistry,\n ).getVaultProviderCommission(vaultProvider);\n } catch (error) {\n throw new Error(\n \"Failed to query vault provider commission from the contract. \" +\n \"Please check your network connection and contract address.\",\n { cause: error },\n );\n }\n if (quotedCommissionBps !== undefined) {\n if (currentBps > quotedCommissionBps + COMMISSION_BPS_HEADROOM) {\n throw new Error(\n `Vault provider commission changed since quote: quoted ${quotedCommissionBps} bps, ` +\n `chain currently reports ${currentBps} bps (allowed drift ${COMMISSION_BPS_HEADROOM} bps). ` +\n `Please refresh and try again.`,\n );\n }\n return capMaxAcceptableCommissionBps(quotedCommissionBps);\n }\n return capMaxAcceptableCommissionBps(currentBps);\n }\n\n private async sendAndWait(\n data: Hex,\n value: bigint,\n batch: boolean,\n depositor: Address,\n ): Promise<Hex> {\n let account = this.assertEthAccount(depositor);\n let gas: bigint;\n try {\n gas = await this.config.publicClient.estimateGas({\n to: this.config.btcVaultRegistry,\n data,\n value,\n account,\n });\n } catch (error) {\n handleContractError(error);\n }\n\n account = this.assertEthAccount(depositor);\n let submittedHash: Hex;\n try {\n submittedHash = await this.config.ethWallet.sendTransaction({\n to: this.config.btcVaultRegistry,\n data,\n value,\n gas,\n account,\n chain: this.config.ethChain,\n });\n } catch (error) {\n handleContractError(error);\n }\n const receipt = await waitForTransactionReceiptSmartAware({\n publicClient: this.config.publicClient,\n walletAddress: depositor,\n hash: submittedHash,\n timeout: this.config.receiptTimeoutMs ?? RECEIPT_TIMEOUT_MS,\n });\n if (receipt.status === \"reverted\") {\n handleContractError(\n new Error(\n `${batch ? \"Batch transaction\" : \"Transaction\"} reverted. ` +\n `Hash: ${receipt.transactionHash}. Check a block explorer for details.`,\n ),\n );\n }\n return receipt.transactionHash;\n }\n}\n"],"names":["COMMISSION_BPS_HEADROOM","MAX_ACCEPTABLE_COMMISSION_BPS_CAP","capMaxAcceptableCommissionBps","bps","MAX_VP_COMMISSION_BPS_EXCLUSIVE","Rho160","Id160","_","i","Pi160","idxLR","res","j","k","idxL","idxR","shifts160","shiftsL160","idx","shiftsR160","Kl160","Kr160","ripemd_f","group","x","y","z","BUF_160","_RIPEMD160","HashMD","__publicField","h0","h1","h2","h3","h4","view","offset","al","ar","bl","br","cl","cr","dl","dr","el","er","rGroup","hbl","hbr","rl","rr","sl","sr","tl","rotl","tr","clean","ripemd160","createHasher","P2TR_SCRIPT_PREFIX","P2WPKH_SCRIPT_PREFIX","HASH160_BYTES","COMPRESSED_PUBKEY_BYTES","UNCOMPRESSED_PUBKEY_BYTES","SEC1_EVEN_Y_PREFIX","SEC1_ODD_Y_PREFIX","SEC1_UNCOMPRESSED_PREFIX","normalizeHex","value","label","body","deriveP2trScript","xOnlyPubkey","pubkeyBytes","hexToBytes","internalKey","schnorr","tweak","secp256k1","outputKey","bytesToHex","normalizePayoutPubkey","normalized","pubkey","assertOnChainBtcPubkey","isCompressed","isUncompressed","deriveP2wpkhScript","sha256","assertPayoutScriptMatchesPopKey","scriptPubKey","depositorBtcPubkey","depositorBtcPubkeyRaw","payoutScript","MAX_PAYOUT_SCRIPT_LEN","keyBody","payoutPubkey","UINT16_MAX","MAX_BASIS_POINTS","UINT32_MAX","UINT8_MAX","assertValidOffchainParamsVersion","version","validateOffchainParams","params","errors","validateTBVProtocolParams","validatePegInConfiguration","config","assertValidVaultCoreVersion","REGISTRATION_LOGS_UNAVAILABLE_ERROR_NAME","RegistrationLogsUnavailableError","blockNumber","isRegistrationLogsUnavailableError","err","MAX_VP_COMMISSION_BPS","mapVaultBasicInfo","result","mapVaultProtocolInfo","offchainParamsVersion","UINT64_EXCLUSIVE_UPPER_BOUND","VP_GENESIS_KEY_EPOCH","PEGIN_SUBMITTED_EVENTS","getAbiItem","BTCVaultRegistryABI","assertEpochInRange","field","vaultId","mapKeyEpochs","ViemVaultRegistryReader","publicClient","contractAddress","vpAddress","epoch","BTCVaultRegistryKeyEpochsABI","vaultIds","info","vaultProvider","basicRaw","protocolRaw","basic","protocol","createdAt","logs","vaultIdLower","registered","ceilings","log","NO_REFERRAL_CODE","RECEIPT_TIMEOUT_MS","ensureHex","prefixed","assertBytes32","ZERO_BYTES32","assertFingerprint","assertHtlcVout","ViemPeginRegistrationClient","request","depositor","btcPopSignature","peginFee","maxCommission","callData","encodeFunctionData","batch","unsignedPrePeginTx","vaults","requests","seenVaultIds","vault","quotedCommissionBps","pop","expectedDepositor","account","isAddressEqual","depositorSignedPeginTx","peginTxHash","calculateBtcTxHash","derivePeginVaultId","zeroAddress","error","currentBps","data","gas","handleContractError","submittedHash","receipt","waitForTransactionReceiptSmartAware"],"mappings":"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","x_google_ignoreList":[1]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var z=Object.defineProperty;var Q=(r,e,t)=>e in r?z(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var u=(r,e,t)=>Q(r,typeof e!="symbol"?e+"":e,t);const _=require("./bitcoin-D-O2GjbC.cjs"),Z=require("./index-MRdle0fs.cjs"),ee=require("./state-C4WoNCy1.cjs"),te=require("@bitcoin-js/tiny-secp256k1-asmjs"),y=require("./validation-C6XTfZak.cjs"),re=require("./bip322Verify-DLxJR9CQ.cjs"),ne=require("./sha2-Ce6KewYx.cjs");function ie(r){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const t in r)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(r,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return e.default=r,Object.freeze(e)}const J=ie(te);function k(r,e){const t=(r&7)<<5,n=typeof e=="bigint"?e:BigInt(e);if(n<0n)throw new Error("cborHead: negative argument");if(n<24n)return new Uint8Array([t|Number(n)]);if(n<0x100n)return new Uint8Array([t|24,Number(n)]);if(n<0x10000n){const i=Number(n);return new Uint8Array([t|25,i>>>8&255,i&255])}if(n<0x100000000n){const i=Number(n);return new Uint8Array([t|26,i>>>24&255,i>>>16&255,i>>>8&255,i&255])}const s=new Uint8Array(9);s[0]=t|27;for(let i=7;i>=0;i--)s[1+i]=Number(n>>BigInt((7-i)*8))&255;return s}function V(...r){const e=r.reduce((s,i)=>s+i.length,0),t=new Uint8Array(e);let n=0;for(const s of r)t.set(s,n),n+=s.length;return t}function I(r){const t=[k(4,r.length)];for(const n of r)t.push(k(0,n));return V(...t)}function se(r,e,t){if(!Number.isSafeInteger(t)||t<0)throw new Error(`encodeServerIdentityPayload: expires_at must be a non-negative safe integer, got ${t}`);const n=k(4,3),s=I(r),i=I(e),o=k(0,t);return V(n,s,i,o)}const oe=new TextEncoder().encode("btc-auth.server-identity.v1"),ce=2*3600;class h extends Error{constructor(e,t){super(e),this.reason=t,this.name="ServerIdentityError"}}function v(r){const e=new Uint8Array(r.length/2);for(let t=0;t<e.length;t++)e[t]=parseInt(r.slice(t*2,t*2+2),16);return e}function D(r){const{proof:e,pinnedServerPubkey:t,now:n}=r,s=r.maxLifetimeSecs??ce,i=_.stripHexPrefix(t).toLowerCase();if(i.length!==y.X_ONLY_PUBKEY_HEX_LEN||!y.HEX_RE.test(i))throw new h(`pinnedServerPubkey must be 32-byte hex; got ${i.length} chars`,"invalid_pubkey_encoding");const o=_.stripHexPrefix(e.server_pubkey).toLowerCase();if(o.length!==y.X_ONLY_PUBKEY_HEX_LEN||!y.HEX_RE.test(o))throw new h(`server_pubkey must be 32-byte hex; got ${o.length} chars`,"invalid_pubkey_encoding");if(o!==i)throw new h(`server_pubkey does not match pinned value: expected ${i}, got ${o}`,"pinned_pubkey_mismatch");if(!Number.isSafeInteger(e.expires_at))throw new h(`expires_at must be a finite integer; got ${JSON.stringify(e.expires_at)}`,"invalid_expires_at");if(!Number.isSafeInteger(n))throw new h(`now must be a finite integer; got ${JSON.stringify(n)}`,"invalid_expires_at");if(e.expires_at<=n)throw new h(`server identity proof expired at ${e.expires_at}, now ${n}`,"expired");if(!Number.isSafeInteger(s)||s<=0)throw new h(`maxLifetimeSecs must be a positive safe integer; got ${JSON.stringify(s)}`,"invalid_max_lifetime");if(e.expires_at-n>s)throw new h(`server identity proof expires too far in the future: expires_at=${e.expires_at}, now=${n}, max lifetime=${s}s`,"expires_too_far");const a=_.stripHexPrefix(e.ephemeral_pubkey).toLowerCase();if(a.length!==y.COMPRESSED_PUBKEY_HEX_LEN||!y.HEX_RE.test(a))throw new h(`ephemeral_pubkey must be 33-byte compressed hex; got ${a.length} chars`,"invalid_ephemeral_pubkey");const g=a.slice(0,2);if(g!=="02"&&g!=="03")throw new h(`ephemeral_pubkey must be compressed (prefix 02/03); got ${g}`,"invalid_ephemeral_pubkey");const l=v(a);if(!J.isPoint(l))throw new h("ephemeral_pubkey is not a valid secp256k1 point","invalid_ephemeral_pubkey");const p=_.stripHexPrefix(e.signature).toLowerCase();if(p.length!==_.SCHNORR_SIG_HEX_LEN||!y.HEX_RE.test(p))throw new h(`signature must be 64-byte Schnorr hex; got ${p.length} chars`,"invalid_signature_encoding");const b=se(oe,v(a),e.expires_at);if(!re.verifyBip322Simple(b,v(o),v(p)))throw new h("BIP-322 signature verification failed — ephemeral key is not attested by pinned server pubkey","signature_verification_failed")}const ae=new Set(["vaultProvider_submitDepositorWotsKey","vaultProvider_submitDepositorPresignatures","vaultProvider_requestDepositorPresignTransactions"]),de=new Set(["vaultProvider_requestDepositorClaimerArtifacts"]),ue=6e4,T="auth_createDepositorToken",C="auth_createDepositorTokenGrpc";function j(r,e){return new ee.JsonRpcClient({baseUrl:r,timeout:ue,headers:e,retryableFor:t=>t===T||t===C})}const pe=0,he=1,A=2,le=3,ye=4,ge=5,_e=6,fe=7,H=24,be=28,xe=20,we=21,ve=22,N=256;class f extends Error{constructor(e){super(`CBOR decode: ${e}`),this.name="CborDecodeError"}}class K{constructor(e){u(this,"buf");u(this,"pos",0);this.buf=e}nextByte(){if(this.pos>=this.buf.length)throw new f("unexpected end of input");return this.buf[this.pos++]}readHead(){const e=this.nextByte(),t=e>>5,n=e&31;if(n<H)return{major:t,arg:n};if(n>=be)throw new f(`unsupported additional info ${n} (indefinite-length or reserved)`);const s=1<<n-H;let i=0n;for(let o=0;o<s;o++)i=i<<8n|BigInt(this.nextByte());if(i>BigInt(Number.MAX_SAFE_INTEGER))throw new f(`argument ${i} exceeds safe integer range`);return{major:t,arg:Number(i)}}readBytes(e){if(this.pos+e>this.buf.length)throw new f("length overruns end of input");const t=this.buf.subarray(this.pos,this.pos+e);return this.pos+=e,t}readByteString(){const e=this.readHead();if(e.major!==A)throw new f(`expected byte string (major ${A}), got major ${e.major}`);return this.readBytes(e.arg)}readValue(e=0){if(e>N)throw new f(`nesting exceeds maximum depth ${N}`);const t=this.readHead();switch(t.major){case pe:return t.arg;case he:return-1-t.arg;case A:return this.readBytes(t.arg);case le:return new TextDecoder("utf-8",{fatal:!0}).decode(this.readBytes(t.arg));case ye:{const n=[];for(let s=0;s<t.arg;s++)n.push(this.readValue(e+1));return n}case ge:{const n=new Map;for(let s=0;s<t.arg;s++){const i=this.readValue(e+1),o=this.readValue(e+1);n.set(i,o)}return n}case _e:return{tag:t.arg,value:this.readValue(e+1)};case fe:if(t.arg===xe)return!1;if(t.arg===we)return!0;if(t.arg===ve)return null;throw new f(`unsupported simple/float value ${t.arg}`);default:throw new f(`unsupported major type ${t.major}`)}}}function F(r){const e=new K(r),t=e.readValue();if(e.pos!==r.length)throw new f("trailing bytes after top-level item");return t}const ke="vaultd-jsonrpc",Pe="vaultd-grpc",L=18,R=4,X=-47,Se=1,M=64,Ae=128,Ee=96,me=64,Te=1,Ce=2,Re=3,Oe=4,$e=5,Ie=6,He=7,B=new TextEncoder().encode("Signature1");class c extends Error{constructor(e,t){super(e),this.reason=t,this.name="CwtVerificationError"}}function Ne(r){const e=G(r.expectedIssuerXOnlyPubkey,"expectedIssuerXOnlyPubkey"),t=G(r.expectedAudienceXOnlyPubkey,"expectedAudienceXOnlyPubkey"),n=Ge(r.ephemeralPubkeyHex),s=Je(r.token),i=new K(s),o=i.readHead();if(o.major!==6||o.arg!==L)throw new c(`token is not a COSE Sign1 tagged value (tag ${L})`,"invalid_token_structure");const a=i.readHead();if(a.major!==4||a.arg!==R)throw new c(`COSE Sign1 must be a ${R}-element array`,"invalid_token_structure");const g=i.pos,l=i.readByteString(),p=s.subarray(g,i.pos);i.readValue();const b=i.pos,x=i.readByteString(),P=s.subarray(b,i.pos),S=i.readByteString();if(S.length!==M)throw new c(`COSE signature must be ${M} bytes, got ${S.length}`,"invalid_token_structure");if(i.pos!==s.length)throw new c("COSE Sign1 token has trailing bytes after the signature","invalid_token_structure");const $=Le(l);if($!==X)throw new c(`unexpected COSE algorithm ${$} (expected ES256K ${X})`,"unexpected_algorithm");const Y=Xe(p,P),W=ne.sha256(Y);if(!J.verify(W,n,S,!0))throw new c("COSE signature does not verify against the server's ephemeral key","signature_verification_failed");const d=Me(x),w=d.audience.toLowerCase();if(w.length!==y.X_ONLY_PUBKEY_HEX_LEN||!y.HEX_RE.test(w))throw new c("token `aud` is not a 32-byte x-only pubkey hex","invalid_claims");if(d.issuedAt>d.expiresAt)throw new c(`token iat (${d.issuedAt}) is after exp (${d.expiresAt})`,"invalid_claims");if(d.issuer.toLowerCase()!==e)throw new c(`token issuer does not match pinned server pubkey: expected ${e}, got ${d.issuer.toLowerCase()}`,"issuer_mismatch");if(d.subject!==r.expectedSubject)throw new c(`token subject mismatch: expected ${r.expectedSubject}, got ${d.subject}`,"subject_mismatch");if(w!==t)throw new c(`token audience does not match depositor pubkey: expected ${t}, got ${w}`,"audience_mismatch");if(d.expiresAt<=r.now)throw new c(`token expired: exp ${d.expiresAt} <= now ${r.now}`,"token_expired");if(r.responseExpiresAt!==d.expiresAt)throw new c(`response expires_at (${r.responseExpiresAt}) does not equal token exp (${d.expiresAt})`,"expiry_mismatch");if(r.serverIdentityExpiresAt<d.expiresAt)throw new c(`server identity expires (${r.serverIdentityExpiresAt}) before token exp (${d.expiresAt})`,"server_identity_expires_before_token");return{issuer:d.issuer,subject:d.subject,audience:w,expiresAt:d.expiresAt,notBefore:d.notBefore,issuedAt:d.issuedAt}}function Le(r){if(r.length===0)throw new c("empty COSE protected header (no algorithm)","unexpected_algorithm");const e=F(r);if(!(e instanceof Map))throw new c("COSE protected header is not a map","invalid_token_structure");const t=e.get(Se);if(typeof t!="number")throw new c("COSE protected header missing integer algorithm label","unexpected_algorithm");return t}function Xe(r,e){return Ve(Uint8Array.of(Ae|R),Uint8Array.of(Ee|B.length),B,r,Uint8Array.of(me),e)}function Me(r){const e=F(r);if(!(e instanceof Map))throw new c("CWT claims root is not a map","invalid_claims");if(Be(e,He,"cti").length===0)throw new c("token cti is empty","invalid_claims");return{issuer:E(e,Te,"iss"),subject:E(e,Ce,"sub"),audience:E(e,Re,"aud"),expiresAt:m(e,Oe,"exp"),notBefore:m(e,$e,"nbf"),issuedAt:m(e,Ie,"iat")}}function E(r,e,t){const n=r.get(e);if(typeof n!="string")throw new c(`token claim ${t} is missing or not a text string`,"invalid_claims");return n}function Be(r,e,t){const n=r.get(e);if(!(n instanceof Uint8Array))throw new c(`token claim ${t} is missing or not a byte string`,"invalid_claims");return n}function m(r,e,t){const n=r.get(e);if(typeof n!="number"||!Number.isSafeInteger(n)||n<0)throw new c(`token claim ${t} is missing or not a non-negative integer timestamp`,"invalid_claims");return n}function G(r,e){const t=_.stripHexPrefix(r).toLowerCase();if(t.length!==y.X_ONLY_PUBKEY_HEX_LEN||!y.HEX_RE.test(t))throw new c(`${e} must be 32-byte x-only hex; got ${t.length} chars`,"invalid_input");return t}function Ge(r){const e=_.stripHexPrefix(r).toLowerCase(),t=e.slice(0,2);if(e.length!==y.COMPRESSED_PUBKEY_HEX_LEN||!y.HEX_RE.test(e)||t!=="02"&&t!=="03")throw new c("ephemeralPubkeyHex must be 33-byte compressed pubkey hex (prefix 02/03)","invalid_input");return _.hexToUint8Array(e)}const Ue=(()=>{const r=new Int16Array(128).fill(-1),e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";for(let t=0;t<e.length;t++)r[e.charCodeAt(t)]=t;return r})();function Je(r){const e=r.length,t=Math.floor(e/4),n=e%4;if(n===1)throw new c("invalid base64url length","invalid_token_structure");const s=t*3+(n===0?0:n-1),i=new Uint8Array(s),o=l=>{const p=l<128?Ue[l]:-1;if(p<0)throw new c("invalid base64url character","invalid_token_structure");return p};let a=0,g=0;for(let l=0;l<t;l++){const p=o(r.charCodeAt(a++)),b=o(r.charCodeAt(a++)),x=o(r.charCodeAt(a++)),P=o(r.charCodeAt(a++));i[g++]=p<<2|b>>4,i[g++]=(b&15)<<4|x>>2,i[g++]=(x&3)<<6|P}if(n===2){const l=o(r.charCodeAt(a++)),p=o(r.charCodeAt(a++));i[g++]=l<<2|p>>4}else if(n===3){const l=o(r.charCodeAt(a++)),p=o(r.charCodeAt(a++)),b=o(r.charCodeAt(a++));i[g++]=l<<2|p>>4,i[g++]=(p&15)<<4|b>>2}return i}function Ve(...r){const e=r.reduce((s,i)=>s+i.length,0),t=new Uint8Array(e);let n=0;for(const s of r)t.set(s,n),n+=s.length;return t}const U=4102444800,De=30;class je{constructor(e){u(this,"client");u(this,"peginTxid");u(this,"authAnchorHex");u(this,"jsonRpcPinnedServerPubkey");u(this,"grpcPinnedServerPubkey");u(this,"refreshJsonRpcPinnedServerPubkey");u(this,"expectedAudienceXOnlyPubkey");u(this,"authGatedMethods");u(this,"grpcGatedMethods");u(this,"refreshSkewSecs");u(this,"now");u(this,"cachedJsonRpc",null);u(this,"inFlightJsonRpc",null);u(this,"cachedGrpc",null);u(this,"inFlightGrpc",null);this.client=e.client,this.peginTxid=e.peginTxid,this.authAnchorHex=e.authAnchorHex,this.jsonRpcPinnedServerPubkey=e.pinnedServerPubkey,this.grpcPinnedServerPubkey=e.grpcPinnedServerPubkey,this.refreshJsonRpcPinnedServerPubkey=e.refreshJsonRpcPinnedServerPubkey,this.expectedAudienceXOnlyPubkey=e.expectedAudienceXOnlyPubkey,this.authGatedMethods=e.authGatedMethods,this.grpcGatedMethods=e.grpcGatedMethods,this.refreshSkewSecs=e.refreshSkewSecs??De,this.now=e.now??(()=>Math.floor(Date.now()/1e3))}async getToken(e){return e===T||e===C?null:this.grpcGatedMethods.has(e)?this.getTokenForSubject("grpc"):this.authGatedMethods.has(e)?this.getTokenForSubject("jsonrpc"):null}invalidate(){this.cachedJsonRpc=null,this.cachedGrpc=null}async getTokenForSubject(e){const t=e==="grpc"?this.cachedGrpc:this.cachedJsonRpc;return t&&this.now()+this.refreshSkewSecs<t.expiresAt?t.token:(await this.acquireSingleFlight(e)).token}setClient(e){this.client=e}getPinnedServerPubkey(e){return e==="grpc"?this.grpcPinnedServerPubkey:this.jsonRpcPinnedServerPubkey}acquireSingleFlight(e){const t=e==="grpc"?this.inFlightGrpc:this.inFlightJsonRpc;if(t)return t;const n=e==="grpc"?C:T,s=(async()=>{try{const i=await this.acquireAndVerify(e,n,!0);return e==="grpc"?this.cachedGrpc=i:this.cachedJsonRpc=i,i}finally{e==="grpc"?this.inFlightGrpc=null:this.inFlightJsonRpc=null}})();return e==="grpc"?this.inFlightGrpc=s:this.inFlightJsonRpc=s,s}async acquireAndVerify(e,t,n){const s=await this.client.call(t,{pegin_txid:this.peginTxid,auth_anchor:this.authAnchorHex}),i=this.getPinnedServerPubkey(e);try{if(D({proof:s.server_identity,pinnedServerPubkey:i,now:this.now()}),typeof s.token!="string"||s.token.length===0)throw new Error(`VpTokenProvider: invalid token in acquire response (expected non-empty string, got ${typeof s.token})`);const o=this.now();if(!Number.isSafeInteger(s.expires_at)||s.expires_at<=o||s.expires_at>U)throw new Error(`VpTokenProvider: invalid expires_at in acquire response (got ${JSON.stringify(s.expires_at)}; must be a safe integer in (${o}, ${U}])`);return Ne({token:s.token,ephemeralPubkeyHex:s.server_identity.ephemeral_pubkey,expectedIssuerXOnlyPubkey:i,expectedSubject:e==="grpc"?Pe:ke,expectedAudienceXOnlyPubkey:this.expectedAudienceXOnlyPubkey,responseExpiresAt:s.expires_at,serverIdentityExpiresAt:s.server_identity.expires_at,now:o}),{token:s.token,expiresAt:s.expires_at}}catch(o){if(n&&e==="jsonrpc"&&this.refreshJsonRpcPinnedServerPubkey&&Ke(o)){const a=await this.refreshJsonRpcPinnedServerPubkey();if(a!==this.jsonRpcPinnedServerPubkey)return this.jsonRpcPinnedServerPubkey=a,this.acquireAndVerify(e,t,!1)}throw o}}}function Ke(r){return r instanceof h&&r.reason==="pinned_pubkey_mismatch"||r instanceof c&&r.reason==="issuer_mismatch"}class q{constructor(){u(this,"entries",new Map)}getOrCreate(e){const t=this.entries.get(e.peginTxid);if(t){if(t.authAnchorHex!==e.authAnchorHex)throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to authAnchorHex ${t.authAnchorHex.slice(0,8)}…; got ${e.authAnchorHex.slice(0,8)}…`);if(t.providerAddress.toLowerCase()!==e.providerAddress.toLowerCase())throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to providerAddress ${t.providerAddress}; got ${e.providerAddress}`);if(t.provider.getPinnedServerPubkey("jsonrpc")!==e.pinnedServerPubkey)throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to JSON-RPC pinnedServerPubkey ${t.provider.getPinnedServerPubkey("jsonrpc").slice(0,8)}…; got ${e.pinnedServerPubkey.slice(0,8)}…`);if(t.provider.getPinnedServerPubkey("grpc")!==e.grpcPinnedServerPubkey)throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to gRPC pinnedServerPubkey ${t.provider.getPinnedServerPubkey("grpc").slice(0,8)}…; got ${e.grpcPinnedServerPubkey.slice(0,8)}…`);if(t.grpcKeyEpoch!==e.grpcKeyEpoch)throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to gRPC key epoch ${t.grpcKeyEpoch.toString()}; got ${e.grpcKeyEpoch.toString()}`);if(t.expectedAudienceXOnlyPubkey.toLowerCase()!==e.expectedAudienceXOnlyPubkey.toLowerCase())throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to expectedAudienceXOnlyPubkey ${t.expectedAudienceXOnlyPubkey.slice(0,8)}…; got ${e.expectedAudienceXOnlyPubkey.slice(0,8)}…`);return t.provider.setClient(e.client),t.provider}const n=new je({client:e.client,peginTxid:e.peginTxid,authAnchorHex:e.authAnchorHex,pinnedServerPubkey:e.pinnedServerPubkey,grpcPinnedServerPubkey:e.grpcPinnedServerPubkey,refreshJsonRpcPinnedServerPubkey:e.refreshJsonRpcPinnedServerPubkey,expectedAudienceXOnlyPubkey:e.expectedAudienceXOnlyPubkey,authGatedMethods:ae,grpcGatedMethods:de});return this.entries.set(e.peginTxid,{provider:n,authAnchorHex:e.authAnchorHex,providerAddress:e.providerAddress,grpcKeyEpoch:e.grpcKeyEpoch,expectedAudienceXOnlyPubkey:e.expectedAudienceXOnlyPubkey}),n}peek(e){const t=this.entries.get(e.peginTxid);if(t){if(t.providerAddress.toLowerCase()!==e.providerAddress.toLowerCase())throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to providerAddress ${t.providerAddress}; got ${e.providerAddress}`);if(t.expectedAudienceXOnlyPubkey.toLowerCase()!==e.expectedAudienceXOnlyPubkey.toLowerCase())throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to expectedAudienceXOnlyPubkey ${t.expectedAudienceXOnlyPubkey.slice(0,8)}…; got ${e.expectedAudienceXOnlyPubkey.slice(0,8)}…`);return t.provider}}release(e){this.entries.delete(e)}clear(){this.entries.clear()}get size(){return this.entries.size}}const O=new q;function Fe(r){var n;const e=j(r.baseUrl,(n=r.options)==null?void 0:n.headers),t=O.getOrCreate({client:e,peginTxid:r.peginTxid,authAnchorHex:r.authAnchorHex,providerAddress:r.providerAddress,pinnedServerPubkey:r.pinnedServerPubkey,grpcPinnedServerPubkey:r.grpcPinnedServerPubkey,grpcKeyEpoch:r.grpcKeyEpoch,refreshJsonRpcPinnedServerPubkey:r.refreshJsonRpcPinnedServerPubkey,expectedAudienceXOnlyPubkey:_.processPublicKeyToXOnly(r.depositorBtcPubkey)});return new Z.VaultProviderRpcClient(r.baseUrl,{...r.options,tokenProvider:t})}function qe(r){O.getOrCreate({client:j(r.baseUrl,r.headers),peginTxid:r.peginTxid,authAnchorHex:r.authAnchorHex,providerAddress:r.providerAddress,pinnedServerPubkey:r.pinnedServerPubkey,grpcPinnedServerPubkey:r.grpcPinnedServerPubkey,grpcKeyEpoch:r.grpcKeyEpoch,refreshJsonRpcPinnedServerPubkey:r.refreshJsonRpcPinnedServerPubkey,expectedAudienceXOnlyPubkey:_.processPublicKeyToXOnly(r.depositorBtcPubkey)})}exports.ServerIdentityError=h;exports.VpTokenRegistry=q;exports.createAuthenticatedVpClient=Fe;exports.primeVpTokenRegistry=qe;exports.verifyServerIdentity=D;exports.vpTokenRegistry=O;
|
|
2
|
+
//# sourceMappingURL=primeVpAuth-BDWBKYhv.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primeVpAuth-BDWBKYhv.cjs","sources":["../src/tbv/core/clients/vault-provider/auth/cbor.ts","../src/tbv/core/clients/vault-provider/auth/serverIdentity.ts","../src/tbv/core/clients/vault-provider/auth/gatedMethods.ts","../src/tbv/core/clients/vault-provider/auth/innerTokenClient.ts","../src/tbv/core/clients/vault-provider/auth/cborDecode.ts","../src/tbv/core/clients/vault-provider/auth/verifyDepositorCwt.ts","../src/tbv/core/clients/vault-provider/auth/tokenProvider.ts","../src/tbv/core/clients/vault-provider/auth/tokenRegistry.ts","../src/tbv/core/clients/vault-provider/auth/createAuthenticatedVpClient.ts","../src/tbv/core/clients/vault-provider/auth/primeVpAuth.ts"],"sourcesContent":["/**\n * Minimal CBOR encoder for the server-identity payload shape.\n *\n * We only need to encode one specific CBOR structure — the 3-tuple\n * `(SERVER_IDENTITY_DOMAIN, ephemeral_pubkey_bytes, expires_at_u64)` —\n * byte-for-byte identical to what the Rust `ciborium` crate produces\n * for the corresponding tuple, because that's the exact message the\n * VP signs with BIP-322.\n *\n * IMPORTANT encoding quirk: the Rust side passes the domain and\n * pubkey as `&[u8]` / `Vec<u8>` without a `#[serde(with = \"serde_bytes\")]`\n * attribute, so serde/ciborium encodes them as **CBOR arrays of u8**\n * (major type 4, one item per byte) — NOT as CBOR byte strings (major\n * type 2). A naive byte-string encoding would produce the wrong bytes\n * and signature verification would fail.\n *\n * Rather than pull in a full CBOR dependency for this one shape, we\n * implement the exact subset inline (~40 LOC) and pin it with golden\n * vectors against the Rust reference output.\n *\n * @module tbv/core/clients/vault-provider/auth/cbor\n */\n\n/**\n * Encode a small CBOR unsigned-integer \"head\" byte for major type\n * `major` (0..7) with argument `arg` (0..2^64-1).\n *\n * Returns the header bytes; the caller concatenates any trailing data\n * (e.g. array elements). Encoding rules:\n * arg < 24 → single byte `(major << 5) | arg`\n * arg < 256 → `(major << 5) | 24` + 1-byte arg\n * arg < 65536 → `(major << 5) | 25` + 2-byte BE arg\n * arg < 2^32 → `(major << 5) | 26` + 4-byte BE arg\n * arg < 2^64 → `(major << 5) | 27` + 8-byte BE arg\n */\nfunction cborHead(major: number, arg: number | bigint): Uint8Array {\n const tag = (major & 0x07) << 5;\n const n = typeof arg === \"bigint\" ? arg : BigInt(arg);\n if (n < 0n) throw new Error(\"cborHead: negative argument\");\n\n if (n < 24n) return new Uint8Array([tag | Number(n)]);\n if (n < 0x100n) return new Uint8Array([tag | 24, Number(n)]);\n if (n < 0x10000n) {\n const v = Number(n);\n return new Uint8Array([tag | 25, (v >>> 8) & 0xff, v & 0xff]);\n }\n if (n < 0x1_0000_0000n) {\n const v = Number(n);\n return new Uint8Array([\n tag | 26,\n (v >>> 24) & 0xff,\n (v >>> 16) & 0xff,\n (v >>> 8) & 0xff,\n v & 0xff,\n ]);\n }\n // 8-byte BE for u64 range\n const out = new Uint8Array(9);\n out[0] = tag | 27;\n for (let i = 7; i >= 0; i--) {\n out[1 + i] = Number(n >> BigInt((7 - i) * 8)) & 0xff;\n }\n return out;\n}\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n const total = parts.reduce((s, p) => s + p.length, 0);\n const out = new Uint8Array(total);\n let offset = 0;\n for (const p of parts) {\n out.set(p, offset);\n offset += p.length;\n }\n return out;\n}\n\n/**\n * Encode a `Vec<u8>` / `&[u8]` the way ciborium does by default — as a\n * CBOR array of u8 (major type 4), one element per byte.\n *\n * Each byte becomes a CBOR unsigned integer (major type 0): bytes\n * < 24 are encoded as single bytes, bytes 24..255 as `0x18 XX`.\n */\nfunction encodeBytesAsArrayOfU8(bytes: Uint8Array): Uint8Array {\n const header = cborHead(4, bytes.length);\n const items: Uint8Array[] = [header];\n for (const b of bytes) {\n items.push(cborHead(0, b));\n }\n return concat(...items);\n}\n\n/**\n * Encode the server-identity payload the Rust side signs:\n *\n * ciborium::into_writer(\n * &(SERVER_IDENTITY_DOMAIN, ephemeral_pubkey.serialize().to_vec(), expires_at),\n * buf\n * )\n *\n * Output bytes are byte-for-byte identical to the Rust reference,\n * pinned by the golden vector in the corresponding test file.\n *\n * @internal Exposed only for the golden-vector test that pins this\n * encoding against ciborium's output. Production callers reach this\n * via `verifyServerIdentity` from `./serverIdentity`.\n *\n * @param domain - Must be `\"btc-auth.server-identity.v1\"` (27 bytes)\n * — the constant from btc-vault's `server_identity.rs`.\n * @param ephemeralPubkeyCompressed - 33-byte SEC1-compressed pubkey.\n * @param expiresAt - Unix timestamp (seconds). Must be a safe integer.\n */\nexport function encodeServerIdentityPayload(\n domain: Uint8Array,\n ephemeralPubkeyCompressed: Uint8Array,\n expiresAt: number,\n): Uint8Array {\n if (!Number.isSafeInteger(expiresAt) || expiresAt < 0) {\n throw new Error(\n `encodeServerIdentityPayload: expires_at must be a non-negative safe integer, got ${expiresAt}`,\n );\n }\n const arrayHeader = cborHead(4, 3); // 3-tuple encoded as array of 3\n const domainBytes = encodeBytesAsArrayOfU8(domain);\n const pubkeyBytes = encodeBytesAsArrayOfU8(ephemeralPubkeyCompressed);\n const expiresAtBytes = cborHead(0, expiresAt);\n return concat(arrayHeader, domainBytes, pubkeyBytes, expiresAtBytes);\n}\n","/**\n * Server-identity verification for the vault provider's\n * `auth_createDepositorToken` response.\n *\n * The VP returns a `ServerIdentityResponse` bundled with every issued\n * token:\n *\n * - `server_pubkey`: VP's persistent x-only pubkey (HEX, 32B)\n * - `ephemeral_pubkey`: VP's ephemeral token-signing key (HEX, 33B compressed)\n * - `expires_at`: Unix timestamp when the ephemeral key expires\n * - `signature`: BIP-322 signature by the persistent key over\n * `(SERVER_IDENTITY_DOMAIN, ephemeral_pubkey, expires_at)`\n *\n * The FE pins `server_pubkey` against the on-chain `VaultProvider.btcPubKey`\n * it reads from the registry contract. A mismatch rejects the token.\n *\n * @module tbv/core/clients/vault-provider/auth/serverIdentity\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\n\nimport {\n SCHNORR_SIG_HEX_LEN,\n stripHexPrefix,\n} from \"../../../primitives/utils/bitcoin\";\nimport {\n COMPRESSED_PUBKEY_HEX_LEN,\n HEX_RE,\n X_ONLY_PUBKEY_HEX_LEN,\n} from \"../../../utils/validation\";\n\nimport { verifyBip322Simple } from \"./bip322Verify\";\nimport { encodeServerIdentityPayload } from \"./cbor\";\n\n/**\n * Byte-string domain the btc-vault Rust reference passes as the first\n * element of the CBOR tuple signed over for server-identity proofs.\n * Must match `SERVER_IDENTITY_DOMAIN` in\n * `btc-vault/crates/btc-auth/src/server_identity.rs`.\n */\nconst SERVER_IDENTITY_DOMAIN = new TextEncoder().encode(\n \"btc-auth.server-identity.v1\",\n);\n\n/**\n * Cap on `proof.expires_at - now`. Bounds how long a leaked VP\n * ephemeral key stays usable; the bearer token's own TTL does not\n * (different trust boundary). 2h = Rust ref VP's 1h rotation × 2 for\n * clock skew. Override per call via `maxLifetimeSecs`.\n */\nconst DEFAULT_MAX_PROOF_LIFETIME_SECS = 2 * 3600;\n\n/**\n * Wire representation from btc-vault's `ServerIdentityResponse`.\n */\nexport interface ServerIdentityResponse {\n /** Hex-encoded x-only (32-byte) persistent server pubkey. */\n server_pubkey: string;\n /** Hex-encoded compressed (33-byte) ephemeral token-signing pubkey. */\n ephemeral_pubkey: string;\n /** Unix timestamp at which the ephemeral key expires. */\n expires_at: number;\n /** Hex-encoded 64-byte BIP-322 Schnorr signature. */\n signature: string;\n}\n\nexport interface VerifyServerIdentityInput {\n /** The proof returned by `auth_createDepositorToken`. */\n proof: ServerIdentityResponse;\n /**\n * The x-only persistent server pubkey the FE expects (sourced from\n * the on-chain `VaultProvider.btcPubKey` via the vault registry\n * reader). 64-char lowercase hex, no `0x` prefix.\n */\n pinnedServerPubkey: string;\n /** Current Unix timestamp in seconds. Injected for testability. */\n now: number;\n /** Cap on `proof.expires_at - now` (seconds). Defaults to {@link DEFAULT_MAX_PROOF_LIFETIME_SECS}. */\n maxLifetimeSecs?: number;\n}\n\nexport class ServerIdentityError extends Error {\n constructor(\n message: string,\n public readonly reason:\n | \"pinned_pubkey_mismatch\"\n | \"expired\"\n | \"expires_too_far\"\n | \"invalid_expires_at\"\n | \"invalid_max_lifetime\"\n | \"invalid_pubkey_encoding\"\n | \"invalid_ephemeral_pubkey\"\n | \"invalid_signature_encoding\"\n | \"signature_verification_failed\",\n ) {\n super(message);\n this.name = \"ServerIdentityError\";\n }\n}\n\n/** Parse a lowercase-hex string to bytes. Expects even length, already validated. */\nfunction hexToBytes(hex: string): Uint8Array {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < out.length; i++) {\n out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\n/**\n * Verify a server identity proof against a pinned server pubkey.\n *\n * Checks:\n * 1. `server_pubkey` matches the pin.\n * 2. `now < expires_at <= now + maxLifetimeSecs` (with integer guards).\n * 3. `ephemeral_pubkey` is a well-formed 33-byte compressed pubkey.\n * 4. `signature` is a well-formed 64-byte Schnorr hex string.\n * 5. The BIP-322 Schnorr signature cryptographically verifies\n * against `server_pubkey` over the CBOR-encoded tuple\n * `(SERVER_IDENTITY_DOMAIN, ephemeral_pubkey, expires_at)`.\n *\n * Step 5 is what actually binds the ephemeral key to the persistent\n * pubkey — without it, a TLS-MITM attacker who reads the pinned\n * pubkey from the on-chain registry could substitute an arbitrary\n * ephemeral pubkey paired with any lexically-valid signature.\n *\n * @throws ServerIdentityError on any validation failure.\n */\nexport function verifyServerIdentity(input: VerifyServerIdentityInput): void {\n const { proof, pinnedServerPubkey, now } = input;\n const maxLifetimeSecs =\n input.maxLifetimeSecs ?? DEFAULT_MAX_PROOF_LIFETIME_SECS;\n\n const pinned = stripHexPrefix(pinnedServerPubkey).toLowerCase();\n if (pinned.length !== X_ONLY_PUBKEY_HEX_LEN || !HEX_RE.test(pinned)) {\n throw new ServerIdentityError(\n `pinnedServerPubkey must be 32-byte hex; got ${pinned.length} chars`,\n \"invalid_pubkey_encoding\",\n );\n }\n\n const actual = stripHexPrefix(proof.server_pubkey).toLowerCase();\n if (actual.length !== X_ONLY_PUBKEY_HEX_LEN || !HEX_RE.test(actual)) {\n throw new ServerIdentityError(\n `server_pubkey must be 32-byte hex; got ${actual.length} chars`,\n \"invalid_pubkey_encoding\",\n );\n }\n\n if (actual !== pinned) {\n throw new ServerIdentityError(\n `server_pubkey does not match pinned value: expected ${pinned}, got ${actual}`,\n \"pinned_pubkey_mismatch\",\n );\n }\n\n // Validate both sides of the comparison are well-formed integers\n // BEFORE comparing — untrusted JSON-RPC input can supply\n // undefined/NaN/string values for `expires_at`, and relational\n // comparisons with those silently evaluate to `false` (accepting the\n // proof). Caller's `now` is injected but we still sanity-check it.\n // Garbage data and \"valid but past\" both render the proof unusable\n // but mean different things to a caller — keep the reasons distinct.\n if (!Number.isSafeInteger(proof.expires_at)) {\n throw new ServerIdentityError(\n `expires_at must be a finite integer; got ${JSON.stringify(proof.expires_at)}`,\n \"invalid_expires_at\",\n );\n }\n if (!Number.isSafeInteger(now)) {\n throw new ServerIdentityError(\n `now must be a finite integer; got ${JSON.stringify(now)}`,\n \"invalid_expires_at\",\n );\n }\n if (proof.expires_at <= now) {\n throw new ServerIdentityError(\n `server identity proof expired at ${proof.expires_at}, now ${now}`,\n \"expired\",\n );\n }\n if (!Number.isSafeInteger(maxLifetimeSecs) || maxLifetimeSecs <= 0) {\n throw new ServerIdentityError(\n `maxLifetimeSecs must be a positive safe integer; got ${JSON.stringify(maxLifetimeSecs)}`,\n \"invalid_max_lifetime\",\n );\n }\n if (proof.expires_at - now > maxLifetimeSecs) {\n throw new ServerIdentityError(\n `server identity proof expires too far in the future: ` +\n `expires_at=${proof.expires_at}, now=${now}, max lifetime=${maxLifetimeSecs}s`,\n \"expires_too_far\",\n );\n }\n\n const eph = stripHexPrefix(proof.ephemeral_pubkey).toLowerCase();\n if (eph.length !== COMPRESSED_PUBKEY_HEX_LEN || !HEX_RE.test(eph)) {\n throw new ServerIdentityError(\n `ephemeral_pubkey must be 33-byte compressed hex; got ${eph.length} chars`,\n \"invalid_ephemeral_pubkey\",\n );\n }\n const prefix = eph.slice(0, 2);\n if (prefix !== \"02\" && prefix !== \"03\") {\n throw new ServerIdentityError(\n `ephemeral_pubkey must be compressed (prefix 02/03); got ${prefix}`,\n \"invalid_ephemeral_pubkey\",\n );\n }\n // Curve validation. The BIP-322 signature attests to the byte string\n // of `ephemeral_pubkey` only, not to its curve validity. Without\n // this check, a server could sign a structurally-valid byte string\n // that doesn't decode to a secp256k1 point — passing verification\n // here and surfacing as an obscure crypto error later when the\n // depositor tries to use the key. Reject up front.\n const ephBytes = hexToBytes(eph);\n if (!ecc.isPoint(ephBytes)) {\n throw new ServerIdentityError(\n \"ephemeral_pubkey is not a valid secp256k1 point\",\n \"invalid_ephemeral_pubkey\",\n );\n }\n\n const sig = stripHexPrefix(proof.signature).toLowerCase();\n if (sig.length !== SCHNORR_SIG_HEX_LEN || !HEX_RE.test(sig)) {\n throw new ServerIdentityError(\n `signature must be 64-byte Schnorr hex; got ${sig.length} chars`,\n \"invalid_signature_encoding\",\n );\n }\n\n // Cryptographic verification of the BIP-322 signature over the\n // CBOR-encoded payload. Without this, the ephemeral-key binding is\n // unenforced and a TLS-MITM could substitute a fake ephemeral key\n // alongside the real (publicly-readable) pinned pubkey.\n const payload = encodeServerIdentityPayload(\n SERVER_IDENTITY_DOMAIN,\n hexToBytes(eph),\n proof.expires_at,\n );\n const verified = verifyBip322Simple(\n payload,\n hexToBytes(actual),\n hexToBytes(sig),\n );\n if (!verified) {\n throw new ServerIdentityError(\n \"BIP-322 signature verification failed — ephemeral key is not attested by pinned server pubkey\",\n \"signature_verification_failed\",\n );\n }\n}\n","/**\n * VP RPC methods that require `Authorization: Bearer <token>`.\n * Protocol invariant — must be kept in sync with the VP server.\n *\n * Split into two sets by the CWT subject the VP demands:\n *\n * - {@link AUTH_GATED_METHODS} — bearer minted by\n * `auth_createDepositorToken` (Subject::VaultdJsonRpc). These run\n * through the proxy's plain JSON-RPC forward path.\n * - {@link GRPC_AUTH_GATED_METHODS} — bearer minted by\n * `auth_createDepositorTokenGrpc` (Subject::VaultdGrpc). The proxy\n * translates these into gRPC calls to vaultd's daemon gRPC server,\n * so a JSON-RPC-subject token would be rejected by\n * `GrpcAuthInterceptor`.\n *\n * @stability frozen\n *\n * @module tbv/core/clients/vault-provider/auth/gatedMethods\n */\n\nexport const AUTH_GATED_METHODS: ReadonlySet<string> = new Set([\n \"vaultProvider_submitDepositorWotsKey\",\n \"vaultProvider_submitDepositorPresignatures\",\n \"vaultProvider_requestDepositorPresignTransactions\",\n]);\n\nexport const GRPC_AUTH_GATED_METHODS: ReadonlySet<string> = new Set([\n \"vaultProvider_requestDepositorClaimerArtifacts\",\n]);\n","/**\n * Shared internals for the unauthenticated token-issuing JSON-RPC\n * client. The \"inner\" client is dedicated to `auth_createDepositorToken`\n * — it MUST NOT carry a `tokenProvider`, else the JSON-RPC header\n * builder would recurse into token acquisition.\n *\n * @module tbv/core/clients/vault-provider/auth/innerTokenClient\n */\n\nimport { JsonRpcClient } from \"../json-rpc-client\";\n\nconst TOKEN_RPC_TIMEOUT_MS = 60_000;\n\nexport const TOKEN_ISSUE_METHOD = \"auth_createDepositorToken\";\n/**\n * gRPC-subject sibling of {@link TOKEN_ISSUE_METHOD}. The proxy bridges\n * this call to vaultd's `VaultProviderDepositorAuthService.CreateDepositorToken`\n * so the resulting CWT is bound to `Subject::VaultdGrpc` — required to\n * pass vaultd's `GrpcAuthInterceptor` on methods the proxy translates to\n * gRPC (currently just the artifact stream).\n */\nexport const GRPC_TOKEN_ISSUE_METHOD = \"auth_createDepositorTokenGrpc\";\n\nexport function buildInnerTokenClient(\n baseUrl: string,\n headers?: Record<string, string>,\n): JsonRpcClient {\n return new JsonRpcClient({\n baseUrl,\n timeout: TOKEN_RPC_TIMEOUT_MS,\n headers,\n retryableFor: (method) =>\n method === TOKEN_ISSUE_METHOD || method === GRPC_TOKEN_ISSUE_METHOD,\n });\n}\n","/**\n * Minimal CBOR decoder — the read-side counterpart to {@link ./cbor}.\n *\n * Decodes only the subset needed to verify a vault-provider CWT bearer\n * token (RFC 8392) wrapped in a COSE Sign1 envelope (RFC 8152): tagged\n * values, definite-length arrays and maps, byte/text strings, and\n * unsigned/negative integers. Indefinite-length items, floats, and\n * big-number tags are intentionally rejected — the issuer\n * (btc-vault's `coset`/`ciborium` stack) never emits them for this\n * shape, so accepting them would only widen the parser's attack\n * surface.\n *\n * The decoder is a cursor over a single buffer. {@link CborReader.pos}\n * is public so callers can slice the exact encoded byte range of an\n * item (head + content) — required to reconstruct the COSE\n * `Sig_structure` byte-for-byte from the token's own protected-header\n * and payload byte strings.\n *\n * @module tbv/core/clients/vault-provider/auth/cborDecode\n */\n\n/** CBOR major types (the high 3 bits of the initial byte). */\nconst MAJOR_UNSIGNED_INT = 0;\nconst MAJOR_NEGATIVE_INT = 1;\nconst MAJOR_BYTE_STRING = 2;\nconst MAJOR_TEXT_STRING = 3;\nconst MAJOR_ARRAY = 4;\nconst MAJOR_MAP = 5;\nconst MAJOR_TAG = 6;\nconst MAJOR_SIMPLE = 7;\n\n/**\n * Smallest additional-info value that introduces a multi-byte argument\n * (24 ⇒ 1 byte, 25 ⇒ 2, 26 ⇒ 4, 27 ⇒ 8 — i.e. `1 << (info - 24)`).\n */\nconst ARG_IN_NEXT_1_BYTE = 24;\n/** Additional-info ≥ this (28..31) is reserved/indefinite — unsupported. */\nconst ARG_RESERVED_MIN = 28;\n\n/** Major-7 simple values we accept. */\nconst SIMPLE_FALSE = 20;\nconst SIMPLE_TRUE = 21;\nconst SIMPLE_NULL = 22;\n\n/**\n * Maximum CBOR nesting depth. Mirrors the issuer's recursion cap (256 in\n * btc-vault's `ciborium` stack). The COSE protected header is decoded\n * *before* the signature is verified, so without this bound a\n * malicious/MITM'd VP could send a deeply-nested blob and crash token\n * acquisition with an uncatchable stack overflow. Far below the JS call\n * stack limit, so it converts that DoS into a catchable decode error.\n */\nconst MAX_NESTING_DEPTH = 256;\n\n/** A decoded CBOR data item. Maps preserve key insertion order. */\nexport type CborValue =\n | number\n | bigint\n | string\n | Uint8Array\n | boolean\n | null\n | CborValue[]\n | Map<CborValue, CborValue>\n | CborTagged;\n\n/** A CBOR tagged value (major type 6). */\nexport interface CborTagged {\n tag: number;\n value: CborValue;\n}\n\n/** Parsed initial-byte header: major type plus its decoded argument. */\nexport interface CborHead {\n major: number;\n /** The header argument (length, value, tag number, …) as a number. */\n arg: number;\n}\n\nexport class CborDecodeError extends Error {\n constructor(message: string) {\n super(`CBOR decode: ${message}`);\n this.name = \"CborDecodeError\";\n }\n}\n\n/**\n * Cursor-based reader over a CBOR buffer. Not reusable across buffers —\n * construct one per decode.\n */\nexport class CborReader {\n readonly buf: Uint8Array;\n /** Current read offset. Public so callers can slice encoded sub-ranges. */\n pos = 0;\n\n constructor(buf: Uint8Array) {\n this.buf = buf;\n }\n\n private nextByte(): number {\n if (this.pos >= this.buf.length) {\n throw new CborDecodeError(\"unexpected end of input\");\n }\n return this.buf[this.pos++];\n }\n\n /**\n * Read an initial byte and its argument. Rejects indefinite-length\n * and reserved additional-info encodings. Arguments wider than\n * {@link Number.MAX_SAFE_INTEGER} are rejected — none of the token's\n * lengths, tags, or timestamps approach that bound.\n */\n readHead(): CborHead {\n const initial = this.nextByte();\n const major = initial >> 5;\n const info = initial & 0x1f;\n\n if (info < ARG_IN_NEXT_1_BYTE) {\n return { major, arg: info };\n }\n if (info >= ARG_RESERVED_MIN) {\n throw new CborDecodeError(\n `unsupported additional info ${info} (indefinite-length or reserved)`,\n );\n }\n\n const byteCount = 1 << (info - ARG_IN_NEXT_1_BYTE);\n\n let value = 0n;\n for (let i = 0; i < byteCount; i++) {\n value = (value << 8n) | BigInt(this.nextByte());\n }\n if (value > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new CborDecodeError(`argument ${value} exceeds safe integer range`);\n }\n return { major, arg: Number(value) };\n }\n\n /** Read `length` raw bytes as a sub-array view into the backing buffer. */\n private readBytes(length: number): Uint8Array {\n if (this.pos + length > this.buf.length) {\n throw new CborDecodeError(\"length overruns end of input\");\n }\n const slice = this.buf.subarray(this.pos, this.pos + length);\n this.pos += length;\n return slice;\n }\n\n /**\n * Read a byte string (major type 2), returning its content bytes.\n * Throws if the next item is not a byte string.\n */\n readByteString(): Uint8Array {\n const head = this.readHead();\n if (head.major !== MAJOR_BYTE_STRING) {\n throw new CborDecodeError(\n `expected byte string (major ${MAJOR_BYTE_STRING}), got major ${head.major}`,\n );\n }\n return this.readBytes(head.arg);\n }\n\n /**\n * Read the next complete data item as a decoded {@link CborValue}.\n *\n * `depth` tracks the current nesting level so a deeply-nested blob is\n * rejected with a {@link CborDecodeError} rather than overflowing the\n * native call stack (see {@link MAX_NESTING_DEPTH}).\n */\n readValue(depth = 0): CborValue {\n if (depth > MAX_NESTING_DEPTH) {\n throw new CborDecodeError(\n `nesting exceeds maximum depth ${MAX_NESTING_DEPTH}`,\n );\n }\n const head = this.readHead();\n switch (head.major) {\n case MAJOR_UNSIGNED_INT:\n return head.arg;\n case MAJOR_NEGATIVE_INT:\n // RFC 8949 §3.1: the encoded argument n represents -1 - n.\n return -1 - head.arg;\n case MAJOR_BYTE_STRING:\n return this.readBytes(head.arg);\n case MAJOR_TEXT_STRING:\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(\n this.readBytes(head.arg),\n );\n case MAJOR_ARRAY: {\n const items: CborValue[] = [];\n for (let i = 0; i < head.arg; i++) {\n items.push(this.readValue(depth + 1));\n }\n return items;\n }\n case MAJOR_MAP: {\n const map = new Map<CborValue, CborValue>();\n for (let i = 0; i < head.arg; i++) {\n const key = this.readValue(depth + 1);\n const value = this.readValue(depth + 1);\n map.set(key, value);\n }\n return map;\n }\n case MAJOR_TAG:\n return { tag: head.arg, value: this.readValue(depth + 1) };\n case MAJOR_SIMPLE:\n if (head.arg === SIMPLE_FALSE) return false;\n if (head.arg === SIMPLE_TRUE) return true;\n if (head.arg === SIMPLE_NULL) return null;\n throw new CborDecodeError(\n `unsupported simple/float value ${head.arg}`,\n );\n default:\n throw new CborDecodeError(`unsupported major type ${head.major}`);\n }\n }\n}\n\n/**\n * Decode a single CBOR item from `bytes`, rejecting any trailing bytes.\n *\n * Used to parse the COSE protected header and CWT claims set — both are\n * exactly one top-level item, so a valid prefix followed by extra bytes\n * is a malformed structure, not a benign tail. Strict consumption keeps\n * the parser from silently accepting a token a stricter CWT/COSE\n * consumer would interpret differently.\n */\nexport function decodeCbor(bytes: Uint8Array): CborValue {\n const reader = new CborReader(bytes);\n const value = reader.readValue();\n if (reader.pos !== bytes.length) {\n throw new CborDecodeError(\"trailing bytes after top-level item\");\n }\n return value;\n}\n","/**\n * Verify a vault-provider CWT bearer (RFC 8392 / COSE Sign1, ES256K): checks the\n * signature against the VP's attested ephemeral key (see {@link ./serverIdentity})\n * and binds `iss`/`sub`/`aud` to the pinned VP, subject, and depositor. TS port\n * of btc-vault `client.rs::validate_token_with_public_key_at_time`.\n *\n * Divergence from that reference: the FE does NOT clock-gate `nbf`/`iat`. The VP\n * server is the temporal authority and re-checks `nbf`/`exp` on every gated call;\n * re-checking `nbf` against the browser clock only bricked freshly minted tokens\n * on benign skew. `exp` (wide window) and the structural `iat <= exp` are kept.\n *\n * @module tbv/core/clients/vault-provider/auth/verifyDepositorCwt\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport {\n hexToUint8Array,\n stripHexPrefix,\n} from \"../../../primitives/utils/bitcoin\";\nimport {\n COMPRESSED_PUBKEY_HEX_LEN,\n HEX_RE,\n X_ONLY_PUBKEY_HEX_LEN,\n} from \"../../../utils/validation\";\n\nimport { CborReader, decodeCbor } from \"./cborDecode\";\n\n/** CWT `sub` value for JSON-RPC-subject tokens (`auth_createDepositorToken`). */\nexport const CWT_SUBJECT_JSONRPC = \"vaultd-jsonrpc\";\n/** CWT `sub` value for gRPC-subject tokens (`auth_createDepositorTokenGrpc`). */\nexport const CWT_SUBJECT_GRPC = \"vaultd-grpc\";\n\n/** CBOR tag wrapping a COSE_Sign1 structure (RFC 8152 §2). */\nconst COSE_SIGN1_TAG = 18;\n/** A COSE_Sign1 is a 4-element array: [protected, unprotected, payload, signature]. */\nconst COSE_SIGN1_ARRAY_LEN = 4;\n/** COSE algorithm id for ES256K (ECDSA w/ secp256k1 + SHA-256), RFC 8812. */\nconst COSE_ALG_ES256K = -47;\n/** COSE header label for the algorithm (RFC 8152 §3.1). */\nconst COSE_HEADER_LABEL_ALG = 1;\n/** ECDSA signature length in COSE compact (r‖s) form. */\nconst ECDSA_COMPACT_SIG_LEN = 64;\n\n/** CBOR major-type 4 (array) high bits, for the Sig_structure header. */\nconst CBOR_ARRAY_HEAD = 0x80;\n/** CBOR major-type 3 (text string) high bits, for the context string head. */\nconst CBOR_TEXT_STRING_HEAD = 0x60;\n/** CBOR encoding of an empty byte string (major type 2, length 0). */\nconst CBOR_EMPTY_BYTE_STRING = 0x40;\n\n/** CWT registered claim keys (RFC 8392 §4 / IANA CWT registry). */\nconst CWT_CLAIM_ISS = 1;\nconst CWT_CLAIM_SUB = 2;\nconst CWT_CLAIM_AUD = 3;\nconst CWT_CLAIM_EXP = 4;\nconst CWT_CLAIM_NBF = 5;\nconst CWT_CLAIM_IAT = 6;\nconst CWT_CLAIM_CTI = 7;\n\n/**\n * Context string for a COSE_Sign1 Sig_structure (RFC 8152 §4.4). 10\n * bytes, so it encodes with a single-byte CBOR text-string head.\n */\nconst SIG_STRUCTURE_CONTEXT = new TextEncoder().encode(\"Signature1\");\n\nexport type CwtVerificationReason =\n | \"invalid_input\"\n | \"invalid_token_structure\"\n | \"unexpected_algorithm\"\n | \"signature_verification_failed\"\n | \"invalid_claims\"\n | \"issuer_mismatch\"\n | \"subject_mismatch\"\n | \"audience_mismatch\"\n | \"token_expired\"\n | \"expiry_mismatch\"\n | \"server_identity_expires_before_token\";\n\nexport class CwtVerificationError extends Error {\n constructor(\n message: string,\n public readonly reason: CwtVerificationReason,\n ) {\n super(message);\n this.name = \"CwtVerificationError\";\n }\n}\n\nexport interface VerifyDepositorCwtInput {\n /** Base64url (no padding) COSE Sign1 token from `auth_createDepositorToken`. */\n token: string;\n /**\n * VP ephemeral token-signing pubkey (33-byte compressed hex) from the\n * bundled `server_identity` proof — MUST already be verified by\n * {@link verifyServerIdentity} before being passed here.\n */\n ephemeralPubkeyHex: string;\n /** Pinned VP persistent x-only pubkey (on-chain). Asserted against the token `iss`. */\n expectedIssuerXOnlyPubkey: string;\n /** Expected `sub` — {@link CWT_SUBJECT_JSONRPC} or {@link CWT_SUBJECT_GRPC}. */\n expectedSubject: string;\n /** Depositor x-only pubkey. Asserted against the token `aud`. */\n expectedAudienceXOnlyPubkey: string;\n /** Outer wire `expires_at`. Must equal the token's `exp` exactly. */\n responseExpiresAt: number;\n /** `server_identity.expires_at`. Must be ≥ the token's `exp`. */\n serverIdentityExpiresAt: number;\n /** Current Unix time (seconds). Injected for testability. */\n now: number;\n}\n\nexport interface VerifiedCwtClaims {\n issuer: string;\n subject: string;\n audience: string;\n expiresAt: number;\n notBefore: number;\n issuedAt: number;\n}\n\n/**\n * Verify a depositor CWT and return its claims, or throw\n * {@link CwtVerificationError}.\n *\n * Steps (mirroring the Rust reference; see the divergence note above):\n * 1. Decode the COSE Sign1 envelope and assert the protected header\n * pins ES256K.\n * 2. Verify the ECDSA signature over the reconstructed Sig_structure\n * against the (already server-identity-verified) ephemeral key.\n * 3. Decode the CWT claims and assert `iss`/`sub`/`aud` bindings, the\n * structural `iat <= exp`, `exp` validity, `cti` presence, and the\n * outer-vs-inner expiry cross-checks. `nbf`/`iat` are intentionally not\n * clock-gated here (see the module note above).\n */\nexport function verifyDepositorCwt(\n input: VerifyDepositorCwtInput,\n): VerifiedCwtClaims {\n const expectedIssuer = normalizeXOnly(\n input.expectedIssuerXOnlyPubkey,\n \"expectedIssuerXOnlyPubkey\",\n );\n const expectedAudience = normalizeXOnly(\n input.expectedAudienceXOnlyPubkey,\n \"expectedAudienceXOnlyPubkey\",\n );\n const ephemeral = decodeCompressedPubkey(input.ephemeralPubkeyHex);\n\n const tokenBytes = base64UrlToBytes(input.token);\n\n // --- 1. COSE Sign1 structural decode -------------------------------\n // Capture the exact encoded byte ranges of the protected header and\n // payload so the Sig_structure can be rebuilt byte-for-byte from the\n // token's own bytes (any re-encoding risks a non-canonical mismatch).\n const reader = new CborReader(tokenBytes);\n const tag = reader.readHead();\n if (tag.major !== 6 || tag.arg !== COSE_SIGN1_TAG) {\n throw new CwtVerificationError(\n `token is not a COSE Sign1 tagged value (tag ${COSE_SIGN1_TAG})`,\n \"invalid_token_structure\",\n );\n }\n const array = reader.readHead();\n if (array.major !== 4 || array.arg !== COSE_SIGN1_ARRAY_LEN) {\n throw new CwtVerificationError(\n `COSE Sign1 must be a ${COSE_SIGN1_ARRAY_LEN}-element array`,\n \"invalid_token_structure\",\n );\n }\n\n const protectedStart = reader.pos;\n const protectedContent = reader.readByteString();\n const protectedBstr = tokenBytes.subarray(protectedStart, reader.pos);\n\n // Unprotected header map: present in the envelope but unused here.\n reader.readValue();\n\n const payloadStart = reader.pos;\n const payloadContent = reader.readByteString();\n const payloadBstr = tokenBytes.subarray(payloadStart, reader.pos);\n\n const signature = reader.readByteString();\n if (signature.length !== ECDSA_COMPACT_SIG_LEN) {\n throw new CwtVerificationError(\n `COSE signature must be ${ECDSA_COMPACT_SIG_LEN} bytes, got ${signature.length}`,\n \"invalid_token_structure\",\n );\n }\n // Reject anything after the COSE_Sign1 structure. The bearer we verify\n // must be the exact bytes attached to authenticated calls; a stricter\n // CWT/COSE consumer could interpret trailing bytes differently.\n if (reader.pos !== tokenBytes.length) {\n throw new CwtVerificationError(\n \"COSE Sign1 token has trailing bytes after the signature\",\n \"invalid_token_structure\",\n );\n }\n\n // --- 2a. Algorithm pin --------------------------------------------\n const alg = readProtectedAlgorithm(protectedContent);\n if (alg !== COSE_ALG_ES256K) {\n throw new CwtVerificationError(\n `unexpected COSE algorithm ${alg} (expected ES256K ${COSE_ALG_ES256K})`,\n \"unexpected_algorithm\",\n );\n }\n\n // --- 2b. Signature verification -----------------------------------\n const sigStructure = buildSigStructure(protectedBstr, payloadBstr);\n const digest = sha256(sigStructure);\n // strict = true enforces low-S, matching libsecp256k1's `verify_ecdsa`.\n if (!ecc.verify(digest, ephemeral, signature, true)) {\n throw new CwtVerificationError(\n \"COSE signature does not verify against the server's ephemeral key\",\n \"signature_verification_failed\",\n );\n }\n\n // --- 3. Claims -----------------------------------------------------\n const claims = decodeClaims(payloadContent);\n\n const audience = claims.audience.toLowerCase();\n if (audience.length !== X_ONLY_PUBKEY_HEX_LEN || !HEX_RE.test(audience)) {\n throw new CwtVerificationError(\n \"token `aud` is not a 32-byte x-only pubkey hex\",\n \"invalid_claims\",\n );\n }\n if (claims.issuedAt > claims.expiresAt) {\n throw new CwtVerificationError(\n `token iat (${claims.issuedAt}) is after exp (${claims.expiresAt})`,\n \"invalid_claims\",\n );\n }\n\n if (claims.issuer.toLowerCase() !== expectedIssuer) {\n throw new CwtVerificationError(\n `token issuer does not match pinned server pubkey: expected ${expectedIssuer}, got ${claims.issuer.toLowerCase()}`,\n \"issuer_mismatch\",\n );\n }\n if (claims.subject !== input.expectedSubject) {\n throw new CwtVerificationError(\n `token subject mismatch: expected ${input.expectedSubject}, got ${claims.subject}`,\n \"subject_mismatch\",\n );\n }\n if (audience !== expectedAudience) {\n throw new CwtVerificationError(\n `token audience does not match depositor pubkey: expected ${expectedAudience}, got ${audience}`,\n \"audience_mismatch\",\n );\n }\n // No nbf/iat clock-gate on purpose — the VP server is the temporal authority\n // (re-checks nbf/exp per call). See the module-level divergence note.\n if (claims.expiresAt <= input.now) {\n throw new CwtVerificationError(\n `token expired: exp ${claims.expiresAt} <= now ${input.now}`,\n \"token_expired\",\n );\n }\n if (input.responseExpiresAt !== claims.expiresAt) {\n throw new CwtVerificationError(\n `response expires_at (${input.responseExpiresAt}) does not equal token exp (${claims.expiresAt})`,\n \"expiry_mismatch\",\n );\n }\n if (input.serverIdentityExpiresAt < claims.expiresAt) {\n throw new CwtVerificationError(\n `server identity expires (${input.serverIdentityExpiresAt}) before token exp (${claims.expiresAt})`,\n \"server_identity_expires_before_token\",\n );\n }\n\n return {\n issuer: claims.issuer,\n subject: claims.subject,\n audience,\n expiresAt: claims.expiresAt,\n notBefore: claims.notBefore,\n issuedAt: claims.issuedAt,\n };\n}\n\n/** Read the algorithm label from the COSE protected-header byte string. */\nfunction readProtectedAlgorithm(protectedContent: Uint8Array): number {\n if (protectedContent.length === 0) {\n throw new CwtVerificationError(\n \"empty COSE protected header (no algorithm)\",\n \"unexpected_algorithm\",\n );\n }\n const header = decodeCbor(protectedContent);\n if (!(header instanceof Map)) {\n throw new CwtVerificationError(\n \"COSE protected header is not a map\",\n \"invalid_token_structure\",\n );\n }\n const alg = header.get(COSE_HEADER_LABEL_ALG);\n if (typeof alg !== \"number\") {\n throw new CwtVerificationError(\n \"COSE protected header missing integer algorithm label\",\n \"unexpected_algorithm\",\n );\n }\n return alg;\n}\n\n/**\n * Rebuild the COSE_Sign1 Sig_structure (RFC 8152 §4.4):\n *\n * [ \"Signature1\", body_protected (bstr), external_aad = h'' , payload (bstr) ]\n *\n * `body_protected` and `payload` are spliced verbatim from the token's\n * own encoded byte strings, so the result is byte-identical to what the\n * issuer signed regardless of CBOR canonicalization choices.\n */\nfunction buildSigStructure(\n protectedBstr: Uint8Array,\n payloadBstr: Uint8Array,\n): Uint8Array {\n return concatBytes(\n Uint8Array.of(CBOR_ARRAY_HEAD | COSE_SIGN1_ARRAY_LEN),\n Uint8Array.of(CBOR_TEXT_STRING_HEAD | SIG_STRUCTURE_CONTEXT.length),\n SIG_STRUCTURE_CONTEXT,\n protectedBstr,\n Uint8Array.of(CBOR_EMPTY_BYTE_STRING),\n payloadBstr,\n );\n}\n\ninterface DecodedClaims {\n issuer: string;\n subject: string;\n audience: string;\n expiresAt: number;\n notBefore: number;\n issuedAt: number;\n}\n\n/** Decode and type-check the CWT registered claims from the payload. */\nfunction decodeClaims(payloadContent: Uint8Array): DecodedClaims {\n const root = decodeCbor(payloadContent);\n if (!(root instanceof Map)) {\n throw new CwtVerificationError(\n \"CWT claims root is not a map\",\n \"invalid_claims\",\n );\n }\n const cti = requireBytes(root, CWT_CLAIM_CTI, \"cti\");\n if (cti.length === 0) {\n throw new CwtVerificationError(\"token cti is empty\", \"invalid_claims\");\n }\n return {\n issuer: requireString(root, CWT_CLAIM_ISS, \"iss\"),\n subject: requireString(root, CWT_CLAIM_SUB, \"sub\"),\n audience: requireString(root, CWT_CLAIM_AUD, \"aud\"),\n expiresAt: requireTimestamp(root, CWT_CLAIM_EXP, \"exp\"),\n notBefore: requireTimestamp(root, CWT_CLAIM_NBF, \"nbf\"),\n issuedAt: requireTimestamp(root, CWT_CLAIM_IAT, \"iat\"),\n };\n}\n\nfunction requireString(\n claims: Map<unknown, unknown>,\n key: number,\n name: string,\n): string {\n const value = claims.get(key);\n if (typeof value !== \"string\") {\n throw new CwtVerificationError(\n `token claim ${name} is missing or not a text string`,\n \"invalid_claims\",\n );\n }\n return value;\n}\n\nfunction requireBytes(\n claims: Map<unknown, unknown>,\n key: number,\n name: string,\n): Uint8Array {\n const value = claims.get(key);\n if (!(value instanceof Uint8Array)) {\n throw new CwtVerificationError(\n `token claim ${name} is missing or not a byte string`,\n \"invalid_claims\",\n );\n }\n return value;\n}\n\nfunction requireTimestamp(\n claims: Map<unknown, unknown>,\n key: number,\n name: string,\n): number {\n const value = claims.get(key);\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n throw new CwtVerificationError(\n `token claim ${name} is missing or not a non-negative integer timestamp`,\n \"invalid_claims\",\n );\n }\n return value;\n}\n\n/** Validate and normalize a 32-byte x-only pubkey to lowercase hex. */\nfunction normalizeXOnly(pubkey: string, label: string): string {\n const normalized = stripHexPrefix(pubkey).toLowerCase();\n if (normalized.length !== X_ONLY_PUBKEY_HEX_LEN || !HEX_RE.test(normalized)) {\n throw new CwtVerificationError(\n `${label} must be 32-byte x-only hex; got ${normalized.length} chars`,\n \"invalid_input\",\n );\n }\n return normalized;\n}\n\n/** Validate a 33-byte compressed pubkey hex and return its bytes. */\nfunction decodeCompressedPubkey(pubkeyHex: string): Uint8Array {\n const normalized = stripHexPrefix(pubkeyHex).toLowerCase();\n const prefix = normalized.slice(0, 2);\n if (\n normalized.length !== COMPRESSED_PUBKEY_HEX_LEN ||\n !HEX_RE.test(normalized) ||\n (prefix !== \"02\" && prefix !== \"03\")\n ) {\n throw new CwtVerificationError(\n \"ephemeralPubkeyHex must be 33-byte compressed pubkey hex (prefix 02/03)\",\n \"invalid_input\",\n );\n }\n return hexToUint8Array(normalized);\n}\n\nconst B64URL_LOOKUP = (() => {\n const table = new Int16Array(128).fill(-1);\n const alphabet =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\n for (let i = 0; i < alphabet.length; i++) {\n table[alphabet.charCodeAt(i)] = i;\n }\n return table;\n})();\n\n/** Decode a base64url (no-padding) string to bytes. */\nfunction base64UrlToBytes(input: string): Uint8Array {\n const len = input.length;\n const fullGroups = Math.floor(len / 4);\n const remainder = len % 4;\n if (remainder === 1) {\n throw new CwtVerificationError(\n \"invalid base64url length\",\n \"invalid_token_structure\",\n );\n }\n const outLen = fullGroups * 3 + (remainder === 0 ? 0 : remainder - 1);\n const out = new Uint8Array(outLen);\n\n const sextet = (charCode: number): number => {\n const value = charCode < 128 ? B64URL_LOOKUP[charCode] : -1;\n if (value < 0) {\n throw new CwtVerificationError(\n \"invalid base64url character\",\n \"invalid_token_structure\",\n );\n }\n return value;\n };\n\n let inPos = 0;\n let outPos = 0;\n for (let g = 0; g < fullGroups; g++) {\n const a = sextet(input.charCodeAt(inPos++));\n const b = sextet(input.charCodeAt(inPos++));\n const c = sextet(input.charCodeAt(inPos++));\n const d = sextet(input.charCodeAt(inPos++));\n out[outPos++] = (a << 2) | (b >> 4);\n out[outPos++] = ((b & 0x0f) << 4) | (c >> 2);\n out[outPos++] = ((c & 0x03) << 6) | d;\n }\n if (remainder === 2) {\n const a = sextet(input.charCodeAt(inPos++));\n const b = sextet(input.charCodeAt(inPos++));\n out[outPos++] = (a << 2) | (b >> 4);\n } else if (remainder === 3) {\n const a = sextet(input.charCodeAt(inPos++));\n const b = sextet(input.charCodeAt(inPos++));\n const c = sextet(input.charCodeAt(inPos++));\n out[outPos++] = (a << 2) | (b >> 4);\n out[outPos++] = ((b & 0x0f) << 4) | (c >> 2);\n }\n return out;\n}\n\nfunction concatBytes(...parts: Uint8Array[]): Uint8Array {\n const total = parts.reduce((sum, part) => sum + part.length, 0);\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n return out;\n}\n","/**\n * `VpTokenProvider` — caches CWT bearer tokens issued by the vault\n * provider's `auth_createDepositorToken` RPC, with lazy expiry check\n * and single-flight concurrent acquire.\n *\n * Usage:\n *\n * ```ts\n * const provider = new VpTokenProvider({\n * client,\n * peginTxid,\n * authAnchorHex,\n * pinnedServerPubkey,\n * authGatedMethods,\n * });\n * const bearer = await provider.getToken(method); // null if not gated\n * ```\n *\n * The provider implements the `BearerTokenProvider` interface expected\n * by `JsonRpcClient`. Plug directly:\n *\n * ```ts\n * const client = new JsonRpcClient({ ..., tokenProvider: provider });\n * ```\n *\n * @module tbv/core/clients/vault-provider/auth/tokenProvider\n */\n\nimport type { OnChainBtcPubkey } from \"../../eth/types\";\nimport type { BearerTokenProvider, JsonRpcClient } from \"../json-rpc-client\";\nimport {\n GRPC_TOKEN_ISSUE_METHOD,\n TOKEN_ISSUE_METHOD,\n} from \"./innerTokenClient\";\nimport {\n ServerIdentityError,\n type ServerIdentityResponse,\n verifyServerIdentity,\n} from \"./serverIdentity\";\nimport {\n CWT_SUBJECT_GRPC,\n CWT_SUBJECT_JSONRPC,\n CwtVerificationError,\n verifyDepositorCwt,\n} from \"./verifyDepositorCwt\";\n\n/**\n * Maximum reasonable `expires_at` value (seconds since epoch). Guards\n * against a bogus far-future timestamp that would lock the cache on a\n * bad token forever. Jan 1, 2100 in Unix seconds.\n */\nconst MAX_EXPIRES_AT_SECS = 4_102_444_800;\n\n/**\n * Default safety margin before `expires_at` — we treat a token as\n * expired this many seconds before its stated expiry so that in-flight\n * requests don't race the expiry boundary.\n */\nconst DEFAULT_REFRESH_SKEW_SECS = 30;\n\n/**\n * Wire response shape of `auth_createDepositorToken`.\n */\nexport interface CreateDepositorTokenResponse {\n /** Base64url-encoded COSE Sign1 CWT bearer token. */\n token: string;\n /** Unix timestamp at which the token expires. */\n expires_at: number;\n /** Server identity proof bundled with every token response. */\n server_identity: ServerIdentityResponse;\n}\n\nexport interface VpTokenProviderConfig {\n client: JsonRpcClient;\n /** Per-vault depositor-signed PegIn tx id. NOT shared across sibling vaults in a batch. */\n peginTxid: string;\n /** 64-char hex of the 32-byte OP_RETURN auth-anchor preimage. */\n authAnchorHex: string;\n /** Live JSON-RPC-subject VP pubkey from chain; branded so mirrors can't substitute it. */\n pinnedServerPubkey: OnChainBtcPubkey;\n /**\n * Pin for the gRPC-subject bootstrap. This must be the operation key at the\n * vault's frozen VP epoch: vaultd signs this subject with that key.\n */\n grpcPinnedServerPubkey: OnChainBtcPubkey;\n /**\n * Re-read the authoritative current operation key after a JSON-RPC-subject\n * identity mismatch. The provider retries at most once, and only when the\n * chain returns a key different from the stale pin.\n */\n refreshJsonRpcPinnedServerPubkey?: () => Promise<OnChainBtcPubkey>;\n /**\n * Depositor x-only pubkey (32-byte hex). Asserted against every\n * issued token's CWT `aud` claim so a token minted for a different\n * depositor — or mis-issued by a buggy/compromised VP — is rejected\n * before it can authenticate a mutation.\n */\n expectedAudienceXOnlyPubkey: string;\n /**\n * Methods that need a JSON-RPC-subject bearer (minted via\n * `auth_createDepositorToken`). Forwarded over plain HTTP JSON-RPC by\n * the proxy. `getToken` returns `null` for any method outside this and\n * {@link grpcGatedMethods}.\n */\n authGatedMethods: ReadonlySet<string>;\n /**\n * Methods that need a gRPC-subject bearer (minted via\n * `auth_createDepositorTokenGrpc`). The proxy translates these into\n * gRPC calls to vaultd; the JSON-RPC bearer is rejected with a\n * `Subject` mismatch.\n */\n grpcGatedMethods: ReadonlySet<string>;\n /** Default {@link DEFAULT_REFRESH_SKEW_SECS}. */\n refreshSkewSecs?: number;\n /** Clock source for testability. */\n now?: () => number;\n}\n\ninterface CachedToken {\n token: string;\n expiresAt: number;\n}\n\n/**\n * Acquire, cache, and refresh VP bearer tokens.\n *\n * Implements {@link BearerTokenProvider}. Safe to pass directly into\n * `JsonRpcClient` as `tokenProvider`.\n */\nexport class VpTokenProvider implements BearerTokenProvider {\n // Most identity-bearing fields remain readonly and are checked against\n // re-registration in the registry's `getOrCreate`. The JSON-RPC pin is the\n // one exception: RFC-006 explicitly permits it to move, but only to a value\n // re-read through the caller's authoritative chain resolver.\n private client: JsonRpcClient;\n private readonly peginTxid: string;\n private readonly authAnchorHex: string;\n private jsonRpcPinnedServerPubkey: OnChainBtcPubkey;\n private readonly grpcPinnedServerPubkey: OnChainBtcPubkey;\n private readonly refreshJsonRpcPinnedServerPubkey?: () => Promise<OnChainBtcPubkey>;\n private readonly expectedAudienceXOnlyPubkey: string;\n private readonly authGatedMethods: ReadonlySet<string>;\n private readonly grpcGatedMethods: ReadonlySet<string>;\n private readonly refreshSkewSecs: number;\n private readonly now: () => number;\n\n /** Cached JSON-RPC-subject bearer (auth_createDepositorToken). */\n private cachedJsonRpc: CachedToken | null = null;\n private inFlightJsonRpc: Promise<CachedToken> | null = null;\n /** Cached gRPC-subject bearer (auth_createDepositorTokenGrpc). */\n private cachedGrpc: CachedToken | null = null;\n private inFlightGrpc: Promise<CachedToken> | null = null;\n\n constructor(config: VpTokenProviderConfig) {\n this.client = config.client;\n this.peginTxid = config.peginTxid;\n this.authAnchorHex = config.authAnchorHex;\n this.jsonRpcPinnedServerPubkey = config.pinnedServerPubkey;\n this.grpcPinnedServerPubkey = config.grpcPinnedServerPubkey;\n this.refreshJsonRpcPinnedServerPubkey =\n config.refreshJsonRpcPinnedServerPubkey;\n this.expectedAudienceXOnlyPubkey = config.expectedAudienceXOnlyPubkey;\n this.authGatedMethods = config.authGatedMethods;\n this.grpcGatedMethods = config.grpcGatedMethods;\n this.refreshSkewSecs = config.refreshSkewSecs ?? DEFAULT_REFRESH_SKEW_SECS;\n this.now = config.now ?? (() => Math.floor(Date.now() / 1000));\n }\n\n /**\n * Return a bearer token for `method`, or `null` if `method` is not\n * auth-gated.\n *\n * Routes by subject: `authGatedMethods` → JSON-RPC bearer (issued via\n * `auth_createDepositorToken`); `grpcGatedMethods` → gRPC bearer\n * (`auth_createDepositorTokenGrpc`). Either path acquires lazily and\n * single-flights concurrent callers; the two cache slots are\n * independent.\n *\n * Both token-issuing methods are hard-exempted from the gate — if\n * either were ever included in the gated sets (caller misconfiguration)\n * the provider would recurse into `acquireSingleFlight` from inside the\n * JSON-RPC header builder before `inFlight` is assigned, defeating the\n * single-flight guard. Returning `null` here breaks that recursion\n * deterministically.\n */\n async getToken(method: string): Promise<string | null> {\n if (method === TOKEN_ISSUE_METHOD || method === GRPC_TOKEN_ISSUE_METHOD) {\n return null;\n }\n\n if (this.grpcGatedMethods.has(method)) {\n return this.getTokenForSubject(\"grpc\");\n }\n if (this.authGatedMethods.has(method)) {\n return this.getTokenForSubject(\"jsonrpc\");\n }\n return null;\n }\n\n /**\n * Drop both cached tokens. Next `getToken` call re-acquires the slot\n * that's actually needed. Called by `JsonRpcClient` on wire\n * `auth_expired` responses; the client doesn't tell us which subject\n * expired, so we evict both to stay correct under either.\n *\n * Worst case is one extra round-trip on the slot that was still fresh,\n * which is cheaper than carrying a `Subject` argument through\n * `BearerTokenProvider`.\n */\n invalidate(): void {\n this.cachedJsonRpc = null;\n this.cachedGrpc = null;\n // Do NOT clear `inFlight*` — a concurrent acquire is still valid;\n // the invalidator is saying \"the cached token is bad\", not \"any\n // in-flight acquire is bad\". The in-flight acquire will populate\n // a fresh `cached*` on completion.\n }\n\n private async getTokenForSubject(\n subject: \"jsonrpc\" | \"grpc\",\n ): Promise<string> {\n const cached = subject === \"grpc\" ? this.cachedGrpc : this.cachedJsonRpc;\n if (cached && this.now() + this.refreshSkewSecs < cached.expiresAt) {\n return cached.token;\n }\n const fresh = await this.acquireSingleFlight(subject);\n return fresh.token;\n }\n\n /**\n * Swap in a different transport for subsequent token-issuing calls.\n * Used by the registry when a later caller registers the same\n * `peginTxid` against a different `baseUrl` — the cached token\n * (bound to identity, not transport) stays valid, but future\n * refreshes hit the new URL. An in-flight acquire keeps using the\n * old client (it captured the reference); next call uses the new.\n */\n setClient(client: JsonRpcClient): void {\n this.client = client;\n }\n\n /** Current subject-specific pin, exposed for registry identity checks. */\n getPinnedServerPubkey(subject: \"jsonrpc\" | \"grpc\"): OnChainBtcPubkey {\n return subject === \"grpc\"\n ? this.grpcPinnedServerPubkey\n : this.jsonRpcPinnedServerPubkey;\n }\n\n private acquireSingleFlight(\n subject: \"jsonrpc\" | \"grpc\",\n ): Promise<CachedToken> {\n const existing =\n subject === \"grpc\" ? this.inFlightGrpc : this.inFlightJsonRpc;\n if (existing) return existing;\n\n const issueMethod =\n subject === \"grpc\" ? GRPC_TOKEN_ISSUE_METHOD : TOKEN_ISSUE_METHOD;\n\n const p = (async () => {\n try {\n const fresh = await this.acquireAndVerify(subject, issueMethod, true);\n if (subject === \"grpc\") {\n this.cachedGrpc = fresh;\n } else {\n this.cachedJsonRpc = fresh;\n }\n return fresh;\n } finally {\n if (subject === \"grpc\") {\n this.inFlightGrpc = null;\n } else {\n this.inFlightJsonRpc = null;\n }\n }\n })();\n\n if (subject === \"grpc\") {\n this.inFlightGrpc = p;\n } else {\n this.inFlightJsonRpc = p;\n }\n return p;\n }\n\n private async acquireAndVerify(\n subject: \"jsonrpc\" | \"grpc\",\n issueMethod: string,\n allowPinRefresh: boolean,\n ): Promise<CachedToken> {\n const response = await this.client.call<\n { pegin_txid: string; auth_anchor: string },\n CreateDepositorTokenResponse\n >(issueMethod, {\n pegin_txid: this.peginTxid,\n auth_anchor: this.authAnchorHex,\n });\n const pinnedServerPubkey = this.getPinnedServerPubkey(subject);\n\n try {\n verifyServerIdentity({\n proof: response.server_identity,\n pinnedServerPubkey,\n now: this.now(),\n });\n\n // Validate wire payload before caching so a malformed response\n // from a compromised VP or proxy can't poison the cache with\n // unusable values (non-string token, non-integer expiry, etc.).\n if (typeof response.token !== \"string\" || response.token.length === 0) {\n throw new Error(\n `VpTokenProvider: invalid token in acquire response (expected non-empty string, got ${typeof response.token})`,\n );\n }\n const now = this.now();\n if (\n !Number.isSafeInteger(response.expires_at) ||\n response.expires_at <= now ||\n response.expires_at > MAX_EXPIRES_AT_SECS\n ) {\n throw new Error(\n `VpTokenProvider: invalid expires_at in acquire response (got ${JSON.stringify(response.expires_at)}; must be a safe integer in (${now}, ${MAX_EXPIRES_AT_SECS}])`,\n );\n }\n\n // Cryptographically verify the token itself — not just the wire\n // envelope. The COSE Sign1 signature is checked against the\n // (server-identity-verified) ephemeral key, and the inner CWT\n // claims are bound to this depositor (`aud`), this VP (`iss`),\n // and this subject. Without this the bearer is an opaque blob the\n // FE would attach to mutations on the VP's word alone.\n verifyDepositorCwt({\n token: response.token,\n ephemeralPubkeyHex: response.server_identity.ephemeral_pubkey,\n expectedIssuerXOnlyPubkey: pinnedServerPubkey,\n expectedSubject:\n subject === \"grpc\" ? CWT_SUBJECT_GRPC : CWT_SUBJECT_JSONRPC,\n expectedAudienceXOnlyPubkey: this.expectedAudienceXOnlyPubkey,\n responseExpiresAt: response.expires_at,\n serverIdentityExpiresAt: response.server_identity.expires_at,\n now,\n });\n\n return {\n token: response.token,\n expiresAt: response.expires_at,\n };\n } catch (error) {\n if (\n allowPinRefresh &&\n subject === \"jsonrpc\" &&\n this.refreshJsonRpcPinnedServerPubkey &&\n isPinnedIdentityMismatch(error)\n ) {\n const refreshed = await this.refreshJsonRpcPinnedServerPubkey();\n if (refreshed !== this.jsonRpcPinnedServerPubkey) {\n this.jsonRpcPinnedServerPubkey = refreshed;\n return this.acquireAndVerify(subject, issueMethod, false);\n }\n }\n throw error;\n }\n }\n}\n\nfunction isPinnedIdentityMismatch(error: unknown): boolean {\n return (\n (error instanceof ServerIdentityError &&\n error.reason === \"pinned_pubkey_mismatch\") ||\n (error instanceof CwtVerificationError &&\n error.reason === \"issuer_mismatch\")\n );\n}\n","/**\n * In-memory registry of {@link VpTokenProvider} instances keyed by\n * the per-vault depositor-signed PegIn tx hash. Module-level\n * singleton, per-tab, never persisted.\n *\n * @module tbv/core/clients/vault-provider/auth/tokenRegistry\n */\n\nimport type { OnChainBtcPubkey } from \"../../eth/types\";\nimport type { JsonRpcClient } from \"../json-rpc-client\";\n\nimport { AUTH_GATED_METHODS, GRPC_AUTH_GATED_METHODS } from \"./gatedMethods\";\nimport { VpTokenProvider } from \"./tokenProvider\";\n\nexport interface VpTokenRegistryInput {\n client: JsonRpcClient;\n peginTxid: string;\n authAnchorHex: string;\n /** Stable provider identity used to prevent cross-provider cache reuse. */\n providerAddress: string;\n pinnedServerPubkey: OnChainBtcPubkey;\n /** Frozen-epoch issuer used only by the gRPC token subject. */\n grpcPinnedServerPubkey: OnChainBtcPubkey;\n /** Frozen VP epoch that selected `grpcPinnedServerPubkey`. */\n grpcKeyEpoch: bigint;\n /** Authoritative live-key resolver for bounded JSON-RPC pin recovery. */\n refreshJsonRpcPinnedServerPubkey?: () => Promise<OnChainBtcPubkey>;\n /** Depositor x-only pubkey (32-byte hex), asserted against each token's CWT `aud`. */\n expectedAudienceXOnlyPubkey: string;\n}\n\nexport interface VpTokenRegistryLookup {\n peginTxid: string;\n providerAddress: string;\n expectedAudienceXOnlyPubkey: string;\n}\n\ninterface RegistryEntry {\n provider: VpTokenProvider;\n authAnchorHex: string;\n providerAddress: string;\n grpcKeyEpoch: bigint;\n expectedAudienceXOnlyPubkey: string;\n}\n\nexport class VpTokenRegistry {\n private readonly entries = new Map<string, RegistryEntry>();\n\n /**\n * Return the cached `VpTokenProvider` for `peginTxid` if one exists\n * with matching anchor, provider, audience, and subject-specific issuer\n * bindings, otherwise construct and cache a fresh provider. A mismatch\n * throws — silent overwrite would mask derivation drift or cross-provider\n * cache reuse. A legitimate live JSON-RPC key rotation is handled inside\n * `VpTokenProvider` through its chain-backed refresh callback.\n */\n getOrCreate(input: VpTokenRegistryInput): VpTokenProvider {\n const existing = this.entries.get(input.peginTxid);\n if (existing) {\n if (existing.authAnchorHex !== input.authAnchorHex) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to authAnchorHex ${existing.authAnchorHex.slice(0, 8)}…; got ${input.authAnchorHex.slice(0, 8)}…`,\n );\n }\n // Case-insensitive, as in `peek`: callers prime with the indexer's\n // lowercase address or the contract's checksummed one.\n if (\n existing.providerAddress.toLowerCase() !==\n input.providerAddress.toLowerCase()\n ) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to providerAddress ${existing.providerAddress}; got ${input.providerAddress}`,\n );\n }\n if (\n existing.provider.getPinnedServerPubkey(\"jsonrpc\") !==\n input.pinnedServerPubkey\n ) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to JSON-RPC pinnedServerPubkey ${existing.provider.getPinnedServerPubkey(\"jsonrpc\").slice(0, 8)}…; got ${input.pinnedServerPubkey.slice(0, 8)}…`,\n );\n }\n if (\n existing.provider.getPinnedServerPubkey(\"grpc\") !==\n input.grpcPinnedServerPubkey\n ) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to gRPC pinnedServerPubkey ${existing.provider.getPinnedServerPubkey(\"grpc\").slice(0, 8)}…; got ${input.grpcPinnedServerPubkey.slice(0, 8)}…`,\n );\n }\n if (existing.grpcKeyEpoch !== input.grpcKeyEpoch) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to gRPC key epoch ${existing.grpcKeyEpoch.toString()}; got ${input.grpcKeyEpoch.toString()}`,\n );\n }\n if (\n existing.expectedAudienceXOnlyPubkey.toLowerCase() !==\n input.expectedAudienceXOnlyPubkey.toLowerCase()\n ) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to expectedAudienceXOnlyPubkey ${existing.expectedAudienceXOnlyPubkey.slice(0, 8)}…; got ${input.expectedAudienceXOnlyPubkey.slice(0, 8)}…`,\n );\n }\n // Refresh the inner transport on every reuse so a VP URL\n // change between calls doesn't leave the cached provider\n // pinned to a dead URL for token refresh.\n existing.provider.setClient(input.client);\n return existing.provider;\n }\n\n const provider = new VpTokenProvider({\n client: input.client,\n peginTxid: input.peginTxid,\n authAnchorHex: input.authAnchorHex,\n pinnedServerPubkey: input.pinnedServerPubkey,\n grpcPinnedServerPubkey: input.grpcPinnedServerPubkey,\n refreshJsonRpcPinnedServerPubkey: input.refreshJsonRpcPinnedServerPubkey,\n expectedAudienceXOnlyPubkey: input.expectedAudienceXOnlyPubkey,\n authGatedMethods: AUTH_GATED_METHODS,\n grpcGatedMethods: GRPC_AUTH_GATED_METHODS,\n });\n this.entries.set(input.peginTxid, {\n provider,\n authAnchorHex: input.authAnchorHex,\n providerAddress: input.providerAddress,\n grpcKeyEpoch: input.grpcKeyEpoch,\n expectedAudienceXOnlyPubkey: input.expectedAudienceXOnlyPubkey,\n });\n return provider;\n }\n\n /**\n * Return the cached provider only when its request-facing identity matches.\n * A missing entry is a normal cold-cache result; a binding mismatch throws\n * so callers cannot attach one provider's bearer to another provider or\n * depositor request.\n */\n peek(input: VpTokenRegistryLookup): VpTokenProvider | undefined {\n const existing = this.entries.get(input.peginTxid);\n if (!existing) return undefined;\n\n if (\n existing.providerAddress.toLowerCase() !==\n input.providerAddress.toLowerCase()\n ) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to providerAddress ${existing.providerAddress}; got ${input.providerAddress}`,\n );\n }\n if (\n existing.expectedAudienceXOnlyPubkey.toLowerCase() !==\n input.expectedAudienceXOnlyPubkey.toLowerCase()\n ) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to expectedAudienceXOnlyPubkey ${existing.expectedAudienceXOnlyPubkey.slice(0, 8)}…; got ${input.expectedAudienceXOnlyPubkey.slice(0, 8)}…`,\n );\n }\n\n return existing.provider;\n }\n\n /**\n * Evict the entry for `peginTxid`. Idempotent. Called on terminal\n * paths — activation success, user-cancel, or component unmount —\n * so `authAnchorHex` doesn't outlive the deposit session.\n */\n release(peginTxid: string): void {\n this.entries.delete(peginTxid);\n }\n\n /**\n * Wipe every cached entry. Test-only escape hatch — not exposed on\n * the public {@link VpTokenRegistryPublic} singleton type.\n *\n * @internal\n */\n clear(): void {\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\n/**\n * Public surface of the singleton — excludes the test-only `clear`\n * method.\n */\nexport interface VpTokenRegistryPublic {\n getOrCreate(input: VpTokenRegistryInput): VpTokenProvider;\n peek(input: VpTokenRegistryLookup): VpTokenProvider | undefined;\n release(peginTxid: string): void;\n readonly size: number;\n}\n\nexport const vpTokenRegistry: VpTokenRegistryPublic = new VpTokenRegistry();\n","/**\n * Build a {@link VaultProviderRpcClient} that auto-attaches CWT\n * bearer tokens on auth-gated methods. Caller pre-derives both the\n * `authAnchorHex` (from the wallet) and the `pinnedServerPubkey`\n * (from the on-chain registry) and hands them in — the SDK has no\n * notion of wallets here.\n *\n * @module tbv/core/clients/vault-provider/auth/createAuthenticatedVpClient\n */\n\nimport { processPublicKeyToXOnly } from \"../../../primitives/utils/bitcoin\";\nimport type { OnChainBtcPubkey } from \"../../eth/types\";\nimport {\n VaultProviderRpcClient,\n type VaultProviderRpcClientOptions,\n} from \"../api\";\n\nimport { buildInnerTokenClient } from \"./innerTokenClient\";\nimport { vpTokenRegistry } from \"./tokenRegistry\";\n\nexport interface AuthenticatedVpClientConfig {\n /** Base URL of the VP RPC endpoint (already proxied if applicable). */\n baseUrl: string;\n /** Per-vault depositor-signed PegIn tx id (registry cache key). */\n peginTxid: string;\n /** Already-derived 32-byte auth-anchor preimage (64-char hex, no `0x`). */\n authAnchorHex: string;\n /** Stable vault-provider address used to scope the registry entry. */\n providerAddress: string;\n /** On-chain VP pubkey, branded so it can only come from the registry reader. */\n pinnedServerPubkey: OnChainBtcPubkey;\n /** Frozen-epoch VP pubkey used by the gRPC-subject bootstrap. */\n grpcPinnedServerPubkey: OnChainBtcPubkey;\n /** Vault's frozen VP epoch, paired with `grpcPinnedServerPubkey`. */\n grpcKeyEpoch: bigint;\n /** Re-read the current operation key after a JSON-RPC identity mismatch. */\n refreshJsonRpcPinnedServerPubkey?: () => Promise<OnChainBtcPubkey>;\n /**\n * Depositor BTC pubkey (x-only or compressed hex). Normalized to\n * x-only and asserted against every issued token's CWT `aud` claim.\n */\n depositorBtcPubkey: string;\n /** Optional outer-client tunables (timeout, retries, headers, etc.). */\n options?: VaultProviderRpcClientOptions;\n}\n\nexport function createAuthenticatedVpClient(\n config: AuthenticatedVpClientConfig,\n): VaultProviderRpcClient {\n const innerTokenClient = buildInnerTokenClient(\n config.baseUrl,\n config.options?.headers,\n );\n\n const tokenProvider = vpTokenRegistry.getOrCreate({\n client: innerTokenClient,\n peginTxid: config.peginTxid,\n authAnchorHex: config.authAnchorHex,\n providerAddress: config.providerAddress,\n pinnedServerPubkey: config.pinnedServerPubkey,\n grpcPinnedServerPubkey: config.grpcPinnedServerPubkey,\n grpcKeyEpoch: config.grpcKeyEpoch,\n refreshJsonRpcPinnedServerPubkey: config.refreshJsonRpcPinnedServerPubkey,\n expectedAudienceXOnlyPubkey: processPublicKeyToXOnly(\n config.depositorBtcPubkey,\n ),\n });\n\n return new VaultProviderRpcClient(config.baseUrl, {\n ...config.options,\n tokenProvider,\n });\n}\n","/**\n * Pre-populate {@link vpTokenRegistry} when the caller already has\n * both the auth-anchor preimage and the on-chain VP pubkey. Seeds\n * the cache for a `peginTxid` so a later `createAuthenticatedVpClient`\n * call reuses the cached `VpTokenProvider` instead of rebuilding it.\n *\n * @module tbv/core/clients/vault-provider/auth/primeVpAuth\n */\n\nimport { processPublicKeyToXOnly } from \"../../../primitives/utils/bitcoin\";\nimport type { OnChainBtcPubkey } from \"../../eth/types\";\n\nimport { buildInnerTokenClient } from \"./innerTokenClient\";\nimport { vpTokenRegistry } from \"./tokenRegistry\";\n\nexport interface PrimeVpAuthInput {\n baseUrl: string;\n peginTxid: string;\n authAnchorHex: string;\n /** Stable vault-provider address used to scope the registry entry. */\n providerAddress: string;\n pinnedServerPubkey: OnChainBtcPubkey;\n /** Frozen-epoch VP pubkey used by the gRPC-subject bootstrap. */\n grpcPinnedServerPubkey: OnChainBtcPubkey;\n /** Vault's frozen VP epoch, paired with `grpcPinnedServerPubkey`. */\n grpcKeyEpoch: bigint;\n /** Re-read the current operation key after a JSON-RPC identity mismatch. */\n refreshJsonRpcPinnedServerPubkey?: () => Promise<OnChainBtcPubkey>;\n /**\n * Depositor BTC pubkey (x-only or compressed hex). Normalized to\n * x-only and asserted against every issued token's CWT `aud` claim.\n */\n depositorBtcPubkey: string;\n /** Optional headers forwarded to the inner token client (e.g. gateway auth). */\n headers?: Record<string, string>;\n}\n\nexport function primeVpTokenRegistry(input: PrimeVpAuthInput): void {\n vpTokenRegistry.getOrCreate({\n client: buildInnerTokenClient(input.baseUrl, input.headers),\n peginTxid: input.peginTxid,\n authAnchorHex: input.authAnchorHex,\n providerAddress: input.providerAddress,\n pinnedServerPubkey: input.pinnedServerPubkey,\n grpcPinnedServerPubkey: input.grpcPinnedServerPubkey,\n grpcKeyEpoch: input.grpcKeyEpoch,\n refreshJsonRpcPinnedServerPubkey: input.refreshJsonRpcPinnedServerPubkey,\n expectedAudienceXOnlyPubkey: processPublicKeyToXOnly(\n input.depositorBtcPubkey,\n ),\n });\n}\n"],"names":["cborHead","major","arg","tag","v","out","concat","parts","total","p","offset","encodeBytesAsArrayOfU8","bytes","items","b","encodeServerIdentityPayload","domain","ephemeralPubkeyCompressed","expiresAt","arrayHeader","domainBytes","pubkeyBytes","expiresAtBytes","SERVER_IDENTITY_DOMAIN","DEFAULT_MAX_PROOF_LIFETIME_SECS","ServerIdentityError","message","reason","hexToBytes","hex","i","verifyServerIdentity","input","proof","pinnedServerPubkey","now","maxLifetimeSecs","pinned","stripHexPrefix","X_ONLY_PUBKEY_HEX_LEN","HEX_RE","actual","eph","COMPRESSED_PUBKEY_HEX_LEN","prefix","ephBytes","ecc","sig","SCHNORR_SIG_HEX_LEN","payload","verifyBip322Simple","AUTH_GATED_METHODS","GRPC_AUTH_GATED_METHODS","TOKEN_RPC_TIMEOUT_MS","TOKEN_ISSUE_METHOD","GRPC_TOKEN_ISSUE_METHOD","buildInnerTokenClient","baseUrl","headers","JsonRpcClient","method","MAJOR_UNSIGNED_INT","MAJOR_NEGATIVE_INT","MAJOR_BYTE_STRING","MAJOR_TEXT_STRING","MAJOR_ARRAY","MAJOR_MAP","MAJOR_TAG","MAJOR_SIMPLE","ARG_IN_NEXT_1_BYTE","ARG_RESERVED_MIN","SIMPLE_FALSE","SIMPLE_TRUE","SIMPLE_NULL","MAX_NESTING_DEPTH","CborDecodeError","CborReader","buf","__publicField","initial","info","byteCount","value","length","slice","head","depth","map","key","decodeCbor","reader","CWT_SUBJECT_JSONRPC","CWT_SUBJECT_GRPC","COSE_SIGN1_TAG","COSE_SIGN1_ARRAY_LEN","COSE_ALG_ES256K","COSE_HEADER_LABEL_ALG","ECDSA_COMPACT_SIG_LEN","CBOR_ARRAY_HEAD","CBOR_TEXT_STRING_HEAD","CBOR_EMPTY_BYTE_STRING","CWT_CLAIM_ISS","CWT_CLAIM_SUB","CWT_CLAIM_AUD","CWT_CLAIM_EXP","CWT_CLAIM_NBF","CWT_CLAIM_IAT","CWT_CLAIM_CTI","SIG_STRUCTURE_CONTEXT","CwtVerificationError","verifyDepositorCwt","expectedIssuer","normalizeXOnly","expectedAudience","ephemeral","decodeCompressedPubkey","tokenBytes","base64UrlToBytes","array","protectedStart","protectedContent","protectedBstr","payloadStart","payloadContent","payloadBstr","signature","alg","readProtectedAlgorithm","sigStructure","buildSigStructure","digest","sha256","claims","decodeClaims","audience","header","concatBytes","root","requireBytes","requireString","requireTimestamp","name","pubkey","label","normalized","pubkeyHex","hexToUint8Array","B64URL_LOOKUP","table","alphabet","len","fullGroups","remainder","outLen","sextet","charCode","inPos","outPos","g","a","c","d","sum","part","MAX_EXPIRES_AT_SECS","DEFAULT_REFRESH_SKEW_SECS","VpTokenProvider","config","subject","cached","client","existing","issueMethod","fresh","allowPinRefresh","response","error","isPinnedIdentityMismatch","refreshed","VpTokenRegistry","provider","peginTxid","vpTokenRegistry","createAuthenticatedVpClient","innerTokenClient","_a","tokenProvider","processPublicKeyToXOnly","VaultProviderRpcClient","primeVpTokenRegistry"],"mappings":"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"}
|