@bloxchain/contracts 1.0.0-alpha.7 → 1.0.0

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +8 -9
  3. package/abi/BaseStateMachine.abi.json +773 -822
  4. package/abi/EngineBlox.abi.json +562 -552
  5. package/abi/GuardController.abi.json +1597 -1609
  6. package/abi/GuardControllerDefinitions.abi.json +235 -199
  7. package/abi/IDefinition.abi.json +57 -47
  8. package/abi/RuntimeRBAC.abi.json +841 -842
  9. package/abi/RuntimeRBACDefinitions.abi.json +212 -202
  10. package/abi/SecureOwnable.abi.json +1365 -1349
  11. package/abi/SecureOwnableDefinitions.abi.json +174 -164
  12. package/core/AUDIT.md +45 -0
  13. package/core/access/RuntimeRBAC.sol +130 -61
  14. package/core/access/interface/IRuntimeRBAC.sol +3 -3
  15. package/core/access/lib/definitions/RuntimeRBACDefinitions.sol +7 -3
  16. package/core/base/BaseStateMachine.sol +971 -967
  17. package/core/base/interface/IBaseStateMachine.sol +153 -160
  18. package/core/execution/GuardController.sol +89 -75
  19. package/core/execution/interface/IGuardController.sol +146 -160
  20. package/core/execution/lib/definitions/GuardControllerDefinitions.sol +136 -25
  21. package/core/lib/EngineBlox.sol +577 -327
  22. package/core/lib/interfaces/IDefinition.sol +49 -49
  23. package/core/lib/interfaces/IEventForwarder.sol +4 -2
  24. package/core/lib/utils/SharedValidation.sol +534 -490
  25. package/core/pattern/Account.sol +84 -75
  26. package/core/security/SecureOwnable.sol +446 -390
  27. package/core/security/interface/ISecureOwnable.sol +105 -105
  28. package/core/security/lib/definitions/SecureOwnableDefinitions.sol +49 -17
  29. package/package.json +51 -49
  30. package/standards/behavior/ICopyable.sol +3 -11
  31. package/standards/hooks/IOnActionHook.sol +1 -1
  32. package/abi/AccountBlox.abi.json +0 -3935
  33. package/abi/BareBlox.abi.json +0 -1378
  34. package/abi/RoleBlox.abi.json +0 -2983
  35. package/abi/SecureBlox.abi.json +0 -2753
  36. package/abi/SimpleRWA20.abi.json +0 -4032
  37. package/abi/SimpleRWA20Definitions.abi.json +0 -191
  38. package/abi/SimpleVault.abi.json +0 -3407
  39. package/abi/SimpleVaultDefinitions.abi.json +0 -269
  40. package/core/research/BloxchainWallet.sol +0 -133
  41. package/core/research/FactoryBlox/FactoryBlox.sol +0 -343
  42. package/core/research/FactoryBlox/FactoryBloxDefinitions.sol +0 -143
  43. package/core/research/erc1155-blox/ERC1155Blox.sol +0 -169
  44. package/core/research/erc1155-blox/lib/definitions/ERC1155BloxDefinitions.sol +0 -203
  45. package/core/research/erc20-blox/ERC20Blox.sol +0 -167
  46. package/core/research/erc20-blox/lib/definitions/ERC20BloxDefinitions.sol +0 -185
  47. package/core/research/erc721-blox/ERC721Blox.sol +0 -131
  48. package/core/research/erc721-blox/lib/definitions/ERC721BloxDefinitions.sol +0 -172
  49. package/core/research/lending-blox/.gitkeep +0 -1
  50. package/core/research/p2p-blox/P2PBlox.sol +0 -266
  51. package/core/research/p2p-blox/README.md +0 -85
  52. package/core/research/p2p-blox/lib/definitions/P2PBloxDefinitions.sol +0 -19
