@silvana-one/upgradable 0.1.0

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 ADDED
@@ -0,0 +1,70 @@
1
+ # Upgradable Interface for Mina zkApps
2
+
3
+ ## Upgrade Authority Contract
4
+
5
+ The **Upgrade Authority Contract** provides a secure mechanism for upgrading the verification keys of smart contracts without requiring redeployment. It manages a list of validators who can vote on upgrade proposals, ensuring that only authorized upgrades are applied.
6
+
7
+ #### Key Features
8
+
9
+ - **Verification Key Management**: Allows for secure upgrades of verification keys for other contracts.
10
+ - **Validators Governance**: Maintains a list of authorized validators who can vote on upgrade proposals.
11
+ - **Secure Voting Mechanism**: Implements Zero-Knowledge proofs to validate votes from validators without revealing sensitive information.
12
+ - **Upgrade Database Management**: Keeps track of upgrade proposals and their validity periods.
13
+ - **Event Emissions**: Emits events when validators list or upgrade database is updated.
14
+
15
+ #### State Variables
16
+
17
+ - `verificationKeyHash`: The hash of the proof verification key (`Field`).
18
+ - `validators`: The hash representing the current state of the validators list (`Field`).
19
+ - `upgradeDatabasePacked`: Packed state containing the upgrade database information (`UpgradeDatabaseStatePacked`).
20
+
21
+ #### Key Methods
22
+
23
+ ```typescript:src/upgrade/upgrade.ts
24
+ class VerificationKeyUpgradeAuthority extends SmartContract implements UpgradeAuthorityBase {
25
+ @method
26
+ async initialize(validators: ValidatorsState, storage: Storage, verificationKeyHash: Field) {
27
+ // Initialize the contract with validators and set the verification key hash
28
+ }
29
+
30
+ @method.returns(UpgradeAuthorityAnswer)
31
+ async verifyUpgradeData(data: VerificationKeyUpgradeData): Promise<UpgradeAuthorityAnswer> {
32
+ // Verify the upgrade data provided by another contract
33
+ }
34
+
35
+ @method
36
+ async updateDatabase(proof: ValidatorsVotingProof, vk: VerificationKey) {
37
+ // Update the upgrade database after validator consensus
38
+ }
39
+
40
+ @method
41
+ async updateValidatorsList(validators: ValidatorsState, storage: Storage, proof: ValidatorsVotingProof, vk: VerificationKey) {
42
+ // Update the validators list based on validator votes
43
+ }
44
+
45
+ // ... Additional methods and helper functions
46
+ }
47
+ ```
48
+
49
+ #### Events
50
+
51
+ - `validatorsList`: Emitted when the validators list is updated.
52
+ - `updateDatabase`: Emitted when the upgrade database is updated.
53
+
54
+ #### Notes
55
+
56
+ - **Validator Governance**: Validators can vote on upgrade proposals. The contract uses Zero-Knowledge proofs (ZkPrograms) to verify validator votes securely.
57
+ - **Upgrade Process**: Contracts wishing to upgrade their verification keys interact with the Upgrade Authority Contract to verify that the new verification key is authorized.
58
+ - **Validators List Management**: The validators list is stored as a Merkle Tree for efficient verification and can be updated through consensus.
59
+ - **Off-chain Data**: Some data, like the full validators list, is stored off-chain (e.g., in IPFS) with only the root hash stored on-chain to optimize performance.
60
+ - **Security**: The contract ensures that only valid upgrade proposals that have been approved by the required number of validators are executed.
61
+
62
+ #### Usage Example
63
+
64
+ This contract is essential for scenarios where:
65
+
66
+ - **Decentralized Governance**: Multiple validators need to agree on contract upgrades, ensuring no single party can unilaterally upgrade the contract.
67
+ - **Secure Contract Upgrades**: Contracts can securely upgrade their verification keys without redeploying, maintaining continuity and state.
68
+ - **Regulated Environments**: Applications requiring compliance and oversight can leverage validator governance for contract changes.
69
+
70
+ For a contract to utilize the Upgrade Authority Contract, it needs to implement the `UpgradableContract` interface and interact with the `VerificationKeyUpgradeAuthority` for upgrading its verification key securely.
@@ -0,0 +1,625 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // dist/node/index.js
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ChainId: () => ChainId,
34
+ PublicKeyOption: () => PublicKeyOption,
35
+ UpgradeAuthorityAnswer: () => UpgradeAuthorityAnswer,
36
+ UpgradeAuthorityDatabase: () => UpgradeAuthorityDatabase,
37
+ UpgradeDatabaseState: () => UpgradeDatabaseState,
38
+ UpgradeDatabaseStatePacked: () => UpgradeDatabaseStatePacked,
39
+ ValidatorDecisionType: () => ValidatorDecisionType,
40
+ ValidatorsDecision: () => ValidatorsDecision,
41
+ ValidatorsDecisionState: () => ValidatorsDecisionState,
42
+ ValidatorsList: () => ValidatorsList,
43
+ ValidatorsListEvent: () => ValidatorsListEvent,
44
+ ValidatorsState: () => ValidatorsState,
45
+ ValidatorsVoting: () => ValidatorsVoting,
46
+ ValidatorsVotingNativeProof: () => ValidatorsVotingNativeProof,
47
+ ValidatorsVotingProof: () => ValidatorsVotingProof,
48
+ VerificationKeyUpgradeAuthority: () => VerificationKeyUpgradeAuthority,
49
+ VerificationKeyUpgradeData: () => VerificationKeyUpgradeData
50
+ });
51
+ module.exports = __toCommonJS(index_exports);
52
+
53
+ // dist/node/validators.js
54
+ var import_o1js2 = require("o1js");
55
+ var import_storage = require("@silvana-one/storage");
56
+
57
+ // dist/node/upgradable.js
58
+ var import_o1js = require("o1js");
59
+ var VerificationKeyUpgradeData = class _VerificationKeyUpgradeData extends (0, import_o1js.Struct)({
60
+ /** The address of the contract to be upgraded. */
61
+ address: import_o1js.PublicKey,
62
+ /** The token ID associated with the contract. */
63
+ tokenId: import_o1js.Field,
64
+ /** The hash of the previous verification key. */
65
+ previousVerificationKeyHash: import_o1js.Field,
66
+ /** The hash of the new verification key. */
67
+ newVerificationKeyHash: import_o1js.Field
68
+ }) {
69
+ /**
70
+ * Generates a unique hash for the upgrade data using the Poseidon hash function.
71
+ * @returns {Field} The hash representing the upgrade data.
72
+ */
73
+ hash() {
74
+ return import_o1js.Poseidon.hash(_VerificationKeyUpgradeData.toFields(this));
75
+ }
76
+ };
77
+ var PublicKeyOption = class extends (0, import_o1js.Option)(import_o1js.PublicKey) {
78
+ };
79
+ var UpgradeAuthorityAnswer = class extends (0, import_o1js.Struct)({
80
+ /**
81
+ * The public key of the next upgrade authority, if a change is required.
82
+ *
83
+ * If we upgrade the verification key, we may not be able to use the same upgrade
84
+ * authority next time because the new o1js version can break the verification key
85
+ * of the upgrade authority too, and since the upgrade authority serves many
86
+ * contracts, it cannot be upgraded. In this case, we need to use another upgrade
87
+ * authority with the public key that will be provided in `nextUpgradeAuthority`.
88
+ */
89
+ nextUpgradeAuthority: PublicKeyOption,
90
+ /** Indicates whether the upgrade data has been successfully verified. */
91
+ isVerified: import_o1js.Bool
92
+ }) {
93
+ };
94
+
95
+ // dist/node/validators.js
96
+ var import_mina_signer = __toESM(require("mina-signer"), 1);
97
+ var { IndexedMerkleMap } = import_o1js2.Experimental;
98
+ var VALIDATORS_LIST_HEIGHT = 10;
99
+ var UPGRADE_AUTHORITY_DATABASE_HEIGHT = 20;
100
+ var ValidatorsList = class extends IndexedMerkleMap(VALIDATORS_LIST_HEIGHT) {
101
+ };
102
+ var UpgradeAuthorityDatabase = class extends IndexedMerkleMap(UPGRADE_AUTHORITY_DATABASE_HEIGHT) {
103
+ };
104
+ var ChainId = {
105
+ "mina:mainnet": fieldFromString("mina:mainnet"),
106
+ "mina:devnet": fieldFromString("mina:devnet"),
107
+ "zeko:mainnet": fieldFromString("zeko:mainnet"),
108
+ "zeko:devnet": fieldFromString("zeko:devnet")
109
+ };
110
+ var ValidatorDecisionType = {
111
+ updateDatabase: fieldFromString("updateDatabase"),
112
+ updateValidatorsList: fieldFromString("updateValidatorsList")
113
+ };
114
+ var ValidatorsState = class _ValidatorsState extends (0, import_o1js2.Struct)({
115
+ /** Chain ID (e.g., 'mina:mainnet') */
116
+ chainId: import_o1js2.Field,
117
+ /** Merkle root of the ValidatorsList */
118
+ root: import_o1js2.Field,
119
+ /** Number of validators */
120
+ count: import_o1js2.UInt32
121
+ }) {
122
+ /**
123
+ * Asserts that two `ValidatorsState` instances are equal.
124
+ * @param a First `ValidatorsState` instance.
125
+ * @param b Second `ValidatorsState` instance.
126
+ */
127
+ static assertEquals(a, b) {
128
+ a.chainId.assertEquals(b.chainId);
129
+ a.root.assertEquals(b.root);
130
+ a.count.assertEquals(b.count);
131
+ }
132
+ /**
133
+ * Computes the hash of the validators state.
134
+ * @returns Hash of the current state.
135
+ */
136
+ hash() {
137
+ return import_o1js2.Poseidon.hashPacked(_ValidatorsState, this);
138
+ }
139
+ /**
140
+ * Returns an empty `ValidatorsState`.
141
+ * @returns An empty `ValidatorsState` instance.
142
+ */
143
+ static empty() {
144
+ return new _ValidatorsState({
145
+ chainId: (0, import_o1js2.Field)(0),
146
+ root: (0, import_o1js2.Field)(0),
147
+ count: import_o1js2.UInt32.zero
148
+ });
149
+ }
150
+ };
151
+ var UpgradeDatabaseStatePacked = class extends (0, import_o1js2.Struct)({
152
+ /** Root of the UpgradeAuthority database */
153
+ root: import_o1js2.Field,
154
+ /** Storage information (e.g., IPFS hash) */
155
+ storage: import_storage.Storage,
156
+ /** X-coordinate of the next upgrade authority's public key */
157
+ nextUpgradeAuthorityX: import_o1js2.Field,
158
+ /** Packed data containing version, validFrom, and flags */
159
+ data: import_o1js2.Field
160
+ }) {
161
+ };
162
+ var UpgradeDatabaseState = class _UpgradeDatabaseState extends (0, import_o1js2.Struct)({
163
+ /** Root of the UpgradeAuthority database */
164
+ root: import_o1js2.Field,
165
+ /** Storage information (e.g., IPFS hash) */
166
+ storage: import_storage.Storage,
167
+ /** Optional public key of the next upgrade authority */
168
+ nextUpgradeAuthority: PublicKeyOption,
169
+ /** Version of the UpgradeAuthorityDatabase */
170
+ version: import_o1js2.UInt32,
171
+ /** Slot when the UpgradeAuthority is valid from */
172
+ validFrom: import_o1js2.UInt32
173
+ }) {
174
+ /**
175
+ * Asserts that two `UpgradeDatabaseState` instances are equal.
176
+ * @param a First `UpgradeDatabaseState` instance.
177
+ * @param b Second `UpgradeDatabaseState` instance.
178
+ */
179
+ static assertEquals(a, b) {
180
+ a.root.assertEquals(b.root);
181
+ import_storage.Storage.assertEquals(a.storage, b.storage);
182
+ a.nextUpgradeAuthority.value.assertEquals(b.nextUpgradeAuthority.value);
183
+ a.nextUpgradeAuthority.isSome.assertEquals(b.nextUpgradeAuthority.isSome);
184
+ a.version.assertEquals(b.version);
185
+ }
186
+ /**
187
+ * Returns an empty `UpgradeDatabaseState`.
188
+ * @returns An empty `UpgradeDatabaseState` instance.
189
+ */
190
+ static empty() {
191
+ return new _UpgradeDatabaseState({
192
+ root: new UpgradeAuthorityDatabase().root,
193
+ storage: import_storage.Storage.empty(),
194
+ nextUpgradeAuthority: PublicKeyOption.none(),
195
+ version: import_o1js2.UInt32.zero,
196
+ validFrom: import_o1js2.UInt32.MAXINT()
197
+ });
198
+ }
199
+ /**
200
+ * Packs the `UpgradeDatabaseState` into a `UpgradeDatabaseStatePacked`.
201
+ * @returns A packed representation of the upgrade database state.
202
+ */
203
+ pack() {
204
+ const nextUpgradeAuthorityX = this.nextUpgradeAuthority.value.x;
205
+ const data = import_o1js2.Field.fromBits([
206
+ ...this.version.value.toBits(32),
207
+ ...this.validFrom.value.toBits(32),
208
+ this.nextUpgradeAuthority.value.isOdd,
209
+ this.nextUpgradeAuthority.isSome
210
+ ]);
211
+ return new UpgradeDatabaseStatePacked({
212
+ root: this.root,
213
+ storage: this.storage,
214
+ nextUpgradeAuthorityX,
215
+ data
216
+ });
217
+ }
218
+ /**
219
+ * Unpacks a `UpgradeDatabaseStatePacked` into a `UpgradeDatabaseState`.
220
+ * @param packed The packed upgrade database state.
221
+ * @returns An unpacked `UpgradeDatabaseState` instance.
222
+ */
223
+ static unpack(packed) {
224
+ const bits = packed.data.toBits(66);
225
+ const versionBits = bits.slice(0, 32);
226
+ const validFromBits = bits.slice(32, 64);
227
+ const isOddBit = bits[64];
228
+ const isSomeBit = bits[65];
229
+ const version = import_o1js2.UInt32.Unsafe.fromField(import_o1js2.Field.fromBits(versionBits));
230
+ const validFrom = import_o1js2.UInt32.Unsafe.fromField(import_o1js2.Field.fromBits(validFromBits));
231
+ const nextUpgradeAuthority = PublicKeyOption.from(import_o1js2.PublicKey.from({ x: packed.nextUpgradeAuthorityX, isOdd: isOddBit }));
232
+ nextUpgradeAuthority.isSome = isSomeBit;
233
+ return new _UpgradeDatabaseState({
234
+ root: packed.root,
235
+ storage: packed.storage,
236
+ nextUpgradeAuthority,
237
+ version,
238
+ validFrom
239
+ });
240
+ }
241
+ };
242
+ var ValidatorsDecision = class _ValidatorsDecision extends (0, import_o1js2.Struct)({
243
+ /** Message to be signed when producing the nullifier, also serves as the nonce to prevent replay attacks */
244
+ message: import_o1js2.Field,
245
+ /** Type of decision (e.g., 'updateDatabase') */
246
+ decisionType: import_o1js2.Field,
247
+ /** UpgradeAuthority contract address */
248
+ contractAddress: import_o1js2.PublicKey,
249
+ /** Chain ID */
250
+ chainId: import_o1js2.Field,
251
+ /** Current validators state */
252
+ validators: ValidatorsState,
253
+ /** Current upgrade database state */
254
+ upgradeDatabase: UpgradeDatabaseState,
255
+ /** Proposed update to validators state */
256
+ updateValidatorsList: ValidatorsState,
257
+ /** Slot when decision expires */
258
+ expiry: import_o1js2.UInt32
259
+ }) {
260
+ /**
261
+ * Asserts that two `ValidatorsDecision` instances are equal.
262
+ * @param a First `ValidatorsDecision` instance.
263
+ * @param b Second `ValidatorsDecision` instance.
264
+ */
265
+ static assertEquals(a, b) {
266
+ a.message.assertEquals(b.message);
267
+ a.decisionType.assertEquals(b.decisionType);
268
+ a.contractAddress.assertEquals(b.contractAddress);
269
+ a.chainId.assertEquals(b.chainId);
270
+ ValidatorsState.assertEquals(a.validators, b.validators);
271
+ UpgradeDatabaseState.assertEquals(a.upgradeDatabase, b.upgradeDatabase);
272
+ a.expiry.assertEquals(b.expiry);
273
+ }
274
+ createNullifierMessage() {
275
+ return [this.message, ..._ValidatorsDecision.toFields(this)];
276
+ }
277
+ createJsonNullifier(params) {
278
+ const { network, privateKey } = params;
279
+ const minaSigner = new import_mina_signer.default({ network });
280
+ const message = this.createNullifierMessage();
281
+ const nullifier = minaSigner.createNullifier(message.map((field) => field.toBigInt()), privateKey.toBase58());
282
+ return nullifier;
283
+ }
284
+ };
285
+ var ValidatorsDecisionState = class _ValidatorsDecisionState extends (0, import_o1js2.Struct)({
286
+ /** The validators' decision */
287
+ decision: ValidatorsDecision,
288
+ /** Indexed Merkle Map root of the validators who have voted */
289
+ alreadyVoted: import_o1js2.Field,
290
+ /** Number of votes in favor of the decision */
291
+ yesVotes: import_o1js2.UInt32,
292
+ /** Number of votes against the decision */
293
+ noVotes: import_o1js2.UInt32,
294
+ /** Number of votes of abstention */
295
+ abstainVotes: import_o1js2.UInt32
296
+ }) {
297
+ static startVoting(decision) {
298
+ return new _ValidatorsDecisionState({
299
+ decision,
300
+ alreadyVoted: new ValidatorsList().root,
301
+ yesVotes: import_o1js2.UInt32.zero,
302
+ noVotes: import_o1js2.UInt32.zero,
303
+ abstainVotes: import_o1js2.UInt32.zero
304
+ });
305
+ }
306
+ /**
307
+ * Records a vote
308
+ * @param validatorNullifier The nullifier of the validator.
309
+ * @param validatorsList The ValidatorsList containing authorized validators.
310
+ * @param votedList The ValidatorsList tracking who has already voted.
311
+ * @param yes Whether this is a "yes" vote.
312
+ * @param no Whether this is a "no" vote.
313
+ * @param abstain Whether this is an "abstain" vote.
314
+ * @param signature The signature of the validator.
315
+ * @returns A new `ValidatorsDecisionState` reflecting the vote.
316
+ */
317
+ vote(validatorNullifier, validatorsList, votedList, yes, no, abstain, signature) {
318
+ const publicKey = validatorNullifier.getPublicKey();
319
+ const key = validatorNullifier.key();
320
+ validatorNullifier.verify(this.decision.createNullifierMessage());
321
+ const previousVotesCount = this.yesVotes.add(this.noVotes).add(this.abstainVotes);
322
+ const yesVotes = this.yesVotes.add(import_o1js2.Provable.if(yes, import_o1js2.UInt32.from(1), import_o1js2.UInt32.from(0)));
323
+ const noVotes = this.noVotes.add(import_o1js2.Provable.if(no, import_o1js2.UInt32.from(1), import_o1js2.UInt32.from(0)));
324
+ const abstainVotes = this.abstainVotes.add(import_o1js2.Provable.if(abstain, import_o1js2.UInt32.from(1), import_o1js2.UInt32.from(0)));
325
+ previousVotesCount.add(import_o1js2.UInt32.from(1)).assertEquals(yesVotes.add(noVotes).add(abstainVotes));
326
+ const hash = import_o1js2.Poseidon.hashPacked(import_o1js2.PublicKey, publicKey);
327
+ validatorsList.root.assertEquals(this.decision.validators.root);
328
+ validatorsList.get(hash).assertBool("Wrong ValidatorsList format").assertTrue("Validator doesn't have authority to sign");
329
+ signature.verify(publicKey, ValidatorsDecision.toFields(this.decision)).assertTrue("Wrong validator signature");
330
+ this.decision.validators.root.assertEquals(validatorsList.root);
331
+ votedList.root.assertEquals(this.alreadyVoted);
332
+ votedList.insert(key, (0, import_o1js2.Field)(1));
333
+ return new _ValidatorsDecisionState({
334
+ decision: this.decision,
335
+ alreadyVoted: votedList.root,
336
+ yesVotes,
337
+ noVotes,
338
+ abstainVotes
339
+ });
340
+ }
341
+ /**
342
+ * Asserts that two `ValidatorsDecisionState` instances are equal.
343
+ * @param a First `ValidatorsDecisionState` instance.
344
+ * @param b Second `ValidatorsDecisionState` instance.
345
+ */
346
+ static assertEquals(a, b) {
347
+ ValidatorsDecision.assertEquals(a.decision, b.decision);
348
+ a.alreadyVoted.assertEquals(b.alreadyVoted);
349
+ a.yesVotes.assertEquals(b.yesVotes);
350
+ a.noVotes.assertEquals(b.noVotes);
351
+ a.abstainVotes.assertEquals(b.abstainVotes);
352
+ }
353
+ };
354
+ var ValidatorsVoting = (0, import_o1js2.ZkProgram)({
355
+ name: "ValidatorsVoting",
356
+ publicInput: ValidatorsDecisionState,
357
+ publicOutput: ValidatorsDecisionState,
358
+ methods: {
359
+ /**
360
+ * Starts the voting process for a decision.
361
+ */
362
+ startVoting: {
363
+ privateInputs: [ValidatorsDecision],
364
+ async method(state2, decision) {
365
+ const calculatedState = ValidatorsDecisionState.startVoting(decision);
366
+ ValidatorsDecisionState.assertEquals(state2, calculatedState);
367
+ return { publicOutput: calculatedState };
368
+ }
369
+ },
370
+ /**
371
+ * Records a vote
372
+ */
373
+ vote: {
374
+ privateInputs: [
375
+ ValidatorsDecision,
376
+ import_o1js2.Nullifier,
377
+ ValidatorsList,
378
+ ValidatorsList,
379
+ import_o1js2.Bool,
380
+ import_o1js2.Bool,
381
+ import_o1js2.Bool,
382
+ import_o1js2.Signature
383
+ ],
384
+ async method(state2, decision, nullifier, validatorsList, votedList, yes, no, abstain, signature) {
385
+ const calculatedState = state2.vote(nullifier, validatorsList, votedList, yes, no, abstain, signature);
386
+ return { publicOutput: calculatedState };
387
+ }
388
+ },
389
+ /**
390
+ * Merges two `ValidatorsDecisionState` proofs.
391
+ */
392
+ merge: {
393
+ privateInputs: [import_o1js2.SelfProof, import_o1js2.SelfProof],
394
+ async method(state2, proof1, proof2) {
395
+ proof1.verify();
396
+ proof2.verify();
397
+ ValidatorsDecisionState.assertEquals(state2, proof1.publicInput);
398
+ ValidatorsDecisionState.assertEquals(proof1.publicOutput, proof2.publicInput);
399
+ return { publicOutput: proof2.publicOutput };
400
+ }
401
+ }
402
+ }
403
+ });
404
+ var ValidatorsVotingNativeProof = class extends import_o1js2.ZkProgram.Proof(ValidatorsVoting) {
405
+ };
406
+ var _ValidatorsVotingProof = class _ValidatorsVotingProof extends import_o1js2.DynamicProof {
407
+ };
408
+ _ValidatorsVotingProof.publicInputType = ValidatorsDecisionState;
409
+ _ValidatorsVotingProof.publicOutputType = ValidatorsDecisionState;
410
+ _ValidatorsVotingProof.maxProofsVerified = 2;
411
+ _ValidatorsVotingProof.featureFlags = import_o1js2.FeatureFlags.allMaybe;
412
+ var ValidatorsVotingProof = _ValidatorsVotingProof;
413
+ function fieldFromString(storage) {
414
+ const fields = import_o1js2.Encoding.stringToFields(storage);
415
+ if (fields.length !== 1)
416
+ throw new Error("String is too long");
417
+ return fields[0];
418
+ }
419
+
420
+ // dist/node/upgrade.js
421
+ var import_tslib = require("tslib");
422
+ var import_o1js3 = require("o1js");
423
+ var import_storage2 = require("@silvana-one/storage");
424
+ var ValidatorsListEvent = class extends (0, import_o1js3.Struct)({
425
+ validators: ValidatorsState,
426
+ storage: import_storage2.Storage
427
+ }) {
428
+ };
429
+ var VerificationKeyUpgradeAuthorityErrors = {
430
+ WrongNewVerificationKeyHash: "Wrong new verification key hash"
431
+ };
432
+ var VerificationKeyUpgradeAuthority = class extends import_o1js3.SmartContract {
433
+ constructor() {
434
+ super(...arguments);
435
+ this.verificationKeyHash = (0, import_o1js3.State)();
436
+ this.validators = (0, import_o1js3.State)();
437
+ this.upgradeDatabasePacked = (0, import_o1js3.State)();
438
+ this.events = {
439
+ validatorsList: ValidatorsListEvent,
440
+ updateDatabase: UpgradeDatabaseState
441
+ };
442
+ }
443
+ /**
444
+ * Deploys the contract and sets the initial state.
445
+ */
446
+ async deploy() {
447
+ await super.deploy();
448
+ this.upgradeDatabasePacked.set(UpgradeDatabaseState.empty().pack());
449
+ this.account.permissions.set({
450
+ ...import_o1js3.Permissions.default(),
451
+ setVerificationKey: (
452
+ // The contract needs to be redeployed in the case of an upgrade.
453
+ import_o1js3.Permissions.VerificationKey.impossibleDuringCurrentVersion()
454
+ ),
455
+ setPermissions: import_o1js3.Permissions.impossible()
456
+ });
457
+ }
458
+ /**
459
+ * Initializes the contract with validators and sets the verification key hash.
460
+ *
461
+ * @param {ValidatorsState} validators - The initial validators state.
462
+ * @param {Storage} storage - Off-chain storage information, e.g., IPFS hash.
463
+ * @param {Field} verificationKeyHash - The hash of the verification key.
464
+ */
465
+ async initialize(validators, storage, verificationKeyHash) {
466
+ this.account.provedState.requireEquals((0, import_o1js3.Bool)(false));
467
+ await this.setValidatorsList(validators, storage);
468
+ this.verificationKeyHash.set(verificationKeyHash);
469
+ }
470
+ /**
471
+ * Sets the validators list and emits an event.
472
+ *
473
+ * @param {ValidatorsState} validators - The validators state to set.
474
+ * @param {Storage} storage - The storage associated with the validators list.
475
+ */
476
+ async setValidatorsList(validators, storage) {
477
+ this.validators.set(validators.hash());
478
+ this.emitEvent("validatorsList", new ValidatorsListEvent({ validators, storage }));
479
+ }
480
+ /**
481
+ * Verifies the upgrade data provided by another contract.
482
+ *
483
+ * @param {VerificationKeyUpgradeData} data - The upgrade data to verify.
484
+ * @returns {Promise<UpgradeAuthorityAnswer>} - The answer indicating verification result.
485
+ */
486
+ async verifyUpgradeData(data) {
487
+ const upgradeDatabase = UpgradeDatabaseState.unpack(this.upgradeDatabasePacked.getAndRequireEquals());
488
+ this.network.globalSlotSinceGenesis.requireBetween(upgradeDatabase.validFrom, import_o1js3.UInt32.MAXINT());
489
+ const map = await import_o1js3.Provable.witnessAsync(UpgradeAuthorityDatabase, async () => {
490
+ return await (0, import_storage2.loadIndexedMerkleMap)({
491
+ url: (0, import_storage2.createIpfsURL)({ hash: upgradeDatabase.storage.toString() }),
492
+ type: UpgradeAuthorityDatabase
493
+ });
494
+ });
495
+ map.root.assertEquals(upgradeDatabase.root);
496
+ const key = data.hash();
497
+ const newVerificationKeyHash = map.get(key);
498
+ newVerificationKeyHash.assertEquals(data.newVerificationKeyHash, VerificationKeyUpgradeAuthorityErrors.WrongNewVerificationKeyHash);
499
+ return new UpgradeAuthorityAnswer({
500
+ // Should be public key of the next upgrade authority in case
501
+ // new version of o1js breaks the verification key of upgrade authority
502
+ nextUpgradeAuthority: upgradeDatabase.nextUpgradeAuthority,
503
+ isVerified: (0, import_o1js3.Bool)(true)
504
+ });
505
+ }
506
+ /**
507
+ * Updates the upgrade database after validator consensus.
508
+ *
509
+ * @param {ValidatorsVotingProof} proof - The proof of validators voting.
510
+ * @param {VerificationKey} vk - The verification key to validate the proof.
511
+ */
512
+ async updateDatabase(proof, vk, validators) {
513
+ const oldUpgradeDatabase = UpgradeDatabaseState.unpack(this.upgradeDatabasePacked.getAndRequireEquals());
514
+ const upgradeDatabase = proof.publicInput.decision.upgradeDatabase;
515
+ upgradeDatabase.version.assertGreaterThan(oldUpgradeDatabase.version);
516
+ await this.checkValidatorsDecision(proof, vk, ValidatorDecisionType["updateDatabase"], validators);
517
+ const map = await import_o1js3.Provable.witnessAsync(UpgradeAuthorityDatabase, async () => {
518
+ return await (0, import_storage2.loadIndexedMerkleMap)({
519
+ url: (0, import_storage2.createIpfsURL)({ hash: upgradeDatabase.storage.toString() }),
520
+ type: UpgradeAuthorityDatabase
521
+ });
522
+ });
523
+ map.root.assertEquals(upgradeDatabase.root);
524
+ this.upgradeDatabasePacked.set(upgradeDatabase.pack());
525
+ this.emitEvent("updateDatabase", upgradeDatabase);
526
+ }
527
+ /**
528
+ * Updates the validators list based on validator votes.
529
+ *
530
+ * @param {ValidatorsState} validators - The new validators state.
531
+ * @param {Storage} storage - The storage associated with the validators list.
532
+ * @param {ValidatorsVotingProof} proof - The proof of validators voting.
533
+ * @param {VerificationKey} vk - The verification key to validate the proof.
534
+ */
535
+ async updateValidatorsList(validators, storage, proof, vk) {
536
+ await this.checkValidatorsDecision(proof, vk, ValidatorDecisionType["updateValidatorsList"], validators);
537
+ await this.setValidatorsList(validators, storage);
538
+ }
539
+ /**
540
+ * Checks the validators' decision by verifying the provided proof.
541
+ *
542
+ * @param {ValidatorsVotingProof} proof - The proof to verify.
543
+ * @param {VerificationKey} vk - The verification key to validate the proof.
544
+ * @param {Field} decisionType - The type of decision being validated.
545
+ */
546
+ async checkValidatorsDecision(proof, vk, decisionType, validatorsState) {
547
+ this.network.globalSlotSinceGenesis.requireBetween(import_o1js3.UInt32.zero, proof.publicInput.decision.expiry);
548
+ vk.hash.assertEquals(this.verificationKeyHash.getAndRequireEquals());
549
+ proof.verify(vk);
550
+ proof.publicInput.decision.validators.hash().assertEquals(this.validators.getAndRequireEquals());
551
+ proof.publicInput.decision.decisionType.assertEquals(decisionType);
552
+ proof.publicInput.decision.contractAddress.assertEquals(this.address);
553
+ validatorsState.hash().assertEquals(this.validators.getAndRequireEquals());
554
+ proof.publicOutput.yesVotes.mul(2).assertGreaterThan(validatorsState.count);
555
+ }
556
+ };
557
+ (0, import_tslib.__decorate)([
558
+ (0, import_o1js3.state)(import_o1js3.Field),
559
+ (0, import_tslib.__metadata)("design:type", Object)
560
+ ], VerificationKeyUpgradeAuthority.prototype, "verificationKeyHash", void 0);
561
+ (0, import_tslib.__decorate)([
562
+ (0, import_o1js3.state)(import_o1js3.Field),
563
+ (0, import_tslib.__metadata)("design:type", Object)
564
+ ], VerificationKeyUpgradeAuthority.prototype, "validators", void 0);
565
+ (0, import_tslib.__decorate)([
566
+ (0, import_o1js3.state)(UpgradeDatabaseStatePacked),
567
+ (0, import_tslib.__metadata)("design:type", Object)
568
+ ], VerificationKeyUpgradeAuthority.prototype, "upgradeDatabasePacked", void 0);
569
+ (0, import_tslib.__decorate)([
570
+ import_o1js3.method,
571
+ (0, import_tslib.__metadata)("design:type", Function),
572
+ (0, import_tslib.__metadata)("design:paramtypes", [
573
+ ValidatorsState,
574
+ import_storage2.Storage,
575
+ import_o1js3.Field
576
+ ]),
577
+ (0, import_tslib.__metadata)("design:returntype", Promise)
578
+ ], VerificationKeyUpgradeAuthority.prototype, "initialize", null);
579
+ (0, import_tslib.__decorate)([
580
+ import_o1js3.method.returns(UpgradeAuthorityAnswer),
581
+ (0, import_tslib.__metadata)("design:type", Function),
582
+ (0, import_tslib.__metadata)("design:paramtypes", [VerificationKeyUpgradeData]),
583
+ (0, import_tslib.__metadata)("design:returntype", Promise)
584
+ ], VerificationKeyUpgradeAuthority.prototype, "verifyUpgradeData", null);
585
+ (0, import_tslib.__decorate)([
586
+ import_o1js3.method,
587
+ (0, import_tslib.__metadata)("design:type", Function),
588
+ (0, import_tslib.__metadata)("design:paramtypes", [
589
+ ValidatorsVotingProof,
590
+ import_o1js3.VerificationKey,
591
+ ValidatorsState
592
+ ]),
593
+ (0, import_tslib.__metadata)("design:returntype", Promise)
594
+ ], VerificationKeyUpgradeAuthority.prototype, "updateDatabase", null);
595
+ (0, import_tslib.__decorate)([
596
+ import_o1js3.method,
597
+ (0, import_tslib.__metadata)("design:type", Function),
598
+ (0, import_tslib.__metadata)("design:paramtypes", [
599
+ ValidatorsState,
600
+ import_storage2.Storage,
601
+ ValidatorsVotingProof,
602
+ import_o1js3.VerificationKey
603
+ ]),
604
+ (0, import_tslib.__metadata)("design:returntype", Promise)
605
+ ], VerificationKeyUpgradeAuthority.prototype, "updateValidatorsList", null);
606
+ // Annotate the CommonJS export names for ESM import in node:
607
+ 0 && (module.exports = {
608
+ ChainId,
609
+ PublicKeyOption,
610
+ UpgradeAuthorityAnswer,
611
+ UpgradeAuthorityDatabase,
612
+ UpgradeDatabaseState,
613
+ UpgradeDatabaseStatePacked,
614
+ ValidatorDecisionType,
615
+ ValidatorsDecision,
616
+ ValidatorsDecisionState,
617
+ ValidatorsList,
618
+ ValidatorsListEvent,
619
+ ValidatorsState,
620
+ ValidatorsVoting,
621
+ ValidatorsVotingNativeProof,
622
+ ValidatorsVotingProof,
623
+ VerificationKeyUpgradeAuthority,
624
+ VerificationKeyUpgradeData
625
+ });