@iexec-nox/nox-protocol-contracts 0.1.0-beta.7 → 0.1.0-beta.8

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.
@@ -20,6 +20,8 @@ interface INoxCompute {
20
20
  error UnsupportedType();
21
21
  error IncompatibleTypes();
22
22
  error NotPubliclyDecryptable(bytes32 handle);
23
+ /// Error thrown when attempting an ACL mutation on a public handle
24
+ error PublicHandleACLForbidden();
23
25
 
24
26
  /// Emitted when admin role is granted
25
27
  event Allowed(address indexed sender, address indexed account, bytes32 indexed handle);
@@ -31,7 +33,7 @@ interface INoxCompute {
31
33
  event GatewayUpdated(address indexed newGateway);
32
34
  event ProofExpirationDurationUpdated(uint256 newDuration);
33
35
 
34
- event PlaintextToEncrypted(
36
+ event WrapAsPublicHandle(
35
37
  address indexed caller,
36
38
  bytes32 plaintext,
37
39
  TEEType toType,
@@ -161,7 +163,7 @@ interface INoxCompute {
161
163
  );
162
164
 
163
165
  enum Operator {
164
- PlaintextToEncrypted,
166
+ WrapAsPublicHandle,
165
167
  Add,
166
168
  Sub,
167
169
  Mul,
@@ -200,11 +202,11 @@ interface INoxCompute {
200
202
  function allowTransient(bytes32 handle, address account) external;
201
203
 
202
204
  /**
203
- * Removes all transient authorizations. This is useful for integration with Account Abstraction
204
- * when bundling several UserOps calling the NoxCompute.
205
- * @dev Can be called by anyone (typically by AA bundlers between UserOps).
205
+ * Revokes transient access to `handle` for address `account` within the current transaction.
206
+ * @param handle Handle.
207
+ * @param account Address of the account.
206
208
  */
207
- function cleanTransientStorage() external;
209
+ function disallowTransient(bytes32 handle, address account) external;
208
210
 
209
211
  /**
210
212
  * Returns whether the account is allowed to use the `handle`, either due to
@@ -261,19 +263,38 @@ interface INoxCompute {
261
263
  // ------------- Compute functions -------------
262
264
 
263
265
  /**
264
- * @notice Converts a plaintext value into an encrypted value
265
- * @param value The plaintext value to encrypt
266
- * @param teeType The type of the encrypted value
267
- * @return The encrypted value
268
- */
269
- function plaintextToEncrypted(bytes32 value, TEEType teeType) external returns (bytes32);
270
-
271
- /**
272
- * @notice Validates an input handle proof for a given owner and type.
273
- * @param handle handle to validate
274
- * @param owner owner of the provided handle
275
- * @param proof proof data
276
- * @param teeType expected handle type
266
+ * @notice Wraps a plaintext value into a deterministic public handle.
267
+ * The resulting handle has bit 0 of the attributes byte (byte 30) unset,
268
+ * meaning it can be non unique, it carries no ACL and is accessible by everyone.
269
+ * The same value and type always produce the same handle.
270
+ * @param value The plaintext value
271
+ * @param teeType The type of the handle
272
+ * @return The public handle
273
+ */
274
+ function wrapAsPublicHandle(bytes32 value, TEEType teeType) external returns (bytes32);
275
+
276
+ /**
277
+ * Validates that a handle provided by a user is:
278
+ * - of expected type
279
+ * - not expired
280
+ * - issued for the correct app (caller)
281
+ * - issued for the correct owner
282
+ * - issued by the configured gateway (signed by the gateway wallet)
283
+ * or reverts otherwise.
284
+ *
285
+ * Handle format:
286
+ * 1 byte 4 bytes 1 byte 1 byte 25 bytes
287
+ * [0] [1------4] [5] [6] [7-----------31]
288
+ * Version ChainId Type Attrs Pre-handle
289
+ *
290
+ * Proof format:
291
+ * 20 bytes 20 bytes 32 bytes 65 bytes
292
+ * [0-----19] [20-----39] [40--------71] [72------------136]
293
+ * Owner App CreatedAt EIP-712 signature
294
+ *
295
+ * @param handle handle id
296
+ * @param owner The address of the handle owner
297
+ * @param proof Proof data
277
298
  */
278
299
  function validateInputProof(
279
300
  bytes32 handle,
@@ -283,10 +304,17 @@ interface INoxCompute {
283
304
  ) external;
284
305
 
285
306
  /**
286
- * @notice Validates a decryption proof issued by the gateway for a publicly decryptable handle.
307
+ * Validates the decryption proof issued by the gateway for a given handle.
308
+ * The proof must be signed by the configured gateway.
309
+ *
310
+ * The proof uses a compact serialization: `signature (65 bytes) || decryptedResult (N >= 32 bytes)`.
311
+ * The signature is placed first (fixed size) so that `decryptedResult` can be variable-length,
312
+ * supporting all current types (ABI-encoded as 32 bytes) and future types that may exceed
313
+ * 32 bytes (e.g. encrypted strings).
314
+ *
287
315
  * @param handle Handle to decrypt
288
- * @param decryptionProof Serialized decryption proof (signature + decrypted value)
289
- * @return The decrypted value (variable length)
316
+ * @param decryptionProof Compact proof: `signature (65 bytes) || decryptedResult (N >= 32 bytes)`
317
+ * @return decryptedResult The decrypted value (variable length)
290
318
  */
291
319
  function validateDecryptionProof(
292
320
  bytes32 handle,
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  pragma solidity ^0.8.0;
3
3
 
4
- import {TEEType} from "../shared/TypeUtils.sol";
4
+ import {TEEType, TypeUtils} from "../shared/TypeUtils.sol";
5
5
  import {INoxCompute} from "../interfaces/INoxCompute.sol";
6
6
  import "encrypted-types/EncryptedTypes.sol";
7
7
 
@@ -29,11 +29,11 @@ library Nox {
29
29
  }
30
30
  // Arbitrum Sepolia or its fork
31
31
  if (block.chainid == 421614) {
32
- return 0xE4622fbFCd0bDd482775bBf5b3e72382C0D99208;
32
+ return 0xd464B198f06756a1d00be223634b85E0a731c229;
33
33
  }
34
34
  // Local development chain
35
35
  if (block.chainid == 31337) {
36
- return 0x9bdef3F9fEc61eE7cDfE84BDE8398595c6E0b22d;
36
+ return 0x6cC89dEd8c25E1460fa8408099C8Ab5b902D8b6B;
37
37
  }
38
38
  revert("Nox: Unsupported chain");
39
39
  }
@@ -42,6 +42,36 @@ library Nox {
42
42
  return INoxCompute(noxComputeContract());
43
43
  }
44
44
 
45
+ /**
46
+ * @dev Calls allow on NoxCompute, silently skipping public handles.
47
+ * Public handles are already accessible by everyone and don't need ACL.
48
+ */
49
+ function _allowIfNotPublic(bytes32 handle, address account) private {
50
+ if (!TypeUtils.isPublicHandle(handle)) {
51
+ _noxComputeContract().allow(handle, account);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * @dev Calls allowTransient on NoxCompute, silently skipping public handles.
57
+ * Public handles are already accessible by everyone and don't need ACL.
58
+ */
59
+ function _allowTransientIfNotPublic(bytes32 handle, address account) private {
60
+ if (!TypeUtils.isPublicHandle(handle)) {
61
+ _noxComputeContract().allowTransient(handle, account);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * @dev Calls disallowTransient on NoxCompute, silently skipping public handles.
67
+ * Public handles are already accessible by everyone and don't need ACL.
68
+ */
69
+ function _disallowTransientIfNotPublic(bytes32 handle, address account) private {
70
+ if (!TypeUtils.isPublicHandle(handle)) {
71
+ _noxComputeContract().disallowTransient(handle, account);
72
+ }
73
+ }
74
+
45
75
  // =========== Handle initialization checks ============
46
76
 
47
77
  /**
@@ -112,7 +142,7 @@ library Nox {
112
142
  function toEbool(bool value) internal returns (ebool) {
113
143
  return
114
144
  ebool.wrap(
115
- _noxComputeContract().plaintextToEncrypted(
145
+ _noxComputeContract().wrapAsPublicHandle(
116
146
  bytes32(uint256(value ? 1 : 0)),
117
147
  TEEType.Bool
118
148
  )
@@ -125,7 +155,7 @@ library Nox {
125
155
  function toEuint16(uint16 value) internal returns (euint16) {
126
156
  return
127
157
  euint16.wrap(
128
- _noxComputeContract().plaintextToEncrypted(bytes32(uint256(value)), TEEType.Uint16)
158
+ _noxComputeContract().wrapAsPublicHandle(bytes32(uint256(value)), TEEType.Uint16)
129
159
  );
130
160
  }
131
161
 
@@ -135,7 +165,7 @@ library Nox {
135
165
  function toEuint256(uint256 value) internal returns (euint256) {
136
166
  return
137
167
  euint256.wrap(
138
- _noxComputeContract().plaintextToEncrypted(bytes32(value), TEEType.Uint256)
168
+ _noxComputeContract().wrapAsPublicHandle(bytes32(value), TEEType.Uint256)
139
169
  );
140
170
  }
141
171
 
@@ -145,7 +175,7 @@ library Nox {
145
175
  function toEint16(int16 value) internal returns (eint16) {
146
176
  return
147
177
  eint16.wrap(
148
- _noxComputeContract().plaintextToEncrypted(
178
+ _noxComputeContract().wrapAsPublicHandle(
149
179
  bytes32(uint256(uint16(value))),
150
180
  TEEType.Int16
151
181
  )
@@ -158,7 +188,7 @@ library Nox {
158
188
  function toEint256(int256 value) internal returns (eint256) {
159
189
  return
160
190
  eint256.wrap(
161
- _noxComputeContract().plaintextToEncrypted(bytes32(uint256(value)), TEEType.Int256)
191
+ _noxComputeContract().wrapAsPublicHandle(bytes32(uint256(value)), TEEType.Int256)
162
192
  );
163
193
  }
164
194
 
@@ -558,128 +588,194 @@ library Nox {
558
588
 
559
589
  /**
560
590
  * @dev Allows the use of value for the address account.
591
+ * Silently skips public handles (they are already accessible by everyone).
561
592
  */
562
593
  function allow(ebool value, address account) internal {
563
- _noxComputeContract().allow(ebool.unwrap(value), account);
594
+ _allowIfNotPublic(ebool.unwrap(value), account);
564
595
  }
565
596
 
566
597
  /**
567
598
  * @dev Allows the use of value for the address account.
599
+ * Silently skips public handles (they are already accessible by everyone).
568
600
  */
569
601
  function allow(eaddress value, address account) internal {
570
- _noxComputeContract().allow(eaddress.unwrap(value), account);
602
+ _allowIfNotPublic(eaddress.unwrap(value), account);
571
603
  }
572
604
 
573
605
  /**
574
606
  * @dev Allows the use of value for the address account.
607
+ * Silently skips public handles (they are already accessible by everyone).
575
608
  */
576
609
  function allow(euint16 value, address account) internal {
577
- _noxComputeContract().allow(euint16.unwrap(value), account);
610
+ _allowIfNotPublic(euint16.unwrap(value), account);
578
611
  }
579
612
 
580
613
  /**
581
614
  * @dev Allows the use of value for the address account.
615
+ * Silently skips public handles (they are already accessible by everyone).
582
616
  */
583
617
  function allow(euint256 value, address account) internal {
584
- _noxComputeContract().allow(euint256.unwrap(value), account);
618
+ _allowIfNotPublic(euint256.unwrap(value), account);
585
619
  }
586
620
 
587
621
  /**
588
622
  * @dev Allows the use of value for the address account.
623
+ * Silently skips public handles (they are already accessible by everyone).
589
624
  */
590
625
  function allow(eint16 value, address account) internal {
591
- _noxComputeContract().allow(eint16.unwrap(value), account);
626
+ _allowIfNotPublic(eint16.unwrap(value), account);
592
627
  }
593
628
 
594
629
  /**
595
630
  * @dev Allows the use of value for the address account.
631
+ * Silently skips public handles (they are already accessible by everyone).
596
632
  */
597
633
  function allow(eint256 value, address account) internal {
598
- _noxComputeContract().allow(eint256.unwrap(value), account);
634
+ _allowIfNotPublic(eint256.unwrap(value), account);
599
635
  }
600
636
 
601
637
  /**
602
638
  * @dev Allows the use of value for this address (address(this)).
639
+ * Silently skips public handles (they are already accessible by everyone).
603
640
  */
604
641
  function allowThis(ebool value) internal {
605
- _noxComputeContract().allow(ebool.unwrap(value), address(this));
642
+ _allowIfNotPublic(ebool.unwrap(value), address(this));
606
643
  }
607
644
 
608
645
  /**
609
646
  * @dev Allows the use of value for this address (address(this)).
647
+ * Silently skips public handles (they are already accessible by everyone).
610
648
  */
611
649
  function allowThis(eaddress value) internal {
612
- _noxComputeContract().allow(eaddress.unwrap(value), address(this));
650
+ _allowIfNotPublic(eaddress.unwrap(value), address(this));
613
651
  }
614
652
 
615
653
  /**
616
654
  * @dev Allows the use of value for this address (address(this)).
655
+ * Silently skips public handles (they are already accessible by everyone).
617
656
  */
618
657
  function allowThis(euint16 value) internal {
619
- _noxComputeContract().allow(euint16.unwrap(value), address(this));
658
+ _allowIfNotPublic(euint16.unwrap(value), address(this));
620
659
  }
621
660
 
622
661
  /**
623
662
  * @dev Allows the use of value for this address (address(this)).
663
+ * Silently skips public handles (they are already accessible by everyone).
624
664
  */
625
665
  function allowThis(euint256 value) internal {
626
- _noxComputeContract().allow(euint256.unwrap(value), address(this));
666
+ _allowIfNotPublic(euint256.unwrap(value), address(this));
627
667
  }
628
668
 
629
669
  /**
630
670
  * @dev Allows the use of value for this address (address(this)).
671
+ * Silently skips public handles (they are already accessible by everyone).
631
672
  */
632
673
  function allowThis(eint16 value) internal {
633
- _noxComputeContract().allow(eint16.unwrap(value), address(this));
674
+ _allowIfNotPublic(eint16.unwrap(value), address(this));
634
675
  }
635
676
 
636
677
  /**
637
678
  * @dev Allows the use of value for this address (address(this)).
679
+ * Silently skips public handles (they are already accessible by everyone).
638
680
  */
639
681
  function allowThis(eint256 value) internal {
640
- _noxComputeContract().allow(eint256.unwrap(value), address(this));
682
+ _allowIfNotPublic(eint256.unwrap(value), address(this));
641
683
  }
642
684
 
643
685
  /**
644
686
  * @dev Allows the use of value by address account for this transaction.
687
+ * Silently skips public handles (they are already accessible by everyone).
645
688
  */
646
689
  function allowTransient(ebool value, address account) internal {
647
- _noxComputeContract().allowTransient(ebool.unwrap(value), account);
690
+ _allowTransientIfNotPublic(ebool.unwrap(value), account);
648
691
  }
649
692
 
650
693
  /**
651
694
  * @dev Allows the use of value by address account for this transaction.
695
+ * Silently skips public handles (they are already accessible by everyone).
652
696
  */
653
697
  function allowTransient(eaddress value, address account) internal {
654
- _noxComputeContract().allowTransient(eaddress.unwrap(value), account);
698
+ _allowTransientIfNotPublic(eaddress.unwrap(value), account);
655
699
  }
656
700
 
657
701
  /**
658
702
  * @dev Allows the use of value by address account for this transaction.
703
+ * Silently skips public handles (they are already accessible by everyone).
659
704
  */
660
705
  function allowTransient(euint16 value, address account) internal {
661
- _noxComputeContract().allowTransient(euint16.unwrap(value), account);
706
+ _allowTransientIfNotPublic(euint16.unwrap(value), account);
662
707
  }
663
708
 
664
709
  /**
665
710
  * @dev Allows the use of value by address account for this transaction.
711
+ * Silently skips public handles (they are already accessible by everyone).
666
712
  */
667
713
  function allowTransient(euint256 value, address account) internal {
668
- _noxComputeContract().allowTransient(euint256.unwrap(value), account);
714
+ _allowTransientIfNotPublic(euint256.unwrap(value), account);
669
715
  }
670
716
 
671
717
  /**
672
718
  * @dev Allows the use of value by address account for this transaction.
719
+ * Silently skips public handles (they are already accessible by everyone).
673
720
  */
674
721
  function allowTransient(eint16 value, address account) internal {
675
- _noxComputeContract().allowTransient(eint16.unwrap(value), account);
722
+ _allowTransientIfNotPublic(eint16.unwrap(value), account);
676
723
  }
677
724
 
678
725
  /**
679
726
  * @dev Allows the use of value by address account for this transaction.
727
+ * Silently skips public handles (they are already accessible by everyone).
680
728
  */
681
729
  function allowTransient(eint256 value, address account) internal {
682
- _noxComputeContract().allowTransient(eint256.unwrap(value), account);
730
+ _allowTransientIfNotPublic(eint256.unwrap(value), account);
731
+ }
732
+
733
+ /**
734
+ * @dev Revokes transient access to value for address account within the current transaction.
735
+ * Silently skips public handles (they are already accessible by everyone).
736
+ */
737
+ function disallowTransient(ebool value, address account) internal {
738
+ _disallowTransientIfNotPublic(ebool.unwrap(value), account);
739
+ }
740
+
741
+ /**
742
+ * @dev Revokes transient access to value for address account within the current transaction.
743
+ * Silently skips public handles (they are already accessible by everyone).
744
+ */
745
+ function disallowTransient(eaddress value, address account) internal {
746
+ _disallowTransientIfNotPublic(eaddress.unwrap(value), account);
747
+ }
748
+
749
+ /**
750
+ * @dev Revokes transient access to value for address account within the current transaction.
751
+ * Silently skips public handles (they are already accessible by everyone).
752
+ */
753
+ function disallowTransient(euint16 value, address account) internal {
754
+ _disallowTransientIfNotPublic(euint16.unwrap(value), account);
755
+ }
756
+
757
+ /**
758
+ * @dev Revokes transient access to value for address account within the current transaction.
759
+ * Silently skips public handles (they are already accessible by everyone).
760
+ */
761
+ function disallowTransient(euint256 value, address account) internal {
762
+ _disallowTransientIfNotPublic(euint256.unwrap(value), account);
763
+ }
764
+
765
+ /**
766
+ * @dev Revokes transient access to value for address account within the current transaction.
767
+ * Silently skips public handles (they are already accessible by everyone).
768
+ */
769
+ function disallowTransient(eint16 value, address account) internal {
770
+ _disallowTransientIfNotPublic(eint16.unwrap(value), account);
771
+ }
772
+
773
+ /**
774
+ * @dev Revokes transient access to value for address account within the current transaction.
775
+ * Silently skips public handles (they are already accessible by everyone).
776
+ */
777
+ function disallowTransient(eint256 value, address account) internal {
778
+ _disallowTransientIfNotPublic(eint256.unwrap(value), account);
683
779
  }
684
780
 
685
781
  /**
@@ -901,7 +997,10 @@ library Nox {
901
997
  /**
902
998
  * @dev Verifies a decryption proof and returns the decrypted boolean value.
903
999
  */
904
- function publicDecrypt(ebool handle, bytes calldata decryptionProof) internal returns (bool) {
1000
+ function publicDecrypt(
1001
+ ebool handle,
1002
+ bytes calldata decryptionProof
1003
+ ) internal view returns (bool plaintextValue) {
905
1004
  bytes memory result = _noxComputeContract().validateDecryptionProof(
906
1005
  ebool.unwrap(handle),
907
1006
  decryptionProof
@@ -915,7 +1014,7 @@ library Nox {
915
1014
  function publicDecrypt(
916
1015
  eaddress handle,
917
1016
  bytes calldata decryptionProof
918
- ) internal returns (address) {
1017
+ ) internal view returns (address plaintextValue) {
919
1018
  bytes memory result = _noxComputeContract().validateDecryptionProof(
920
1019
  eaddress.unwrap(handle),
921
1020
  decryptionProof
@@ -929,7 +1028,7 @@ library Nox {
929
1028
  function publicDecrypt(
930
1029
  euint16 handle,
931
1030
  bytes calldata decryptionProof
932
- ) internal returns (uint16) {
1031
+ ) internal view returns (uint16 plaintextValue) {
933
1032
  bytes memory result = _noxComputeContract().validateDecryptionProof(
934
1033
  euint16.unwrap(handle),
935
1034
  decryptionProof
@@ -943,7 +1042,7 @@ library Nox {
943
1042
  function publicDecrypt(
944
1043
  euint256 handle,
945
1044
  bytes calldata decryptionProof
946
- ) internal returns (uint256) {
1045
+ ) internal view returns (uint256 plaintextValue) {
947
1046
  bytes memory result = _noxComputeContract().validateDecryptionProof(
948
1047
  euint256.unwrap(handle),
949
1048
  decryptionProof
@@ -954,7 +1053,10 @@ library Nox {
954
1053
  /**
955
1054
  * @dev Verifies a decryption proof and returns the decrypted int16 value.
956
1055
  */
957
- function publicDecrypt(eint16 handle, bytes calldata decryptionProof) internal returns (int16) {
1056
+ function publicDecrypt(
1057
+ eint16 handle,
1058
+ bytes calldata decryptionProof
1059
+ ) internal view returns (int16 plaintextValue) {
958
1060
  bytes memory result = _noxComputeContract().validateDecryptionProof(
959
1061
  eint16.unwrap(handle),
960
1062
  decryptionProof
@@ -968,7 +1070,7 @@ library Nox {
968
1070
  function publicDecrypt(
969
1071
  eint256 handle,
970
1072
  bytes calldata decryptionProof
971
- ) internal returns (int256) {
1073
+ ) internal view returns (int256 plaintextValue) {
972
1074
  bytes memory result = _noxComputeContract().validateDecryptionProof(
973
1075
  eint256.unwrap(handle),
974
1076
  decryptionProof
@@ -979,6 +1081,9 @@ library Nox {
979
1081
  // ============ Private helpers ============
980
1082
 
981
1083
  function _assertInitialized(bytes32 handle) private pure {
1084
+ // TODO remove this function and all related asserts and use
1085
+ // default zero values offchain in runner (0, address(0), ...)
1086
+ // when the handle is uninitialized (0x00...00).
982
1087
  require(handle != bytes32(0), UninitializedHandle());
983
1088
  }
984
1089
 
@@ -115,14 +115,28 @@ enum TEEType {
115
115
  error NonArithmeticType();
116
116
 
117
117
  library TypeUtils {
118
+ /// @dev Bit 0 of the attrs byte. When set, the handle is guaranteed unique on-chain.
119
+ bytes1 internal constant ATTR_IS_UNIQ_HANDLE = 0x01;
120
+
118
121
  /**
119
122
  * @notice Extracts the TEE type from a handle.
120
- * The type is stored at byte position 30 in the handle.
123
+ * The type is stored at byte position 5 in the handle.
121
124
  * @param handle The handle to extract the type from
122
125
  * @return The TEEType encoded in the handle
123
126
  */
124
127
  function typeOf(bytes32 handle) internal pure returns (TEEType) {
125
- return TEEType(uint8(handle[30]));
128
+ return TEEType(uint8(handle[5]));
129
+ }
130
+
131
+ /**
132
+ * @notice Checks if a handle is a public handle (isUniqHandle bit == 0).
133
+ * A public handle wraps a plaintext value known on-chain, has no ACL,
134
+ * and is accessible by everyone.
135
+ * @param handle The handle to check
136
+ * @return True if the handle is a public handle
137
+ */
138
+ function isPublicHandle(bytes32 handle) internal pure returns (bool) {
139
+ return (handle[6] & ATTR_IS_UNIQ_HANDLE) == 0;
126
140
  }
127
141
 
128
142
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iexec-nox/nox-protocol-contracts",
3
- "version": "0.1.0-beta.7",
3
+ "version": "0.1.0-beta.8",
4
4
  "description": "Nox protocol smart contracts",
5
5
  "keywords": [
6
6
  "Nox",
@@ -26,6 +26,7 @@
26
26
  "set-gateway": "pnpm hardhat run scripts/set-gateway.ts",
27
27
  "set-kms-public-key": "pnpm hardhat run scripts/set-kms-public-key.ts",
28
28
  "upgrade": "pnpm hardhat run scripts/upgrade.ts",
29
+ "upgrade:production": "pnpm hardhat run scripts/upgrade.ts --build-profile production",
29
30
  "verify": "pnpm hardhat ignition verify",
30
31
  "format": "pnpm prettier --write .",
31
32
  "format:check": "pnpm prettier --check ."