@bloxchain/contracts 1.0.0-alpha.13 → 1.0.0-alpha.15

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.
@@ -1,967 +1,943 @@
1
- // SPDX-License-Identifier: MPL-2.0
2
- pragma solidity 0.8.34;
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
- // Skip if already initialized (e.g. when multiple components call from Account.initialize)
69
- if (!_secureState.initialized) {
70
- __ERC165_init();
71
- __ReentrancyGuard_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 (0 for standard function calls)
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 For standard function calls: value=0, functionSelector=non-zero, params=encoded data
134
- * @notice For simple native token transfers: value>0, functionSelector=NATIVE_TRANSFER_SELECTOR, params=""
135
- */
136
- function _requestTransaction(
137
- address requester,
138
- address target,
139
- uint256 value,
140
- uint256 gasLimit,
141
- bytes32 operationType,
142
- bytes4 functionSelector,
143
- bytes memory params
144
- ) internal virtual returns (EngineBlox.TxRecord memory) {
145
- EngineBlox.TxRecord memory txRecord = EngineBlox.txRequest(
146
- _getSecureState(),
147
- requester,
148
- target,
149
- value,
150
- gasLimit,
151
- operationType,
152
- bytes4(msg.sig),
153
- functionSelector,
154
- params
155
- );
156
- _postActionHook(txRecord);
157
- return txRecord;
158
- }
159
-
160
- /**
161
- * @dev Centralized function to request a transaction with payment details attached from the start
162
- * @param requester The address requesting the transaction
163
- * @param target The target contract address
164
- * @param value The ETH value to send (0 for standard function calls)
165
- * @param gasLimit The gas limit for execution
166
- * @param operationType The type of operation
167
- * @param functionSelector The function selector for execution (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
168
- * @param params The encoded parameters for the function (empty for simple native token transfers)
169
- * @param paymentDetails The payment details to attach to the transaction
170
- * @return The created transaction record with payment set
171
- * @notice Validates request permissions (same as request without payment)
172
- * @notice This function is virtual to allow extensions to add hook functionality
173
- */
174
- function _requestTransactionWithPayment(
175
- address requester,
176
- address target,
177
- uint256 value,
178
- uint256 gasLimit,
179
- bytes32 operationType,
180
- bytes4 functionSelector,
181
- bytes memory params,
182
- EngineBlox.PaymentDetails memory paymentDetails
183
- ) internal virtual returns (EngineBlox.TxRecord memory) {
184
- EngineBlox.TxRecord memory txRecord = EngineBlox.txRequestWithPayment(
185
- _getSecureState(),
186
- requester,
187
- target,
188
- value,
189
- gasLimit,
190
- operationType,
191
- bytes4(msg.sig),
192
- functionSelector,
193
- params,
194
- paymentDetails
195
- );
196
- _postActionHook(txRecord);
197
- return txRecord;
198
- }
199
-
200
- /**
201
- * @dev Centralized function to approve a pending transaction after release time
202
- * @param txId The transaction ID
203
- * @return The updated transaction record
204
- * @notice Validates permissions for the calling function (approval function selector), not the execution selector
205
- * @notice Execution functions are internal-only and don't need permission definitions
206
- * @notice This function is virtual to allow extensions to add hook functionality
207
- * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
208
- */
209
- function _approveTransaction(
210
- uint256 txId
211
- ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
212
- EngineBlox.TxRecord memory txRecord = EngineBlox.txDelayedApproval(_getSecureState(), txId, bytes4(msg.sig));
213
- _postActionHook(txRecord);
214
- return txRecord;
215
- }
216
-
217
- /**
218
- * @dev Centralized function to approve a transaction using meta-transaction
219
- * @param metaTx The meta-transaction
220
- * @return The updated transaction record
221
- * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
222
- * @notice Uses EXECUTE_META_APPROVE action for permission checking
223
- * @notice This function is virtual to allow extensions to add hook functionality
224
- * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
225
- */
226
- function _approveTransactionWithMetaTx(
227
- EngineBlox.MetaTransaction memory metaTx
228
- ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
229
- EngineBlox.TxRecord memory txRecord = EngineBlox.txApprovalWithMetaTx(_getSecureState(), metaTx);
230
- _postActionHook(txRecord);
231
- return txRecord;
232
- }
233
-
234
- /**
235
- * @dev Centralized function to cancel a pending transaction
236
- * @param txId The transaction ID
237
- * @return The updated transaction record
238
- * @notice Validates permissions for the calling function (cancellation function selector), not the execution selector
239
- * @notice Execution functions are internal-only and don't need permission definitions
240
- * @notice This function is virtual to allow extensions to add hook functionality
241
- */
242
- function _cancelTransaction(
243
- uint256 txId
244
- ) internal virtual returns (EngineBlox.TxRecord memory) {
245
- EngineBlox.TxRecord memory txRecord = EngineBlox.txCancellation(_getSecureState(), txId, bytes4(msg.sig));
246
- _postActionHook(txRecord);
247
- return txRecord;
248
- }
249
-
250
- /**
251
- * @dev Centralized function to cancel a transaction using meta-transaction
252
- * @param metaTx The meta-transaction
253
- * @return The updated transaction record
254
- * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
255
- * @notice Uses EXECUTE_META_CANCEL action for permission checking
256
- * @notice This function is virtual to allow extensions to add hook functionality
257
- */
258
- function _cancelTransactionWithMetaTx(
259
- EngineBlox.MetaTransaction memory metaTx
260
- ) internal virtual returns (EngineBlox.TxRecord memory) {
261
- EngineBlox.TxRecord memory txRecord = EngineBlox.txCancellationWithMetaTx(_getSecureState(), metaTx);
262
- _postActionHook(txRecord);
263
- return txRecord;
264
- }
265
-
266
- /**
267
- * @dev Centralized function to request and approve a transaction using meta-transaction
268
- * @param metaTx The meta-transaction
269
- * @return The transaction record
270
- * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
271
- * @notice Uses EXECUTE_META_REQUEST_AND_APPROVE action for permission checking
272
- * @notice This function is virtual to allow extensions to add hook functionality
273
- * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
274
- */
275
- function _requestAndApproveTransaction(
276
- EngineBlox.MetaTransaction memory metaTx
277
- ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
278
- EngineBlox.TxRecord memory txRecord = EngineBlox.requestAndApprove(_getSecureState(), metaTx);
279
- _postActionHook(txRecord);
280
- return txRecord;
281
- }
282
-
283
- /**
284
- * @dev Post-action hook invoked after any transaction operation that produces a TxRecord.
285
- * Override in derived contracts to add centralized post-tx logic (e.g. notifications, side effects).
286
- * @param txRecord The transaction record produced by the operation
287
- */
288
- function _postActionHook(EngineBlox.TxRecord memory txRecord) internal virtual {}
289
-
290
- // ============ HOOK MANAGEMENT ============
291
-
292
- /**
293
- * @dev Sets the hook contract for a function selector (internal; no access control).
294
- * Extensions (e.g. HookManager) may expose an external setHook with owner check.
295
- * @param functionSelector The function selector
296
- * @param hook The hook contract address (must not be zero)
297
- */
298
- function _setHook(bytes4 functionSelector, address hook) internal {
299
- EngineBlox.addTargetToFunctionHooks(_getSecureState(), functionSelector, hook);
300
- }
301
-
302
- /**
303
- * @dev Clears the hook contract for a function selector (internal; no access control).
304
- * Extensions may expose an external clearHook with owner check.
305
- * @param functionSelector The function selector
306
- * @param hook The hook contract address to remove (must not be zero)
307
- */
308
- function _clearHook(bytes4 functionSelector, address hook) internal {
309
- EngineBlox.removeTargetFromFunctionHooks(_getSecureState(), functionSelector, hook);
310
- }
311
-
312
- /**
313
- * @dev Returns all configured hooks for a function selector
314
- * @param functionSelector The function selector
315
- * @return hooks Array of hook contract addresses
316
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
317
- */
318
- function getHooks(bytes4 functionSelector) public view returns (address[] memory hooks) {
319
- _validateAnyRole();
320
- return EngineBlox.getFunctionHookTargets(_getSecureState(), functionSelector);
321
- }
322
-
323
- // ============ META-TRANSACTION UTILITIES ============
324
-
325
- /**
326
- * @dev Creates meta-transaction parameters with specified values
327
- * @param handlerContract The contract that will handle the meta-transaction
328
- * @param handlerSelector The function selector for the handler
329
- * @param action The transaction action type
330
- * @param deadline The timestamp after which the meta-transaction expires
331
- * @param maxGasPrice The maximum gas price allowed for execution
332
- * @param signer The address that will sign the meta-transaction
333
- * @return The formatted meta-transaction parameters
334
- */
335
- function createMetaTxParams(
336
- address handlerContract,
337
- bytes4 handlerSelector,
338
- EngineBlox.TxAction action,
339
- uint256 deadline,
340
- uint256 maxGasPrice,
341
- address signer
342
- ) public view returns (EngineBlox.MetaTxParams memory) {
343
- return EngineBlox.createMetaTxParams(
344
- handlerContract,
345
- handlerSelector,
346
- action,
347
- deadline,
348
- maxGasPrice,
349
- signer
350
- );
351
- }
352
-
353
- /**
354
- * @dev Generates an unsigned meta-transaction for a new operation
355
- * @param requester The address requesting the operation
356
- * @param target The target contract address
357
- * @param value The ETH value to send
358
- * @param gasLimit The gas limit for execution
359
- * @param operationType The type of operation
360
- * @param executionSelector The function selector to execute (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
361
- * @param executionParams The encoded parameters for the function (empty for simple native token transfers)
362
- * @param metaTxParams The meta-transaction parameters
363
- * @return The unsigned meta-transaction
364
- */
365
- function generateUnsignedMetaTransactionForNew(
366
- address requester,
367
- address target,
368
- uint256 value,
369
- uint256 gasLimit,
370
- bytes32 operationType,
371
- bytes4 executionSelector,
372
- bytes memory executionParams,
373
- EngineBlox.MetaTxParams memory metaTxParams
374
- ) public view returns (EngineBlox.MetaTransaction memory) {
375
- EngineBlox.TxParams memory txParams = EngineBlox.TxParams({
376
- requester: requester,
377
- target: target,
378
- value: value,
379
- gasLimit: gasLimit,
380
- operationType: operationType,
381
- executionSelector: executionSelector,
382
- executionParams: executionParams
383
- });
384
-
385
- return _secureState.generateUnsignedForNewMetaTx(txParams, metaTxParams);
386
- }
387
-
388
- /**
389
- * @dev Generates an unsigned meta-transaction for an existing transaction
390
- * @param txId The ID of the existing transaction
391
- * @param metaTxParams The meta-transaction parameters
392
- * @return The unsigned meta-transaction
393
- */
394
- function generateUnsignedMetaTransactionForExisting(
395
- uint256 txId,
396
- EngineBlox.MetaTxParams memory metaTxParams
397
- ) public view returns (EngineBlox.MetaTransaction memory) {
398
- return _secureState.generateUnsignedForExistingMetaTx(txId, metaTxParams);
399
- }
400
-
401
- // ============ STATE QUERIES ============
402
-
403
- /**
404
- * @dev Gets transaction history within a specified range
405
- * @param fromTxId The starting transaction ID (inclusive)
406
- * @param toTxId The ending transaction ID (inclusive)
407
- * @return The transaction history within the specified range
408
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
409
- */
410
- function getTransactionHistory(uint256 fromTxId, uint256 toTxId) public view returns (EngineBlox.TxRecord[] memory) {
411
- _validateAnyRole();
412
-
413
- // Validate the range
414
- fromTxId = fromTxId > 0 ? fromTxId : 1;
415
- toTxId = toTxId > _secureState.txCounter ? _secureState.txCounter : toTxId;
416
-
417
- // Validate that fromTxId is less than toTxId
418
- SharedValidation.validateLessThan(fromTxId, toTxId);
419
-
420
- uint256 rangeSize = toTxId - fromTxId + 1;
421
-
422
- // For larger ranges, use paginated version
423
- SharedValidation.validateRangeSize(rangeSize, 1000);
424
-
425
- EngineBlox.TxRecord[] memory history = new EngineBlox.TxRecord[](rangeSize);
426
-
427
- for (uint256 i = 0; i < rangeSize; i++) {
428
- history[i] = _secureState.getTxRecord(fromTxId + i);
429
- }
430
-
431
- return history;
432
- }
433
-
434
- /**
435
- * @dev Gets a transaction by ID
436
- * @param txId The transaction ID
437
- * @return The transaction record
438
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
439
- */
440
- function getTransaction(uint256 txId) public view returns (EngineBlox.TxRecord memory) {
441
- _validateAnyRole();
442
- return _secureState.getTxRecord(txId);
443
- }
444
-
445
- /**
446
- * @dev Gets all pending transaction IDs
447
- * @return Array of pending transaction IDs
448
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
449
- */
450
- function getPendingTransactions() public view returns (uint256[] memory) {
451
- _validateAnyRole();
452
- return _secureState.getPendingTransactionsList();
453
- }
454
-
455
- // ============ ROLE AND PERMISSION QUERIES ============
456
-
457
- /**
458
- * @dev Gets the basic role information by its hash
459
- * @param roleHash The hash of the role to get
460
- * @return roleName The name of the role
461
- * @return roleHashReturn The hash of the role
462
- * @return maxWallets The maximum number of wallets allowed for this role
463
- * @return walletCount The current number of wallets assigned to this role
464
- * @return isProtected Whether the role is protected from removal
465
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
466
- */
467
- function getRole(bytes32 roleHash) public view returns (
468
- string memory roleName,
469
- bytes32 roleHashReturn,
470
- uint256 maxWallets,
471
- uint256 walletCount,
472
- bool isProtected
473
- ) {
474
- _validateAnyRole();
475
- EngineBlox.Role storage role = _secureState.getRole(roleHash);
476
- return (
477
- role.roleName,
478
- role.roleHash,
479
- role.maxWallets,
480
- role.walletCount,
481
- role.isProtected
482
- );
483
- }
484
-
485
- /**
486
- * @dev Returns if a wallet is authorized for a role
487
- * @param roleHash The hash of the role to check
488
- * @param wallet The wallet address to check
489
- * @return True if the wallet is authorized for the role, false otherwise
490
- */
491
- function hasRole(bytes32 roleHash, address wallet) public view returns (bool) {
492
- return _secureState.hasRole(roleHash, wallet);
493
- }
494
-
495
- /**
496
- * @dev Gets all roles assigned to a wallet
497
- * @param wallet The wallet address to get roles for
498
- * @return Array of role hashes assigned to the wallet
499
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
500
- * @notice This function uses the reverse index for efficient lookup
501
- */
502
- function getWalletRoles(address wallet) public view returns (bytes32[] memory) {
503
- _validateAnyRole();
504
- return EngineBlox.getWalletRoles(_getSecureState(), wallet);
505
- }
506
-
507
- /**
508
- * @dev Gets all authorized wallets for a role
509
- * @param roleHash The role hash to get wallets for
510
- * @return Array of authorized wallet addresses
511
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
512
- */
513
- function getWalletsInRole(bytes32 roleHash) public view returns (address[] memory) {
514
- _validateAnyRole();
515
- _validateRoleExists(roleHash);
516
- return _getAuthorizedWallets(roleHash);
517
- }
518
-
519
- /**
520
- * @dev Checks if a function schema exists
521
- * @param functionSelector The function selector to check
522
- * @return True if the function schema exists, false otherwise
523
- */
524
- function functionSchemaExists(bytes4 functionSelector) public view returns (bool) {
525
- return _secureState.functions[functionSelector].functionSelector == functionSelector;
526
- }
527
-
528
- /**
529
- * @dev Returns if an action is supported by a function
530
- * @param functionSelector The function selector to check
531
- * @param action The action to check
532
- * @return True if the action is supported by the function, false otherwise
533
- */
534
- function isActionSupportedByFunction(bytes4 functionSelector, EngineBlox.TxAction action) public view returns (bool) {
535
- return _secureState.isActionSupportedByFunction(functionSelector, action);
536
- }
537
-
538
- /**
539
- * @dev Gets function schema information
540
- * @param functionSelector The function selector to get information for
541
- * @return The full FunctionSchema struct (functionSignature, functionSelector, operationType, operationName, supportedActionsBitmap, isProtected, handlerForSelectors)
542
- */
543
- function getFunctionSchema(bytes4 functionSelector) external view returns (EngineBlox.FunctionSchema memory) {
544
- _validateAnyRole();
545
- return _secureState.getFunctionSchema(functionSelector);
546
- }
547
-
548
- /**
549
- * @dev Gets the function permissions for a specific role
550
- * @param roleHash The hash of the role to get permissions for
551
- * @return The function permissions array for the role
552
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
553
- */
554
- function getActiveRolePermissions(bytes32 roleHash) public view returns (EngineBlox.FunctionPermission[] memory) {
555
- _validateAnyRole();
556
- return _secureState.getRoleFunctionPermissions(roleHash);
557
- }
558
-
559
- /**
560
- * @dev Gets the current nonce for a specific signer
561
- * @param signer The address of the signer
562
- * @return The current nonce for the signer
563
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
564
- */
565
- function getSignerNonce(address signer) public view returns (uint256) {
566
- _validateAnyRole();
567
- return _secureState.getSignerNonce(signer);
568
- }
569
-
570
- // ============ SYSTEM STATE QUERIES ============
571
-
572
- /**
573
- * @dev Returns the supported operation types
574
- * @return The supported operation types
575
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
576
- */
577
- function getSupportedOperationTypes() public view returns (bytes32[] memory) {
578
- _validateAnyRole();
579
- return _secureState.getSupportedOperationTypesList();
580
- }
581
-
582
- /**
583
- * @dev Returns the supported roles list
584
- * @return The supported roles list
585
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
586
- */
587
- function getSupportedRoles() public view returns (bytes32[] memory) {
588
- _validateAnyRole();
589
- return _secureState.getSupportedRolesList();
590
- }
591
-
592
- /**
593
- * @dev Returns the supported functions list
594
- * @return The supported functions list
595
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
596
- */
597
- function getSupportedFunctions() public view returns (bytes4[] memory) {
598
- _validateAnyRole();
599
- return _secureState.getSupportedFunctionsList();
600
- }
601
-
602
- /**
603
- * @dev Returns the time lock period
604
- * @return The time lock period in seconds
605
- */
606
- function getTimeLockPeriodSec() public view returns (uint256) {
607
- return _secureState.timeLockPeriodSec;
608
- }
609
-
610
- /**
611
- * @dev Returns whether the contract is initialized
612
- * @return bool True if the contract is initialized, false otherwise
613
- */
614
- function initialized() public view returns (bool) {
615
- return _getInitializedVersion() != type(uint8).max && _secureState.initialized;
616
- }
617
-
618
- // ============ ROLE MANAGEMENT ============
619
-
620
- /**
621
- * @dev Centralized function to get authorized wallet at specific index
622
- * @param roleHash The role hash
623
- * @param index The wallet index
624
- * @return The authorized wallet address
625
- */
626
- function _getAuthorizedWalletAt(bytes32 roleHash, uint256 index) internal view returns (address) {
627
- return EngineBlox.getAuthorizedWalletAt(_getSecureState(), roleHash, index);
628
- }
629
-
630
- /**
631
- * @dev Centralized function to get all authorized wallets for a role
632
- * @param roleHash The role hash
633
- * @return Array of authorized wallet addresses
634
- */
635
- function _getAuthorizedWallets(bytes32 roleHash) internal view returns (address[] memory) {
636
- return EngineBlox._getAuthorizedWallets(_getSecureState(), roleHash);
637
- }
638
-
639
- /**
640
- * @dev Centralized function to create a new role
641
- * @param roleName The name of the role
642
- * @param maxWallets The maximum number of wallets allowed for this role
643
- * @param isProtected Whether the role is protected from removal
644
- * @return roleHash The hash of the created role
645
- * @notice This function is virtual to allow extensions to add hook functionality
646
- */
647
- function _createRole(
648
- string memory roleName,
649
- uint256 maxWallets,
650
- bool isProtected
651
- ) internal virtual returns (bytes32) {
652
- bytes32 roleHash = keccak256(bytes(roleName));
653
- EngineBlox.createRole(_getSecureState(), roleName, maxWallets, isProtected);
654
- return roleHash;
655
- }
656
-
657
- /**
658
- * @dev Centralized function to remove a role
659
- * @param roleHash The hash of the role to remove
660
- * @notice This function is virtual to allow extensions to add hook functionality
661
- */
662
- function _removeRole(bytes32 roleHash) internal virtual {
663
- EngineBlox.removeRole(_getSecureState(), roleHash);
664
- }
665
-
666
- /**
667
- * @dev Centralized function to assign a wallet to a role
668
- * @param roleHash The role hash
669
- * @param wallet The wallet address to assign
670
- * @notice This function is virtual to allow extensions to add hook functionality
671
- */
672
- function _assignWallet(bytes32 roleHash, address wallet) internal virtual {
673
- EngineBlox.assignWallet(_getSecureState(), roleHash, wallet);
674
- }
675
-
676
- /**
677
- * @dev Centralized function to revoke a wallet from a role
678
- * @param roleHash The role hash
679
- * @param wallet The wallet address to revoke
680
- * @notice This function is virtual to allow extensions to add hook functionality
681
- */
682
- function _revokeWallet(bytes32 roleHash, address wallet) internal virtual {
683
- EngineBlox.revokeWallet(_getSecureState(), roleHash, wallet);
684
- }
685
-
686
- /**
687
- * @dev Centralized function to update assigned wallet for a role
688
- * @param roleHash The role hash
689
- * @param newWallet The new wallet address
690
- * @param oldWallet The old wallet address
691
- * @notice This function is virtual to allow extensions to add hook functionality or additional validation
692
- */
693
- function _updateAssignedWallet(bytes32 roleHash, address newWallet, address oldWallet) internal virtual {
694
- EngineBlox.updateAssignedWallet(_getSecureState(), roleHash, newWallet, oldWallet);
695
- }
696
-
697
- /**
698
- * @dev Centralized function to update the time lock period
699
- * @param newTimeLockPeriodSec The new time lock period in seconds
700
- * @notice This function is virtual to allow extensions to add hook functionality
701
- */
702
- function _updateTimeLockPeriod(uint256 newTimeLockPeriodSec) internal virtual {
703
- uint256 oldPeriod = getTimeLockPeriodSec();
704
- EngineBlox.updateTimeLockPeriod(_getSecureState(), newTimeLockPeriodSec);
705
- _logComponentEvent(abi.encode(oldPeriod, newTimeLockPeriodSec));
706
- }
707
-
708
- // ============ FUNCTION SCHEMA MANAGEMENT ============
709
-
710
- /**
711
- * @dev Centralized function to create a function schema
712
- * @param functionSignature The function signature
713
- * @param functionSelector The function selector
714
- * @param operationName The operation name
715
- * @param supportedActionsBitmap The bitmap of supported actions
716
- * @param isProtected Whether the function schema is protected
717
- * @param handlerForSelectors Array of handler selectors
718
- * @notice This function is virtual to allow extensions to add hook functionality
719
- */
720
- function _createFunctionSchema(
721
- string memory functionSignature,
722
- bytes4 functionSelector,
723
- string memory operationName,
724
- uint16 supportedActionsBitmap,
725
- bool isProtected,
726
- bytes4[] memory handlerForSelectors
727
- ) internal virtual {
728
- EngineBlox.createFunctionSchema(
729
- _getSecureState(),
730
- functionSignature,
731
- functionSelector,
732
- operationName,
733
- supportedActionsBitmap,
734
- isProtected,
735
- handlerForSelectors
736
- );
737
- }
738
-
739
- /**
740
- * @dev Centralized function to remove a function schema
741
- * @param functionSelector The function selector to remove
742
- * @param safeRemoval Whether to perform safe removal (check for role references)
743
- * @notice This function is virtual to allow extensions to add hook functionality
744
- */
745
- function _removeFunctionSchema(bytes4 functionSelector, bool safeRemoval) internal virtual {
746
- EngineBlox.removeFunctionSchema(_getSecureState(), functionSelector, safeRemoval);
747
- }
748
-
749
- /**
750
- * @dev Centralized function to add a function permission to a role
751
- * @param roleHash The role hash
752
- * @param functionPermission The function permission to add
753
- * @notice This function is virtual to allow extensions to add hook functionality
754
- */
755
- function _addFunctionToRole(
756
- bytes32 roleHash,
757
- EngineBlox.FunctionPermission memory functionPermission
758
- ) internal virtual {
759
- EngineBlox.addFunctionToRole(_getSecureState(), roleHash, functionPermission);
760
- }
761
-
762
- /**
763
- * @dev Centralized function to remove a function permission from a role
764
- * @param roleHash The role hash
765
- * @param functionSelector The function selector to remove
766
- * @notice This function is virtual to allow extensions to add hook functionality
767
- */
768
- function _removeFunctionFromRole(bytes32 roleHash, bytes4 functionSelector) internal virtual {
769
- EngineBlox.removeFunctionFromRole(_getSecureState(), roleHash, functionSelector);
770
- }
771
-
772
- // ============ PERMISSION VALIDATION ============
773
-
774
- /**
775
- * @dev Centralized function to validate that the caller has any role
776
- */
777
- function _validateAnyRole() internal view {
778
- EngineBlox._validateAnyRole(_getSecureState());
779
- }
780
-
781
- /**
782
- * @dev Centralized function to validate that a role exists
783
- * @param roleHash The role hash to validate
784
- */
785
- function _validateRoleExists(bytes32 roleHash) internal view {
786
- EngineBlox._validateRoleExists(_getSecureState(), roleHash);
787
- }
788
-
789
- /**
790
- * @dev Centralized function to validate that the caller is the contract itself (for execution-only entry points).
791
- */
792
- function _validateExecuteBySelf() internal view {
793
- SharedValidation.validateInternalCall(address(this));
794
- }
795
-
796
- /**
797
- * @dev Centralized function to validate batch size against EngineBlox.MAX_BATCH_SIZE.
798
- * @param length The batch length to validate
799
- */
800
- function _validateBatchSize(uint256 length) internal pure {
801
- SharedValidation.validateBatchSize(length, EngineBlox.MAX_BATCH_SIZE);
802
- }
803
-
804
- // ============ MACRO SELECTORS ============
805
-
806
- /**
807
- * @dev Adds a function selector to the system macro selectors set.
808
- * Macro selectors are allowed to target address(this) for system-level operations.
809
- * @param functionSelector The function selector to add (e.g. NATIVE_TRANSFER_SELECTOR).
810
- */
811
- function _addMacroSelector(bytes4 functionSelector) internal {
812
- EngineBlox.addMacroSelector(_getSecureState(), functionSelector);
813
- }
814
-
815
- /**
816
- * @dev Returns true if the given function selector is in the system macro selectors set.
817
- * @param functionSelector The function selector to check.
818
- */
819
- function _isMacroSelector(bytes4 functionSelector) internal view returns (bool) {
820
- return EngineBlox.isMacroSelector(_getSecureState(), functionSelector);
821
- }
822
-
823
- // ============ UTILITY FUNCTIONS ============
824
-
825
- /**
826
- * @dev Centralized function to convert a bitmap to an array of actions
827
- * @param bitmap The bitmap to convert
828
- * @return Array of TxAction values
829
- */
830
- function _convertBitmapToActions(uint16 bitmap) internal pure returns (EngineBlox.TxAction[] memory) {
831
- return EngineBlox.convertBitmapToActions(bitmap);
832
- }
833
-
834
- /**
835
- * @dev Centralized function to create a bitmap from an array of actions
836
- * @param actions Array of TxAction values
837
- * @return The bitmap representation
838
- */
839
- function _createBitmapFromActions(EngineBlox.TxAction[] memory actions) internal pure returns (uint16) {
840
- return EngineBlox.createBitmapFromActions(actions);
841
- }
842
-
843
- // ============ TARGET WHITELIST MANAGEMENT ============
844
-
845
- /**
846
- * @dev Centralized function to add a target address to the whitelist for a function selector
847
- * @param functionSelector The function selector
848
- * @param target The target address to whitelist
849
- * @notice This function is virtual to allow extensions to add hook functionality
850
- */
851
- function _addTargetToFunctionWhitelist(bytes4 functionSelector, address target) internal virtual {
852
- _getSecureState().addTargetToFunctionWhitelist(functionSelector, target);
853
- }
854
-
855
- /**
856
- * @dev Centralized function to remove a target address from the whitelist for a function selector
857
- * @param functionSelector The function selector
858
- * @param target The target address to remove
859
- * @notice This function is virtual to allow extensions to add hook functionality
860
- */
861
- function _removeTargetFromFunctionWhitelist(bytes4 functionSelector, address target) internal virtual {
862
- _getSecureState().removeTargetFromFunctionWhitelist(functionSelector, target);
863
- }
864
-
865
- /**
866
- * @dev Gets all whitelisted targets for a function selector
867
- * @param functionSelector The function selector
868
- * @return Array of whitelisted target addresses
869
- * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
870
- */
871
- function getFunctionWhitelistTargets(bytes4 functionSelector) public view returns (address[] memory) {
872
- _validateAnyRole();
873
- return _getSecureState().getFunctionWhitelistTargets(functionSelector);
874
- }
875
-
876
- // ============ DEFINITION LOADING ============
877
-
878
- /**
879
- * @dev Loads definitions directly into the secure state
880
- * This function initializes the secure state with all predefined definitions
881
- * @param functionSchemas Array of function schema definitions
882
- * @param roleHashes Array of role hashes
883
- * @param functionPermissions Array of function permissions (parallel to roleHashes)
884
- * @param enforceProtectedSchemas When true, all function schemas must be protected; reverts if any is not
885
- * @notice When enforceProtectedSchemas is true, every function schema must have isProtected == true
886
- */
887
- function _loadDefinitions(
888
- EngineBlox.FunctionSchema[] memory functionSchemas,
889
- bytes32[] memory roleHashes,
890
- EngineBlox.FunctionPermission[] memory functionPermissions,
891
- bool enforceProtectedSchemas
892
- ) internal {
893
- // Load function schemas
894
- for (uint256 i = 0; i < functionSchemas.length; i++) {
895
- // When enforcing, require every schema to be protected
896
- if (enforceProtectedSchemas && !functionSchemas[i].isProtected) {
897
- revert SharedValidation.ContractFunctionMustBeProtected(
898
- 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.34;
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
+ // Skip if already initialized (e.g. when multiple components call from Account.initialize)
69
+ if (!_secureState.initialized) {
70
+ __ERC165_init();
71
+ __ReentrancyGuard_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 (0 for standard function calls)
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 For standard function calls: value=0, functionSelector=non-zero, params=encoded data
134
+ * @notice For simple native token transfers: value>0, functionSelector=NATIVE_TRANSFER_SELECTOR, params=""
135
+ */
136
+ function _requestTransaction(
137
+ address requester,
138
+ address target,
139
+ uint256 value,
140
+ uint256 gasLimit,
141
+ bytes32 operationType,
142
+ bytes4 functionSelector,
143
+ bytes memory params
144
+ ) internal virtual returns (EngineBlox.TxRecord memory) {
145
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txRequest(
146
+ _getSecureState(),
147
+ requester,
148
+ target,
149
+ value,
150
+ gasLimit,
151
+ operationType,
152
+ bytes4(msg.sig),
153
+ functionSelector,
154
+ params
155
+ );
156
+ _postActionHook(txRecord);
157
+ return txRecord;
158
+ }
159
+
160
+ /**
161
+ * @dev Centralized function to request a transaction with payment details attached from the start
162
+ * @param requester The address requesting the transaction
163
+ * @param target The target contract address
164
+ * @param value The ETH value to send (0 for standard function calls)
165
+ * @param gasLimit The gas limit for execution
166
+ * @param operationType The type of operation
167
+ * @param functionSelector The function selector for execution (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
168
+ * @param params The encoded parameters for the function (empty for simple native token transfers)
169
+ * @param paymentDetails The payment details to attach to the transaction
170
+ * @return The created transaction record with payment set
171
+ * @notice Validates request permissions (same as request without payment)
172
+ * @notice This function is virtual to allow extensions to add hook functionality
173
+ */
174
+ function _requestTransactionWithPayment(
175
+ address requester,
176
+ address target,
177
+ uint256 value,
178
+ uint256 gasLimit,
179
+ bytes32 operationType,
180
+ bytes4 functionSelector,
181
+ bytes memory params,
182
+ EngineBlox.PaymentDetails memory paymentDetails
183
+ ) internal virtual returns (EngineBlox.TxRecord memory) {
184
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txRequestWithPayment(
185
+ _getSecureState(),
186
+ requester,
187
+ target,
188
+ value,
189
+ gasLimit,
190
+ operationType,
191
+ bytes4(msg.sig),
192
+ functionSelector,
193
+ params,
194
+ paymentDetails
195
+ );
196
+ _postActionHook(txRecord);
197
+ return txRecord;
198
+ }
199
+
200
+ /**
201
+ * @dev Centralized function to approve a pending transaction after release time
202
+ * @param txId The transaction ID
203
+ * @return The updated transaction record
204
+ * @notice Validates permissions for the calling function (approval function selector), not the execution selector
205
+ * @notice Execution functions are internal-only and don't need permission definitions
206
+ * @notice This function is virtual to allow extensions to add hook functionality
207
+ * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
208
+ */
209
+ function _approveTransaction(
210
+ uint256 txId
211
+ ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
212
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txDelayedApproval(_getSecureState(), txId, bytes4(msg.sig));
213
+ _postActionHook(txRecord);
214
+ return txRecord;
215
+ }
216
+
217
+ /**
218
+ * @dev Centralized function to approve a transaction using meta-transaction
219
+ * @param metaTx The meta-transaction
220
+ * @return The updated transaction record
221
+ * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
222
+ * @notice Uses EXECUTE_META_APPROVE action for permission checking
223
+ * @notice This function is virtual to allow extensions to add hook functionality
224
+ * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
225
+ */
226
+ function _approveTransactionWithMetaTx(
227
+ EngineBlox.MetaTransaction memory metaTx
228
+ ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
229
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txApprovalWithMetaTx(_getSecureState(), metaTx);
230
+ _postActionHook(txRecord);
231
+ return txRecord;
232
+ }
233
+
234
+ /**
235
+ * @dev Centralized function to cancel a pending transaction
236
+ * @param txId The transaction ID
237
+ * @return The updated transaction record
238
+ * @notice Validates permissions for the calling function (cancellation function selector), not the execution selector
239
+ * @notice Execution functions are internal-only and don't need permission definitions
240
+ * @notice This function is virtual to allow extensions to add hook functionality
241
+ */
242
+ function _cancelTransaction(
243
+ uint256 txId
244
+ ) internal virtual returns (EngineBlox.TxRecord memory) {
245
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txCancellation(_getSecureState(), txId, bytes4(msg.sig));
246
+ _postActionHook(txRecord);
247
+ return txRecord;
248
+ }
249
+
250
+ /**
251
+ * @dev Centralized function to cancel a transaction using meta-transaction
252
+ * @param metaTx The meta-transaction
253
+ * @return The updated transaction record
254
+ * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
255
+ * @notice Uses EXECUTE_META_CANCEL action for permission checking
256
+ * @notice This function is virtual to allow extensions to add hook functionality
257
+ */
258
+ function _cancelTransactionWithMetaTx(
259
+ EngineBlox.MetaTransaction memory metaTx
260
+ ) internal virtual returns (EngineBlox.TxRecord memory) {
261
+ EngineBlox.TxRecord memory txRecord = EngineBlox.txCancellationWithMetaTx(_getSecureState(), metaTx);
262
+ _postActionHook(txRecord);
263
+ return txRecord;
264
+ }
265
+
266
+ /**
267
+ * @dev Centralized function to request and approve a transaction using meta-transaction
268
+ * @param metaTx The meta-transaction
269
+ * @return The transaction record
270
+ * @notice Validates permissions for the calling function (msg.sig) and handler selector from metaTx
271
+ * @notice Uses EXECUTE_META_REQUEST_AND_APPROVE action for permission checking
272
+ * @notice This function is virtual to allow extensions to add hook functionality
273
+ * @notice Protected by ReentrancyGuard to prevent reentrancy attacks
274
+ */
275
+ function _requestAndApproveTransaction(
276
+ EngineBlox.MetaTransaction memory metaTx
277
+ ) internal virtual nonReentrant returns (EngineBlox.TxRecord memory) {
278
+ EngineBlox.TxRecord memory txRecord = EngineBlox.requestAndApprove(_getSecureState(), metaTx);
279
+ _postActionHook(txRecord);
280
+ return txRecord;
281
+ }
282
+
283
+ /**
284
+ * @dev Post-action hook invoked after any transaction operation that produces a TxRecord.
285
+ * Override in derived contracts to add centralized post-tx logic (e.g. notifications, side effects).
286
+ * @param txRecord The transaction record produced by the operation
287
+ */
288
+ function _postActionHook(EngineBlox.TxRecord memory txRecord) internal virtual {}
289
+
290
+ // ============ HOOK MANAGEMENT ============
291
+
292
+ /**
293
+ * @dev Sets the hook contract for a function selector (internal; no access control).
294
+ * Extensions (e.g. HookManager) may expose an external setHook with owner check.
295
+ * @param functionSelector The function selector
296
+ * @param hook The hook contract address (must not be zero)
297
+ */
298
+ function _setHook(bytes4 functionSelector, address hook) internal {
299
+ EngineBlox.setHook(_getSecureState(), functionSelector, hook);
300
+ }
301
+
302
+ /**
303
+ * @dev Clears the hook contract for a function selector (internal; no access control).
304
+ * Extensions may expose an external clearHook with owner check.
305
+ * @param functionSelector The function selector
306
+ * @param hook The hook contract address to remove (must not be zero)
307
+ */
308
+ function _clearHook(bytes4 functionSelector, address hook) internal {
309
+ EngineBlox.clearHook(_getSecureState(), functionSelector, hook);
310
+ }
311
+
312
+ /**
313
+ * @dev Returns all configured hooks for a function selector
314
+ * @param functionSelector The function selector
315
+ * @return hooks Array of hook contract addresses
316
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
317
+ */
318
+ function getHooks(bytes4 functionSelector) public view returns (address[] memory hooks) {
319
+ _validateAnyRole();
320
+ return EngineBlox.getHooks(_getSecureState(), functionSelector);
321
+ }
322
+
323
+ // ============ META-TRANSACTION UTILITIES ============
324
+
325
+ /**
326
+ * @dev Creates meta-transaction parameters with specified values
327
+ * @param handlerContract The contract that will handle the meta-transaction
328
+ * @param handlerSelector The function selector for the handler
329
+ * @param action The transaction action type
330
+ * @param deadline The timestamp after which the meta-transaction expires
331
+ * @param maxGasPrice The maximum gas price allowed for execution
332
+ * @param signer The address that will sign the meta-transaction
333
+ * @return The formatted meta-transaction parameters
334
+ */
335
+ function createMetaTxParams(
336
+ address handlerContract,
337
+ bytes4 handlerSelector,
338
+ EngineBlox.TxAction action,
339
+ uint256 deadline,
340
+ uint256 maxGasPrice,
341
+ address signer
342
+ ) public view returns (EngineBlox.MetaTxParams memory) {
343
+ return EngineBlox.createMetaTxParams(
344
+ handlerContract,
345
+ handlerSelector,
346
+ action,
347
+ deadline,
348
+ maxGasPrice,
349
+ signer
350
+ );
351
+ }
352
+
353
+ /**
354
+ * @dev Generates an unsigned meta-transaction for a new operation
355
+ * @param requester The address requesting the operation
356
+ * @param target The target contract address
357
+ * @param value The ETH value to send
358
+ * @param gasLimit The gas limit for execution
359
+ * @param operationType The type of operation
360
+ * @param executionSelector The function selector to execute (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
361
+ * @param executionParams The encoded parameters for the function (empty for simple native token transfers)
362
+ * @param metaTxParams The meta-transaction parameters
363
+ * @return The unsigned meta-transaction
364
+ */
365
+ function generateUnsignedMetaTransactionForNew(
366
+ address requester,
367
+ address target,
368
+ uint256 value,
369
+ uint256 gasLimit,
370
+ bytes32 operationType,
371
+ bytes4 executionSelector,
372
+ bytes memory executionParams,
373
+ EngineBlox.MetaTxParams memory metaTxParams
374
+ ) public view returns (EngineBlox.MetaTransaction memory) {
375
+ EngineBlox.TxParams memory txParams = EngineBlox.TxParams({
376
+ requester: requester,
377
+ target: target,
378
+ value: value,
379
+ gasLimit: gasLimit,
380
+ operationType: operationType,
381
+ executionSelector: executionSelector,
382
+ executionParams: executionParams
383
+ });
384
+
385
+ return _secureState.generateUnsignedForNewMetaTx(txParams, metaTxParams);
386
+ }
387
+
388
+ /**
389
+ * @dev Generates an unsigned meta-transaction for an existing transaction
390
+ * @param txId The ID of the existing transaction
391
+ * @param metaTxParams The meta-transaction parameters
392
+ * @return The unsigned meta-transaction
393
+ */
394
+ function generateUnsignedMetaTransactionForExisting(
395
+ uint256 txId,
396
+ EngineBlox.MetaTxParams memory metaTxParams
397
+ ) public view returns (EngineBlox.MetaTransaction memory) {
398
+ return _secureState.generateUnsignedForExistingMetaTx(txId, metaTxParams);
399
+ }
400
+
401
+ // ============ STATE QUERIES ============
402
+
403
+ /**
404
+ * @dev Gets transaction history within a specified range
405
+ * @param fromTxId The starting transaction ID (inclusive)
406
+ * @param toTxId The ending transaction ID (inclusive)
407
+ * @return The transaction history within the specified range
408
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
409
+ */
410
+ function getTransactionHistory(uint256 fromTxId, uint256 toTxId) public view returns (EngineBlox.TxRecord[] memory) {
411
+ _validateAnyRole();
412
+
413
+ // Validate the range
414
+ fromTxId = fromTxId > 0 ? fromTxId : 1;
415
+ toTxId = toTxId > _secureState.txCounter ? _secureState.txCounter : toTxId;
416
+
417
+ // Validate that fromTxId is less than toTxId
418
+ SharedValidation.validateLessThan(fromTxId, toTxId);
419
+
420
+ uint256 rangeSize = toTxId - fromTxId + 1;
421
+
422
+ // For larger ranges, use paginated version
423
+ SharedValidation.validateRangeSize(rangeSize, 1000);
424
+
425
+ EngineBlox.TxRecord[] memory history = new EngineBlox.TxRecord[](rangeSize);
426
+
427
+ for (uint256 i = 0; i < rangeSize; i++) {
428
+ history[i] = _secureState.getTxRecord(fromTxId + i);
429
+ }
430
+
431
+ return history;
432
+ }
433
+
434
+ /**
435
+ * @dev Gets a transaction by ID
436
+ * @param txId The transaction ID
437
+ * @return The transaction record
438
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
439
+ */
440
+ function getTransaction(uint256 txId) public view returns (EngineBlox.TxRecord memory) {
441
+ _validateAnyRole();
442
+ return _secureState.getTxRecord(txId);
443
+ }
444
+
445
+ /**
446
+ * @dev Gets all pending transaction IDs
447
+ * @return Array of pending transaction IDs
448
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
449
+ */
450
+ function getPendingTransactions() public view returns (uint256[] memory) {
451
+ _validateAnyRole();
452
+ return _secureState.getPendingTransactions();
453
+ }
454
+
455
+ // ============ ROLE AND PERMISSION QUERIES ============
456
+
457
+ /**
458
+ * @dev Gets the basic role information by its hash
459
+ * @param roleHash The hash of the role to get
460
+ * @return roleName The name of the role
461
+ * @return hash The hash of the role
462
+ * @return maxWallets The maximum number of wallets allowed for this role
463
+ * @return walletCount The current number of wallets assigned to this role
464
+ * @return isProtected Whether the role is protected from removal
465
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
466
+ */
467
+ function getRole(bytes32 roleHash) public view returns (
468
+ string memory roleName,
469
+ bytes32 hash,
470
+ uint256 maxWallets,
471
+ uint256 walletCount,
472
+ bool isProtected
473
+ ) {
474
+ _validateAnyRole();
475
+ EngineBlox.Role storage role = _secureState.getRole(roleHash);
476
+ return (
477
+ role.roleName,
478
+ role.roleHash,
479
+ role.maxWallets,
480
+ role.walletCount,
481
+ role.isProtected
482
+ );
483
+ }
484
+
485
+ /**
486
+ * @dev Returns if a wallet is authorized for a role
487
+ * @param roleHash The hash of the role to check
488
+ * @param wallet The wallet address to check
489
+ * @return True if the wallet is authorized for the role, false otherwise
490
+ */
491
+ function hasRole(bytes32 roleHash, address wallet) public view returns (bool) {
492
+ return _secureState.hasRole(roleHash, wallet);
493
+ }
494
+
495
+ /**
496
+ * @dev Gets all roles assigned to a wallet
497
+ * @param wallet The wallet address to get roles for
498
+ * @return Array of role hashes assigned to the wallet
499
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
500
+ * @notice This function uses the reverse index for efficient lookup
501
+ */
502
+ function getWalletRoles(address wallet) public view returns (bytes32[] memory) {
503
+ _validateAnyRole();
504
+ return EngineBlox.getWalletRoles(_getSecureState(), wallet);
505
+ }
506
+
507
+ /**
508
+ * @dev Gets all authorized wallets for a role
509
+ * @param roleHash The role hash to get wallets for
510
+ * @return Array of authorized wallet addresses
511
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
512
+ */
513
+ function getAuthorizedWallets(bytes32 roleHash) public view returns (address[] memory) {
514
+ _validateAnyRole();
515
+ _validateRoleExists(roleHash);
516
+ return _getAuthorizedWallets(roleHash);
517
+ }
518
+
519
+ /**
520
+ * @dev Gets function schema information
521
+ * @param functionSelector The function selector to get information for
522
+ * @return The full FunctionSchema struct (functionSignature, functionSelector, operationType, operationName, supportedActionsBitmap, isProtected, handlerForSelectors)
523
+ */
524
+ function getFunctionSchema(bytes4 functionSelector) external view returns (EngineBlox.FunctionSchema memory) {
525
+ _validateAnyRole();
526
+ return _secureState.getFunctionSchema(functionSelector);
527
+ }
528
+
529
+ /**
530
+ * @dev Gets the function permissions for a specific role
531
+ * @param roleHash The hash of the role to get permissions for
532
+ * @return The function permissions array for the role
533
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
534
+ */
535
+ function getActiveRolePermissions(bytes32 roleHash) public view returns (EngineBlox.FunctionPermission[] memory) {
536
+ _validateAnyRole();
537
+ return _secureState.getRoleFunctionPermissions(roleHash);
538
+ }
539
+
540
+ /**
541
+ * @dev Gets the current nonce for a specific signer
542
+ * @param signer The address of the signer
543
+ * @return The current nonce for the signer
544
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
545
+ */
546
+ function getSignerNonce(address signer) public view returns (uint256) {
547
+ _validateAnyRole();
548
+ return _secureState.getSignerNonce(signer);
549
+ }
550
+
551
+ // ============ SYSTEM STATE QUERIES ============
552
+
553
+ /**
554
+ * @dev Returns the supported operation types
555
+ * @return The supported operation types
556
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
557
+ */
558
+ function getSupportedOperationTypes() public view returns (bytes32[] memory) {
559
+ _validateAnyRole();
560
+ return _secureState.getSupportedOperationTypes();
561
+ }
562
+
563
+ /**
564
+ * @dev Returns the supported roles list
565
+ * @return The supported roles list
566
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
567
+ */
568
+ function getSupportedRoles() public view returns (bytes32[] memory) {
569
+ _validateAnyRole();
570
+ return _secureState.getSupportedRoles();
571
+ }
572
+
573
+ /**
574
+ * @dev Returns the supported functions list
575
+ * @return The supported functions list
576
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
577
+ */
578
+ function getSupportedFunctions() public view returns (bytes4[] memory) {
579
+ _validateAnyRole();
580
+ return _secureState.getSupportedFunctions();
581
+ }
582
+
583
+ /**
584
+ * @dev Returns the time lock period
585
+ * @return The time lock period in seconds
586
+ */
587
+ function getTimeLockPeriodSec() public view returns (uint256) {
588
+ return _secureState.timeLockPeriodSec;
589
+ }
590
+
591
+ /**
592
+ * @dev Returns whether the contract is initialized
593
+ * @return bool True if the contract is initialized, false otherwise
594
+ */
595
+ function initialized() public view returns (bool) {
596
+ return _getInitializedVersion() != type(uint8).max && _secureState.initialized;
597
+ }
598
+
599
+ // ============ ROLE MANAGEMENT ============
600
+
601
+ /**
602
+ * @dev Centralized function to get authorized wallet at specific index
603
+ * @param roleHash The role hash
604
+ * @param index The wallet index
605
+ * @return The authorized wallet address
606
+ */
607
+ function _getAuthorizedWalletAt(bytes32 roleHash, uint256 index) internal view returns (address) {
608
+ return EngineBlox.getAuthorizedWalletAt(_getSecureState(), roleHash, index);
609
+ }
610
+
611
+ /**
612
+ * @dev Centralized function to get all authorized wallets for a role
613
+ * @param roleHash The role hash
614
+ * @return Array of authorized wallet addresses
615
+ */
616
+ function _getAuthorizedWallets(bytes32 roleHash) internal view returns (address[] memory) {
617
+ return EngineBlox.getAuthorizedWallets(_getSecureState(), roleHash);
618
+ }
619
+
620
+ /**
621
+ * @dev Centralized function to create a new role
622
+ * @param roleName The name of the role
623
+ * @param maxWallets The maximum number of wallets allowed for this role
624
+ * @param isProtected Whether the role is protected from removal
625
+ * @return roleHash The hash of the created role
626
+ * @notice This function is virtual to allow extensions to add hook functionality
627
+ */
628
+ function _createRole(
629
+ string memory roleName,
630
+ uint256 maxWallets,
631
+ bool isProtected
632
+ ) internal virtual returns (bytes32) {
633
+ bytes32 roleHash = keccak256(bytes(roleName));
634
+ EngineBlox.createRole(_getSecureState(), roleName, maxWallets, isProtected);
635
+ return roleHash;
636
+ }
637
+
638
+ /**
639
+ * @dev Centralized function to remove a role
640
+ * @param roleHash The hash of the role to remove
641
+ * @notice This function is virtual to allow extensions to add hook functionality
642
+ */
643
+ function _removeRole(bytes32 roleHash) internal virtual {
644
+ EngineBlox.removeRole(_getSecureState(), roleHash);
645
+ }
646
+
647
+ /**
648
+ * @dev Centralized function to assign a wallet to a role
649
+ * @param roleHash The role hash
650
+ * @param wallet The wallet address to assign
651
+ * @notice This function is virtual to allow extensions to add hook functionality
652
+ */
653
+ function _assignWallet(bytes32 roleHash, address wallet) internal virtual {
654
+ EngineBlox.assignWallet(_getSecureState(), roleHash, wallet);
655
+ }
656
+
657
+ /**
658
+ * @dev Centralized function to revoke a wallet from a role
659
+ * @param roleHash The role hash
660
+ * @param wallet The wallet address to revoke
661
+ * @notice This function is virtual to allow extensions to add hook functionality
662
+ */
663
+ function _revokeWallet(bytes32 roleHash, address wallet) internal virtual {
664
+ EngineBlox.revokeWallet(_getSecureState(), roleHash, wallet);
665
+ }
666
+
667
+ /**
668
+ * @dev Centralized function to update wallet for a role (replaces oldWallet with newWallet).
669
+ * @param roleHash The role hash
670
+ * @param newWallet The new wallet address
671
+ * @param oldWallet The old wallet address
672
+ * @notice This function is virtual to allow extensions to add hook functionality or additional validation
673
+ */
674
+ function _updateWallet(bytes32 roleHash, address newWallet, address oldWallet) internal virtual {
675
+ EngineBlox.updateWallet(_getSecureState(), roleHash, newWallet, oldWallet);
676
+ }
677
+
678
+ /**
679
+ * @dev Centralized function to update the time lock period
680
+ * @param newTimeLockPeriodSec The new time lock period in seconds
681
+ * @notice This function is virtual to allow extensions to add hook functionality
682
+ */
683
+ function _updateTimeLockPeriod(uint256 newTimeLockPeriodSec) internal virtual {
684
+ uint256 oldPeriod = getTimeLockPeriodSec();
685
+ EngineBlox.updateTimeLockPeriod(_getSecureState(), newTimeLockPeriodSec);
686
+ _logComponentEvent(abi.encode(oldPeriod, newTimeLockPeriodSec));
687
+ }
688
+
689
+ // ============ FUNCTION SCHEMA MANAGEMENT ============
690
+
691
+ /**
692
+ * @dev Centralized function to register a function schema
693
+ * @param functionSignature The function signature
694
+ * @param functionSelector The function selector
695
+ * @param operationName The operation name
696
+ * @param supportedActionsBitmap The bitmap of supported actions
697
+ * @param isProtected Whether the function schema is protected
698
+ * @param handlerForSelectors Array of handler selectors
699
+ * @notice This function is virtual to allow extensions to add hook functionality
700
+ */
701
+ function _registerFunction(
702
+ string memory functionSignature,
703
+ bytes4 functionSelector,
704
+ string memory operationName,
705
+ uint16 supportedActionsBitmap,
706
+ bool isProtected,
707
+ bytes4[] memory handlerForSelectors
708
+ ) internal virtual {
709
+ EngineBlox.registerFunction(
710
+ _getSecureState(),
711
+ functionSignature,
712
+ functionSelector,
713
+ operationName,
714
+ supportedActionsBitmap,
715
+ isProtected,
716
+ handlerForSelectors
717
+ );
718
+ }
719
+
720
+ /**
721
+ * @dev Centralized function to unregister a function schema
722
+ * @param functionSelector The function selector to unregister
723
+ * @param safeRemoval Whether to perform safe removal (check for role references)
724
+ * @notice This function is virtual to allow extensions to add hook functionality
725
+ */
726
+ function _unregisterFunction(bytes4 functionSelector, bool safeRemoval) internal virtual {
727
+ EngineBlox.unregisterFunction(_getSecureState(), functionSelector, safeRemoval);
728
+ }
729
+
730
+ /**
731
+ * @dev Centralized function to add a function permission to a role
732
+ * @param roleHash The role hash
733
+ * @param functionPermission The function permission to add
734
+ * @notice This function is virtual to allow extensions to add hook functionality
735
+ */
736
+ function _addFunctionToRole(
737
+ bytes32 roleHash,
738
+ EngineBlox.FunctionPermission memory functionPermission
739
+ ) internal virtual {
740
+ EngineBlox.addFunctionToRole(_getSecureState(), roleHash, functionPermission);
741
+ }
742
+
743
+ /**
744
+ * @dev Centralized function to remove a function permission from a role
745
+ * @param roleHash The role hash
746
+ * @param functionSelector The function selector to remove
747
+ * @notice This function is virtual to allow extensions to add hook functionality
748
+ */
749
+ function _removeFunctionFromRole(bytes32 roleHash, bytes4 functionSelector) internal virtual {
750
+ EngineBlox.removeFunctionFromRole(_getSecureState(), roleHash, functionSelector);
751
+ }
752
+
753
+ // ============ PERMISSION VALIDATION ============
754
+
755
+ /**
756
+ * @dev Centralized function to validate that the caller has any role
757
+ */
758
+ function _validateAnyRole() internal view {
759
+ EngineBlox._validateAnyRole(_getSecureState());
760
+ }
761
+
762
+ /**
763
+ * @dev Centralized function to validate that a role exists
764
+ * @param roleHash The role hash to validate
765
+ */
766
+ function _validateRoleExists(bytes32 roleHash) internal view {
767
+ EngineBlox._validateRoleExists(_getSecureState(), roleHash);
768
+ }
769
+
770
+ /**
771
+ * @dev Centralized function to validate that the caller is the contract itself (for execution-only entry points).
772
+ */
773
+ function _validateExecuteBySelf() internal view {
774
+ SharedValidation.validateInternalCall(address(this));
775
+ }
776
+
777
+ /**
778
+ * @dev Centralized function to validate batch size against EngineBlox.MAX_BATCH_SIZE.
779
+ * @param length The batch length to validate
780
+ */
781
+ function _validateBatchSize(uint256 length) internal pure {
782
+ SharedValidation.validateBatchSize(length, EngineBlox.MAX_BATCH_SIZE);
783
+ }
784
+
785
+ // ============ MACRO SELECTORS ============
786
+
787
+ /**
788
+ * @dev Adds a function selector to the system macro selectors set.
789
+ * Macro selectors are allowed to target address(this) for system-level operations.
790
+ * @param functionSelector The function selector to add (e.g. NATIVE_TRANSFER_SELECTOR).
791
+ */
792
+ function _addMacroSelector(bytes4 functionSelector) internal {
793
+ EngineBlox.addMacroSelector(_getSecureState(), functionSelector);
794
+ }
795
+
796
+ /**
797
+ * @dev Returns true if the given function selector is in the system macro selectors set.
798
+ * @param functionSelector The function selector to check.
799
+ */
800
+ function _isMacroSelector(bytes4 functionSelector) internal view returns (bool) {
801
+ return EngineBlox.isMacroSelector(_getSecureState(), functionSelector);
802
+ }
803
+
804
+ // ============ UTILITY FUNCTIONS ============
805
+
806
+ /**
807
+ * @dev Centralized function to convert a bitmap to an array of actions
808
+ * @param bitmap The bitmap to convert
809
+ * @return Array of TxAction values
810
+ */
811
+ function _convertBitmapToActions(uint16 bitmap) internal pure returns (EngineBlox.TxAction[] memory) {
812
+ return EngineBlox.convertBitmapToActions(bitmap);
813
+ }
814
+
815
+ /**
816
+ * @dev Centralized function to create a bitmap from an array of actions
817
+ * @param actions Array of TxAction values
818
+ * @return The bitmap representation
819
+ */
820
+ function _createBitmapFromActions(EngineBlox.TxAction[] memory actions) internal pure returns (uint16) {
821
+ return EngineBlox.createBitmapFromActions(actions);
822
+ }
823
+
824
+ // ============ TARGET WHITELIST MANAGEMENT ============
825
+
826
+ /**
827
+ * @dev Centralized function to add a target address to the whitelist for a function selector
828
+ * @param functionSelector The function selector
829
+ * @param target The target address to whitelist
830
+ * @notice This function is virtual to allow extensions to add hook functionality
831
+ */
832
+ function _addTargetToWhitelist(bytes4 functionSelector, address target) internal virtual {
833
+ _getSecureState().addTargetToWhitelist(functionSelector, target);
834
+ }
835
+
836
+ /**
837
+ * @dev Centralized function to remove a target address from the whitelist for a function selector
838
+ * @param functionSelector The function selector
839
+ * @param target The target address to remove
840
+ * @notice This function is virtual to allow extensions to add hook functionality
841
+ */
842
+ function _removeTargetFromWhitelist(bytes4 functionSelector, address target) internal virtual {
843
+ _getSecureState().removeTargetFromWhitelist(functionSelector, target);
844
+ }
845
+
846
+ /**
847
+ * @dev Gets all whitelisted targets for a function selector
848
+ * @param functionSelector The function selector
849
+ * @return Array of whitelisted target addresses
850
+ * @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
851
+ */
852
+ function getFunctionWhitelistTargets(bytes4 functionSelector) public view returns (address[] memory) {
853
+ _validateAnyRole();
854
+ return _getSecureState().getFunctionWhitelistTargets(functionSelector);
855
+ }
856
+
857
+ // ============ DEFINITION LOADING ============
858
+
859
+ /**
860
+ * @dev Loads definitions directly into the secure state
861
+ * This function initializes the secure state with all predefined definitions
862
+ * @param functionSchemas Array of function schema definitions
863
+ * @param roleHashes Array of role hashes
864
+ * @param functionPermissions Array of function permissions (parallel to roleHashes)
865
+ * @param requireProtected When true, all function schemas must be protected; reverts if any is not
866
+ * @notice When requireProtected is true, every function schema must have isProtected == true
867
+ */
868
+ function _loadDefinitions(
869
+ EngineBlox.FunctionSchema[] memory functionSchemas,
870
+ bytes32[] memory roleHashes,
871
+ EngineBlox.FunctionPermission[] memory functionPermissions,
872
+ bool requireProtected
873
+ ) internal {
874
+ // Load function schemas
875
+ for (uint256 i = 0; i < functionSchemas.length; i++) {
876
+ // When enforcing, require every schema to be protected
877
+ if (requireProtected && !functionSchemas[i].isProtected) {
878
+ revert SharedValidation.ContractFunctionMustBeProtected(
879
+ functionSchemas[i].functionSelector
880
+ );
881
+ }
882
+ _registerFunction(
883
+ functionSchemas[i].functionSignature,
884
+ functionSchemas[i].functionSelector,
885
+ functionSchemas[i].operationName,
886
+ functionSchemas[i].supportedActionsBitmap,
887
+ functionSchemas[i].isProtected,
888
+ functionSchemas[i].handlerForSelectors
889
+ );
890
+ }
891
+
892
+ // Load role permissions using parallel arrays
893
+ SharedValidation.validateArrayLengthMatch(roleHashes.length, functionPermissions.length);
894
+ for (uint256 i = 0; i < roleHashes.length; i++) {
895
+ _addFunctionToRole(roleHashes[i], functionPermissions[i]);
896
+ }
897
+ }
898
+
899
+ // ============ INTERNAL UTILITIES ============
900
+
901
+ /**
902
+ * @dev Internal function to get the secure state
903
+ * @return secureState The secure state
904
+ */
905
+ function _getSecureState() internal view returns (EngineBlox.SecureOperationState storage) {
906
+ return _secureState;
907
+ }
908
+
909
+ /**
910
+ * @dev Internal function to check if an address has action permission
911
+ * @param caller The address to check
912
+ * @param functionSelector The function selector
913
+ * @param action The action to check
914
+ * @return True if the caller has permission, false otherwise
915
+ */
916
+ function _hasActionPermission(
917
+ address caller,
918
+ bytes4 functionSelector,
919
+ EngineBlox.TxAction action
920
+ ) internal view returns (bool) {
921
+ return _secureState.hasActionPermission(caller, functionSelector, action);
922
+ }
923
+
924
+ /**
925
+ * @dev Internal helper to validate that a caller has the BROADCASTER_ROLE
926
+ * @param caller The address to validate
927
+ */
928
+ function _validateBroadcaster(address caller) internal view {
929
+ if (!hasRole(EngineBlox.BROADCASTER_ROLE, caller)) {
930
+ revert SharedValidation.NoPermission(caller);
931
+ }
932
+ }
933
+
934
+ /**
935
+ * @dev Centralized component event logging for SecureOwnable, GuardController, RuntimeRBAC.
936
+ * Uses msg.sig as the event index so callers only pass encoded data.
937
+ * @param data abi.encode of event parameters
938
+ */
939
+ function _logComponentEvent(bytes memory data) internal {
940
+ emit ComponentEvent(msg.sig, data);
941
+ }
942
+
943
+ }