@bloxchain/contracts 1.0.0-alpha.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +8 -9
  3. package/abi/BaseStateMachine.abi.json +773 -822
  4. package/abi/EngineBlox.abi.json +562 -552
  5. package/abi/GuardController.abi.json +1597 -1609
  6. package/abi/GuardControllerDefinitions.abi.json +257 -120
  7. package/abi/IDefinition.abi.json +57 -47
  8. package/abi/RuntimeRBAC.abi.json +841 -842
  9. package/abi/RuntimeRBACDefinitions.abi.json +265 -99
  10. package/abi/SecureOwnable.abi.json +1365 -1349
  11. package/abi/SecureOwnableDefinitions.abi.json +174 -164
  12. package/components/README.md +8 -0
  13. package/core/AUDIT.md +45 -0
  14. package/core/access/RuntimeRBAC.sol +130 -61
  15. package/core/access/interface/IRuntimeRBAC.sol +3 -3
  16. package/core/access/lib/definitions/RuntimeRBACDefinitions.sol +67 -3
  17. package/core/base/BaseStateMachine.sol +971 -967
  18. package/core/base/interface/IBaseStateMachine.sol +153 -160
  19. package/core/execution/GuardController.sol +89 -75
  20. package/core/execution/interface/IGuardController.sol +146 -160
  21. package/core/execution/lib/definitions/GuardControllerDefinitions.sol +180 -24
  22. package/core/lib/EngineBlox.sol +577 -327
  23. package/core/lib/interfaces/IDefinition.sol +49 -49
  24. package/core/lib/interfaces/IEventForwarder.sol +4 -2
  25. package/core/lib/utils/SharedValidation.sol +534 -487
  26. package/core/pattern/Account.sol +84 -65
  27. package/core/security/SecureOwnable.sol +446 -390
  28. package/core/security/interface/ISecureOwnable.sol +105 -105
  29. package/core/security/lib/definitions/SecureOwnableDefinitions.sol +49 -17
  30. package/package.json +11 -7
  31. package/standards/README.md +12 -0
  32. package/{core/research → standards/behavior}/ICopyable.sol +3 -11
  33. package/standards/hooks/IOnActionHook.sol +21 -0
  34. package/abi/AccountBlox.abi.json +0 -3916
  35. package/abi/BareBlox.abi.json +0 -1378
  36. package/abi/RoleBlox.abi.json +0 -2983
  37. package/abi/SecureBlox.abi.json +0 -2753
  38. package/abi/SimpleRWA20.abi.json +0 -4032
  39. package/abi/SimpleRWA20Definitions.abi.json +0 -191
  40. package/abi/SimpleVault.abi.json +0 -3407
  41. package/abi/SimpleVaultDefinitions.abi.json +0 -269
  42. package/core/research/BloxchainWallet.sol +0 -292
  43. package/core/research/FactoryBlox/FactoryBlox.sol +0 -346
  44. package/core/research/FactoryBlox/FactoryBloxDefinitions.sol +0 -143
  45. package/core/research/erc1155-blox/ERC1155Blox.sol +0 -169
  46. package/core/research/erc1155-blox/lib/definitions/ERC1155BloxDefinitions.sol +0 -203
  47. package/core/research/erc20-blox/ERC20Blox.sol +0 -167
  48. package/core/research/erc20-blox/lib/definitions/ERC20BloxDefinitions.sol +0 -185
  49. package/core/research/erc721-blox/ERC721Blox.sol +0 -131
  50. package/core/research/erc721-blox/lib/definitions/ERC721BloxDefinitions.sol +0 -172
  51. package/core/research/lending-blox/.gitkeep +0 -1
  52. package/core/research/p2p-blox/P2PBlox.sol +0 -266
  53. package/core/research/p2p-blox/README.md +0 -85
  54. package/core/research/p2p-blox/lib/definitions/P2PBloxDefinitions.sol +0 -19
