@@ -74,10 +74,11 @@ contract WorkflowRegistry is Ownable2StepMsgSender, ITypeAndVersion {
74
74
/// When a workflow is paused it is removed from the don family.
75
75
mapping (bytes32 rid = > bytes32 donHash ) private s_donByWorkflowRid;
76
76
77
- /// @dev Tracking allowlisted requests for the owner address, required to enable anyone to verify off-chain requests.
78
- mapping (bytes32 ownerDigestHash = > uint32 expiryTimestamp ) private s_requestsAllowlist;
79
- /// @dev Storing allowlisted requests for all owners, enabling fetching all non-expired requests
80
- OwnerAllowlistedRequest[] private s_requestAllowlistArray;
77
+ /// @dev Fast lookup for allowlisted requests. Key is keccak256(abi.encode(owner, requestDigest)), value is (array_index + 1).
78
+ /// We store index+1 so that 0 can represent "not found" (since array indices start at 0).
79
+ mapping (bytes32 => uint256 ) private s_requestIndexMap;
80
+ /// @dev Array storing all allowlisted request data for enumeration and pagination.
81
+ OwnerAllowlistedRequest[] private s_requestData;
81
82
/// @dev Map each owner address to their arbitrary config. Can be used to control billing parameters or any other data per owner
82
83
mapping (address owner = > bytes config ) private s_ownerConfig;
83
84
@@ -1278,10 +1279,23 @@ contract WorkflowRegistry is Ownable2StepMsgSender, ITypeAndVersion {
1278
1279
}
1279
1280
if (! s_linkedOwners.contains (msg .sender )) revert OwnershipLinkDoesNotExist (msg .sender );
1280
1281
1281
- s_requestsAllowlist[keccak256 (abi.encode (msg .sender , requestDigest))] = expiryTimestamp;
1282
- s_requestAllowlistArray.push (
1283
- OwnerAllowlistedRequest ({owner: msg .sender , requestDigest: requestDigest, expiryTimestamp: expiryTimestamp})
1284
- );
1282
+ bytes32 key = keccak256 (abi.encode (msg .sender , requestDigest));
1283
+
1284
+ // Check if this request already exists (0 means not found)
1285
+ uint256 storedIndex = s_requestIndexMap[key];
1286
+
1287
+ if (storedIndex != 0 ) {
1288
+ // Update existing entry in place (convert back to 0-based index)
1289
+ s_requestData[storedIndex - 1 ].expiryTimestamp = expiryTimestamp;
1290
+ } else {
1291
+ // Create new entry
1292
+ uint256 newIndex = s_requestData.length ;
1293
+ s_requestData.push (
1294
+ OwnerAllowlistedRequest ({owner: msg .sender , requestDigest: requestDigest, expiryTimestamp: expiryTimestamp})
1295
+ );
1296
+ // Store index+1 so that 0 can represent "not found"
1297
+ s_requestIndexMap[key] = newIndex + 1 ;
1298
+ }
1285
1299
emit RequestAllowlisted (msg .sender , requestDigest, expiryTimestamp);
1286
1300
}
1287
1301
@@ -1292,41 +1306,59 @@ contract WorkflowRegistry is Ownable2StepMsgSender, ITypeAndVersion {
1292
1306
/// @param requestDigest Unique identifier for the request (hash of the request payload).
1293
1307
/// @return bool True if the request is allowlisted and not expired, false otherwise.
1294
1308
function isRequestAllowlisted (address owner , bytes32 requestDigest ) external view returns (bool ) {
1295
- return s_requestsAllowlist[keccak256 (abi.encode (owner, requestDigest))] > block .timestamp ;
1296
- }
1297
-
1309
+ bytes32 key = keccak256 (abi.encode (owner, requestDigest));
1310
+ uint256 storedIndex = s_requestIndexMap[key];
1311
+ if (storedIndex == 0 ) return false ; // Not found
1312
+
1313
+ OwnerAllowlistedRequest storage request = s_requestData[storedIndex - 1 ];
1314
+ return request.expiryTimestamp > block .timestamp ;
1315
+ }
1316
+
1317
+ /// @notice Returns a paginated list of allowlisted requests across all owners.
1318
+ /// @dev - Reads a slice of the allowlisted requests starting at `start` and spanning up to `limit` elements.
1319
+ /// - Expired entries (where `expiryTimestamp <= block.timestamp`) are filtered out.
1320
+ /// - The returned array may therefore be shorter than `limit`.
1321
+ /// - Does not revert on out-of-range pagination: if `start >= total`, returns an empty array.
1322
+ /// @param start Zero-based index into the allowlist at which to begin.
1323
+ /// @param limit Maximum number of entries to return from `start`.
1324
+ /// @return allowlistedRequests Array of {requestDigest, owner, expiryTimestamp} structs
1325
+ /// for all non-expired requests found in the page slice.
1298
1326
function getAllowlistedRequests (
1299
1327
uint256 start ,
1300
1328
uint256 limit
1301
1329
) external view returns (OwnerAllowlistedRequest[] memory allowlistedRequests ) {
1302
- uint256 total = s_requestAllowlistArray .length ;
1330
+ uint256 total = s_requestData .length ;
1303
1331
uint256 pageCount = _getPageCount (total, start, limit);
1304
1332
1305
1333
if (pageCount == 0 ) return new OwnerAllowlistedRequest [](0 );
1306
1334
1307
- allowlistedRequests = new OwnerAllowlistedRequest [](pageCount);
1308
- uint256 addedCount = 0 ;
1335
+ // First pass: count valid (non-expired) entries in the page range
1336
+ uint256 validCount = 0 ;
1309
1337
for (uint256 i = 0 ; i < pageCount; ++ i) {
1310
- OwnerAllowlistedRequest storage request = s_requestAllowlistArray [start + i];
1338
+ OwnerAllowlistedRequest storage request = s_requestData [start + i];
1311
1339
if (request.expiryTimestamp > block .timestamp ) {
1312
- allowlistedRequests[addedCount] = request;
1313
- ++ addedCount;
1340
+ ++ validCount;
1314
1341
}
1315
1342
}
1316
1343
1317
- if (addedCount < pageCount) {
1318
- OwnerAllowlistedRequest[] memory shrinkedList = new OwnerAllowlistedRequest [](addedCount);
1319
- for (uint256 i = 0 ; i < addedCount; ++ i) {
1320
- shrinkedList[i] = allowlistedRequests[i];
1344
+ // Allocate exact size needed
1345
+ allowlistedRequests = new OwnerAllowlistedRequest [](validCount);
1346
+
1347
+ // Second pass: populate the array with valid entries
1348
+ uint256 addedCount = 0 ;
1349
+ for (uint256 i = 0 ; i < pageCount; ++ i) {
1350
+ OwnerAllowlistedRequest storage request = s_requestData[start + i];
1351
+ if (request.expiryTimestamp > block .timestamp ) {
1352
+ allowlistedRequests[addedCount] = request;
1353
+ ++ addedCount;
1321
1354
}
1322
- allowlistedRequests = shrinkedList;
1323
1355
}
1324
1356
1325
1357
return allowlistedRequests;
1326
1358
}
1327
1359
1328
1360
function totalAllowlistedRequests () external view returns (uint256 ) {
1329
- return s_requestAllowlistArray .length ;
1361
+ return s_requestData .length ;
1330
1362
}
1331
1363
1332
1364
// ================================================================
0 commit comments