@inco/lightning 0.11.0-testnet-3 → 1.0.0-devnet-2
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/manifest.yaml +99 -0
- package/package.json +2 -1
- package/src/IncoLightning.sol +13 -0
- package/src/IncoVerifier.sol +13 -0
- package/src/Lib.demonet.sol +1 -1
- package/src/Lib.devnet.sol +1 -1
- package/src/Lib.sol +1 -1
- package/src/Types.sol +1 -5
- package/src/interfaces/automata-interfaces/IPCCSRouterExtended.sol +2 -0
- package/src/libs/incoLightning_demonet_v11_473256067.sol +1242 -0
- package/src/libs/incoLightning_devnet_v12_873394282.sol +1242 -0
- package/src/lightning-parts/AccessControl/AdvancedAccessControl.sol +29 -4
- package/src/lightning-parts/AccessControl/AdvancedAccessControl.types.sol +12 -0
- package/src/lightning-parts/AccessControl/BaseAccessControlList.sol +8 -0
- package/src/lightning-parts/AccessControl/test/TestAdvancedAccessControl.t.sol +36 -9
- package/src/lightning-parts/DecryptionAttester.sol +15 -3
- package/src/lightning-parts/primitives/EventCounter.sol +7 -3
- package/src/periphery/SessionVerifier.sol +16 -14
- package/src/test/IncoTest.sol +18 -1
- package/src/test/TestLib.t.sol +0 -13
- package/src/test/TestPause.t.sol +152 -0
- package/src/test/TestUpgrade.t.sol +1 -1
- package/src/test/TestVerifierPause.t.sol +211 -0
- package/src/version/IncoLightningConfig.sol +1 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
// SPDX-License-Identifier: No License
|
|
2
2
|
pragma solidity ^0.8;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
AllowanceVoucher,
|
|
6
|
+
AllowanceProof,
|
|
7
|
+
REQUIRED_ALLOWANCE_VOUCHER_WARNING_HASH
|
|
8
|
+
} from "./AdvancedAccessControl.types.sol";
|
|
5
9
|
import {ALLOWANCE_GRANTED_MAGIC_VALUE} from "../../Types.sol";
|
|
6
10
|
import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
|
|
7
11
|
import {IAdvancedAccessControl, IVoucherEip712Checker} from "./interfaces/IAdvancedAccessControl.sol";
|
|
@@ -9,6 +13,8 @@ import {SharerNotAllowedForHandle} from "../../Types.sol";
|
|
|
9
13
|
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
|
|
10
14
|
import {IBaseAccessControlList} from "./interfaces/IBaseAccessControlList.sol";
|
|
11
15
|
import {LightningAddressGetter} from "../primitives/LightningAddressGetter.sol";
|
|
16
|
+
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
|
|
17
|
+
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
12
18
|
|
|
13
19
|
/// @title AdvancedAccessControlStorage
|
|
14
20
|
/// @notice Diamond storage pattern for advanced ACL session nonce tracking
|
|
@@ -47,7 +53,7 @@ abstract contract VoucherEip712Checker is IVoucherEip712Checker, EIP712Upgradeab
|
|
|
47
53
|
/// @notice EIP-712 type hash for the AllowanceVoucher struct
|
|
48
54
|
/// @dev Computed once at compile time for gas efficiency
|
|
49
55
|
bytes32 constant ALLOWANCE_VOUCHER_STRUCT_HASH = keccak256(
|
|
50
|
-
"AllowanceVoucher(bytes32 sessionNonce,address verifyingContract,bytes4 callFunction,bytes sharerArgData)"
|
|
56
|
+
"AllowanceVoucher(string warning,bytes32 sessionNonce,address verifyingContract,bytes4 callFunction,bytes sharerArgData)"
|
|
51
57
|
);
|
|
52
58
|
|
|
53
59
|
/// @notice Computes the EIP-712 digest for an allowance voucher
|
|
@@ -60,6 +66,7 @@ abstract contract VoucherEip712Checker is IVoucherEip712Checker, EIP712Upgradeab
|
|
|
60
66
|
keccak256(
|
|
61
67
|
abi.encode(
|
|
62
68
|
ALLOWANCE_VOUCHER_STRUCT_HASH,
|
|
69
|
+
keccak256(bytes(voucher.warning)),
|
|
63
70
|
voucher.sessionNonce,
|
|
64
71
|
voucher.verifyingContract,
|
|
65
72
|
voucher.callFunction,
|
|
@@ -86,15 +93,22 @@ abstract contract VoucherEip712Checker is IVoucherEip712Checker, EIP712Upgradeab
|
|
|
86
93
|
/// - Session nonces allow sharers to invalidate all previous vouchers
|
|
87
94
|
/// - EIP-712 typed data ensures vouchers are human-readable when signing
|
|
88
95
|
/// - Supports both EOA and smart contract signatures (ERC-1271)
|
|
96
|
+
/// @dev `OwnableUpgradeable` is only here to align Context ordering with DecryptionAttester
|
|
97
|
+
/// for IncoVerifier's C3 linearization.
|
|
89
98
|
abstract contract AdvancedAccessControl is
|
|
90
99
|
IAdvancedAccessControl,
|
|
91
100
|
AdvancedAccessControlStorage,
|
|
101
|
+
OwnableUpgradeable,
|
|
92
102
|
VoucherEip712Checker,
|
|
93
|
-
LightningAddressGetter
|
|
103
|
+
LightningAddressGetter,
|
|
104
|
+
PausableUpgradeable
|
|
94
105
|
{
|
|
95
106
|
|
|
96
107
|
using SignatureChecker for address;
|
|
97
108
|
|
|
109
|
+
/// @notice Thrown when a voucher's warning field does not match the required warning text
|
|
110
|
+
error InvalidVoucherWarning();
|
|
111
|
+
|
|
98
112
|
/// @notice Thrown when a voucher signature is invalid for the claimed signer
|
|
99
113
|
/// @param signer The address that allegedly signed the voucher
|
|
100
114
|
/// @param digest The EIP-712 digest that should have been signed
|
|
@@ -111,6 +125,7 @@ abstract contract AdvancedAccessControl is
|
|
|
111
125
|
|
|
112
126
|
/// @notice Checks if an account is allowed to access a handle using a signed voucher proof
|
|
113
127
|
/// @dev Intended for simulation/off-chain calls. Not a view function as it calls external contracts.
|
|
128
|
+
/// Returns false unconditionally when this contract is paused, before any input validation.
|
|
114
129
|
/// Verification steps:
|
|
115
130
|
/// 1. Verify the sharer has access to the handle
|
|
116
131
|
/// 2. Verify the voucher signature is valid
|
|
@@ -120,7 +135,17 @@ abstract contract AdvancedAccessControl is
|
|
|
120
135
|
/// @param account The account requesting access
|
|
121
136
|
/// @param proof The allowance proof containing voucher, signature, and requester data
|
|
122
137
|
/// @return True if access is allowed, false or reverts otherwise
|
|
123
|
-
function isAllowedWithProof(bytes32 handle, address account, AllowanceProof memory proof)
|
|
138
|
+
function isAllowedWithProof(bytes32 handle, address account, AllowanceProof memory proof)
|
|
139
|
+
public
|
|
140
|
+
virtual
|
|
141
|
+
returns (bool)
|
|
142
|
+
{
|
|
143
|
+
if (paused()) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
require(
|
|
147
|
+
keccak256(bytes(proof.voucher.warning)) == REQUIRED_ALLOWANCE_VOUCHER_WARNING_HASH, InvalidVoucherWarning()
|
|
148
|
+
);
|
|
124
149
|
require(proof.voucher.verifyingContract != address(0), InvalidVerifyingContract());
|
|
125
150
|
require(
|
|
126
151
|
IBaseAccessControlList(incoLightningAddress).isAllowed(handle, proof.sharer),
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
// SPDX-License-Identifier: No License
|
|
2
2
|
pragma solidity ^0.8;
|
|
3
3
|
|
|
4
|
+
// Required warning that must be present in every AllowanceVoucher.
|
|
5
|
+
// Must match SESSION_KEY_WARNING in js/src/advancedacl/session-key.ts.
|
|
6
|
+
string constant REQUIRED_ALLOWANCE_VOUCHER_WARNING =
|
|
7
|
+
"Inco Warning: signing this message may leak your private data, including from unrelated apps. Sign only if you fully trust this app.";
|
|
8
|
+
|
|
9
|
+
// Precomputed hash of REQUIRED_ALLOWANCE_VOUCHER_WARNING for cheap runtime comparison.
|
|
10
|
+
// Evaluated at compile time — no storage slot used, no runtime keccak256 of the full string.
|
|
11
|
+
bytes32 constant REQUIRED_ALLOWANCE_VOUCHER_WARNING_HASH = keccak256(bytes(REQUIRED_ALLOWANCE_VOUCHER_WARNING));
|
|
12
|
+
|
|
4
13
|
// can be for arbitrary handles to arbitrary accounts
|
|
5
14
|
// signed by the account sharing its read access
|
|
6
15
|
struct AllowanceVoucher {
|
|
16
|
+
// Human-readable warning displayed by wallets at signing time.
|
|
17
|
+
// Must be first so wallets show it before the opaque byte fields below.
|
|
18
|
+
string warning;
|
|
7
19
|
bytes32 sessionNonce;
|
|
8
20
|
address verifyingContract;
|
|
9
21
|
bytes4 callFunction;
|
|
@@ -162,17 +162,25 @@ abstract contract BaseAccessControlList is
|
|
|
162
162
|
|
|
163
163
|
/// @notice Checks if an account has access to an encrypted handle.
|
|
164
164
|
/// @dev Returns true if any of: transient access, persistent access, or handle is revealed.
|
|
165
|
+
/// Returns false unconditionally when the contract is paused.
|
|
165
166
|
/// @param handle The encrypted handle to check.
|
|
166
167
|
/// @param account The account to check access for.
|
|
167
168
|
/// @return True if the account has access to the handle.
|
|
168
169
|
function isAllowed(bytes32 handle, address account) public view returns (bool) {
|
|
170
|
+
if (paused()) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
169
173
|
return allowedTransient(handle, account) || persistAllowed(handle, account) || isRevealed(handle);
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
/// @notice Checks if a handle has been revealed for public access.
|
|
177
|
+
/// @dev Returns false unconditionally when the contract is paused.
|
|
173
178
|
/// @param handle The encrypted handle to check.
|
|
174
179
|
/// @return True if the handle has been revealed.
|
|
175
180
|
function isRevealed(bytes32 handle) public view returns (bool) {
|
|
181
|
+
if (paused()) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
176
184
|
AclStorage storage $ = getAclStorage();
|
|
177
185
|
return $.persistedAllowedForDecryption[handle];
|
|
178
186
|
}
|
|
@@ -4,6 +4,7 @@ pragma solidity ^0.8;
|
|
|
4
4
|
import {IncoTest} from "../../../test/IncoTest.sol";
|
|
5
5
|
import {SessionVerifier, Session} from "../../../periphery/SessionVerifier.sol";
|
|
6
6
|
import {AllowanceVoucher, AllowanceProof} from "../AdvancedAccessControl.sol";
|
|
7
|
+
import {REQUIRED_ALLOWANCE_VOUCHER_WARNING} from "../AdvancedAccessControl.types.sol";
|
|
7
8
|
import {euint256, SharerNotAllowedForHandle} from "../../../Types.sol";
|
|
8
9
|
import {e, inco} from "../../../Lib.sol";
|
|
9
10
|
import {AdvancedAccessControl} from "../AdvancedAccessControl.sol";
|
|
@@ -93,7 +94,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
93
94
|
sessionNonce: bytes32(0),
|
|
94
95
|
verifyingContract: address(0),
|
|
95
96
|
callFunction: SessionVerifier.canUseSession.selector,
|
|
96
|
-
sharerArgData: abi.encode(Session({decrypter: bob, expiresAt: block.timestamp + 1 days}))
|
|
97
|
+
sharerArgData: abi.encode(Session({decrypter: bob, expiresAt: block.timestamp + 1 days})),
|
|
98
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
97
99
|
});
|
|
98
100
|
AllowanceProof memory bobsProof = getBobsProof(invalidSessionVoucher);
|
|
99
101
|
vm.expectRevert(abi.encodeWithSelector(AdvancedAccessControl.InvalidVerifyingContract.selector));
|
|
@@ -111,7 +113,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
111
113
|
sessionNonce: bytes32(0),
|
|
112
114
|
verifyingContract: address(sessionVerifier),
|
|
113
115
|
callFunction: SessionVerifier.canUseSession.selector,
|
|
114
|
-
sharerArgData: abi.encode(Session({decrypter: bob, expiresAt: block.timestamp + 1 days}))
|
|
116
|
+
sharerArgData: abi.encode(Session({decrypter: bob, expiresAt: block.timestamp + 1 days})),
|
|
117
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
115
118
|
});
|
|
116
119
|
AllowanceProof memory bobsProof = getBobsProof(aliceSessionVoucherForBob);
|
|
117
120
|
assertTrue(
|
|
@@ -128,7 +131,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
128
131
|
sessionNonce: bytes32(0),
|
|
129
132
|
verifyingContract: address(verifier),
|
|
130
133
|
callFunction: verifier.someCheck.selector,
|
|
131
|
-
sharerArgData: ""
|
|
134
|
+
sharerArgData: "",
|
|
135
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
132
136
|
});
|
|
133
137
|
AllowanceProof memory bobsFirstProof = getBobsProof(voucher);
|
|
134
138
|
assertTrue(
|
|
@@ -140,7 +144,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
140
144
|
sessionNonce: madeUpNonce,
|
|
141
145
|
verifyingContract: address(verifier),
|
|
142
146
|
callFunction: verifier.someCheck.selector,
|
|
143
|
-
sharerArgData: ""
|
|
147
|
+
sharerArgData: "",
|
|
148
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
144
149
|
});
|
|
145
150
|
AllowanceProof memory invalidBobProof = getBobsProof(voucher);
|
|
146
151
|
// the session nonce should be checked by inco
|
|
@@ -164,7 +169,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
164
169
|
sessionNonce: alicesNewNonce,
|
|
165
170
|
verifyingContract: address(verifier),
|
|
166
171
|
callFunction: verifier.someCheck.selector,
|
|
167
|
-
sharerArgData: ""
|
|
172
|
+
sharerArgData: "",
|
|
173
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
168
174
|
});
|
|
169
175
|
AllowanceProof memory bobsSecondProof = getBobsProof(voucher);
|
|
170
176
|
assertTrue(
|
|
@@ -179,7 +185,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
179
185
|
sessionNonce: bytes32(0),
|
|
180
186
|
verifyingContract: address(verifier),
|
|
181
187
|
callFunction: verifier.someCheck.selector,
|
|
182
|
-
sharerArgData: abi.encode(SomeVerifier.SharerArg({handleShared: secretHandle, allowedAccount: bob}))
|
|
188
|
+
sharerArgData: abi.encode(SomeVerifier.SharerArg({handleShared: secretHandle, allowedAccount: bob})),
|
|
189
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
183
190
|
});
|
|
184
191
|
AllowanceProof memory bobsProof = AllowanceProof({
|
|
185
192
|
sharer: alice,
|
|
@@ -217,7 +224,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
217
224
|
sessionNonce: bytes32(0),
|
|
218
225
|
verifyingContract: address(verifier),
|
|
219
226
|
callFunction: verifier.someCheck.selector,
|
|
220
|
-
sharerArgData: ""
|
|
227
|
+
sharerArgData: "",
|
|
228
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
221
229
|
});
|
|
222
230
|
// Use bob as sharer, but bob is NOT allowed on the secret (only alice is)
|
|
223
231
|
AllowanceProof memory proof = AllowanceProof({
|
|
@@ -237,7 +245,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
237
245
|
sessionNonce: bytes32(0),
|
|
238
246
|
verifyingContract: address(verifier),
|
|
239
247
|
callFunction: verifier.someCheck.selector,
|
|
240
|
-
sharerArgData: ""
|
|
248
|
+
sharerArgData: "",
|
|
249
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
241
250
|
});
|
|
242
251
|
// Alice is the sharer (and is allowed), but we sign with Bob's key
|
|
243
252
|
bytes memory wrongSignature = getSignatureForDigest(incoVerifier.allowanceVoucherDigest(voucher), bobPrivKey);
|
|
@@ -252,6 +261,23 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
252
261
|
incoVerifier.isAllowedWithProof(secretHandle, bob, proof);
|
|
253
262
|
}
|
|
254
263
|
|
|
264
|
+
/// @notice Test InvalidVoucherWarning error when voucher warning does not match required text
|
|
265
|
+
function testIsAllowedWithProofInvalidVoucherWarning() public {
|
|
266
|
+
DoesNotVerifyAnything verifier = new DoesNotVerifyAnything();
|
|
267
|
+
AllowanceVoucher memory voucher = AllowanceVoucher({
|
|
268
|
+
sessionNonce: bytes32(0),
|
|
269
|
+
verifyingContract: address(verifier),
|
|
270
|
+
callFunction: verifier.someCheck.selector,
|
|
271
|
+
sharerArgData: "",
|
|
272
|
+
warning: "wrong warning"
|
|
273
|
+
});
|
|
274
|
+
AllowanceProof memory proof = AllowanceProof({
|
|
275
|
+
sharer: alice, voucher: voucher, voucherSignature: getAliceSig(voucher), requesterArgData: ""
|
|
276
|
+
});
|
|
277
|
+
vm.expectRevert(abi.encodeWithSelector(AdvancedAccessControl.InvalidVoucherWarning.selector));
|
|
278
|
+
incoVerifier.isAllowedWithProof(secretHandle, bob, proof);
|
|
279
|
+
}
|
|
280
|
+
|
|
255
281
|
/// @notice Test claimHandle fails when proof verification fails (line 107)
|
|
256
282
|
function testClaimHandleProofVerificationFailed() public {
|
|
257
283
|
SomeVerifier verifier = new SomeVerifier();
|
|
@@ -261,7 +287,8 @@ contract TestAdvancedAccessControl is IncoTest {
|
|
|
261
287
|
sessionNonce: bytes32(0),
|
|
262
288
|
verifyingContract: address(verifier),
|
|
263
289
|
callFunction: verifier.someCheck.selector,
|
|
264
|
-
sharerArgData: abi.encode(SomeVerifier.SharerArg({handleShared: secretHandle, allowedAccount: bob}))
|
|
290
|
+
sharerArgData: abi.encode(SomeVerifier.SharerArg({handleShared: secretHandle, allowedAccount: bob})),
|
|
291
|
+
warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
|
|
265
292
|
});
|
|
266
293
|
AllowanceProof memory proof = AllowanceProof({
|
|
267
294
|
sharer: alice, // alice IS allowed on the secret
|
|
@@ -10,6 +10,7 @@ import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/crypt
|
|
|
10
10
|
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
11
11
|
import {SignatureVerifier} from "./primitives/SignatureVerifier.sol";
|
|
12
12
|
import {IDecryptionAttester} from "./interfaces/IDecryptionAttester.sol";
|
|
13
|
+
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
|
|
13
14
|
|
|
14
15
|
/// @title DecryptionAttester
|
|
15
16
|
/// @notice Verifies decryption attestations signed by covalidators.
|
|
@@ -17,7 +18,7 @@ import {IDecryptionAttester} from "./interfaces/IDecryptionAttester.sol";
|
|
|
17
18
|
/// the value and signs an attestation. This contract verifies that attestation using EIP-712
|
|
18
19
|
/// typed data signatures. The attestation binds a handle to its decrypted value, allowing
|
|
19
20
|
/// on-chain verification that a decryption was performed correctly by authorized covalidators.
|
|
20
|
-
abstract contract DecryptionAttester is IDecryptionAttester, SignatureVerifier, EIP712Upgradeable {
|
|
21
|
+
abstract contract DecryptionAttester is IDecryptionAttester, SignatureVerifier, EIP712Upgradeable, PausableUpgradeable {
|
|
21
22
|
|
|
22
23
|
using ECDSA for bytes32;
|
|
23
24
|
|
|
@@ -61,14 +62,19 @@ abstract contract DecryptionAttester is IDecryptionAttester, SignatureVerifier,
|
|
|
61
62
|
|
|
62
63
|
/// @notice Validates a decryption attestation against covalidator signatures.
|
|
63
64
|
/// @dev Verifies that the attestation was signed by the required threshold of covalidators.
|
|
65
|
+
/// Returns false unconditionally when this contract is paused.
|
|
64
66
|
/// @param decryption The decryption attestation to validate.
|
|
65
67
|
/// @param signatures Array of signatures from covalidators.
|
|
66
68
|
/// @return True if the attestation has valid signatures from the required covalidators.
|
|
67
69
|
function isValidDecryptionAttestation(DecryptionAttestation memory decryption, bytes[] calldata signatures)
|
|
68
70
|
public
|
|
69
71
|
view
|
|
72
|
+
virtual
|
|
70
73
|
returns (bool)
|
|
71
74
|
{
|
|
75
|
+
if (paused()) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
72
78
|
return isValidSignature(decryptionAttestationDigest(decryption), signatures);
|
|
73
79
|
}
|
|
74
80
|
|
|
@@ -85,7 +91,10 @@ abstract contract DecryptionAttester is IDecryptionAttester, SignatureVerifier,
|
|
|
85
91
|
ElementAttestationWithProof[] calldata proofElements,
|
|
86
92
|
bytes32 proof,
|
|
87
93
|
bytes[] calldata signatures
|
|
88
|
-
) public view override returns (bool) {
|
|
94
|
+
) public view virtual override returns (bool) {
|
|
95
|
+
if (paused()) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
89
98
|
DecryptionAttestation memory attestation = DecryptionAttestation({handle: elistHandle, value: proof});
|
|
90
99
|
|
|
91
100
|
// Verify the provided proof by reconstructing it from the provided value-commitment pairs and/or hashes.
|
|
@@ -118,7 +127,10 @@ abstract contract DecryptionAttester is IDecryptionAttester, SignatureVerifier,
|
|
|
118
127
|
function isValidReencryptionAttestation(
|
|
119
128
|
ReencryptionAttestation[] calldata attestations,
|
|
120
129
|
bytes[] calldata signatures
|
|
121
|
-
) public view returns (bool) {
|
|
130
|
+
) public view virtual returns (bool) {
|
|
131
|
+
if (paused()) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
122
134
|
if (attestations.length != signatures.length) {
|
|
123
135
|
revert AttestationsSignaturesLengthMismatch(attestations.length, signatures.length);
|
|
124
136
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8;
|
|
3
3
|
|
|
4
4
|
import {IEventCounter} from "./interfaces/IEventCounter.sol";
|
|
5
|
+
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
|
|
5
6
|
|
|
6
7
|
/// @title EventCounterStorage
|
|
7
8
|
/// @notice Diamond storage pattern for the event counter state
|
|
@@ -40,7 +41,7 @@ contract EventCounterStorage {
|
|
|
40
41
|
///
|
|
41
42
|
/// The event ID is incorporated into handle generation to ensure uniqueness even when
|
|
42
43
|
/// the same operation is performed multiple times in the same transaction.
|
|
43
|
-
contract EventCounter is IEventCounter, EventCounterStorage {
|
|
44
|
+
contract EventCounter is IEventCounter, EventCounterStorage, PausableUpgradeable {
|
|
44
45
|
|
|
45
46
|
/// @notice Generates and returns a new unique event ID
|
|
46
47
|
/// @dev Post-increments the counter, so the returned value is the ID before incrementing.
|
|
@@ -52,9 +53,12 @@ contract EventCounter is IEventCounter, EventCounterStorage {
|
|
|
52
53
|
|
|
53
54
|
/// @notice Sets the event counter to a digest value for batch operation tracking
|
|
54
55
|
/// @dev Used when processing batched operations where a serialization hash
|
|
55
|
-
/// provides better uniqueness than sequential IDs
|
|
56
|
+
/// provides better uniqueness than sequential IDs. Reverts when the contract
|
|
57
|
+
/// is paused, which transitively blocks every event-emitting operation that
|
|
58
|
+
/// finalizes by calling this function (encrypted ops, list ops, trivial encryption,
|
|
59
|
+
/// input registration, allow/reveal).
|
|
56
60
|
/// @param serialization The serialized batch data to hash
|
|
57
|
-
function setDigest(bytes memory serialization) internal {
|
|
61
|
+
function setDigest(bytes memory serialization) internal whenNotPaused {
|
|
58
62
|
getEventCounterStorage().eventCounter = uint256(keccak256(serialization));
|
|
59
63
|
}
|
|
60
64
|
|
|
@@ -26,18 +26,21 @@ struct Session {
|
|
|
26
26
|
|
|
27
27
|
/// @title SessionVerifier
|
|
28
28
|
/// @notice Inco access sharing verifier for browser dApp sessions
|
|
29
|
-
/// @dev Grants
|
|
30
|
-
///
|
|
29
|
+
/// @dev Grants a single decrypter address temporary access to all of the sharer's
|
|
30
|
+
/// encrypted handles. The session is valid as long as block.timestamp < expiresAt
|
|
31
|
+
/// and the requesting account matches the authorized decrypter.
|
|
31
32
|
///
|
|
32
33
|
/// Usage:
|
|
33
|
-
/// 1. User signs a voucher containing a Session struct with their chosen decrypter
|
|
34
|
-
///
|
|
35
|
-
///
|
|
34
|
+
/// 1. User signs a voucher containing a Session struct with their chosen decrypter
|
|
35
|
+
/// and expiration time.
|
|
36
|
+
/// 2. The voucher specifies canUseSession.selector as the callFunction.
|
|
37
|
+
/// 3. When the decrypter requests access, this contract verifies the session is still
|
|
38
|
+
/// valid and the caller matches the authorized decrypter.
|
|
36
39
|
///
|
|
37
40
|
/// To use this verifier, set the voucher's callFunction to SessionVerifier.canUseSession.selector
|
|
38
41
|
contract SessionVerifier is UUPSUpgradeable, OwnableUpgradeable, Version {
|
|
39
42
|
|
|
40
|
-
/// @notice Initializes the SessionVerifier with version information
|
|
43
|
+
/// @notice Initializes the SessionVerifier with version information.
|
|
41
44
|
/// @param _salt Unique salt used for deterministic deployment via CreateX
|
|
42
45
|
constructor(bytes32 _salt)
|
|
43
46
|
Version(
|
|
@@ -49,29 +52,28 @@ contract SessionVerifier is UUPSUpgradeable, OwnableUpgradeable, Version {
|
|
|
49
52
|
)
|
|
50
53
|
{}
|
|
51
54
|
|
|
52
|
-
/// @notice Verifies if an account can use a session to access encrypted
|
|
55
|
+
/// @notice Verifies if an account can use a session to access an encrypted handle.
|
|
53
56
|
/// @dev This function is called by the ACL system when validating access permissions.
|
|
54
|
-
///
|
|
55
|
-
/// parameter is intentionally ignored.
|
|
57
|
+
/// Access is granted if the session has not expired and the caller is the authorized decrypter.
|
|
56
58
|
/// @param account The address requesting access (must match session.decrypter)
|
|
57
|
-
/// @param sharerArgData ABI-encoded Session struct containing decrypter
|
|
58
|
-
/// @return ALLOWANCE_GRANTED_MAGIC_VALUE if
|
|
59
|
+
/// @param sharerArgData ABI-encoded Session struct containing decrypter and expiration
|
|
60
|
+
/// @return ALLOWANCE_GRANTED_MAGIC_VALUE if access is granted, bytes32(0) otherwise
|
|
59
61
|
function canUseSession(
|
|
60
62
|
bytes32, /* handle */
|
|
61
63
|
address account,
|
|
62
64
|
bytes memory sharerArgData,
|
|
63
|
-
bytes memory requesterArgData
|
|
65
|
+
bytes memory /* requesterArgData */
|
|
64
66
|
)
|
|
65
67
|
external
|
|
66
68
|
view
|
|
67
69
|
returns (bytes32)
|
|
68
70
|
{
|
|
69
|
-
// unused variable just here to bypass linter
|
|
70
|
-
(requesterArgData);
|
|
71
71
|
Session memory session = abi.decode(sharerArgData, (Session));
|
|
72
|
+
|
|
72
73
|
if (session.expiresAt >= block.timestamp && session.decrypter == account) {
|
|
73
74
|
return ALLOWANCE_GRANTED_MAGIC_VALUE;
|
|
74
75
|
}
|
|
76
|
+
|
|
75
77
|
return bytes32(0);
|
|
76
78
|
}
|
|
77
79
|
|
package/src/test/IncoTest.sol
CHANGED
|
@@ -12,6 +12,7 @@ import {FakeQuoteVerifier} from "./FakeIncoInfra/FakeQuoteVerifier.sol";
|
|
|
12
12
|
import {IOwnable} from "../../src/shared/IOwnable.sol";
|
|
13
13
|
import {MockRemoteAttestation} from "./FakeIncoInfra/MockRemoteAttestation.sol";
|
|
14
14
|
import {BootstrapResult} from "../lightning-parts/TEELifecycle.types.sol";
|
|
15
|
+
import {AllowanceProof, AllowanceVoucher} from "../lightning-parts/AccessControl/AdvancedAccessControl.sol";
|
|
15
16
|
import {Safe} from "safe-smart-account/Safe.sol";
|
|
16
17
|
import {SafeProxyFactory} from "safe-smart-account/proxies/SafeProxyFactory.sol";
|
|
17
18
|
|
|
@@ -61,7 +62,7 @@ contract IncoTest is MockOpHandler, DeployUtils, FakeDecryptionAttester, MockRem
|
|
|
61
62
|
deployer: testDeployer,
|
|
62
63
|
owner: owner,
|
|
63
64
|
// The highest precedent deployment pepper
|
|
64
|
-
pepper: "
|
|
65
|
+
pepper: "devnet",
|
|
65
66
|
quoteVerifier: new FakeQuoteVerifier()
|
|
66
67
|
});
|
|
67
68
|
vm.stopPrank();
|
|
@@ -82,4 +83,20 @@ contract IncoTest is MockOpHandler, DeployUtils, FakeDecryptionAttester, MockRem
|
|
|
82
83
|
vm.recordLogs();
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
/// @dev Creates an empty AllowanceProof (no proof required when sharer is address(0))
|
|
87
|
+
function _emptyAllowanceProof() internal pure returns (AllowanceProof memory) {
|
|
88
|
+
return AllowanceProof({
|
|
89
|
+
sharer: address(0),
|
|
90
|
+
voucher: AllowanceVoucher({
|
|
91
|
+
sessionNonce: bytes32(0),
|
|
92
|
+
verifyingContract: address(0),
|
|
93
|
+
callFunction: bytes4(0),
|
|
94
|
+
sharerArgData: "",
|
|
95
|
+
warning: ""
|
|
96
|
+
}),
|
|
97
|
+
voucherSignature: "",
|
|
98
|
+
requesterArgData: ""
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
85
102
|
}
|
package/src/test/TestLib.t.sol
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
} from "../Types.sol";
|
|
19
19
|
import {EncryptedOperations} from "../lightning-parts/EncryptedOperations.sol";
|
|
20
20
|
import {DecryptionAttestation, ElementAttestationWithProof} from "../lightning-parts/DecryptionAttester.types.sol";
|
|
21
|
-
import {AllowanceProof, AllowanceVoucher} from "../lightning-parts/AccessControl/AdvancedAccessControl.sol";
|
|
22
21
|
|
|
23
22
|
/// @notice Wrapper to expose internal requireEqual as an external call so vm.expectRevert works
|
|
24
23
|
contract RequireEqualCaller {
|
|
@@ -958,18 +957,6 @@ contract TestLib is IncoTest {
|
|
|
958
957
|
assertFalse(isValid, "Invalid bool value should return false");
|
|
959
958
|
}
|
|
960
959
|
|
|
961
|
-
/// @dev Creates an empty AllowanceProof (no proof required when sharer is address(0))
|
|
962
|
-
function _emptyAllowanceProof() internal pure returns (AllowanceProof memory) {
|
|
963
|
-
return AllowanceProof({
|
|
964
|
-
sharer: address(0),
|
|
965
|
-
voucher: AllowanceVoucher({
|
|
966
|
-
sessionNonce: bytes32(0), verifyingContract: address(0), callFunction: bytes4(0), sharerArgData: ""
|
|
967
|
-
}),
|
|
968
|
-
voucherSignature: "",
|
|
969
|
-
requesterArgData: ""
|
|
970
|
-
});
|
|
971
|
-
}
|
|
972
|
-
|
|
973
960
|
// ============ REQUIRE EQUAL TESTS ============
|
|
974
961
|
|
|
975
962
|
function testRequireEqual_Ebool_ValidAttestation_True() public {
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// SPDX-License-Identifier: No License
|
|
2
|
+
pragma solidity ^0.8;
|
|
3
|
+
|
|
4
|
+
import {inco} from "../Lib.sol";
|
|
5
|
+
import {euint256, ebool, ETypes, elist, typeBitSize, SenderNotAllowedForHandle} from "../Types.sol";
|
|
6
|
+
import {IncoTest} from "./IncoTest.sol";
|
|
7
|
+
import {IEncryptedOperations} from "../lightning-parts/interfaces/IEncryptedOperations.sol";
|
|
8
|
+
import {ITrivialEncryption} from "../lightning-parts/interfaces/ITrivialEncryption.sol";
|
|
9
|
+
import {IBaseAccessControlList} from "../lightning-parts/AccessControl/interfaces/IBaseAccessControlList.sol";
|
|
10
|
+
import {IEList} from "../lightning-parts/interfaces/IEList.sol";
|
|
11
|
+
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
|
|
12
|
+
import {BIT_FEE, FEE} from "../lightning-parts/Fee.sol";
|
|
13
|
+
|
|
14
|
+
contract TestPause is IncoTest {
|
|
15
|
+
|
|
16
|
+
/// @dev A single op spec: calldata, msg.value, and the exact selector the op must
|
|
17
|
+
/// revert with when the contract is paused. Annotating each op keeps payable and
|
|
18
|
+
/// non-payable ops in one loop while still asserting the specific expected error.
|
|
19
|
+
struct Op {
|
|
20
|
+
bytes data;
|
|
21
|
+
uint256 value;
|
|
22
|
+
bytes4 expectedPauseError;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function testPausedOpsRevertAndUnpausedOpsSucceed() public {
|
|
26
|
+
// Fund this contract for the payable ops below.
|
|
27
|
+
vm.deal(address(this), 100 ether);
|
|
28
|
+
|
|
29
|
+
// Create encrypted operands. Trivial-encryption grants transient ACL access to
|
|
30
|
+
// this contract for the lifetime of this transaction, so subsequent ops can
|
|
31
|
+
// call back into `inco` as msg.sender.
|
|
32
|
+
euint256 a = inco.asEuint256(10);
|
|
33
|
+
euint256 b = inco.asEuint256(5);
|
|
34
|
+
ebool t = inco.asEbool(true);
|
|
35
|
+
bytes32 aH = euint256.unwrap(a);
|
|
36
|
+
bytes32 bH = euint256.unwrap(b);
|
|
37
|
+
|
|
38
|
+
// Build a 3-element euint256 elist to feed into list ops.
|
|
39
|
+
uint256 listFee = uint256(3) * typeBitSize(ETypes.Uint256) * BIT_FEE;
|
|
40
|
+
elist list = inco.listRange{value: listFee}(0, 3, ETypes.Uint256);
|
|
41
|
+
// Pull a valid encrypted index/value out of the list (transient ACL access).
|
|
42
|
+
bytes32 idxH = inco.listGet(list, 0);
|
|
43
|
+
uint256 listBits = uint256(3) * typeBitSize(ETypes.Uint256);
|
|
44
|
+
uint256 listAppendFee = listBits + typeBitSize(ETypes.Uint256);
|
|
45
|
+
|
|
46
|
+
// Selector each op is expected to revert with under pause:
|
|
47
|
+
// - aclErr: ops that take input handles. `isAllowed(...)` returns false when
|
|
48
|
+
// paused, so `checkInput` reverts before the op reaches `setDigest`.
|
|
49
|
+
// - pauseErr: ops without input handle checks. They reach `setDigest`, which
|
|
50
|
+
// has the `whenNotPaused` modifier.
|
|
51
|
+
bytes4 aclErr = SenderNotAllowedForHandle.selector;
|
|
52
|
+
bytes4 pauseErr = PausableUpgradeable.EnforcedPause.selector;
|
|
53
|
+
|
|
54
|
+
// Build the op list. Each op MUST revert with `expectedPauseError` when paused
|
|
55
|
+
// and succeed when unpaused.
|
|
56
|
+
Op[] memory ops = new Op[](41);
|
|
57
|
+
uint256 i;
|
|
58
|
+
// ----- EncryptedOperations: all check input handles -----
|
|
59
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eAdd, (a, b)), 0, aclErr);
|
|
60
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eSub, (a, b)), 0, aclErr);
|
|
61
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eMul, (a, b)), 0, aclErr);
|
|
62
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eDiv, (a, b)), 0, aclErr);
|
|
63
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eRem, (a, b)), 0, aclErr);
|
|
64
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eShl, (a, b)), 0, aclErr);
|
|
65
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eShr, (a, b)), 0, aclErr);
|
|
66
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eRotl, (a, b)), 0, aclErr);
|
|
67
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eRotr, (a, b)), 0, aclErr);
|
|
68
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eBitAnd, (aH, bH)), 0, aclErr);
|
|
69
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eBitOr, (aH, bH)), 0, aclErr);
|
|
70
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eBitXor, (aH, bH)), 0, aclErr);
|
|
71
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eEq, (aH, bH)), 0, aclErr);
|
|
72
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eNe, (aH, bH)), 0, aclErr);
|
|
73
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eGe, (a, b)), 0, aclErr);
|
|
74
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eGt, (a, b)), 0, aclErr);
|
|
75
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eLe, (a, b)), 0, aclErr);
|
|
76
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eLt, (a, b)), 0, aclErr);
|
|
77
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eMin, (a, b)), 0, aclErr);
|
|
78
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eMax, (a, b)), 0, aclErr);
|
|
79
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eNot, (t)), 0, aclErr);
|
|
80
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eCast, (aH, ETypes.AddressOrUint160OrBytes20)), 0, aclErr);
|
|
81
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eIfThenElse, (t, aH, bH)), 0, aclErr);
|
|
82
|
+
ops[i++] = Op(abi.encodeCall(IEncryptedOperations.eRandBounded, (aH, ETypes.Uint256)), FEE, aclErr);
|
|
83
|
+
// ----- TrivialEncryption: plaintext inputs, no ACL check -----
|
|
84
|
+
ops[i++] = Op(abi.encodeCall(ITrivialEncryption.asEuint256, (uint256(7))), 0, pauseErr);
|
|
85
|
+
ops[i++] = Op(abi.encodeCall(ITrivialEncryption.asEbool, (false)), 0, pauseErr);
|
|
86
|
+
ops[i++] = Op(abi.encodeCall(ITrivialEncryption.asEaddress, (bob)), 0, pauseErr);
|
|
87
|
+
// ----- ACL grant: gated on `isAllowed(handle, msg.sender)` -----
|
|
88
|
+
ops[i++] = Op(abi.encodeCall(IBaseAccessControlList.allow, (aH, bob)), 0, aclErr);
|
|
89
|
+
ops[i++] = Op(abi.encodeCall(IBaseAccessControlList.reveal, (bH)), 0, aclErr);
|
|
90
|
+
// ----- EList -----
|
|
91
|
+
// listRange takes only plain integers; reaches setDigest directly.
|
|
92
|
+
ops[i++] = Op(
|
|
93
|
+
abi.encodeCall(IEList.listRange, (0, 2, ETypes.Uint256)),
|
|
94
|
+
2 * typeBitSize(ETypes.Uint256) * BIT_FEE,
|
|
95
|
+
pauseErr
|
|
96
|
+
);
|
|
97
|
+
// The rest take a list handle (and often value/index handles).
|
|
98
|
+
ops[i++] = Op(abi.encodeCall(IEList.listAppend, (list, idxH)), listAppendFee * BIT_FEE, aclErr);
|
|
99
|
+
ops[i++] = Op(abi.encodeCall(IEList.listGet, (list, uint16(0))), 0, aclErr);
|
|
100
|
+
ops[i++] = Op(abi.encodeCall(IEList.listGetOr, (list, idxH, idxH)), 0, aclErr);
|
|
101
|
+
ops[i++] = Op(abi.encodeCall(IEList.listSet, (list, idxH, idxH)), listBits * BIT_FEE, aclErr);
|
|
102
|
+
ops[i++] = Op(abi.encodeCall(IEList.listInsert, (list, idxH, idxH)), listAppendFee * BIT_FEE, aclErr);
|
|
103
|
+
ops[i++] = Op(abi.encodeCall(IEList.listConcat, (list, list)), (listBits + listBits) * BIT_FEE, aclErr);
|
|
104
|
+
ops[i++] = Op(
|
|
105
|
+
abi.encodeCall(IEList.listSlice, (list, idxH, uint16(2), idxH)),
|
|
106
|
+
2 * typeBitSize(ETypes.Uint256) * BIT_FEE,
|
|
107
|
+
aclErr
|
|
108
|
+
);
|
|
109
|
+
ops[i++] = Op(abi.encodeCall(IEList.listShuffle, (list)), listBits * BIT_FEE, aclErr);
|
|
110
|
+
ops[i++] = Op(abi.encodeCall(IEList.listReverse, (list)), listBits * BIT_FEE, aclErr);
|
|
111
|
+
// newEList overloads — overloaded, so resolve by signature.
|
|
112
|
+
// Empty arrays are valid inputs and skip the inner loops, isolating the pause
|
|
113
|
+
// gate (the `setDigest` call) as the only thing that can revert.
|
|
114
|
+
bytes32[] memory emptyHandles = new bytes32[](0);
|
|
115
|
+
bytes[] memory emptyInputs = new bytes[](0);
|
|
116
|
+
ops[i++] = Op(abi.encodeWithSignature("newEList(bytes32[],uint8)", emptyHandles, ETypes.Uint256), 0, pauseErr);
|
|
117
|
+
ops[i++] = Op(
|
|
118
|
+
abi.encodeWithSignature("newEList(bytes[],uint8,address)", emptyInputs, ETypes.Uint256, address(this)),
|
|
119
|
+
0,
|
|
120
|
+
pauseErr
|
|
121
|
+
);
|
|
122
|
+
assertEq(i, ops.length, "ops list length mismatch");
|
|
123
|
+
|
|
124
|
+
// ---- Pause: every op must revert with its expected selector ----
|
|
125
|
+
vm.prank(owner);
|
|
126
|
+
inco.pause();
|
|
127
|
+
|
|
128
|
+
for (uint256 j = 0; j < ops.length; j++) {
|
|
129
|
+
(bool ok, bytes memory ret) = address(inco).call{value: ops[j].value}(ops[j].data);
|
|
130
|
+
assertFalse(ok, string.concat("expected revert when paused, op #", vm.toString(j)));
|
|
131
|
+
assertGe(ret.length, 4, "revert payload too short");
|
|
132
|
+
// Read the first 4 bytes of revert data (the error selector).
|
|
133
|
+
bytes4 sel;
|
|
134
|
+
assembly {
|
|
135
|
+
sel := mload(add(ret, 0x20))
|
|
136
|
+
}
|
|
137
|
+
assertTrue(
|
|
138
|
+
sel == ops[j].expectedPauseError, string.concat("unexpected revert selector, op #", vm.toString(j))
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ---- Unpause: every op must succeed ----
|
|
143
|
+
vm.prank(owner);
|
|
144
|
+
inco.unpause();
|
|
145
|
+
|
|
146
|
+
for (uint256 j = 0; j < ops.length; j++) {
|
|
147
|
+
(bool ok,) = address(inco).call{value: ops[j].value}(ops[j].data);
|
|
148
|
+
assertTrue(ok, string.concat("expected success when unpaused, op #", vm.toString(j)));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
|
@@ -277,7 +277,7 @@ contract TestUpgrade is IncoTest {
|
|
|
277
277
|
|
|
278
278
|
// Helpers
|
|
279
279
|
function _deploySessionVerifierProxy(address proxyOwner) private returns (SessionVerifier) {
|
|
280
|
-
SessionVerifier impl = new SessionVerifier(
|
|
280
|
+
SessionVerifier impl = new SessionVerifier(bytes32(0));
|
|
281
281
|
ERC1967Proxy proxy = new ERC1967Proxy(address(impl), abi.encodeCall(SessionVerifier.initialize, (proxyOwner)));
|
|
282
282
|
return SessionVerifier(address(proxy));
|
|
283
283
|
}
|