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.
Files changed (317) hide show
  1. package/README.md +417 -201
  2. package/build/agent.d.ts +371 -0
  3. package/build/agent.d.ts.map +1 -0
  4. package/build/agent.js +553 -0
  5. package/build/agent.js.map +1 -0
  6. package/build/agentActions.d.ts +841 -0
  7. package/build/agentActions.d.ts.map +1 -0
  8. package/build/agentActions.js +581 -0
  9. package/build/agentActions.js.map +1 -0
  10. package/build/agentRecord.d.ts +83 -0
  11. package/build/agentRecord.d.ts.map +1 -0
  12. package/build/agentRecord.js +69 -0
  13. package/build/agentRecord.js.map +1 -0
  14. package/build/agentVendor.d.ts +220 -0
  15. package/build/agentVendor.d.ts.map +1 -0
  16. package/build/agentVendor.js +306 -0
  17. package/build/agentVendor.js.map +1 -0
  18. package/build/appsLookup.d.ts +14 -0
  19. package/build/appsLookup.d.ts.map +1 -0
  20. package/build/appsLookup.js +12 -0
  21. package/build/appsLookup.js.map +1 -0
  22. package/build/archiveBootstrap.d.ts +31 -5
  23. package/build/archiveBootstrap.d.ts.map +1 -0
  24. package/build/archiveBootstrap.js +140 -47
  25. package/build/archiveBootstrap.js.map +1 -0
  26. package/build/atomicJson.d.ts +5 -0
  27. package/build/atomicJson.d.ts.map +1 -0
  28. package/build/atomicJson.js +55 -0
  29. package/build/atomicJson.js.map +1 -0
  30. package/build/bindClient.d.ts +85 -0
  31. package/build/bindClient.d.ts.map +1 -0
  32. package/build/bindClient.js +187 -0
  33. package/build/bindClient.js.map +1 -0
  34. package/build/buyClient.d.ts +27 -4
  35. package/build/buyClient.d.ts.map +1 -0
  36. package/build/buyClient.js +72 -26
  37. package/build/buyClient.js.map +1 -0
  38. package/build/chainHead.d.ts +61 -0
  39. package/build/chainHead.d.ts.map +1 -0
  40. package/build/chainHead.js +88 -0
  41. package/build/chainHead.js.map +1 -0
  42. package/build/compactMerkleMap.d.ts +72 -0
  43. package/build/compactMerkleMap.d.ts.map +1 -0
  44. package/build/compactMerkleMap.js +224 -0
  45. package/build/compactMerkleMap.js.map +1 -0
  46. package/build/contractInterface.d.ts +191 -51
  47. package/build/contractInterface.d.ts.map +1 -0
  48. package/build/contractInterface.js +234 -43
  49. package/build/contractInterface.js.map +1 -0
  50. package/build/contractTypes.d.ts +9 -0
  51. package/build/contractTypes.d.ts.map +1 -0
  52. package/build/contractTypes.js +28 -0
  53. package/build/contractTypes.js.map +1 -0
  54. package/build/countryStats.d.ts +12 -3
  55. package/build/countryStats.d.ts.map +1 -0
  56. package/build/countryStats.js +87 -23
  57. package/build/countryStats.js.map +1 -0
  58. package/build/deployClient.d.ts +138 -24
  59. package/build/deployClient.d.ts.map +1 -0
  60. package/build/deployClient.js +91 -31
  61. package/build/deployClient.js.map +1 -0
  62. package/build/deviceIdentity.d.ts +68 -0
  63. package/build/deviceIdentity.d.ts.map +1 -0
  64. package/build/deviceIdentity.js +209 -0
  65. package/build/deviceIdentity.js.map +1 -0
  66. package/build/freezeClient.d.ts +26 -6
  67. package/build/freezeClient.d.ts.map +1 -0
  68. package/build/freezeClient.js +30 -6
  69. package/build/freezeClient.js.map +1 -0
  70. package/build/generationClient.d.ts +6 -3
  71. package/build/generationClient.d.ts.map +1 -0
  72. package/build/generationClient.js +25 -38
  73. package/build/generationClient.js.map +1 -0
  74. package/build/holderSecret.d.ts +70 -0
  75. package/build/holderSecret.d.ts.map +1 -0
  76. package/build/holderSecret.js +76 -0
  77. package/build/holderSecret.js.map +1 -0
  78. package/build/index.d.ts +38 -38
  79. package/build/index.d.ts.map +1 -0
  80. package/build/index.js +97 -121
  81. package/build/index.js.map +1 -0
  82. package/build/keysClient.d.ts +142 -0
  83. package/build/keysClient.d.ts.map +1 -0
  84. package/build/keysClient.js +109 -0
  85. package/build/keysClient.js.map +1 -0
  86. package/build/licenseLeaf.d.ts +76 -0
  87. package/build/licenseLeaf.d.ts.map +1 -0
  88. package/build/licenseLeaf.js +189 -0
  89. package/build/licenseLeaf.js.map +1 -0
  90. package/build/licenseRecord.d.ts +68 -5
  91. package/build/licenseRecord.d.ts.map +1 -0
  92. package/build/licenseRecord.js +26 -1
  93. package/build/licenseRecord.js.map +1 -0
  94. package/build/licenseStore.d.ts +81 -4
  95. package/build/licenseStore.d.ts.map +1 -0
  96. package/build/licenseStore.js +400 -30
  97. package/build/licenseStore.js.map +1 -0
  98. package/build/licenseTrustless.d.ts +43 -0
  99. package/build/licenseTrustless.d.ts.map +1 -0
  100. package/build/licenseTrustless.js +180 -0
  101. package/build/licenseTrustless.js.map +1 -0
  102. package/build/manifestVerify.d.ts +29 -1
  103. package/build/manifestVerify.d.ts.map +1 -0
  104. package/build/manifestVerify.js +46 -4
  105. package/build/manifestVerify.js.map +1 -0
  106. package/build/minaPriceHistory.d.ts +9 -0
  107. package/build/minaPriceHistory.d.ts.map +1 -0
  108. package/build/minaPriceHistory.js +152 -0
  109. package/build/minaPriceHistory.js.map +1 -0
  110. package/build/onChainRoot.d.ts +60 -0
  111. package/build/onChainRoot.d.ts.map +1 -0
  112. package/build/onChainRoot.js +74 -0
  113. package/build/onChainRoot.js.map +1 -0
  114. package/build/ownershipLicenseHash.d.ts +25 -0
  115. package/build/ownershipLicenseHash.d.ts.map +1 -0
  116. package/build/ownershipLicenseHash.js +29 -0
  117. package/build/ownershipLicenseHash.js.map +1 -0
  118. package/build/ownershipSignature.d.ts +153 -0
  119. package/build/ownershipSignature.d.ts.map +1 -0
  120. package/build/ownershipSignature.js +297 -0
  121. package/build/ownershipSignature.js.map +1 -0
  122. package/build/permitCheckFlow.d.ts +155 -0
  123. package/build/permitCheckFlow.d.ts.map +1 -0
  124. package/build/permitCheckFlow.js +196 -0
  125. package/build/permitCheckFlow.js.map +1 -0
  126. package/build/permitDescribe.d.ts +124 -0
  127. package/build/permitDescribe.d.ts.map +1 -0
  128. package/build/permitDescribe.js +324 -0
  129. package/build/permitDescribe.js.map +1 -0
  130. package/build/permitInterface.d.ts +85 -0
  131. package/build/permitInterface.d.ts.map +1 -0
  132. package/build/permitInterface.js +121 -0
  133. package/build/permitInterface.js.map +1 -0
  134. package/build/permitMessages.d.ts +313 -0
  135. package/build/permitMessages.d.ts.map +1 -0
  136. package/build/permitMessages.js +462 -0
  137. package/build/permitMessages.js.map +1 -0
  138. package/build/permitProof.d.ts +108 -0
  139. package/build/permitProof.d.ts.map +1 -0
  140. package/build/permitProof.js +202 -0
  141. package/build/permitProof.js.map +1 -0
  142. package/build/permitRegistryRebuild.d.ts +166 -0
  143. package/build/permitRegistryRebuild.d.ts.map +1 -0
  144. package/build/permitRegistryRebuild.js +347 -0
  145. package/build/permitRegistryRebuild.js.map +1 -0
  146. package/build/permitTree.d.ts +88 -0
  147. package/build/permitTree.d.ts.map +1 -0
  148. package/build/permitTree.js +230 -0
  149. package/build/permitTree.js.map +1 -0
  150. package/build/permitsClient.d.ts +680 -0
  151. package/build/permitsClient.d.ts.map +1 -0
  152. package/build/permitsClient.js +597 -0
  153. package/build/permitsClient.js.map +1 -0
  154. package/build/proveErrors.d.ts +50 -0
  155. package/build/proveErrors.d.ts.map +1 -0
  156. package/build/proveErrors.js +76 -0
  157. package/build/proveErrors.js.map +1 -0
  158. package/build/receipt.d.ts +95 -0
  159. package/build/receipt.d.ts.map +1 -0
  160. package/build/receipt.js +84 -0
  161. package/build/receipt.js.map +1 -0
  162. package/build/refundClient.d.ts +7 -12
  163. package/build/refundClient.d.ts.map +1 -0
  164. package/build/refundClient.js +52 -21
  165. package/build/refundClient.js.map +1 -0
  166. package/build/registryTrustVerify.d.ts +78 -0
  167. package/build/registryTrustVerify.d.ts.map +1 -0
  168. package/build/registryTrustVerify.js +129 -0
  169. package/build/registryTrustVerify.js.map +1 -0
  170. package/build/releaseClient.d.ts +26 -0
  171. package/build/releaseClient.d.ts.map +1 -0
  172. package/build/releaseClient.js +65 -0
  173. package/build/releaseClient.js.map +1 -0
  174. package/build/renewClient.d.ts +28 -2
  175. package/build/renewClient.d.ts.map +1 -0
  176. package/build/renewClient.js +31 -27
  177. package/build/renewClient.js.map +1 -0
  178. package/build/seatName.d.ts +8 -0
  179. package/build/seatName.d.ts.map +1 -0
  180. package/build/seatName.js +136 -0
  181. package/build/seatName.js.map +1 -0
  182. package/build/slotConstants.d.ts +15 -0
  183. package/build/slotConstants.d.ts.map +1 -0
  184. package/build/slotConstants.js +17 -0
  185. package/build/slotConstants.js.map +1 -0
  186. package/build/statsClient.d.ts +61 -7
  187. package/build/statsClient.d.ts.map +1 -0
  188. package/build/statsClient.js +44 -5
  189. package/build/statsClient.js.map +1 -0
  190. package/build/successorChain.d.ts +35 -0
  191. package/build/successorChain.d.ts.map +1 -0
  192. package/build/successorChain.js +69 -0
  193. package/build/successorChain.js.map +1 -0
  194. package/build/taxId.d.ts +44 -0
  195. package/build/taxId.d.ts.map +1 -0
  196. package/build/taxId.js +212 -0
  197. package/build/taxId.js.map +1 -0
  198. package/build/trustAnchorVerify.d.ts +49 -0
  199. package/build/trustAnchorVerify.d.ts.map +1 -0
  200. package/build/trustAnchorVerify.js +432 -0
  201. package/build/trustAnchorVerify.js.map +1 -0
  202. package/build/trustAnchorVerifyCli.d.ts +45 -0
  203. package/build/trustAnchorVerifyCli.d.ts.map +1 -0
  204. package/build/trustAnchorVerifyCli.js +235 -0
  205. package/build/trustAnchorVerifyCli.js.map +1 -0
  206. package/build/txBroadcastClient.d.ts +26 -0
  207. package/build/txBroadcastClient.d.ts.map +1 -0
  208. package/build/txBroadcastClient.js +20 -0
  209. package/build/txBroadcastClient.js.map +1 -0
  210. package/build/unbindClient.d.ts +77 -0
  211. package/build/unbindClient.d.ts.map +1 -0
  212. package/build/unbindClient.js +169 -0
  213. package/build/unbindClient.js.map +1 -0
  214. package/build/units.d.ts +28 -0
  215. package/build/units.d.ts.map +1 -0
  216. package/build/units.js +65 -0
  217. package/build/units.js.map +1 -0
  218. package/build/vatRates.d.ts +54 -0
  219. package/build/vatRates.d.ts.map +1 -0
  220. package/build/vatRates.js +82 -0
  221. package/build/vatRates.js.map +1 -0
  222. package/build/vatRatesData.d.ts +5 -0
  223. package/build/vatRatesData.d.ts.map +1 -0
  224. package/build/vatRatesData.js +42 -0
  225. package/build/vatRatesData.js.map +1 -0
  226. package/build/vendorAccountClient.d.ts +66 -0
  227. package/build/vendorAccountClient.d.ts.map +1 -0
  228. package/build/vendorAccountClient.js +47 -0
  229. package/build/vendorAccountClient.js.map +1 -0
  230. package/build/verifyCore.d.ts +4 -1
  231. package/build/verifyCore.d.ts.map +1 -0
  232. package/build/verifyCore.js +21 -10
  233. package/build/verifyCore.js.map +1 -0
  234. package/build/verifyOffline.d.ts +85 -0
  235. package/build/verifyOffline.d.ts.map +1 -0
  236. package/build/verifyOffline.js +139 -0
  237. package/build/verifyOffline.js.map +1 -0
  238. package/build/verifyService.d.ts.map +1 -0
  239. package/build/verifyService.js +571 -501
  240. package/build/verifyService.js.map +1 -0
  241. package/build/verifyWithAncestors.d.ts +19 -0
  242. package/build/verifyWithAncestors.d.ts.map +1 -0
  243. package/build/verifyWithAncestors.js +127 -0
  244. package/build/verifyWithAncestors.js.map +1 -0
  245. package/build/zipToState.d.ts +2 -0
  246. package/build/zipToState.d.ts.map +1 -0
  247. package/build/zipToState.js +94 -0
  248. package/build/zipToState.js.map +1 -0
  249. package/package.json +141 -16
  250. package/src/agent.ts +682 -0
  251. package/src/agentActions.ts +637 -0
  252. package/src/agentRecord.ts +121 -0
  253. package/src/agentVendor.ts +356 -0
  254. package/src/appsLookup.ts +48 -0
  255. package/src/archiveBootstrap.ts +386 -0
  256. package/src/atomicJson.ts +53 -0
  257. package/src/bindClient.ts +297 -0
  258. package/src/buyClient.ts +344 -0
  259. package/src/chainHead.ts +106 -0
  260. package/src/compactMerkleMap.ts +222 -0
  261. package/src/contractInterface.ts +465 -0
  262. package/src/contractTypes.ts +31 -0
  263. package/src/countryStats.ts +200 -0
  264. package/src/deployClient.ts +517 -0
  265. package/src/deviceIdentity.ts +249 -0
  266. package/src/freezeClient.ts +162 -0
  267. package/src/generationClient.ts +145 -0
  268. package/src/holderSecret.ts +91 -0
  269. package/src/index.ts +362 -0
  270. package/src/keysClient.ts +135 -0
  271. package/src/licenseLeaf.ts +221 -0
  272. package/src/licenseRecord.ts +190 -0
  273. package/src/licenseStore.ts +767 -0
  274. package/src/licenseTrustless.ts +207 -0
  275. package/src/manifestVerify.ts +164 -0
  276. package/src/minaPriceHistory.ts +166 -0
  277. package/src/onChainRoot.ts +90 -0
  278. package/src/ownershipLicenseHash.ts +31 -0
  279. package/src/ownershipSignature.ts +421 -0
  280. package/src/permitCheckFlow.ts +227 -0
  281. package/src/permitDescribe.ts +362 -0
  282. package/src/permitInterface.ts +146 -0
  283. package/src/permitMessages.ts +572 -0
  284. package/src/permitProof.ts +230 -0
  285. package/src/permitRegistryRebuild.ts +423 -0
  286. package/src/permitTree.ts +232 -0
  287. package/src/permitsClient.ts +746 -0
  288. package/src/proveErrors.ts +98 -0
  289. package/src/receipt.ts +156 -0
  290. package/src/refundClient.ts +177 -0
  291. package/src/registryTrustVerify.ts +192 -0
  292. package/src/releaseClient.ts +101 -0
  293. package/src/renewClient.ts +234 -0
  294. package/src/seatName.ts +165 -0
  295. package/src/slotConstants.ts +18 -0
  296. package/src/statsClient.ts +249 -0
  297. package/src/successorChain.ts +87 -0
  298. package/src/taxId.ts +227 -0
  299. package/src/trustAnchorVerify.ts +550 -0
  300. package/src/trustAnchorVerifyCli.ts +234 -0
  301. package/src/txBroadcastClient.ts +48 -0
  302. package/src/unbindClient.ts +233 -0
  303. package/src/units.ts +74 -0
  304. package/src/vatRates.ts +100 -0
  305. package/src/vatRatesData.ts +43 -0
  306. package/src/vendorAccountClient.ts +120 -0
  307. package/src/verifyCore.ts +100 -0
  308. package/src/verifyOffline.ts +212 -0
  309. package/src/verifyService.ts +982 -0
  310. package/src/verifyWithAncestors.ts +163 -0
  311. package/src/zipToState.ts +94 -0
  312. package/build/licenseProof.d.ts +0 -26
  313. package/build/licenseProof.js +0 -41
  314. package/build/migrateClient.d.ts +0 -43
  315. package/build/migrateClient.js +0 -47
  316. package/build/ownership.d.ts +0 -34
  317. package/build/ownership.js +0 -147
