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 @@
|
|
|
1
|
+
{"version":3,"file":"licenseTrustless.d.ts","sourceRoot":"","sources":["../src/licenseTrustless.ts"],"names":[],"mappings":"AAqCA,MAAM,MAAM,4BAA4B,GAAG;IACzC,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,yHAAyH;IACzH,eAAe,EAAE,MAAM,CAAC;IACxB,qFAAqF;IACrF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,qJAAqJ;IACrJ,WAAW,EAAE,UAAU,GAAG,oBAAoB,CAAC;CAChD,CAAC;AAEF,KAAK,YAAY,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAqBlL,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAO9D;AAqCD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CA+DxC"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
/**
|
|
4
|
+
* licenseTrustless.ts — a license check that doesn't trust the keeper.
|
|
5
|
+
*
|
|
6
|
+
* The keeper's `/verify` reads the chain for you; here the caller reads it:
|
|
7
|
+
*
|
|
8
|
+
* 1. From a Mina node: the contract account at each address checked (its
|
|
9
|
+
* license root, verification key and permissions) and the current slot.
|
|
10
|
+
* The contract must run a published LicensingApp release (the pinned
|
|
11
|
+
* CANONICAL_VK_HASHES) and be locked: state changes only by proof, no
|
|
12
|
+
* new verification key, no new permissions.
|
|
13
|
+
* 2. From the keeper: only the license's leaf fields and Merkle path
|
|
14
|
+
* (`/witness`). They are hashed and folded up to the root read in 1, so
|
|
15
|
+
* a keeper that lies, or is behind, can't make the check pass; it can
|
|
16
|
+
* only make it fail. An absent license is proved the same way (an
|
|
17
|
+
* empty leaf folds to the root).
|
|
18
|
+
* 3. Which addresses belong to the app: the platform-signed generation
|
|
19
|
+
* list (`/apps/by-address`), checked against the pinned manifest keys.
|
|
20
|
+
* As the keeper does, the current generation is tried first, then the
|
|
21
|
+
* address given, then the other retired ones (licenses refunded or
|
|
22
|
+
* expired before a redeploy stay there). Without a valid signed list the
|
|
23
|
+
* given address and its on-chain successors are checked: a retired
|
|
24
|
+
* contract names its successor in its state (see successorChain.ts).
|
|
25
|
+
*
|
|
26
|
+
* Whether the address is the app you think it is (the seller's website) is
|
|
27
|
+
* a separate check: verifyTrustAnchor. Loads o1js (for Poseidon).
|
|
28
|
+
*/
|
|
29
|
+
import { AgentError, PLATFORM_MANIFEST_PUBKEYS } from './agent.js';
|
|
30
|
+
import { CANONICAL_VK_HASHES, GRACE_PERIOD_N, LICENSING_APP_STATE, MS_PER_SLOT_N, SLOTS_PER_DAY_N, effectiveExpirySlot } from './contractInterface.js';
|
|
31
|
+
import { DEFAULT_MINA_GRAPHQL_URLS } from './onChainRoot.js';
|
|
32
|
+
import { MinaNodeError, readZkappHead } from './chainHead.js';
|
|
33
|
+
import { LICENSING_LINEAGE, currentOnChain } from './successorChain.js';
|
|
34
|
+
import { verifyManifest } from './manifestVerify.js';
|
|
35
|
+
async function readContract(address, graphqlUrl, f) {
|
|
36
|
+
let head;
|
|
37
|
+
try {
|
|
38
|
+
head = await readZkappHead({ address, graphqlUrl, fetcher: f });
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
throw new AgentError(e?.message ?? String(e), 'UPSTREAM_UNAVAILABLE', e instanceof MinaNodeError ? e.status : 0, true);
|
|
42
|
+
}
|
|
43
|
+
const { account: a, slot } = head;
|
|
44
|
+
if (slot === undefined)
|
|
45
|
+
throw new AgentError(`Mina node ${graphqlUrl} did not report the current slot`, 'UPSTREAM_UNAVAILABLE', 0, true);
|
|
46
|
+
if (!a.found)
|
|
47
|
+
return { found: false, slot };
|
|
48
|
+
return {
|
|
49
|
+
found: true, slot,
|
|
50
|
+
root: a.appState?.[0],
|
|
51
|
+
forkSlot: Number(a.appState?.[LICENSING_APP_STATE.forkActivationSlot] ?? 0),
|
|
52
|
+
vkHash: a.vkHash,
|
|
53
|
+
editState: a.permissions?.editState, setPermissions: a.permissions?.setPermissions, setVerificationKey: a.permissions?.setVerificationKey?.auth,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** Why a contract isn't a genuine, locked LicensingApp, or null. */
|
|
57
|
+
export function contractProblem(c) {
|
|
58
|
+
if (!c.found || !c.root)
|
|
59
|
+
return 'no zkApp at this address on this network';
|
|
60
|
+
if (!c.vkHash || !Object.values(CANONICAL_VK_HASHES).includes(c.vkHash))
|
|
61
|
+
return 'the contract is not a published LicensingApp release (verification key)';
|
|
62
|
+
if (c.editState !== 'Proof')
|
|
63
|
+
return 'the contract state can be changed without a proof';
|
|
64
|
+
if (c.setVerificationKey !== 'Impossible')
|
|
65
|
+
return 'the contract\'s verification key can be replaced';
|
|
66
|
+
if (c.setPermissions !== 'Impossible')
|
|
67
|
+
return 'the contract\'s permissions can be changed';
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
/** Addresses to try, current generation first; null when no valid signed list. */
|
|
71
|
+
async function signedGenerations(base, address, f, pinned, network) {
|
|
72
|
+
try {
|
|
73
|
+
const r = await f(`${base}/apps/by-address/${encodeURIComponent(address)}`, { headers: { Accept: 'application/json' } });
|
|
74
|
+
if (!r.ok)
|
|
75
|
+
return null;
|
|
76
|
+
// Only the signed fields count (the keeper adds unsigned envelope fields after signing).
|
|
77
|
+
const b = await verifyManifest(await r.json(), pinned, { network });
|
|
78
|
+
if (!b)
|
|
79
|
+
return null;
|
|
80
|
+
const gens = b.generations.filter(g => typeof g.zkAppAddress === 'string');
|
|
81
|
+
if (!gens.some(g => g.zkAppAddress === address))
|
|
82
|
+
return null;
|
|
83
|
+
const current = gens.find(g => g.gen === b.current)?.zkAppAddress;
|
|
84
|
+
const others = gens.map(g => g.zkAppAddress).filter(a => a !== current && a !== address).reverse();
|
|
85
|
+
return [...new Set([current, address, ...others].filter((a) => !!a))];
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Folds the keeper's leaf fields and path; the on-chain root decides. */
|
|
92
|
+
async function foldsTo(w, licenseHash, root) {
|
|
93
|
+
const { Field, UInt32 } = await import('o1js');
|
|
94
|
+
const { LicenseLeaf, leafHash } = await import('./licenseLeaf.js');
|
|
95
|
+
const { deserializeWitness } = await import('./licenseStore.js');
|
|
96
|
+
const leafValue = w.currentValue === '0'
|
|
97
|
+
? Field(0)
|
|
98
|
+
: leafHash(new LicenseLeaf({
|
|
99
|
+
licenseHash: Field(licenseHash), expirySlot: UInt32.from(w.leaf.expirySlot), cap: UInt32.from(w.leaf.deviceCap),
|
|
100
|
+
deviceSlotsRoot: Field(w.leaf.deviceSlotsRoot), deviceSlotsFilled: UInt32.from(w.leaf.deviceSlotsFilled),
|
|
101
|
+
}));
|
|
102
|
+
const [computedRoot, key] = deserializeWitness({ isLefts: w.isLefts, siblings: w.siblings }).computeRootAndKey(leafValue);
|
|
103
|
+
return key.toString() === Field(licenseHash).toString() && computedRoot.toString() === root;
|
|
104
|
+
}
|
|
105
|
+
export async function verifyLicenseTrustless(opts) {
|
|
106
|
+
const f = opts.fetcher ?? fetch;
|
|
107
|
+
const base = opts.keeperUrl.replace(/\/+$/, '');
|
|
108
|
+
const graphqlUrl = opts.graphqlUrl ?? DEFAULT_MINA_GRAPHQL_URLS[opts.network];
|
|
109
|
+
if (!/^\d{1,80}$/.test(opts.licenseHash))
|
|
110
|
+
throw new AgentError('licenseHash must be a decimal field element', 'INVALID_REQUEST', 0, false);
|
|
111
|
+
const signed = await signedGenerations(base, opts.zkAppAddress, f, opts.pinnedPublicKeysBase64 ?? PLATFORM_MANIFEST_PUBKEYS, opts.network);
|
|
112
|
+
// The chain names the current generation too: a retired contract stores
|
|
113
|
+
// its successor. One found there goes first, so a missing or stale list
|
|
114
|
+
// still finds it.
|
|
115
|
+
let current;
|
|
116
|
+
try {
|
|
117
|
+
current = (await currentOnChain({ start: opts.zkAppAddress, layout: LICENSING_LINEAGE, canonicalVks: Object.values(CANONICAL_VK_HASHES), graphqlUrl, fetcher: f })).address;
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
if (e instanceof MinaNodeError)
|
|
121
|
+
throw new AgentError(e.message, 'UPSTREAM_UNAVAILABLE', e.status, true);
|
|
122
|
+
return result({ valid: false, reason: `Not a genuine licensing lineage: ${e?.message ?? e}` }, opts.zkAppAddress, null, 0, signed);
|
|
123
|
+
}
|
|
124
|
+
const listed = signed ?? [opts.zkAppAddress];
|
|
125
|
+
const addresses = current === opts.zkAppAddress ? listed : [...new Set([current, ...listed])];
|
|
126
|
+
let last = null;
|
|
127
|
+
for (const address of addresses) {
|
|
128
|
+
const c = await readContract(address, graphqlUrl, f);
|
|
129
|
+
const problem = contractProblem(c);
|
|
130
|
+
if (problem) {
|
|
131
|
+
// The address asked about must be genuine; a broken other generation is skipped.
|
|
132
|
+
if (address === opts.zkAppAddress) {
|
|
133
|
+
return result({ valid: false, reason: `Not a genuine licensing contract: ${problem}` }, address, null, c.slot, signed);
|
|
134
|
+
}
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const generation = Number(Object.entries(CANONICAL_VK_HASHES).find(([, h]) => h === c.vkHash)[0]);
|
|
138
|
+
let w = null;
|
|
139
|
+
let ok = false;
|
|
140
|
+
// The keeper may be a block or two behind a fresh purchase: one more read.
|
|
141
|
+
for (let attempt = 0; attempt < 2 && !ok; attempt++) {
|
|
142
|
+
if (attempt > 0)
|
|
143
|
+
await new Promise(r => setTimeout(r, opts.retryDelayMs ?? 3000));
|
|
144
|
+
const r = await f(`${base}/witness/${encodeURIComponent(address)}/${encodeURIComponent(opts.licenseHash)}?network=${opts.network}`, { headers: { Accept: 'application/json' } }).catch(() => null);
|
|
145
|
+
if (!r?.ok)
|
|
146
|
+
continue;
|
|
147
|
+
w = await r.json().catch(() => null);
|
|
148
|
+
if (w && Array.isArray(w.isLefts) && Array.isArray(w.siblings) && w.leaf)
|
|
149
|
+
ok = await foldsTo(w, opts.licenseHash, c.root);
|
|
150
|
+
}
|
|
151
|
+
if (!ok || !w) {
|
|
152
|
+
throw new AgentError(`The keeper's copy of ${address} does not match the chain (it may be catching up); retry, or check without trustless`, 'STATE_MISMATCH', 0, true, 10_000);
|
|
153
|
+
}
|
|
154
|
+
last = { address, generation, slot: c.slot };
|
|
155
|
+
if (w.currentValue === '0')
|
|
156
|
+
continue; // proved absent here: try the next generation
|
|
157
|
+
const expirySlot = w.leaf.expirySlot;
|
|
158
|
+
// A license that lapsed during the pre-fork sales freeze counts from the fork slot.
|
|
159
|
+
const until = effectiveExpirySlot(expirySlot, c.forkSlot ?? 0);
|
|
160
|
+
const inGracePeriod = c.slot > until && c.slot <= until + GRACE_PERIOD_N;
|
|
161
|
+
const expired = c.slot > until + GRACE_PERIOD_N;
|
|
162
|
+
return result({
|
|
163
|
+
valid: !expired,
|
|
164
|
+
expirySlot,
|
|
165
|
+
inGracePeriod: !expired && inGracePeriod,
|
|
166
|
+
expiresAt: new Date(Date.now() + (until - c.slot) * MS_PER_SLOT_N).toISOString(),
|
|
167
|
+
remainingDays: Math.floor((until - c.slot) / SLOTS_PER_DAY_N),
|
|
168
|
+
reason: expired ? 'License has expired' : inGracePeriod ? 'License is in grace period — renew to avoid interruption' : null,
|
|
169
|
+
}, address, generation, c.slot, signed);
|
|
170
|
+
}
|
|
171
|
+
return result({ valid: false, reason: 'License not found on chain (never bought at this app, or refunded)' }, last?.address ?? opts.zkAppAddress, last?.generation ?? null, last?.slot ?? 0, signed);
|
|
172
|
+
}
|
|
173
|
+
function result(r, address, generation, slot, signed) {
|
|
174
|
+
return {
|
|
175
|
+
valid: r.valid, expiresAt: r.expiresAt ?? null, expirySlot: r.expirySlot ?? 0, inGracePeriod: r.inGracePeriod ?? false,
|
|
176
|
+
remainingDays: r.remainingDays ?? 0, reason: r.reason, trustless: true,
|
|
177
|
+
resolvedAddress: address, generation, slot, generations: signed ? 'verified' : 'given-address-only',
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=licenseTrustless.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"licenseTrustless.js","sourceRoot":"","sources":["../src/licenseTrustless.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Browser + Node Ed25519 signature verification for platform-signed manifests
|
|
5
5
|
* (currently: the generation-list served at GET /apps/:appId, next: the
|
|
6
|
-
* sales-freeze manifest). The
|
|
6
|
+
* sales-freeze manifest). The backend signs with the platform manifest key
|
|
7
7
|
* loaded via PLATFORM_MANIFEST_KEY_FILE; the SDK pins the public key against
|
|
8
8
|
* a caller-supplied allow-list and verifies before trusting anything.
|
|
9
9
|
*
|
|
@@ -27,4 +27,32 @@ export declare function canonicalize(value: unknown): string;
|
|
|
27
27
|
* as "do not trust."
|
|
28
28
|
*/
|
|
29
29
|
export declare function verifyManifestSignature(payload: unknown, signatureBase64: string, pinnedPublicKeysBase64: readonly string[]): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* The fields the platform signs in an app's generation manifest (GET
|
|
32
|
+
* /apps/:appId, and the vendor's /.well-known/zklicensing/<address>.json).
|
|
33
|
+
* The keeper adds envelope fields after signing (signature, publicKey, app,
|
|
34
|
+
* forkActivationSlot…), so verifiers rebuild exactly these. `network` keeps a
|
|
35
|
+
* devnet manifest from passing for mainnet and the other way round.
|
|
36
|
+
*/
|
|
37
|
+
export type SignedManifest = {
|
|
38
|
+
appId: string;
|
|
39
|
+
network: 'devnet' | 'mainnet';
|
|
40
|
+
current: number;
|
|
41
|
+
generations: unknown[];
|
|
42
|
+
issuedAt: string;
|
|
43
|
+
};
|
|
44
|
+
/** The signed fields of a manifest body, or null when any is missing. */
|
|
45
|
+
export declare function signedManifestOf(body: unknown): SignedManifest | null;
|
|
46
|
+
/**
|
|
47
|
+
* Every signature a manifest carries: `signature`, and `signatures` (one per
|
|
48
|
+
* platform key; during a key rotation both the old and the new key sign).
|
|
49
|
+
*/
|
|
50
|
+
export declare function manifestSignaturesOf(body: unknown): string[];
|
|
51
|
+
/**
|
|
52
|
+
* The signed manifest in `body` when one of its signatures verifies against
|
|
53
|
+
* a pinned key (and it is for `expect.network`, when given); else null.
|
|
54
|
+
*/
|
|
55
|
+
export declare function verifyManifest(body: unknown, pinnedPublicKeysBase64: readonly string[], expect?: {
|
|
56
|
+
network?: 'devnet' | 'mainnet';
|
|
57
|
+
}): Promise<SignedManifest | null>;
|
|
30
58
|
//# sourceMappingURL=manifestVerify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifestVerify.d.ts","sourceRoot":"","sources":["../src/manifestVerify.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQnD;AA6BD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,EACvB,sBAAsB,EAAE,SAAS,MAAM,EAAE,GACxC,OAAO,CAAC,OAAO,CAAC,CA+BlB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAMrE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAK5D;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,OAAO,EACb,sBAAsB,EAAE,SAAS,MAAM,EAAE,EACzC,MAAM,GAAE;IAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CAAO,GAC9C,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQhC"}
|
package/build/manifestVerify.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
-
//
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
3
|
/**
|
|
4
4
|
* manifestVerify.ts
|
|
5
5
|
*
|
|
6
6
|
* Browser + Node Ed25519 signature verification for platform-signed manifests
|
|
7
7
|
* (currently: the generation-list served at GET /apps/:appId, next: the
|
|
8
|
-
* sales-freeze manifest). The
|
|
8
|
+
* sales-freeze manifest). The backend signs with the platform manifest key
|
|
9
9
|
* loaded via PLATFORM_MANIFEST_KEY_FILE; the SDK pins the public key against
|
|
10
10
|
* a caller-supplied allow-list and verifies before trusting anything.
|
|
11
11
|
*
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
* simple and mirrored.
|
|
22
22
|
*/
|
|
23
23
|
// Canonical JSON: sorted keys, no whitespace, arrays preserved in order.
|
|
24
|
+
// Undefined values are skipped, mirroring JSON.stringify — otherwise the
|
|
25
|
+
// signed bytes would contain `"key":undefined` for optional fields left
|
|
26
|
+
// unset, while `res.json()` on the wire would strip them, and the signature
|
|
27
|
+
// would never verify.
|
|
24
28
|
// Mirror of src/manifestSign.ts:canonicalize. Divergence here silently
|
|
25
29
|
// breaks verification.
|
|
26
30
|
export function canonicalize(value) {
|
|
@@ -28,8 +32,9 @@ export function canonicalize(value) {
|
|
|
28
32
|
return JSON.stringify(value);
|
|
29
33
|
if (Array.isArray(value))
|
|
30
34
|
return '[' + value.map(canonicalize).join(',') + ']';
|
|
31
|
-
const
|
|
32
|
-
|
|
35
|
+
const obj = value;
|
|
36
|
+
const keys = Object.keys(obj).filter(k => obj[k] !== undefined).sort();
|
|
37
|
+
return '{' + keys.map(k => JSON.stringify(k) + ':' + canonicalize(obj[k])).join(',') + '}';
|
|
33
38
|
}
|
|
34
39
|
function base64ToBytes(b64) {
|
|
35
40
|
// atob is present in every modern JS runtime we target (browser + Node ≥ 16).
|
|
@@ -92,4 +97,41 @@ export async function verifyManifestSignature(payload, signatureBase64, pinnedPu
|
|
|
92
97
|
}
|
|
93
98
|
return false;
|
|
94
99
|
}
|
|
100
|
+
/** The signed fields of a manifest body, or null when any is missing. */
|
|
101
|
+
export function signedManifestOf(body) {
|
|
102
|
+
if (!body || typeof body !== 'object')
|
|
103
|
+
return null;
|
|
104
|
+
const b = body;
|
|
105
|
+
if (typeof b.appId !== 'string' || (b.network !== 'devnet' && b.network !== 'mainnet') || typeof b.current !== 'number'
|
|
106
|
+
|| !Array.isArray(b.generations) || typeof b.issuedAt !== 'string')
|
|
107
|
+
return null;
|
|
108
|
+
return { appId: b.appId, network: b.network, current: b.current, generations: b.generations, issuedAt: b.issuedAt };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Every signature a manifest carries: `signature`, and `signatures` (one per
|
|
112
|
+
* platform key; during a key rotation both the old and the new key sign).
|
|
113
|
+
*/
|
|
114
|
+
export function manifestSignaturesOf(body) {
|
|
115
|
+
if (!body || typeof body !== 'object')
|
|
116
|
+
return [];
|
|
117
|
+
const b = body;
|
|
118
|
+
const list = Array.isArray(b.signatures) ? b.signatures.map((s) => s?.signature).filter((s) => typeof s === 'string') : [];
|
|
119
|
+
return [...new Set([...(typeof b.signature === 'string' ? [b.signature] : []), ...list])];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The signed manifest in `body` when one of its signatures verifies against
|
|
123
|
+
* a pinned key (and it is for `expect.network`, when given); else null.
|
|
124
|
+
*/
|
|
125
|
+
export async function verifyManifest(body, pinnedPublicKeysBase64, expect = {}) {
|
|
126
|
+
const payload = signedManifestOf(body);
|
|
127
|
+
if (!payload)
|
|
128
|
+
return null;
|
|
129
|
+
if (expect.network && payload.network !== expect.network)
|
|
130
|
+
return null;
|
|
131
|
+
for (const sig of manifestSignaturesOf(body)) {
|
|
132
|
+
if (await verifyManifestSignature(payload, sig, pinnedPublicKeysBase64))
|
|
133
|
+
return payload;
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
95
137
|
//# sourceMappingURL=manifestVerify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifestVerify.js","sourceRoot":"","sources":["../src/manifestVerify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type HistoricalRate = {
|
|
2
|
+
eur: number;
|
|
3
|
+
usd: number;
|
|
4
|
+
gbp: number;
|
|
5
|
+
};
|
|
6
|
+
export declare function slotToUtcDate(slot: number, currentSlot: number, nowMs: number): string;
|
|
7
|
+
export declare function getMinaFiatForDate(iso: string): Promise<HistoricalRate | null>;
|
|
8
|
+
export declare function _resetForTests(): void;
|
|
9
|
+
//# sourceMappingURL=minaPriceHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"minaPriceHistory.d.ts","sourceRoot":"","sources":["../src/minaPriceHistory.ts"],"names":[],"mappings":"AAsCA,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAKF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAItF;AAmED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAmCpF;AAKD,wBAAgB,cAAc,IAAI,IAAI,CAOrC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
/**
|
|
4
|
+
* minaPriceHistory.ts
|
|
5
|
+
*
|
|
6
|
+
* Historical MINA→fiat lookups for archive-replayed license records that were
|
|
7
|
+
* created before the backend had a live CoinGecko cache. Uses CoinGecko's
|
|
8
|
+
* free-tier `/coins/mina-protocol/history?date=DD-MM-YYYY` endpoint, which
|
|
9
|
+
* returns a UTC end-of-day snapshot in a single call. Rates for a past day
|
|
10
|
+
* never change, so results are cached permanently to a JSON file — a repeat
|
|
11
|
+
* bootstrap replays without another HTTP round-trip.
|
|
12
|
+
*
|
|
13
|
+
* Not used by live purchase / renew flows — those keep hitting the 5-minute
|
|
14
|
+
* `/simple/price` cache in keeperService.ts. Only invoked by the backfill
|
|
15
|
+
* pass that stamps historical `fiatSnapshot` after archive replay.
|
|
16
|
+
*/
|
|
17
|
+
import fs from 'fs/promises';
|
|
18
|
+
// Mina consensus slot is 3 min in theory; on-chain block time targets 90s.
|
|
19
|
+
// The stats module uses the same constant for its monthly aggregation
|
|
20
|
+
// (stats.ts:25). Any drift here shows up as records stamped with the wrong
|
|
21
|
+
// day's rate for events near the UTC midnight boundary.
|
|
22
|
+
const SLOT_DURATION_MS = 90 * 1000;
|
|
23
|
+
// CoinGecko free-tier is ~30 req/min. A 1.5s spacing keeps us comfortably
|
|
24
|
+
// under that for a single-tenant backend backfill; if a very large replay ever
|
|
25
|
+
// hits the limit CoinGecko returns 429 and getMinaFiatForDate returns null,
|
|
26
|
+
// leaving that day's records unstamped (dashboards render fiat as `—`).
|
|
27
|
+
const THROTTLE_MS = 1500;
|
|
28
|
+
// Days for which CoinGecko returned no usable data. Kept in-memory only —
|
|
29
|
+
// they don't get written to the on-disk cache so a follow-up bootstrap after
|
|
30
|
+
// e.g. a CoinGecko outage will retry them. Guards against re-hitting the
|
|
31
|
+
// endpoint for the same missing date within one process lifetime.
|
|
32
|
+
const missingDates = new Set();
|
|
33
|
+
// Convert a Mina global slot to a UTC calendar date (YYYY-MM-DD). Uses the
|
|
34
|
+
// per-network (currentSlot, nowMs) pair as the anchor so caller can pass the
|
|
35
|
+
// clock captured at bootstrap time. Same trick stats.ts:slotToMonthKey uses.
|
|
36
|
+
export function slotToUtcDate(slot, currentSlot, nowMs) {
|
|
37
|
+
const ms = nowMs - (currentSlot - slot) * SLOT_DURATION_MS;
|
|
38
|
+
const d = new Date(ms);
|
|
39
|
+
return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;
|
|
40
|
+
}
|
|
41
|
+
function isoToCoinGeckoDate(iso) {
|
|
42
|
+
const [y, m, d] = iso.split('-');
|
|
43
|
+
return `${d}-${m}-${y}`;
|
|
44
|
+
}
|
|
45
|
+
function cachePath() {
|
|
46
|
+
return process.env.MINA_PRICE_CACHE_PATH ?? 'mina-prices.json';
|
|
47
|
+
}
|
|
48
|
+
let cache = null;
|
|
49
|
+
let cacheLoaded = false;
|
|
50
|
+
async function loadCache() {
|
|
51
|
+
if (cacheLoaded && cache)
|
|
52
|
+
return cache;
|
|
53
|
+
try {
|
|
54
|
+
const raw = await fs.readFile(cachePath(), 'utf8');
|
|
55
|
+
const parsed = JSON.parse(raw);
|
|
56
|
+
if (parsed && typeof parsed === 'object') {
|
|
57
|
+
cache = parsed;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
cache = {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
cache = {};
|
|
65
|
+
}
|
|
66
|
+
cacheLoaded = true;
|
|
67
|
+
return cache;
|
|
68
|
+
}
|
|
69
|
+
// Serialize cache writes so concurrent stamping calls don't clobber each
|
|
70
|
+
// other's entries. Every write flushes the whole file — tiny (< 10KB even
|
|
71
|
+
// for years of dates) so no need for anything fancier.
|
|
72
|
+
let writeChain = Promise.resolve();
|
|
73
|
+
function withWriteLock(fn) {
|
|
74
|
+
const result = writeChain.then(fn, fn);
|
|
75
|
+
writeChain = result.then(() => { }, () => { });
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
async function persistCache() {
|
|
79
|
+
if (!cache)
|
|
80
|
+
return;
|
|
81
|
+
await fs.writeFile(cachePath(), JSON.stringify(cache, null, 2));
|
|
82
|
+
}
|
|
83
|
+
// Serialize the outbound HTTP calls so we respect CoinGecko's rate limit
|
|
84
|
+
// without a global scheduler. Concurrent callers of getMinaFiatForDate for
|
|
85
|
+
// distinct dates queue up 1.5s apart.
|
|
86
|
+
let lastFetchAt = 0;
|
|
87
|
+
let fetchChain = Promise.resolve();
|
|
88
|
+
function throttled(fn) {
|
|
89
|
+
const next = fetchChain.then(async () => {
|
|
90
|
+
const wait = Math.max(0, THROTTLE_MS - (Date.now() - lastFetchAt));
|
|
91
|
+
if (wait > 0)
|
|
92
|
+
await new Promise(r => setTimeout(r, wait));
|
|
93
|
+
lastFetchAt = Date.now();
|
|
94
|
+
});
|
|
95
|
+
fetchChain = next.then(() => { }, () => { });
|
|
96
|
+
return next.then(fn);
|
|
97
|
+
}
|
|
98
|
+
// Return { eur, usd, gbp } for the given UTC calendar date, or null if the
|
|
99
|
+
// endpoint fails or omits any of the three currencies. Cached results are
|
|
100
|
+
// returned immediately. Fail-soft: no exceptions, just null → caller leaves
|
|
101
|
+
// the record unstamped.
|
|
102
|
+
export async function getMinaFiatForDate(iso) {
|
|
103
|
+
const c = await loadCache();
|
|
104
|
+
if (c[iso])
|
|
105
|
+
return c[iso];
|
|
106
|
+
if (missingDates.has(iso))
|
|
107
|
+
return null;
|
|
108
|
+
const cgDate = isoToCoinGeckoDate(iso);
|
|
109
|
+
const url = `https://api.coingecko.com/api/v3/coins/mina-protocol/history?date=${cgDate}&localization=false`;
|
|
110
|
+
try {
|
|
111
|
+
const r = await throttled(() => fetch(url));
|
|
112
|
+
if (!r.ok) {
|
|
113
|
+
missingDates.add(iso);
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const d = await r.json();
|
|
117
|
+
const px = d?.market_data?.current_price;
|
|
118
|
+
const eur = px?.eur;
|
|
119
|
+
const usd = px?.usd;
|
|
120
|
+
const gbp = px?.gbp;
|
|
121
|
+
const eurOk = typeof eur === 'number' && Number.isFinite(eur) && eur > 0;
|
|
122
|
+
const usdOk = typeof usd === 'number' && Number.isFinite(usd) && usd > 0;
|
|
123
|
+
const gbpOk = typeof gbp === 'number' && Number.isFinite(gbp) && gbp > 0;
|
|
124
|
+
if (!eurOk || !usdOk || !gbpOk) {
|
|
125
|
+
missingDates.add(iso);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const rate = { eur: eur, usd: usd, gbp: gbp };
|
|
129
|
+
await withWriteLock(async () => {
|
|
130
|
+
const cc = await loadCache();
|
|
131
|
+
cc[iso] = rate;
|
|
132
|
+
await persistCache();
|
|
133
|
+
});
|
|
134
|
+
return rate;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
missingDates.add(iso);
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Test-only: reset in-process state so unit tests can exercise fresh cache
|
|
142
|
+
// misses without cross-contamination. Not exported through the SDK's public
|
|
143
|
+
// entry points.
|
|
144
|
+
export function _resetForTests() {
|
|
145
|
+
cache = null;
|
|
146
|
+
cacheLoaded = false;
|
|
147
|
+
missingDates.clear();
|
|
148
|
+
lastFetchAt = 0;
|
|
149
|
+
fetchChain = Promise.resolve();
|
|
150
|
+
writeChain = Promise.resolve();
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=minaPriceHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"minaPriceHistory.js","sourceRoot":"","sources":["../src/minaPriceHistory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* onChainRoot.ts
|
|
3
|
+
*
|
|
4
|
+
* Non-custodial trust anchor for `verifyOffline`. Reads the live
|
|
5
|
+
* `licensesRoot` (`zkapp.appState[0]`) directly from Mina — no
|
|
6
|
+
* licensing-service round-trip, no trust assumption about whoever
|
|
7
|
+
* served the witness / license record.
|
|
8
|
+
*
|
|
9
|
+
* Pair it with `verifyOffline` to close the trust loop:
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { fetchOnChainLicensesRoot } from 'zklicensing/on-chain-root';
|
|
13
|
+
* import { verifyOffline } from 'zklicensing/verify-offline';
|
|
14
|
+
*
|
|
15
|
+
* // 1. Ask the licensing service for a witness + slot snapshot.
|
|
16
|
+
* const snap = await fetch(`${service}/witness?licenseHash=${h}&zkAppAddress=${a}`).then(r => r.json());
|
|
17
|
+
*
|
|
18
|
+
* // 2. Fetch the on-chain root INDEPENDENTLY, from Mina.
|
|
19
|
+
* const onChainRoot = await fetchOnChainLicensesRoot({ zkAppAddress: a, network: 'devnet' });
|
|
20
|
+
*
|
|
21
|
+
* // 3. Cross-check — if they disagree, the service is stale/wrong; bail.
|
|
22
|
+
* if (snap.root !== onChainRoot) throw new Error('service root disagrees with chain');
|
|
23
|
+
*
|
|
24
|
+
* // 4. Fold-verify the snapshot against the on-chain root.
|
|
25
|
+
* const res = verifyOffline({ licensesRoot: onChainRoot, ...snap });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* The read goes to the node's GraphQL API directly: no o1js is needed
|
|
29
|
+
* and o1js's global Mina instance is never touched, so it is safe in
|
|
30
|
+
* long-lived hosts that talk to several networks.
|
|
31
|
+
*/
|
|
32
|
+
export declare const DEFAULT_MINA_GRAPHQL_URLS: {
|
|
33
|
+
readonly mainnet: "https://api.minascan.io/node/mainnet/v1/graphql";
|
|
34
|
+
readonly devnet: "https://devnet-plain-1.gcp.o1test.net/graphql";
|
|
35
|
+
};
|
|
36
|
+
export type NetworkName = 'mainnet' | 'devnet';
|
|
37
|
+
export type FetchOnChainLicensesRootInput = {
|
|
38
|
+
/** B62q… address of the deployed LicensingApp for this app. */
|
|
39
|
+
zkAppAddress: string;
|
|
40
|
+
} & ({
|
|
41
|
+
network: NetworkName;
|
|
42
|
+
graphqlUrl?: string;
|
|
43
|
+
} | {
|
|
44
|
+
graphqlUrl: string;
|
|
45
|
+
network?: NetworkName;
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Read the live `licensesRoot` from the deployed LicensingApp's
|
|
49
|
+
* on-chain state. Returns the field value as a decimal string,
|
|
50
|
+
* matching the shape `verifyOffline` and the licensing service both
|
|
51
|
+
* consume.
|
|
52
|
+
*
|
|
53
|
+
* Throws on any of:
|
|
54
|
+
* - `fetchAccount` returned an error (network down, wrong endpoint,
|
|
55
|
+
* account doesn't exist on this chain);
|
|
56
|
+
* - account exists but has no zkApp state (not a zkApp address, or
|
|
57
|
+
* contract deployed but `initialize()` never ran).
|
|
58
|
+
*/
|
|
59
|
+
export declare function fetchOnChainLicensesRoot(input: FetchOnChainLicensesRootInput): Promise<string>;
|
|
60
|
+
//# sourceMappingURL=onChainRoot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onChainRoot.d.ts","sourceRoot":"","sources":["../src/onChainRoot.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAOH,eAAO,MAAM,yBAAyB;;;CAG5B,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/C,MAAM,MAAM,6BAA6B,GAAG;IAC1C,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,CACA;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,WAAW,CAAA;CAAE,CAChD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
|