zklicensing 0.1.0-beta.2 → 0.1.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +417 -201
- package/build/agent.d.ts +371 -0
- package/build/agent.d.ts.map +1 -0
- package/build/agent.js +553 -0
- package/build/agent.js.map +1 -0
- package/build/agentActions.d.ts +841 -0
- package/build/agentActions.d.ts.map +1 -0
- package/build/agentActions.js +581 -0
- package/build/agentActions.js.map +1 -0
- package/build/agentRecord.d.ts +83 -0
- package/build/agentRecord.d.ts.map +1 -0
- package/build/agentRecord.js +69 -0
- package/build/agentRecord.js.map +1 -0
- package/build/agentVendor.d.ts +220 -0
- package/build/agentVendor.d.ts.map +1 -0
- package/build/agentVendor.js +306 -0
- package/build/agentVendor.js.map +1 -0
- package/build/appsLookup.d.ts +14 -0
- package/build/appsLookup.d.ts.map +1 -0
- package/build/appsLookup.js +12 -0
- package/build/appsLookup.js.map +1 -0
- package/build/archiveBootstrap.d.ts +31 -5
- package/build/archiveBootstrap.d.ts.map +1 -0
- package/build/archiveBootstrap.js +140 -47
- package/build/archiveBootstrap.js.map +1 -0
- package/build/atomicJson.d.ts +5 -0
- package/build/atomicJson.d.ts.map +1 -0
- package/build/atomicJson.js +55 -0
- package/build/atomicJson.js.map +1 -0
- package/build/bindClient.d.ts +85 -0
- package/build/bindClient.d.ts.map +1 -0
- package/build/bindClient.js +187 -0
- package/build/bindClient.js.map +1 -0
- package/build/buyClient.d.ts +27 -4
- package/build/buyClient.d.ts.map +1 -0
- package/build/buyClient.js +72 -26
- package/build/buyClient.js.map +1 -0
- package/build/chainHead.d.ts +61 -0
- package/build/chainHead.d.ts.map +1 -0
- package/build/chainHead.js +88 -0
- package/build/chainHead.js.map +1 -0
- package/build/compactMerkleMap.d.ts +72 -0
- package/build/compactMerkleMap.d.ts.map +1 -0
- package/build/compactMerkleMap.js +224 -0
- package/build/compactMerkleMap.js.map +1 -0
- package/build/contractInterface.d.ts +191 -51
- package/build/contractInterface.d.ts.map +1 -0
- package/build/contractInterface.js +234 -43
- package/build/contractInterface.js.map +1 -0
- package/build/contractTypes.d.ts +9 -0
- package/build/contractTypes.d.ts.map +1 -0
- package/build/contractTypes.js +28 -0
- package/build/contractTypes.js.map +1 -0
- package/build/countryStats.d.ts +12 -3
- package/build/countryStats.d.ts.map +1 -0
- package/build/countryStats.js +87 -23
- package/build/countryStats.js.map +1 -0
- package/build/deployClient.d.ts +138 -24
- package/build/deployClient.d.ts.map +1 -0
- package/build/deployClient.js +91 -31
- package/build/deployClient.js.map +1 -0
- package/build/deviceIdentity.d.ts +68 -0
- package/build/deviceIdentity.d.ts.map +1 -0
- package/build/deviceIdentity.js +209 -0
- package/build/deviceIdentity.js.map +1 -0
- package/build/freezeClient.d.ts +26 -6
- package/build/freezeClient.d.ts.map +1 -0
- package/build/freezeClient.js +30 -6
- package/build/freezeClient.js.map +1 -0
- package/build/generationClient.d.ts +6 -3
- package/build/generationClient.d.ts.map +1 -0
- package/build/generationClient.js +25 -38
- package/build/generationClient.js.map +1 -0
- package/build/holderSecret.d.ts +70 -0
- package/build/holderSecret.d.ts.map +1 -0
- package/build/holderSecret.js +76 -0
- package/build/holderSecret.js.map +1 -0
- package/build/index.d.ts +38 -38
- package/build/index.d.ts.map +1 -0
- package/build/index.js +97 -121
- package/build/index.js.map +1 -0
- package/build/keysClient.d.ts +142 -0
- package/build/keysClient.d.ts.map +1 -0
- package/build/keysClient.js +109 -0
- package/build/keysClient.js.map +1 -0
- package/build/licenseLeaf.d.ts +76 -0
- package/build/licenseLeaf.d.ts.map +1 -0
- package/build/licenseLeaf.js +189 -0
- package/build/licenseLeaf.js.map +1 -0
- package/build/licenseRecord.d.ts +68 -5
- package/build/licenseRecord.d.ts.map +1 -0
- package/build/licenseRecord.js +26 -1
- package/build/licenseRecord.js.map +1 -0
- package/build/licenseStore.d.ts +81 -4
- package/build/licenseStore.d.ts.map +1 -0
- package/build/licenseStore.js +400 -30
- package/build/licenseStore.js.map +1 -0
- package/build/licenseTrustless.d.ts +43 -0
- package/build/licenseTrustless.d.ts.map +1 -0
- package/build/licenseTrustless.js +180 -0
- package/build/licenseTrustless.js.map +1 -0
- package/build/manifestVerify.d.ts +29 -1
- package/build/manifestVerify.d.ts.map +1 -0
- package/build/manifestVerify.js +46 -4
- package/build/manifestVerify.js.map +1 -0
- package/build/minaPriceHistory.d.ts +9 -0
- package/build/minaPriceHistory.d.ts.map +1 -0
- package/build/minaPriceHistory.js +152 -0
- package/build/minaPriceHistory.js.map +1 -0
- package/build/onChainRoot.d.ts +60 -0
- package/build/onChainRoot.d.ts.map +1 -0
- package/build/onChainRoot.js +74 -0
- package/build/onChainRoot.js.map +1 -0
- package/build/ownershipLicenseHash.d.ts +25 -0
- package/build/ownershipLicenseHash.d.ts.map +1 -0
- package/build/ownershipLicenseHash.js +29 -0
- package/build/ownershipLicenseHash.js.map +1 -0
- package/build/ownershipSignature.d.ts +153 -0
- package/build/ownershipSignature.d.ts.map +1 -0
- package/build/ownershipSignature.js +297 -0
- package/build/ownershipSignature.js.map +1 -0
- package/build/permitCheckFlow.d.ts +155 -0
- package/build/permitCheckFlow.d.ts.map +1 -0
- package/build/permitCheckFlow.js +196 -0
- package/build/permitCheckFlow.js.map +1 -0
- package/build/permitDescribe.d.ts +124 -0
- package/build/permitDescribe.d.ts.map +1 -0
- package/build/permitDescribe.js +324 -0
- package/build/permitDescribe.js.map +1 -0
- package/build/permitInterface.d.ts +85 -0
- package/build/permitInterface.d.ts.map +1 -0
- package/build/permitInterface.js +121 -0
- package/build/permitInterface.js.map +1 -0
- package/build/permitMessages.d.ts +313 -0
- package/build/permitMessages.d.ts.map +1 -0
- package/build/permitMessages.js +462 -0
- package/build/permitMessages.js.map +1 -0
- package/build/permitProof.d.ts +108 -0
- package/build/permitProof.d.ts.map +1 -0
- package/build/permitProof.js +202 -0
- package/build/permitProof.js.map +1 -0
- package/build/permitRegistryRebuild.d.ts +166 -0
- package/build/permitRegistryRebuild.d.ts.map +1 -0
- package/build/permitRegistryRebuild.js +347 -0
- package/build/permitRegistryRebuild.js.map +1 -0
- package/build/permitTree.d.ts +88 -0
- package/build/permitTree.d.ts.map +1 -0
- package/build/permitTree.js +230 -0
- package/build/permitTree.js.map +1 -0
- package/build/permitsClient.d.ts +680 -0
- package/build/permitsClient.d.ts.map +1 -0
- package/build/permitsClient.js +597 -0
- package/build/permitsClient.js.map +1 -0
- package/build/proveErrors.d.ts +50 -0
- package/build/proveErrors.d.ts.map +1 -0
- package/build/proveErrors.js +76 -0
- package/build/proveErrors.js.map +1 -0
- package/build/receipt.d.ts +95 -0
- package/build/receipt.d.ts.map +1 -0
- package/build/receipt.js +84 -0
- package/build/receipt.js.map +1 -0
- package/build/refundClient.d.ts +7 -12
- package/build/refundClient.d.ts.map +1 -0
- package/build/refundClient.js +52 -21
- package/build/refundClient.js.map +1 -0
- package/build/registryTrustVerify.d.ts +78 -0
- package/build/registryTrustVerify.d.ts.map +1 -0
- package/build/registryTrustVerify.js +129 -0
- package/build/registryTrustVerify.js.map +1 -0
- package/build/releaseClient.d.ts +26 -0
- package/build/releaseClient.d.ts.map +1 -0
- package/build/releaseClient.js +65 -0
- package/build/releaseClient.js.map +1 -0
- package/build/renewClient.d.ts +28 -2
- package/build/renewClient.d.ts.map +1 -0
- package/build/renewClient.js +31 -27
- package/build/renewClient.js.map +1 -0
- package/build/seatName.d.ts +8 -0
- package/build/seatName.d.ts.map +1 -0
- package/build/seatName.js +136 -0
- package/build/seatName.js.map +1 -0
- package/build/slotConstants.d.ts +15 -0
- package/build/slotConstants.d.ts.map +1 -0
- package/build/slotConstants.js +17 -0
- package/build/slotConstants.js.map +1 -0
- package/build/statsClient.d.ts +61 -7
- package/build/statsClient.d.ts.map +1 -0
- package/build/statsClient.js +44 -5
- package/build/statsClient.js.map +1 -0
- package/build/successorChain.d.ts +35 -0
- package/build/successorChain.d.ts.map +1 -0
- package/build/successorChain.js +69 -0
- package/build/successorChain.js.map +1 -0
- package/build/taxId.d.ts +44 -0
- package/build/taxId.d.ts.map +1 -0
- package/build/taxId.js +212 -0
- package/build/taxId.js.map +1 -0
- package/build/trustAnchorVerify.d.ts +49 -0
- package/build/trustAnchorVerify.d.ts.map +1 -0
- package/build/trustAnchorVerify.js +432 -0
- package/build/trustAnchorVerify.js.map +1 -0
- package/build/trustAnchorVerifyCli.d.ts +45 -0
- package/build/trustAnchorVerifyCli.d.ts.map +1 -0
- package/build/trustAnchorVerifyCli.js +235 -0
- package/build/trustAnchorVerifyCli.js.map +1 -0
- package/build/txBroadcastClient.d.ts +26 -0
- package/build/txBroadcastClient.d.ts.map +1 -0
- package/build/txBroadcastClient.js +20 -0
- package/build/txBroadcastClient.js.map +1 -0
- package/build/unbindClient.d.ts +77 -0
- package/build/unbindClient.d.ts.map +1 -0
- package/build/unbindClient.js +169 -0
- package/build/unbindClient.js.map +1 -0
- package/build/units.d.ts +28 -0
- package/build/units.d.ts.map +1 -0
- package/build/units.js +65 -0
- package/build/units.js.map +1 -0
- package/build/vatRates.d.ts +54 -0
- package/build/vatRates.d.ts.map +1 -0
- package/build/vatRates.js +82 -0
- package/build/vatRates.js.map +1 -0
- package/build/vatRatesData.d.ts +5 -0
- package/build/vatRatesData.d.ts.map +1 -0
- package/build/vatRatesData.js +42 -0
- package/build/vatRatesData.js.map +1 -0
- package/build/vendorAccountClient.d.ts +66 -0
- package/build/vendorAccountClient.d.ts.map +1 -0
- package/build/vendorAccountClient.js +47 -0
- package/build/vendorAccountClient.js.map +1 -0
- package/build/verifyCore.d.ts +4 -1
- package/build/verifyCore.d.ts.map +1 -0
- package/build/verifyCore.js +21 -10
- package/build/verifyCore.js.map +1 -0
- package/build/verifyOffline.d.ts +85 -0
- package/build/verifyOffline.d.ts.map +1 -0
- package/build/verifyOffline.js +139 -0
- package/build/verifyOffline.js.map +1 -0
- package/build/verifyService.d.ts.map +1 -0
- package/build/verifyService.js +571 -501
- package/build/verifyService.js.map +1 -0
- package/build/verifyWithAncestors.d.ts +19 -0
- package/build/verifyWithAncestors.d.ts.map +1 -0
- package/build/verifyWithAncestors.js +127 -0
- package/build/verifyWithAncestors.js.map +1 -0
- package/build/zipToState.d.ts +2 -0
- package/build/zipToState.d.ts.map +1 -0
- package/build/zipToState.js +94 -0
- package/build/zipToState.js.map +1 -0
- package/package.json +141 -16
- package/src/agent.ts +682 -0
- package/src/agentActions.ts +637 -0
- package/src/agentRecord.ts +121 -0
- package/src/agentVendor.ts +356 -0
- package/src/appsLookup.ts +48 -0
- package/src/archiveBootstrap.ts +386 -0
- package/src/atomicJson.ts +53 -0
- package/src/bindClient.ts +297 -0
- package/src/buyClient.ts +344 -0
- package/src/chainHead.ts +106 -0
- package/src/compactMerkleMap.ts +222 -0
- package/src/contractInterface.ts +465 -0
- package/src/contractTypes.ts +31 -0
- package/src/countryStats.ts +200 -0
- package/src/deployClient.ts +517 -0
- package/src/deviceIdentity.ts +249 -0
- package/src/freezeClient.ts +162 -0
- package/src/generationClient.ts +145 -0
- package/src/holderSecret.ts +91 -0
- package/src/index.ts +362 -0
- package/src/keysClient.ts +135 -0
- package/src/licenseLeaf.ts +221 -0
- package/src/licenseRecord.ts +190 -0
- package/src/licenseStore.ts +767 -0
- package/src/licenseTrustless.ts +207 -0
- package/src/manifestVerify.ts +164 -0
- package/src/minaPriceHistory.ts +166 -0
- package/src/onChainRoot.ts +90 -0
- package/src/ownershipLicenseHash.ts +31 -0
- package/src/ownershipSignature.ts +421 -0
- package/src/permitCheckFlow.ts +227 -0
- package/src/permitDescribe.ts +362 -0
- package/src/permitInterface.ts +146 -0
- package/src/permitMessages.ts +572 -0
- package/src/permitProof.ts +230 -0
- package/src/permitRegistryRebuild.ts +423 -0
- package/src/permitTree.ts +232 -0
- package/src/permitsClient.ts +746 -0
- package/src/proveErrors.ts +98 -0
- package/src/receipt.ts +156 -0
- package/src/refundClient.ts +177 -0
- package/src/registryTrustVerify.ts +192 -0
- package/src/releaseClient.ts +101 -0
- package/src/renewClient.ts +234 -0
- package/src/seatName.ts +165 -0
- package/src/slotConstants.ts +18 -0
- package/src/statsClient.ts +249 -0
- package/src/successorChain.ts +87 -0
- package/src/taxId.ts +227 -0
- package/src/trustAnchorVerify.ts +550 -0
- package/src/trustAnchorVerifyCli.ts +234 -0
- package/src/txBroadcastClient.ts +48 -0
- package/src/unbindClient.ts +233 -0
- package/src/units.ts +74 -0
- package/src/vatRates.ts +100 -0
- package/src/vatRatesData.ts +43 -0
- package/src/vendorAccountClient.ts +120 -0
- package/src/verifyCore.ts +100 -0
- package/src/verifyOffline.ts +212 -0
- package/src/verifyService.ts +982 -0
- package/src/verifyWithAncestors.ts +163 -0
- package/src/zipToState.ts +94 -0
- package/build/licenseProof.d.ts +0 -26
- package/build/licenseProof.js +0 -41
- package/build/migrateClient.d.ts +0 -43
- package/build/migrateClient.js +0 -47
- package/build/ownership.d.ts +0 -34
- package/build/ownership.js +0 -147
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
/**
|
|
4
|
+
* bindClient.ts
|
|
5
|
+
*
|
|
6
|
+
* Browser-safe client for the non-custodial device-binding flow.
|
|
7
|
+
* Mirrors `buyClient.ts` in shape: the caller drives the wallet step
|
|
8
|
+
* between `proveBind` and `confirmBind`, so the SDK stays
|
|
9
|
+
* wallet-agnostic.
|
|
10
|
+
*
|
|
11
|
+
* Binding is a root-mutating tx on the same per-app in-flight slot
|
|
12
|
+
* that buy / renew / refund use — a concurrent request
|
|
13
|
+
* against the same app returns 409 `ProveQueueBusyError`, which the
|
|
14
|
+
* caller must catch and retry (see the retry loop in
|
|
15
|
+
* examples/src/bind.ts).
|
|
16
|
+
*
|
|
17
|
+
* The signature scheme is Pallas Schnorr and is re-verified INSIDE
|
|
18
|
+
* the on-chain circuit via `Signature.verify()` — a compromised
|
|
19
|
+
* backend cannot forge a bind because it can't produce a signature
|
|
20
|
+
* that satisfies the in-circuit check.
|
|
21
|
+
*/
|
|
22
|
+
import { Field } from 'o1js';
|
|
23
|
+
import { readErrorBody, tryQueueBusyFromBody, keeperError } from './proveErrors.js';
|
|
24
|
+
import { encodePublicKey, encodeSignature, signBinding, slotStateOf } from './ownershipSignature.js';
|
|
25
|
+
function baseUrl(url) {
|
|
26
|
+
return url.replace(/\/+$/, '');
|
|
27
|
+
}
|
|
28
|
+
async function readJsonError(resp) {
|
|
29
|
+
try {
|
|
30
|
+
const body = await resp.json();
|
|
31
|
+
if (typeof body.error === 'string')
|
|
32
|
+
return body.error;
|
|
33
|
+
}
|
|
34
|
+
catch { /* body wasn't JSON */ }
|
|
35
|
+
return `HTTP ${resp.status}`;
|
|
36
|
+
}
|
|
37
|
+
// Sample a fresh replay-defense nonce. WebCrypto is required for
|
|
38
|
+
// `crypto.getRandomValues` — same runtime floor as the rest of the
|
|
39
|
+
// signing surface (Node ≥ 20, modern browsers).
|
|
40
|
+
function freshNonce() {
|
|
41
|
+
const crypto = globalThis.crypto;
|
|
42
|
+
if (!crypto?.getRandomValues) {
|
|
43
|
+
throw new Error('crypto.getRandomValues unavailable — bindClient requires Node ≥ 20 or a modern browser');
|
|
44
|
+
}
|
|
45
|
+
const bytes = new Uint8Array(16); // 128 bits
|
|
46
|
+
crypto.getRandomValues(bytes);
|
|
47
|
+
let n = 0n;
|
|
48
|
+
for (const b of bytes)
|
|
49
|
+
n = (n << 8n) | BigInt(b);
|
|
50
|
+
// Field(n) is safe: 128 bits << the Pallas base field size, so no
|
|
51
|
+
// modular reduction ever fires here.
|
|
52
|
+
return Field(n).toString();
|
|
53
|
+
}
|
|
54
|
+
// Read the target slot's current packed state and the license's expiry from
|
|
55
|
+
// the keeper's license mirror. Shared with unbindClient.
|
|
56
|
+
export async function fetchBindingState(opts) {
|
|
57
|
+
const fetcher = opts.fetcher ?? fetch;
|
|
58
|
+
const url = `${baseUrl(opts.keeperUrl)}/license/${encodeURIComponent(opts.zkAppAddress)}/`
|
|
59
|
+
+ `${encodeURIComponent(opts.licenseHash)}?network=${encodeURIComponent(opts.network)}`;
|
|
60
|
+
const resp = await fetcher(url, { signal: opts.signal });
|
|
61
|
+
if (!resp.ok)
|
|
62
|
+
throw new Error(`License lookup failed: ${await readJsonError(resp)}`);
|
|
63
|
+
const body = await resp.json();
|
|
64
|
+
if (!body.found || !body.expirySlot)
|
|
65
|
+
throw new Error('License not found on the keeper.');
|
|
66
|
+
return {
|
|
67
|
+
slotState: slotStateOf((body.devices ?? [])[opts.slotIndex]),
|
|
68
|
+
expirySlot: body.expirySlot,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// POST /prove/bind — backend compiles + proves the bind tx.
|
|
72
|
+
//
|
|
73
|
+
// Retry contract:
|
|
74
|
+
// - 409 `proving queue busy` → `ProveQueueBusyError`; caller catches
|
|
75
|
+
// and retries with `retryAfterMs` cadence (see examples/src/bind.ts).
|
|
76
|
+
// - Any other non-2xx surfaces the body's `error` field verbatim.
|
|
77
|
+
export async function proveBind(req) {
|
|
78
|
+
const fetcher = req.fetcher ?? fetch;
|
|
79
|
+
const nonce = req.nonce ?? freshNonce();
|
|
80
|
+
const { slotState, expirySlot } = (req.slotState !== undefined && req.expirySlot !== undefined)
|
|
81
|
+
? { slotState: req.slotState, expirySlot: req.expirySlot }
|
|
82
|
+
: await fetchBindingState({ ...req, fetcher });
|
|
83
|
+
const ownerPubKey = req.ownerPrivateKey.toPublicKey();
|
|
84
|
+
const ownerSig = signBinding(req.ownerPrivateKey, {
|
|
85
|
+
licenseHash: req.licenseHash,
|
|
86
|
+
deviceCommitment: req.deviceCommitment,
|
|
87
|
+
slotIndex: req.slotIndex,
|
|
88
|
+
nonce,
|
|
89
|
+
slotState,
|
|
90
|
+
expirySlot,
|
|
91
|
+
zkAppAddress: req.zkAppAddress,
|
|
92
|
+
});
|
|
93
|
+
const resp = await fetcher(`${baseUrl(req.keeperUrl)}/prove/bind`, {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
headers: { 'Content-Type': 'application/json' },
|
|
96
|
+
signal: req.signal,
|
|
97
|
+
body: JSON.stringify({
|
|
98
|
+
licenseHash: req.licenseHash,
|
|
99
|
+
buyerAddress: req.buyerAddress,
|
|
100
|
+
zkAppAddress: req.zkAppAddress,
|
|
101
|
+
network: req.network,
|
|
102
|
+
ownerPubKey: encodePublicKey(ownerPubKey),
|
|
103
|
+
ownerSig: encodeSignature(ownerSig),
|
|
104
|
+
deviceCommitment: req.deviceCommitment,
|
|
105
|
+
slotIndex: req.slotIndex,
|
|
106
|
+
nonce,
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
if (!resp.ok) {
|
|
110
|
+
const parsed = await readErrorBody(resp);
|
|
111
|
+
const queueBusy = tryQueueBusyFromBody(parsed);
|
|
112
|
+
if (queueBusy)
|
|
113
|
+
throw queueBusy;
|
|
114
|
+
throw keeperError(parsed);
|
|
115
|
+
}
|
|
116
|
+
return await resp.json();
|
|
117
|
+
}
|
|
118
|
+
// POST /confirm/bind — pass-through no-op that clears the staged
|
|
119
|
+
// intent on the backend. Call this only after the wallet has returned
|
|
120
|
+
// a real txHash; a cancelled or dropped signature leaves the intent
|
|
121
|
+
// to expire on its own.
|
|
122
|
+
export async function confirmBind(req) {
|
|
123
|
+
const fetcher = req.fetcher ?? fetch;
|
|
124
|
+
const resp = await fetcher(`${baseUrl(req.keeperUrl)}/confirm/bind`, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers: { 'Content-Type': 'application/json' },
|
|
127
|
+
signal: req.signal,
|
|
128
|
+
body: JSON.stringify({
|
|
129
|
+
zkAppAddress: req.zkAppAddress,
|
|
130
|
+
licenseHash: req.licenseHash,
|
|
131
|
+
txHash: req.txHash,
|
|
132
|
+
}),
|
|
133
|
+
});
|
|
134
|
+
if (!resp.ok)
|
|
135
|
+
throw new Error(await readJsonError(resp));
|
|
136
|
+
return { ok: true };
|
|
137
|
+
}
|
|
138
|
+
// Polls GET /license/:zkAppAddress/:licenseHash until the bind has
|
|
139
|
+
// landed on-chain (the target slot's commitment matches the expected
|
|
140
|
+
// value) or the timeout fires. Mirrors pollRenewStatus in shape.
|
|
141
|
+
export async function pollBindStatus(opts) {
|
|
142
|
+
const fetcher = opts.fetcher ?? fetch;
|
|
143
|
+
const interval = opts.intervalMs ?? 10_000;
|
|
144
|
+
const timeout = opts.timeoutMs ?? 20 * 60 * 1000;
|
|
145
|
+
const startedAt = Date.now();
|
|
146
|
+
const deadline = startedAt + timeout;
|
|
147
|
+
const url = `${baseUrl(opts.keeperUrl)}/license/${encodeURIComponent(opts.zkAppAddress)}/${encodeURIComponent(opts.licenseHash)}?network=${opts.network}`;
|
|
148
|
+
while (true) {
|
|
149
|
+
if (opts.signal?.aborted)
|
|
150
|
+
throw new Error('pollBindStatus aborted');
|
|
151
|
+
let status = { status: 'unknown', elapsedMs: Date.now() - startedAt };
|
|
152
|
+
try {
|
|
153
|
+
const resp = await fetcher(url, { signal: opts.signal });
|
|
154
|
+
if (resp.ok) {
|
|
155
|
+
const body = await resp.json();
|
|
156
|
+
if (body.found) {
|
|
157
|
+
const slot = (body.devices ?? []).find(d => d.slotIndex === opts.slotIndex);
|
|
158
|
+
const commitment = slot?.deviceCommitment ?? '0';
|
|
159
|
+
if (commitment === opts.deviceCommitment) {
|
|
160
|
+
status = {
|
|
161
|
+
status: 'confirmed',
|
|
162
|
+
slotIndex: opts.slotIndex,
|
|
163
|
+
deviceCommitment: commitment,
|
|
164
|
+
elapsedMs: Date.now() - startedAt,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
status = {
|
|
169
|
+
status: 'pending',
|
|
170
|
+
slotIndex: opts.slotIndex,
|
|
171
|
+
deviceCommitment: commitment,
|
|
172
|
+
elapsedMs: Date.now() - startedAt,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch { /* transient network — try again on next tick */ }
|
|
179
|
+
opts.onTick?.(status);
|
|
180
|
+
if (status.status === 'confirmed')
|
|
181
|
+
return status;
|
|
182
|
+
if (Date.now() >= deadline)
|
|
183
|
+
return status;
|
|
184
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=bindClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bindClient.js","sourceRoot":"","sources":["../src/bindClient.ts"],"names":[],"mappings":"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"}
|
package/build/buyClient.d.ts
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
|
+
import type { PurchaseReceipt } from './receipt.js';
|
|
2
|
+
import type { PrivateKey, PublicKey } from 'o1js';
|
|
1
3
|
export type BuyIdentity = {
|
|
2
|
-
|
|
4
|
+
publicKey: PublicKey;
|
|
5
|
+
publicKeyBase58: string;
|
|
6
|
+
privateKey: PrivateKey;
|
|
3
7
|
licenseHash: string;
|
|
4
8
|
};
|
|
5
|
-
export declare function deriveBuyIdentity(passphrase: string): BuyIdentity
|
|
9
|
+
export declare function deriveBuyIdentity(passphrase: string, zkAppAddress: string): Promise<BuyIdentity>;
|
|
6
10
|
export type ProveBuyRequest = {
|
|
11
|
+
agentConsent?: unknown;
|
|
7
12
|
keeperUrl: string;
|
|
8
13
|
licenseHash: string;
|
|
9
14
|
buyerAddress: string;
|
|
10
15
|
zkAppAddress: string;
|
|
11
|
-
|
|
16
|
+
ownerPubKey: string;
|
|
17
|
+
network: 'devnet' | 'mainnet';
|
|
18
|
+
duration: 0 | 1 | 2 | 3;
|
|
12
19
|
buyerCountry: string;
|
|
20
|
+
buyerZip?: string;
|
|
13
21
|
refundWaiverAccepted?: boolean;
|
|
14
22
|
freezeAfterSlot?: number | null;
|
|
15
23
|
fetcher?: typeof fetch;
|
|
@@ -25,6 +33,7 @@ export type ProveBuyResponse = {
|
|
|
25
33
|
duration: number;
|
|
26
34
|
durationLabel: string;
|
|
27
35
|
generation: number;
|
|
36
|
+
appKey: string;
|
|
28
37
|
};
|
|
29
38
|
export type ConfirmBuyRequest = {
|
|
30
39
|
keeperUrl: string;
|
|
@@ -35,15 +44,29 @@ export type ConfirmBuyRequest = {
|
|
|
35
44
|
signal?: AbortSignal;
|
|
36
45
|
};
|
|
37
46
|
export type BuyStatus = {
|
|
38
|
-
status: 'unknown' | 'pending' | '
|
|
47
|
+
status: 'unknown' | 'pending' | 'landed' | 'timeout' | 'failed';
|
|
48
|
+
failureReason?: string;
|
|
39
49
|
txHash?: string;
|
|
40
50
|
landedAtBlockHeight?: number;
|
|
41
51
|
landedAtSlot?: number;
|
|
42
52
|
elapsedMs?: number;
|
|
43
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* The buyer's country guessed from their IP address (keeper `GET /geo/country`),
|
|
56
|
+
* to pre-fill the country field. Null when the keeper has no geolocation
|
|
57
|
+
* database, the address has no country, or the keeper is unreachable. The
|
|
58
|
+
* buyer's own choice is what `proveBuy` sends; the keeper separately records
|
|
59
|
+
* the country it sees as VAT evidence, and never the address.
|
|
60
|
+
*/
|
|
61
|
+
export declare function detectBuyerCountry(keeperUrl: string, fetcher?: typeof fetch): Promise<string | null>;
|
|
44
62
|
export declare function proveBuy(req: ProveBuyRequest): Promise<ProveBuyResponse>;
|
|
63
|
+
/**
|
|
64
|
+
* Returns the buyer's receipt (zklicensing/receipt) when the keeper issued
|
|
65
|
+
* one: put it in the license file as `receipt` (Vendor Terms §7.1).
|
|
66
|
+
*/
|
|
45
67
|
export declare function confirmBuy(req: ConfirmBuyRequest): Promise<{
|
|
46
68
|
ok: true;
|
|
69
|
+
receipt?: PurchaseReceipt;
|
|
47
70
|
}>;
|
|
48
71
|
export type PollBuyStatusOptions = {
|
|
49
72
|
keeperUrl: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buyClient.d.ts","sourceRoot":"","sources":["../src/buyClient.ts"],"names":[],"mappings":"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"}
|
package/build/buyClient.js
CHANGED
|
@@ -1,31 +1,42 @@
|
|
|
1
1
|
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
-
//
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
3
|
/**
|
|
4
4
|
* buyClient.ts
|
|
5
5
|
*
|
|
6
|
-
* Browser-safe client for the buy flow. Exposes the three
|
|
6
|
+
* Browser-safe client for the buy flow. Exposes the three backend roundtrips
|
|
7
7
|
* (derive identity → prove → confirm) as small, individually testable
|
|
8
8
|
* functions plus a `pollBuyStatus` helper. Deliberately does NOT talk to a
|
|
9
9
|
* wallet — the caller drives the wallet step between `proveBuy` and
|
|
10
10
|
* `confirmBuy`, so the SDK stays wallet-agnostic and can be reused by CLI
|
|
11
11
|
* tools, alternate UIs, and third-party integrators.
|
|
12
12
|
*
|
|
13
|
-
* Peer dep: o1js (for Poseidon +
|
|
14
|
-
*
|
|
13
|
+
* Peer dep: o1js (for Poseidon + Pallas PrivateKey/PublicKey/Signature).
|
|
14
|
+
* The ownership-signing surface (ownershipSignature.ts) uses Mina-native
|
|
15
|
+
* Schnorr so the passphrase-derived keypair also authorizes /prove/bind
|
|
16
|
+
* and /prove/unbind — verified IN-CIRCUIT there via Signature.verify(),
|
|
17
|
+
* which requires o1js. Every buy-flow consumer already ships o1js for the
|
|
18
|
+
* buy-witness path, so this is not new cost.
|
|
15
19
|
*/
|
|
16
|
-
import { Encoding, Poseidon } from 'o1js';
|
|
17
20
|
import { resolveFreezeState } from './freezeClient.js';
|
|
18
21
|
import { REFUND_WINDOW_N, TOLERANCE_WINDOW_N } from './contractInterface.js';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
// the
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
import { readErrorBody, tryQueueBusyFromBody, keeperError } from './proveErrors.js';
|
|
23
|
+
import { deriveOwnershipKeypair } from './ownershipSignature.js';
|
|
24
|
+
import { licenseHashFromPubkey } from './ownershipLicenseHash.js';
|
|
25
|
+
// Derive the ownership keypair + licenseHash the buy flow keys off.
|
|
26
|
+
// Deterministic in (passphrase, zkAppAddress) — same inputs always map
|
|
27
|
+
// to the same keypair (via HKDF-SHA256) and therefore the same
|
|
28
|
+
// licenseHash on every device, so a buyer can re-derive their license
|
|
29
|
+
// identity anywhere from the passphrase and the app address. Binding
|
|
30
|
+
// the derivation to the app address means a leaked passphrase for app A
|
|
31
|
+
// cannot be replayed as a valid activation for app B.
|
|
32
|
+
//
|
|
33
|
+
// HKDF still needs WebCrypto (Node ≥20, Chromium 137+, Safari 17+,
|
|
34
|
+
// Firefox 130+); the scalar reduction and Pallas group operations are
|
|
35
|
+
// pure JS through o1js. Async because subtle.deriveBits is async.
|
|
36
|
+
export async function deriveBuyIdentity(passphrase, zkAppAddress) {
|
|
37
|
+
const { privateKey, publicKey, publicKeyBase58 } = await deriveOwnershipKeypair(passphrase, zkAppAddress);
|
|
38
|
+
const licenseHash = licenseHashFromPubkey(publicKey);
|
|
39
|
+
return { publicKey, publicKeyBase58, privateKey, licenseHash };
|
|
29
40
|
}
|
|
30
41
|
function baseUrl(url) {
|
|
31
42
|
return url.replace(/\/+$/, '');
|
|
@@ -39,11 +50,11 @@ async function readJsonError(resp) {
|
|
|
39
50
|
catch { /* body wasn't JSON */ }
|
|
40
51
|
return `HTTP ${resp.status}`;
|
|
41
52
|
}
|
|
42
|
-
// POST /prove/buy —
|
|
53
|
+
// POST /prove/buy — backend compiles + proves the buy tx.
|
|
43
54
|
// The buyer's wallet then signs the returned provenTxJson.
|
|
44
55
|
//
|
|
45
56
|
// Pre-network guards:
|
|
46
|
-
// - salesFrozen === true → refuse immediately (
|
|
57
|
+
// - salesFrozen === true → refuse immediately (backend would 423 anyway).
|
|
47
58
|
// - freezeAfterSlot announced AND this buy's 14-day refund window would
|
|
48
59
|
// extend past the freeze slot AND refundWaiverAccepted !== true →
|
|
49
60
|
// refuse (buyer must explicitly accept that the scheduled hardfork
|
|
@@ -58,16 +69,36 @@ async function readJsonError(resp) {
|
|
|
58
69
|
// delivery) or forced by a freeze overlap.
|
|
59
70
|
// - refundWaiverAccepted !== true → POST /prove/buy (standard escrow path
|
|
60
71
|
// with a 14-day refund window).
|
|
72
|
+
/**
|
|
73
|
+
* The buyer's country guessed from their IP address (keeper `GET /geo/country`),
|
|
74
|
+
* to pre-fill the country field. Null when the keeper has no geolocation
|
|
75
|
+
* database, the address has no country, or the keeper is unreachable. The
|
|
76
|
+
* buyer's own choice is what `proveBuy` sends; the keeper separately records
|
|
77
|
+
* the country it sees as VAT evidence, and never the address.
|
|
78
|
+
*/
|
|
79
|
+
export async function detectBuyerCountry(keeperUrl, fetcher = fetch) {
|
|
80
|
+
try {
|
|
81
|
+
const res = await fetcher(`${keeperUrl.replace(/\/$/, '')}/geo/country`, { cache: 'no-store' });
|
|
82
|
+
if (!res.ok)
|
|
83
|
+
return null;
|
|
84
|
+
const body = await res.json();
|
|
85
|
+
return typeof body.country === 'string' && /^[A-Z]{2}$/.test(body.country) ? body.country : null;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
61
91
|
export async function proveBuy(req) {
|
|
62
92
|
const fetcher = req.fetcher ?? fetch;
|
|
63
93
|
const freeze = await resolveFreezeState({
|
|
64
94
|
keeperUrl: req.keeperUrl,
|
|
95
|
+
network: req.network,
|
|
65
96
|
freezeAfterSlot: req.freezeAfterSlot,
|
|
66
97
|
fetcher,
|
|
67
98
|
signal: req.signal,
|
|
68
99
|
});
|
|
69
100
|
if (freeze.salesFrozen) {
|
|
70
|
-
throw new Error('Sales frozen — new buys refused ahead of scheduled hardfork
|
|
101
|
+
throw new Error('Sales frozen — new buys refused ahead of a scheduled hardfork');
|
|
71
102
|
}
|
|
72
103
|
let windowOverlapsFreeze = false;
|
|
73
104
|
if (freeze.freezeAfterSlot !== null) {
|
|
@@ -95,20 +126,28 @@ export async function proveBuy(req) {
|
|
|
95
126
|
licenseHash: req.licenseHash,
|
|
96
127
|
buyerAddress: req.buyerAddress,
|
|
97
128
|
zkAppAddress: req.zkAppAddress,
|
|
129
|
+
ownerPubKey: req.ownerPubKey,
|
|
130
|
+
network: req.network,
|
|
98
131
|
duration: req.duration,
|
|
99
132
|
buyerCountry: req.buyerCountry,
|
|
133
|
+
...(req.buyerZip ? { buyerZip: req.buyerZip } : {}),
|
|
100
134
|
...(req.refundWaiverAccepted === true ? { refundWaiverAccepted: true } : {}),
|
|
135
|
+
...(req.refundWaiverAccepted === true && req.agentConsent ? { agentConsent: req.agentConsent } : {}),
|
|
101
136
|
}),
|
|
102
137
|
});
|
|
103
138
|
if (!resp.ok) {
|
|
104
139
|
// Distinct guidance for the no-escrow path: a 404 here means the
|
|
105
140
|
// vendor's zkApp was deployed before the no-escrow method existed. Fix
|
|
106
|
-
// is a redeploy
|
|
141
|
+
// is a redeploy (§12.13); until
|
|
107
142
|
// then the escrowless (waiver) path is unavailable on this vendor.
|
|
108
143
|
if (useNoEscrow && resp.status === 404) {
|
|
109
|
-
throw new Error('
|
|
144
|
+
throw new Error('Backend does not offer /prove/buy-no-escrow — this vendor\'s zkApp does not support the escrowless (waiver) path; vendor must redeploy');
|
|
110
145
|
}
|
|
111
|
-
|
|
146
|
+
const parsed = await readErrorBody(resp);
|
|
147
|
+
const queueBusy = tryQueueBusyFromBody(parsed);
|
|
148
|
+
if (queueBusy)
|
|
149
|
+
throw queueBusy;
|
|
150
|
+
throw keeperError(parsed);
|
|
112
151
|
}
|
|
113
152
|
return await resp.json();
|
|
114
153
|
}
|
|
@@ -116,6 +155,10 @@ export async function proveBuy(req) {
|
|
|
116
155
|
// into a persisted (pending: true) LicenseRecord. Call this only after the
|
|
117
156
|
// wallet has actually returned a txHash — a cancelled or dropped signature
|
|
118
157
|
// leaves the intent to expire on its own.
|
|
158
|
+
/**
|
|
159
|
+
* Returns the buyer's receipt (zklicensing/receipt) when the keeper issued
|
|
160
|
+
* one: put it in the license file as `receipt` (Vendor Terms §7.1).
|
|
161
|
+
*/
|
|
119
162
|
export async function confirmBuy(req) {
|
|
120
163
|
const fetcher = req.fetcher ?? fetch;
|
|
121
164
|
const resp = await fetcher(`${baseUrl(req.keeperUrl)}/confirm/buy`, {
|
|
@@ -130,11 +173,14 @@ export async function confirmBuy(req) {
|
|
|
130
173
|
});
|
|
131
174
|
if (!resp.ok)
|
|
132
175
|
throw new Error(await readJsonError(resp));
|
|
133
|
-
|
|
176
|
+
const body = await resp.json().catch(() => ({}));
|
|
177
|
+
return { ok: true, ...(body?.receipt ? { receipt: body.receipt } : {}) };
|
|
134
178
|
}
|
|
135
|
-
// Polls GET /buy/status until it returns a terminal state ('
|
|
136
|
-
// 'failed'
|
|
137
|
-
//
|
|
179
|
+
// Polls GET /buy/status until it returns a terminal state ('landed' — success,
|
|
180
|
+
// tx included on-chain; 'failed' — included but failed on chain; or 'timeout'
|
|
181
|
+
// — watch deadline passed without inclusion)
|
|
182
|
+
// or the local poll timeout fires. 'unknown' just means the backend hasn't seen
|
|
183
|
+
// a watch record yet (confirmBuy still landing, or retention window expired).
|
|
138
184
|
export async function pollBuyStatus(opts) {
|
|
139
185
|
const fetcher = opts.fetcher ?? fetch;
|
|
140
186
|
const interval = opts.intervalMs ?? 3_000;
|
|
@@ -152,7 +198,7 @@ export async function pollBuyStatus(opts) {
|
|
|
152
198
|
}
|
|
153
199
|
catch { /* transient network — try again on next tick */ }
|
|
154
200
|
opts.onTick?.(status);
|
|
155
|
-
if (status.status === '
|
|
201
|
+
if (status.status === 'landed' || status.status === 'timeout' || status.status === 'failed')
|
|
156
202
|
return status;
|
|
157
203
|
if (Date.now() >= deadline)
|
|
158
204
|
return status;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buyClient.js","sourceRoot":"","sources":["../src/buyClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** `state`: the account's whole app state (decimal strings). */
|
|
2
|
+
export type ChainHead = {
|
|
3
|
+
root: string;
|
|
4
|
+
slot: number;
|
|
5
|
+
state: string[];
|
|
6
|
+
};
|
|
7
|
+
export declare function readChainHead(args: {
|
|
8
|
+
address: string;
|
|
9
|
+
network: 'devnet' | 'mainnet';
|
|
10
|
+
graphqlUrl?: string;
|
|
11
|
+
fetcher?: typeof fetch;
|
|
12
|
+
}): Promise<ChainHead>;
|
|
13
|
+
/** Permission names as a Mina node reports them: 'Proof', 'Signature', 'Either', 'None', 'Impossible'. */
|
|
14
|
+
export type ZkappAccount = {
|
|
15
|
+
found: boolean;
|
|
16
|
+
zkappUri?: string;
|
|
17
|
+
vkHash?: string;
|
|
18
|
+
appState?: string[];
|
|
19
|
+
permissions?: {
|
|
20
|
+
editState?: string;
|
|
21
|
+
send?: string;
|
|
22
|
+
setZkappUri?: string;
|
|
23
|
+
setPermissions?: string;
|
|
24
|
+
setDelegate?: string;
|
|
25
|
+
setTiming?: string;
|
|
26
|
+
setVerificationKey?: {
|
|
27
|
+
auth?: string;
|
|
28
|
+
txnVersion?: number;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/** A Mina node that couldn't be reached or answered with an error; `status` 0 when there was no HTTP answer. */
|
|
33
|
+
export declare class MinaNodeError extends Error {
|
|
34
|
+
readonly status: number;
|
|
35
|
+
constructor(message: string, status: number);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reads a zkApp account (state, verification-key hash, URI, permissions)
|
|
39
|
+
* from a Mina node over GraphQL — the fields o1js's fetchAccount reads,
|
|
40
|
+
* without o1js and its global Mina instance. `found: false` when the node
|
|
41
|
+
* has no such account.
|
|
42
|
+
*/
|
|
43
|
+
export declare function readZkappAccount(args: {
|
|
44
|
+
address: string;
|
|
45
|
+
graphqlUrl: string;
|
|
46
|
+
fetcher?: typeof fetch;
|
|
47
|
+
}): Promise<ZkappAccount>;
|
|
48
|
+
/**
|
|
49
|
+
* The one GraphQL read behind readZkappAccount and readChainHead: the
|
|
50
|
+
* account and the chain's current slot (`undefined` when the node didn't
|
|
51
|
+
* report it) in one query. Throws MinaNodeError.
|
|
52
|
+
*/
|
|
53
|
+
export declare function readZkappHead(args: {
|
|
54
|
+
address: string;
|
|
55
|
+
graphqlUrl: string;
|
|
56
|
+
fetcher?: typeof fetch;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
account: ZkappAccount;
|
|
59
|
+
slot?: number;
|
|
60
|
+
}>;
|
|
61
|
+
//# sourceMappingURL=chainHead.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chainHead.d.ts","sourceRoot":"","sources":["../src/chainHead.ts"],"names":[],"mappings":"AAWA,gEAAgE;AAChE,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAExE,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB,GAAG,OAAO,CAAC,SAAS,CAAC,CAOrB;AAED,0GAA0G;AAC1G,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE;QACZ,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QACjF,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QACzC,kBAAkB,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAC7D,CAAC;CACH,CAAC;AAEF,gHAAgH;AAChH,qBAAa,aAAc,SAAQ,KAAK;IACT,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAW,MAAM,EAAE,MAAM;CACrD;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAEnI;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA4C5J"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
/**
|
|
4
|
+
* chainHead.ts — reads a zkApp's first state field (its tree root) and the
|
|
5
|
+
* chain's current slot from a Mina node over GraphQL, in one query, without
|
|
6
|
+
* o1js and without touching o1js's global Mina instance.
|
|
7
|
+
*/
|
|
8
|
+
import { DEFAULT_MINA_GRAPHQL_URLS } from './onChainRoot.js';
|
|
9
|
+
export async function readChainHead(args) {
|
|
10
|
+
const url = args.graphqlUrl ?? DEFAULT_MINA_GRAPHQL_URLS[args.network];
|
|
11
|
+
const { account, slot } = await readZkappHead({ address: args.address, graphqlUrl: url, fetcher: args.fetcher });
|
|
12
|
+
const root = account.appState?.[0];
|
|
13
|
+
if (!root)
|
|
14
|
+
throw new Error(`${args.address} is not a zkApp on ${args.network}`);
|
|
15
|
+
if (slot === undefined)
|
|
16
|
+
throw new MinaNodeError(`Mina node ${url} did not report the current slot`, 0);
|
|
17
|
+
return { root, slot, state: account.appState };
|
|
18
|
+
}
|
|
19
|
+
/** A Mina node that couldn't be reached or answered with an error; `status` 0 when there was no HTTP answer. */
|
|
20
|
+
export class MinaNodeError extends Error {
|
|
21
|
+
status;
|
|
22
|
+
constructor(message, status) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.status = status;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Reads a zkApp account (state, verification-key hash, URI, permissions)
|
|
29
|
+
* from a Mina node over GraphQL — the fields o1js's fetchAccount reads,
|
|
30
|
+
* without o1js and its global Mina instance. `found: false` when the node
|
|
31
|
+
* has no such account.
|
|
32
|
+
*/
|
|
33
|
+
export async function readZkappAccount(args) {
|
|
34
|
+
return (await readZkappHead(args)).account;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The one GraphQL read behind readZkappAccount and readChainHead: the
|
|
38
|
+
* account and the chain's current slot (`undefined` when the node didn't
|
|
39
|
+
* report it) in one query. Throws MinaNodeError.
|
|
40
|
+
*/
|
|
41
|
+
export async function readZkappHead(args) {
|
|
42
|
+
const query = `query($pk: PublicKey!) {
|
|
43
|
+
account(publicKey: $pk) {
|
|
44
|
+
zkappUri
|
|
45
|
+
zkappState
|
|
46
|
+
verificationKey { hash }
|
|
47
|
+
permissions { editState send setZkappUri setPermissions setDelegate setTiming setVerificationKey { auth txnVersion } }
|
|
48
|
+
}
|
|
49
|
+
bestChain(maxLength: 1) { protocolState { consensusState { slotSinceGenesis } } }
|
|
50
|
+
}`;
|
|
51
|
+
let resp;
|
|
52
|
+
try {
|
|
53
|
+
resp = await (args.fetcher ?? fetch)(args.graphqlUrl, {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
headers: { 'Content-Type': 'application/json' },
|
|
56
|
+
body: JSON.stringify({ query, variables: { pk: args.address } }),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
throw new MinaNodeError(`Mina node ${args.graphqlUrl}: ${e?.message ?? e}`, 0);
|
|
61
|
+
}
|
|
62
|
+
const body = await resp.json().catch(() => null);
|
|
63
|
+
if (!resp.ok || !body?.data) {
|
|
64
|
+
throw new MinaNodeError(`Mina node ${args.graphqlUrl}: ${body?.errors?.map(e => e.message).join('; ') || `HTTP ${resp.status}`}`, resp.status);
|
|
65
|
+
}
|
|
66
|
+
const rawSlot = body.data.bestChain?.[0]?.protocolState?.consensusState?.slotSinceGenesis;
|
|
67
|
+
const slot = rawSlot === undefined || rawSlot === null || !Number.isFinite(Number(rawSlot)) ? undefined : Number(rawSlot);
|
|
68
|
+
const a = body.data.account;
|
|
69
|
+
if (!a)
|
|
70
|
+
return { account: { found: false }, slot };
|
|
71
|
+
const p = a.permissions ?? {};
|
|
72
|
+
const txn = p.setVerificationKey?.txnVersion;
|
|
73
|
+
return {
|
|
74
|
+
slot,
|
|
75
|
+
account: {
|
|
76
|
+
found: true,
|
|
77
|
+
zkappUri: a.zkappUri ?? undefined,
|
|
78
|
+
vkHash: a.verificationKey?.hash != null ? String(a.verificationKey.hash) : undefined,
|
|
79
|
+
appState: Array.isArray(a.zkappState) ? a.zkappState.map(String) : undefined,
|
|
80
|
+
permissions: {
|
|
81
|
+
editState: p.editState, send: p.send, setZkappUri: p.setZkappUri, setPermissions: p.setPermissions,
|
|
82
|
+
setDelegate: p.setDelegate, setTiming: p.setTiming,
|
|
83
|
+
setVerificationKey: p.setVerificationKey ? { auth: p.setVerificationKey.auth, txnVersion: txn === undefined || txn === null ? undefined : Number(txn) } : undefined,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=chainHead.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chainHead.js","sourceRoot":"","sources":["../src/chainHead.ts"],"names":[],"mappings":"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"}
|