@@ -1,160 +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 function schema information
110
- * @param functionSelector The function selector to get information for
111
- * @return The full FunctionSchema struct
112
- */
113
- function getFunctionSchema(bytes4 functionSelector) external view returns (EngineBlox.FunctionSchema memory);
114
-
115
- /**
116
- * @dev Gets the function permissions for a specific role
117
- * @param roleHash The hash of the role to get permissions for
118
- * @return The function permissions array for the role
119
- */
120
- function getActiveRolePermissions(bytes32 roleHash) external view returns (EngineBlox.FunctionPermission[] memory);
121
-
122
- /**
123
- * @dev Gets the current nonce for a specific signer
124
- * @param signer The address of the signer
125
- * @return The current nonce for the signer
126
- */
127
- function getSignerNonce(address signer) external view returns (uint256);
128
-
129
- // ============ SYSTEM STATE QUERIES ============
130
-
131
- /**
132
- * @dev Returns the supported operation types
133
- * @return The supported operation types
134
- */
135
- function getSupportedOperationTypes() external view returns (bytes32[] memory);
136
-
137
- /**
138
- * @dev Returns the supported roles list
139
- * @return The supported roles list
140
- */
141
- function getSupportedRoles() external view returns (bytes32[] memory);
142
-
143
- /**
144
- * @dev Returns the supported functions list
145
- * @return The supported functions list
146
- */
147
- function getSupportedFunctions() external view returns (bytes4[] memory);
148
-
149
- /**
150
- * @dev Returns the time lock period
151
- * @return The time lock period in seconds
152
- */
153
- function getTimeLockPeriodSec() external view returns (uint256);
154
-
155
- /**
156
- * @dev Returns whether the contract is initialized
157
- * @return bool True if the contract is initialized, false otherwise
158
- */
159
- function initialized() external view returns (bool);
160
- }
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ pragma solidity 0.8.35;
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
+ * @notice Empty array if there are no transactions yet, or if the clamped range does not intersect **1..txCounter**.
75
+ */
76
+ function getTransactionHistory(uint256 fromTxId, uint256 toTxId) external view returns (EngineBlox.TxRecord[] memory);
77
+
78
+ /**
79
+ * @dev Gets a transaction by ID
80
+ * @param txId The transaction ID
81
+ * @return The transaction record
82
+ */
83
+ function getTransaction(uint256 txId) external view returns (EngineBlox.TxRecord memory);
84
+
85
+ /**
86
+ * @dev Gets all pending transaction IDs
87
+ * @return Array of pending transaction IDs
88
+ */
89
+ function getPendingTransactions() external view returns (uint256[] memory);
90
+
91
+ // ============ ROLE AND PERMISSION QUERIES ============
92
+
93
+ /**
94
+ * @dev Returns if a wallet is authorized for a role
95
+ * @param roleHash The hash of the role to check
96
+ * @param wallet The wallet address to check
97
+ * @return True if the wallet is authorized for the role, false otherwise
98
+ */
99
+ function hasRole(bytes32 roleHash, address wallet) external view returns (bool);
100
+
101
+ /**
102
+ * @dev Gets function schema information
103
+ * @param functionSelector The function selector to get information for
104
+ * @return The full FunctionSchema struct
105
+ */
106
+ function getFunctionSchema(bytes4 functionSelector) external view returns (EngineBlox.FunctionSchema memory);
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
+ }
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MPL-2.0
2
- pragma solidity 0.8.33;
2
+ pragma solidity 0.8.35;
3
3
 
4
4
  import "../base/BaseStateMachine.sol";
5
5
  import "../lib/utils/SharedValidation.sol";
