@bloxchain/contracts 1.0.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -0
- package/abi/BareBlox.abi.json +1341 -0
- package/abi/BaseStateMachine.abi.json +1308 -0
- package/abi/ControlBlox.abi.json +6210 -0
- package/abi/EngineBlox.abi.json +872 -0
- package/abi/GuardController.abi.json +3045 -0
- package/abi/IDefinition.abi.json +94 -0
- package/abi/RoleBlox.abi.json +4569 -0
- package/abi/RuntimeRBAC.abi.json +1857 -0
- package/abi/RuntimeRBACDefinitions.abi.json +133 -0
- package/abi/SecureBlox.abi.json +4085 -0
- package/abi/SecureOwnable.abi.json +4085 -0
- package/abi/SecureOwnableDefinitions.abi.json +354 -0
- package/abi/SimpleRWA20.abi.json +5545 -0
- package/abi/SimpleRWA20Definitions.abi.json +172 -0
- package/abi/SimpleVault.abi.json +5208 -0
- package/abi/SimpleVaultDefinitions.abi.json +250 -0
- package/contracts/core/access/RuntimeRBAC.sol +344 -0
- package/contracts/core/access/interface/IRuntimeRBAC.sol +108 -0
- package/contracts/core/access/lib/definitions/RuntimeRBACDefinitions.sol +168 -0
- package/contracts/core/base/BaseStateMachine.sol +834 -0
- package/contracts/core/base/interface/IBaseStateMachine.sol +153 -0
- package/contracts/core/execution/GuardController.sol +507 -0
- package/contracts/core/execution/interface/IGuardController.sol +120 -0
- package/contracts/core/execution/lib/definitions/GuardControllerDefinitions.sol +401 -0
- package/contracts/core/lib/EngineBlox.sol +2283 -0
- package/contracts/core/security/SecureOwnable.sol +419 -0
- package/contracts/core/security/interface/ISecureOwnable.sol +118 -0
- package/contracts/core/security/lib/definitions/SecureOwnableDefinitions.sol +757 -0
- package/contracts/interfaces/IDefinition.sol +40 -0
- package/contracts/interfaces/IEventForwarder.sol +33 -0
- package/contracts/interfaces/IOnActionHook.sol +79 -0
- package/contracts/utils/SharedValidation.sol +486 -0
- package/package.json +47 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
pragma solidity 0.8.33;
|
|
3
|
+
|
|
4
|
+
// Contracts imports
|
|
5
|
+
import "../../lib/EngineBlox.sol";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @title IBaseStateMachine
|
|
9
|
+
* @dev Interface for BaseStateMachine functionality
|
|
10
|
+
*/
|
|
11
|
+
interface IBaseStateMachine {
|
|
12
|
+
// ============ CORE TRANSACTION MANAGEMENT ============
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @dev Creates meta-transaction parameters with specified values
|
|
16
|
+
* @param handlerContract The contract that will handle the meta-transaction
|
|
17
|
+
* @param handlerSelector The function selector for the handler
|
|
18
|
+
* @param action The transaction action type
|
|
19
|
+
* @param deadline The timestamp after which the meta-transaction expires
|
|
20
|
+
* @param maxGasPrice The maximum gas price allowed for execution
|
|
21
|
+
* @param signer The address that will sign the meta-transaction
|
|
22
|
+
* @return The formatted meta-transaction parameters
|
|
23
|
+
*/
|
|
24
|
+
function createMetaTxParams(
|
|
25
|
+
address handlerContract,
|
|
26
|
+
bytes4 handlerSelector,
|
|
27
|
+
EngineBlox.TxAction action,
|
|
28
|
+
uint256 deadline,
|
|
29
|
+
uint256 maxGasPrice,
|
|
30
|
+
address signer
|
|
31
|
+
) external view returns (EngineBlox.MetaTxParams memory);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @dev Generates an unsigned meta-transaction for a new operation
|
|
35
|
+
* @param requester The address requesting the operation
|
|
36
|
+
* @param target The target contract address
|
|
37
|
+
* @param value The ETH value to send
|
|
38
|
+
* @param gasLimit The gas limit for execution
|
|
39
|
+
* @param operationType The type of operation
|
|
40
|
+
* @param executionSelector The function selector to execute (0x00000000 for simple ETH transfers)
|
|
41
|
+
* @param executionParams The encoded parameters for the function (empty for simple ETH transfers)
|
|
42
|
+
* @param metaTxParams The meta-transaction parameters
|
|
43
|
+
* @return The unsigned meta-transaction
|
|
44
|
+
*/
|
|
45
|
+
function generateUnsignedMetaTransactionForNew(
|
|
46
|
+
address requester,
|
|
47
|
+
address target,
|
|
48
|
+
uint256 value,
|
|
49
|
+
uint256 gasLimit,
|
|
50
|
+
bytes32 operationType,
|
|
51
|
+
bytes4 executionSelector,
|
|
52
|
+
bytes memory executionParams,
|
|
53
|
+
EngineBlox.MetaTxParams memory metaTxParams
|
|
54
|
+
) external view returns (EngineBlox.MetaTransaction memory);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @dev Generates an unsigned meta-transaction for an existing transaction
|
|
58
|
+
* @param txId The ID of the existing transaction
|
|
59
|
+
* @param metaTxParams The meta-transaction parameters
|
|
60
|
+
* @return The unsigned meta-transaction
|
|
61
|
+
*/
|
|
62
|
+
function generateUnsignedMetaTransactionForExisting(
|
|
63
|
+
uint256 txId,
|
|
64
|
+
EngineBlox.MetaTxParams memory metaTxParams
|
|
65
|
+
) external view returns (EngineBlox.MetaTransaction memory);
|
|
66
|
+
|
|
67
|
+
// ============ STATE QUERIES ============
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @dev Gets transaction history within a specified range
|
|
71
|
+
* @param fromTxId The starting transaction ID (inclusive)
|
|
72
|
+
* @param toTxId The ending transaction ID (inclusive)
|
|
73
|
+
* @return The transaction history within the specified range
|
|
74
|
+
*/
|
|
75
|
+
function getTransactionHistory(uint256 fromTxId, uint256 toTxId) external view returns (EngineBlox.TxRecord[] memory);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @dev Gets a transaction by ID
|
|
79
|
+
* @param txId The transaction ID
|
|
80
|
+
* @return The transaction record
|
|
81
|
+
*/
|
|
82
|
+
function getTransaction(uint256 txId) external view returns (EngineBlox.TxRecord memory);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @dev Gets all pending transaction IDs
|
|
86
|
+
* @return Array of pending transaction IDs
|
|
87
|
+
*/
|
|
88
|
+
function getPendingTransactions() external view returns (uint256[] memory);
|
|
89
|
+
|
|
90
|
+
// ============ ROLE AND PERMISSION QUERIES ============
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @dev Returns if a wallet is authorized for a role
|
|
94
|
+
* @param roleHash The hash of the role to check
|
|
95
|
+
* @param wallet The wallet address to check
|
|
96
|
+
* @return True if the wallet is authorized for the role, false otherwise
|
|
97
|
+
*/
|
|
98
|
+
function hasRole(bytes32 roleHash, address wallet) external view returns (bool);
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @dev Returns if an action is supported by a function
|
|
102
|
+
* @param functionSelector The function selector to check
|
|
103
|
+
* @param action The action to check
|
|
104
|
+
* @return True if the action is supported by the function, false otherwise
|
|
105
|
+
*/
|
|
106
|
+
function isActionSupportedByFunction(bytes4 functionSelector, EngineBlox.TxAction action) external view returns (bool);
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @dev Gets the function permissions for a specific role
|
|
110
|
+
* @param roleHash The hash of the role to get permissions for
|
|
111
|
+
* @return The function permissions array for the role
|
|
112
|
+
*/
|
|
113
|
+
function getActiveRolePermissions(bytes32 roleHash) external view returns (EngineBlox.FunctionPermission[] memory);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @dev Gets the current nonce for a specific signer
|
|
117
|
+
* @param signer The address of the signer
|
|
118
|
+
* @return The current nonce for the signer
|
|
119
|
+
*/
|
|
120
|
+
function getSignerNonce(address signer) external view returns (uint256);
|
|
121
|
+
|
|
122
|
+
// ============ SYSTEM STATE QUERIES ============
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @dev Returns the supported operation types
|
|
126
|
+
* @return The supported operation types
|
|
127
|
+
*/
|
|
128
|
+
function getSupportedOperationTypes() external view returns (bytes32[] memory);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @dev Returns the supported roles list
|
|
132
|
+
* @return The supported roles list
|
|
133
|
+
*/
|
|
134
|
+
function getSupportedRoles() external view returns (bytes32[] memory);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @dev Returns the supported functions list
|
|
138
|
+
* @return The supported functions list
|
|
139
|
+
*/
|
|
140
|
+
function getSupportedFunctions() external view returns (bytes4[] memory);
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @dev Returns the time lock period
|
|
144
|
+
* @return The time lock period in seconds
|
|
145
|
+
*/
|
|
146
|
+
function getTimeLockPeriodSec() external view returns (uint256);
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @dev Returns whether the contract is initialized
|
|
150
|
+
* @return bool True if the contract is initialized, false otherwise
|
|
151
|
+
*/
|
|
152
|
+
function initialized() external view returns (bool);
|
|
153
|
+
}
|
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
pragma solidity 0.8.33;
|
|
3
|
+
|
|
4
|
+
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|
5
|
+
import "../base/BaseStateMachine.sol";
|
|
6
|
+
import "../../utils/SharedValidation.sol";
|
|
7
|
+
import "./lib/definitions/GuardControllerDefinitions.sol";
|
|
8
|
+
import "../../interfaces/IDefinition.sol";
|
|
9
|
+
import "./interface/IGuardController.sol";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @title GuardController
|
|
13
|
+
* @dev Lightweight controller for generic contract delegation with full EngineBlox workflows
|
|
14
|
+
*
|
|
15
|
+
* This contract provides a complete solution for delegating control to external addresses.
|
|
16
|
+
* It extends BaseStateMachine for core state machine functionality and supports all EngineBlox
|
|
17
|
+
* execution patterns including time-locked transactions, meta-transactions, and payment management.
|
|
18
|
+
*
|
|
19
|
+
* Key Features:
|
|
20
|
+
* - Core state machine functionality from BaseStateMachine
|
|
21
|
+
* - Function schema query support (functionSchemaExists)
|
|
22
|
+
* - STANDARD execution type only (function selector + params)
|
|
23
|
+
* - Meta-transaction support for delegated approvals and cancellations
|
|
24
|
+
* - Payment management for native tokens and ERC20 tokens
|
|
25
|
+
* - Role-based access control with action-level permissions
|
|
26
|
+
* - Target address whitelist per function selector (defense-in-depth security layer)
|
|
27
|
+
*
|
|
28
|
+
* Security Features:
|
|
29
|
+
* - Target whitelist: Strict security - restricts which contract addresses can be called per function selector
|
|
30
|
+
* - Prevents exploitation of global function selector permissions by limiting valid target contracts
|
|
31
|
+
* - Strict enforcement: Target MUST be explicitly whitelisted for the function selector
|
|
32
|
+
* - If whitelist is empty (no entries), no targets are allowed - explicit deny for security
|
|
33
|
+
* - Target whitelist is ALWAYS checked - no backward compatibility fallback
|
|
34
|
+
*
|
|
35
|
+
* Usage Flow:
|
|
36
|
+
* 1. Deploy GuardController (or combine with RuntimeRBAC/SecureOwnable for role management)
|
|
37
|
+
* 2. Function schemas should be registered via definitions or RuntimeRBAC if combined
|
|
38
|
+
* 3. Create roles and assign function permissions with action bitmaps (via RuntimeRBAC if combined)
|
|
39
|
+
* 4. Assign wallets to roles (via RuntimeRBAC if combined)
|
|
40
|
+
* 5. Configure target whitelists per function selector (REQUIRED for execution)
|
|
41
|
+
* 6. Execute operations via time-lock workflows based on action permissions
|
|
42
|
+
* 7. Target whitelist is ALWAYS validated before execution - target must be in whitelist
|
|
43
|
+
* 8. Target contract validates access (ownership/role-based)
|
|
44
|
+
*
|
|
45
|
+
* Workflows Available:
|
|
46
|
+
* - Standard execution: function selector + params
|
|
47
|
+
* - Time-locked approval: request + approve workflow
|
|
48
|
+
* - Meta-transaction workflows: signed approvals/cancellations
|
|
49
|
+
*
|
|
50
|
+
* Whitelist Management:
|
|
51
|
+
* - executeGuardConfigBatch: Batch execution for adding/removing targets from whitelist (OWNER_ROLE only)
|
|
52
|
+
* - getAllowedTargets: Query whitelisted targets for a function selector
|
|
53
|
+
*
|
|
54
|
+
* @notice This contract is modular and can be combined with RuntimeRBAC and SecureOwnable
|
|
55
|
+
* @notice Target whitelist is a GuardController-specific security feature, not part of EngineBlox library
|
|
56
|
+
* @custom:security-contact security@particlecrypto.com
|
|
57
|
+
*/
|
|
58
|
+
abstract contract GuardController is BaseStateMachine {
|
|
59
|
+
using EngineBlox for EngineBlox.SecureOperationState;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @dev Action types for batched Guard configuration
|
|
63
|
+
*/
|
|
64
|
+
enum GuardConfigActionType {
|
|
65
|
+
ADD_TARGET_TO_WHITELIST,
|
|
66
|
+
REMOVE_TARGET_FROM_WHITELIST,
|
|
67
|
+
REGISTER_FUNCTION,
|
|
68
|
+
UNREGISTER_FUNCTION
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @dev Encodes a single Guard configuration action in a batch
|
|
73
|
+
*/
|
|
74
|
+
struct GuardConfigAction {
|
|
75
|
+
GuardConfigActionType actionType;
|
|
76
|
+
bytes data;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============ EVENTS ============
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @dev Unified event for all Guard configuration changes applied via batches
|
|
83
|
+
*
|
|
84
|
+
* - actionType: the high-level type of configuration action
|
|
85
|
+
* - functionSelector: affected function selector (if applicable, otherwise 0)
|
|
86
|
+
* - target: affected target address (if applicable, otherwise 0)
|
|
87
|
+
* - data: optional action-specific payload (kept minimal for size; decoded off-chain if needed)
|
|
88
|
+
*/
|
|
89
|
+
event GuardConfigApplied(
|
|
90
|
+
GuardConfigActionType indexed actionType,
|
|
91
|
+
bytes4 indexed functionSelector,
|
|
92
|
+
address indexed target,
|
|
93
|
+
bytes data
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @notice Initializer to initialize GuardController
|
|
98
|
+
* @param initialOwner The initial owner address
|
|
99
|
+
* @param broadcaster The broadcaster address
|
|
100
|
+
* @param recovery The recovery address
|
|
101
|
+
* @param timeLockPeriodSec The timelock period in seconds
|
|
102
|
+
* @param eventForwarder The event forwarder address
|
|
103
|
+
*/
|
|
104
|
+
function initialize(
|
|
105
|
+
address initialOwner,
|
|
106
|
+
address broadcaster,
|
|
107
|
+
address recovery,
|
|
108
|
+
uint256 timeLockPeriodSec,
|
|
109
|
+
address eventForwarder
|
|
110
|
+
) public virtual onlyInitializing {
|
|
111
|
+
// Initialize base state machine (only if not already initialized)
|
|
112
|
+
if (!_secureState.initialized) {
|
|
113
|
+
_initializeBaseStateMachine(initialOwner, broadcaster, recovery, timeLockPeriodSec, eventForwarder);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Load GuardController-specific definitions
|
|
117
|
+
IDefinition.RolePermission memory guardControllerPermissions = GuardControllerDefinitions.getRolePermissions();
|
|
118
|
+
_loadDefinitions(
|
|
119
|
+
GuardControllerDefinitions.getFunctionSchemas(),
|
|
120
|
+
guardControllerPermissions.roleHashes,
|
|
121
|
+
guardControllerPermissions.functionPermissions
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ============ INTERFACE SUPPORT ============
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @dev See {IERC165-supportsInterface}.
|
|
129
|
+
* @notice Adds IGuardController interface ID for component detection
|
|
130
|
+
*/
|
|
131
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
132
|
+
return interfaceId == type(IGuardController).interfaceId || super.supportsInterface(interfaceId);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ============ EXECUTION FUNCTIONS ============
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @dev Requests a time-locked execution via EngineBlox workflow
|
|
139
|
+
* @param target The address of the target contract
|
|
140
|
+
* @param value The ETH value to send (0 for standard function calls)
|
|
141
|
+
* @param functionSelector The function selector to execute (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
|
|
142
|
+
* @param params The encoded parameters for the function (empty for simple native token transfers)
|
|
143
|
+
* @param gasLimit The gas limit for execution
|
|
144
|
+
* @param operationType The operation type hash
|
|
145
|
+
* @return txId The transaction ID for the requested operation
|
|
146
|
+
* @notice Creates a time-locked transaction that must be approved after the timelock period
|
|
147
|
+
* @notice Requires EXECUTE_TIME_DELAY_REQUEST permission for the function selector
|
|
148
|
+
* @notice For standard function calls: value=0, functionSelector=non-zero, params=encoded data
|
|
149
|
+
* @notice For simple native token transfers: value>0, functionSelector=NATIVE_TRANSFER_SELECTOR, params=""
|
|
150
|
+
*/
|
|
151
|
+
function executeWithTimeLock(
|
|
152
|
+
address target,
|
|
153
|
+
uint256 value,
|
|
154
|
+
bytes4 functionSelector,
|
|
155
|
+
bytes memory params,
|
|
156
|
+
uint256 gasLimit,
|
|
157
|
+
bytes32 operationType
|
|
158
|
+
) public returns (EngineBlox.TxRecord memory) {
|
|
159
|
+
// Validate inputs
|
|
160
|
+
SharedValidation.validateNotZeroAddress(target);
|
|
161
|
+
|
|
162
|
+
// SECURITY: Prevent access to internal execution functions
|
|
163
|
+
_validateNotInternalFunction(target, functionSelector);
|
|
164
|
+
|
|
165
|
+
// Request via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
166
|
+
EngineBlox.TxRecord memory txRecord = _requestTransaction(
|
|
167
|
+
msg.sender,
|
|
168
|
+
target,
|
|
169
|
+
value,
|
|
170
|
+
gasLimit,
|
|
171
|
+
operationType,
|
|
172
|
+
functionSelector,
|
|
173
|
+
params
|
|
174
|
+
);
|
|
175
|
+
return txRecord;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @dev Approves and executes a time-locked transaction
|
|
180
|
+
* @param txId The transaction ID
|
|
181
|
+
* @return result The execution result
|
|
182
|
+
* @notice Requires STANDARD execution type and EXECUTE_TIME_DELAY_APPROVE permission for the execution function
|
|
183
|
+
*/
|
|
184
|
+
function approveTimeLockExecution(
|
|
185
|
+
uint256 txId
|
|
186
|
+
) public returns (EngineBlox.TxRecord memory) {
|
|
187
|
+
// SECURITY: Prevent access to internal execution functions
|
|
188
|
+
EngineBlox.TxRecord memory txRecord = _getSecureState().txRecords[txId];
|
|
189
|
+
_validateNotInternalFunction(txRecord.params.target, txRecord.params.executionSelector);
|
|
190
|
+
|
|
191
|
+
// Approve via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
192
|
+
return _approveTransaction(txId);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @dev Cancels a time-locked transaction
|
|
197
|
+
* @param txId The transaction ID
|
|
198
|
+
* @return The updated transaction record
|
|
199
|
+
* @notice Requires STANDARD execution type and EXECUTE_TIME_DELAY_CANCEL permission for the execution function
|
|
200
|
+
*/
|
|
201
|
+
function cancelTimeLockExecution(
|
|
202
|
+
uint256 txId
|
|
203
|
+
) public returns (EngineBlox.TxRecord memory) {
|
|
204
|
+
// SECURITY: Prevent access to internal execution functions
|
|
205
|
+
EngineBlox.TxRecord memory txRecord = _getSecureState().txRecords[txId];
|
|
206
|
+
_validateNotInternalFunction(txRecord.params.target, txRecord.params.executionSelector);
|
|
207
|
+
|
|
208
|
+
// Cancel via BaseStateMachine helper (validates permissions in EngineBlox)
|
|
209
|
+
return _cancelTransaction(txId);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @dev Approves a time-locked transaction using a meta-transaction
|
|
214
|
+
* @param metaTx The meta-transaction containing the transaction record and signature
|
|
215
|
+
* @return The updated transaction record
|
|
216
|
+
* @notice Requires STANDARD execution type and EXECUTE_META_APPROVE permission for the execution function
|
|
217
|
+
*/
|
|
218
|
+
function approveTimeLockExecutionWithMetaTx(
|
|
219
|
+
EngineBlox.MetaTransaction memory metaTx
|
|
220
|
+
) public returns (EngineBlox.TxRecord memory) {
|
|
221
|
+
// SECURITY: Prevent access to internal execution functions
|
|
222
|
+
_validateNotInternalFunction(metaTx.txRecord.params.target, metaTx.txRecord.params.executionSelector);
|
|
223
|
+
|
|
224
|
+
// Approve via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
225
|
+
return _approveTransactionWithMetaTx(metaTx);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @dev Cancels a time-locked transaction using a meta-transaction
|
|
230
|
+
* @param metaTx The meta-transaction containing the transaction record and signature
|
|
231
|
+
* @return The updated transaction record
|
|
232
|
+
* @notice Requires STANDARD execution type and EXECUTE_META_CANCEL permission for the execution function
|
|
233
|
+
*/
|
|
234
|
+
function cancelTimeLockExecutionWithMetaTx(
|
|
235
|
+
EngineBlox.MetaTransaction memory metaTx
|
|
236
|
+
) public returns (EngineBlox.TxRecord memory) {
|
|
237
|
+
// SECURITY: Prevent access to internal execution functions
|
|
238
|
+
_validateNotInternalFunction(metaTx.txRecord.params.target, metaTx.txRecord.params.executionSelector);
|
|
239
|
+
|
|
240
|
+
// Cancel via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
241
|
+
return _cancelTransactionWithMetaTx(metaTx);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @dev Requests and approves a transaction in one step using a meta-transaction
|
|
246
|
+
* @param metaTx The meta-transaction containing the transaction record and signature
|
|
247
|
+
* @return The transaction record after request and approval
|
|
248
|
+
* @notice Requires STANDARD execution type
|
|
249
|
+
* @notice Validates function schema and permissions for the execution function (same as executeWithTimeLock)
|
|
250
|
+
* @notice Requires EXECUTE_META_REQUEST_AND_APPROVE permission for the execution function selector
|
|
251
|
+
*/
|
|
252
|
+
function requestAndApproveExecution(
|
|
253
|
+
EngineBlox.MetaTransaction memory metaTx
|
|
254
|
+
) public returns (EngineBlox.TxRecord memory) {
|
|
255
|
+
// SECURITY: Prevent access to internal execution functions
|
|
256
|
+
_validateNotInternalFunction(metaTx.txRecord.params.target, metaTx.txRecord.params.executionSelector);
|
|
257
|
+
|
|
258
|
+
// Request and approve via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
259
|
+
return _requestAndApproveTransaction(metaTx);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Note: Meta-transaction utility functions (createMetaTxParams,
|
|
263
|
+
// generateUnsignedMetaTransactionForNew, generateUnsignedMetaTransactionForExisting)
|
|
264
|
+
// are already available through inheritance from BaseStateMachine
|
|
265
|
+
//
|
|
266
|
+
// Note: Permission validation is handled by EngineBlox library functions
|
|
267
|
+
// which validate both function schema existence and RBAC permissions for execution selectors
|
|
268
|
+
|
|
269
|
+
// ============ INTERNAL VALIDATION HELPERS ============
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* @dev Checks if a function selector is a known system macro selector
|
|
273
|
+
* @param functionSelector The function selector to check
|
|
274
|
+
* @return true if the selector is a known system macro selector, false otherwise
|
|
275
|
+
* @notice System macro selectors are special selectors that represent system-level operations
|
|
276
|
+
* and are allowed to bypass certain security restrictions
|
|
277
|
+
* @notice Currently known macro selectors:
|
|
278
|
+
* - NATIVE_TRANSFER_SELECTOR: For native token transfers
|
|
279
|
+
*/
|
|
280
|
+
function _isSystemMacroSelector(bytes4 functionSelector) internal pure returns (bool) {
|
|
281
|
+
return functionSelector == EngineBlox.NATIVE_TRANSFER_SELECTOR
|
|
282
|
+
|| functionSelector == EngineBlox.UPDATE_PAYMENT_SELECTOR;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @dev Validates that GuardController is not attempting to access internal execution functions
|
|
287
|
+
* @param target The target contract address
|
|
288
|
+
* @param functionSelector The function selector to validate
|
|
289
|
+
* @notice Internal functions use validateInternalCallInternal and should only be called
|
|
290
|
+
* through the contract's own workflow, not via GuardController
|
|
291
|
+
* @notice Blocks all calls to address(this) to prevent bypassing internal-only protection
|
|
292
|
+
* @notice Exception: System macro selectors (e.g., NATIVE_TRANSFER_SELECTOR) are allowed
|
|
293
|
+
* to target address(this) for system-level operations like native token deposits
|
|
294
|
+
*/
|
|
295
|
+
function _validateNotInternalFunction(
|
|
296
|
+
address target,
|
|
297
|
+
bytes4 functionSelector
|
|
298
|
+
) internal view {
|
|
299
|
+
// SECURITY: Prevent GuardController from accessing internal execution functions
|
|
300
|
+
// Internal functions use validateInternalCallInternal and should only be called
|
|
301
|
+
// through the contract's own workflow, not via GuardController
|
|
302
|
+
|
|
303
|
+
// If target is this contract, we need to validate the function selector
|
|
304
|
+
if (target == address(this)) {
|
|
305
|
+
// Allow system macro selectors (e.g., NATIVE_TRANSFER_SELECTOR for native token deposits)
|
|
306
|
+
// These are special system-level operations that are safe to execute on address(this)
|
|
307
|
+
if (_isSystemMacroSelector(functionSelector)) {
|
|
308
|
+
return; // Allow system macro selectors
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Block all other calls to address(this) to prevent bypassing internal-only protection
|
|
312
|
+
revert SharedValidation.InternalFunctionNotAccessible(functionSelector);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ============ GUARD CONFIGURATION BATCH INTERFACE ============
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* @dev Creates execution params for a Guard configuration batch
|
|
320
|
+
* @param actions Encoded guard configuration actions
|
|
321
|
+
* @return The execution params for EngineBlox
|
|
322
|
+
*/
|
|
323
|
+
function guardConfigBatchExecutionParams(
|
|
324
|
+
GuardConfigAction[] memory actions
|
|
325
|
+
) public pure returns (bytes memory) {
|
|
326
|
+
return abi.encode(actions);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @dev Requests and approves a Guard configuration batch using a meta-transaction
|
|
331
|
+
* @param metaTx The meta-transaction
|
|
332
|
+
* @return The transaction record
|
|
333
|
+
* @notice OWNER signs, BROADCASTER executes according to GuardControllerDefinitions
|
|
334
|
+
*/
|
|
335
|
+
function guardConfigBatchRequestAndApprove(
|
|
336
|
+
EngineBlox.MetaTransaction memory metaTx
|
|
337
|
+
) public returns (EngineBlox.TxRecord memory) {
|
|
338
|
+
_validateBroadcaster(msg.sender);
|
|
339
|
+
SharedValidation.validateOwnerIsSigner(metaTx.params.signer, owner());
|
|
340
|
+
|
|
341
|
+
return _requestAndApproveTransaction(metaTx);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @dev External function that can only be called by the contract itself to execute a Guard configuration batch
|
|
346
|
+
* @param actions Encoded guard configuration actions
|
|
347
|
+
*/
|
|
348
|
+
function executeGuardConfigBatch(GuardConfigAction[] calldata actions) external {
|
|
349
|
+
SharedValidation.validateInternalCall(address(this));
|
|
350
|
+
_executeGuardConfigBatch(actions);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ============ HELPER FUNCTIONS ============
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* @dev Internal helper to execute a Guard configuration batch
|
|
357
|
+
* @param actions Encoded guard configuration actions
|
|
358
|
+
*/
|
|
359
|
+
function _executeGuardConfigBatch(GuardConfigAction[] calldata actions) internal {
|
|
360
|
+
// Validate batch size limit
|
|
361
|
+
SharedValidation.validateBatchSize(
|
|
362
|
+
actions.length,
|
|
363
|
+
EngineBlox.MAX_BATCH_SIZE
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
for (uint256 i = 0; i < actions.length; i++) {
|
|
367
|
+
GuardConfigAction calldata action = actions[i];
|
|
368
|
+
|
|
369
|
+
if (action.actionType == GuardConfigActionType.ADD_TARGET_TO_WHITELIST) {
|
|
370
|
+
// Decode ADD_TARGET_TO_WHITELIST action data
|
|
371
|
+
// Format: (bytes4 functionSelector, address target)
|
|
372
|
+
(bytes4 functionSelector, address target) = abi.decode(action.data, (bytes4, address));
|
|
373
|
+
|
|
374
|
+
_addTargetToFunctionWhitelist(functionSelector, target);
|
|
375
|
+
|
|
376
|
+
emit GuardConfigApplied(
|
|
377
|
+
GuardConfigActionType.ADD_TARGET_TO_WHITELIST,
|
|
378
|
+
functionSelector,
|
|
379
|
+
target,
|
|
380
|
+
"" // optional: could encode additional data if needed
|
|
381
|
+
);
|
|
382
|
+
} else if (action.actionType == GuardConfigActionType.REMOVE_TARGET_FROM_WHITELIST) {
|
|
383
|
+
// Decode REMOVE_TARGET_FROM_WHITELIST action data
|
|
384
|
+
// Format: (bytes4 functionSelector, address target)
|
|
385
|
+
(bytes4 functionSelector, address target) = abi.decode(action.data, (bytes4, address));
|
|
386
|
+
|
|
387
|
+
_removeTargetFromFunctionWhitelist(functionSelector, target);
|
|
388
|
+
|
|
389
|
+
emit GuardConfigApplied(
|
|
390
|
+
GuardConfigActionType.REMOVE_TARGET_FROM_WHITELIST,
|
|
391
|
+
functionSelector,
|
|
392
|
+
target,
|
|
393
|
+
""
|
|
394
|
+
);
|
|
395
|
+
} else if (action.actionType == GuardConfigActionType.REGISTER_FUNCTION) {
|
|
396
|
+
// Decode REGISTER_FUNCTION action data
|
|
397
|
+
// Format: (string functionSignature, string operationName, TxAction[] supportedActions)
|
|
398
|
+
(
|
|
399
|
+
string memory functionSignature,
|
|
400
|
+
string memory operationName,
|
|
401
|
+
EngineBlox.TxAction[] memory supportedActions
|
|
402
|
+
) = abi.decode(action.data, (string, string, EngineBlox.TxAction[]));
|
|
403
|
+
|
|
404
|
+
bytes4 functionSelector = _registerFunction(functionSignature, operationName, supportedActions);
|
|
405
|
+
|
|
406
|
+
emit GuardConfigApplied(
|
|
407
|
+
GuardConfigActionType.REGISTER_FUNCTION,
|
|
408
|
+
functionSelector,
|
|
409
|
+
address(0),
|
|
410
|
+
"" // optional: abi.encode(operationName)
|
|
411
|
+
);
|
|
412
|
+
} else if (action.actionType == GuardConfigActionType.UNREGISTER_FUNCTION) {
|
|
413
|
+
// Decode UNREGISTER_FUNCTION action data
|
|
414
|
+
// Format: (bytes4 functionSelector, bool safeRemoval)
|
|
415
|
+
(bytes4 functionSelector, bool safeRemoval) = abi.decode(action.data, (bytes4, bool));
|
|
416
|
+
|
|
417
|
+
_unregisterFunction(functionSelector, safeRemoval);
|
|
418
|
+
|
|
419
|
+
emit GuardConfigApplied(
|
|
420
|
+
GuardConfigActionType.UNREGISTER_FUNCTION,
|
|
421
|
+
functionSelector,
|
|
422
|
+
address(0),
|
|
423
|
+
""
|
|
424
|
+
);
|
|
425
|
+
} else {
|
|
426
|
+
revert SharedValidation.NotSupported();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ============ INTERNAL FUNCTION SCHEMA HELPERS ============
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* @dev Internal helper to register a new function schema
|
|
435
|
+
* @param functionSignature The function signature
|
|
436
|
+
* @param operationName The operation name
|
|
437
|
+
* @param supportedActions Array of supported actions
|
|
438
|
+
* @return functionSelector The derived function selector
|
|
439
|
+
*/
|
|
440
|
+
function _registerFunction(
|
|
441
|
+
string memory functionSignature,
|
|
442
|
+
string memory operationName,
|
|
443
|
+
EngineBlox.TxAction[] memory supportedActions
|
|
444
|
+
) internal returns (bytes4 functionSelector) {
|
|
445
|
+
// Derive function selector from signature
|
|
446
|
+
functionSelector = bytes4(keccak256(bytes(functionSignature)));
|
|
447
|
+
|
|
448
|
+
// Validate that function schema doesn't already exist
|
|
449
|
+
if (functionSchemaExists(functionSelector)) {
|
|
450
|
+
revert SharedValidation.ResourceAlreadyExists(bytes32(functionSelector));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Convert actions array to bitmap
|
|
454
|
+
uint16 supportedActionsBitmap = _createBitmapFromActions(supportedActions);
|
|
455
|
+
|
|
456
|
+
// Create function schema directly (always non-protected)
|
|
457
|
+
// Dynamically registered functions are execution selectors (handlerForSelectors must contain self-reference)
|
|
458
|
+
bytes4[] memory executionHandlerForSelectors = new bytes4[](1);
|
|
459
|
+
executionHandlerForSelectors[0] = functionSelector; // Self-reference for execution selector
|
|
460
|
+
_createFunctionSchema(
|
|
461
|
+
functionSignature,
|
|
462
|
+
functionSelector,
|
|
463
|
+
operationName,
|
|
464
|
+
supportedActionsBitmap,
|
|
465
|
+
false, // isProtected = false for dynamically registered functions
|
|
466
|
+
executionHandlerForSelectors // handlerForSelectors with self-reference for execution selectors
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* @dev Internal helper to unregister a function schema
|
|
472
|
+
* @param functionSelector The function selector to unregister
|
|
473
|
+
* @param safeRemoval If true, checks for role references before removal
|
|
474
|
+
*/
|
|
475
|
+
function _unregisterFunction(bytes4 functionSelector, bool safeRemoval) internal {
|
|
476
|
+
// Load schema and validate it exists
|
|
477
|
+
EngineBlox.FunctionSchema storage schema = _getSecureState().functions[functionSelector];
|
|
478
|
+
if (schema.functionSelector != functionSelector) {
|
|
479
|
+
revert SharedValidation.ResourceNotFound(bytes32(functionSelector));
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Ensure not protected
|
|
483
|
+
if (schema.isProtected) {
|
|
484
|
+
revert SharedValidation.CannotModifyProtected(bytes32(functionSelector));
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// The safeRemoval check is now handled within EngineBlox.removeFunctionSchema
|
|
488
|
+
// (avoids getSupportedRolesList/getRoleFunctionPermissions which call _validateAnyRole;
|
|
489
|
+
// during meta-tx execution msg.sender is the contract, causing NoPermission)
|
|
490
|
+
_removeFunctionSchema(functionSelector, safeRemoval);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* @dev Gets all whitelisted targets for a function selector
|
|
495
|
+
* @param functionSelector The function selector
|
|
496
|
+
* @return Array of whitelisted target addresses
|
|
497
|
+
* @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
|
|
498
|
+
*/
|
|
499
|
+
function getAllowedTargets(
|
|
500
|
+
bytes4 functionSelector
|
|
501
|
+
) external view returns (address[] memory) {
|
|
502
|
+
_validateAnyRole();
|
|
503
|
+
return _getFunctionWhitelistTargets(functionSelector);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
|