@inco/lightning 0.2.17 → 0.3.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 +29 -0
- package/package.json +5 -1
- package/src/DeployTEE.sol +153 -0
- package/src/DeployUtils.sol +17 -9
- package/src/Errors.sol +4 -0
- package/src/IncoLightning.gen.sol +1 -1
- package/src/IncoLightning.sol +2 -1
- package/src/Types.sol +45 -3
- package/src/lightning-parts/EncryptedInput.gen.sol +1 -0
- package/src/lightning-parts/EncryptedInput.sol +1 -1
- package/src/lightning-parts/EncryptedOperations.gen.sol +1 -1
- package/src/lightning-parts/EncryptedOperations.sol +8 -6
- package/src/lightning-parts/TEELifecycle.gen.sol +58 -0
- package/src/lightning-parts/TEELifecycle.sol +255 -0
- package/src/lightning-parts/TEELifecycle.types.sol +21 -0
- package/src/lightning-parts/primitives/SignatureVerifier.gen.sol +1 -0
- package/src/lightning-parts/primitives/SignatureVerifier.sol +11 -0
- package/src/lightning-parts/test/HandleMetadata.t.sol +1 -1
- package/src/test/FakeIncoInfra/FakeQuoteVerifier.sol +29 -0
- package/src/test/FakeIncoInfra/MockRemoteAttestation.sol +37 -0
- package/src/test/FibonacciDecrypt.sol +1 -0
- package/src/test/IncoTest.sol +5 -1
- package/src/test/TEELifecycle/README.md +53 -0
- package/src/test/TEELifecycle/TEELifecycleHWTest.t.sol +119 -0
- package/src/test/TEELifecycle/TEELifecycleMockTest.t.sol +145 -0
- package/src/test/TEELifecycle/addnode_data/eoa.txt +1 -0
- package/src/test/TEELifecycle/addnode_data/quote.bin +0 -0
- package/src/test/TEELifecycle/bootstrap_data/ecies_pubkey.bin +1 -0
- package/src/test/TEELifecycle/bootstrap_data/eip712_signature.bin +1 -0
- package/src/test/TEELifecycle/bootstrap_data/eoa.txt +1 -0
- package/src/test/TEELifecycle/bootstrap_data/qe_identity +1 -0
- package/src/test/TEELifecycle/bootstrap_data/qe_identity_signature.bin +1 -0
- package/src/test/TEELifecycle/bootstrap_data/quote.bin +0 -0
- package/src/test/TEELifecycle/bootstrap_data/tcb_info +1 -0
- package/src/test/TEELifecycle/bootstrap_data/tcb_info_signature.bin +1 -0
- package/src/test/TEELifecycle/test_cert/AttestationReportSigningCA.crl +0 -0
- package/src/test/TEELifecycle/test_cert/Intel_SGX_Attestation_RootCA.cer +0 -0
- package/src/test/TEELifecycle/test_cert/Intel_SGX_PCK_CRL.crl +0 -0
- package/src/test/TEELifecycle/test_cert/Intel_SGX_PCK_PlatformCA.cer +0 -0
- package/src/test/TEELifecycle/test_cert/Intel_SGX_TCB_Signing.cer +0 -0
- package/src/test/TestFakeInfra.t.sol +18 -1
- package/src/test/TestUpgrade.t.sol +314 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import "@inco/lightning/src/lightning-parts/TEELifecycle.sol";
|
|
5
|
+
import "@inco/lightning/src/lightning-parts/TEELifecycle.types.sol";
|
|
6
|
+
import {MockRemoteAttestation} from "../FakeIncoInfra/MockRemoteAttestation.sol";
|
|
7
|
+
import {FakeQuoteVerifier} from "../FakeIncoInfra/FakeQuoteVerifier.sol";
|
|
8
|
+
|
|
9
|
+
import "forge-std/Vm.sol";
|
|
10
|
+
import "forge-std/Test.sol";
|
|
11
|
+
|
|
12
|
+
contract TEELifecycleMockTest is Test, MockRemoteAttestation, TEELifecycle {
|
|
13
|
+
|
|
14
|
+
function setUp() public {
|
|
15
|
+
quoteVerifier = new FakeQuoteVerifier();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function test_successfulBootstrap() public {
|
|
19
|
+
(BootstrapResult memory bootstrapResult, , , bytes memory quote, bytes memory signature, bytes memory mrtd) = successfulBootstrapResult();
|
|
20
|
+
vm.startPrank(this.owner());
|
|
21
|
+
this.approveNewTEEVersion(mrtd);
|
|
22
|
+
this.verifyBootstrapResult(
|
|
23
|
+
bootstrapResult,
|
|
24
|
+
quote,
|
|
25
|
+
signature
|
|
26
|
+
);
|
|
27
|
+
assertTrue(this.isBootstrapComplete(), "Bootstrap should be complete");
|
|
28
|
+
vm.stopPrank();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function test_invalidMrtd() public {
|
|
32
|
+
bytes memory badMrtd = hex"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
|
|
33
|
+
|
|
34
|
+
(BootstrapResult memory bootstrapResult, , address bootstrapPartyAddress, bytes memory quote, bytes memory signature, bytes memory mrtd) = successfulBootstrapResult();
|
|
35
|
+
|
|
36
|
+
quote = createQuote(badMrtd, bootstrapPartyAddress); // Replace with bad MRTD
|
|
37
|
+
vm.startPrank(this.owner());
|
|
38
|
+
this.approveNewTEEVersion(mrtd);
|
|
39
|
+
vm.expectRevert(bytes("Invalid report MRTD"));
|
|
40
|
+
this.verifyBootstrapResult(
|
|
41
|
+
bootstrapResult,
|
|
42
|
+
quote,
|
|
43
|
+
signature
|
|
44
|
+
);
|
|
45
|
+
vm.stopPrank();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function test_invalidSignature() public {
|
|
49
|
+
(BootstrapResult memory bootstrapResult, , , bytes memory quote, , bytes memory mrtd) = successfulBootstrapResult();
|
|
50
|
+
(uint256 bootstrapPartyFakePrivkey, ) = getLabeledKeyPair("bootstrapPartyFake");
|
|
51
|
+
bytes memory signatureInvalid = signBootstrapResult(bootstrapResult, bootstrapPartyFakePrivkey);
|
|
52
|
+
vm.startPrank(this.owner());
|
|
53
|
+
this.approveNewTEEVersion(mrtd);
|
|
54
|
+
vm.expectRevert(bytes("Invalid signature for bootstrap data"));
|
|
55
|
+
this.verifyBootstrapResult(
|
|
56
|
+
bootstrapResult,
|
|
57
|
+
quote,
|
|
58
|
+
signatureInvalid
|
|
59
|
+
);
|
|
60
|
+
vm.stopPrank();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function test_bootstrapAlreadyComplete() public {
|
|
64
|
+
(BootstrapResult memory bootstrapResult, , , bytes memory quote, bytes memory signature, bytes memory mrtd) = successfulBootstrapResult();
|
|
65
|
+
vm.startPrank(this.owner());
|
|
66
|
+
this.approveNewTEEVersion(mrtd);
|
|
67
|
+
this.verifyBootstrapResult(
|
|
68
|
+
bootstrapResult,
|
|
69
|
+
quote,
|
|
70
|
+
signature
|
|
71
|
+
);
|
|
72
|
+
vm.expectRevert(bytes("Bootstrap already completed"));
|
|
73
|
+
this.verifyBootstrapResult(
|
|
74
|
+
bootstrapResult,
|
|
75
|
+
quote,
|
|
76
|
+
signature
|
|
77
|
+
);
|
|
78
|
+
vm.stopPrank();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function test_approveNewTEEInvalidMrtd() public {
|
|
82
|
+
bytes memory mrtd = hex"deadbeef";
|
|
83
|
+
vm.startPrank(this.owner());
|
|
84
|
+
vm.expectRevert(bytes("MRTD must be 48 bytes"));
|
|
85
|
+
this.approveNewTEEVersion(mrtd);
|
|
86
|
+
vm.stopPrank();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function test_bootstrapNotCompleteNewCoval() public {
|
|
90
|
+
bytes memory mrtd = hex"2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525";
|
|
91
|
+
(, address newCoval) = getLabeledKeyPair("newCoval");
|
|
92
|
+
bytes memory quote = createQuote(mrtd, newCoval);
|
|
93
|
+
vm.startPrank(this.owner());
|
|
94
|
+
vm.expectRevert(bytes("Bootstrap not complete"));
|
|
95
|
+
this.addNewCovalidator(quote);
|
|
96
|
+
vm.stopPrank();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function test_invalidMrtdNewCoval() public {
|
|
100
|
+
(BootstrapResult memory bootstrapResult, , , bytes memory quote, bytes memory signature, bytes memory mrtd) = successfulBootstrapResult();
|
|
101
|
+
vm.startPrank(this.owner());
|
|
102
|
+
this.approveNewTEEVersion(mrtd);
|
|
103
|
+
this.verifyBootstrapResult(
|
|
104
|
+
bootstrapResult,
|
|
105
|
+
quote,
|
|
106
|
+
signature
|
|
107
|
+
);
|
|
108
|
+
bytes memory badMrtd = hex"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
|
|
109
|
+
(, address newCoval) = getLabeledKeyPair("newCoval");
|
|
110
|
+
bytes memory quoteNew = createQuote(badMrtd, newCoval);
|
|
111
|
+
|
|
112
|
+
vm.expectRevert(bytes("Invalid report MRTD"));
|
|
113
|
+
this.addNewCovalidator(quoteNew);
|
|
114
|
+
vm.stopPrank();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Helper function to create a successful bootstrap result
|
|
118
|
+
function successfulBootstrapResult() internal returns (BootstrapResult memory bootstrapResult, uint256 bootstrapPartyPrivkey, address bootstrapPartyAddress, bytes memory quote, bytes memory signature, bytes memory mrtd) {
|
|
119
|
+
(bootstrapPartyPrivkey, bootstrapPartyAddress) = getLabeledKeyPair("bootstrapParty");
|
|
120
|
+
bytes memory eciesPubkey = hex"04ff5c6dd72ad7583288b84ee2598e081fe0bc6ef543c342e925a5dfcff9afb2444d25454d7d5dcfadc9ed99477c245efa93caf58d7f58143300d81cc948e7bdf5";
|
|
121
|
+
mrtd = hex"2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525";
|
|
122
|
+
|
|
123
|
+
bootstrapResult = BootstrapResult({
|
|
124
|
+
ecies_pubkey: eciesPubkey
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
quote = createQuote(
|
|
128
|
+
mrtd,
|
|
129
|
+
bootstrapPartyAddress
|
|
130
|
+
);
|
|
131
|
+
signature = signBootstrapResult(bootstrapResult, bootstrapPartyPrivkey);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Helper function to sign the bootstrap result
|
|
135
|
+
function signBootstrapResult(
|
|
136
|
+
BootstrapResult memory bootstrapResult,
|
|
137
|
+
uint256 privateKey
|
|
138
|
+
) internal view returns (bytes memory) {
|
|
139
|
+
bytes32 bootstrapResultDigest = bootstrapResultDigest(
|
|
140
|
+
bootstrapResult
|
|
141
|
+
);
|
|
142
|
+
return getSignatureForDigest(bootstrapResultDigest, privateKey);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0x32B70C13186E3B81137ec09c0CB3ee8e14e69f64
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
�@��3��X���r�F��[s�X"�t��$��
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
�a�[O$��������G�s#������@ZH �W#��3�-`�x'r�U�?G�)|H3}�K;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0x8461984E47D19e9B86702F398982a5c2747A734D
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"TD_QE","version":2,"issueDate":"2025-08-06T16:32:25Z","nextUpdate":"2025-09-05T16:32:25Z","tcbEvaluationDataNumber":17,"miscselect":"00000000","miscselectMask":"FFFFFFFF","attributes":"11000000000000000000000000000000","attributesMask":"FBFFFFFFFFFFFFFF0000000000000000","mrsigner":"DC9E2A7C6F948F17474E34A7FC43ED030F7C1563F1BABDDF6340C82E0E54A8C5","isvprodid":2,"tcbLevels":[{"tcb":{"isvsvn":4},"tcbDate":"2024-03-13T00:00:00Z","tcbStatus":"UpToDate"}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ETw���bwޱ�˧����-ĭ�%u#O�Po�����'�ࣳE&T�d�.F�����|��
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"TDX","version":3,"issueDate":"2025-08-06T16:25:19Z","nextUpdate":"2025-09-05T16:25:19Z","fmspc":"00806F050000","pceId":"0000","tcbType":0,"tcbEvaluationDataNumber":17,"tdxModule":{"mrsigner":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","attributes":"0000000000000000","attributesMask":"FFFFFFFFFFFFFFFF"},"tdxModuleIdentities":[{"id":"TDX_03","mrsigner":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","attributes":"0000000000000000","attributesMask":"FFFFFFFFFFFFFFFF","tcbLevels":[{"tcb":{"isvsvn":3},"tcbDate":"2024-03-13T00:00:00Z","tcbStatus":"UpToDate"}]},{"id":"TDX_01","mrsigner":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","attributes":"0000000000000000","attributesMask":"FFFFFFFFFFFFFFFF","tcbLevels":[{"tcb":{"isvsvn":4},"tcbDate":"2024-03-13T00:00:00Z","tcbStatus":"UpToDate"},{"tcb":{"isvsvn":2},"tcbDate":"2023-08-09T00:00:00Z","tcbStatus":"OutOfDate"}]}],"tcbLevels":[{"tcb":{"sgxtcbcomponents":[{"svn":7,"category":"BIOS","type":"Early Microcode Update"},{"svn":7,"category":"OS/VMM","type":"SGX Late Microcode Update"},{"svn":2,"category":"OS/VMM","type":"TXT SINIT"},{"svn":2,"category":"BIOS"},{"svn":3,"category":"BIOS"},{"svn":1,"category":"BIOS"},{"svn":0},{"svn":3,"category":"OS/VMM","type":"SEAMLDR ACM"},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":11,"tdxtcbcomponents":[{"svn":5,"category":"OS/VMM","type":"TDX Module"},{"svn":0,"category":"OS/VMM","type":"TDX Module"},{"svn":7,"category":"OS/VMM","type":"TDX Late Microcode Update"},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}]},"tcbDate":"2024-03-13T00:00:00Z","tcbStatus":"UpToDate"},{"tcb":{"sgxtcbcomponents":[{"svn":6,"category":"BIOS","type":"Early Microcode Update"},{"svn":6,"category":"OS/VMM","type":"SGX Late Microcode Update"},{"svn":2,"category":"OS/VMM","type":"TXT SINIT"},{"svn":2,"category":"BIOS"},{"svn":3,"category":"BIOS"},{"svn":1,"category":"BIOS"},{"svn":0},{"svn":3,"category":"OS/VMM","type":"SEAMLDR ACM"},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":11,"tdxtcbcomponents":[{"svn":3,"category":"OS/VMM","type":"TDX Module"},{"svn":0,"category":"OS/VMM","type":"TDX Module"},{"svn":6,"category":"OS/VMM","type":"TDX Late Microcode Update"},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}]},"tcbDate":"2023-08-09T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00960","INTEL-SA-00982","INTEL-SA-00986"]},{"tcb":{"sgxtcbcomponents":[{"svn":5,"category":"BIOS","type":"Early Microcode Update"},{"svn":5,"category":"OS/VMM","type":"SGX Late Microcode Update"},{"svn":2,"category":"OS/VMM","type":"TXT SINIT"},{"svn":2,"category":"BIOS"},{"svn":3,"category":"BIOS"},{"svn":1,"category":"BIOS"},{"svn":0},{"svn":3,"category":"OS/VMM","type":"SEAMLDR ACM"},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":11,"tdxtcbcomponents":[{"svn":3,"category":"OS/VMM","type":"TDX Module"},{"svn":0,"category":"OS/VMM","type":"TDX Module"},{"svn":5,"category":"OS/VMM","type":"TDX Late Microcode Update"},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}]},"tcbDate":"2023-02-15T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00837","INTEL-SA-00960","INTEL-SA-00982","INTEL-SA-00986"]},{"tcb":{"sgxtcbcomponents":[{"svn":5,"category":"BIOS","type":"Early Microcode Update"},{"svn":5,"category":"OS/VMM","type":"SGX Late Microcode Update"},{"svn":2,"category":"OS/VMM","type":"TXT SINIT"},{"svn":2,"category":"BIOS"},{"svn":3,"category":"BIOS"},{"svn":1,"category":"BIOS"},{"svn":0},{"svn":3,"category":"OS/VMM","type":"SEAMLDR ACM"},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":5,"tdxtcbcomponents":[{"svn":3,"category":"OS/VMM","type":"TDX Module"},{"svn":0,"category":"OS/VMM","type":"TDX Module"},{"svn":5,"category":"OS/VMM","type":"TDX Late Microcode Update"},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}]},"tcbDate":"2018-01-04T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00106","INTEL-SA-00115","INTEL-SA-00135","INTEL-SA-00203","INTEL-SA-00220","INTEL-SA-00233","INTEL-SA-00270","INTEL-SA-00293","INTEL-SA-00320","INTEL-SA-00329","INTEL-SA-00381","INTEL-SA-00389","INTEL-SA-00477","INTEL-SA-00837","INTEL-SA-00960","INTEL-SA-00982","INTEL-SA-00986"]}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
��e�3?��b� \���@E\�B���2���v3��KLm�C����
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -4,6 +4,11 @@ pragma solidity ^0.8;
|
|
|
4
4
|
import {IncoTest} from "./IncoTest.sol";
|
|
5
5
|
import {e, euint256, ebool, eaddress} from "../Lib.sol";
|
|
6
6
|
import {SenderNotAllowedForHandle} from "../Types.sol";
|
|
7
|
+
import {TEELifecycle} from "../lightning-parts/TEELifecycle.sol";
|
|
8
|
+
import {MockRemoteAttestation} from "./FakeIncoInfra/MockRemoteAttestation.sol";
|
|
9
|
+
|
|
10
|
+
import {MINIMUM_QUOTE_LENGTH} from "@automata-network/dcap-attestation/types/Constants.sol";
|
|
11
|
+
import {TD10ReportBody} from "@automata-network/dcap-attestation/types/V4Structs.sol";
|
|
7
12
|
|
|
8
13
|
contract TakesEInput {
|
|
9
14
|
using e for bytes;
|
|
@@ -36,7 +41,7 @@ contract TakesEInput {
|
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
// its meta: this is testing correct behavior of our testing infrastructure
|
|
39
|
-
contract TestFakeInfra is IncoTest {
|
|
44
|
+
contract TestFakeInfra is IncoTest, MockRemoteAttestation {
|
|
40
45
|
using e for euint256;
|
|
41
46
|
using e for ebool;
|
|
42
47
|
using e for uint256;
|
|
@@ -303,4 +308,16 @@ contract TestFakeInfra is IncoTest {
|
|
|
303
308
|
);
|
|
304
309
|
a.add(euint256.wrap(randomHandle));
|
|
305
310
|
}
|
|
311
|
+
|
|
312
|
+
function testCreateQuote() public {
|
|
313
|
+
bytes memory mrtd = hex"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
|
|
314
|
+
address signer = address(0x1234567890123456789012345678901234567890);
|
|
315
|
+
bytes memory quote = createQuote(mrtd, signer);
|
|
316
|
+
TEELifecycle lifecycle = new TEELifecycle();
|
|
317
|
+
TD10ReportBody memory tdReport = lifecycle.parseTD10ReportBody(quote);
|
|
318
|
+
(address reportDataSigner, bytes memory reportMrtd) = lifecycle.parseReport(tdReport);
|
|
319
|
+
assertEq(reportDataSigner, signer);
|
|
320
|
+
assertEq(keccak256(reportMrtd), keccak256(mrtd));
|
|
321
|
+
assertEq(quote.length, MINIMUM_QUOTE_LENGTH);
|
|
322
|
+
}
|
|
306
323
|
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
// SPDX-License-Identifier: No License
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
|
|
5
|
+
import {Safe} from "safe-smart-account/Safe.sol";
|
|
6
|
+
import {SafeProxyFactory} from "safe-smart-account/proxies/SafeProxyFactory.sol";
|
|
7
|
+
import {Enum} from "safe-smart-account/libraries/Enum.sol";
|
|
8
|
+
import {IOwnerManager} from "safe-smart-account/interfaces/IOwnerManager.sol";
|
|
9
|
+
import {IncoTest} from "./IncoTest.sol";
|
|
10
|
+
import {inco} from "../Lib.sol";
|
|
11
|
+
import {IncoLightning} from "../IncoLightning.sol";
|
|
12
|
+
import {
|
|
13
|
+
MAJOR_VERSION,
|
|
14
|
+
MINOR_VERSION,
|
|
15
|
+
PATCH_VERSION
|
|
16
|
+
} from "../version/IncoLightningConfig.sol";
|
|
17
|
+
|
|
18
|
+
interface IUUPS {
|
|
19
|
+
function upgradeToAndCall(
|
|
20
|
+
address newImplementation,
|
|
21
|
+
bytes calldata data
|
|
22
|
+
) external payable;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
contract IncoLightningV2 is IncoLightning {
|
|
26
|
+
uint8 constant MAJOR_VERSION_MOCK = 255;
|
|
27
|
+
uint8 constant MINOR_VERSION_MOCK = 255;
|
|
28
|
+
uint8 constant PATCH_VERSION_MOCK = 255;
|
|
29
|
+
|
|
30
|
+
constructor(bytes32 salt) IncoLightning(salt) {}
|
|
31
|
+
|
|
32
|
+
function getVersion() public view virtual override returns (string memory) {
|
|
33
|
+
return
|
|
34
|
+
versionString(
|
|
35
|
+
MAJOR_VERSION_MOCK,
|
|
36
|
+
MINOR_VERSION_MOCK,
|
|
37
|
+
PATCH_VERSION_MOCK
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
contract TestUpgrade is IncoTest {
|
|
43
|
+
using Strings for uint256;
|
|
44
|
+
|
|
45
|
+
// EIP-1967 implementation slot
|
|
46
|
+
bytes32 private constant IMPLEMENTATION_SLOT =
|
|
47
|
+
0x360894A13BA1A3210667C828492DB98DCA3E2076CC3735A920A3CA505D382BBC;
|
|
48
|
+
|
|
49
|
+
address private incoProxyAddr;
|
|
50
|
+
IncoLightning private v1Impl;
|
|
51
|
+
IncoLightningV2 private v2Impl;
|
|
52
|
+
|
|
53
|
+
Safe private safe;
|
|
54
|
+
|
|
55
|
+
function setUp() public override {
|
|
56
|
+
super.setUp();
|
|
57
|
+
incoProxyAddr = address(inco);
|
|
58
|
+
|
|
59
|
+
Safe master = new Safe();
|
|
60
|
+
SafeProxyFactory factory = new SafeProxyFactory();
|
|
61
|
+
|
|
62
|
+
address[] memory owners = new address[](3);
|
|
63
|
+
owners[0] = alice;
|
|
64
|
+
owners[1] = bob;
|
|
65
|
+
owners[2] = carol;
|
|
66
|
+
uint256 threshold = 2;
|
|
67
|
+
bytes memory setupData = abi.encodeWithSelector(
|
|
68
|
+
Safe.setup.selector,
|
|
69
|
+
owners,
|
|
70
|
+
threshold,
|
|
71
|
+
address(0),
|
|
72
|
+
bytes(""),
|
|
73
|
+
address(0),
|
|
74
|
+
address(0),
|
|
75
|
+
0,
|
|
76
|
+
payable(address(0))
|
|
77
|
+
);
|
|
78
|
+
safe = Safe(
|
|
79
|
+
payable(factory.createProxyWithNonce(address(master), setupData, 0))
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
vm.prank(owner);
|
|
83
|
+
inco.transferOwnership(address(safe));
|
|
84
|
+
|
|
85
|
+
// Deploy V2
|
|
86
|
+
bytes32 salt = getSalt(
|
|
87
|
+
"IncoLightningV2",
|
|
88
|
+
255,
|
|
89
|
+
255,
|
|
90
|
+
255,
|
|
91
|
+
testDeployer,
|
|
92
|
+
"testnet"
|
|
93
|
+
);
|
|
94
|
+
v2Impl = new IncoLightningV2(salt);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function test_SafeUpgrade2of3_Succeeds() public {
|
|
98
|
+
string memory versionBefore = inco.getVersion();
|
|
99
|
+
assertEq(
|
|
100
|
+
versionBefore,
|
|
101
|
+
string.concat(
|
|
102
|
+
uint256(MAJOR_VERSION).toString(),
|
|
103
|
+
"_",
|
|
104
|
+
uint256(MINOR_VERSION).toString(),
|
|
105
|
+
"_",
|
|
106
|
+
uint256(PATCH_VERSION).toString()
|
|
107
|
+
)
|
|
108
|
+
);
|
|
109
|
+
// data to sign
|
|
110
|
+
bytes memory data = abi.encodeWithSelector(
|
|
111
|
+
IUUPS.upgradeToAndCall.selector,
|
|
112
|
+
address(v2Impl),
|
|
113
|
+
""
|
|
114
|
+
);
|
|
115
|
+
// prepare txhash
|
|
116
|
+
bytes32 txHash = _txHash(safe, incoProxyAddr, 0, data);
|
|
117
|
+
// sign txHash
|
|
118
|
+
bytes memory sigA = _sign(alicePrivKey, txHash);
|
|
119
|
+
bytes memory sigB = _sign(bobPrivKey, txHash);
|
|
120
|
+
// sort signatures (asc)
|
|
121
|
+
bytes memory signatures = _packSortedTwo(sigA, alice, sigB, bob);
|
|
122
|
+
// execute tx with sorted signatures
|
|
123
|
+
_execSafe(safe, incoProxyAddr, 0, data, signatures);
|
|
124
|
+
|
|
125
|
+
address implAfter = address(
|
|
126
|
+
uint160(uint256(vm.load(incoProxyAddr, IMPLEMENTATION_SLOT)))
|
|
127
|
+
);
|
|
128
|
+
assertEq(implAfter, address(v2Impl));
|
|
129
|
+
|
|
130
|
+
string memory versionAfter = inco.getVersion();
|
|
131
|
+
assertEq(versionAfter, "255_255_255");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function test_SafeSingleSignature_Fails() public {
|
|
135
|
+
bytes memory data = abi.encodeWithSelector(
|
|
136
|
+
IUUPS.upgradeToAndCall.selector,
|
|
137
|
+
address(v2Impl),
|
|
138
|
+
""
|
|
139
|
+
);
|
|
140
|
+
bytes32 txHash = _txHash(safe, incoProxyAddr, 0, data);
|
|
141
|
+
bytes memory sigA = _sign(alicePrivKey, txHash);
|
|
142
|
+
vm.expectRevert();
|
|
143
|
+
_execSafe(safe, incoProxyAddr, 0, data, sigA);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function test_Safe_UnsortedSignatures_Fails() public {
|
|
147
|
+
bytes memory data = abi.encodeWithSelector(
|
|
148
|
+
IUUPS.upgradeToAndCall.selector,
|
|
149
|
+
address(v2Impl),
|
|
150
|
+
""
|
|
151
|
+
);
|
|
152
|
+
bytes32 txHash = _txHash(safe, incoProxyAddr, 0, data);
|
|
153
|
+
bytes memory sigA = _sign(alicePrivKey, txHash);
|
|
154
|
+
bytes memory sigC = _sign(carolPrivKey, txHash);
|
|
155
|
+
bytes memory signatures = bytes.concat(sigC, sigA); // unsorted
|
|
156
|
+
vm.expectRevert();
|
|
157
|
+
_execSafe(safe, incoProxyAddr, 0, data, signatures);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function test_Safe_WrongSigner_Fails() public {
|
|
161
|
+
bytes memory data = abi.encodeWithSelector(
|
|
162
|
+
IUUPS.upgradeToAndCall.selector,
|
|
163
|
+
address(v2Impl),
|
|
164
|
+
""
|
|
165
|
+
);
|
|
166
|
+
bytes32 txHash = _txHash(safe, incoProxyAddr, 0, data);
|
|
167
|
+
bytes memory sigOwner = _sign(alicePrivKey, txHash);
|
|
168
|
+
bytes memory sigAttacker = _sign(davePrivKey, txHash);
|
|
169
|
+
bytes memory signatures = _packSortedTwo(
|
|
170
|
+
sigOwner,
|
|
171
|
+
alice,
|
|
172
|
+
sigAttacker,
|
|
173
|
+
dave
|
|
174
|
+
); // dave not an owner
|
|
175
|
+
vm.expectRevert();
|
|
176
|
+
_execSafe(safe, incoProxyAddr, 0, data, signatures);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function test_Safe_ReplayNonce_Fails() public {
|
|
180
|
+
bytes memory data = abi.encodeWithSelector(
|
|
181
|
+
IUUPS.upgradeToAndCall.selector,
|
|
182
|
+
address(v2Impl),
|
|
183
|
+
""
|
|
184
|
+
);
|
|
185
|
+
bytes32 txHash = _txHash(safe, incoProxyAddr, 0, data);
|
|
186
|
+
bytes memory sigA = _sign(alicePrivKey, txHash);
|
|
187
|
+
bytes memory sigB = _sign(bobPrivKey, txHash);
|
|
188
|
+
bytes memory signatures = _packSortedTwo(sigA, alice, sigB, bob);
|
|
189
|
+
_execSafe(safe, incoProxyAddr, 0, data, signatures);
|
|
190
|
+
|
|
191
|
+
string memory versionAfter = inco.getVersion();
|
|
192
|
+
assertEq(versionAfter, "255_255_255");
|
|
193
|
+
|
|
194
|
+
vm.expectRevert();
|
|
195
|
+
_execSafe(safe, incoProxyAddr, 0, data, signatures); // nonce advanced
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function test_Safe_UpdateSigners_SwapOwner_ThenUpgrade() public {
|
|
199
|
+
// swap bob -> eve (prevOwner = alice since owners were [alice, bob, carol])
|
|
200
|
+
bytes memory change = abi.encodeWithSelector(
|
|
201
|
+
IOwnerManager.swapOwner.selector,
|
|
202
|
+
alice,
|
|
203
|
+
bob,
|
|
204
|
+
eve
|
|
205
|
+
);
|
|
206
|
+
bytes32 changeHash = _txHash(safe, address(safe), 0, change);
|
|
207
|
+
bytes memory changeSigA = _sign(alicePrivKey, changeHash);
|
|
208
|
+
bytes memory changeSigC = _sign(carolPrivKey, changeHash);
|
|
209
|
+
bytes memory changeSigs = _packSortedTwo(
|
|
210
|
+
changeSigA,
|
|
211
|
+
alice,
|
|
212
|
+
changeSigC,
|
|
213
|
+
carol
|
|
214
|
+
);
|
|
215
|
+
_execSafe(safe, address(safe), 0, change, changeSigs);
|
|
216
|
+
|
|
217
|
+
// assertions on owners/threshold
|
|
218
|
+
assertTrue(safe.isOwner(eve), "new owner not added");
|
|
219
|
+
assertFalse(safe.isOwner(bob), "old owner not removed");
|
|
220
|
+
assertEq(safe.getThreshold(), 2, "threshold changed unexpectedly");
|
|
221
|
+
|
|
222
|
+
// Attempt upgrade signed by removed owner should fail
|
|
223
|
+
bytes memory upg = abi.encodeWithSelector(
|
|
224
|
+
IUUPS.upgradeToAndCall.selector,
|
|
225
|
+
address(v2Impl),
|
|
226
|
+
""
|
|
227
|
+
);
|
|
228
|
+
bytes32 upgHash = _txHash(safe, incoProxyAddr, 0, upg);
|
|
229
|
+
bytes memory badSigA = _sign(alicePrivKey, upgHash);
|
|
230
|
+
bytes memory badSigB = _sign(bobPrivKey, upgHash); // removed owner
|
|
231
|
+
bytes memory badSigs = _packSortedTwo(badSigA, alice, badSigB, bob);
|
|
232
|
+
vm.expectRevert();
|
|
233
|
+
_execSafe(safe, incoProxyAddr, 0, upg, badSigs);
|
|
234
|
+
|
|
235
|
+
// Now sign with new owner (owner4) and succeed
|
|
236
|
+
bytes memory goodSigA = _sign(alicePrivKey, upgHash);
|
|
237
|
+
bytes memory goodSigE = _sign(evePrivKey, upgHash);
|
|
238
|
+
bytes memory goodSigs = _packSortedTwo(goodSigA, alice, goodSigE, eve);
|
|
239
|
+
_execSafe(safe, incoProxyAddr, 0, upg, goodSigs);
|
|
240
|
+
|
|
241
|
+
address implAfter = address(
|
|
242
|
+
uint160(uint256(vm.load(incoProxyAddr, IMPLEMENTATION_SLOT)))
|
|
243
|
+
);
|
|
244
|
+
assertEq(implAfter, address(v2Impl));
|
|
245
|
+
|
|
246
|
+
string memory versionAfter = inco.getVersion();
|
|
247
|
+
assertEq(versionAfter, "255_255_255");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function test_Upgrade_NotBy_SafeWallet_Fails() public {
|
|
251
|
+
vm.prank(owner);
|
|
252
|
+
vm.expectRevert();
|
|
253
|
+
inco.upgradeToAndCall(address(v2Impl), "");
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Helpers
|
|
257
|
+
function _txHash(
|
|
258
|
+
Safe _safe,
|
|
259
|
+
address to,
|
|
260
|
+
uint256 value,
|
|
261
|
+
bytes memory data
|
|
262
|
+
) internal view returns (bytes32) {
|
|
263
|
+
return
|
|
264
|
+
_safe.getTransactionHash(
|
|
265
|
+
to,
|
|
266
|
+
value,
|
|
267
|
+
data,
|
|
268
|
+
Enum.Operation.Call,
|
|
269
|
+
0,
|
|
270
|
+
0,
|
|
271
|
+
0,
|
|
272
|
+
address(0),
|
|
273
|
+
payable(address(0)),
|
|
274
|
+
_safe.nonce()
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
function _sign(
|
|
278
|
+
uint256 pk,
|
|
279
|
+
bytes32 txHash
|
|
280
|
+
) internal view returns (bytes memory) {
|
|
281
|
+
(uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, txHash);
|
|
282
|
+
if (v < 27) v += 27;
|
|
283
|
+
return abi.encodePacked(r, s, v);
|
|
284
|
+
}
|
|
285
|
+
function _packSortedTwo(
|
|
286
|
+
bytes memory sigA,
|
|
287
|
+
address addrA,
|
|
288
|
+
bytes memory sigB,
|
|
289
|
+
address addrB
|
|
290
|
+
) internal pure returns (bytes memory) {
|
|
291
|
+
return
|
|
292
|
+
addrA < addrB ? bytes.concat(sigA, sigB) : bytes.concat(sigB, sigA);
|
|
293
|
+
}
|
|
294
|
+
function _execSafe(
|
|
295
|
+
Safe _safe,
|
|
296
|
+
address to,
|
|
297
|
+
uint256 value,
|
|
298
|
+
bytes memory data,
|
|
299
|
+
bytes memory signatures
|
|
300
|
+
) internal {
|
|
301
|
+
_safe.execTransaction(
|
|
302
|
+
to,
|
|
303
|
+
value,
|
|
304
|
+
data,
|
|
305
|
+
Enum.Operation.Call,
|
|
306
|
+
0,
|
|
307
|
+
0,
|
|
308
|
+
0,
|
|
309
|
+
address(0),
|
|
310
|
+
payable(address(0)),
|
|
311
|
+
signatures
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
}
|