@inco/lightning 0.8.0-devnet → 0.8.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/package.json +1 -1
- package/src/IncoLightning.sol +4 -0
- package/src/Lib.alphanet.sol +62 -6
- package/src/Lib.demonet.sol +62 -6
- package/src/Lib.devnet.sol +62 -6
- package/src/Lib.sol +62 -6
- package/src/Lib.template.sol +65 -9
- package/src/Lib.testnet.sol +62 -6
- package/src/interfaces/IIncoLightning.sol +2 -0
- package/src/libs/incoLightning_alphanet_v0_297966649.sol +62 -6
- package/src/libs/incoLightning_alphanet_v1_725458969.sol +62 -6
- package/src/libs/incoLightning_alphanet_v2_976644394.sol +62 -6
- package/src/libs/incoLightning_demonet_v0_863421733.sol +62 -6
- package/src/libs/incoLightning_demonet_v2_467437523.sol +62 -6
- package/src/libs/incoLightning_devnet_v0_340846814.sol +62 -6
- package/src/libs/incoLightning_devnet_v1_904635675.sol +62 -6
- package/src/libs/incoLightning_devnet_v2_295237520.sol +62 -6
- package/src/libs/incoLightning_devnet_v3_976859633.sol +62 -6
- package/src/libs/incoLightning_testnet_v0_183408998.sol +62 -6
- package/src/libs/incoLightning_testnet_v2_889158349.sol +62 -6
- package/src/lightning-parts/Fee.sol +9 -13
- package/src/lightning-parts/TEELifecycle.sol +24 -0
- package/src/periphery/IncoUtils.sol +42 -0
- package/src/test/AddTwo.sol +3 -3
- package/src/test/TEELifecycle/TEELifecycleMockTest.t.sol +55 -0
- package/src/test/TestFakeInfra.t.sol +263 -0
- package/src/test/TestFeeWithdrawal.t.sol +60 -0
- package/src/test/TestIncoUtils.t.sol +242 -0
- package/src/IIncoLightning.sol +0 -22
|
@@ -16,6 +16,11 @@ function typeOf(bytes32 handle) pure returns (ETypes) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
library e {
|
|
19
|
+
error CallFailedAfterFeeRefresh();
|
|
20
|
+
|
|
21
|
+
/// @dev slot to store the fee for inco operations
|
|
22
|
+
bytes32 private constant FEE_SLOT = keccak256("inco.fee");
|
|
23
|
+
|
|
19
24
|
function sanitize(euint256 a) internal returns (euint256) {
|
|
20
25
|
if (euint256.unwrap(a) == bytes32(0)) {
|
|
21
26
|
return asEuint256(0);
|
|
@@ -355,17 +360,22 @@ library e {
|
|
|
355
360
|
|
|
356
361
|
/// @dev costs the inco fee
|
|
357
362
|
function rand() internal returns (euint256) {
|
|
358
|
-
|
|
363
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRand.selector, ETypes.Uint256));
|
|
364
|
+
return euint256.wrap(result);
|
|
359
365
|
}
|
|
360
366
|
|
|
361
367
|
/// @dev costs the inco fee
|
|
362
368
|
function randBounded(uint256 upperBound) internal returns (euint256) {
|
|
363
|
-
|
|
369
|
+
bytes32 boundHandle = euint256.unwrap(asEuint256(upperBound));
|
|
370
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRandBounded.selector, boundHandle, ETypes.Uint256));
|
|
371
|
+
return euint256.wrap(result);
|
|
364
372
|
}
|
|
365
373
|
|
|
366
374
|
/// @dev costs the inco fee
|
|
367
375
|
function randBounded(euint256 upperBound) internal returns (euint256) {
|
|
368
|
-
|
|
376
|
+
bytes32 boundHandle = euint256.unwrap(s(upperBound));
|
|
377
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRandBounded.selector, boundHandle, ETypes.Uint256));
|
|
378
|
+
return euint256.wrap(result);
|
|
369
379
|
}
|
|
370
380
|
|
|
371
381
|
function asEuint256(uint256 a) internal returns (euint256) {
|
|
@@ -397,7 +407,8 @@ library e {
|
|
|
397
407
|
/// @notice Creates a new encrypted uint256 for the given user.
|
|
398
408
|
/// @dev costs the inco fee
|
|
399
409
|
function newEuint256(bytes memory ciphertext, address user) internal returns (euint256) {
|
|
400
|
-
|
|
410
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.newEuint256.selector, ciphertext, user));
|
|
411
|
+
return euint256.wrap(result);
|
|
401
412
|
}
|
|
402
413
|
|
|
403
414
|
/// @notice Creates a new encrypted bool assuming msg.sender is the user
|
|
@@ -409,7 +420,8 @@ library e {
|
|
|
409
420
|
/// @notice Creates a new encrypted bool for the given user.
|
|
410
421
|
/// @dev costs the inco fee
|
|
411
422
|
function newEbool(bytes memory ciphertext, address user) internal returns (ebool) {
|
|
412
|
-
|
|
423
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.newEbool.selector, ciphertext, user));
|
|
424
|
+
return ebool.wrap(result);
|
|
413
425
|
}
|
|
414
426
|
|
|
415
427
|
/// @notice Creates a new encrypted address assuming msg.sender is the user
|
|
@@ -421,7 +433,8 @@ library e {
|
|
|
421
433
|
/// @notice Creates a new encrypted address for the given user.
|
|
422
434
|
/// @dev costs the inco fee
|
|
423
435
|
function newEaddress(bytes memory ciphertext, address user) internal returns (eaddress) {
|
|
424
|
-
|
|
436
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.newEaddress.selector, ciphertext, user));
|
|
437
|
+
return eaddress.wrap(result);
|
|
425
438
|
}
|
|
426
439
|
|
|
427
440
|
function allow(euint256 a, address to) internal {
|
|
@@ -475,4 +488,47 @@ library e {
|
|
|
475
488
|
function select(ebool control, eaddress ifTrue, eaddress ifFalse) internal returns (eaddress) {
|
|
476
489
|
return eaddress.wrap(inco.eIfThenElse(s(control), eaddress.unwrap(s(ifTrue)), eaddress.unwrap(s(ifFalse))));
|
|
477
490
|
}
|
|
491
|
+
|
|
492
|
+
/// @dev Store fee in the custom slot
|
|
493
|
+
/// @param _fee The fee to store
|
|
494
|
+
function _setFee(uint256 _fee) private {
|
|
495
|
+
bytes32 slot = FEE_SLOT;
|
|
496
|
+
assembly {
|
|
497
|
+
sstore(slot, _fee)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/// @dev Retrieve fee from the custom slot
|
|
502
|
+
/// @return fee The stored fee
|
|
503
|
+
function _getFee() private view returns (uint256 fee) {
|
|
504
|
+
bytes32 slot = FEE_SLOT;
|
|
505
|
+
assembly {
|
|
506
|
+
fee := sload(slot)
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/// @dev Get current fee with fallback to inco.getFee() if not cached
|
|
511
|
+
function getCurrentFee() private returns (uint256) {
|
|
512
|
+
uint256 cachedFee = _getFee();
|
|
513
|
+
if (cachedFee == 0) {
|
|
514
|
+
cachedFee = inco.getFee();
|
|
515
|
+
_setFee(cachedFee);
|
|
516
|
+
}
|
|
517
|
+
return cachedFee;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/// @dev Execute a call to inco with fee, retrying with fresh fee if it fails
|
|
521
|
+
/// @param callData The encoded function call (use abi.encodeWithSelector)
|
|
522
|
+
/// @return result The bytes32 result from the call
|
|
523
|
+
function _callWithFeeRetry(bytes memory callData) private returns (bytes32) {
|
|
524
|
+
uint256 fee = getCurrentFee();
|
|
525
|
+
(bool success, bytes memory result) = address(inco).call{value: fee}(callData);
|
|
526
|
+
if (!success) {
|
|
527
|
+
fee = inco.getFee();
|
|
528
|
+
_setFee(fee);
|
|
529
|
+
(success, result) = address(inco).call{value: fee}(callData);
|
|
530
|
+
require(success, CallFailedAfterFeeRefresh());
|
|
531
|
+
}
|
|
532
|
+
return abi.decode(result, (bytes32));
|
|
533
|
+
}
|
|
478
534
|
}
|
|
@@ -16,6 +16,11 @@ function typeOf(bytes32 handle) pure returns (ETypes) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
library e {
|
|
19
|
+
error CallFailedAfterFeeRefresh();
|
|
20
|
+
|
|
21
|
+
/// @dev slot to store the fee for inco operations
|
|
22
|
+
bytes32 private constant FEE_SLOT = keccak256("inco.fee");
|
|
23
|
+
|
|
19
24
|
function sanitize(euint256 a) internal returns (euint256) {
|
|
20
25
|
if (euint256.unwrap(a) == bytes32(0)) {
|
|
21
26
|
return asEuint256(0);
|
|
@@ -355,17 +360,22 @@ library e {
|
|
|
355
360
|
|
|
356
361
|
/// @dev costs the inco fee
|
|
357
362
|
function rand() internal returns (euint256) {
|
|
358
|
-
|
|
363
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRand.selector, ETypes.Uint256));
|
|
364
|
+
return euint256.wrap(result);
|
|
359
365
|
}
|
|
360
366
|
|
|
361
367
|
/// @dev costs the inco fee
|
|
362
368
|
function randBounded(uint256 upperBound) internal returns (euint256) {
|
|
363
|
-
|
|
369
|
+
bytes32 boundHandle = euint256.unwrap(asEuint256(upperBound));
|
|
370
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRandBounded.selector, boundHandle, ETypes.Uint256));
|
|
371
|
+
return euint256.wrap(result);
|
|
364
372
|
}
|
|
365
373
|
|
|
366
374
|
/// @dev costs the inco fee
|
|
367
375
|
function randBounded(euint256 upperBound) internal returns (euint256) {
|
|
368
|
-
|
|
376
|
+
bytes32 boundHandle = euint256.unwrap(s(upperBound));
|
|
377
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRandBounded.selector, boundHandle, ETypes.Uint256));
|
|
378
|
+
return euint256.wrap(result);
|
|
369
379
|
}
|
|
370
380
|
|
|
371
381
|
function asEuint256(uint256 a) internal returns (euint256) {
|
|
@@ -397,7 +407,8 @@ library e {
|
|
|
397
407
|
/// @notice Creates a new encrypted uint256 for the given user.
|
|
398
408
|
/// @dev costs the inco fee
|
|
399
409
|
function newEuint256(bytes memory ciphertext, address user) internal returns (euint256) {
|
|
400
|
-
|
|
410
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.newEuint256.selector, ciphertext, user));
|
|
411
|
+
return euint256.wrap(result);
|
|
401
412
|
}
|
|
402
413
|
|
|
403
414
|
/// @notice Creates a new encrypted bool assuming msg.sender is the user
|
|
@@ -409,7 +420,8 @@ library e {
|
|
|
409
420
|
/// @notice Creates a new encrypted bool for the given user.
|
|
410
421
|
/// @dev costs the inco fee
|
|
411
422
|
function newEbool(bytes memory ciphertext, address user) internal returns (ebool) {
|
|
412
|
-
|
|
423
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.newEbool.selector, ciphertext, user));
|
|
424
|
+
return ebool.wrap(result);
|
|
413
425
|
}
|
|
414
426
|
|
|
415
427
|
/// @notice Creates a new encrypted address assuming msg.sender is the user
|
|
@@ -421,7 +433,8 @@ library e {
|
|
|
421
433
|
/// @notice Creates a new encrypted address for the given user.
|
|
422
434
|
/// @dev costs the inco fee
|
|
423
435
|
function newEaddress(bytes memory ciphertext, address user) internal returns (eaddress) {
|
|
424
|
-
|
|
436
|
+
bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.newEaddress.selector, ciphertext, user));
|
|
437
|
+
return eaddress.wrap(result);
|
|
425
438
|
}
|
|
426
439
|
|
|
427
440
|
function allow(euint256 a, address to) internal {
|
|
@@ -475,4 +488,47 @@ library e {
|
|
|
475
488
|
function select(ebool control, eaddress ifTrue, eaddress ifFalse) internal returns (eaddress) {
|
|
476
489
|
return eaddress.wrap(inco.eIfThenElse(s(control), eaddress.unwrap(s(ifTrue)), eaddress.unwrap(s(ifFalse))));
|
|
477
490
|
}
|
|
491
|
+
|
|
492
|
+
/// @dev Store fee in the custom slot
|
|
493
|
+
/// @param _fee The fee to store
|
|
494
|
+
function _setFee(uint256 _fee) private {
|
|
495
|
+
bytes32 slot = FEE_SLOT;
|
|
496
|
+
assembly {
|
|
497
|
+
sstore(slot, _fee)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/// @dev Retrieve fee from the custom slot
|
|
502
|
+
/// @return fee The stored fee
|
|
503
|
+
function _getFee() private view returns (uint256 fee) {
|
|
504
|
+
bytes32 slot = FEE_SLOT;
|
|
505
|
+
assembly {
|
|
506
|
+
fee := sload(slot)
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/// @dev Get current fee with fallback to inco.getFee() if not cached
|
|
511
|
+
function getCurrentFee() private returns (uint256) {
|
|
512
|
+
uint256 cachedFee = _getFee();
|
|
513
|
+
if (cachedFee == 0) {
|
|
514
|
+
cachedFee = inco.getFee();
|
|
515
|
+
_setFee(cachedFee);
|
|
516
|
+
}
|
|
517
|
+
return cachedFee;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/// @dev Execute a call to inco with fee, retrying with fresh fee if it fails
|
|
521
|
+
/// @param callData The encoded function call (use abi.encodeWithSelector)
|
|
522
|
+
/// @return result The bytes32 result from the call
|
|
523
|
+
function _callWithFeeRetry(bytes memory callData) private returns (bytes32) {
|
|
524
|
+
uint256 fee = getCurrentFee();
|
|
525
|
+
(bool success, bytes memory result) = address(inco).call{value: fee}(callData);
|
|
526
|
+
if (!success) {
|
|
527
|
+
fee = inco.getFee();
|
|
528
|
+
_setFee(fee);
|
|
529
|
+
(success, result) = address(inco).call{value: fee}(callData);
|
|
530
|
+
require(success, CallFailedAfterFeeRefresh());
|
|
531
|
+
}
|
|
532
|
+
return abi.decode(result, (bytes32));
|
|
533
|
+
}
|
|
478
534
|
}
|
|
@@ -9,6 +9,8 @@ uint256 constant FEE = 0.000001 ether;
|
|
|
9
9
|
abstract contract Fee {
|
|
10
10
|
|
|
11
11
|
error FeeNotPaid();
|
|
12
|
+
error FeeWithdrawalFailed();
|
|
13
|
+
error NoFeesToWithdraw();
|
|
12
14
|
|
|
13
15
|
/// @notice the fee to pay through msg.value for inputs and randomness IT MAY CHANGE
|
|
14
16
|
function getFee() public pure returns (uint256) {
|
|
@@ -25,19 +27,13 @@ abstract contract Fee {
|
|
|
25
27
|
_;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
uint256 spent = balanceBefore > balanceAfter ? balanceBefore - balanceAfter : 0;
|
|
36
|
-
uint256 refund = msg.value > spent ? msg.value - spent : 0;
|
|
37
|
-
if (refund > 0) {
|
|
38
|
-
(bool success,) = msg.sender.call{value: refund}("");
|
|
39
|
-
require(success, "Refund failed");
|
|
40
|
-
}
|
|
30
|
+
/// @notice Internal helper to withdraw accumulated fees to a recipient
|
|
31
|
+
/// @param recipient The address to send the fees to
|
|
32
|
+
function _withdrawFeesTo(address recipient) internal {
|
|
33
|
+
uint256 fees = address(this).balance;
|
|
34
|
+
require(fees > 0, NoFeesToWithdraw());
|
|
35
|
+
(bool success,) = payable(recipient).call{value: fees}("");
|
|
36
|
+
require(success, FeeWithdrawalFailed());
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
}
|
|
@@ -70,6 +70,8 @@ abstract contract TEELifecycle is
|
|
|
70
70
|
// Events
|
|
71
71
|
// @notice A new MR_AGGREGATED has been approved
|
|
72
72
|
event NewTEEVersionApproved(uint256 indexed version, bytes32 indexed mrAggregated);
|
|
73
|
+
// @notice A previously approved TEE version has been removed
|
|
74
|
+
event TEEVersionRemoved(bytes32 indexed mrAggregated);
|
|
73
75
|
event NewCovalidatorAdded(address covalidatorAddress, bytes quote);
|
|
74
76
|
event BootstrapStageComplete(address indexed newEoaSigner, BootstrapResult bootstrapResult);
|
|
75
77
|
// @notice Emitted to prove that an EOA has upgraded their TDX to a new
|
|
@@ -211,6 +213,28 @@ abstract contract TEELifecycle is
|
|
|
211
213
|
emit NewTEEVersionApproved($.approvedTeeVersions.length - 1, newMrAggregated);
|
|
212
214
|
}
|
|
213
215
|
|
|
216
|
+
/**
|
|
217
|
+
* @notice Removes a previously approved TEE version from the contract state
|
|
218
|
+
* @param mrAggregated - The MR_AGGREGATED bytes of the TEE version to remove
|
|
219
|
+
*/
|
|
220
|
+
function removeApprovedTeeVersion(bytes32 mrAggregated) public onlyOwner {
|
|
221
|
+
StorageForTeeLifecycle storage $ = getTeeLifecycleStorage();
|
|
222
|
+
bool found = false;
|
|
223
|
+
for (uint256 i = 0; i < $.approvedTeeVersions.length; i++) {
|
|
224
|
+
if ($.approvedTeeVersions[i] == mrAggregated) {
|
|
225
|
+
// Shift all elements after index i to the left to preserve insertion order
|
|
226
|
+
for (uint256 j = i; j < $.approvedTeeVersions.length - 1; j++) {
|
|
227
|
+
$.approvedTeeVersions[j] = $.approvedTeeVersions[j + 1];
|
|
228
|
+
}
|
|
229
|
+
$.approvedTeeVersions.pop();
|
|
230
|
+
found = true;
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
require(found, TEEVersionNotFound());
|
|
235
|
+
emit TEEVersionRemoved(mrAggregated);
|
|
236
|
+
}
|
|
237
|
+
|
|
214
238
|
function _isApprovedTeeVersion(bytes32 newMrAggregated) internal view returns (bool) {
|
|
215
239
|
StorageForTeeLifecycle storage $ = getTeeLifecycleStorage();
|
|
216
240
|
for (uint256 i = 0; i < $.approvedTeeVersions.length; i++) {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// SPDX-License-Identifier: No License
|
|
2
|
+
pragma solidity ^0.8;
|
|
3
|
+
|
|
4
|
+
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";
|
|
5
|
+
|
|
6
|
+
// Re-export FEE constant for convenience - consumers can import both IncoUtils and FEE from this file
|
|
7
|
+
import {FEE} from "../lightning-parts/Fee.sol";
|
|
8
|
+
|
|
9
|
+
contract IncoUtils {
|
|
10
|
+
|
|
11
|
+
error RefundFailed();
|
|
12
|
+
error ReentrantCall();
|
|
13
|
+
|
|
14
|
+
uint256 private constant NOT_ENTERED = 1;
|
|
15
|
+
uint256 private constant ENTERED = 2;
|
|
16
|
+
|
|
17
|
+
bytes32 private constant REENTRANCY_GUARD_SLOT = keccak256("inco.storage.IncoUtils.reentrancyGuard");
|
|
18
|
+
|
|
19
|
+
/// @notice Refund the difference between msg.value and what was actually spent
|
|
20
|
+
/// @dev Assumes all outflows and inflows to the contract are due to the user; refund is capped at msg.value
|
|
21
|
+
/// @dev Includes built-in reentrancy protection using OZ StorageSlot pattern (modifiers cannot use other modifiers)
|
|
22
|
+
modifier refundUnspent() {
|
|
23
|
+
StorageSlot.Uint256Slot storage status = StorageSlot.getUint256Slot(REENTRANCY_GUARD_SLOT);
|
|
24
|
+
|
|
25
|
+
require(status.value != ENTERED, ReentrantCall());
|
|
26
|
+
status.value = ENTERED;
|
|
27
|
+
|
|
28
|
+
uint256 balanceBefore = address(this).balance;
|
|
29
|
+
_;
|
|
30
|
+
uint256 balanceAfter = address(this).balance;
|
|
31
|
+
uint256 spent = balanceBefore > balanceAfter ? balanceBefore - balanceAfter : 0;
|
|
32
|
+
uint256 refund = msg.value > spent ? msg.value - spent : 0;
|
|
33
|
+
|
|
34
|
+
if (refund > 0) {
|
|
35
|
+
(bool success,) = msg.sender.call{value: refund}("");
|
|
36
|
+
require(success, RefundFailed());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
status.value = NOT_ENTERED;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
package/src/test/AddTwo.sol
CHANGED
|
@@ -3,12 +3,12 @@ pragma solidity ^0.8;
|
|
|
3
3
|
|
|
4
4
|
import {euint256, ebool} from "../Types.sol";
|
|
5
5
|
import {IncoLightning} from "../IncoLightning.sol";
|
|
6
|
-
import {
|
|
6
|
+
import {IncoUtils, FEE} from "../periphery/IncoUtils.sol";
|
|
7
7
|
import {DecryptionAttestation} from "../lightning-parts/DecryptionAttester.types.sol";
|
|
8
8
|
|
|
9
9
|
// To implement such a contract, we would normally import e form Lib.sol. For test purposes, we take inco as
|
|
10
10
|
// a constructor argument instead, so we can test it from other deployment addresses.
|
|
11
|
-
contract AddTwo is
|
|
11
|
+
contract AddTwo is IncoUtils {
|
|
12
12
|
|
|
13
13
|
IncoLightning inco;
|
|
14
14
|
|
|
@@ -36,7 +36,7 @@ contract AddTwo is Fee {
|
|
|
36
36
|
refundUnspent
|
|
37
37
|
returns (euint256 result, euint256 resultRevealed)
|
|
38
38
|
{
|
|
39
|
-
euint256 value = inco.newEuint256{value:
|
|
39
|
+
euint256 value = inco.newEuint256{value: FEE}(uint256EInput, msg.sender);
|
|
40
40
|
result = addTwo(value);
|
|
41
41
|
|
|
42
42
|
inco.allow(euint256.unwrap(result), address(this));
|
|
@@ -124,6 +124,61 @@ contract TEELifecycleMockTest is MockRemoteAttestation, TEELifecycle {
|
|
|
124
124
|
vm.stopPrank();
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
function testRemoveApprovedTeeVersionPreservesOrder() public {
|
|
128
|
+
bytes32 mrAggregated1 = hex"1111111111111111111111111111111111111111111111111111111111111111";
|
|
129
|
+
bytes32 mrAggregated2 = hex"2222222222222222222222222222222222222222222222222222222222222222";
|
|
130
|
+
bytes32 mrAggregated3 = hex"3333333333333333333333333333333333333333333333333333333333333333";
|
|
131
|
+
|
|
132
|
+
vm.startPrank(this.owner());
|
|
133
|
+
|
|
134
|
+
// Add three versions
|
|
135
|
+
this.approveNewTeeVersion(mrAggregated1);
|
|
136
|
+
this.approveNewTeeVersion(mrAggregated2);
|
|
137
|
+
this.approveNewTeeVersion(mrAggregated3);
|
|
138
|
+
|
|
139
|
+
// Verify all exist in order
|
|
140
|
+
assertEq(this.approvedTeeVersions(0), mrAggregated1);
|
|
141
|
+
assertEq(this.approvedTeeVersions(1), mrAggregated2);
|
|
142
|
+
assertEq(this.approvedTeeVersions(2), mrAggregated3);
|
|
143
|
+
|
|
144
|
+
// Remove the middle one (mrAggregated2)
|
|
145
|
+
this.removeApprovedTeeVersion(mrAggregated2);
|
|
146
|
+
|
|
147
|
+
// Verify insertion order is preserved: mrAggregated1 stays at 0, mrAggregated3 shifts to 1
|
|
148
|
+
assertEq(this.approvedTeeVersions(0), mrAggregated1);
|
|
149
|
+
assertEq(this.approvedTeeVersions(1), mrAggregated3);
|
|
150
|
+
|
|
151
|
+
// Verify index 2 is now out of bounds
|
|
152
|
+
vm.expectRevert(TEELifecycle.IndexOutOfBounds.selector);
|
|
153
|
+
this.approvedTeeVersions(2);
|
|
154
|
+
|
|
155
|
+
vm.stopPrank();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function testRemoveApprovedTeeVersionNotFound() public {
|
|
159
|
+
bytes32 nonExistentMrAggregated = hex"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
|
160
|
+
|
|
161
|
+
vm.startPrank(this.owner());
|
|
162
|
+
vm.expectRevert(TEELifecycle.TEEVersionNotFound.selector);
|
|
163
|
+
this.removeApprovedTeeVersion(nonExistentMrAggregated);
|
|
164
|
+
vm.stopPrank();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function testRemoveApprovedTeeVersionOnlyOwner() public {
|
|
168
|
+
bytes32 mrAggregated = hex"1111111111111111111111111111111111111111111111111111111111111111";
|
|
169
|
+
|
|
170
|
+
vm.startPrank(this.owner());
|
|
171
|
+
this.approveNewTeeVersion(mrAggregated);
|
|
172
|
+
vm.stopPrank();
|
|
173
|
+
|
|
174
|
+
// Try to remove as non-owner
|
|
175
|
+
address nonOwner = address(0x1234);
|
|
176
|
+
vm.startPrank(nonOwner);
|
|
177
|
+
vm.expectRevert();
|
|
178
|
+
this.removeApprovedTeeVersion(mrAggregated);
|
|
179
|
+
vm.stopPrank();
|
|
180
|
+
}
|
|
181
|
+
|
|
127
182
|
// Helper function to create a successful bootstrap result
|
|
128
183
|
function successfulBootstrapResult()
|
|
129
184
|
internal
|