@@ -0,0 +1,362 @@
1
+ // Copyright (c) 2025-2026 zkLicensing project developers
2
+ // SPDX-License-Identifier: BUSL-1.1
3
+
4
+ /**
5
+ * permitDescribe.ts — `zklicensing/permits/describe`
6
+ *
7
+ * What a zkPermits field signature means, in words. Wallets show these
8
+ * messages as a list of numbers, and most carry only a hash of the details
9
+ * (the permit, the fees, the keys). So the description is built the other
10
+ * way round: from the request's details, the message is rebuilt and must
11
+ * equal the numbers about to be signed — only then is the summary
12
+ * `verified`. Show it before asking the wallet, with the fingerprint (how
13
+ * many numbers, and how the last one ends) for comparing with the wallet's
14
+ * screen.
15
+ */
16
+
17
+ import { Bool, Field, PublicKey, UInt32, UInt64 } from 'o1js';
18
+ import {
19
+ PERMIT_TAGS, PERMIT_NETWORK, acceptMessage, applyMessage, approveMessage, authorityKeys, authorityKeysHash, grantMessage,
20
+ DEFAULT_DECISION_WINDOW, DEFAULT_MIN_PROCESSING_FEE, initMessage, networkField, packApplicationTerms, packFees, packPolicy, rejectMessage, retireMessage, rotateMessage, setFeesMessage,
21
+ statusMessage, surrenderMessage, payoutMessage, payoutCancelMessage, rekeyMessage, unpackApplicationTerms, unpackFees, withdrawMessage, type PermitNetwork,
22
+ } from './permitMessages.js';
23
+ import { recordToApplication, recordToLeaf, type ApplicationRecord, type PermitRecord } from './permitRegistryRebuild.js';
24
+ import { minaUnit } from './units.js';
25
+ import { EMPTY_ROOT } from './contractInterface.js';
26
+
27
+ export type PermitMessageDescription = {
28
+ kind: string;
29
+ /** One line: what signing does. */
30
+ title: string;
31
+ /** The details, as label/value pairs. */
32
+ facts: Array<[string, string]>;
33
+ network: PermitNetwork | null;
34
+ registry: string | null;
35
+ /** The details were checked to give exactly these numbers. */
36
+ verified: boolean;
37
+ /** Why not, when not verified. */
38
+ problem?: string;
39
+ /** For comparing with the wallet: "7 numbers, the last ending …123456". */
40
+ fingerprint: string;
41
+ };
42
+
43
+ export type DescribeContext = {
44
+ /** Activity names by bit (the registry's scopes). */
45
+ scopeLabel?: (bit: number) => string;
46
+ /** A date for a slot. */
47
+ slotLabel?: (slot: number) => string;
48
+ /** The registry's configuration, for a deployment request. */
49
+ registry?: {
50
+ keys: string[]; threshold: number; payout: string; metadataHash: string;
51
+ policy: { gracePeriod: number; maxTerm: number; singleKeySuspend: boolean; holderSigRequired: boolean };
52
+ /** processingFee and minProcessingFee default to DEFAULT_MIN_PROCESSING_FEE, as the keeper does for older drafts. */
53
+ fees: { grantFee: string; renewalFee: string; minFee: string; processingFee?: string; minProcessingFee?: string };
54
+ /** Slots from filing an application to its decision deadline (default DEFAULT_DECISION_WINDOW). */
55
+ decisionWindow?: number;
56
+ /** A redeploy: the frozen tree this one starts with and the registry it replaces (the chain checks both). */
57
+ initialPermitsRoot?: string;
58
+ forkActivationSlot?: number;
59
+ predecessor?: string;
60
+ generation?: number;
61
+ };
62
+ };
63
+
64
+ const TAG_KIND = new Map<string, string>(Object.entries(PERMIT_TAGS).map(([k, v]) => [v.toString(), k]));
65
+ const NET_NAME = new Map<string, PermitNetwork>(Object.entries(PERMIT_NETWORK).map(([k, v]) => [v.toString(), k as PermitNetwork]));
66
+ const NO_EXPIRY = 4294967295;
67
+
68
+ export function fingerprint(fields: string[]): string {
69
+ const last = fields[fields.length - 1] ?? '';
70
+ return `${fields.length} numbers, the last ending …${last.slice(-6)}`;
71
+ }
72
+
73
+ // Devnet fees are tMINA (test MINA, no value).
74
+ const mina = (nano: string | bigint, network?: string | null) => {
75
+ const s = BigInt(nano).toString().padStart(10, '0');
76
+ return `${s.slice(0, -9)}.${s.slice(-9)}`.replace(/\.?0+$/, '') + ' ' + minaUnit(network ?? 'mainnet');
77
+ };
78
+ const short = (s: string) => (s.length > 14 ? `${s.slice(0, 6)}…${s.slice(-6)}` : s);
79
+
80
+ function scopeText(scope: string, ctx: DescribeContext): string {
81
+ const v = BigInt(scope);
82
+ const bits: number[] = [];
83
+ for (let i = 0; i < 254; i++) if ((v >> BigInt(i)) & 1n) bits.push(i);
84
+ return bits.length ? bits.map(b => ctx.scopeLabel?.(b) ?? `activity ${b}`).join(', ') : 'none';
85
+ }
86
+ const slotText = (slot: number, ctx: DescribeContext) => (slot >= NO_EXPIRY ? 'no expiry' : ctx.slotLabel?.(slot) ?? `slot ${slot}`);
87
+
88
+ const windowText = (slots: number) => `${Math.round(slots / 960)} days after the application`;
89
+
90
+ function applicationFacts(a: ApplicationRecord, ctx: DescribeContext, network: string | null): Array<[string, string]> {
91
+ return [
92
+ ['Activities', scopeText(a.scope, ctx)],
93
+ ['Valid', `${slotText(a.validFrom, ctx)} – ${slotText(a.expirySlot, ctx)}`],
94
+ ['Document hash', short(a.docHash)],
95
+ ['Kind', a.baseSeq === 0 ? 'new permit' : 'renewal or change'],
96
+ ['Fee in escrow', mina(a.fee, network)],
97
+ ['Decision deadline', slotText(a.deadline, ctx)],
98
+ ];
99
+ }
100
+
101
+ function leafFacts(prefix: string, r: PermitRecord, ctx: DescribeContext): Array<[string, string]> {
102
+ return [
103
+ [`${prefix}activities`, scopeText(r.scope, ctx)],
104
+ [`${prefix}valid`, `${slotText(r.validFrom, ctx)} – ${slotText(r.expirySlot, ctx)}`],
105
+ [`${prefix}document hash`, short(r.docHash)],
106
+ ];
107
+ }
108
+
109
+ /** The message's tag, network and registry (readable from the numbers themselves). */
110
+ function header(fields: string[]): { kind: string | null; network: PermitNetwork | null; registry: string | null } {
111
+ const kind = TAG_KIND.get(fields[0] ?? '') ?? null;
112
+ const network = NET_NAME.get(fields[1] ?? '') ?? null;
113
+ let registry: string | null = null;
114
+ try { registry = PublicKey.fromFields([Field(fields[2]), Field(fields[3])]).toBase58(); } catch { /* not a key */ }
115
+ return { kind, network, registry };
116
+ }
117
+
118
+ const same = (a: Field[], b: string[]) => a.length === b.length && a.every((f, i) => f.toString() === b[i]);
119
+
120
+ /**
121
+ * Describes an authority request (the keeper's RequestView: kind, message
122
+ * and its details) and checks that the details give exactly `message`.
123
+ */
124
+ export function describeRequest(q: {
125
+ kind: string; registry: string; message: string[];
126
+ oldLeaf?: PermitRecord; newLeaf?: PermitRecord; fee?: string; reasonCode?: string;
127
+ newFeesPacked?: string; newAppTermsPacked?: string; newKeys?: string[]; newThreshold?: number;
128
+ application?: ApplicationRecord; newPayout?: string;
129
+ }, ctx: DescribeContext = {}): PermitMessageDescription {
130
+ const fields = q.message;
131
+ const h = header(fields);
132
+ const base = { kind: q.kind, network: h.network, registry: h.registry, fingerprint: fingerprint(fields) };
133
+ const fail = (title: string, problem: string, facts: Array<[string, string]> = []): PermitMessageDescription => ({ ...base, title, facts, verified: false, problem });
134
+ if (!h.network) return fail('Unknown message', 'The message names no zkPermits network.');
135
+ if (h.registry !== q.registry) return fail('Unknown message', 'The message is for another registry than the request says.');
136
+ const net = networkField(h.network);
137
+ const reg = PublicKey.fromBase58(q.registry);
138
+ const epoch = UInt32.from(fields[4] ?? 0);
139
+ const nonce = UInt32.from(fields[5] ?? 0);
140
+ let expected: Field[];
141
+ let title: string;
142
+ let facts: Array<[string, string]> = [];
143
+ try {
144
+ switch (q.kind) {
145
+ case 'grant': {
146
+ if (!q.oldLeaf || !q.newLeaf) return fail('Grant', 'The request has no permit details.');
147
+ expected = grantMessage({ network: net, registry: reg, epoch, oldLeaf: recordToLeaf(q.oldLeaf), newLeaf: recordToLeaf(q.newLeaf) });
148
+ const isNew = q.oldLeaf.seq === 0 && !q.oldLeaf.holderKey;
149
+ title = isNew ? `Approve a new permit for ${short(q.newLeaf.holderKey)}` : `Approve a change to permit ${short(q.newLeaf.subject)}`;
150
+ facts = [
151
+ ['Permit', short(q.newLeaf.subject)],
152
+ ['Holder key', q.newLeaf.holderKey],
153
+ ...leafFacts('', q.newLeaf, ctx),
154
+ ...(isNew ? [] : leafFacts('Before: ', q.oldLeaf, ctx)),
155
+ ...(q.fee ? [['Fee the holder pays', mina(q.fee, h.network)] as [string, string]] : []),
156
+ ];
157
+ break;
158
+ }
159
+ case 'suspend': case 'reinstate': case 'revoke': {
160
+ if (!q.oldLeaf) return fail(q.kind, 'The request has no permit details.');
161
+ expected = statusMessage(q.kind, { network: net, registry: reg, epoch, leaf: recordToLeaf(q.oldLeaf), reasonCode: Field(q.reasonCode ?? 0) });
162
+ title = `${q.kind === 'suspend' ? 'Suspend' : q.kind === 'reinstate' ? 'Reinstate' : 'Revoke (final)'} permit ${short(q.oldLeaf.subject)}`;
163
+ facts = [['Permit', short(q.oldLeaf.subject)], ['Holder key', q.oldLeaf.holderKey], ['Activities', scopeText(q.oldLeaf.scope, ctx)], ['Reason code', String(q.reasonCode ?? 0)]];
164
+ break;
165
+ }
166
+ case 'setFees': {
167
+ if (!q.newFeesPacked || !q.newAppTermsPacked) return fail('Change fees', 'The request has no fees.');
168
+ expected = setFeesMessage({ network: net, registry: reg, epoch, actionNonce: nonce, newFeesPacked: Field(q.newFeesPacked), newAppTermsPacked: Field(q.newAppTermsPacked) });
169
+ const f = unpackFees(Field(q.newFeesPacked));
170
+ const t = unpackApplicationTerms(Field(q.newAppTermsPacked));
171
+ title = 'Change the registry\'s fees';
172
+ facts = [
173
+ ['Permit fee', mina(f.grantFee.toBigInt(), h.network)], ['Renewal fee', mina(f.renewalFee.toBigInt(), h.network)], ['Minimum', mina(f.minFee.toBigInt(), h.network)],
174
+ ['Processing fee (kept on rejection or withdrawal)', mina(t.processingFee.toBigInt(), h.network)],
175
+ ['Decision deadline', windowText(Number(t.decisionWindow.toString()))],
176
+ ];
177
+ break;
178
+ }
179
+ case 'approveApplication': case 'rejectApplication': {
180
+ if (!q.application) return fail('Application', 'The request has no application.');
181
+ const app = recordToApplication(q.application);
182
+ const reject = q.kind === 'rejectApplication';
183
+ expected = reject
184
+ ? rejectMessage({ network: net, registry: reg, epoch, application: app, reasonCode: Field(q.reasonCode ?? 0) })
185
+ : approveMessage({ network: net, registry: reg, epoch, application: app });
186
+ const kept = BigInt(q.application.processingFee);
187
+ title = reject
188
+ ? `Reject the application of ${short(q.application.holderKey)}`
189
+ : `Approve the application of ${short(q.application.holderKey)} (permit active at once)`;
190
+ facts = [
191
+ ['Applicant key', q.application.holderKey],
192
+ ...applicationFacts(q.application, ctx, h.network),
193
+ ...(reject
194
+ ? [['Kept (processing fee)', mina(kept, h.network)], ['Refunded to the payer', mina(BigInt(q.application.fee) - kept, h.network)], ['Reason code', String(q.reasonCode ?? 0)]] as Array<[string, string]>
195
+ : [['Paid out from escrow', mina(q.application.fee, h.network)]] as Array<[string, string]>),
196
+ ];
197
+ break;
198
+ }
199
+ case 'rotate': {
200
+ if (!q.newKeys || !q.newThreshold) return fail('Rotate keys', 'The request has no new keys.');
201
+ const newKeysHash = authorityKeysHash(authorityKeys(q.newKeys.map(k => PublicKey.fromBase58(k)), q.newThreshold));
202
+ expected = rotateMessage({ network: net, registry: reg, epoch, actionNonce: nonce, newKeysHash });
203
+ title = 'Replace the authority keys';
204
+ facts = [...q.newKeys.map((k, i) => [`New key ${i + 1}`, k] as [string, string]), ['Signatures needed', `${q.newThreshold} of ${q.newKeys.length}`]];
205
+ break;
206
+ }
207
+ case 'payout': {
208
+ if (!q.newPayout) return fail('Change the payout address', 'The request has no address.');
209
+ expected = payoutMessage({ network: net, registry: reg, epoch, actionNonce: nonce, payout: PublicKey.fromBase58(q.newPayout) });
210
+ title = 'Change the payout address (after 48 hours)';
211
+ facts = [['New payout address', q.newPayout], ['Takes effect', '48 hours after it lands; until then fees go to the current address, and the keys can cancel it']];
212
+ break;
213
+ }
214
+ case 'payoutCancel': {
215
+ expected = payoutCancelMessage({ network: net, registry: reg, epoch, actionNonce: nonce });
216
+ title = 'Cancel the pending payout address change';
217
+ facts = q.newPayout ? [['Cancelled address', q.newPayout]] : [];
218
+ break;
219
+ }
220
+ case 'retire': {
221
+ const root = fields[6];
222
+ if (root === undefined || fields[7] === undefined || fields[8] === undefined) return fail('Retire the registry', 'The message names no permits root or successor.');
223
+ let successor: PublicKey;
224
+ try { successor = PublicKey.fromFields([Field(fields[7]), Field(fields[8])]); } catch { return fail('Retire the registry', 'The successor in the message is not a valid address.'); }
225
+ expected = retireMessage({ network: net, registry: reg, epoch, actionNonce: nonce, permitsRoot: Field(root), successor });
226
+ title = 'Retire the registry for a redeploy (final)';
227
+ facts = [
228
+ ['Effect', 'no more changes here: no grants, renewals, status changes, applications or surrenders'],
229
+ ['Permits', 'carry over, all at once and unchanged, to the new registry below: only it can start from them'],
230
+ ['New registry', successor.toBase58()],
231
+ ['Frozen permits root', root],
232
+ ];
233
+ break;
234
+ }
235
+ case 'init': {
236
+ const r = ctx.registry;
237
+ if (!r) return fail('Deploy registry', 'The registry\'s configuration is needed to check this message.');
238
+ const keysHash = authorityKeysHash(authorityKeys(r.keys.map(k => PublicKey.fromBase58(k)), r.threshold));
239
+ const policyPacked = packPolicy({ gracePeriod: UInt32.from(r.policy.gracePeriod), maxTerm: UInt32.from(r.policy.maxTerm), singleKeySuspend: Bool(r.policy.singleKeySuspend), holderSigRequired: Bool(r.policy.holderSigRequired) });
240
+ const feesPacked = packFees({ grantFee: UInt64.from(r.fees.grantFee), renewalFee: UInt64.from(r.fees.renewalFee), minFee: UInt64.from(r.fees.minFee) });
241
+ const processingFee = r.fees.processingFee ?? DEFAULT_MIN_PROCESSING_FEE.toString();
242
+ const decisionWindow = r.decisionWindow ?? Number(DEFAULT_DECISION_WINDOW.toBigint());
243
+ const appTermsPacked = packApplicationTerms({
244
+ processingFee: UInt64.from(processingFee), minProcessingFee: UInt64.from(r.fees.minProcessingFee ?? DEFAULT_MIN_PROCESSING_FEE.toString()), decisionWindow: UInt32.from(decisionWindow),
245
+ });
246
+ expected = initMessage({
247
+ network: net, registry: reg, keysHash, policyPacked, feesPacked, appTermsPacked, metadataHash: Field(r.metadataHash), payout: PublicKey.fromBase58(r.payout),
248
+ forkActivationSlot: UInt32.from(r.forkActivationSlot ?? 0),
249
+ predecessor: r.predecessor ? PublicKey.fromBase58(r.predecessor) : PublicKey.empty(),
250
+ initialPermitsRoot: Field(r.initialPermitsRoot ?? EMPTY_ROOT.toString()),
251
+ });
252
+ title = r.predecessor
253
+ ? `Redeploy the registry (generation ${r.generation ?? 2}, replacing ${short(r.predecessor)})`
254
+ : 'Set up the registry (keys, rules and fees)';
255
+ facts = [
256
+ ...(r.predecessor ? [['Replaces', r.predecessor], ['Permits', `starts with all permits of the replaced registry, as they are when it retires (permits root ${short(r.initialPermitsRoot ?? '')})`]] as Array<[string, string]> : []),
257
+ ...r.keys.map((k, i) => [`Key ${i + 1}`, k] as [string, string]),
258
+ ['Signatures needed', `${r.threshold} of ${r.keys.length}`],
259
+ ['Permit fee', mina(r.fees.grantFee, h.network)], ['Renewal fee', mina(r.fees.renewalFee, h.network)],
260
+ ['Processing fee (kept on rejection or withdrawal)', mina(processingFee, h.network)],
261
+ ['Decision deadline', windowText(decisionWindow)],
262
+ ['Fees paid to', r.payout],
263
+ ['Suspension', r.policy.singleKeySuspend ? 'any one key' : 'same as other actions'],
264
+ ];
265
+ break;
266
+ }
267
+ default:
268
+ return fail('Unknown request', `Unknown request kind ${q.kind}.`);
269
+ }
270
+ } catch (e: any) {
271
+ return fail('Unreadable request', e?.message ?? String(e));
272
+ }
273
+ facts.unshift(['Registry', q.registry], ['Network', h.network]);
274
+ if (!same(expected, fields)) return { ...base, title, facts, verified: false, problem: 'The numbers to sign do not match these details. Do not sign.' };
275
+ return { ...base, title, facts, verified: true };
276
+ }
277
+
278
+ /** The holder accepting a permit and its fee (acceptMessage). */
279
+ export function describeAccept(a: { network: PermitNetwork; registry: string; newLeaf: PermitRecord; fee: string; fields: string[] }, ctx: DescribeContext = {}): PermitMessageDescription {
280
+ const expected = acceptMessage({ network: networkField(a.network), registry: PublicKey.fromBase58(a.registry), newLeaf: recordToLeaf(a.newLeaf), fee: UInt64.from(a.fee) });
281
+ const ok = same(expected, a.fields);
282
+ return {
283
+ kind: 'accept', title: `Accept permit ${short(a.newLeaf.subject)} and pay ${mina(a.fee, a.network)}`,
284
+ facts: [['Registry', a.registry], ['Network', a.network], ...leafFacts('', a.newLeaf, ctx), ['Fee', mina(a.fee, a.network)]],
285
+ network: a.network, registry: a.registry, verified: ok, ...(ok ? {} : { problem: 'The numbers to sign do not match these details. Do not sign.' }),
286
+ fingerprint: fingerprint(a.fields),
287
+ };
288
+ }
289
+
290
+ /**
291
+ * The holder moving a permit to a new key (rekeyMessage): signed by the
292
+ * current key and the new one. Same terms, a new subject; the old one closes.
293
+ */
294
+ export function describeRekey(a: { network: PermitNetwork; registry: string; leaf: PermitRecord; newSubject: string; newHolderKey: string; fields: string[] }, ctx: DescribeContext = {}): PermitMessageDescription {
295
+ const expected = rekeyMessage({ network: networkField(a.network), registry: PublicKey.fromBase58(a.registry), leaf: recordToLeaf(a.leaf), newSubject: Field(a.newSubject), newHolderKey: PublicKey.fromBase58(a.newHolderKey) });
296
+ const ok = same(expected, a.fields);
297
+ return {
298
+ kind: 'rekey', title: `Move permit ${short(a.leaf.subject)} to the key ${short(a.newHolderKey)}`,
299
+ facts: [['Registry', a.registry], ['Network', a.network], ['New holder key', a.newHolderKey], ['Activities', scopeText(a.leaf.scope, ctx)], ['Effect', 'the same permit under the new key; this one closes (moved)']],
300
+ network: a.network, registry: a.registry, verified: ok, ...(ok ? {} : { problem: 'The numbers to sign do not match these details. Do not sign.' }),
301
+ fingerprint: fingerprint(a.fields),
302
+ };
303
+ }
304
+
305
+ /** The holder giving up a permit (surrenderMessage). */
306
+ export function describeSurrender(a: { network: PermitNetwork; registry: string; leaf: PermitRecord; fields: string[] }, ctx: DescribeContext = {}): PermitMessageDescription {
307
+ const expected = surrenderMessage({ network: networkField(a.network), registry: PublicKey.fromBase58(a.registry), leaf: recordToLeaf(a.leaf) });
308
+ const ok = same(expected, a.fields);
309
+ return {
310
+ kind: 'surrender', title: `Give up permit ${short(a.leaf.subject)} (final)`,
311
+ facts: [['Registry', a.registry], ['Network', a.network], ['Activities', scopeText(a.leaf.scope, ctx)]],
312
+ network: a.network, registry: a.registry, verified: ok, ...(ok ? {} : { problem: 'The numbers to sign do not match these details. Do not sign.' }),
313
+ fingerprint: fingerprint(a.fields),
314
+ };
315
+ }
316
+
317
+ /**
318
+ * The holder's application (applyMessage): the terms and the fee put in
319
+ * escrow. `application.payer` and `deadline` aren't part of what the holder
320
+ * signs (the sender pays; the contract sets the deadline).
321
+ */
322
+ export function describeApply(a: { network: PermitNetwork; registry: string; application: ApplicationRecord; fields: string[] }, ctx: DescribeContext = {}): PermitMessageDescription {
323
+ const expected = applyMessage({ network: networkField(a.network), registry: PublicKey.fromBase58(a.registry), application: recordToApplication(a.application) });
324
+ const ok = same(expected, a.fields);
325
+ const kept = BigInt(a.application.processingFee);
326
+ return {
327
+ kind: 'apply', title: `Apply for a permit and put ${mina(a.application.fee, a.network)} in escrow`,
328
+ facts: [
329
+ ['Registry', a.registry], ['Network', a.network],
330
+ ['Activities', scopeText(a.application.scope, ctx)],
331
+ ['Valid', `${slotText(a.application.validFrom, ctx)} – ${slotText(a.application.expirySlot, ctx)}`],
332
+ ['Document hash', short(a.application.docHash)],
333
+ ['Fee in escrow', mina(a.application.fee, a.network)],
334
+ ['If approved', 'the permit is active at once and the fee is paid'],
335
+ ['If rejected or withdrawn', `${mina(kept, a.network)} processing fee kept, ${mina(BigInt(a.application.fee) - kept, a.network)} refunded`],
336
+ ['If no decision by the deadline', 'full refund'],
337
+ ],
338
+ network: a.network, registry: a.registry, verified: ok, ...(ok ? {} : { problem: 'The numbers to sign do not match these details. Do not sign.' }),
339
+ fingerprint: fingerprint(a.fields),
340
+ };
341
+ }
342
+
343
+ /** The holder withdrawing an application (withdrawMessage). */
344
+ export function describeWithdraw(a: { network: PermitNetwork; registry: string; application: ApplicationRecord; fields: string[] }, ctx: DescribeContext = {}): PermitMessageDescription {
345
+ const expected = withdrawMessage({ network: networkField(a.network), registry: PublicKey.fromBase58(a.registry), application: recordToApplication(a.application) });
346
+ const ok = same(expected, a.fields);
347
+ const kept = BigInt(a.application.processingFee);
348
+ return {
349
+ kind: 'withdraw', title: 'Withdraw the application',
350
+ facts: [
351
+ ['Registry', a.registry], ['Network', a.network], ['Activities', scopeText(a.application.scope, ctx)],
352
+ ['Kept (processing fee)', mina(kept, a.network)], ['Refunded to the payer', mina(BigInt(a.application.fee) - kept, a.network)],
353
+ ],
354
+ network: a.network, registry: a.registry, verified: ok, ...(ok ? {} : { problem: 'The numbers to sign do not match these details. Do not sign.' }),
355
+ fingerprint: fingerprint(a.fields),
356
+ };
357
+ }
358
+
359
+ /** What any zkPermits field message is, from the numbers alone (kind, network, registry); details need describeRequest. */
360
+ export function identifyPermitMessage(fields: string[]): { kind: string | null; network: PermitNetwork | null; registry: string | null; fingerprint: string } {
361
+ return { ...header(fields), fingerprint: fingerprint(fields) };
362
+ }
@@ -0,0 +1,146 @@
1
+ // Copyright (c) 2025-2026 zkLicensing project developers
2
+ // SPDX-License-Identifier: BUSL-1.1
3
+
4
+ /**
5
+ * permitInterface.ts — `zklicensing/permits/interface`
6
+ *
7
+ * Public interface of the PermitRegistry contract: event shapes, state
8
+ * layout indices and the canonical verification-key hashes. Enough to
9
+ * decode events and rebuild a registry's tree without the private circuit
10
+ * source (same split as contractInterface.ts for licensing).
11
+ */
12
+
13
+ import { Bool, Field, PublicKey, SmartContract, Struct, UInt32, UInt64 } from 'o1js';
14
+ import { Application, PermitLeaf } from './permitMessages.js';
15
+ import { PayoutChangedEvent, PayoutProposedEvent, PlatformChangedEvent } from './contractInterface.js';
16
+ export { PayoutChangedEvent, PayoutProposedEvent, PlatformChangedEvent };
17
+
18
+ export const PermitGrantedEvent: any = Struct({
19
+ leaf: PermitLeaf,
20
+ fee: UInt64,
21
+ payer: PublicKey,
22
+ isNew: Field, // 1 = first grant for this subject, 0 = renewal / change
23
+ });
24
+ export type PermitGrantedEvent = any;
25
+
26
+ export const PermitStatusEvent: any = Struct({
27
+ leaf: PermitLeaf, // the leaf after the change
28
+ reasonCode: Field, // authority's reason code; 0 for surrender
29
+ });
30
+ export type PermitStatusEvent = any;
31
+
32
+ export const FeesUpdatedEvent: any = Struct({ feesPacked: Field, appTermsPacked: Field, actionNonce: UInt32 });
33
+ export type FeesUpdatedEvent = any;
34
+
35
+ export const AuthorityRotatedEvent: any = Struct({ keysHash: Field, epoch: UInt32 });
36
+ export type AuthorityRotatedEvent = any;
37
+
38
+ /**
39
+ * The registry was initialized; `permitsRoot` is the tree it starts with (its
40
+ * predecessor's frozen permits on a redeploy) and `predecessor` the retired
41
+ * registry it continues (PublicKey.empty() for a first generation), so a
42
+ * registry's lineage can be rebuilt from chain events alone.
43
+ */
44
+ export const RegistryCreatedEvent: any = Struct({ keysHash: Field, network: Field, payout: PublicKey, permitsRoot: Field, predecessor: PublicKey });
45
+ /** The registry was retired for a redeploy: its permits are frozen at `permitsRoot`, and only `successor` can start from them. */
46
+ /**
47
+ * `byPlatform`: retired by the platform key (retireByPlatform), not the
48
+ * authority's keys; `forced`: with application fees still in escrow, which
49
+ * stay on the retired registry.
50
+ */
51
+ export const RegistryRetiredEvent: any = Struct({ permitsRoot: Field, actionNonce: UInt32, successor: PublicKey, byPlatform: Bool, forced: Bool });
52
+ export type RegistryCreatedEvent = any;
53
+
54
+ // Application escrow.
55
+ export const ApplicationFiledEvent: any = Struct({ application: Application });
56
+ export type ApplicationFiledEvent = any;
57
+
58
+ /** A permit moved to a new holder key: `leaf` is the new one (its old leaf is closed as MOVED, in a permitStatusChanged event). */
59
+ export const PermitMovedEvent: any = Struct({ oldSubject: Field, leaf: PermitLeaf });
60
+ export type PermitMovedEvent = any;
61
+
62
+ export const ApplicationSettledEvent: any = Struct({
63
+ subject: Field,
64
+ applicationHash: Field,
65
+ outcome: Field, // APPLICATION_OUTCOME: 1 approved, 2 rejected, 3 withdrawn, 4 reclaimed, 5 cancelled by the platform
66
+ kept: UInt64, // paid out to the authority and the platform (98/2)
67
+ refunded: UInt64, // returned to the payer
68
+ });
69
+ export type ApplicationSettledEvent = any;
70
+
71
+
72
+ /** On-chain state layout (appState index → field), for direct account reads. */
73
+ export const PERMIT_REGISTRY_STATE = {
74
+ permitsRoot: 0,
75
+ authorityKeysHash: 1,
76
+ authorityEpoch: 2,
77
+ actionNonce: 3,
78
+ policyPacked: 4,
79
+ feesPacked: 5,
80
+ payoutX: 6,
81
+ payoutIsOdd: 7,
82
+ version: 8,
83
+ ancestorsRoot: 9,
84
+ forkActivationSlot: 10,
85
+ metadataHash: 11,
86
+ networkId: 12,
87
+ escrowRoot: 13,
88
+ appTermsPacked: 14,
89
+ filingCount: 15,
90
+ successorX: 16,
91
+ successorIsOdd: 17,
92
+ pendingPayoutX: 18,
93
+ pendingPayoutIsOdd: 19,
94
+ pendingPayoutSlot: 20,
95
+ platformX: 21,
96
+ platformIsOdd: 22,
97
+ treasuryX: 23,
98
+ treasuryIsOdd: 24,
99
+ platformEpoch: 25,
100
+ /** Set by a platform retire: the key set the successor must keep (0 after the authority's own retire). */
101
+ frozenKeysHash: 26,
102
+ } as const;
103
+
104
+ /** Source version of the PermitRegistry circuit, set at initialize. */
105
+ export const PERMIT_REGISTRY_VERSION = 1;
106
+
107
+ /**
108
+ * Canonical PermitRegistry verification-key hashes by generation (the
109
+ * platform address is compiled in). Append-only, like CANONICAL_VK_HASHES:
110
+ * add a row for a new circuit release, never delete one. The keeper refuses
111
+ * to prove with a circuit whose hash isn't the current row, and the
112
+ * vkDrift test catches an unintended change.
113
+ */
114
+ export const CANONICAL_PERMIT_VK_HASHES: Readonly<Record<number, string>> = {
115
+ 1: '27337945734556665205684717094424577317630618958452630976255659397562153215921',
116
+ };
117
+
118
+ export const CURRENT_PERMIT_GENERATION: number = 1;
119
+
120
+ export const CANONICAL_PERMIT_VK_HASH: string = CANONICAL_PERMIT_VK_HASHES[CURRENT_PERMIT_GENERATION];
121
+
122
+ /** Verification-key hash of the PermitProof holder-proof ZkProgram. */
123
+ export const CANONICAL_PERMIT_PROOF_VK_HASH: string = '17966873603167039790277974846902264570097359740655050143055465189220786366055';
124
+
125
+ /**
126
+ * Events-only view of a PermitRegistry: `new PermitRegistryEvents(address)
127
+ * .fetchEvents(from?)` decodes a registry's events (archive node or local
128
+ * chain) without the private circuit source. Event names and shapes match
129
+ * PermitRegistry exactly, so the type indices agree.
130
+ */
131
+ export const PermitRegistryEvents: any = class PermitRegistryEvents extends SmartContract {
132
+ events: any = {
133
+ registryCreated: RegistryCreatedEvent,
134
+ permitGranted: PermitGrantedEvent,
135
+ permitStatusChanged: PermitStatusEvent,
136
+ feesUpdated: FeesUpdatedEvent,
137
+ authorityRotated: AuthorityRotatedEvent,
138
+ applicationFiled: ApplicationFiledEvent,
139
+ applicationSettled: ApplicationSettledEvent,
140
+ registryRetired: RegistryRetiredEvent,
141
+ permitMoved: PermitMovedEvent,
142
+ payoutProposed: PayoutProposedEvent,
143
+ payoutChanged: PayoutChangedEvent,
144
+ platformChanged: PlatformChangedEvent,
145
+ };
146
+ };