@@ -1,967 +1,971 @@
1
- // SPDX-License-Identifier: MPL-2.0
2
- pragma solidity 0.8.33;
3
-
4
- // OpenZeppelin imports
5
- import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
6
- import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
7
- import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
8
-
9
- // Contracts imports
10
- import "../lib/EngineBlox.sol";
11
- import "../lib/utils/SharedValidation.sol";
12
- import "./interface/IBaseStateMachine.sol";
13
-
14
- /**
15
- * @title BaseStateMachine
16
- * @dev Core state machine functionality for secure multi-phase operations
17
- *
18
- * This contract provides the foundational state machine capabilities that can be extended
19
- * by security-specific contracts. It handles:
20
- * - State initialization and management
21
- * - Meta-transaction utilities and parameter creation
22
- * - State queries and transaction history
23
- * - Role-based access control queries
24
- * - System state information
25
- *
26
- * The contract is designed to be inherited by security-specific contracts that implement
27
- * their own operation types and business logic while leveraging the core state machine.
28
- * All access to EngineBlox library functions is centralized through BaseStateMachine
29
- * wrapper functions to ensure consistency and maintainability.
30
- *
31
- * Key Features:
32
- * - State initialization with role and permission setup
33
- * - Meta-transaction parameter creation and generation
34
- * - Comprehensive state queries and transaction history
35
- * - Role and permission validation utilities
36
- * - System configuration queries
37
- * - Event forwarding for external monitoring
38
- */
39
- abstract contract BaseStateMachine is Initializable, ERC165Upgradeable, ReentrancyGuardUpgradeable {
40
- using EngineBlox for EngineBlox.SecureOperationState;
41
- using SharedValidation for *;
42
-
43
- EngineBlox.SecureOperationState internal _secureState;
44
-
45
- /**
46
- * @dev Unified component event for SecureOwnable, GuardController, RuntimeRBAC.
47
- * Indexers filter by functionSelector (msg.sig at emit site) and decode data (abi-encoded payload).
48
- * @param functionSelector The function selector (msg.sig) at the emit site; used by indexers to filter
49
- * @param data ABI-encoded payload associated with the event
50
- */
51
- event ComponentEvent(bytes4 indexed functionSelector, bytes data);
52
-
53
- /**
54
- * @notice Initializes the base state machine core
55
- * @param initialOwner The initial owner address
56
- * @param broadcaster The broadcaster address
57
- * @param recovery The recovery address
58
- * @param timeLockPeriodSec The timelock period in seconds
59
- * @param eventForwarder The event forwarder address
60
- */
61
- function _initializeBaseStateMachine(
62
- address initialOwner,
63
- address broadcaster,
64
- address recovery,
65
- uint256 timeLockPeriodSec,
66
- address eventForwarder
67
- ) internal onlyInitializing {
68
- __ERC165_init();
69
- __ReentrancyGuard_init();
70
-
71
- _secureState.initialize(initialOwner, broadcaster, recovery, timeLockPeriodSec);
72
-
73
- _secureState.setEventForwarder(eventForwarder);
74
- }
75
-
76
- // ============ SYSTEM ROLE QUERY FUNCTIONS ============
77
-
78
- /**
79
- * @dev Returns the owner of the contract
80
- * @return The owner of the contract
81
- */
82
- function owner() public view returns (address) {
83
- return _getAuthorizedWalletAt(EngineBlox.OWNER_ROLE, 0);
84
- }
85
-
86
- /**
87
- * @dev Returns all broadcaster addresses for the BROADCASTER_ROLE
88
- * @return Array of broadcaster addresses
89
- */
90
- function getBroadcasters() public view returns (address[] memory) {
91
- return _getAuthorizedWallets(EngineBlox.BROADCASTER_ROLE);
92
- }
93
-
94
- /**
95
- * @dev Returns the recovery address
96
- * @return The recovery address
97
- */
98
- function getRecovery() public view returns (address) {
99
- return _getAuthorizedWalletAt(EngineBlox.RECOVERY_ROLE, 0);
100
- }
101
-
102
- // ============ INTERFACE SUPPORT ============
103
-
104
- /**
105
- * @dev See {IERC165-supportsInterface}.
106
- * @notice Base implementation for ERC165 interface detection
107
- * @notice Registers IBaseStateMachine interface ID for proper interface detection
108
- * @notice Component contracts (SecureOwnable, RuntimeRBAC, GuardController) should override
109
- * to add their respective interface IDs for component detection
110
- */
111
- function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
112
- return interfaceId == type(IBaseStateMachine).interfaceId || super.supportsInterface(interfaceId);
113
- }
114
-
115
- // ============ TRANSACTION MANAGEMENT ============
116
-
117
- /**
118
- * @dev Centralized function to request a transaction with common validation
119
- * @param requester The address requesting the transaction
120
- * @param target The target contract address
121
- * @param value The ETH value to send (0 for standard function calls)
122
- * @param gasLimit The gas limit for execution
123
- * @param operationType The type of operation
124
- * @param functionSelector The function selector for execution (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
125
- * @param params The encoded parameters for the function (empty for simple native token transfers)
126
- * @return The created transaction record
127
- * @notice Validates permissions for the calling function (request function), not the execution selector
128
- * @notice Execution functions are internal-only and don't need permission definitions
129
- * @notice This function is virtual to allow extensions to add hook functionality
130
- * @notice For standard function calls: value=0, functionSelector=non-zero, params=encoded data
131
- * @notice For simple native token transfers: value>0, functionSelector=NATIVE_TRANSFER_SELECTOR, params=""
132
- */
133
- function _requestTransaction(
134
- address requester,
135
- address target,
136
- uint256 value,
137
- uint256 gasLimit,
138
- bytes32 operationType,
139
- bytes4 functionSelector,
140
- bytes memory params
141
- ) internal virtual returns (EngineBlox.TxRecord memory) {
142
- EngineBlox.TxRecord memory txRecord = EngineBlox.txRequest(
143
- _getSecureState(),
144
- requester,
145
- target,
146
- value,
147
- gasLimit,
148
- operationType,
149
- bytes4(msg.sig),
150
- functionSelector,
151
- params
152
- );
153
- _postActionHook(txRecord);
154
- return txRecord;
155
- }
156
-
157
- /**
158
- * @dev Centralized function to request a transaction with payment details attached from the start
159
- * @param requester The address requesting the transaction
160
- * @param target The target contract address
161
- * @param value The ETH value to send (0 for standard function calls)
162
- * @param gasLimit The gas limit for execution
163
- * @param operationType The type of operation
164
- * @param functionSelector The function selector for execution (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
165
- * @param params The encoded parameters for the function (empty for simple native token transfers)
166
- * @param paymentDetails The payment details to attach to the transaction
167
- * @return The created transaction record with payment set
168
- * @notice Validates request permissions (same as request without payment)
169
- * @notice This function is virtual to allow extensions to add hook functionality
170
- */
171
- function _requestTransactionWithPayment(
172
- address requester,
173
- address target,
174
- uint256 value,
175
- uint256 gasLimit,
176
- bytes32 operationType,
177
- bytes4 functionSelector,
178
- bytes memory params,
179
- EngineBlox.PaymentDetails memory paymentDetails
180
- ) internal virtual returns (EngineBlox.TxRecord memory) {
181
- EngineBlox.TxRecord memory txRecord = EngineBlox.txRequestWithPayment(
182
- _getSecureState(),
183
- requester,
184
- target,
185
- value,
186
- gasLimit,
187
- operationType,
188
- bytes4(msg.sig),
189
- functionSelector,
190
- params,
191
- paymentDetails
192
- );
193
- _postActionHook(txRecord);
194
- return txRecord;
195
- }
196
-
197
- /**
198
- * @dev Centralized function to approve a pending transaction after release time
199
- * @param txId The transaction ID
200
- * @return The updated transaction record
201
- * @notice Validates permissions for the calling function (approval function selector), not the execution selector
202
- * @notice Execution functions are internal-only and don't need permission definitions
203
- * @notice This function is virtual to allow extensions to add hook functionality
204
- * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
205
- */
206
- function _approveTransaction(
207
- uint256 txId
208
- ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
209
- EngineBlox.TxRecord memory txRecord = EngineBlox.txDelayedApproval(_getSecureState(), txId, bytes4(msg.sig));
210
- _postActionHook(txRecord);
211
- return txRecord;
212
- }
213
-
214
- /**
215
- * @dev Centralized function to approve a transaction using meta-transaction
216
- * @param metaTx The meta-transaction
217
- * @return The updated transaction record
218
- * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
219
- * @notice Uses EXECUTE_META_APPROVE action for permission checking
220
- * @notice This function is virtual to allow extensions to add hook functionality
221
- * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
222
- */
223
- function _approveTransactionWithMetaTx(
224
- EngineBlox.MetaTransaction memory metaTx
225
- ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
226
- EngineBlox.TxRecord memory txRecord = EngineBlox.txApprovalWithMetaTx(_getSecureState(), metaTx);
227
- _postActionHook(txRecord);
228
- return txRecord;
229
- }
230
-
231
- /**
232
- * @dev Centralized function to cancel a pending transaction
233
- * @param txId The transaction ID
234
- * @return The updated transaction record
235
- * @notice Validates permissions for the calling function (cancellation function selector), not the execution selector
236
- * @notice Execution functions are internal-only and don't need permission definitions
237
- * @notice This function is virtual to allow extensions to add hook functionality
238
- */
239
- function _cancelTransaction(
240
- uint256 txId
241
- ) internal virtual returns (EngineBlox.TxRecord memory) {
242
- EngineBlox.TxRecord memory txRecord = EngineBlox.txCancellation(_getSecureState(), txId, bytes4(msg.sig));
243
- _postActionHook(txRecord);
244
- return txRecord;
245
- }
246
-
247
- /**
248
- * @dev Centralized function to cancel a transaction using meta-transaction
249
- * @param metaTx The meta-transaction
250
- * @return The updated transaction record
251
- * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
252
- * @notice Uses EXECUTE_META_CANCEL action for permission checking
253
- * @notice This function is virtual to allow extensions to add hook functionality
254
- */
255
- function _cancelTransactionWithMetaTx(
256
- EngineBlox.MetaTransaction memory metaTx
257
- ) internal virtual returns (EngineBlox.TxRecord memory) {
258
- EngineBlox.TxRecord memory txRecord = EngineBlox.txCancellationWithMetaTx(_getSecureState(), metaTx);
259
- _postActionHook(txRecord);
260
- return txRecord;
261
- }
262
-
263
- /**
264
- * @dev Centralized function to request and approve a transaction using meta-transaction
265
- * @param metaTx The meta-transaction
266
- * @return The transaction record
267
- * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
268
- * @notice Uses EXECUTE_META_REQUEST_AND_APPROVE action for permission checking
269
- * @notice This function is virtual to allow extensions to add hook functionality
270
- * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
271
- */
272
- function _requestAndApproveTransaction(
273
- EngineBlox.MetaTransaction memory metaTx
274
- ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
275
- EngineBlox.TxRecord memory txRecord = EngineBlox.requestAndApprove(_getSecureState(), metaTx);
276
- _postActionHook(txRecord);
277
- return txRecord;
278
- }
279
-
280
- /**
281
- * @dev Post-action hook invoked after any transaction operation that produces a TxRecord.
282
- * Override in derived contracts to add centralized post-tx logic (e.g. notifications, side effects).
283
- * @param txRecord The transaction record produced by the operation
284
- */
285
- function _postActionHook(EngineBlox.TxRecord memory txRecord) internal virtual {}
286
-
287
- // ============ HOOK MANAGEMENT ============
288
-
289
- /**
290
- * @dev Sets the hook contract for a function selector (internal; no access control).
291
- * Extensions (e.g. HookManager) may expose an external setHook with owner check.
292
- * @param functionSelector The function selector
293
- * @param hook The hook contract address (must not be zero)
294
- */
295
- function _setHook(bytes4 functionSelector, address hook) internal {
296
- EngineBlox.addTargetToFunctionHooks(_getSecureState(), functionSelector, hook);
297
- _logComponentEvent(abi.encode(functionSelector, hook));
298
- }
299
-
300
- /**
301
- * @dev Clears the hook contract for a function selector (internal; no access control).
302
- * Extensions may expose an external clearHook with owner check.
303
- * @param functionSelector The function selector
304
- * @param hook The hook contract address to remove (must not be zero)
305
- */
306
- function _clearHook(bytes4 functionSelector, address hook) internal {
307
- EngineBlox.removeTargetFromFunctionHooks(_getSecureState(), functionSelector, hook);
308
- _logComponentEvent(abi.encode(functionSelector, hook));
309
- }
310
-
311
- /**
312
- * @dev Returns all configured hooks for a function selector
313
- * @param functionSelector The function selector
314
- * @return hooks Array of hook contract addresses
315
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
316
- */
317
- function getHooks(bytes4 functionSelector) public view returns (address[] memory hooks) {
318
- _validateAnyRole();
319
- return EngineBlox.getFunctionHookTargets(_getSecureState(), functionSelector);
320
- }
321
-
322
- // ============ META-TRANSACTION UTILITIES ============
323
-
324
- /**
325
- * @dev Creates meta-transaction parameters with specified values
326
- * @param handlerContract The contract that will handle the meta-transaction
327
- * @param handlerSelector The function selector for the handler
328
- * @param action The transaction action type
329
- * @param deadline The timestamp after which the meta-transaction expires
330
- * @param maxGasPrice The maximum gas price allowed for execution
331
- * @param signer The address that will sign the meta-transaction
332
- * @return The formatted meta-transaction parameters
333
- */
334
- function createMetaTxParams(
335
- address handlerContract,
336
- bytes4 handlerSelector,
337
- EngineBlox.TxAction action,
338
- uint256 deadline,
339
- uint256 maxGasPrice,
340
- address signer
341
- ) public view returns (EngineBlox.MetaTxParams memory) {
342
- return EngineBlox.createMetaTxParams(
343
- handlerContract,
344
- handlerSelector,
345
- action,
346
- deadline,
347
- maxGasPrice,
348
- signer
349
- );
350
- }
351
-
352
- /**
353
- * @dev Generates an unsigned meta-transaction for a new operation
354
- * @param requester The address requesting the operation
355
- * @param target The target contract address
356
- * @param value The ETH value to send
357
- * @param gasLimit The gas limit for execution
358
- * @param operationType The type of operation
359
- * @param executionSelector The function selector to execute (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
360
- * @param executionParams The encoded parameters for the function (empty for simple native token transfers)
361
- * @param metaTxParams The meta-transaction parameters
362
- * @return The unsigned meta-transaction
363
- */
364
- function generateUnsignedMetaTransactionForNew(
365
- address requester,
366
- address target,
367
- uint256 value,
368
- uint256 gasLimit,
369
- bytes32 operationType,
370
- bytes4 executionSelector,
371
- bytes memory executionParams,
372
- EngineBlox.MetaTxParams memory metaTxParams
373
- ) public view returns (EngineBlox.MetaTransaction memory) {
374
- EngineBlox.TxParams memory txParams = EngineBlox.TxParams({
375
- requester: requester,
376
- target: target,
377
- value: value,
378
- gasLimit: gasLimit,
379
- operationType: operationType,
380
- executionSelector: executionSelector,
381
- executionParams: executionParams
382
- });
383
-
384
- return _secureState.generateUnsignedForNewMetaTx(txParams, metaTxParams);
385
- }
386
-
387
- /**
388
- * @dev Generates an unsigned meta-transaction for an existing transaction
389
- * @param txId The ID of the existing transaction
390
- * @param metaTxParams The meta-transaction parameters
391
- * @return The unsigned meta-transaction
392
- */
393
- function generateUnsignedMetaTransactionForExisting(
394
- uint256 txId,
395
- EngineBlox.MetaTxParams memory metaTxParams
396
- ) public view returns (EngineBlox.MetaTransaction memory) {
397
- return _secureState.generateUnsignedForExistingMetaTx(txId, metaTxParams);
398
- }
399
-
400
- // ============ STATE QUERIES ============
401
-
402
- /**
403
- * @dev Gets transaction history within a specified range
404
- * @param fromTxId The starting transaction ID (inclusive)
405
- * @param toTxId The ending transaction ID (inclusive)
406
- * @return The transaction history within the specified range
407
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
408
- */
409
- function getTransactionHistory(uint256 fromTxId, uint256 toTxId) public view returns (EngineBlox.TxRecord[] memory) {
410
- _validateAnyRole();
411
-
412
- // Validate the range
413
- fromTxId = fromTxId > 0 ? fromTxId : 1;
414
- toTxId = toTxId > _secureState.txCounter ? _secureState.txCounter : toTxId;
415
-
416
- // Validate that fromTxId is less than toTxId
417
- SharedValidation.validateLessThan(fromTxId, toTxId);
418
-
419
- uint256 rangeSize = toTxId - fromTxId + 1;
420
-
421
- // For larger ranges, use paginated version
422
- SharedValidation.validateRangeSize(rangeSize, 1000);
423
-
424
- EngineBlox.TxRecord[] memory history = new EngineBlox.TxRecord[](rangeSize);
425
-
426
- for (uint256 i = 0; i < rangeSize; i++) {
427
- history[i] = _secureState.getTxRecord(fromTxId + i);
428
- }
429
-
430
- return history;
431
- }
432
-
433
- /**
434
- * @dev Gets a transaction by ID
435
- * @param txId The transaction ID
436
- * @return The transaction record
437
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
438
- */
439
- function getTransaction(uint256 txId) public view returns (EngineBlox.TxRecord memory) {
440
- _validateAnyRole();
441
- return _secureState.getTxRecord(txId);
442
- }
443
-
444
- /**
445
- * @dev Gets all pending transaction IDs
446
- * @return Array of pending transaction IDs
447
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
448
- */
449
- function getPendingTransactions() public view returns (uint256[] memory) {
450
- _validateAnyRole();
451
- return _secureState.getPendingTransactionsList();
452
- }
453
-
454
- // ============ ROLE AND PERMISSION QUERIES ============
455
-
456
- /**
457
- * @dev Gets the basic role information by its hash
458
- * @param roleHash The hash of the role to get
459
- * @return roleName The name of the role
460
- * @return roleHashReturn The hash of the role
461
- * @return maxWallets The maximum number of wallets allowed for this role
462
- * @return walletCount The current number of wallets assigned to this role
463
- * @return isProtected Whether the role is protected from removal
464
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
465
- */
466
- function getRole(bytes32 roleHash) public view returns (
467
- string memory roleName,
468
- bytes32 roleHashReturn,
469
- uint256 maxWallets,
470
- uint256 walletCount,
471
- bool isProtected
472
- ) {
473
- _validateAnyRole();
474
- EngineBlox.Role storage role = _secureState.getRole(roleHash);
475
- return (
476
- role.roleName,
477
- role.roleHash,
478
- role.maxWallets,
479
- role.walletCount,
480
- role.isProtected
481
- );
482
- }
483
-
484
- /**
485
- * @dev Returns if a wallet is authorized for a role
486
- * @param roleHash The hash of the role to check
487
- * @param wallet The wallet address to check
488
- * @return True if the wallet is authorized for the role, false otherwise
489
- */
490
- function hasRole(bytes32 roleHash, address wallet) public view returns (bool) {
491
- return _secureState.hasRole(roleHash, wallet);
492
- }
493
-
494
- /**
495
- * @dev Gets all roles assigned to a wallet
496
- * @param wallet The wallet address to get roles for
497
- * @return Array of role hashes assigned to the wallet
498
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
499
- * @notice This function uses the reverse index for efficient lookup
500
- */
501
- function getWalletRoles(address wallet) public view returns (bytes32[] memory) {
502
- _validateAnyRole();
503
- return EngineBlox.getWalletRoles(_getSecureState(), wallet);
504
- }
505
-
506
- /**
507
- * @dev Gets all authorized wallets for a role
508
- * @param roleHash The role hash to get wallets for
509
- * @return Array of authorized wallet addresses
510
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
511
- */
512
- function getWalletsInRole(bytes32 roleHash) public view returns (address[] memory) {
513
- _validateAnyRole();
514
- _validateRoleExists(roleHash);
515
- return _getAuthorizedWallets(roleHash);
516
- }
517
-
518
- /**
519
- * @dev Checks if a function schema exists
520
- * @param functionSelector The function selector to check
521
- * @return True if the function schema exists, false otherwise
522
- */
523
- function functionSchemaExists(bytes4 functionSelector) public view returns (bool) {
524
- return _secureState.functions[functionSelector].functionSelector == functionSelector;
525
- }
526
-
527
- /**
528
- * @dev Returns if an action is supported by a function
529
- * @param functionSelector The function selector to check
530
- * @param action The action to check
531
- * @return True if the action is supported by the function, false otherwise
532
- */
533
- function isActionSupportedByFunction(bytes4 functionSelector, EngineBlox.TxAction action) public view returns (bool) {
534
- return _secureState.isActionSupportedByFunction(functionSelector, action);
535
- }
536
-
537
- /**
538
- * @dev Gets function schema information
539
- * @param functionSelector The function selector to get information for
540
- * @return The full FunctionSchema struct (functionSignature, functionSelector, operationType, operationName, supportedActionsBitmap, isProtected, handlerForSelectors)
541
- */
542
- function getFunctionSchema(bytes4 functionSelector) external view returns (EngineBlox.FunctionSchema memory) {
543
- _validateAnyRole();
544
- return _secureState.getFunctionSchema(functionSelector);
545
- }
546
-
547
- /**
548
- * @dev Gets the function permissions for a specific role
549
- * @param roleHash The hash of the role to get permissions for
550
- * @return The function permissions array for the role
551
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
552
- */
553
- function getActiveRolePermissions(bytes32 roleHash) public view returns (EngineBlox.FunctionPermission[] memory) {
554
- _validateAnyRole();
555
- return _secureState.getRoleFunctionPermissions(roleHash);
556
- }
557
-
558
- /**
559
- * @dev Gets the current nonce for a specific signer
560
- * @param signer The address of the signer
561
- * @return The current nonce for the signer
562
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
563
- */
564
- function getSignerNonce(address signer) public view returns (uint256) {
565
- _validateAnyRole();
566
- return _secureState.getSignerNonce(signer);
567
- }
568
-
569
- // ============ SYSTEM STATE QUERIES ============
570
-
571
- /**
572
- * @dev Returns the supported operation types
573
- * @return The supported operation types
574
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
575
- */
576
- function getSupportedOperationTypes() public view returns (bytes32[] memory) {
577
- _validateAnyRole();
578
- return _secureState.getSupportedOperationTypesList();
579
- }
580
-
581
- /**
582
- * @dev Returns the supported roles list
583
- * @return The supported roles list
584
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
585
- */
586
- function getSupportedRoles() public view returns (bytes32[] memory) {
587
- _validateAnyRole();
588
- return _secureState.getSupportedRolesList();
589
- }
590
-
591
- /**
592
- * @dev Returns the supported functions list
593
- * @return The supported functions list
594
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
595
- */
596
- function getSupportedFunctions() public view returns (bytes4[] memory) {
597
- _validateAnyRole();
598
- return _secureState.getSupportedFunctionsList();
599
- }
600
-
601
- /**
602
- * @dev Returns the time lock period
603
- * @return The time lock period in seconds
604
- */
605
- function getTimeLockPeriodSec() public view returns (uint256) {
606
- return _secureState.timeLockPeriodSec;
607
- }
608
-
609
- /**
610
- * @dev Returns whether the contract is initialized
611
- * @return bool True if the contract is initialized, false otherwise
612
- */
613
- function initialized() public view returns (bool) {
614
- return _getInitializedVersion() != type(uint8).max && _secureState.initialized;
615
- }
616
-
617
- // ============ ROLE MANAGEMENT ============
618
-
619
- /**
620
- * @dev Centralized function to get authorized wallet at specific index
621
- * @param roleHash The role hash
622
- * @param index The wallet index
623
- * @return The authorized wallet address
624
- */
625
- function _getAuthorizedWalletAt(bytes32 roleHash, uint256 index) internal view returns (address) {
626
- return EngineBlox.getAuthorizedWalletAt(_getSecureState(), roleHash, index);
627
- }
628
-
629
- /**
630
- * @dev Centralized function to get all authorized wallets for a role
631
- * @param roleHash The role hash
632
- * @return Array of authorized wallet addresses
633
- */
634
- function _getAuthorizedWallets(bytes32 roleHash) internal view returns (address[] memory) {
635
- return EngineBlox._getAuthorizedWallets(_getSecureState(), roleHash);
636
- }
637
-
638
- /**
639
- * @dev Centralized function to create a new role
640
- * @param roleName The name of the role
641
- * @param maxWallets The maximum number of wallets allowed for this role
642
- * @param isProtected Whether the role is protected from removal
643
- * @return roleHash The hash of the created role
644
- * @notice This function is virtual to allow extensions to add hook functionality
645
- */
646
- function _createRole(
647
- string memory roleName,
648
- uint256 maxWallets,
649
- bool isProtected
650
- ) internal virtual returns (bytes32) {
651
- bytes32 roleHash = keccak256(bytes(roleName));
652
- EngineBlox.createRole(_getSecureState(), roleName, maxWallets, isProtected);
653
- return roleHash;
654
- }
655
-
656
- /**
657
- * @dev Centralized function to remove a role
658
- * @param roleHash The hash of the role to remove
659
- * @notice This function is virtual to allow extensions to add hook functionality
660
- */
661
- function _removeRole(bytes32 roleHash) internal virtual {
662
- EngineBlox.removeRole(_getSecureState(), roleHash);
663
- }
664
-
665
- /**
666
- * @dev Centralized function to assign a wallet to a role
667
- * @param roleHash The role hash
668
- * @param wallet The wallet address to assign
669
- * @notice This function is virtual to allow extensions to add hook functionality
670
- */
671
- function _assignWallet(bytes32 roleHash, address wallet) internal virtual {
672
- EngineBlox.assignWallet(_getSecureState(), roleHash, wallet);
673
- }
674
-
675
- /**
676
- * @dev Centralized function to revoke a wallet from a role
677
- * @param roleHash The role hash
678
- * @param wallet The wallet address to revoke
679
- * @notice This function is virtual to allow extensions to add hook functionality
680
- */
681
- function _revokeWallet(bytes32 roleHash, address wallet) internal virtual {
682
- EngineBlox.revokeWallet(_getSecureState(), roleHash, wallet);
683
- }
684
-
685
- /**
686
- * @dev Centralized function to update assigned wallet for a role
687
- * @param roleHash The role hash
688
- * @param newWallet The new wallet address
689
- * @param oldWallet The old wallet address
690
- * @notice This function is virtual to allow extensions to add hook functionality or additional validation
691
- */
692
- function _updateAssignedWallet(bytes32 roleHash, address newWallet, address oldWallet) internal virtual {
693
- EngineBlox.updateAssignedWallet(_getSecureState(), roleHash, newWallet, oldWallet);
694
- }
695
-
696
- /**
697
- * @dev Centralized function to update the time lock period
698
- * @param newTimeLockPeriodSec The new time lock period in seconds
699
- * @notice This function is virtual to allow extensions to add hook functionality
700
- */
701
- function _updateTimeLockPeriod(uint256 newTimeLockPeriodSec) internal virtual {
702
- uint256 oldPeriod = getTimeLockPeriodSec();
703
- EngineBlox.updateTimeLockPeriod(_getSecureState(), newTimeLockPeriodSec);
704
- _logComponentEvent(abi.encode(oldPeriod, newTimeLockPeriodSec));
705
- }
706
-
707
- // ============ FUNCTION SCHEMA MANAGEMENT ============
708
-
709
- /**
710
- * @dev Centralized function to create a function schema
711
- * @param functionSignature The function signature
712
- * @param functionSelector The function selector
713
- * @param operationName The operation name
714
- * @param supportedActionsBitmap The bitmap of supported actions
715
- * @param isProtected Whether the function schema is protected
716
- * @param handlerForSelectors Array of handler selectors
717
- * @notice This function is virtual to allow extensions to add hook functionality
718
- */
719
- function _createFunctionSchema(
720
- string memory functionSignature,
721
- bytes4 functionSelector,
722
- string memory operationName,
723
- uint16 supportedActionsBitmap,
724
- bool isProtected,
725
- bytes4[] memory handlerForSelectors
726
- ) internal virtual {
727
- EngineBlox.createFunctionSchema(
728
- _getSecureState(),
729
- functionSignature,
730
- functionSelector,
731
- operationName,
732
- supportedActionsBitmap,
733
- isProtected,
734
- handlerForSelectors
735
- );
736
- }
737
-
738
- /**
739
- * @dev Centralized function to remove a function schema
740
- * @param functionSelector The function selector to remove
741
- * @param safeRemoval Whether to perform safe removal (check for role references)
742
- * @notice This function is virtual to allow extensions to add hook functionality
743
- */
744
- function _removeFunctionSchema(bytes4 functionSelector, bool safeRemoval) internal virtual {
745
- EngineBlox.removeFunctionSchema(_getSecureState(), functionSelector, safeRemoval);
746
- }
747
-
748
- /**
749
- * @dev Centralized function to add a function permission to a role
750
- * @param roleHash The role hash
751
- * @param functionPermission The function permission to add
752
- * @notice This function is virtual to allow extensions to add hook functionality
753
- */
754
- function _addFunctionToRole(
755
- bytes32 roleHash,
756
- EngineBlox.FunctionPermission memory functionPermission
757
- ) internal virtual {
758
- EngineBlox.addFunctionToRole(_getSecureState(), roleHash, functionPermission);
759
- }
760
-
761
- /**
762
- * @dev Centralized function to remove a function permission from a role
763
- * @param roleHash The role hash
764
- * @param functionSelector The function selector to remove
765
- * @notice This function is virtual to allow extensions to add hook functionality
766
- */
767
- function _removeFunctionFromRole(bytes32 roleHash, bytes4 functionSelector) internal virtual {
768
- EngineBlox.removeFunctionFromRole(_getSecureState(), roleHash, functionSelector);
769
- }
770
-
771
- // ============ PERMISSION VALIDATION ============
772
-
773
- /**
774
- * @dev Centralized function to validate that the caller has any role
775
- */
776
- function _validateAnyRole() internal view {
777
- EngineBlox._validateAnyRole(_getSecureState());
778
- }
779
-
780
- /**
781
- * @dev Centralized function to validate that a role exists
782
- * @param roleHash The role hash to validate
783
- */
784
- function _validateRoleExists(bytes32 roleHash) internal view {
785
- EngineBlox._validateRoleExists(_getSecureState(), roleHash);
786
- }
787
-
788
- /**
789
- * @dev Centralized function to validate that the caller is the contract itself (for execution-only entry points).
790
- */
791
- function _validateExecuteBySelf() internal view {
792
- SharedValidation.validateInternalCall(address(this));
793
- }
794
-
795
- /**
796
- * @dev Centralized function to validate batch size against EngineBlox.MAX_BATCH_SIZE.
797
- * @param length The batch length to validate
798
- */
799
- function _validateBatchSize(uint256 length) internal pure {
800
- SharedValidation.validateBatchSize(length, EngineBlox.MAX_BATCH_SIZE);
801
- }
802
-
803
- // ============ MACRO SELECTORS ============
804
-
805
- /**
806
- * @dev Adds a function selector to the system macro selectors set.
807
- * Macro selectors are allowed to target address(this) for system-level operations.
808
- * @param functionSelector The function selector to add (e.g. NATIVE_TRANSFER_SELECTOR).
809
- */
810
- function _addMacroSelector(bytes4 functionSelector) internal {
811
- EngineBlox.addMacroSelector(_getSecureState(), functionSelector);
812
- }
813
-
814
- /**
815
- * @dev Returns true if the given function selector is in the system macro selectors set.
816
- * @param functionSelector The function selector to check.
817
- */
818
- function _isMacroSelector(bytes4 functionSelector) internal view returns (bool) {
819
- return EngineBlox.isMacroSelector(_getSecureState(), functionSelector);
820
- }
821
-
822
- // ============ UTILITY FUNCTIONS ============
823
-
824
- /**
825
- * @dev Centralized function to convert a bitmap to an array of actions
826
- * @param bitmap The bitmap to convert
827
- * @return Array of TxAction values
828
- */
829
- function _convertBitmapToActions(uint16 bitmap) internal pure returns (EngineBlox.TxAction[] memory) {
830
- return EngineBlox.convertBitmapToActions(bitmap);
831
- }
832
-
833
- /**
834
- * @dev Centralized function to create a bitmap from an array of actions
835
- * @param actions Array of TxAction values
836
- * @return The bitmap representation
837
- */
838
- function _createBitmapFromActions(EngineBlox.TxAction[] memory actions) internal pure returns (uint16) {
839
- return EngineBlox.createBitmapFromActions(actions);
840
- }
841
-
842
- // ============ TARGET WHITELIST MANAGEMENT ============
843
-
844
- /**
845
- * @dev Centralized function to add a target address to the whitelist for a function selector
846
- * @param functionSelector The function selector
847
- * @param target The target address to whitelist
848
- * @notice This function is virtual to allow extensions to add hook functionality
849
- */
850
- function _addTargetToFunctionWhitelist(bytes4 functionSelector, address target) internal virtual {
851
- _getSecureState().addTargetToFunctionWhitelist(functionSelector, target);
852
- }
853
-
854
- /**
855
- * @dev Centralized function to remove a target address from the whitelist for a function selector
856
- * @param functionSelector The function selector
857
- * @param target The target address to remove
858
- * @notice This function is virtual to allow extensions to add hook functionality
859
- */
860
- function _removeTargetFromFunctionWhitelist(bytes4 functionSelector, address target) internal virtual {
861
- _getSecureState().removeTargetFromFunctionWhitelist(functionSelector, target);
862
- }
863
-
864
- /**
865
- * @dev Gets all whitelisted targets for a function selector
866
- * @param functionSelector The function selector
867
- * @return Array of whitelisted target addresses
868
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
869
- */
870
- function getFunctionWhitelistTargets(bytes4 functionSelector) public view returns (address[] memory) {
871
- _validateAnyRole();
872
- return _getSecureState().getFunctionWhitelistTargets(functionSelector);
873
- }
874
-
875
- // ============ DEFINITION LOADING ============
876
-
877
- /**
878
- * @dev Loads definitions directly into the secure state
879
- * This function initializes the secure state with all predefined definitions
880
- * @param functionSchemas Array of function schema definitions
881
- * @param roleHashes Array of role hashes
882
- * @param functionPermissions Array of function permissions (parallel to roleHashes)
883
- * @param allowProtectedSchemas Whether to allow protected function schemas (default: true for factory settings)
884
- * @notice When allowProtectedSchemas is false, reverts if any function schema is protected
885
- * @notice This allows custom definitions to be restricted from creating protected schemas
886
- */
887
- function _loadDefinitions(
888
- EngineBlox.FunctionSchema[] memory functionSchemas,
889
- bytes32[] memory roleHashes,
890
- EngineBlox.FunctionPermission[] memory functionPermissions,
891
- bool allowProtectedSchemas
892
- ) internal {
893
- // Load function schemas
894
- for (uint256 i = 0; i < functionSchemas.length; i++) {
895
- // Validate protected schemas if not allowed (for custom definitions)
896
- if (!allowProtectedSchemas && functionSchemas[i].isProtected) {
897
- revert SharedValidation.CannotModifyProtected(
898
- bytes32(functionSchemas[i].functionSelector)
899
- );
900
- }
901
- EngineBlox.createFunctionSchema(
902
- _getSecureState(),
903
- functionSchemas[i].functionSignature,
904
- functionSchemas[i].functionSelector,
905
- functionSchemas[i].operationName,
906
- functionSchemas[i].supportedActionsBitmap,
907
- functionSchemas[i].isProtected,
908
- functionSchemas[i].handlerForSelectors
909
- );
910
- }
911
-
912
- // Load role permissions using parallel arrays
913
- SharedValidation.validateArrayLengthMatch(roleHashes.length, functionPermissions.length);
914
- for (uint256 i = 0; i < roleHashes.length; i++) {
915
- EngineBlox.addFunctionToRole(
916
- _getSecureState(),
917
- roleHashes[i],
918
- functionPermissions[i]
919
- );
920
- }
921
- }
922
-
923
- // ============ INTERNAL UTILITIES ============
924
-
925
- /**
926
- * @dev Internal function to get the secure state
927
- * @return secureState The secure state
928
- */
929
- function _getSecureState() internal view returns (EngineBlox.SecureOperationState storage) {
930
- return _secureState;
931
- }
932
-
933
- /**
934
- * @dev Internal function to check if an address has action permission
935
- * @param caller The address to check
936
- * @param functionSelector The function selector
937
- * @param action The action to check
938
- * @return True if the caller has permission, false otherwise
939
- */
940
- function _hasActionPermission(
941
- address caller,
942
- bytes4 functionSelector,
943
- EngineBlox.TxAction action
944
- ) internal view returns (bool) {
945
- return _secureState.hasActionPermission(caller, functionSelector, action);
946
- }
947
-
948
- /**
949
- * @dev Internal helper to validate that a caller has the BROADCASTER_ROLE
950
- * @param caller The address to validate
951
- */
952
- function _validateBroadcaster(address caller) internal view {
953
- if (!hasRole(EngineBlox.BROADCASTER_ROLE, caller)) {
954
- revert SharedValidation.NoPermission(caller);
955
- }
956
- }
957
-
958
- /**
959
- * @dev Centralized component event logging for SecureOwnable, GuardController, RuntimeRBAC.
960
- * Uses msg.sig as the event index so callers only pass encoded data.
961
- * @param data abi.encode of event parameters
962
- */
963
- function _logComponentEvent(bytes memory data) internal {
964
- emit ComponentEvent(msg.sig, data);
965
- }
966
-
967
- }
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ pragma solidity 0.8.35;
3
+
4
+ // OpenZeppelin imports
5
+ import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
6
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
7
+ import "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol";
8
+
9
+ // Contracts imports
10
+ import "../lib/EngineBlox.sol";
11
+ import "../lib/utils/SharedValidation.sol";
12
+ import "./interface/IBaseStateMachine.sol";
13
+
14
+ /**
15
+ * @title BaseStateMachine
16
+ * @dev Core state machine functionality for secure multi-phase operations
17
+ *
18
+ * This contract provides the foundational state machine capabilities that can be extended
19
+ * by security-specific contracts. It handles:
20
+ * - State initialization and management
21
+ * - Meta-transaction utilities and parameter creation
22
+ * - State queries and transaction history
23
+ * - Role-based access control queries
24
+ * - System state information
25
+ *
26
+ * The contract is designed to be inherited by security-specific contracts that implement
27
+ * their own operation types and business logic while leveraging the core state machine.
28
+ * All access to EngineBlox library functions is centralized through BaseStateMachine
29
+ * wrapper functions to ensure consistency and maintainability.
30
+ *
31
+ * Key Features:
32
+ * - State initialization with role and permission setup
33
+ * - Meta-transaction parameter creation and generation
34
+ * - Comprehensive state queries and transaction history
35
+ * - Role and permission validation utilities
36
+ * - System configuration queries
37
+ * - Event forwarding for external monitoring
38
+ */
39
+ abstract contract BaseStateMachine is Initializable, ERC165Upgradeable, ReentrancyGuardTransient {
40
+ using EngineBlox for EngineBlox.SecureOperationState;
41
+ using SharedValidation for *;
42
+
43
+ EngineBlox.SecureOperationState internal _secureState;
44
+
45
+ /**
46
+ * @dev Unified component event for SecureOwnable, GuardController, RuntimeRBAC.
47
+ * Indexers filter by functionSelector (msg.sig at emit site) and decode data (abi-encoded payload).
48
+ * @param functionSelector The function selector (msg.sig) at the emit site; used by indexers to filter
49
+ * @param data ABI-encoded payload associated with the event
50
+ */
51
+ event ComponentEvent(bytes4 indexed functionSelector, bytes data);
52
+
53
+ /**
54
+ * @notice Initializes the base state machine core
55
+ * @param initialOwner The initial owner address
56
+ * @param broadcaster The broadcaster address
57
+ * @param recovery The recovery address
58
+ * @param timeLockPeriodSec The timelock period in seconds
59
+ * @param eventForwarder The event forwarder address
60
+ * @dev Reentrancy protection inherits OpenZeppelin {ReentrancyGuardTransient} (EIP-1153 transient storage; requires Cancun+ / configured EVM such as Osaka). No initializer is required.
61
+ */
62
+ function _initializeBaseStateMachine(
63
+ address initialOwner,
64
+ address broadcaster,
65
+ address recovery,
66
+ uint256 timeLockPeriodSec,
67
+ address eventForwarder
68
+ ) internal onlyInitializing {
69
+ // Skip if already initialized (e.g. when multiple components call from Account.initialize)
70
+ if (!_secureState.initialized) {
71
+ __ERC165_init();
72
+
73
+ _secureState.initialize(initialOwner, broadcaster, recovery, timeLockPeriodSec);
74
+
75
+ _secureState.setEventForwarder(eventForwarder);
76
+ }
77
+ }
78
+
79
+ // ============ SYSTEM ROLE QUERY FUNCTIONS ============
80
+
81
+ /**
82
+ * @dev Returns the owner of the contract
83
+ * @return The owner of the contract
84
+ */
85
+ function owner() public view returns (address) {
86
+ return _getAuthorizedWalletAt(EngineBlox.OWNER_ROLE, 0);
87
+ }
88
+
89
+ /**
90
+ * @dev Returns all broadcaster addresses for the BROADCASTER_ROLE
91
+ * @return Array of broadcaster addresses
92
+ */
93
+ function getBroadcasters() public view returns (address[] memory) {
94
+ return _getAuthorizedWallets(EngineBlox.BROADCASTER_ROLE);
95
+ }
96
+
97
+ /**
98
+ * @dev Returns the recovery address
99
+ * @return The recovery address
100
+ */
101
+ function getRecovery() public view returns (address) {
102
+ return _getAuthorizedWalletAt(EngineBlox.RECOVERY_ROLE, 0);
103
+ }
104
+
105
+ // ============ INTERFACE SUPPORT ============
106
+
107
+ /**
108
+ * @dev See {IERC165-supportsInterface}.
109
+ * @notice Base implementation for ERC165 interface detection
110
+ * @notice Registers IBaseStateMachine interface ID for proper interface detection
111
+ * @notice Component contracts (SecureOwnable, RuntimeRBAC, GuardController) should override
112
+ * to add their respective interface IDs for component detection
113
+ */
114
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
115
+ return interfaceId == type(IBaseStateMachine).interfaceId || super.supportsInterface(interfaceId);
116
+ }
117
+
118
+ // ============ TRANSACTION MANAGEMENT ============
119
+
120
+ /**
121
+ * @dev Centralized function to request a transaction with common validation
122
+ * @param requester The address requesting the transaction
123
+ * @param target The target contract address
124
+ * @param value The ETH value to send (typically 0 for standard function calls; non-zero is supported for payable edge-case workflows)
125
+ * @param gasLimit The gas limit for execution
126
+ * @param operationType The type of operation
127
+ * @param functionSelector The function selector for execution (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
128
+ * @param params The encoded parameters for the function (empty for simple native token transfers)
129
+ * @return The created transaction record
130
+ * @notice Validates permissions for the calling function (request function), not the execution selector
131
+ * @notice Execution functions are internal-only and don't need permission definitions
132
+ * @notice This function is virtual to allow extensions to add hook functionality
133
+ * @notice Recommended standard calls: value=0, functionSelector=non-zero, params=encoded data
134
+ * @notice Flexible edge case: non-native selectors may intentionally forward ETH to payable targets
135
+ * @notice Native-only convenience flow: value>0, functionSelector=NATIVE_TRANSFER_SELECTOR, params=""
136
+ */
137
+ function _requestTransaction(
138
+ address requester,
139
+ address target,
140
+ uint256 value,
141
+ uint256 gasLimit,
142
+ bytes32 operationType,
143
+ bytes4 functionSelector,
144
+ bytes memory params
145
+ ) internal virtual returns (EngineBlox.TxRecord memory) {
146
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txRequest(
147
+ _getSecureState(),
148
+ requester,
149
+ target,
150
+ value,
151
+ gasLimit,
152
+ operationType,
153
+ bytes4(msg.sig),
154
+ functionSelector,
155
+ params
156
+ );
157
+ _postActionHook(txRecord);
158
+ return txRecord;
159
+ }
160
+
161
+ /**
162
+ * @dev Centralized function to request a transaction with payment details attached from the start
163
+ * @param requester The address requesting the transaction
164
+ * @param target The target contract address
165
+ * @param value The ETH value to send (typically 0 for standard function calls; non-zero is supported for payable edge-case workflows)
166
+ * @param gasLimit The gas limit for execution
167
+ * @param operationType The type of operation
168
+ * @param functionSelector The function selector for execution (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
169
+ * @param params The encoded parameters for the function (empty for simple native token transfers)
170
+ * @param paymentDetails The payment details to attach to the transaction
171
+ * @return The created transaction record with payment set
172
+ * @notice Validates request permissions (same as request without payment)
173
+ * @notice This function is virtual to allow extensions to add hook functionality
174
+ */
175
+ function _requestTransactionWithPayment(
176
+ address requester,
177
+ address target,
178
+ uint256 value,
179
+ uint256 gasLimit,
180
+ bytes32 operationType,
181
+ bytes4 functionSelector,
182
+ bytes memory params,
183
+ EngineBlox.PaymentDetails memory paymentDetails
184
+ ) internal virtual returns (EngineBlox.TxRecord memory) {
185
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txRequestWithPayment(
186
+ _getSecureState(),
187
+ requester,
188
+ target,
189
+ value,
190
+ gasLimit,
191
+ operationType,
192
+ bytes4(msg.sig),
193
+ functionSelector,
194
+ params,
195
+ paymentDetails
196
+ );
197
+ _postActionHook(txRecord);
198
+ return txRecord;
199
+ }
200
+
201
+ /**
202
+ * @dev Centralized function to approve a pending transaction after release time
203
+ * @param txId The transaction ID
204
+ * @return The updated transaction record
205
+ * @notice Validates permissions for the calling function (approval function selector), not the execution selector
206
+ * @notice Execution functions are internal-only and don't need permission definitions
207
+ * @notice This function is virtual to allow extensions to add hook functionality
208
+ * @notice Protected by ReentrancyGuardTransient to prevent reentrancy attacks
209
+ */
210
+ function _approveTransaction(
211
+ uint256 txId
212
+ ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
213
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txDelayedApproval(_getSecureState(), txId, bytes4(msg.sig));
214
+ _postActionHook(txRecord);
215
+ return txRecord;
216
+ }
217
+
218
+ /**
219
+ * @dev Centralized function to approve a transaction using meta-transaction
220
+ * @param metaTx The meta-transaction
221
+ * @return The updated transaction record
222
+ * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
223
+ * @notice Uses EXECUTE_META_APPROVE action for permission checking
224
+ * @notice This function is virtual to allow extensions to add hook functionality
225
+ * @notice Protected by ReentrancyGuardTransient to prevent reentrancy attacks
226
+ */
227
+ function _approveTransactionWithMetaTx(
228
+ EngineBlox.MetaTransaction memory metaTx
229
+ ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
230
+ _validateMetaTxHandlerBinding(metaTx);
231
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txApprovalWithMetaTx(_getSecureState(), metaTx);
232
+ _postActionHook(txRecord);
233
+ return txRecord;
234
+ }
235
+
236
+ /**
237
+ * @dev Centralized function to cancel a pending transaction
238
+ * @param txId The transaction ID
239
+ * @return The updated transaction record
240
+ * @notice Validates permissions for the calling function (cancellation function selector), not the execution selector
241
+ * @notice Execution functions are internal-only and don't need permission definitions
242
+ * @notice This function is virtual to allow extensions to add hook functionality
243
+ */
244
+ function _cancelTransaction(
245
+ uint256 txId
246
+ ) internal virtual returns (EngineBlox.TxRecord memory) {
247
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txCancellation(_getSecureState(), txId, bytes4(msg.sig));
248
+ _postActionHook(txRecord);
249
+ return txRecord;
250
+ }
251
+
252
+ /**
253
+ * @dev Centralized function to cancel a transaction using meta-transaction
254
+ * @param metaTx The meta-transaction
255
+ * @return The updated transaction record
256
+ * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
257
+ * @notice Uses EXECUTE_META_CANCEL action for permission checking
258
+ * @notice This function is virtual to allow extensions to add hook functionality
259
+ */
260
+ function _cancelTransactionWithMetaTx(
261
+ EngineBlox.MetaTransaction memory metaTx
262
+ ) internal virtual returns (EngineBlox.TxRecord memory) {
263
+ _validateMetaTxHandlerBinding(metaTx);
264
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txCancellationWithMetaTx(_getSecureState(), metaTx);
265
+ _postActionHook(txRecord);
266
+ return txRecord;
267
+ }
268
+
269
+ /**
270
+ * @dev Centralized function to request and approve a transaction using meta-transaction
271
+ * @param metaTx The meta-transaction
272
+ * @return The transaction record
273
+ * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
274
+ * @notice Uses EXECUTE_META_REQUEST_AND_APPROVE action for permission checking
275
+ * @notice This function is virtual to allow extensions to add hook functionality
276
+ * @notice Protected by ReentrancyGuardTransient to prevent reentrancy attacks
277
+ */
278
+ function _requestAndApproveTransaction(
279
+ EngineBlox.MetaTransaction memory metaTx
280
+ ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
281
+ _validateMetaTxHandlerBinding(metaTx);
282
+ EngineBlox.TxRecord memory txRecord = EngineBlox.requestAndApprove(_getSecureState(), metaTx);
283
+ _postActionHook(txRecord);
284
+ return txRecord;
285
+ }
286
+
287
+ /**
288
+ * @dev Post-action hook invoked after any transaction operation that produces a TxRecord.
289
+ * Override in derived contracts to add centralized post-tx logic (e.g. notifications, side effects).
290
+ * @param txRecord The transaction record produced by the operation
291
+ */
292
+ function _postActionHook(EngineBlox.TxRecord memory txRecord) internal virtual {}
293
+
294
+ // ============ HOOK MANAGEMENT ============
295
+
296
+ /**
297
+ * @dev Sets the hook contract for a function selector (internal; no access control).
298
+ * Extensions (e.g. HookManager) may expose an external setHook with owner check.
299
+ * @param functionSelector The function selector
300
+ * @param hook The hook contract address (must not be zero)
301
+ */
302
+ function _setHook(bytes4 functionSelector, address hook) internal {
303
+ EngineBlox.setHook(_getSecureState(), functionSelector, hook);
304
+ }
305
+
306
+ /**
307
+ * @dev Clears the hook contract for a function selector (internal; no access control).
308
+ * Extensions may expose an external clearHook with owner check.
309
+ * @param functionSelector The function selector
310
+ * @param hook The hook contract address to remove (must not be zero)
311
+ */
312
+ function _clearHook(bytes4 functionSelector, address hook) internal {
313
+ EngineBlox.clearHook(_getSecureState(), functionSelector, hook);
314
+ }
315
+
316
+ /**
317
+ * @dev Returns all configured hooks for a function selector
318
+ * @param functionSelector The function selector
319
+ * @return hooks Array of hook contract addresses
320
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
321
+ */
322
+ function getHooks(bytes4 functionSelector) public view returns (address[] memory hooks) {
323
+ _validateAnyRole();
324
+ return EngineBlox.getHooks(_getSecureState(), functionSelector);
325
+ }
326
+
327
+ // ============ META-TRANSACTION UTILITIES ============
328
+
329
+ /**
330
+ * @dev Creates meta-transaction parameters with specified values
331
+ * @param handlerContract The contract that will handle the meta-transaction
332
+ * @param handlerSelector The function selector for the handler
333
+ * @param action The transaction action type
334
+ * @param deadline The timestamp after which the meta-transaction expires
335
+ * @param maxGasPrice The maximum gas price allowed for execution
336
+ * @param signer The address that will sign the meta-transaction
337
+ * @return The formatted meta-transaction parameters
338
+ */
339
+ function createMetaTxParams(
340
+ address handlerContract,
341
+ bytes4 handlerSelector,
342
+ EngineBlox.TxAction action,
343
+ uint256 deadline,
344
+ uint256 maxGasPrice,
345
+ address signer
346
+ ) public view returns (EngineBlox.MetaTxParams memory) {
347
+ return EngineBlox.createMetaTxParams(
348
+ handlerContract,
349
+ handlerSelector,
350
+ action,
351
+ deadline,
352
+ maxGasPrice,
353
+ signer
354
+ );
355
+ }
356
+
357
+ /**
358
+ * @dev Generates an unsigned meta-transaction for a new operation
359
+ * @param requester The address requesting the operation
360
+ * @param target The target contract address
361
+ * @param value The ETH value to send
362
+ * @param gasLimit The gas limit for execution
363
+ * @param operationType The type of operation
364
+ * @param executionSelector The function selector to execute (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
365
+ * @param executionParams The encoded parameters for the function (empty for simple native token transfers)
366
+ * @param metaTxParams The meta-transaction parameters
367
+ * @return The unsigned meta-transaction
368
+ */
369
+ function generateUnsignedMetaTransactionForNew(
370
+ address requester,
371
+ address target,
372
+ uint256 value,
373
+ uint256 gasLimit,
374
+ bytes32 operationType,
375
+ bytes4 executionSelector,
376
+ bytes memory executionParams,
377
+ EngineBlox.MetaTxParams memory metaTxParams
378
+ ) public view returns (EngineBlox.MetaTransaction memory) {
379
+ EngineBlox.TxParams memory txParams = EngineBlox.TxParams({
380
+ requester: requester,
381
+ target: target,
382
+ value: value,
383
+ gasLimit: gasLimit,
384
+ operationType: operationType,
385
+ executionSelector: executionSelector,
386
+ executionParams: executionParams
387
+ });
388
+
389
+ return _secureState.generateUnsignedForNewMetaTx(txParams, metaTxParams);
390
+ }
391
+
392
+ /**
393
+ * @dev Generates an unsigned meta-transaction for an existing transaction
394
+ * @param txId The ID of the existing transaction
395
+ * @param metaTxParams The meta-transaction parameters
396
+ * @return The unsigned meta-transaction
397
+ */
398
+ function generateUnsignedMetaTransactionForExisting(
399
+ uint256 txId,
400
+ EngineBlox.MetaTxParams memory metaTxParams
401
+ ) public view returns (EngineBlox.MetaTransaction memory) {
402
+ return _secureState.generateUnsignedForExistingMetaTx(txId, metaTxParams);
403
+ }
404
+
405
+ // ============ STATE QUERIES ============
406
+
407
+ /**
408
+ * @dev Gets transaction history within a specified range
409
+ * @param fromTxId The starting transaction ID (inclusive)
410
+ * @param toTxId The ending transaction ID (inclusive)
411
+ * @return The transaction history within the specified range
412
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
413
+ * @notice Returns an empty array when **`txCounter == 0`** or when the range, after clamping to **1..txCounter**,
414
+ * does not overlap any transaction ids (e.g. `fromTxId` entirely above the current counter).
415
+ */
416
+ function getTransactionHistory(uint256 fromTxId, uint256 toTxId) public view returns (EngineBlox.TxRecord[] memory) {
417
+ _validateAnyRole();
418
+
419
+ uint256 counter = _secureState.txCounter;
420
+
421
+ // Normalize bounds to valid transaction id range [1, counter]
422
+ fromTxId = fromTxId > 0 ? fromTxId : 1;
423
+ toTxId = toTxId > counter ? counter : toTxId;
424
+
425
+ // Empty history: invalid / non-overlapping clamped range (includes txCounter == 0 → toTxId == 0).
426
+ uint256 rangeSize = fromTxId > toTxId ? 0 : toTxId - fromTxId + 1;
427
+
428
+ if (rangeSize > 0) {
429
+ SharedValidation.validateRangeSize(rangeSize, 1000);
430
+ }
431
+
432
+ EngineBlox.TxRecord[] memory history = new EngineBlox.TxRecord[](rangeSize);
433
+ for (uint256 i = 0; i < rangeSize; i++) {
434
+ history[i] = _secureState.getTxRecord(fromTxId + i);
435
+ }
436
+ return history;
437
+ }
438
+
439
+ /**
440
+ * @dev Gets a transaction by ID
441
+ * @param txId The transaction ID
442
+ * @return The transaction record
443
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
444
+ */
445
+ function getTransaction(uint256 txId) public view returns (EngineBlox.TxRecord memory) {
446
+ _validateAnyRole();
447
+ return _secureState.getTxRecord(txId);
448
+ }
449
+
450
+ /**
451
+ * @dev Gets all pending transaction IDs
452
+ * @return Array of pending transaction IDs
453
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
454
+ */
455
+ function getPendingTransactions() public view returns (uint256[] memory) {
456
+ _validateAnyRole();
457
+ return _secureState.getPendingTransactions();
458
+ }
459
+
460
+ // ============ ROLE AND PERMISSION QUERIES ============
461
+
462
+ /**
463
+ * @dev Gets the basic role information by its hash
464
+ * @param roleHash The hash of the role to get
465
+ * @return roleName The name of the role
466
+ * @return hash The hash of the role
467
+ * @return maxWallets The maximum number of wallets allowed for this role
468
+ * @return walletCount The current number of wallets assigned to this role
469
+ * @return isProtected Whether the role is protected from removal
470
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
471
+ */
472
+ function getRole(bytes32 roleHash) public view returns (
473
+ string memory roleName,
474
+ bytes32 hash,
475
+ uint256 maxWallets,
476
+ uint256 walletCount,
477
+ bool isProtected
478
+ ) {
479
+ _validateAnyRole();
480
+ EngineBlox.Role storage role = _secureState.getRole(roleHash);
481
+ return (
482
+ role.roleName,
483
+ role.roleHash,
484
+ role.maxWallets,
485
+ role.walletCount,
486
+ role.isProtected
487
+ );
488
+ }
489
+
490
+ /**
491
+ * @dev Returns if a wallet is authorized for a role
492
+ * @param roleHash The hash of the role to check
493
+ * @param wallet The wallet address to check
494
+ * @return True if the wallet is authorized for the role, false otherwise
495
+ */
496
+ function hasRole(bytes32 roleHash, address wallet) public view returns (bool) {
497
+ return _secureState.hasRole(roleHash, wallet);
498
+ }
499
+
500
+ /**
501
+ * @dev Gets all roles assigned to a wallet
502
+ * @param wallet The wallet address to get roles for
503
+ * @return Array of role hashes assigned to the wallet
504
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
505
+ * @notice This function uses the reverse index for efficient lookup
506
+ */
507
+ function getWalletRoles(address wallet) public view returns (bytes32[] memory) {
508
+ _validateAnyRole();
509
+ return EngineBlox.getWalletRoles(_getSecureState(), wallet);
510
+ }
511
+
512
+ /**
513
+ * @dev Gets all authorized wallets for a role
514
+ * @param roleHash The role hash to get wallets for
515
+ * @return Array of authorized wallet addresses
516
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
517
+ */
518
+ function getAuthorizedWallets(bytes32 roleHash) public view returns (address[] memory) {
519
+ _validateAnyRole();
520
+ _validateRoleExists(roleHash);
521
+ return _getAuthorizedWallets(roleHash);
522
+ }
523
+
524
+ /**
525
+ * @dev Gets function schema information
526
+ * @param functionSelector The function selector to get information for
527
+ * @return The full FunctionSchema struct (functionSignature, functionSelector, operationType, operationName, supportedActionsBitmap, enforceHandlerRelations, isProtected, isGrantRevocable, handlerForSelectors)
528
+ * @notice Reverts with ResourceNotFound if the schema does not exist
529
+ */
530
+ function getFunctionSchema(bytes4 functionSelector) external view returns (EngineBlox.FunctionSchema memory) {
531
+ _validateAnyRole();
532
+ return _secureState.getFunctionSchema(functionSelector);
533
+ }
534
+
535
+ /**
536
+ * @dev Gets the function permissions for a specific role
537
+ * @param roleHash The hash of the role to get permissions for
538
+ * @return The function permissions array for the role
539
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
540
+ */
541
+ function getActiveRolePermissions(bytes32 roleHash) public view returns (EngineBlox.FunctionPermission[] memory) {
542
+ _validateAnyRole();
543
+ return _secureState.getRoleFunctionPermissions(roleHash);
544
+ }
545
+
546
+ /**
547
+ * @dev Gets the current nonce for a specific signer
548
+ * @param signer The address of the signer
549
+ * @return The current nonce for the signer
550
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
551
+ */
552
+ function getSignerNonce(address signer) public view returns (uint256) {
553
+ _validateAnyRole();
554
+ return _secureState.getSignerNonce(signer);
555
+ }
556
+
557
+ // ============ SYSTEM STATE QUERIES ============
558
+
559
+ /**
560
+ * @dev Returns the supported operation types
561
+ * @return The supported operation types
562
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
563
+ */
564
+ function getSupportedOperationTypes() public view returns (bytes32[] memory) {
565
+ _validateAnyRole();
566
+ return _secureState.getSupportedOperationTypes();
567
+ }
568
+
569
+ /**
570
+ * @dev Returns the supported roles list
571
+ * @return The supported roles list
572
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
573
+ */
574
+ function getSupportedRoles() public view returns (bytes32[] memory) {
575
+ _validateAnyRole();
576
+ return _secureState.getSupportedRoles();
577
+ }
578
+
579
+ /**
580
+ * @dev Returns the supported functions list
581
+ * @return The supported functions list
582
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
583
+ */
584
+ function getSupportedFunctions() public view returns (bytes4[] memory) {
585
+ _validateAnyRole();
586
+ return _secureState.getSupportedFunctions();
587
+ }
588
+
589
+ /**
590
+ * @dev Returns the time lock period
591
+ * @return The time lock period in seconds
592
+ */
593
+ function getTimeLockPeriodSec() public view returns (uint256) {
594
+ return _secureState.timeLockPeriodSec;
595
+ }
596
+
597
+ /**
598
+ * @dev Returns whether the contract is initialized
599
+ * @return bool True if the contract is initialized, false otherwise
600
+ */
601
+ function initialized() public view returns (bool) {
602
+ return _getInitializedVersion() != type(uint8).max && _secureState.initialized;
603
+ }
604
+
605
+ // ============ ROLE MANAGEMENT ============
606
+
607
+ /**
608
+ * @dev Centralized function to get authorized wallet at specific index
609
+ * @param roleHash The role hash
610
+ * @param index The wallet index
611
+ * @return The authorized wallet address
612
+ */
613
+ function _getAuthorizedWalletAt(bytes32 roleHash, uint256 index) internal view returns (address) {
614
+ return EngineBlox.getAuthorizedWalletAt(_getSecureState(), roleHash, index);
615
+ }
616
+
617
+ /**
618
+ * @dev Centralized function to get all authorized wallets for a role
619
+ * @param roleHash The role hash
620
+ * @return Array of authorized wallet addresses
621
+ */
622
+ function _getAuthorizedWallets(bytes32 roleHash) internal view returns (address[] memory) {
623
+ return EngineBlox.getAuthorizedWallets(_getSecureState(), roleHash);
624
+ }
625
+
626
+ /**
627
+ * @dev Centralized function to create a new role
628
+ * @param roleName The name of the role
629
+ * @param maxWallets The maximum number of wallets allowed for this role
630
+ * @param isProtected Whether the role is protected from removal
631
+ * @return roleHash The hash of the created role
632
+ * @notice This function is virtual to allow extensions to add hook functionality
633
+ */
634
+ function _createRole(
635
+ string memory roleName,
636
+ uint256 maxWallets,
637
+ bool isProtected
638
+ ) internal virtual returns (bytes32) {
639
+ bytes32 roleHash = keccak256(bytes(roleName));
640
+ EngineBlox.createRole(_getSecureState(), roleName, maxWallets, isProtected);
641
+ return roleHash;
642
+ }
643
+
644
+ /**
645
+ * @dev Centralized function to remove a role
646
+ * @param roleHash The hash of the role to remove
647
+ * @notice This function is virtual to allow extensions to add hook functionality
648
+ */
649
+ function _removeRole(bytes32 roleHash) internal virtual {
650
+ EngineBlox.removeRole(_getSecureState(), roleHash);
651
+ }
652
+
653
+ /**
654
+ * @dev Centralized function to assign a wallet to a role
655
+ * @param roleHash The role hash
656
+ * @param wallet The wallet address to assign
657
+ * @notice This function is virtual to allow extensions to add hook functionality
658
+ */
659
+ function _assignWallet(bytes32 roleHash, address wallet) internal virtual {
660
+ EngineBlox.assignWallet(_getSecureState(), roleHash, wallet);
661
+ }
662
+
663
+ /**
664
+ * @dev Centralized function to revoke a wallet from a role
665
+ * @param roleHash The role hash
666
+ * @param wallet The wallet address to revoke
667
+ * @notice This function is virtual to allow extensions to add hook functionality
668
+ */
669
+ function _revokeWallet(bytes32 roleHash, address wallet) internal virtual {
670
+ EngineBlox.revokeWallet(_getSecureState(), roleHash, wallet);
671
+ }
672
+
673
+ /**
674
+ * @dev Centralized function to update wallet for a role (replaces oldWallet with newWallet).
675
+ * @param roleHash The role hash
676
+ * @param newWallet The new wallet address
677
+ * @param oldWallet The old wallet address
678
+ * @notice This function is virtual to allow extensions to add hook functionality or additional validation
679
+ */
680
+ function _updateWallet(bytes32 roleHash, address newWallet, address oldWallet) internal virtual {
681
+ EngineBlox.updateWallet(_getSecureState(), roleHash, newWallet, oldWallet);
682
+ }
683
+
684
+ /**
685
+ * @dev Centralized function to update the time lock period
686
+ * @param newTimeLockPeriodSec The new time lock period in seconds
687
+ * @notice This function is virtual to allow extensions to add hook functionality
688
+ */
689
+ function _updateTimeLockPeriod(uint256 newTimeLockPeriodSec) internal virtual {
690
+ uint256 oldPeriod = getTimeLockPeriodSec();
691
+ EngineBlox.updateTimeLockPeriod(_getSecureState(), newTimeLockPeriodSec);
692
+ _logComponentEvent(abi.encode(oldPeriod, newTimeLockPeriodSec));
693
+ }
694
+
695
+ // ============ FUNCTION SCHEMA MANAGEMENT ============
696
+
697
+ /**
698
+ * @dev Centralized function to register a function schema
699
+ * @param functionSignature The function signature
700
+ * @param functionSelector The function selector
701
+ * @param operationName The operation name
702
+ * @param supportedActionsBitmap The bitmap of supported actions
703
+ * @param enforceHandlerRelations Whether to enforce strict handler/schema alignment
704
+ * @param isProtected Whether the function schema is protected from unregister
705
+ * @param isGrantRevocable Whether role grants for this schema may be removed via `removeFunctionFromRole` (any role, including protected roles, when true)
706
+ * @param handlerForSelectors Array of handler selectors
707
+ * @notice This function is virtual to allow extensions to add hook functionality
708
+ */
709
+ function _registerFunction(
710
+ string memory functionSignature,
711
+ bytes4 functionSelector,
712
+ string memory operationName,
713
+ uint16 supportedActionsBitmap,
714
+ bool enforceHandlerRelations,
715
+ bool isProtected,
716
+ bool isGrantRevocable,
717
+ bytes4[] memory handlerForSelectors
718
+ ) internal virtual {
719
+ EngineBlox.registerFunction(
720
+ _getSecureState(),
721
+ functionSignature,
722
+ functionSelector,
723
+ operationName,
724
+ supportedActionsBitmap,
725
+ enforceHandlerRelations,
726
+ isProtected,
727
+ isGrantRevocable,
728
+ handlerForSelectors
729
+ );
730
+ }
731
+
732
+ /**
733
+ * @dev Centralized function to unregister a function schema
734
+ * @param functionSelector The function selector to unregister
735
+ * @param safeRemoval Whether to perform safe removal (check for role references)
736
+ * @notice This function is virtual to allow extensions to add hook functionality
737
+ */
738
+ function _unregisterFunction(bytes4 functionSelector, bool safeRemoval) internal virtual {
739
+ EngineBlox.unregisterFunction(_getSecureState(), functionSelector, safeRemoval);
740
+ }
741
+
742
+ /**
743
+ * @dev Centralized function to add a function permission to a role
744
+ * @param roleHash The role hash
745
+ * @param functionPermission The function permission to add
746
+ * @notice This function is virtual to allow extensions to add hook functionality
747
+ */
748
+ function _addFunctionToRole(
749
+ bytes32 roleHash,
750
+ EngineBlox.FunctionPermission memory functionPermission
751
+ ) internal virtual {
752
+ EngineBlox.addFunctionToRole(_getSecureState(), roleHash, functionPermission);
753
+ }
754
+
755
+ /**
756
+ * @dev Centralized function to remove a function permission from a role
757
+ * @param roleHash The role hash
758
+ * @param functionSelector The function selector to remove
759
+ * @notice This function is virtual to allow extensions to add hook functionality
760
+ */
761
+ function _removeFunctionFromRole(bytes32 roleHash, bytes4 functionSelector) internal virtual {
762
+ EngineBlox.removeFunctionFromRole(_getSecureState(), roleHash, functionSelector);
763
+ }
764
+
765
+ // ============ PERMISSION VALIDATION ============
766
+
767
+ /**
768
+ * @dev Binds signed `MetaTxParams` to this wrapper's entrypoint (`msg.sig`) and verifying contract.
769
+ * Must run in `BaseStateMachine` context, not inside linked `EngineBlox` library code (delegatecall
770
+ * would make `msg.sig` refer to the library function, not the outer wrapper).
771
+ * @param metaTx The meta-transaction whose `params` are validated against `msg.sig` and `address(this)`.
772
+ */
773
+ function _validateMetaTxHandlerBinding(EngineBlox.MetaTransaction memory metaTx) internal view {
774
+ SharedValidation.validateMetaTxHandlerSelectorBinding(
775
+ metaTx.params.handlerSelector,
776
+ bytes4(msg.sig)
777
+ );
778
+ SharedValidation.validateMetaTxHandlerContractBinding(metaTx.params.handlerContract);
779
+ }
780
+
781
+ /**
782
+ * @dev Centralized function to validate that the caller has any role
783
+ */
784
+ function _validateAnyRole() internal view {
785
+ EngineBlox._validateAnyRole(_getSecureState());
786
+ }
787
+
788
+ /**
789
+ * @dev Centralized function to validate that a role exists
790
+ * @param roleHash The role hash to validate
791
+ */
792
+ function _validateRoleExists(bytes32 roleHash) internal view {
793
+ EngineBlox._validateRoleExists(_getSecureState(), roleHash);
794
+ }
795
+
796
+ /**
797
+ * @dev Centralized function to validate that the caller is the contract itself (for execution-only entry points).
798
+ */
799
+ function _validateExecuteBySelf() internal view {
800
+ SharedValidation.validateInternalCall(address(this));
801
+ }
802
+
803
+ /**
804
+ * @dev Centralized function to validate batch size against EngineBlox.MAX_BATCH_SIZE.
805
+ * @param length The batch length to validate
806
+ */
807
+ function _validateBatchSize(uint256 length) internal pure {
808
+ SharedValidation.validateBatchSize(length, EngineBlox.MAX_BATCH_SIZE);
809
+ }
810
+
811
+ // ============ MACRO SELECTORS ============
812
+
813
+ /**
814
+ * @dev Adds a function selector to the system macro selectors set.
815
+ * Macro selectors are allowed to target address(this) for system-level operations.
816
+ * @param functionSelector The function selector to add (e.g. NATIVE_TRANSFER_SELECTOR).
817
+ */
818
+ function _addMacroSelector(bytes4 functionSelector) internal {
819
+ EngineBlox.addMacroSelector(_getSecureState(), functionSelector);
820
+ }
821
+
822
+ /**
823
+ * @dev Returns true if the given function selector is in the system macro selectors set.
824
+ * @param functionSelector The function selector to check.
825
+ */
826
+ function _isMacroSelector(bytes4 functionSelector) internal view returns (bool) {
827
+ return EngineBlox.isMacroSelector(_getSecureState(), functionSelector);
828
+ }
829
+
830
+ // ============ UTILITY FUNCTIONS ============
831
+
832
+ /**
833
+ * @dev Centralized function to convert a bitmap to an array of actions
834
+ * @param bitmap The bitmap to convert
835
+ * @return Array of TxAction values
836
+ */
837
+ function _convertBitmapToActions(uint16 bitmap) internal pure returns (EngineBlox.TxAction[] memory) {
838
+ return EngineBlox.convertBitmapToActions(bitmap);
839
+ }
840
+
841
+ /**
842
+ * @dev Centralized function to create a bitmap from an array of actions
843
+ * @param actions Array of TxAction values
844
+ * @return The bitmap representation
845
+ */
846
+ function _createBitmapFromActions(EngineBlox.TxAction[] memory actions) internal pure returns (uint16) {
847
+ return EngineBlox.createBitmapFromActions(actions);
848
+ }
849
+
850
+ // ============ TARGET WHITELIST MANAGEMENT ============
851
+
852
+ /**
853
+ * @dev Centralized function to add a target address to the whitelist for a function selector
854
+ * @param functionSelector The function selector
855
+ * @param target The target address to whitelist
856
+ * @notice This function is virtual to allow extensions to add hook functionality
857
+ */
858
+ function _addTargetToWhitelist(bytes4 functionSelector, address target) internal virtual {
859
+ _getSecureState().addTargetToWhitelist(functionSelector, target);
860
+ }
861
+
862
+ /**
863
+ * @dev Centralized function to remove a target address from the whitelist for a function selector
864
+ * @param functionSelector The function selector
865
+ * @param target The target address to remove
866
+ * @notice This function is virtual to allow extensions to add hook functionality
867
+ */
868
+ function _removeTargetFromWhitelist(bytes4 functionSelector, address target) internal virtual {
869
+ _getSecureState().removeTargetFromWhitelist(functionSelector, target);
870
+ }
871
+
872
+ /**
873
+ * @dev Gets all whitelisted targets for a function selector
874
+ * @param functionSelector The function selector
875
+ * @return Array of whitelisted target addresses
876
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
877
+ */
878
+ function getFunctionWhitelistTargets(bytes4 functionSelector) public view returns (address[] memory) {
879
+ _validateAnyRole();
880
+ return _getSecureState().getFunctionWhitelistTargets(functionSelector);
881
+ }
882
+
883
+ // ============ DEFINITION LOADING ============
884
+
885
+ /**
886
+ * @dev Loads definitions directly into the secure state
887
+ * This function initializes the secure state with all predefined definitions
888
+ * @param functionSchemas Array of function schema definitions
889
+ * @param roleHashes Array of role hashes
890
+ * @param functionPermissions Array of function permissions (parallel to roleHashes)
891
+ * @param requireProtected When true, all function schemas must be protected; reverts if any is not
892
+ * @notice When requireProtected is true, every function schema must have isProtected == true
893
+ */
894
+ function _loadDefinitions(
895
+ EngineBlox.FunctionSchema[] memory functionSchemas,
896
+ bytes32[] memory roleHashes,
897
+ EngineBlox.FunctionPermission[] memory functionPermissions,
898
+ bool requireProtected
899
+ ) internal {
900
+ // Load function schemas
901
+ for (uint256 i = 0; i < functionSchemas.length; i++) {
902
+ // When enforcing, require every schema to be protected
903
+ if (requireProtected && !functionSchemas[i].isProtected) {
904
+ revert SharedValidation.ContractFunctionMustBeProtected(
905
+ functionSchemas[i].functionSelector
906
+ );
907
+ }
908
+ _registerFunction(
909
+ functionSchemas[i].functionSignature,
910
+ functionSchemas[i].functionSelector,
911
+ functionSchemas[i].operationName,
912
+ functionSchemas[i].supportedActionsBitmap,
913
+ functionSchemas[i].enforceHandlerRelations,
914
+ functionSchemas[i].isProtected,
915
+ functionSchemas[i].isGrantRevocable,
916
+ functionSchemas[i].handlerForSelectors
917
+ );
918
+ }
919
+
920
+ // Load role permissions using parallel arrays
921
+ SharedValidation.validateArrayLengthMatch(roleHashes.length, functionPermissions.length);
922
+ for (uint256 i = 0; i < roleHashes.length; i++) {
923
+ _addFunctionToRole(roleHashes[i], functionPermissions[i]);
924
+ }
925
+ }
926
+
927
+ // ============ INTERNAL UTILITIES ============
928
+
929
+ /**
930
+ * @dev Internal function to get the secure state
931
+ * @return secureState The secure state
932
+ */
933
+ function _getSecureState() internal view returns (EngineBlox.SecureOperationState storage) {
934
+ return _secureState;
935
+ }
936
+
937
+ /**
938
+ * @dev Internal function to check if an address has action permission
939
+ * @param caller The address to check
940
+ * @param functionSelector The function selector
941
+ * @param action The action to check
942
+ * @return True if the caller has permission, false otherwise
943
+ */
944
+ function _hasActionPermission(
945
+ address caller,
946
+ bytes4 functionSelector,
947
+ EngineBlox.TxAction action
948
+ ) internal view returns (bool) {
949
+ return _secureState.hasActionPermission(caller, functionSelector, action);
950
+ }
951
+
952
+ /**
953
+ * @dev Internal helper to validate that a caller has the BROADCASTER_ROLE
954
+ * @param caller The address to validate
955
+ */
956
+ function _validateBroadcaster(address caller) internal view {
957
+ if (!hasRole(EngineBlox.BROADCASTER_ROLE, caller)) {
958
+ revert SharedValidation.NoPermission(caller);
959
+ }
960
+ }
961
+
962
+ /**
963
+ * @dev Centralized component event logging for SecureOwnable, GuardController, RuntimeRBAC.
964
+ * Uses msg.sig as the event index so callers only pass encoded data.
965
+ * @param data abi.encode of event parameters
966
+ */
967
+ function _logComponentEvent(bytes memory data) internal {
968
+ emit ComponentEvent(msg.sig, data);
969
+ }
970
+
971
+ }