@bloxchain/contracts 1.0.0-alpha.2 → 1.0.0-alpha.20
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 +7 -7
- package/abi/BaseStateMachine.abi.json +85 -45
- package/abi/EngineBlox.abi.json +73 -90
- package/abi/GuardController.abi.json +252 -806
- package/abi/{SimpleVaultDefinitions.abi.json → GuardControllerDefinitions.abi.json} +170 -28
- package/abi/IDefinition.abi.json +5 -0
- package/abi/RuntimeRBAC.abi.json +155 -218
- package/abi/RuntimeRBACDefinitions.abi.json +179 -0
- package/abi/SecureOwnable.abi.json +524 -1621
- package/abi/SecureOwnableDefinitions.abi.json +5 -0
- package/components/README.md +8 -0
- package/core/access/RuntimeRBAC.sol +255 -270
- package/core/access/interface/IRuntimeRBAC.sol +55 -84
- package/core/access/lib/definitions/RuntimeRBACDefinitions.sol +93 -2
- package/core/base/BaseStateMachine.sol +193 -107
- package/core/base/interface/IBaseStateMachine.sol +153 -153
- package/core/execution/GuardController.sol +155 -131
- package/core/execution/interface/IGuardController.sol +146 -120
- package/core/execution/lib/definitions/GuardControllerDefinitions.sol +193 -43
- package/core/lib/EngineBlox.sol +2683 -2322
- package/{interfaces → core/lib/interfaces}/IDefinition.sol +49 -49
- package/{interfaces → core/lib/interfaces}/IEventForwarder.sol +33 -33
- package/{utils → core/lib/utils}/SharedValidation.sol +61 -8
- package/core/pattern/Account.sol +84 -0
- package/core/security/SecureOwnable.sol +456 -412
- package/core/security/interface/ISecureOwnable.sol +105 -104
- package/core/security/lib/definitions/SecureOwnableDefinitions.sol +22 -6
- package/package.json +5 -5
- package/standards/README.md +12 -0
- package/standards/behavior/ICopyable.sol +34 -0
- package/standards/hooks/IOnActionHook.sol +21 -0
- package/abi/AccountBlox.abi.json +0 -5799
- package/abi/BareBlox.abi.json +0 -1284
- package/abi/RoleBlox.abi.json +0 -4209
- package/abi/SecureBlox.abi.json +0 -3828
- package/abi/SimpleRWA20.abi.json +0 -5288
- package/abi/SimpleRWA20Definitions.abi.json +0 -191
- package/abi/SimpleVault.abi.json +0 -4951
- package/core/research/BloxchainWallet.sol +0 -306
- package/core/research/erc20-blox/ERC20Blox.sol +0 -140
- package/core/research/erc20-blox/lib/definitions/ERC20BloxDefinitions.sol +0 -185
- package/interfaces/IOnActionHook.sol +0 -79
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity 0.8.34;
|
|
3
3
|
|
|
4
4
|
import "../base/BaseStateMachine.sol";
|
|
5
|
-
import "
|
|
5
|
+
import "../lib/utils/SharedValidation.sol";
|
|
6
6
|
import "./lib/definitions/GuardControllerDefinitions.sol";
|
|
7
|
-
import "
|
|
7
|
+
import "../lib/interfaces/IDefinition.sol";
|
|
8
8
|
import "./interface/IGuardController.sol";
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -17,7 +17,6 @@ import "./interface/IGuardController.sol";
|
|
|
17
17
|
*
|
|
18
18
|
* Key Features:
|
|
19
19
|
* - Core state machine functionality from BaseStateMachine
|
|
20
|
-
* - Function schema query support (functionSchemaExists)
|
|
21
20
|
* - STANDARD execution type only (function selector + params)
|
|
22
21
|
* - Meta-transaction support for delegated approvals and cancellations
|
|
23
22
|
* - Payment management for native tokens and ERC20 tokens
|
|
@@ -33,7 +32,7 @@ import "./interface/IGuardController.sol";
|
|
|
33
32
|
*
|
|
34
33
|
* Usage Flow:
|
|
35
34
|
* 1. Deploy GuardController (or combine with RuntimeRBAC/SecureOwnable for role management)
|
|
36
|
-
* 2. Function schemas
|
|
35
|
+
* 2. Function schemas are registered via definitions at init or via GuardController guard config batch (REGISTER_FUNCTION)
|
|
37
36
|
* 3. Create roles and assign function permissions with action bitmaps (via RuntimeRBAC if combined)
|
|
38
37
|
* 4. Assign wallets to roles (via RuntimeRBAC if combined)
|
|
39
38
|
* 5. Configure target whitelists per function selector (REQUIRED for execution)
|
|
@@ -51,7 +50,7 @@ import "./interface/IGuardController.sol";
|
|
|
51
50
|
* - getAllowedTargets: Query whitelisted targets for a function selector
|
|
52
51
|
*
|
|
53
52
|
* @notice This contract is modular and can be combined with RuntimeRBAC and SecureOwnable
|
|
54
|
-
* @notice Target whitelist is
|
|
53
|
+
* @notice Target whitelist **state** is enforced by **EngineBlox** (`_validateTargetWhitelist`); GuardController configures it via guard batches. Public execute paths here also apply **`_validateNotInternalFunction`**: self-target is limited to **macro** selectors unless extended by inheritors.
|
|
55
54
|
* @custom:security-contact security@particlecrypto.com
|
|
56
55
|
*/
|
|
57
56
|
abstract contract GuardController is BaseStateMachine {
|
|
@@ -72,18 +71,15 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
72
71
|
uint256 timeLockPeriodSec,
|
|
73
72
|
address eventForwarder
|
|
74
73
|
) public virtual onlyInitializing {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
_initializeBaseStateMachine(initialOwner, broadcaster, recovery, timeLockPeriodSec, eventForwarder);
|
|
78
|
-
}
|
|
79
|
-
|
|
74
|
+
_initializeBaseStateMachine(initialOwner, broadcaster, recovery, timeLockPeriodSec, eventForwarder);
|
|
75
|
+
|
|
80
76
|
// Load GuardController-specific definitions
|
|
81
77
|
IDefinition.RolePermission memory guardControllerPermissions = GuardControllerDefinitions.getRolePermissions();
|
|
82
78
|
_loadDefinitions(
|
|
83
79
|
GuardControllerDefinitions.getFunctionSchemas(),
|
|
84
80
|
guardControllerPermissions.roleHashes,
|
|
85
81
|
guardControllerPermissions.functionPermissions,
|
|
86
|
-
true //
|
|
82
|
+
true // Enforce all function schemas are protected
|
|
87
83
|
);
|
|
88
84
|
}
|
|
89
85
|
|
|
@@ -102,7 +98,7 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
102
98
|
/**
|
|
103
99
|
* @dev Requests a time-locked execution via EngineBlox workflow
|
|
104
100
|
* @param target The address of the target contract
|
|
105
|
-
* @param value The ETH value to send (0 for standard function calls)
|
|
101
|
+
* @param value The ETH value to send (typically 0 for standard function calls; non-zero is supported for payable edge-case workflows)
|
|
106
102
|
* @param functionSelector The function selector to execute (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
|
|
107
103
|
* @param params The encoded parameters for the function (empty for simple native token transfers)
|
|
108
104
|
* @param gasLimit The gas limit for execution
|
|
@@ -110,8 +106,9 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
110
106
|
* @return txId The transaction ID for the requested operation
|
|
111
107
|
* @notice Creates a time-locked transaction that must be approved after the timelock period
|
|
112
108
|
* @notice Requires EXECUTE_TIME_DELAY_REQUEST permission for the function selector
|
|
113
|
-
* @notice
|
|
114
|
-
* @notice
|
|
109
|
+
* @notice Recommended standard calls: value=0, functionSelector=non-zero, params=encoded data
|
|
110
|
+
* @notice Flexible edge case: non-native selectors may intentionally forward ETH to payable targets
|
|
111
|
+
* @notice Native-only convenience flow: value>0, functionSelector=NATIVE_TRANSFER_SELECTOR, params=""
|
|
115
112
|
*/
|
|
116
113
|
function executeWithTimeLock(
|
|
117
114
|
address target,
|
|
@@ -120,7 +117,7 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
120
117
|
bytes memory params,
|
|
121
118
|
uint256 gasLimit,
|
|
122
119
|
bytes32 operationType
|
|
123
|
-
) public returns (
|
|
120
|
+
) public returns (uint256 txId) {
|
|
124
121
|
// SECURITY: Prevent access to internal execution functions
|
|
125
122
|
_validateNotInternalFunction(target, functionSelector);
|
|
126
123
|
|
|
@@ -134,91 +131,133 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
134
131
|
functionSelector,
|
|
135
132
|
params
|
|
136
133
|
);
|
|
137
|
-
return txRecord;
|
|
134
|
+
return txRecord.txId;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @dev Requests a time-locked execution with payment details attached (same permissions as executeWithTimeLock)
|
|
139
|
+
* @param target The address of the target contract
|
|
140
|
+
* @param value The ETH value to send (typically 0 for standard function calls; non-zero is supported for payable edge-case workflows)
|
|
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
|
+
* @param paymentDetails The payment details to attach to the transaction
|
|
146
|
+
* @return txId The transaction ID for the requested operation (use getTransaction(txId) for full record)
|
|
147
|
+
* @notice Creates a time-locked transaction with payment that must be approved after the timelock period
|
|
148
|
+
* @notice Reuses EXECUTE_TIME_DELAY_REQUEST permission for the execution selector (no new definitions)
|
|
149
|
+
* @notice Approval/cancel use same flows as executeWithTimeLock (approveTimeLockExecution, cancelTimeLockExecution)
|
|
150
|
+
*/
|
|
151
|
+
function executeWithPayment(
|
|
152
|
+
address target,
|
|
153
|
+
uint256 value,
|
|
154
|
+
bytes4 functionSelector,
|
|
155
|
+
bytes memory params,
|
|
156
|
+
uint256 gasLimit,
|
|
157
|
+
bytes32 operationType,
|
|
158
|
+
EngineBlox.PaymentDetails memory paymentDetails
|
|
159
|
+
) public returns (uint256 txId) {
|
|
160
|
+
_validateNotInternalFunction(target, functionSelector);
|
|
161
|
+
EngineBlox.TxRecord memory txRecord = _requestTransactionWithPayment(
|
|
162
|
+
msg.sender,
|
|
163
|
+
target,
|
|
164
|
+
value,
|
|
165
|
+
gasLimit,
|
|
166
|
+
operationType,
|
|
167
|
+
functionSelector,
|
|
168
|
+
params,
|
|
169
|
+
paymentDetails
|
|
170
|
+
);
|
|
171
|
+
return txRecord.txId;
|
|
138
172
|
}
|
|
139
173
|
|
|
140
174
|
/**
|
|
141
175
|
* @dev Approves and executes a time-locked transaction
|
|
142
176
|
* @param txId The transaction ID
|
|
143
|
-
* @return
|
|
177
|
+
* @return txId The transaction ID
|
|
144
178
|
* @notice Requires STANDARD execution type and EXECUTE_TIME_DELAY_APPROVE permission for the execution function
|
|
145
179
|
*/
|
|
146
180
|
function approveTimeLockExecution(
|
|
147
181
|
uint256 txId
|
|
148
|
-
) public returns (
|
|
182
|
+
) public returns (uint256) {
|
|
149
183
|
// SECURITY: Prevent access to internal execution functions
|
|
150
184
|
EngineBlox.TxRecord memory txRecord = _getSecureState().txRecords[txId];
|
|
151
185
|
_validateNotInternalFunction(txRecord.params.target, txRecord.params.executionSelector);
|
|
152
186
|
|
|
153
187
|
// Approve via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
154
|
-
|
|
188
|
+
txRecord = _approveTransaction(txId);
|
|
189
|
+
return txRecord.txId;
|
|
155
190
|
}
|
|
156
191
|
|
|
157
192
|
/**
|
|
158
193
|
* @dev Cancels a time-locked transaction
|
|
159
194
|
* @param txId The transaction ID
|
|
160
|
-
* @return The
|
|
195
|
+
* @return The transaction ID
|
|
161
196
|
* @notice Requires STANDARD execution type and EXECUTE_TIME_DELAY_CANCEL permission for the execution function
|
|
162
197
|
*/
|
|
163
198
|
function cancelTimeLockExecution(
|
|
164
199
|
uint256 txId
|
|
165
|
-
) public returns (
|
|
200
|
+
) public returns (uint256) {
|
|
166
201
|
// SECURITY: Prevent access to internal execution functions
|
|
167
202
|
EngineBlox.TxRecord memory txRecord = _getSecureState().txRecords[txId];
|
|
168
203
|
_validateNotInternalFunction(txRecord.params.target, txRecord.params.executionSelector);
|
|
169
204
|
|
|
170
205
|
// Cancel via BaseStateMachine helper (validates permissions in EngineBlox)
|
|
171
|
-
|
|
206
|
+
txRecord = _cancelTransaction(txId);
|
|
207
|
+
return txRecord.txId;
|
|
172
208
|
}
|
|
173
209
|
|
|
174
210
|
/**
|
|
175
211
|
* @dev Approves a time-locked transaction using a meta-transaction
|
|
176
212
|
* @param metaTx The meta-transaction containing the transaction record and signature
|
|
177
|
-
* @return The
|
|
213
|
+
* @return The transaction ID
|
|
178
214
|
* @notice Requires STANDARD execution type and EXECUTE_META_APPROVE permission for the execution function
|
|
179
215
|
*/
|
|
180
216
|
function approveTimeLockExecutionWithMetaTx(
|
|
181
217
|
EngineBlox.MetaTransaction memory metaTx
|
|
182
|
-
) public returns (
|
|
218
|
+
) public returns (uint256) {
|
|
183
219
|
// SECURITY: Prevent access to internal execution functions
|
|
184
220
|
_validateNotInternalFunction(metaTx.txRecord.params.target, metaTx.txRecord.params.executionSelector);
|
|
185
221
|
|
|
186
222
|
// Approve via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
187
|
-
|
|
223
|
+
EngineBlox.TxRecord memory txRecord = _approveTransactionWithMetaTx(metaTx);
|
|
224
|
+
return txRecord.txId;
|
|
188
225
|
}
|
|
189
226
|
|
|
190
227
|
/**
|
|
191
228
|
* @dev Cancels a time-locked transaction using a meta-transaction
|
|
192
229
|
* @param metaTx The meta-transaction containing the transaction record and signature
|
|
193
|
-
* @return The
|
|
230
|
+
* @return The transaction ID
|
|
194
231
|
* @notice Requires STANDARD execution type and EXECUTE_META_CANCEL permission for the execution function
|
|
195
232
|
*/
|
|
196
233
|
function cancelTimeLockExecutionWithMetaTx(
|
|
197
234
|
EngineBlox.MetaTransaction memory metaTx
|
|
198
|
-
) public returns (
|
|
235
|
+
) public returns (uint256) {
|
|
199
236
|
// SECURITY: Prevent access to internal execution functions
|
|
200
237
|
_validateNotInternalFunction(metaTx.txRecord.params.target, metaTx.txRecord.params.executionSelector);
|
|
201
238
|
|
|
202
239
|
// Cancel via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
203
|
-
|
|
240
|
+
EngineBlox.TxRecord memory txRecord = _cancelTransactionWithMetaTx(metaTx);
|
|
241
|
+
return txRecord.txId;
|
|
204
242
|
}
|
|
205
243
|
|
|
206
244
|
/**
|
|
207
245
|
* @dev Requests and approves a transaction in one step using a meta-transaction
|
|
208
246
|
* @param metaTx The meta-transaction containing the transaction record and signature
|
|
209
|
-
* @return The transaction
|
|
247
|
+
* @return The transaction ID
|
|
210
248
|
* @notice Requires STANDARD execution type
|
|
211
249
|
* @notice Validates function schema and permissions for the execution function (same as executeWithTimeLock)
|
|
212
250
|
* @notice Requires EXECUTE_META_REQUEST_AND_APPROVE permission for the execution function selector
|
|
213
251
|
*/
|
|
214
252
|
function requestAndApproveExecution(
|
|
215
253
|
EngineBlox.MetaTransaction memory metaTx
|
|
216
|
-
) public returns (
|
|
254
|
+
) public returns (uint256) {
|
|
217
255
|
// SECURITY: Prevent access to internal execution functions
|
|
218
256
|
_validateNotInternalFunction(metaTx.txRecord.params.target, metaTx.txRecord.params.executionSelector);
|
|
219
257
|
|
|
220
258
|
// Request and approve via BaseStateMachine helper (validates permissions and whitelist in EngineBlox)
|
|
221
|
-
|
|
259
|
+
EngineBlox.TxRecord memory txRecord = _requestAndApproveTransaction(metaTx);
|
|
260
|
+
return txRecord.txId;
|
|
222
261
|
}
|
|
223
262
|
|
|
224
263
|
// Note: Meta-transaction utility functions (createMetaTxParams,
|
|
@@ -236,9 +275,8 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
236
275
|
* @param functionSelector The function selector to validate
|
|
237
276
|
* @notice Internal functions use validateInternalCallInternal and should only be called
|
|
238
277
|
* through the contract's own workflow, not via GuardController
|
|
239
|
-
* @notice
|
|
240
|
-
* @notice Exception:
|
|
241
|
-
* to target address(this) for system-level operations like native token deposits
|
|
278
|
+
* @notice Complements `EngineBlox._validateTargetWhitelist`, which **allows** `target == address(this)` for registered selectors so internal execution does not require listing `address(this)` on every whitelist. This helper **narrows GuardController’s surface**: self-target is rejected unless `functionSelector` is a **system macro** selector.
|
|
279
|
+
* @notice Exception path: macro selectors (e.g. `NATIVE_TRANSFER_SELECTOR`) may target `address(this)` for system-level operations such as native token flows.
|
|
242
280
|
*/
|
|
243
281
|
function _validateNotInternalFunction(
|
|
244
282
|
address target,
|
|
@@ -266,22 +304,28 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
266
304
|
/**
|
|
267
305
|
* @dev Requests and approves a Guard configuration batch using a meta-transaction
|
|
268
306
|
* @param metaTx The meta-transaction
|
|
269
|
-
* @return The transaction
|
|
307
|
+
* @return The transaction ID
|
|
270
308
|
* @notice OWNER signs, BROADCASTER executes according to GuardControllerDefinitions
|
|
271
309
|
*/
|
|
272
310
|
function guardConfigBatchRequestAndApprove(
|
|
273
311
|
EngineBlox.MetaTransaction memory metaTx
|
|
274
|
-
) public returns (
|
|
312
|
+
) public returns (uint256) {
|
|
275
313
|
_validateBroadcaster(msg.sender);
|
|
276
|
-
|
|
277
|
-
|
|
314
|
+
SharedValidation.validateEmptyPayment(
|
|
315
|
+
metaTx.txRecord.payment.recipient,
|
|
316
|
+
metaTx.txRecord.payment.nativeTokenAmount,
|
|
317
|
+
metaTx.txRecord.payment.erc20TokenAddress,
|
|
318
|
+
metaTx.txRecord.payment.erc20TokenAmount
|
|
319
|
+
);
|
|
320
|
+
EngineBlox.TxRecord memory txRecord = _requestAndApproveTransaction(metaTx);
|
|
321
|
+
return txRecord.txId;
|
|
278
322
|
}
|
|
279
323
|
|
|
280
324
|
/**
|
|
281
325
|
* @dev External function that can only be called by the contract itself to execute a Guard configuration batch
|
|
282
326
|
* @param actions Encoded guard configuration actions
|
|
283
327
|
*/
|
|
284
|
-
function executeGuardConfigBatch(
|
|
328
|
+
function executeGuardConfigBatch(IGuardController.GuardConfigAction[] calldata actions) external {
|
|
285
329
|
_validateExecuteBySelf();
|
|
286
330
|
_executeGuardConfigBatch(actions);
|
|
287
331
|
}
|
|
@@ -292,48 +336,20 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
292
336
|
* @dev Internal helper to execute a Guard configuration batch
|
|
293
337
|
* @param actions Encoded guard configuration actions
|
|
294
338
|
*/
|
|
295
|
-
function _executeGuardConfigBatch(
|
|
339
|
+
function _executeGuardConfigBatch(IGuardController.GuardConfigAction[] calldata actions) internal {
|
|
296
340
|
_validateBatchSize(actions.length);
|
|
297
341
|
|
|
298
342
|
for (uint256 i = 0; i < actions.length; i++) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (action.actionType ==
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
} else if (action.actionType == GuardControllerDefinitions.GuardConfigActionType.REMOVE_TARGET_FROM_WHITELIST) {
|
|
310
|
-
// Decode REMOVE_TARGET_FROM_WHITELIST action data
|
|
311
|
-
// Format: (bytes4 functionSelector, address target)
|
|
312
|
-
(bytes4 functionSelector, address target) = abi.decode(action.data, (bytes4, address));
|
|
313
|
-
|
|
314
|
-
_removeTargetFromFunctionWhitelist(functionSelector, target);
|
|
315
|
-
|
|
316
|
-
_logComponentEvent(_encodeGuardConfigEvent(GuardControllerDefinitions.GuardConfigActionType.REMOVE_TARGET_FROM_WHITELIST, functionSelector, target));
|
|
317
|
-
} else if (action.actionType == GuardControllerDefinitions.GuardConfigActionType.REGISTER_FUNCTION) {
|
|
318
|
-
// Decode REGISTER_FUNCTION action data
|
|
319
|
-
// Format: (string functionSignature, string operationName, TxAction[] supportedActions)
|
|
320
|
-
(
|
|
321
|
-
string memory functionSignature,
|
|
322
|
-
string memory operationName,
|
|
323
|
-
EngineBlox.TxAction[] memory supportedActions
|
|
324
|
-
) = abi.decode(action.data, (string, string, EngineBlox.TxAction[]));
|
|
325
|
-
|
|
326
|
-
bytes4 functionSelector = _registerFunction(functionSignature, operationName, supportedActions);
|
|
327
|
-
|
|
328
|
-
_logComponentEvent(_encodeGuardConfigEvent(GuardControllerDefinitions.GuardConfigActionType.REGISTER_FUNCTION, functionSelector, address(0)));
|
|
329
|
-
} else if (action.actionType == GuardControllerDefinitions.GuardConfigActionType.UNREGISTER_FUNCTION) {
|
|
330
|
-
// Decode UNREGISTER_FUNCTION action data
|
|
331
|
-
// Format: (bytes4 functionSelector, bool safeRemoval)
|
|
332
|
-
(bytes4 functionSelector, bool safeRemoval) = abi.decode(action.data, (bytes4, bool));
|
|
333
|
-
|
|
334
|
-
_unregisterFunction(functionSelector, safeRemoval);
|
|
335
|
-
|
|
336
|
-
_logComponentEvent(_encodeGuardConfigEvent(GuardControllerDefinitions.GuardConfigActionType.UNREGISTER_FUNCTION, functionSelector, address(0)));
|
|
343
|
+
IGuardController.GuardConfigAction calldata action = actions[i];
|
|
344
|
+
|
|
345
|
+
if (action.actionType == IGuardController.GuardConfigActionType.ADD_TARGET_TO_WHITELIST) {
|
|
346
|
+
_executeAddTargetToWhitelist(action.data);
|
|
347
|
+
} else if (action.actionType == IGuardController.GuardConfigActionType.REMOVE_TARGET_FROM_WHITELIST) {
|
|
348
|
+
_executeRemoveTargetFromWhitelist(action.data);
|
|
349
|
+
} else if (action.actionType == IGuardController.GuardConfigActionType.REGISTER_FUNCTION) {
|
|
350
|
+
_executeRegisterFunction(action.data);
|
|
351
|
+
} else if (action.actionType == IGuardController.GuardConfigActionType.UNREGISTER_FUNCTION) {
|
|
352
|
+
_executeUnregisterFunction(action.data);
|
|
337
353
|
} else {
|
|
338
354
|
revert SharedValidation.NotSupported();
|
|
339
355
|
}
|
|
@@ -341,14 +357,62 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
341
357
|
}
|
|
342
358
|
|
|
343
359
|
/**
|
|
344
|
-
* @dev
|
|
360
|
+
* @dev Executes ADD_TARGET_TO_WHITELIST: adds a target address to a function's call whitelist
|
|
361
|
+
* @param data ABI-encoded (bytes4 functionSelector, address target)
|
|
362
|
+
*/
|
|
363
|
+
function _executeAddTargetToWhitelist(bytes calldata data) internal {
|
|
364
|
+
(bytes4 functionSelector, address target) = abi.decode(data, (bytes4, address));
|
|
365
|
+
_addTargetToWhitelist(functionSelector, target);
|
|
366
|
+
_logGuardConfigEvent(IGuardController.GuardConfigActionType.ADD_TARGET_TO_WHITELIST, functionSelector, target);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* @dev Executes REMOVE_TARGET_FROM_WHITELIST: removes a target address from a function's call whitelist
|
|
371
|
+
* @param data ABI-encoded (bytes4 functionSelector, address target)
|
|
372
|
+
*/
|
|
373
|
+
function _executeRemoveTargetFromWhitelist(bytes calldata data) internal {
|
|
374
|
+
(bytes4 functionSelector, address target) = abi.decode(data, (bytes4, address));
|
|
375
|
+
_removeTargetFromWhitelist(functionSelector, target);
|
|
376
|
+
_logGuardConfigEvent(IGuardController.GuardConfigActionType.REMOVE_TARGET_FROM_WHITELIST, functionSelector, target);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @dev Executes REGISTER_FUNCTION: registers a new function schema with signature, operation name, and supported actions
|
|
381
|
+
* @param data ABI-encoded (string functionSignature, string operationName, TxAction[] supportedActions)
|
|
382
|
+
*/
|
|
383
|
+
function _executeRegisterFunction(bytes calldata data) internal {
|
|
384
|
+
(
|
|
385
|
+
string memory functionSignature,
|
|
386
|
+
string memory operationName,
|
|
387
|
+
EngineBlox.TxAction[] memory supportedActions
|
|
388
|
+
) = abi.decode(data, (string, string, EngineBlox.TxAction[]));
|
|
389
|
+
|
|
390
|
+
bytes4 functionSelector = _registerGuardedFunction(functionSignature, operationName, supportedActions);
|
|
391
|
+
_logGuardConfigEvent(IGuardController.GuardConfigActionType.REGISTER_FUNCTION, functionSelector, address(0));
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* @dev Executes UNREGISTER_FUNCTION: unregisters a function schema by selector
|
|
396
|
+
* @param data ABI-encoded (bytes4 functionSelector, bool safeRemoval)
|
|
397
|
+
*/
|
|
398
|
+
function _executeUnregisterFunction(bytes calldata data) internal {
|
|
399
|
+
(bytes4 functionSelector, bool safeRemoval) = abi.decode(data, (bytes4, bool));
|
|
400
|
+
_unregisterFunction(functionSelector, safeRemoval);
|
|
401
|
+
_logGuardConfigEvent(IGuardController.GuardConfigActionType.UNREGISTER_FUNCTION, functionSelector, address(0));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* @dev Encodes and logs a guard config event via ComponentEvent. Payload decodes as (GuardConfigActionType, bytes4 functionSelector, address target).
|
|
406
|
+
* @param actionType The guard config action type
|
|
407
|
+
* @param functionSelector The function selector (or zero for N/A)
|
|
408
|
+
* @param target The target address (or zero for N/A)
|
|
345
409
|
*/
|
|
346
|
-
function
|
|
347
|
-
|
|
410
|
+
function _logGuardConfigEvent(
|
|
411
|
+
IGuardController.GuardConfigActionType actionType,
|
|
348
412
|
bytes4 functionSelector,
|
|
349
413
|
address target
|
|
350
|
-
) internal
|
|
351
|
-
|
|
414
|
+
) internal {
|
|
415
|
+
_logComponentEvent(abi.encode(actionType, functionSelector, target));
|
|
352
416
|
}
|
|
353
417
|
|
|
354
418
|
// ============ INTERNAL FUNCTION SCHEMA HELPERS ============
|
|
@@ -360,7 +424,7 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
360
424
|
* @param supportedActions Array of supported actions
|
|
361
425
|
* @return functionSelector The derived function selector
|
|
362
426
|
*/
|
|
363
|
-
function
|
|
427
|
+
function _registerGuardedFunction(
|
|
364
428
|
string memory functionSignature,
|
|
365
429
|
string memory operationName,
|
|
366
430
|
EngineBlox.TxAction[] memory supportedActions
|
|
@@ -368,63 +432,23 @@ abstract contract GuardController is BaseStateMachine {
|
|
|
368
432
|
// Derive function selector from signature
|
|
369
433
|
functionSelector = bytes4(keccak256(bytes(functionSignature)));
|
|
370
434
|
|
|
371
|
-
// Validate that function schema doesn't already exist
|
|
372
|
-
if (functionSchemaExists(functionSelector)) {
|
|
373
|
-
revert SharedValidation.ResourceAlreadyExists(bytes32(functionSelector));
|
|
374
|
-
}
|
|
375
|
-
|
|
376
435
|
// Convert actions array to bitmap
|
|
377
436
|
uint16 supportedActionsBitmap = _createBitmapFromActions(supportedActions);
|
|
378
437
|
|
|
379
438
|
// Create function schema directly (always non-protected)
|
|
380
439
|
// Dynamically registered functions are execution selectors (handlerForSelectors must contain self-reference)
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
440
|
+
// EngineBlox.registerFunction validates schema doesn't already exist (ResourceAlreadyExists)
|
|
441
|
+
bytes4[] memory executionHandlers = new bytes4[](1);
|
|
442
|
+
executionHandlers[0] = functionSelector; // Self-reference for execution selector
|
|
443
|
+
_registerFunction(
|
|
384
444
|
functionSignature,
|
|
385
445
|
functionSelector,
|
|
386
446
|
operationName,
|
|
387
447
|
supportedActionsBitmap,
|
|
448
|
+
true, // enforceHandlerRelations for dynamically registered execution selectors
|
|
388
449
|
false, // isProtected = false for dynamically registered functions
|
|
389
|
-
|
|
450
|
+
executionHandlers // handlerForSelectors with self-reference for execution selectors
|
|
390
451
|
);
|
|
391
452
|
}
|
|
392
453
|
|
|
393
|
-
/**
|
|
394
|
-
* @dev Internal helper to unregister a function schema
|
|
395
|
-
* @param functionSelector The function selector to unregister
|
|
396
|
-
* @param safeRemoval If true, checks for role references before removal
|
|
397
|
-
*/
|
|
398
|
-
function _unregisterFunction(bytes4 functionSelector, bool safeRemoval) internal {
|
|
399
|
-
// Load schema and validate it exists
|
|
400
|
-
EngineBlox.FunctionSchema storage schema = _getSecureState().functions[functionSelector];
|
|
401
|
-
if (schema.functionSelector != functionSelector) {
|
|
402
|
-
revert SharedValidation.ResourceNotFound(bytes32(functionSelector));
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Ensure not protected
|
|
406
|
-
if (schema.isProtected) {
|
|
407
|
-
revert SharedValidation.CannotModifyProtected(bytes32(functionSelector));
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// The safeRemoval check is now handled within EngineBlox.removeFunctionSchema
|
|
411
|
-
// (avoids getSupportedRolesList/getRoleFunctionPermissions which call _validateAnyRole;
|
|
412
|
-
// during meta-tx execution msg.sender is the contract, causing NoPermission)
|
|
413
|
-
_removeFunctionSchema(functionSelector, safeRemoval);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
* @dev Gets all whitelisted targets for a function selector
|
|
418
|
-
* @param functionSelector The function selector
|
|
419
|
-
* @return Array of whitelisted target addresses
|
|
420
|
-
* @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
|
|
421
|
-
*/
|
|
422
|
-
function getAllowedTargets(
|
|
423
|
-
bytes4 functionSelector
|
|
424
|
-
) external view returns (address[] memory) {
|
|
425
|
-
_validateAnyRole();
|
|
426
|
-
return _getFunctionWhitelistTargets(functionSelector);
|
|
427
|
-
}
|
|
428
454
|
}
|
|
429
|
-
|
|
430
|
-
|