Skip to content

Commit 2e33699

Browse files
committed
N-03 use custom errors everywhere
Addresses N-03 on the Q3 2025 OZ audit: Since Solidity version 0.8.26, custom error support has been added to require statements. Initially, this feature was only available through the IR pipeline. However, Solidity 0.8.27 extended support for this feature to the legacy pipeline as well. Throughout the codebase, multiple instances where if-revert statements could be replaced with require statements were identified: For conciseness and gas savings, consider replacing if-revert statements with require statements.
1 parent 1596a79 commit 2e33699

File tree

3 files changed

+20
-41
lines changed

3 files changed

+20
-41
lines changed

src/FlashtestationRegistry.sol

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -141,34 +141,32 @@ contract FlashtestationRegistry is
141141
limitBytesSize(extendedRegistrationData)
142142
{
143143
(bool success, bytes memory output) = attestationContract.verifyAndAttestOnChain{value: msg.value}(rawQuote);
144-
if (!success) {
145-
revert InvalidQuote(output);
146-
}
144+
require(success, InvalidQuote(output));
147145

148146
// now we know the quote is valid, we can safely parse the output into the TDX report body,
149147
// from which we'll extract the data we need to register the TEE
150148
TD10ReportBody memory td10ReportBody = QuoteParser.parseV4VerifierOutput(output);
151149

152150
// Binding the tee address and extended report data to the quote
153-
if (td10ReportBody.reportData.length < TD_REPORTDATA_LENGTH) {
154-
revert InvalidReportDataLength(td10ReportBody.reportData.length);
155-
}
151+
require(
152+
td10ReportBody.reportData.length >= TD_REPORTDATA_LENGTH,
153+
InvalidReportDataLength(td10ReportBody.reportData.length)
154+
);
156155

157156
(address teeAddress, bytes32 extendedDataReportHash) = QuoteParser.parseReportData(td10ReportBody.reportData);
158157

159158
// Ensure that the caller is the TEE-controlled address, otherwise we have no guarantees that
160159
// the TEE-controlled address is the one that is registering the TEE
161-
if (signer != teeAddress) {
162-
revert SignerMustMatchTEEAddress(signer, teeAddress);
163-
}
160+
require(signer == teeAddress, SignerMustMatchTEEAddress(signer, teeAddress));
164161

165162
// Verify that the extended registration data matches the hash in the TDX report data
166163
// This is to ensure that the values in extendedRegistrationData are the same as the values
167164
// in the TDX report data, which cannot be forged by the TEE-controlled address
168165
bytes32 extendedRegistrationDataHash = keccak256(extendedRegistrationData);
169-
if (extendedRegistrationDataHash != extendedDataReportHash) {
170-
revert InvalidRegistrationDataHash(extendedDataReportHash, extendedRegistrationDataHash);
171-
}
166+
require(
167+
extendedRegistrationDataHash == extendedDataReportHash,
168+
InvalidRegistrationDataHash(extendedDataReportHash, extendedRegistrationDataHash)
169+
);
172170

173171
bytes32 newQuoteHash = keccak256(rawQuote);
174172
bool previouslyRegistered = checkPreviousRegistration(teeAddress, newQuoteHash);
@@ -203,9 +201,7 @@ contract FlashtestationRegistry is
203201
*/
204202
function checkPreviousRegistration(address teeAddress, bytes32 newQuoteHash) internal view returns (bool) {
205203
bytes32 existingQuoteHash = registeredTEEs[teeAddress].quoteHash;
206-
if (newQuoteHash == existingQuoteHash) {
207-
revert TEEServiceAlreadyRegistered(teeAddress);
208-
}
204+
require(newQuoteHash != existingQuoteHash, TEEServiceAlreadyRegistered(teeAddress));
209205

210206
// if the TEE is already registered, but we're using a different quote,
211207
// return true to signal that the TEE is already registered but is updating its quote
@@ -234,28 +230,17 @@ contract FlashtestationRegistry is
234230
// if the TEE-controlled address is not registered with the FlashtestationRegistry,
235231
// it doesn't make sense to invalidate the attestation
236232
RegisteredTEE memory registeredTEE = registeredTEEs[teeAddress];
237-
if (registeredTEE.rawQuote.length == 0) {
238-
revert TEEServiceNotRegistered(teeAddress);
239-
}
240-
241-
if (!registeredTEE.isValid) {
242-
revert TEEServiceAlreadyInvalid(teeAddress);
243-
}
233+
require(registeredTEE.rawQuote.length > 0, TEEServiceNotRegistered(teeAddress));
234+
require(registeredTEE.isValid, TEEServiceAlreadyInvalid(teeAddress));
244235

245236
// now we check the attestation, and invalidate the TEE if it's no longer valid.
246237
// This will only happen if the DCAP Endorsements associated with the TEE's quote
247238
// have been updated
248239
(bool success,) = attestationContract.verifyAndAttestOnChain{value: msg.value}(registeredTEE.rawQuote);
249-
if (success) {
250-
// if the attestation is still valid, then this function call is a no-op except for
251-
// wasting the caller's gas. So we revert here to signal that the TEE is still valid.
252-
// Offchain users who want to monitor for potential invalid TEEs can do so by calling
253-
// this function and checking for the `TEEIsStillValid` error
254-
revert TEEIsStillValid(teeAddress);
255-
} else {
256-
registeredTEEs[teeAddress].isValid = false;
257-
emit TEEServiceInvalidated(teeAddress);
258-
}
240+
require(!success, TEEIsStillValid(teeAddress));
241+
242+
registeredTEEs[teeAddress].isValid = false;
243+
emit TEEServiceInvalidated(teeAddress);
259244
}
260245

261246
/// @inheritdoc IFlashtestationRegistry

src/utils/QuoteParser.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,7 @@ library QuoteParser {
107107
*/
108108
function checkTEEVersion(bytes memory rawReportBody) internal pure {
109109
uint16 version = uint16(bytes2((rawReportBody.substring(0, 2)))); // uint16 is 2 bytes
110-
if (version != ACCEPTED_TDX_VERSION) {
111-
revert InvalidTEEVersion(version);
112-
}
110+
require(version == ACCEPTED_TDX_VERSION, InvalidTEEVersion(version));
113111
}
114112

115113
/**
@@ -119,8 +117,6 @@ library QuoteParser {
119117
*/
120118
function checkTEEType(bytes memory rawReportBody) internal pure {
121119
bytes4 teeType = bytes4(rawReportBody.substring(2, 4)); // 4 bytes
122-
if (teeType != TDX_TEE) {
123-
revert InvalidTEEType(teeType);
124-
}
120+
require(teeType == TDX_TEE, InvalidTEEType(teeType));
125121
}
126122
}

test/mocks/MockAutomataDcapAttestationFee.sol

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ contract MockAutomataDcapAttestationFee {
2525
error InsufficientFee(uint256 required, uint256 provided);
2626

2727
function verifyAndAttestOnChain(bytes calldata rawQuote) external payable returns (bool, bytes memory) {
28-
if (msg.value < baseFee) {
29-
revert InsufficientFee(baseFee, msg.value);
30-
}
28+
require(msg.value >= baseFee, InsufficientFee(baseFee, msg.value));
3129

3230
QuoteResult memory result = quoteResults[rawQuote];
3331
return (result.success, result.output);

0 commit comments

Comments
 (0)