@@ -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 should be registered via definitions or RuntimeRBAC if combined
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 a GuardController-specific security feature, not part of EngineBlox library
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
- // Initialize base state machine (only if not already initialized)
76
- if (!_secureState.initialized) {
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 // Allow protected schemas for factory settings
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 For standard function calls: value=0, functionSelector=non-zero, params=encoded data
114
- * @notice For simple native token transfers: value>0, functionSelector=NATIVE_TRANSFER_SELECTOR, params=""
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,
@@ -140,7 +137,7 @@ abstract contract GuardController is BaseStateMachine {
140
137
  /**
141
138
  * @dev Requests a time-locked execution with payment details attached (same permissions as executeWithTimeLock)
142
139
  * @param target The address of the target contract
143
- * @param value The ETH value to send (0 for standard function calls)
140
+ * @param value The ETH value to send (typically 0 for standard function calls; non-zero is supported for payable edge-case workflows)
144
141
  * @param functionSelector The function selector to execute (NATIVE_TRANSFER_SELECTOR for simple native token transfers)
145
142
  * @param params The encoded parameters for the function (empty for simple native token transfers)
146
143
  * @param gasLimit The gas limit for execution
@@ -177,7 +174,7 @@ abstract contract GuardController is BaseStateMachine {
177
174
  /**
178
175
  * @dev Approves and executes a time-locked transaction
179
176
  * @param txId The transaction ID
180
- * @return result The execution result
177
+ * @return txId The transaction ID
181
178
  * @notice Requires STANDARD execution type and EXECUTE_TIME_DELAY_APPROVE permission for the execution function
182
179
  */
183
180
  function approveTimeLockExecution(
@@ -195,7 +192,7 @@ abstract contract GuardController is BaseStateMachine {
195
192
  /**
196
193
  * @dev Cancels a time-locked transaction
197
194
  * @param txId The transaction ID
198
- * @return The updated transaction record
195
+ * @return The transaction ID
199
196
  * @notice Requires STANDARD execution type and EXECUTE_TIME_DELAY_CANCEL permission for the execution function
200
197
  */
201
198
  function cancelTimeLockExecution(
@@ -213,7 +210,7 @@ abstract contract GuardController is BaseStateMachine {
213
210
  /**
214
211
  * @dev Approves a time-locked transaction using a meta-transaction
215
212
  * @param metaTx The meta-transaction containing the transaction record and signature
216
- * @return The updated transaction record
213
+ * @return The transaction ID
217
214
  * @notice Requires STANDARD execution type and EXECUTE_META_APPROVE permission for the execution function
218
215
  */
219
216
  function approveTimeLockExecutionWithMetaTx(
@@ -230,7 +227,7 @@ abstract contract GuardController is BaseStateMachine {
230
227
  /**
231
228
  * @dev Cancels a time-locked transaction using a meta-transaction
232
229
  * @param metaTx The meta-transaction containing the transaction record and signature
233
- * @return The updated transaction record
230
+ * @return The transaction ID
234
231
  * @notice Requires STANDARD execution type and EXECUTE_META_CANCEL permission for the execution function
235
232
  */
236
233
  function cancelTimeLockExecutionWithMetaTx(
@@ -247,7 +244,7 @@ abstract contract GuardController is BaseStateMachine {
247
244
  /**
248
245
  * @dev Requests and approves a transaction in one step using a meta-transaction
249
246
  * @param metaTx The meta-transaction containing the transaction record and signature
250
- * @return The transaction record after request and approval
247
+ * @return The transaction ID
251
248
  * @notice Requires STANDARD execution type
252
249
  * @notice Validates function schema and permissions for the execution function (same as executeWithTimeLock)
253
250
  * @notice Requires EXECUTE_META_REQUEST_AND_APPROVE permission for the execution function selector
@@ -278,9 +275,8 @@ abstract contract GuardController is BaseStateMachine {
278
275
  * @param functionSelector The function selector to validate
279
276
  * @notice Internal functions use validateInternalCallInternal and should only be called
280
277
  * through the contract's own workflow, not via GuardController
281
- * @notice Blocks all calls to address(this) to prevent bypassing internal-only protection
282
- * @notice Exception: System macro selectors (e.g., NATIVE_TRANSFER_SELECTOR) are allowed
283
- * 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.
284
280
  */
285
281
  function _validateNotInternalFunction(
286
282
  address target,
@@ -308,13 +304,19 @@ abstract contract GuardController is BaseStateMachine {
308
304
  /**
309
305
  * @dev Requests and approves a Guard configuration batch using a meta-transaction
310
306
  * @param metaTx The meta-transaction
311
- * @return The transaction record
307
+ * @return The transaction ID
312
308
  * @notice OWNER signs, BROADCASTER executes according to GuardControllerDefinitions
313
309
  */
314
310
  function guardConfigBatchRequestAndApprove(
315
311
  EngineBlox.MetaTransaction memory metaTx
316
312
  ) public returns (uint256) {
317
313
  _validateBroadcaster(msg.sender);
314
+ SharedValidation.validateEmptyPayment(
315
+ metaTx.txRecord.payment.recipient,
316
+ metaTx.txRecord.payment.nativeTokenAmount,
317
+ metaTx.txRecord.payment.erc20TokenAddress,
318
+ metaTx.txRecord.payment.erc20TokenAmount
319
+ );
318
320
  EngineBlox.TxRecord memory txRecord = _requestAndApproveTransaction(metaTx);
319
321
  return txRecord.txId;
320
322
  }
@@ -341,41 +343,13 @@ abstract contract GuardController is BaseStateMachine {
341
343
  IGuardController.GuardConfigAction calldata action = actions[i];
342
344
 
343
345
  if (action.actionType == IGuardController.GuardConfigActionType.ADD_TARGET_TO_WHITELIST) {
344
- // Decode ADD_TARGET_TO_WHITELIST action data
345
- // Format: (bytes4 functionSelector, address target)
346
- (bytes4 functionSelector, address target) = abi.decode(action.data, (bytes4, address));
347
-
348
- _addTargetToFunctionWhitelist(functionSelector, target);
349
-
350
- _logComponentEvent(_encodeGuardConfigEvent(IGuardController.GuardConfigActionType.ADD_TARGET_TO_WHITELIST, functionSelector, target));
346
+ _executeAddTargetToWhitelist(action.data);
351
347
  } else if (action.actionType == IGuardController.GuardConfigActionType.REMOVE_TARGET_FROM_WHITELIST) {
352
- // Decode REMOVE_TARGET_FROM_WHITELIST action data
353
- // Format: (bytes4 functionSelector, address target)
354
- (bytes4 functionSelector, address target) = abi.decode(action.data, (bytes4, address));
355
-
356
- _removeTargetFromFunctionWhitelist(functionSelector, target);
357
-
358
- _logComponentEvent(_encodeGuardConfigEvent(IGuardController.GuardConfigActionType.REMOVE_TARGET_FROM_WHITELIST, functionSelector, target));
348
+ _executeRemoveTargetFromWhitelist(action.data);
359
349
  } else if (action.actionType == IGuardController.GuardConfigActionType.REGISTER_FUNCTION) {
360
- // Decode REGISTER_FUNCTION action data
361
- // Format: (string functionSignature, string operationName, TxAction[] supportedActions)
362
- (
363
- string memory functionSignature,
364
- string memory operationName,
365
- EngineBlox.TxAction[] memory supportedActions
366
- ) = abi.decode(action.data, (string, string, EngineBlox.TxAction[]));
367
-
368
- bytes4 functionSelector = _registerFunction(functionSignature, operationName, supportedActions);
369
-
370
- _logComponentEvent(_encodeGuardConfigEvent(IGuardController.GuardConfigActionType.REGISTER_FUNCTION, functionSelector, address(0)));
350
+ _executeRegisterFunction(action.data);
371
351
  } else if (action.actionType == IGuardController.GuardConfigActionType.UNREGISTER_FUNCTION) {
372
- // Decode UNREGISTER_FUNCTION action data
373
- // Format: (bytes4 functionSelector, bool safeRemoval)
374
- (bytes4 functionSelector, bool safeRemoval) = abi.decode(action.data, (bytes4, bool));
375
-
376
- _unregisterFunction(functionSelector, safeRemoval);
377
-
378
- _logComponentEvent(_encodeGuardConfigEvent(IGuardController.GuardConfigActionType.UNREGISTER_FUNCTION, functionSelector, address(0)));
352
+ _executeUnregisterFunction(action.data);
379
353
  } else {
380
354
  revert SharedValidation.NotSupported();
381
355
  }
@@ -383,14 +357,62 @@ abstract contract GuardController is BaseStateMachine {
383
357
  }
384
358
 
385
359
  /**
386
- * @dev Encodes guard config event payload for ComponentEvent. Decode as (GuardConfigActionType, bytes4 functionSelector, address target).
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)
387
372
  */
388
- function _encodeGuardConfigEvent(
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)
409
+ */
410
+ function _logGuardConfigEvent(
389
411
  IGuardController.GuardConfigActionType actionType,
390
412
  bytes4 functionSelector,
391
413
  address target
392
- ) internal pure returns (bytes memory) {
393
- return abi.encode(actionType, functionSelector, target);
414
+ ) internal {
415
+ _logComponentEvent(abi.encode(actionType, functionSelector, target));
394
416
  }
395
417
 
396
418
  // ============ INTERNAL FUNCTION SCHEMA HELPERS ============
@@ -402,7 +424,7 @@ abstract contract GuardController is BaseStateMachine {
402
424
  * @param supportedActions Array of supported actions
403
425
  * @return functionSelector The derived function selector
404
426
  */
405
- function _registerFunction(
427
+ function _registerGuardedFunction(
406
428
  string memory functionSignature,
407
429
  string memory operationName,
408
430
  EngineBlox.TxAction[] memory supportedActions
@@ -415,27 +437,19 @@ abstract contract GuardController is BaseStateMachine {
415
437
 
416
438
  // Create function schema directly (always non-protected)
417
439
  // Dynamically registered functions are execution selectors (handlerForSelectors must contain self-reference)
418
- // EngineBlox.createFunctionSchema validates schema doesn't already exist (ResourceAlreadyExists)
419
- bytes4[] memory executionHandlerForSelectors = new bytes4[](1);
420
- executionHandlerForSelectors[0] = functionSelector; // Self-reference for execution selector
421
- _createFunctionSchema(
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(
422
444
  functionSignature,
423
445
  functionSelector,
424
446
  operationName,
425
447
  supportedActionsBitmap,
448
+ true, // enforceHandlerRelations for dynamically registered execution selectors
426
449
  false, // isProtected = false for dynamically registered functions
427
- executionHandlerForSelectors // handlerForSelectors with self-reference for execution selectors
450
+ true, // isGrantRevocable: dynamically registered schemas may be revoked from roles
451
+ executionHandlers // handlerForSelectors with self-reference for execution selectors
428
452
  );
429
453
  }
430
454
 
431
- /**
432
- * @dev Internal helper to unregister a function schema
433
- * @param functionSelector The function selector to unregister
434
- * @param safeRemoval If true, checks for role references before removal
435
- * @notice EngineBlox.removeFunctionSchema validates schema existence (ResourceNotFound) and protected status (CannotModifyProtected)
436
- */
437
- function _unregisterFunction(bytes4 functionSelector, bool safeRemoval) internal {
438
- _removeFunctionSchema(functionSelector, safeRemoval);
439
- }
440
-
441
455
  }