@inco/lightning 0.8.0-devnet-13 → 0.8.0-devnet-20
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 +66 -0
- package/package.json +8 -8
- package/src/IncoLightning.sol +5 -0
- package/src/Lib.alphanet.sol +31 -35
- package/src/Lib.demonet.sol +31 -35
- package/src/Lib.devnet.sol +31 -35
- package/src/Lib.sol +31 -35
- package/src/Lib.template.sol +54 -35
- package/src/Lib.testnet.sol +31 -35
- package/src/Types.sol +18 -0
- package/src/interfaces/IIncoLightning.sol +2 -0
- package/src/libs/incoLightning_alphanet_v0_297966649.sol +31 -35
- package/src/libs/incoLightning_alphanet_v1_725458969.sol +31 -35
- package/src/libs/incoLightning_alphanet_v2_976644394.sol +31 -35
- package/src/libs/incoLightning_demonet_v0_863421733.sol +31 -35
- package/src/libs/incoLightning_demonet_v2_467437523.sol +31 -35
- package/src/libs/incoLightning_devnet_v0_340846814.sol +31 -35
- package/src/libs/incoLightning_devnet_v1_904635675.sol +31 -35
- package/src/libs/incoLightning_devnet_v2_295237520.sol +31 -35
- package/src/libs/incoLightning_devnet_v3_976859633.sol +31 -35
- package/src/libs/incoLightning_devnet_v4_409204766.sol +31 -35
- package/src/libs/incoLightning_devnet_v5_203964628.sol +31 -35
- package/src/libs/incoLightning_devnet_v6_281949651.sol +31 -35
- package/src/libs/incoLightning_devnet_v7_24560427.sol +1197 -0
- package/src/libs/incoLightning_devnet_v8_985328058.sol +1197 -0
- package/src/libs/incoLightning_devnet_v9_269218568.sol +1197 -0
- package/src/libs/incoLightning_testnet_v0_183408998.sol +31 -35
- package/src/libs/incoLightning_testnet_v2_889158349.sol +31 -35
- package/src/lightning-parts/AccessControl/AdvancedAccessControl.sol +4 -3
- package/src/lightning-parts/AccessControl/BaseAccessControlList.sol +0 -16
- package/src/lightning-parts/AccessControl/interfaces/IAdvancedAccessControl.sol +1 -1
- package/src/lightning-parts/AccessControl/interfaces/IBaseAccessControlList.sol +0 -1
- package/src/lightning-parts/AccessControl/test/TestAdvancedAccessControl.t.sol +3 -1
- package/src/lightning-parts/AccessControl/test/TestBaseAccessControl.t.sol +0 -43
- package/src/lightning-parts/DecryptionAttester.sol +2 -2
- package/src/lightning-parts/DecryptionAttester.types.sol +3 -3
- package/src/lightning-parts/EList.sol +105 -25
- package/src/lightning-parts/EncryptedOperations.sol +18 -8
- package/src/lightning-parts/Fee.sol +29 -0
- package/src/lightning-parts/interfaces/IDecryptionAttester.sol +2 -2
- package/src/lightning-parts/interfaces/IEList.sol +11 -8
- package/src/lightning-parts/interfaces/IEncryptedInput.sol +2 -2
- package/src/lightning-parts/test/Elist.t.sol +160 -9
- package/src/lightning-parts/test/TestDecryptionAttestationInSynchronousFlow.t.sol +41 -13
- package/src/periphery/IncoUtils.sol +1 -1
- package/src/test/EListTester.sol +31 -13
- package/src/test/FakeIncoInfra/FakeComputeServer.sol +2 -2
- package/src/test/TestDeploy.t.sol +45 -1
- package/src/test/TestFakeInfra.t.sol +32 -6
- package/src/test/TestLib.t.sol +840 -19
- package/src/test/TestReceive.t.sol +42 -0
- package/src/version/IncoLightningConfig.sol +1 -1
|
@@ -3,11 +3,12 @@ pragma solidity ^0.8;
|
|
|
3
3
|
|
|
4
4
|
import {IncoTest} from "../../test/IncoTest.sol";
|
|
5
5
|
import {ElistTester} from "../../test/EListTester.sol";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {FEE, Fee} from "../Fee.sol";
|
|
9
|
-
import {EList} from "../EList.sol";
|
|
6
|
+
import {ETypes, ListTooLong, elist, typeBitSize} from "../../Types.sol";
|
|
7
|
+
import {inco} from "../../Lib.sol";
|
|
8
|
+
import {FEE, BIT_FEE, Fee} from "../Fee.sol";
|
|
9
|
+
import {EList, MAX_LIST_LENGTH} from "../EList.sol";
|
|
10
10
|
import {VerifierAddressGetter} from "../primitives/VerifierAddressGetter.sol";
|
|
11
|
+
import {stdError} from "forge-std/StdError.sol";
|
|
11
12
|
|
|
12
13
|
contract ElistFeeTester is EList {
|
|
13
14
|
|
|
@@ -23,8 +24,38 @@ contract TestEList is IncoTest {
|
|
|
23
24
|
function setUp() public virtual override {
|
|
24
25
|
super.setUp();
|
|
25
26
|
tester = new ElistTester(inco);
|
|
26
|
-
vm.deal(address(tester),
|
|
27
|
+
vm.deal(address(tester), 100 ether);
|
|
28
|
+
vm.deal(address(this), 100 ether);
|
|
27
29
|
feeTester = new ElistFeeTester();
|
|
30
|
+
vm.deal(address(feeTester), 100 ether);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function _listRange(uint16 start, uint16 end) internal returns (elist) {
|
|
34
|
+
return inco.listRange{value: uint256(end - start) * typeBitSize(ETypes.Uint256) * BIT_FEE}(start, end);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function _listAppend(elist list, bytes32 value) internal returns (elist) {
|
|
38
|
+
uint256 typeBits = typeBitSize(ETypes.Uint256);
|
|
39
|
+
return inco.listAppend{value: (uint256(inco.lengthOf(elist.unwrap(list))) * typeBits + typeBits) * BIT_FEE}(
|
|
40
|
+
list, value
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function _listInsert(elist list, bytes32 idx, bytes32 val) internal returns (elist) {
|
|
45
|
+
uint256 typeBits = typeBitSize(ETypes.Uint256);
|
|
46
|
+
return inco.listInsert{value: (uint256(inco.lengthOf(elist.unwrap(list))) * typeBits + typeBits) * BIT_FEE}(
|
|
47
|
+
list, idx, val
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function _listConcat(elist a, elist b) internal returns (elist) {
|
|
52
|
+
uint256 bitsA = uint256(inco.lengthOf(elist.unwrap(a))) * typeBitSize(ETypes.Uint256);
|
|
53
|
+
uint256 bitsB = uint256(inco.lengthOf(elist.unwrap(b))) * typeBitSize(ETypes.Uint256);
|
|
54
|
+
return inco.listConcat{value: (bitsA + bitsB) * BIT_FEE}(a, b);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function _newEList(bytes32[] memory handles, ETypes listType) internal returns (elist) {
|
|
58
|
+
return inco.newEList{value: uint256(handles.length) * typeBitSize(listType) * BIT_FEE}(handles, listType);
|
|
28
59
|
}
|
|
29
60
|
|
|
30
61
|
function testNewElistFromInputs() public {
|
|
@@ -47,21 +78,141 @@ contract TestEList is IncoTest {
|
|
|
47
78
|
}
|
|
48
79
|
|
|
49
80
|
function testRevertsOnBadFeeAmount() public {
|
|
81
|
+
// Construct a handle with length=1, type=Uint256 so fee = 1 * 256 * BIT_FEE
|
|
82
|
+
elist nonZeroList = elist.wrap(bytes32((uint256(1) << 24) | (uint256(uint8(ETypes.Uint256)) << 16)));
|
|
83
|
+
uint256 correctFee = 256 * BIT_FEE;
|
|
84
|
+
|
|
50
85
|
// should fail if no fee
|
|
51
86
|
vm.expectRevert(Fee.FeeNotPaid.selector);
|
|
52
|
-
feeTester.listShuffle(
|
|
87
|
+
feeTester.listShuffle(nonZeroList);
|
|
53
88
|
|
|
54
89
|
// should fail if not enough fee
|
|
55
90
|
vm.expectRevert(Fee.FeeNotPaid.selector);
|
|
56
|
-
feeTester.listShuffle{value:
|
|
91
|
+
feeTester.listShuffle{value: correctFee - 1}(nonZeroList);
|
|
57
92
|
|
|
58
93
|
// should fail if too much fee
|
|
59
94
|
vm.expectRevert(Fee.FeeNotPaid.selector);
|
|
60
|
-
feeTester.listShuffle{value:
|
|
95
|
+
feeTester.listShuffle{value: correctFee + 1}(nonZeroList);
|
|
61
96
|
|
|
97
|
+
// newEList(inputs): uses payingElistFee, so 3 * 256 * BIT_FEE needed, sending less
|
|
62
98
|
vm.expectRevert(Fee.FeeNotPaid.selector);
|
|
63
99
|
bytes[] memory inputs = new bytes[](3);
|
|
64
|
-
feeTester.newEList{value:
|
|
100
|
+
feeTester.newEList{value: 3 * 256 * BIT_FEE - 1}(inputs, ETypes.Uint256, address(this));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function testListAppend_SucceedsAtMaxLength() public {
|
|
104
|
+
elist almostMaxList = _listRange(0, MAX_LIST_LENGTH - 1);
|
|
105
|
+
|
|
106
|
+
bytes32 validHandle = inco.listGet(almostMaxList, 0);
|
|
107
|
+
|
|
108
|
+
elist result = _listAppend(almostMaxList, validHandle);
|
|
109
|
+
assert(elist.unwrap(result) != bytes32(0));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function testListInsert_SucceedsAtMaxLength() public {
|
|
113
|
+
elist almostMaxList = _listRange(0, MAX_LIST_LENGTH - 1);
|
|
114
|
+
|
|
115
|
+
// Get valid handles from the list (listGet returns handles with transient permissions)
|
|
116
|
+
bytes32 validIndex = inco.listGet(almostMaxList, 0);
|
|
117
|
+
bytes32 validValue = inco.listGet(almostMaxList, 1);
|
|
118
|
+
|
|
119
|
+
elist result = _listInsert(almostMaxList, validIndex, validValue);
|
|
120
|
+
assert(elist.unwrap(result) != bytes32(0));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function testListConcat_SucceedsAtMaxLength() public {
|
|
124
|
+
uint16 half = MAX_LIST_LENGTH / 2;
|
|
125
|
+
uint16 otherHalf = MAX_LIST_LENGTH - half;
|
|
126
|
+
elist list1 = _listRange(0, half);
|
|
127
|
+
elist list2 = _listRange(0, otherHalf);
|
|
128
|
+
|
|
129
|
+
// Should succeed
|
|
130
|
+
elist combined = _listConcat(list1, list2);
|
|
131
|
+
assert(elist.unwrap(combined) != bytes32(0));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function testListRange_SucceedsAtMaxLength() public {
|
|
135
|
+
elist maxList = _listRange(0, MAX_LIST_LENGTH);
|
|
136
|
+
assert(elist.unwrap(maxList) != bytes32(0));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ==================== Overflow Tests ====================
|
|
140
|
+
// These tests verify that exceeding MAX_LIST_LENGTH reverts appropriately.
|
|
141
|
+
// Operations use uint16 arithmetic which auto-reverts on overflow in Solidity 0.8+.
|
|
142
|
+
|
|
143
|
+
function testListAppend_RevertsOnOverflow() public {
|
|
144
|
+
elist maxList = _listRange(0, MAX_LIST_LENGTH);
|
|
145
|
+
|
|
146
|
+
bytes32 validHandle = inco.listGet(maxList, 0);
|
|
147
|
+
|
|
148
|
+
// Appending to a max-length list should revert with arithmetic overflow
|
|
149
|
+
// Fee: (65535*256 + 256) * BIT_FEE = 65536*32*FEE
|
|
150
|
+
uint256 typeBits = typeBitSize(ETypes.Uint256);
|
|
151
|
+
vm.expectRevert(stdError.arithmeticError);
|
|
152
|
+
inco.listAppend{value: (uint256(MAX_LIST_LENGTH) * typeBits + typeBits) * BIT_FEE}(maxList, validHandle);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function testListInsert_RevertsOnOverflow() public {
|
|
156
|
+
elist maxList = _listRange(0, MAX_LIST_LENGTH);
|
|
157
|
+
|
|
158
|
+
bytes32 validIndex = inco.listGet(maxList, 0);
|
|
159
|
+
bytes32 validValue = inco.listGet(maxList, 1);
|
|
160
|
+
|
|
161
|
+
// Inserting into a max-length list should revert with arithmetic overflow
|
|
162
|
+
uint256 typeBits = typeBitSize(ETypes.Uint256);
|
|
163
|
+
vm.expectRevert(stdError.arithmeticError);
|
|
164
|
+
inco.listInsert{value: (uint256(MAX_LIST_LENGTH) * typeBits + typeBits) * BIT_FEE}(
|
|
165
|
+
maxList, validIndex, validValue
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function testListConcat_RevertsOnOverflow() public {
|
|
170
|
+
uint16 half = MAX_LIST_LENGTH / 2 + 1;
|
|
171
|
+
elist list1 = _listRange(0, half);
|
|
172
|
+
elist list2 = _listRange(0, half);
|
|
173
|
+
|
|
174
|
+
// Concatenating should revert with arithmetic overflow
|
|
175
|
+
uint256 bitsPerList = uint256(half) * typeBitSize(ETypes.Uint256);
|
|
176
|
+
vm.expectRevert(stdError.arithmeticError);
|
|
177
|
+
inco.listConcat{value: (bitsPerList + bitsPerList) * BIT_FEE}(list1, list2);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function testNewEList_RevertsOnTooManyHandles() public {
|
|
181
|
+
uint256 tooMany = uint256(MAX_LIST_LENGTH) + 1;
|
|
182
|
+
bytes32[] memory handles = new bytes32[](tooMany);
|
|
183
|
+
|
|
184
|
+
// Fee check runs before length check, so we must pay the required fee
|
|
185
|
+
uint256 requiredFee = tooMany * typeBitSize(ETypes.Uint256) * BIT_FEE;
|
|
186
|
+
|
|
187
|
+
// Should revert with ListTooLong error
|
|
188
|
+
vm.expectRevert(abi.encodeWithSelector(ListTooLong.selector, uint32(tooMany), MAX_LIST_LENGTH));
|
|
189
|
+
inco.newEList{value: requiredFee}(handles, ETypes.Uint256);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function testNewEList_RevertsOnTooManyInputs() public {
|
|
193
|
+
uint256 tooMany = uint256(MAX_LIST_LENGTH) + 1;
|
|
194
|
+
bytes[] memory inputs = new bytes[](tooMany);
|
|
195
|
+
|
|
196
|
+
// Fee check runs before length check, so we must pay the required fee
|
|
197
|
+
uint256 requiredFee = tooMany * typeBitSize(ETypes.Uint256) * BIT_FEE;
|
|
198
|
+
|
|
199
|
+
// Should revert with ListTooLong error
|
|
200
|
+
vm.expectRevert(abi.encodeWithSelector(ListTooLong.selector, uint32(tooMany), MAX_LIST_LENGTH));
|
|
201
|
+
inco.newEList{value: requiredFee}(inputs, ETypes.Uint256, address(this));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function testNewEListFromHandles() public {
|
|
205
|
+
elist sourceList = _listRange(0, 3);
|
|
206
|
+
|
|
207
|
+
// Extract handles from the source list
|
|
208
|
+
bytes32[] memory handles = new bytes32[](3);
|
|
209
|
+
handles[0] = inco.listGet(sourceList, 0);
|
|
210
|
+
handles[1] = inco.listGet(sourceList, 1);
|
|
211
|
+
handles[2] = inco.listGet(sourceList, 2);
|
|
212
|
+
|
|
213
|
+
// Create a new list from these handles
|
|
214
|
+
elist newList = _newEList(handles, ETypes.Uint256);
|
|
215
|
+
assert(elist.unwrap(newList) != bytes32(0));
|
|
65
216
|
}
|
|
66
217
|
|
|
67
218
|
}
|
|
@@ -2,21 +2,44 @@
|
|
|
2
2
|
pragma solidity ^0.8;
|
|
3
3
|
|
|
4
4
|
import {IncoTest} from "../../test/IncoTest.sol";
|
|
5
|
-
import {
|
|
5
|
+
import {ERC7984DemoToken} from "@inco/incoERC7984/src/ERC7984DemoToken.sol";
|
|
6
6
|
import {DecryptionAttestation} from "../DecryptionAttester.types.sol";
|
|
7
7
|
import {GWEI} from "../../shared/TypeUtils.sol";
|
|
8
|
-
import {euint256} from "@inco/lightning/src/Lib.sol"; // import via remapping or compiler fails
|
|
8
|
+
import {inco, e, euint256} from "@inco/lightning/src/Lib.sol"; // import via remapping or compiler fails
|
|
9
9
|
import {AllowanceProof} from "../AccessControl/AdvancedAccessControl.sol";
|
|
10
|
-
import {inco} from "../../Lib.sol";
|
|
11
10
|
import {euint256 as remappedEuint256} from "@inco/lightning/src/Lib.sol";
|
|
11
|
+
import {
|
|
12
|
+
DecryptionAttestation as remappedDecryptionAttestation
|
|
13
|
+
} from "@inco/lightning/src/lightning-parts/DecryptionAttester.types.sol";
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
/// @notice This test demonstrates how a decryption attestation can be used in a synchronous flow, where the result of the operation is known at the time of requesting the attestation.
|
|
16
|
+
/// In this example, we simulate a token burn operation where the user proves that they have enough balance to burn before actually performing the burn.
|
|
17
|
+
contract TokenBurnCurrentBalance is ERC7984DemoToken {
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
using e for uint256;
|
|
20
|
+
using e for euint256;
|
|
21
|
+
|
|
22
|
+
/// @notice Deploys the token with specified name, symbol, and initial supply
|
|
23
|
+
/// @param name_ The token name
|
|
24
|
+
/// @param symbol_ The token symbol
|
|
25
|
+
/// @param initialSupply The initial supply to mint to the deployer (in base units)
|
|
26
|
+
constructor(string memory name_, string memory symbol_, uint256 initialSupply)
|
|
27
|
+
ERC7984DemoToken(name_, symbol_, initialSupply)
|
|
28
|
+
{
|
|
29
|
+
if (initialSupply > 0) {
|
|
30
|
+
_mint(msg.sender, initialSupply.asEuint256());
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// @dev In this burn function, the user provides a decryption attestation that proves they have enough balance to burn the specified amount.
|
|
35
|
+
/// The burn operation is performed synchronously, and the success of the burn is verified using the attestation.
|
|
36
|
+
function burnFullCurrentBalance(remappedDecryptionAttestation memory attestation, bytes[] memory signatures)
|
|
37
|
+
public
|
|
38
|
+
{
|
|
16
39
|
euint256 currentBalance = confidentialBalanceOf(msg.sender);
|
|
17
|
-
require(inco.incoVerifier().isValidDecryptionAttestation(
|
|
18
|
-
require(euint256.unwrap(currentBalance) ==
|
|
19
|
-
publicBurn(msg.sender, uint256(
|
|
40
|
+
require(inco.incoVerifier().isValidDecryptionAttestation(attestation, signatures), "Invalid Signature");
|
|
41
|
+
require(euint256.unwrap(currentBalance) == attestation.handle, "Handle mismatch");
|
|
42
|
+
publicBurn(msg.sender, uint256(attestation.value));
|
|
20
43
|
}
|
|
21
44
|
|
|
22
45
|
}
|
|
@@ -26,19 +49,24 @@ contract TestDecryptionAttestationInSynchronousFlow is IncoTest {
|
|
|
26
49
|
AllowanceProof emptyProof; // no proof needed when requester has the handle in persisted allowed pairs
|
|
27
50
|
|
|
28
51
|
function testSynchronousBurning() public {
|
|
29
|
-
TokenBurnCurrentBalance token = new TokenBurnCurrentBalance();
|
|
52
|
+
TokenBurnCurrentBalance token = new TokenBurnCurrentBalance("DemoToken", "DMT", 100 ether);
|
|
30
53
|
vm.deal(address(token), 100 ether);
|
|
31
|
-
token.confidentialTransfer(alice, fakePrepareEuint256Ciphertext(10 * GWEI, address(this), address(token))
|
|
54
|
+
token.confidentialTransfer(alice, fakePrepareEuint256Ciphertext(10 * GWEI, address(this), address(token)));
|
|
32
55
|
processAllOperations(); // saves Alice's balance
|
|
56
|
+
|
|
33
57
|
bytes32 aliceCurrentBalanceHandle = euint256.unwrap(token.confidentialBalanceOf(alice));
|
|
34
58
|
// simulates Alice requesting for a decryption attestation of Ge op on her balance and the amount
|
|
35
59
|
// she intends to burn, therefore proving to the token contract that the operation will succeed
|
|
36
|
-
(DecryptionAttestation memory
|
|
60
|
+
(DecryptionAttestation memory attestation, bytes[] memory signatures) =
|
|
37
61
|
getDecryptionAttestation(alice, HandleWithProof({handle: aliceCurrentBalanceHandle, proof: emptyProof}));
|
|
38
|
-
vm.prank(alice);
|
|
39
62
|
|
|
63
|
+
// Convert attestation to remapped type for cross-project compatibility
|
|
64
|
+
remappedDecryptionAttestation memory remappedAttestation =
|
|
65
|
+
remappedDecryptionAttestation({handle: attestation.handle, value: attestation.value});
|
|
66
|
+
|
|
67
|
+
vm.prank(alice);
|
|
40
68
|
// the decryption attestation is passed to the token burn method
|
|
41
|
-
token.burnFullCurrentBalance(
|
|
69
|
+
token.burnFullCurrentBalance(remappedAttestation, signatures);
|
|
42
70
|
|
|
43
71
|
processAllOperations();
|
|
44
72
|
|
|
@@ -5,7 +5,7 @@ import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";
|
|
|
5
5
|
|
|
6
6
|
// Re-export FEE constant for convenience - consumers can import both IncoUtils and FEE from this file
|
|
7
7
|
// forge-lint: disable-next-line(unused-import)
|
|
8
|
-
import {FEE} from "../lightning-parts/Fee.sol";
|
|
8
|
+
import {FEE, BIT_FEE} from "../lightning-parts/Fee.sol";
|
|
9
9
|
|
|
10
10
|
contract IncoUtils {
|
|
11
11
|
|
package/src/test/EListTester.sol
CHANGED
|
@@ -3,9 +3,9 @@ pragma solidity ^0.8;
|
|
|
3
3
|
|
|
4
4
|
import {IIncoLightning} from "../interfaces/IIncoLightning.sol";
|
|
5
5
|
/// forge-lint: disable-next-line(unused-import)
|
|
6
|
-
import {ETypes, elist} from "../Types.sol";
|
|
6
|
+
import {ETypes, elist, typeBitSize} from "../Types.sol";
|
|
7
7
|
import {euint256} from "../Types.sol";
|
|
8
|
-
import {IncoUtils, FEE} from "../periphery/IncoUtils.sol";
|
|
8
|
+
import {IncoUtils, FEE, BIT_FEE} from "../periphery/IncoUtils.sol";
|
|
9
9
|
|
|
10
10
|
contract ElistTester is IncoUtils {
|
|
11
11
|
|
|
@@ -35,7 +35,10 @@ contract ElistTester is IncoUtils {
|
|
|
35
35
|
euint256 handle = inco.newEuint256{value: FEE}(ctValue, msg.sender);
|
|
36
36
|
inco.allow(euint256.unwrap(handle), address(this));
|
|
37
37
|
inco.allow(euint256.unwrap(handle), address(msg.sender));
|
|
38
|
-
|
|
38
|
+
uint256 typeBits = typeBitSize(ETypes(uint8(uint256(elist.unwrap(list)) >> 16)));
|
|
39
|
+
list = inco.listAppend{value: (uint256(inco.lengthOf(elist.unwrap(list))) * typeBits + typeBits) * BIT_FEE}(
|
|
40
|
+
list, euint256.unwrap(handle)
|
|
41
|
+
);
|
|
39
42
|
inco.allow(elist.unwrap(list), address(this));
|
|
40
43
|
inco.allow(elist.unwrap(list), address(msg.sender));
|
|
41
44
|
return list;
|
|
@@ -48,7 +51,7 @@ contract ElistTester is IncoUtils {
|
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
function newEList(bytes32[] memory handles, ETypes listType) public payable refundUnspent returns (elist) {
|
|
51
|
-
list = inco.newEList(handles, listType);
|
|
54
|
+
list = inco.newEList{value: FEE * handles.length}(handles, listType);
|
|
52
55
|
inco.allow(elist.unwrap(list), address(this));
|
|
53
56
|
inco.allow(elist.unwrap(list), address(msg.sender));
|
|
54
57
|
return list;
|
|
@@ -70,7 +73,10 @@ contract ElistTester is IncoUtils {
|
|
|
70
73
|
function listSet(bytes memory ctIndex, bytes memory ctValue) public payable refundUnspent returns (elist) {
|
|
71
74
|
euint256 index = inco.newEuint256{value: FEE}(ctIndex, msg.sender);
|
|
72
75
|
euint256 value = inco.newEuint256{value: FEE}(ctValue, msg.sender);
|
|
73
|
-
|
|
76
|
+
uint256 typeBits = typeBitSize(ETypes(uint8(uint256(elist.unwrap(list)) >> 16)));
|
|
77
|
+
list = inco.listSet{value: uint256(inco.lengthOf(elist.unwrap(list))) * typeBits * BIT_FEE}(
|
|
78
|
+
list, euint256.unwrap(index), euint256.unwrap(value)
|
|
79
|
+
);
|
|
74
80
|
inco.allow(elist.unwrap(list), address(this));
|
|
75
81
|
inco.allow(elist.unwrap(list), address(msg.sender));
|
|
76
82
|
return list;
|
|
@@ -79,7 +85,10 @@ contract ElistTester is IncoUtils {
|
|
|
79
85
|
function listInsert(bytes memory ctIndex, bytes memory ctValue) public payable refundUnspent returns (elist) {
|
|
80
86
|
euint256 index = inco.newEuint256{value: FEE}(ctIndex, msg.sender);
|
|
81
87
|
euint256 value = inco.newEuint256{value: FEE}(ctValue, msg.sender);
|
|
82
|
-
|
|
88
|
+
uint256 typeBits = typeBitSize(ETypes(uint8(uint256(elist.unwrap(list)) >> 16)));
|
|
89
|
+
list = inco.listInsert{value: (uint256(inco.lengthOf(elist.unwrap(list))) * typeBits + typeBits) * BIT_FEE}(
|
|
90
|
+
list, euint256.unwrap(index), euint256.unwrap(value)
|
|
91
|
+
);
|
|
83
92
|
inco.allow(elist.unwrap(list), address(this));
|
|
84
93
|
inco.allow(elist.unwrap(list), address(msg.sender));
|
|
85
94
|
return list;
|
|
@@ -94,7 +103,11 @@ contract ElistTester is IncoUtils {
|
|
|
94
103
|
elist rhs = inco.newEList{value: FEE * cts.length}(cts, listType, user);
|
|
95
104
|
inco.allow(elist.unwrap(rhs), address(this));
|
|
96
105
|
inco.allow(elist.unwrap(rhs), address(msg.sender));
|
|
97
|
-
|
|
106
|
+
uint256 lhsBits =
|
|
107
|
+
uint256(inco.lengthOf(elist.unwrap(list))) * typeBitSize(ETypes(uint8(uint256(elist.unwrap(list)) >> 16)));
|
|
108
|
+
uint256 rhsBits =
|
|
109
|
+
uint256(inco.lengthOf(elist.unwrap(rhs))) * typeBitSize(ETypes(uint8(uint256(elist.unwrap(rhs)) >> 16)));
|
|
110
|
+
list = inco.listConcat{value: (lhsBits + rhsBits) * BIT_FEE}(list, rhs);
|
|
98
111
|
inco.allow(elist.unwrap(list), address(this));
|
|
99
112
|
inco.allow(elist.unwrap(list), address(msg.sender));
|
|
100
113
|
return list;
|
|
@@ -108,14 +121,17 @@ contract ElistTester is IncoUtils {
|
|
|
108
121
|
{
|
|
109
122
|
euint256 start = inco.newEuint256{value: FEE}(ctStart, msg.sender);
|
|
110
123
|
euint256 defaultValue = inco.newEuint256{value: FEE}(ctDefaultValue, msg.sender);
|
|
111
|
-
|
|
124
|
+
uint256 typeBits = typeBitSize(ETypes(uint8(uint256(elist.unwrap(list)) >> 16)));
|
|
125
|
+
list = inco.listSlice{value: uint256(len) * typeBits * BIT_FEE}(
|
|
126
|
+
list, euint256.unwrap(start), len, euint256.unwrap(defaultValue)
|
|
127
|
+
);
|
|
112
128
|
inco.allow(elist.unwrap(list), address(this));
|
|
113
129
|
inco.allow(elist.unwrap(list), address(msg.sender));
|
|
114
130
|
return list;
|
|
115
131
|
}
|
|
116
132
|
|
|
117
|
-
function listRange(uint16 start, uint16 end) public returns (elist) {
|
|
118
|
-
newRangeList = inco.listRange(start, end);
|
|
133
|
+
function listRange(uint16 start, uint16 end) public payable returns (elist) {
|
|
134
|
+
newRangeList = inco.listRange{value: uint256(end - start) * typeBitSize(ETypes.Uint256) * BIT_FEE}(start, end);
|
|
119
135
|
inco.allow(elist.unwrap(newRangeList), address(this));
|
|
120
136
|
inco.allow(elist.unwrap(newRangeList), address(msg.sender));
|
|
121
137
|
return newRangeList;
|
|
@@ -128,14 +144,16 @@ contract ElistTester is IncoUtils {
|
|
|
128
144
|
}
|
|
129
145
|
|
|
130
146
|
function listShuffle() public payable refundUnspent returns (elist) {
|
|
131
|
-
|
|
147
|
+
uint256 typeBits = typeBitSize(ETypes(uint8(uint256(elist.unwrap(list)) >> 16)));
|
|
148
|
+
list = inco.listShuffle{value: uint256(inco.lengthOf(elist.unwrap(list))) * typeBits * BIT_FEE}(list);
|
|
132
149
|
inco.allow(elist.unwrap(list), address(this));
|
|
133
150
|
inco.allow(elist.unwrap(list), address(msg.sender));
|
|
134
151
|
return list;
|
|
135
152
|
}
|
|
136
153
|
|
|
137
|
-
function listReverse() public returns (elist) {
|
|
138
|
-
|
|
154
|
+
function listReverse() public payable returns (elist) {
|
|
155
|
+
uint256 typeBits = typeBitSize(ETypes(uint8(uint256(elist.unwrap(list)) >> 16)));
|
|
156
|
+
list = inco.listReverse{value: uint256(inco.lengthOf(elist.unwrap(list))) * typeBits * BIT_FEE}(list);
|
|
139
157
|
inco.allow(elist.unwrap(list), address(this));
|
|
140
158
|
inco.allow(elist.unwrap(list), address(msg.sender));
|
|
141
159
|
return list;
|
|
@@ -14,9 +14,9 @@ contract FakeComputeServer {
|
|
|
14
14
|
} else if (op == EOps.Mul) {
|
|
15
15
|
return lhs * rhs;
|
|
16
16
|
} else if (op == EOps.Div) {
|
|
17
|
-
return lhs / rhs;
|
|
17
|
+
return rhs == 0 ? type(uint256).max : lhs / rhs;
|
|
18
18
|
} else if (op == EOps.Rem) {
|
|
19
|
-
return lhs % rhs;
|
|
19
|
+
return rhs == 0 ? lhs : lhs % rhs;
|
|
20
20
|
} else if (op == EOps.Min) {
|
|
21
21
|
return lhs < rhs ? lhs : rhs;
|
|
22
22
|
} else if (op == EOps.Max) {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
// SPDX-License-Identifier: No License
|
|
2
2
|
pragma solidity ^0.8;
|
|
3
3
|
|
|
4
|
-
import {Test} from "forge-std/Test.sol";
|
|
4
|
+
import {Test, Vm} from "forge-std/Test.sol";
|
|
5
5
|
import {TrivialEncryption} from "../lightning-parts/TrivialEncryption.sol";
|
|
6
6
|
import {ETypes} from "../Types.sol";
|
|
7
7
|
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
|
|
8
8
|
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
9
9
|
import {inco} from "../Lib.sol";
|
|
10
10
|
import {IncoTest} from "./IncoTest.sol";
|
|
11
|
+
import {IEncryptedInput} from "../lightning-parts/interfaces/IEncryptedInput.sol";
|
|
11
12
|
|
|
12
13
|
contract ReturnTwo is UUPSUpgradeable {
|
|
13
14
|
|
|
@@ -44,6 +45,26 @@ contract TestDeploy is Test, IncoTest {
|
|
|
44
45
|
assertTrue(inco.isAcceptedVersion(42));
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
function testAddAcceptedVersion_EmitsVersionAccepted() public {
|
|
49
|
+
vm.recordLogs();
|
|
50
|
+
vm.prank(owner);
|
|
51
|
+
inco.addAcceptedVersion(42);
|
|
52
|
+
|
|
53
|
+
Vm.Log[] memory logs = vm.getRecordedLogs();
|
|
54
|
+
bytes32 expectedTopic0 = keccak256("VersionAccepted(uint16)");
|
|
55
|
+
bool found = false;
|
|
56
|
+
for (uint256 i = 0; i < logs.length; i++) {
|
|
57
|
+
if (logs[i].topics[0] == expectedTopic0) {
|
|
58
|
+
found = true;
|
|
59
|
+
// version is indexed: must appear in topics[1], not in data
|
|
60
|
+
assertEq(logs[i].topics[1], bytes32(uint256(42)), "version should be an indexed topic");
|
|
61
|
+
assertEq(logs[i].data.length, 0, "data should be empty since version is indexed");
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
assertTrue(found, "VersionAccepted event was not emitted");
|
|
66
|
+
}
|
|
67
|
+
|
|
47
68
|
function testAddAcceptedVersionNotOwner() public {
|
|
48
69
|
vm.expectRevert(abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, alice));
|
|
49
70
|
vm.prank(alice);
|
|
@@ -57,6 +78,29 @@ contract TestDeploy is Test, IncoTest {
|
|
|
57
78
|
assertFalse(inco.isAcceptedVersion(42));
|
|
58
79
|
}
|
|
59
80
|
|
|
81
|
+
function testRemoveAcceptedVersion_EmitsVersionRemoved() public {
|
|
82
|
+
vm.prank(owner);
|
|
83
|
+
inco.addAcceptedVersion(42);
|
|
84
|
+
|
|
85
|
+
vm.recordLogs();
|
|
86
|
+
vm.prank(owner);
|
|
87
|
+
inco.removeAcceptedVersion(42);
|
|
88
|
+
|
|
89
|
+
Vm.Log[] memory logs = vm.getRecordedLogs();
|
|
90
|
+
bytes32 expectedTopic0 = keccak256("VersionRemoved(uint16)");
|
|
91
|
+
bool found = false;
|
|
92
|
+
for (uint256 i = 0; i < logs.length; i++) {
|
|
93
|
+
if (logs[i].topics[0] == expectedTopic0) {
|
|
94
|
+
found = true;
|
|
95
|
+
// version is indexed: must appear in topics[1], not in data
|
|
96
|
+
assertEq(logs[i].topics[1], bytes32(uint256(42)), "version should be an indexed topic");
|
|
97
|
+
assertEq(logs[i].data.length, 0, "data should be empty since version is indexed");
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
assertTrue(found, "VersionRemoved event was not emitted");
|
|
102
|
+
}
|
|
103
|
+
|
|
60
104
|
function testRemoveAcceptedVersionNotOwner() public {
|
|
61
105
|
vm.expectRevert(abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, alice));
|
|
62
106
|
vm.prank(alice);
|
|
@@ -3,7 +3,7 @@ pragma solidity ^0.8;
|
|
|
3
3
|
|
|
4
4
|
import {IncoTest} from "./IncoTest.sol";
|
|
5
5
|
import {e, euint256, ebool, eaddress, inco} from "../Lib.sol";
|
|
6
|
-
import {SenderNotAllowedForHandle} from "../Types.sol";
|
|
6
|
+
import {SenderNotAllowedForHandle, UnsupportedType, ETypes, UnexpectedType, typeToBitMask} from "../Types.sol";
|
|
7
7
|
import {TEELifecycle} from "../lightning-parts/TEELifecycle.sol";
|
|
8
8
|
import {Td10ReportBody, MINIMUM_QUOTE_LENGTH} from "../interfaces/automata-interfaces/Types.sol";
|
|
9
9
|
|
|
@@ -96,6 +96,14 @@ contract TestFakeInfra is IncoTest {
|
|
|
96
96
|
assertEq(getUint256Value(c), 2);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
function testEDiv_DivisionByZeroReturnsMaxUint256() public {
|
|
100
|
+
euint256 a = e.asEuint256(10);
|
|
101
|
+
euint256 zero = e.asEuint256(0);
|
|
102
|
+
euint256 c = a.div(zero);
|
|
103
|
+
processAllOperations();
|
|
104
|
+
assertEq(getUint256Value(c), type(uint256).max);
|
|
105
|
+
}
|
|
106
|
+
|
|
99
107
|
function testERem() public {
|
|
100
108
|
euint256 a = e.asEuint256(10);
|
|
101
109
|
euint256 b = e.asEuint256(4);
|
|
@@ -104,6 +112,14 @@ contract TestFakeInfra is IncoTest {
|
|
|
104
112
|
assertEq(getUint256Value(c), 2);
|
|
105
113
|
}
|
|
106
114
|
|
|
115
|
+
function testERem_RemainderByZeroReturnsLhs() public {
|
|
116
|
+
euint256 a = e.asEuint256(10);
|
|
117
|
+
euint256 zero = e.asEuint256(0);
|
|
118
|
+
euint256 c = a.rem(zero);
|
|
119
|
+
processAllOperations();
|
|
120
|
+
assertEq(getUint256Value(c), 10);
|
|
121
|
+
}
|
|
122
|
+
|
|
107
123
|
function testEAnd() public {
|
|
108
124
|
euint256 a = e.asEuint256(10);
|
|
109
125
|
euint256 b = e.asEuint256(4);
|
|
@@ -514,11 +530,10 @@ contract TestFakeInfra is IncoTest {
|
|
|
514
530
|
assertEq(getUint256Value(resB), 4);
|
|
515
531
|
}
|
|
516
532
|
|
|
517
|
-
function
|
|
533
|
+
function testECastToEBoolRevert() public {
|
|
518
534
|
euint256 a = e.asEuint256(1);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
assertEq(getBoolValue(b), true);
|
|
535
|
+
vm.expectRevert(abi.encodeWithSelector(UnsupportedType.selector, ETypes.Bool));
|
|
536
|
+
inco.eCast(euint256.unwrap(a), ETypes.Bool);
|
|
522
537
|
}
|
|
523
538
|
|
|
524
539
|
function testECastToFromEBool() public {
|
|
@@ -557,7 +572,7 @@ contract TestFakeInfra is IncoTest {
|
|
|
557
572
|
function testECastAllowed() public {
|
|
558
573
|
bytes32 invalidHandle = keccak256("invalid handle");
|
|
559
574
|
vm.expectRevert(abi.encodeWithSelector(SenderNotAllowedForHandle.selector, invalidHandle, address(this)));
|
|
560
|
-
|
|
575
|
+
ebool.wrap(invalidHandle).asEuint256();
|
|
561
576
|
}
|
|
562
577
|
|
|
563
578
|
function testUninitializedHandleIsDisallowed_Add_Lhs() public {
|
|
@@ -1104,4 +1119,15 @@ contract TestFakeInfra is IncoTest {
|
|
|
1104
1119
|
assertEq(quote.length, MINIMUM_QUOTE_LENGTH);
|
|
1105
1120
|
}
|
|
1106
1121
|
|
|
1122
|
+
function testRandBoundedUpperBoundLargerThanRandType() public {
|
|
1123
|
+
euint256 upperBound = e.asEuint256(type(uint256).max);
|
|
1124
|
+
uint256 fee = inco.getFee();
|
|
1125
|
+
vm.expectRevert(
|
|
1126
|
+
abi.encodeWithSelector(
|
|
1127
|
+
UnexpectedType.selector, ETypes.Uint256, typeToBitMask(ETypes.AddressOrUint160OrBytes20)
|
|
1128
|
+
)
|
|
1129
|
+
);
|
|
1130
|
+
inco.eRandBounded{value: fee}(euint256.unwrap(upperBound), ETypes.AddressOrUint160OrBytes20);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1107
1133
|
}
|