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,572 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* permitMessages.ts — `zklicensing/permits/messages`
|
|
6
|
+
*
|
|
7
|
+
* The single definition of everything signed or hashed for zkPermits: the
|
|
8
|
+
* permit leaf, subject derivation, packed fees and policy, the authority
|
|
9
|
+
* key-set commitment, and the message each signer signs. The PermitRegistry
|
|
10
|
+
* circuit imports this module, so an off-chain signature (authority console,
|
|
11
|
+
* operator page, agent) always hashes to exactly what the circuit verifies.
|
|
12
|
+
* Test vectors: permitMessages.vectors.json.
|
|
13
|
+
*
|
|
14
|
+
* Every function works both off-chain and inside a circuit (o1js types
|
|
15
|
+
* only). Messages are short Field arrays; wallets sign them with
|
|
16
|
+
* `signFields` (Auro, WalletConnect `mina_signFields`), and o1js
|
|
17
|
+
* `Signature.verify` accepts those signatures in-circuit.
|
|
18
|
+
*
|
|
19
|
+
* Wallet field signatures are NOT bound to a network by the signer, so
|
|
20
|
+
* every message carries the network, the registry address and a
|
|
21
|
+
* per-message nonce itself (see `authorityMessage`).
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { Bool, Field, Poseidon, PrivateKey, Provable, PublicKey, Signature, Struct, UInt32, UInt64 } from 'o1js';
|
|
25
|
+
|
|
26
|
+
// ------------------------------------------------------------
|
|
27
|
+
// Domain separation
|
|
28
|
+
// ------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
/** Deterministic Field from a short ASCII label (≤ 31 bytes). */
|
|
31
|
+
function labelField(label: string): Field {
|
|
32
|
+
if (label.length > 31) throw new Error(`label too long: ${label}`);
|
|
33
|
+
let v = 0n;
|
|
34
|
+
for (const ch of label) {
|
|
35
|
+
const c = ch.charCodeAt(0);
|
|
36
|
+
if (c > 0x7f) throw new Error('ASCII labels only');
|
|
37
|
+
v = (v << 8n) | BigInt(c);
|
|
38
|
+
}
|
|
39
|
+
return Field(v);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** One tag per message type. Never reuse or renumber. */
|
|
43
|
+
export const PERMIT_TAGS: Readonly<Record<
|
|
44
|
+
'INIT' | 'GRANT' | 'ACCEPT' | 'SUSPEND' | 'REINSTATE' | 'REVOKE' | 'SURRENDER' | 'SET_FEES' | 'ROTATE' | 'LEAF' | 'SUBJECT' | 'KEYS'
|
|
45
|
+
| 'APPLICATION' | 'APPLY' | 'APPROVE' | 'REJECT' | 'WITHDRAW' | 'RETIRE' | 'PLATFORM_RETIRE' | 'PLATFORM_CANCEL'
|
|
46
|
+
| 'PAYOUT' | 'PAYOUT_CANCEL' | 'REKEY',
|
|
47
|
+
Field
|
|
48
|
+
>> = {
|
|
49
|
+
INIT: labelField('zkPermits/v1/init'),
|
|
50
|
+
GRANT: labelField('zkPermits/v1/grant'),
|
|
51
|
+
ACCEPT: labelField('zkPermits/v1/accept'),
|
|
52
|
+
SUSPEND: labelField('zkPermits/v1/suspend'),
|
|
53
|
+
REINSTATE: labelField('zkPermits/v1/reinstate'),
|
|
54
|
+
REVOKE: labelField('zkPermits/v1/revoke'),
|
|
55
|
+
SURRENDER: labelField('zkPermits/v1/surrender'),
|
|
56
|
+
SET_FEES: labelField('zkPermits/v1/setFees'),
|
|
57
|
+
ROTATE: labelField('zkPermits/v1/rotate'),
|
|
58
|
+
LEAF: labelField('zkPermits/v1/leaf'),
|
|
59
|
+
SUBJECT: labelField('zkPermits/v1/subject'),
|
|
60
|
+
KEYS: labelField('zkPermits/v1/keys'),
|
|
61
|
+
// Application escrow (PERMITS_PLAN.md §4.2).
|
|
62
|
+
APPLICATION: labelField('zkPermits/v1/application'),
|
|
63
|
+
APPLY: labelField('zkPermits/v1/apply'),
|
|
64
|
+
APPROVE: labelField('zkPermits/v1/approve'),
|
|
65
|
+
REJECT: labelField('zkPermits/v1/reject'),
|
|
66
|
+
WITHDRAW: labelField('zkPermits/v1/withdraw'),
|
|
67
|
+
// Generations: the authority retires a registry before redeploying it.
|
|
68
|
+
RETIRE: labelField('zkPermits/v1/retire'),
|
|
69
|
+
// ... or the platform does (one signature by the platform key).
|
|
70
|
+
PLATFORM_RETIRE: labelField('zkPermits/v1/platformRetire'),
|
|
71
|
+
// Before retiring, the platform may cancel an open application (full refund).
|
|
72
|
+
PLATFORM_CANCEL: labelField('zkPermits/v1/platformCancel'),
|
|
73
|
+
// Key changes: a new payout address (threshold, after a delay), a permit moving to a new holder key.
|
|
74
|
+
PAYOUT: labelField('zkPermits/v1/payout'),
|
|
75
|
+
PAYOUT_CANCEL: labelField('zkPermits/v1/payoutCancel'),
|
|
76
|
+
REKEY: labelField('zkPermits/v1/rekey'),
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** Network in signed messages. 0 is never valid. */
|
|
80
|
+
export const PERMIT_NETWORK: Readonly<{ devnet: Field; mainnet: Field }> = { devnet: Field(1), mainnet: Field(2) };
|
|
81
|
+
export type PermitNetwork = keyof typeof PERMIT_NETWORK;
|
|
82
|
+
|
|
83
|
+
export function networkField(network: PermitNetwork): Field {
|
|
84
|
+
const f = PERMIT_NETWORK[network];
|
|
85
|
+
if (!f) throw new Error(`unknown network ${network}`);
|
|
86
|
+
return f;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ------------------------------------------------------------
|
|
90
|
+
// Permit leaf
|
|
91
|
+
// ------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
/** MOVED: the permit moved to a new holder key (rekeyPermit), under a new subject; this leaf is closed. */
|
|
94
|
+
export const PERMIT_STATUS = { ACTIVE: 0, SUSPENDED: 1, REVOKED: 2, MOVED: 3 } as const;
|
|
95
|
+
export const PERMIT_STATUS_ACTIVE = UInt32.from(0);
|
|
96
|
+
export const PERMIT_STATUS_SUSPENDED = UInt32.from(1);
|
|
97
|
+
export const PERMIT_STATUS_REVOKED = UInt32.from(2);
|
|
98
|
+
export const PERMIT_STATUS_MOVED = UInt32.from(3);
|
|
99
|
+
|
|
100
|
+
/** Expiry value meaning "does not expire" (only if the policy allows it). */
|
|
101
|
+
export const NO_EXPIRY_SLOT = UInt32.MAXINT();
|
|
102
|
+
|
|
103
|
+
// `const X: any = Struct(...)` — same pattern as licenseLeaf.ts: the inferred
|
|
104
|
+
// Struct class type references o1js internals outside this package's rootDir.
|
|
105
|
+
export const PermitLeaf: any = Struct({
|
|
106
|
+
subject: Field,
|
|
107
|
+
holderKey: PublicKey,
|
|
108
|
+
scope: Field,
|
|
109
|
+
validFrom: UInt32,
|
|
110
|
+
expirySlot: UInt32,
|
|
111
|
+
status: UInt32,
|
|
112
|
+
seq: UInt32,
|
|
113
|
+
docHash: Field,
|
|
114
|
+
});
|
|
115
|
+
export type PermitLeaf = any;
|
|
116
|
+
|
|
117
|
+
/** Hash stored in the permits MerkleMap. An empty map slot is Field(0). */
|
|
118
|
+
export function permitLeafHash(leaf: PermitLeaf): Field {
|
|
119
|
+
return Poseidon.hash([PERMIT_TAGS.LEAF, ...PermitLeaf.toFields(leaf)]);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Tree key of an operator: hides the key behind a salt. */
|
|
123
|
+
export function permitSubject(holderKey: PublicKey, salt: Field): Field {
|
|
124
|
+
return Poseidon.hash([PERMIT_TAGS.SUBJECT, ...holderKey.toFields(), salt]);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Leaf value for a subject that has never held a permit. */
|
|
128
|
+
export function emptyPermitLeaf(subject: Field): PermitLeaf {
|
|
129
|
+
return new PermitLeaf({
|
|
130
|
+
subject,
|
|
131
|
+
holderKey: PublicKey.empty(),
|
|
132
|
+
scope: Field(0),
|
|
133
|
+
validFrom: UInt32.zero,
|
|
134
|
+
expirySlot: UInt32.zero,
|
|
135
|
+
status: PERMIT_STATUS_ACTIVE,
|
|
136
|
+
seq: UInt32.zero,
|
|
137
|
+
docHash: Field(0),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ------------------------------------------------------------
|
|
142
|
+
// Packed fees and policy
|
|
143
|
+
// ------------------------------------------------------------
|
|
144
|
+
|
|
145
|
+
const TWO_64 = 1n << 64n;
|
|
146
|
+
|
|
147
|
+
export type PermitFees = { grantFee: UInt64; renewalFee: UInt64; minFee: UInt64 };
|
|
148
|
+
|
|
149
|
+
/** grantFee | renewalFee << 64 | minFee << 128 (nanomina). */
|
|
150
|
+
export function packFees(f: PermitFees): Field {
|
|
151
|
+
return f.grantFee.value
|
|
152
|
+
.add(f.renewalFee.value.mul(Field(TWO_64)))
|
|
153
|
+
.add(f.minFee.value.mul(Field(TWO_64 * TWO_64)));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Inverse of packFees; range-checks every part (safe in-circuit). */
|
|
157
|
+
export function unpackFees(packed: Field): PermitFees {
|
|
158
|
+
const bits = packed.toBits(192);
|
|
159
|
+
return {
|
|
160
|
+
grantFee: UInt64.Unsafe.fromField(Field.fromBits(bits.slice(0, 64))),
|
|
161
|
+
renewalFee: UInt64.Unsafe.fromField(Field.fromBits(bits.slice(64, 128))),
|
|
162
|
+
minFee: UInt64.Unsafe.fromField(Field.fromBits(bits.slice(128, 192))),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Default minimum permit fee: 10 MINA. Configurable per registry at initialize. */
|
|
167
|
+
export const DEFAULT_MIN_PERMIT_FEE = UInt64.from(10_000_000_000n);
|
|
168
|
+
|
|
169
|
+
/** Platform share of a fee: 2%, rounded down (rounding favours the authority). */
|
|
170
|
+
export const PERMIT_PLATFORM_FEE_BASIS = UInt64.from(50);
|
|
171
|
+
export function platformShare(fee: UInt64): UInt64 {
|
|
172
|
+
return fee.div(PERMIT_PLATFORM_FEE_BASIS);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export type PermitPolicy = {
|
|
176
|
+
gracePeriod: UInt32; // slots after expiry still reported as valid
|
|
177
|
+
maxTerm: UInt32; // max expirySlot - validFrom; 0 = unlimited
|
|
178
|
+
singleKeySuspend: Bool; // any one authority key may suspend
|
|
179
|
+
holderSigRequired: Bool; // grant needs the holder's countersignature
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/** gracePeriod | maxTerm << 32 | singleKeySuspend << 64 | holderSigRequired << 65 */
|
|
183
|
+
export function packPolicy(p: PermitPolicy): Field {
|
|
184
|
+
return p.gracePeriod.value
|
|
185
|
+
.add(p.maxTerm.value.mul(Field(1n << 32n)))
|
|
186
|
+
.add(p.singleKeySuspend.toField().mul(Field(1n << 64n)))
|
|
187
|
+
.add(p.holderSigRequired.toField().mul(Field(1n << 65n)));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function unpackPolicy(packed: Field): PermitPolicy {
|
|
191
|
+
const bits = packed.toBits(66);
|
|
192
|
+
return {
|
|
193
|
+
gracePeriod: UInt32.Unsafe.fromField(Field.fromBits(bits.slice(0, 32))),
|
|
194
|
+
maxTerm: UInt32.Unsafe.fromField(Field.fromBits(bits.slice(32, 64))),
|
|
195
|
+
singleKeySuspend: bits[64],
|
|
196
|
+
holderSigRequired: bits[65],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ------------------------------------------------------------
|
|
201
|
+
// Application terms
|
|
202
|
+
// ------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
export type ApplicationTerms = {
|
|
205
|
+
processingFee: UInt64; // kept on rejection or withdrawal (nanomina)
|
|
206
|
+
minProcessingFee: UInt64; // platform minimum, fixed for the generation
|
|
207
|
+
decisionWindow: UInt32; // slots from filing to the decision deadline
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/** processingFee | minProcessingFee << 64 | decisionWindow << 128 */
|
|
211
|
+
export function packApplicationTerms(t: ApplicationTerms): Field {
|
|
212
|
+
return t.processingFee.value
|
|
213
|
+
.add(t.minProcessingFee.value.mul(Field(TWO_64)))
|
|
214
|
+
.add(t.decisionWindow.value.mul(Field(TWO_64 * TWO_64)));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function unpackApplicationTerms(packed: Field): ApplicationTerms {
|
|
218
|
+
const bits = packed.toBits(160);
|
|
219
|
+
return {
|
|
220
|
+
processingFee: UInt64.Unsafe.fromField(Field.fromBits(bits.slice(0, 64))),
|
|
221
|
+
minProcessingFee: UInt64.Unsafe.fromField(Field.fromBits(bits.slice(64, 128))),
|
|
222
|
+
decisionWindow: UInt32.Unsafe.fromField(Field.fromBits(bits.slice(128, 160))),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Default minimum processing fee: 1 MINA. Configurable per registry at initialize. */
|
|
227
|
+
export const DEFAULT_MIN_PROCESSING_FEE = UInt64.from(1_000_000_000n);
|
|
228
|
+
/** Default decision window: 14 days of 90 s slots (as licensing's refund window). */
|
|
229
|
+
export const DEFAULT_DECISION_WINDOW = UInt32.from(13_440);
|
|
230
|
+
/** Longest decision window an authority may set: one year. */
|
|
231
|
+
export const MAX_DECISION_WINDOW = UInt32.from(350_640);
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* An application with its fee in escrow. Stored as `applicationHash` in the
|
|
235
|
+
* registry's escrow MerkleMap under `subject`; emitted in full when filed.
|
|
236
|
+
* `baseSeq` is the permit leaf's `seq` it applies to (0 = new permit);
|
|
237
|
+
* `fee` is the whole amount escrowed, `processingFee` the part kept on
|
|
238
|
+
* rejection or withdrawal; both are locked at filing. `filing` is the
|
|
239
|
+
* registry's filing number (its filingCount when filed), so two filings
|
|
240
|
+
* never share a hash and a signature settling one can't settle another.
|
|
241
|
+
*/
|
|
242
|
+
export const Application: any = Struct({
|
|
243
|
+
subject: Field,
|
|
244
|
+
holderKey: PublicKey,
|
|
245
|
+
payer: PublicKey,
|
|
246
|
+
baseSeq: UInt32,
|
|
247
|
+
scope: Field,
|
|
248
|
+
validFrom: UInt32,
|
|
249
|
+
expirySlot: UInt32,
|
|
250
|
+
docHash: Field,
|
|
251
|
+
fee: UInt64,
|
|
252
|
+
processingFee: UInt64,
|
|
253
|
+
deadline: UInt32,
|
|
254
|
+
filing: UInt32,
|
|
255
|
+
});
|
|
256
|
+
export type Application = any;
|
|
257
|
+
|
|
258
|
+
export function applicationHash(app: Application): Field {
|
|
259
|
+
return Poseidon.hash([PERMIT_TAGS.APPLICATION, ...Application.toFields(app)]);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* What the holder agrees to when applying: everything in the application
|
|
264
|
+
* except the payer (the transaction sender), the deadline (set by the
|
|
265
|
+
* contract from the filing slot) and the filing number (the registry's next).
|
|
266
|
+
*/
|
|
267
|
+
export function applicationTermsHash(app: Application): Field {
|
|
268
|
+
return Poseidon.hash([
|
|
269
|
+
PERMIT_TAGS.APPLICATION, app.subject, ...app.holderKey.toFields(), app.baseSeq.value, app.scope,
|
|
270
|
+
app.validFrom.value, app.expirySlot.value, app.docHash, app.fee.value, app.processingFee.value,
|
|
271
|
+
]);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** The permit leaf an approved application becomes. */
|
|
275
|
+
export function leafFromApplication(app: Application): PermitLeaf {
|
|
276
|
+
return new PermitLeaf({
|
|
277
|
+
subject: app.subject,
|
|
278
|
+
holderKey: app.holderKey,
|
|
279
|
+
scope: app.scope,
|
|
280
|
+
validFrom: app.validFrom,
|
|
281
|
+
expirySlot: app.expirySlot,
|
|
282
|
+
status: PERMIT_STATUS_ACTIVE,
|
|
283
|
+
seq: app.baseSeq.add(1),
|
|
284
|
+
docHash: app.docHash,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** Outcome codes in `applicationSettled` events. */
|
|
289
|
+
export const APPLICATION_OUTCOME = { APPROVED: 1, REJECTED: 2, WITHDRAWN: 3, RECLAIMED: 4, CANCELLED: 5 } as const;
|
|
290
|
+
|
|
291
|
+
// ------------------------------------------------------------
|
|
292
|
+
// Authority key set
|
|
293
|
+
// ------------------------------------------------------------
|
|
294
|
+
|
|
295
|
+
export const MAX_AUTHORITY_KEYS = 3;
|
|
296
|
+
|
|
297
|
+
// Fixed-length key set. `count` keys are in use (slots 0..count-1); unused
|
|
298
|
+
// slots hold PublicKey.empty() and never count toward a threshold, whatever
|
|
299
|
+
// signature is supplied for them.
|
|
300
|
+
export const AuthorityKeys: any = Struct({
|
|
301
|
+
keys: Provable.Array(PublicKey, MAX_AUTHORITY_KEYS),
|
|
302
|
+
count: UInt32,
|
|
303
|
+
threshold: UInt32,
|
|
304
|
+
});
|
|
305
|
+
export type AuthorityKeys = any;
|
|
306
|
+
|
|
307
|
+
export function authorityKeys(keys: PublicKey[], threshold: number): AuthorityKeys {
|
|
308
|
+
if (keys.length < 1 || keys.length > MAX_AUTHORITY_KEYS) throw new Error(`1..${MAX_AUTHORITY_KEYS} authority keys`);
|
|
309
|
+
if (!Number.isInteger(threshold) || threshold < 1 || threshold > keys.length) throw new Error('threshold must be 1..number of keys');
|
|
310
|
+
const b58 = keys.map(k => k.toBase58());
|
|
311
|
+
if (new Set(b58).size !== b58.length) throw new Error('authority keys must be distinct');
|
|
312
|
+
const padded = [...keys];
|
|
313
|
+
while (padded.length < MAX_AUTHORITY_KEYS) padded.push(PublicKey.empty());
|
|
314
|
+
return new AuthorityKeys({ keys: padded, count: UInt32.from(keys.length), threshold: UInt32.from(threshold) });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// One optional signature per key slot. `present[i]` false → slot i ignored.
|
|
318
|
+
export const AuthoritySigs: any = Struct({
|
|
319
|
+
sigs: Provable.Array(Signature, MAX_AUTHORITY_KEYS),
|
|
320
|
+
present: Provable.Array(Bool, MAX_AUTHORITY_KEYS),
|
|
321
|
+
});
|
|
322
|
+
export type AuthoritySigs = any;
|
|
323
|
+
|
|
324
|
+
// Placeholder for absent slots: a well-formed signature over an unrelated
|
|
325
|
+
// one-field message. Absent slots are never counted anyway.
|
|
326
|
+
let placeholder: Signature | null = null;
|
|
327
|
+
function placeholderSignature(): Signature {
|
|
328
|
+
placeholder ??= Signature.create(PrivateKey.fromBigInt(1n), [Field(0)]);
|
|
329
|
+
return placeholder;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** Builds the signature bundle from `{ slotIndex: signature }` (base58 or Signature). */
|
|
333
|
+
export function authoritySigs(bySlot: Record<number, Signature | string>): AuthoritySigs {
|
|
334
|
+
const sigs: Signature[] = [];
|
|
335
|
+
const present: Bool[] = [];
|
|
336
|
+
for (let i = 0; i < MAX_AUTHORITY_KEYS; i++) {
|
|
337
|
+
const s = bySlot[i];
|
|
338
|
+
if (s === undefined) { sigs.push(placeholderSignature()); present.push(Bool(false)); continue; }
|
|
339
|
+
sigs.push(typeof s === 'string' ? Signature.fromBase58(s) : s);
|
|
340
|
+
present.push(Bool(true));
|
|
341
|
+
}
|
|
342
|
+
return new AuthoritySigs({ sigs, present });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Number of valid signatures over `message` from distinct, in-use key
|
|
347
|
+
* slots. Works in-circuit. Absent or unused slots count zero; a present
|
|
348
|
+
* signature that doesn't verify also counts zero.
|
|
349
|
+
*/
|
|
350
|
+
export function countAuthoritySignatures(keys: AuthorityKeys, sigs: AuthoritySigs, message: Field[]): UInt32 {
|
|
351
|
+
let n = UInt32.zero;
|
|
352
|
+
for (let i = 0; i < MAX_AUTHORITY_KEYS; i++) {
|
|
353
|
+
const inUse = UInt32.from(i).lessThan(keys.count);
|
|
354
|
+
// An unused slot's key is PublicKey.empty(); verify against a real key
|
|
355
|
+
// instead so the check stays well-formed. The result is masked by inUse.
|
|
356
|
+
const key = Provable.if(inUse, PublicKey, keys.keys[i], keys.keys[0]);
|
|
357
|
+
const ok = sigs.sigs[i].verify(key, message);
|
|
358
|
+
const counted = inUse.and(sigs.present[i]).and(ok);
|
|
359
|
+
n = n.add(Provable.if(counted, UInt32.from(1), UInt32.zero));
|
|
360
|
+
}
|
|
361
|
+
return n;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* In-circuit validity of a key set: 1 ≤ count ≤ MAX, 1 ≤ threshold ≤ count,
|
|
366
|
+
* in-use keys pairwise distinct, unused slots empty.
|
|
367
|
+
*/
|
|
368
|
+
export function assertValidAuthorityKeys(keys: AuthorityKeys): void {
|
|
369
|
+
keys.count.assertGreaterThanOrEqual(UInt32.from(1));
|
|
370
|
+
keys.count.assertLessThanOrEqual(UInt32.from(MAX_AUTHORITY_KEYS));
|
|
371
|
+
keys.threshold.assertGreaterThanOrEqual(UInt32.from(1));
|
|
372
|
+
keys.threshold.assertLessThanOrEqual(keys.count);
|
|
373
|
+
for (let i = 0; i < MAX_AUTHORITY_KEYS; i++) {
|
|
374
|
+
const inUse = UInt32.from(i).lessThan(keys.count);
|
|
375
|
+
// Unused slots must be empty so the commitment is canonical.
|
|
376
|
+
inUse.or(keys.keys[i].equals(PublicKey.empty())).assertTrue();
|
|
377
|
+
// In-use keys are real keys, and distinct from every other in-use key.
|
|
378
|
+
inUse.not().or(keys.keys[i].equals(PublicKey.empty()).not()).assertTrue();
|
|
379
|
+
for (let j = i + 1; j < MAX_AUTHORITY_KEYS; j++) {
|
|
380
|
+
const bothInUse = UInt32.from(j).lessThan(keys.count);
|
|
381
|
+
bothInUse.not().or(keys.keys[i].equals(keys.keys[j]).not()).assertTrue();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/** Commitment stored on-chain as `authorityKeysHash`. */
|
|
387
|
+
export function authorityKeysHash(k: AuthorityKeys): Field {
|
|
388
|
+
return Poseidon.hash([PERMIT_TAGS.KEYS, ...AuthorityKeys.toFields(k)]);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ------------------------------------------------------------
|
|
392
|
+
// Messages
|
|
393
|
+
// ------------------------------------------------------------
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Message an authority key signs:
|
|
397
|
+
* [tag, network, registry.x, registry.isOdd, epoch, nonce, payloadHash]
|
|
398
|
+
* `nonce` is the leaf's `seq` for per-permit actions and the registry's
|
|
399
|
+
* `actionNonce` for registry-wide ones (setFees, rotate, init = 0).
|
|
400
|
+
*/
|
|
401
|
+
export function authorityMessage(
|
|
402
|
+
tag: Field, network: Field, registry: PublicKey, epoch: UInt32, nonce: UInt32, payload: Field[],
|
|
403
|
+
): Field[] {
|
|
404
|
+
return [tag, network, ...registry.toFields(), epoch.value, nonce.value, Poseidon.hash(payload)];
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export function initMessage(a: {
|
|
408
|
+
network: Field; registry: PublicKey; keysHash: Field; policyPacked: Field; feesPacked: Field;
|
|
409
|
+
appTermsPacked: Field; metadataHash: Field; payout: PublicKey; forkActivationSlot: UInt32;
|
|
410
|
+
predecessor: PublicKey; initialPermitsRoot: Field;
|
|
411
|
+
}): Field[] {
|
|
412
|
+
// On a redeploy, the registry this one continues and the frozen permits
|
|
413
|
+
// tree it starts with (the chain checks both); PublicKey.empty() and the
|
|
414
|
+
// empty root for a first generation.
|
|
415
|
+
return authorityMessage(PERMIT_TAGS.INIT, a.network, a.registry, UInt32.zero, UInt32.zero,
|
|
416
|
+
[a.keysHash, a.policyPacked, a.feesPacked, a.appTermsPacked, a.metadataHash, ...a.payout.toFields(), a.forkActivationSlot.value, ...a.predecessor.toFields(), a.initialPermitsRoot]);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** Authority approval of a leaf change (issue, renew, scope change). Nonce = oldLeaf.seq. */
|
|
420
|
+
export function grantMessage(a: {
|
|
421
|
+
network: Field; registry: PublicKey; epoch: UInt32; oldLeaf: PermitLeaf; newLeaf: PermitLeaf;
|
|
422
|
+
}): Field[] {
|
|
423
|
+
return authorityMessage(PERMIT_TAGS.GRANT, a.network, a.registry, a.epoch, a.oldLeaf.seq,
|
|
424
|
+
[permitLeafHash(a.oldLeaf), permitLeafHash(a.newLeaf)]);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/** The operator's acceptance of a grant, including the fee it pays. */
|
|
428
|
+
export function acceptMessage(a: { network: Field; registry: PublicKey; newLeaf: PermitLeaf; fee: UInt64 }): Field[] {
|
|
429
|
+
return [PERMIT_TAGS.ACCEPT, a.network, ...a.registry.toFields(), permitLeafHash(a.newLeaf), a.fee.value];
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export type StatusAction = 'suspend' | 'reinstate' | 'revoke';
|
|
433
|
+
const STATUS_TAG: Record<StatusAction, Field> = {
|
|
434
|
+
suspend: PERMIT_TAGS.SUSPEND, reinstate: PERMIT_TAGS.REINSTATE, revoke: PERMIT_TAGS.REVOKE,
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
/** Authority status change of a permit. Nonce = leaf.seq. */
|
|
438
|
+
export function statusMessage(action: StatusAction, a: {
|
|
439
|
+
network: Field; registry: PublicKey; epoch: UInt32; leaf: PermitLeaf; reasonCode: Field;
|
|
440
|
+
}): Field[] {
|
|
441
|
+
return authorityMessage(STATUS_TAG[action], a.network, a.registry, a.epoch, a.leaf.seq,
|
|
442
|
+
[permitLeafHash(a.leaf), a.reasonCode]);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** The holder giving up their permit. */
|
|
446
|
+
export function surrenderMessage(a: { network: Field; registry: PublicKey; leaf: PermitLeaf }): Field[] {
|
|
447
|
+
return [PERMIT_TAGS.SURRENDER, a.network, ...a.registry.toFields(), permitLeafHash(a.leaf), a.leaf.seq.value];
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** New fees and application terms (processing fee, decision window). */
|
|
451
|
+
export function setFeesMessage(a: {
|
|
452
|
+
network: Field; registry: PublicKey; epoch: UInt32; actionNonce: UInt32; newFeesPacked: Field; newAppTermsPacked: Field;
|
|
453
|
+
}): Field[] {
|
|
454
|
+
return authorityMessage(PERMIT_TAGS.SET_FEES, a.network, a.registry, a.epoch, a.actionNonce,
|
|
455
|
+
[a.newFeesPacked, a.newAppTermsPacked]);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* The authority retires the registry, freezing its permits at `permitsRoot`
|
|
460
|
+
* (the root the redeployed registry's ancestorsRoot commits to). Bound to the
|
|
461
|
+
* epoch and action nonce like the other registry-wide actions.
|
|
462
|
+
*/
|
|
463
|
+
export function retireMessage(a: {
|
|
464
|
+
network: Field; registry: PublicKey; epoch: UInt32; actionNonce: UInt32; permitsRoot: Field;
|
|
465
|
+
/** The one registry that may start from these permits (stored on chain). */
|
|
466
|
+
successor: PublicKey;
|
|
467
|
+
}): Field[] {
|
|
468
|
+
return authorityMessage(PERMIT_TAGS.RETIRE, a.network, a.registry, a.epoch, a.actionNonce, [a.permitsRoot, ...a.successor.toFields()]);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* The platform's retirement of a registry (`retireByPlatform`): what the
|
|
473
|
+
* platform key signs, the fields of retireMessage under its own tag (so
|
|
474
|
+
* neither signature can stand in for the other) plus `force`: retire with
|
|
475
|
+
* application fees still in escrow, which then stay on the retired registry.
|
|
476
|
+
*/
|
|
477
|
+
export function platformRetireMessage(a: {
|
|
478
|
+
network: Field; registry: PublicKey; epoch: UInt32; actionNonce: UInt32; permitsRoot: Field; successor: PublicKey; force: Bool;
|
|
479
|
+
}): Field[] {
|
|
480
|
+
return authorityMessage(PERMIT_TAGS.PLATFORM_RETIRE, a.network, a.registry, a.epoch, a.actionNonce, [a.permitsRoot, ...a.successor.toFields(), a.force.toField()]);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* authorityKeysHash of a retired registry: no key set hashes to it, so no
|
|
485
|
+
* authority action can run again, and filing and surrender check
|
|
486
|
+
* it. (0 means not yet initialized.)
|
|
487
|
+
*/
|
|
488
|
+
export const RETIRED_KEYS_HASH: Field = Field(1);
|
|
489
|
+
|
|
490
|
+
export function rotateMessage(a: {
|
|
491
|
+
network: Field; registry: PublicKey; epoch: UInt32; actionNonce: UInt32; newKeysHash: Field;
|
|
492
|
+
}): Field[] {
|
|
493
|
+
return authorityMessage(PERMIT_TAGS.ROTATE, a.network, a.registry, a.epoch, a.actionNonce, [a.newKeysHash]);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ------------------------------------------------------------
|
|
497
|
+
// Application escrow messages
|
|
498
|
+
// ------------------------------------------------------------
|
|
499
|
+
|
|
500
|
+
/** The holder's application: the terms and the fee they put in escrow. */
|
|
501
|
+
export function applyMessage(a: { network: Field; registry: PublicKey; application: Application }): Field[] {
|
|
502
|
+
return [PERMIT_TAGS.APPLY, a.network, ...a.registry.toFields(), applicationTermsHash(a.application)];
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/** Authority approval of an application exactly as filed. Nonce = baseSeq. */
|
|
506
|
+
export function approveMessage(a: { network: Field; registry: PublicKey; epoch: UInt32; application: Application }): Field[] {
|
|
507
|
+
return authorityMessage(PERMIT_TAGS.APPROVE, a.network, a.registry, a.epoch, a.application.baseSeq,
|
|
508
|
+
[applicationHash(a.application)]);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/** Authority rejection of an application. Nonce = baseSeq. */
|
|
512
|
+
export function rejectMessage(a: {
|
|
513
|
+
network: Field; registry: PublicKey; epoch: UInt32; application: Application; reasonCode: Field;
|
|
514
|
+
}): Field[] {
|
|
515
|
+
return authorityMessage(PERMIT_TAGS.REJECT, a.network, a.registry, a.epoch, a.application.baseSeq,
|
|
516
|
+
[applicationHash(a.application), a.reasonCode]);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* The platform cancelling the open applications of a registry before it
|
|
521
|
+
* retires it (`cancelApplication`, e.g. ahead of a hard fork): every
|
|
522
|
+
* application filed before filing number `cutoff` (the registry's filing
|
|
523
|
+
* count when signed) may be cancelled, its whole fee back to its payer. One
|
|
524
|
+
* signature covers them all; anyone may send the cancellations. Later
|
|
525
|
+
* filings it never covers.
|
|
526
|
+
*/
|
|
527
|
+
export function cancelMessage(a: { network: Field; registry: PublicKey; cutoff: UInt32 }): Field[] {
|
|
528
|
+
return [PERMIT_TAGS.PLATFORM_CANCEL, a.network, ...a.registry.toFields(), a.cutoff.value];
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* A new payout address for the registry (threshold, registry-wide nonce):
|
|
533
|
+
* it takes effect PAYOUT_DELAY_SLOTS_N after it is proposed, unless the keys
|
|
534
|
+
* cancel it (payoutCancelMessage) meanwhile.
|
|
535
|
+
*/
|
|
536
|
+
export function payoutMessage(a: { network: Field; registry: PublicKey; epoch: UInt32; actionNonce: UInt32; payout: PublicKey }): Field[] {
|
|
537
|
+
return authorityMessage(PERMIT_TAGS.PAYOUT, a.network, a.registry, a.epoch, a.actionNonce, a.payout.toFields());
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export function payoutCancelMessage(a: { network: Field; registry: PublicKey; epoch: UInt32; actionNonce: UInt32 }): Field[] {
|
|
541
|
+
return authorityMessage(PERMIT_TAGS.PAYOUT_CANCEL, a.network, a.registry, a.epoch, a.actionNonce, []);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* A permit moving to a new holder key (rekeyPermit), with the same terms,
|
|
546
|
+
* under the new subject permitSubject(newHolderKey, newSalt): signed by the
|
|
547
|
+
* current holder key and the new one, over the permit as it is now. The old
|
|
548
|
+
* leaf is closed (MOVED), so the signatures can't be used twice.
|
|
549
|
+
*/
|
|
550
|
+
export function rekeyMessage(a: { network: Field; registry: PublicKey; leaf: PermitLeaf; newSubject: Field; newHolderKey: PublicKey }): Field[] {
|
|
551
|
+
return [PERMIT_TAGS.REKEY, a.network, ...a.registry.toFields(), permitLeafHash(a.leaf), a.newSubject, ...a.newHolderKey.toFields()];
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** The holder withdrawing their application before a decision. */
|
|
555
|
+
export function withdrawMessage(a: { network: Field; registry: PublicKey; application: Application }): Field[] {
|
|
556
|
+
return [PERMIT_TAGS.WITHDRAW, a.network, ...a.registry.toFields(), applicationHash(a.application)];
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/** What both wallets sign (signMessage) to move an authority account to a new wallet. */
|
|
560
|
+
export function authorityMoveText(from: string, to: string): string {
|
|
561
|
+
return [
|
|
562
|
+
'zkPermits: move my authority account to a new wallet',
|
|
563
|
+
`from: ${from}`,
|
|
564
|
+
`to: ${to}`,
|
|
565
|
+
'Both wallets sign this. The account and its registries move to the new wallet; registry keys change by a rotation.',
|
|
566
|
+
].join('\n');
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/** Decimal strings for a wallet's `signFields({ message })`. */
|
|
570
|
+
export function toSignableFields(message: Field[]): string[] {
|
|
571
|
+
return message.map(f => f.toString());
|
|
572
|
+
}
|