@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,250 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"inputs": [],
|
|
4
|
+
"name": "APPROVE_WITHDRAWAL_DELAYED_SELECTOR",
|
|
5
|
+
"outputs": [
|
|
6
|
+
{
|
|
7
|
+
"internalType": "bytes4",
|
|
8
|
+
"name": "",
|
|
9
|
+
"type": "bytes4"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"stateMutability": "view",
|
|
13
|
+
"type": "function"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"inputs": [],
|
|
17
|
+
"name": "APPROVE_WITHDRAWAL_META_SELECTOR",
|
|
18
|
+
"outputs": [
|
|
19
|
+
{
|
|
20
|
+
"internalType": "bytes4",
|
|
21
|
+
"name": "",
|
|
22
|
+
"type": "bytes4"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"stateMutability": "view",
|
|
26
|
+
"type": "function"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"inputs": [],
|
|
30
|
+
"name": "CANCEL_WITHDRAWAL_SELECTOR",
|
|
31
|
+
"outputs": [
|
|
32
|
+
{
|
|
33
|
+
"internalType": "bytes4",
|
|
34
|
+
"name": "",
|
|
35
|
+
"type": "bytes4"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"stateMutability": "view",
|
|
39
|
+
"type": "function"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"inputs": [],
|
|
43
|
+
"name": "GENERIC_APPROVAL",
|
|
44
|
+
"outputs": [
|
|
45
|
+
{
|
|
46
|
+
"internalType": "bytes32",
|
|
47
|
+
"name": "",
|
|
48
|
+
"type": "bytes32"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"stateMutability": "view",
|
|
52
|
+
"type": "function"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"inputs": [],
|
|
56
|
+
"name": "GENERIC_CANCELLATION",
|
|
57
|
+
"outputs": [
|
|
58
|
+
{
|
|
59
|
+
"internalType": "bytes32",
|
|
60
|
+
"name": "",
|
|
61
|
+
"type": "bytes32"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"stateMutability": "view",
|
|
65
|
+
"type": "function"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"inputs": [],
|
|
69
|
+
"name": "GENERIC_META_APPROVAL",
|
|
70
|
+
"outputs": [
|
|
71
|
+
{
|
|
72
|
+
"internalType": "bytes32",
|
|
73
|
+
"name": "",
|
|
74
|
+
"type": "bytes32"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"stateMutability": "view",
|
|
78
|
+
"type": "function"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"inputs": [],
|
|
82
|
+
"name": "WITHDRAW_ETH",
|
|
83
|
+
"outputs": [
|
|
84
|
+
{
|
|
85
|
+
"internalType": "bytes32",
|
|
86
|
+
"name": "",
|
|
87
|
+
"type": "bytes32"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"stateMutability": "view",
|
|
91
|
+
"type": "function"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"inputs": [],
|
|
95
|
+
"name": "WITHDRAW_ETH_REQUEST_SELECTOR",
|
|
96
|
+
"outputs": [
|
|
97
|
+
{
|
|
98
|
+
"internalType": "bytes4",
|
|
99
|
+
"name": "",
|
|
100
|
+
"type": "bytes4"
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"stateMutability": "view",
|
|
104
|
+
"type": "function"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"inputs": [],
|
|
108
|
+
"name": "WITHDRAW_ETH_SELECTOR",
|
|
109
|
+
"outputs": [
|
|
110
|
+
{
|
|
111
|
+
"internalType": "bytes4",
|
|
112
|
+
"name": "",
|
|
113
|
+
"type": "bytes4"
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"stateMutability": "view",
|
|
117
|
+
"type": "function"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"inputs": [],
|
|
121
|
+
"name": "WITHDRAW_TOKEN",
|
|
122
|
+
"outputs": [
|
|
123
|
+
{
|
|
124
|
+
"internalType": "bytes32",
|
|
125
|
+
"name": "",
|
|
126
|
+
"type": "bytes32"
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
"stateMutability": "view",
|
|
130
|
+
"type": "function"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"inputs": [],
|
|
134
|
+
"name": "WITHDRAW_TOKEN_REQUEST_SELECTOR",
|
|
135
|
+
"outputs": [
|
|
136
|
+
{
|
|
137
|
+
"internalType": "bytes4",
|
|
138
|
+
"name": "",
|
|
139
|
+
"type": "bytes4"
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
"stateMutability": "view",
|
|
143
|
+
"type": "function"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"inputs": [],
|
|
147
|
+
"name": "WITHDRAW_TOKEN_SELECTOR",
|
|
148
|
+
"outputs": [
|
|
149
|
+
{
|
|
150
|
+
"internalType": "bytes4",
|
|
151
|
+
"name": "",
|
|
152
|
+
"type": "bytes4"
|
|
153
|
+
}
|
|
154
|
+
],
|
|
155
|
+
"stateMutability": "view",
|
|
156
|
+
"type": "function"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"inputs": [],
|
|
160
|
+
"name": "getFunctionSchemas",
|
|
161
|
+
"outputs": [
|
|
162
|
+
{
|
|
163
|
+
"components": [
|
|
164
|
+
{
|
|
165
|
+
"internalType": "string",
|
|
166
|
+
"name": "functionSignature",
|
|
167
|
+
"type": "string"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"internalType": "bytes4",
|
|
171
|
+
"name": "functionSelector",
|
|
172
|
+
"type": "bytes4"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"internalType": "bytes32",
|
|
176
|
+
"name": "operationType",
|
|
177
|
+
"type": "bytes32"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"internalType": "string",
|
|
181
|
+
"name": "operationName",
|
|
182
|
+
"type": "string"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"internalType": "uint16",
|
|
186
|
+
"name": "supportedActionsBitmap",
|
|
187
|
+
"type": "uint16"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"internalType": "bool",
|
|
191
|
+
"name": "isProtected",
|
|
192
|
+
"type": "bool"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"internalType": "bytes4[]",
|
|
196
|
+
"name": "handlerForSelectors",
|
|
197
|
+
"type": "bytes4[]"
|
|
198
|
+
}
|
|
199
|
+
],
|
|
200
|
+
"internalType": "struct EngineBlox.FunctionSchema[]",
|
|
201
|
+
"name": "",
|
|
202
|
+
"type": "tuple[]"
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
"stateMutability": "pure",
|
|
206
|
+
"type": "function"
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"inputs": [],
|
|
210
|
+
"name": "getRolePermissions",
|
|
211
|
+
"outputs": [
|
|
212
|
+
{
|
|
213
|
+
"components": [
|
|
214
|
+
{
|
|
215
|
+
"internalType": "bytes32[]",
|
|
216
|
+
"name": "roleHashes",
|
|
217
|
+
"type": "bytes32[]"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"components": [
|
|
221
|
+
{
|
|
222
|
+
"internalType": "bytes4",
|
|
223
|
+
"name": "functionSelector",
|
|
224
|
+
"type": "bytes4"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"internalType": "uint16",
|
|
228
|
+
"name": "grantedActionsBitmap",
|
|
229
|
+
"type": "uint16"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"internalType": "bytes4[]",
|
|
233
|
+
"name": "handlerForSelectors",
|
|
234
|
+
"type": "bytes4[]"
|
|
235
|
+
}
|
|
236
|
+
],
|
|
237
|
+
"internalType": "struct EngineBlox.FunctionPermission[]",
|
|
238
|
+
"name": "functionPermissions",
|
|
239
|
+
"type": "tuple[]"
|
|
240
|
+
}
|
|
241
|
+
],
|
|
242
|
+
"internalType": "struct IDefinition.RolePermission",
|
|
243
|
+
"name": "",
|
|
244
|
+
"type": "tuple"
|
|
245
|
+
}
|
|
246
|
+
],
|
|
247
|
+
"stateMutability": "pure",
|
|
248
|
+
"type": "function"
|
|
249
|
+
}
|
|
250
|
+
]
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
pragma solidity 0.8.33;
|
|
3
|
+
|
|
4
|
+
// Contract imports
|
|
5
|
+
import "../base/BaseStateMachine.sol";
|
|
6
|
+
import "../lib/EngineBlox.sol";
|
|
7
|
+
import "../../utils/SharedValidation.sol";
|
|
8
|
+
import "./lib/definitions/RuntimeRBACDefinitions.sol";
|
|
9
|
+
import "../../interfaces/IDefinition.sol";
|
|
10
|
+
import "./interface/IRuntimeRBAC.sol";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @title RuntimeRBAC
|
|
14
|
+
* @dev Minimal Runtime Role-Based Access Control system based on EngineBlox
|
|
15
|
+
*
|
|
16
|
+
* This contract provides essential runtime RBAC functionality:
|
|
17
|
+
* - Creation of non-protected roles
|
|
18
|
+
* - Basic wallet assignment to roles
|
|
19
|
+
* - Function permission management per role
|
|
20
|
+
* - Integration with EngineBlox for secure operations
|
|
21
|
+
*
|
|
22
|
+
* Key Features:
|
|
23
|
+
* - Only non-protected roles can be created dynamically
|
|
24
|
+
* - Protected roles (OWNER, BROADCASTER, RECOVERY) are managed by SecureOwnable
|
|
25
|
+
* - Minimal interface for core RBAC operations
|
|
26
|
+
* - Essential role management functions only
|
|
27
|
+
*/
|
|
28
|
+
abstract contract RuntimeRBAC is BaseStateMachine {
|
|
29
|
+
using EngineBlox for EngineBlox.SecureOperationState;
|
|
30
|
+
using SharedValidation for *;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @dev Action types for batched RBAC configuration
|
|
34
|
+
*/
|
|
35
|
+
enum RoleConfigActionType {
|
|
36
|
+
CREATE_ROLE,
|
|
37
|
+
REMOVE_ROLE,
|
|
38
|
+
ADD_WALLET,
|
|
39
|
+
REVOKE_WALLET,
|
|
40
|
+
ADD_FUNCTION_TO_ROLE,
|
|
41
|
+
REMOVE_FUNCTION_FROM_ROLE
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @dev Encodes a single RBAC configuration action in a batch
|
|
46
|
+
*/
|
|
47
|
+
struct RoleConfigAction {
|
|
48
|
+
RoleConfigActionType actionType;
|
|
49
|
+
bytes data;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @dev Unified event for all RBAC configuration changes applied via batches
|
|
54
|
+
*
|
|
55
|
+
* - actionType: the high-level type of configuration action
|
|
56
|
+
* - roleHash: affected role hash (if applicable, otherwise 0)
|
|
57
|
+
* - functionSelector: affected function selector (if applicable, otherwise 0)
|
|
58
|
+
* - data: optional action-specific payload (kept minimal for size; decoded off-chain if needed)
|
|
59
|
+
*/
|
|
60
|
+
event RoleConfigApplied(
|
|
61
|
+
RoleConfigActionType indexed actionType,
|
|
62
|
+
bytes32 indexed roleHash,
|
|
63
|
+
bytes4 indexed functionSelector,
|
|
64
|
+
bytes data
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @notice Initializer to initialize RuntimeRBAC
|
|
69
|
+
* @param initialOwner The initial owner address
|
|
70
|
+
* @param broadcaster The broadcaster address
|
|
71
|
+
* @param recovery The recovery address
|
|
72
|
+
* @param timeLockPeriodSec The timelock period in seconds
|
|
73
|
+
* @param eventForwarder The event forwarder address
|
|
74
|
+
*/
|
|
75
|
+
function initialize(
|
|
76
|
+
address initialOwner,
|
|
77
|
+
address broadcaster,
|
|
78
|
+
address recovery,
|
|
79
|
+
uint256 timeLockPeriodSec,
|
|
80
|
+
address eventForwarder
|
|
81
|
+
) public virtual onlyInitializing {
|
|
82
|
+
// Initialize base state machine (only if not already initialized)
|
|
83
|
+
if (!_secureState.initialized) {
|
|
84
|
+
_initializeBaseStateMachine(initialOwner, broadcaster, recovery, timeLockPeriodSec, eventForwarder);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Load RuntimeRBAC-specific definitions
|
|
88
|
+
IDefinition.RolePermission memory permissions = RuntimeRBACDefinitions.getRolePermissions();
|
|
89
|
+
_loadDefinitions(
|
|
90
|
+
RuntimeRBACDefinitions.getFunctionSchemas(),
|
|
91
|
+
permissions.roleHashes,
|
|
92
|
+
permissions.functionPermissions
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ============ INTERFACE SUPPORT ============
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @dev See {IERC165-supportsInterface}.
|
|
100
|
+
* @notice Adds IRuntimeRBAC interface ID for component detection
|
|
101
|
+
*/
|
|
102
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
103
|
+
return interfaceId == type(IRuntimeRBAC).interfaceId || super.supportsInterface(interfaceId);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ============ ROLE CONFIGURATION BATCH INTERFACE ============
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @dev Creates execution params for a RBAC configuration batch
|
|
110
|
+
* @param actions Encoded role configuration actions
|
|
111
|
+
* @return The execution params for EngineBlox
|
|
112
|
+
*/
|
|
113
|
+
function roleConfigBatchExecutionParams(
|
|
114
|
+
RoleConfigAction[] memory actions
|
|
115
|
+
) public pure returns (bytes memory) {
|
|
116
|
+
return abi.encode(actions);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @dev Requests and approves a RBAC configuration batch using a meta-transaction
|
|
121
|
+
* @param metaTx The meta-transaction
|
|
122
|
+
* @return The transaction record
|
|
123
|
+
* @notice OWNER signs, BROADCASTER executes according to RuntimeRBACDefinitions
|
|
124
|
+
*/
|
|
125
|
+
function roleConfigBatchRequestAndApprove(
|
|
126
|
+
EngineBlox.MetaTransaction memory metaTx
|
|
127
|
+
) public returns (EngineBlox.TxRecord memory) {
|
|
128
|
+
_validateBroadcaster(msg.sender);
|
|
129
|
+
return _requestAndApproveTransaction(metaTx);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @dev External function that can only be called by the contract itself to execute a RBAC configuration batch
|
|
134
|
+
* @param actions Encoded role configuration actions
|
|
135
|
+
*/
|
|
136
|
+
function executeRoleConfigBatch(RoleConfigAction[] calldata actions) external {
|
|
137
|
+
SharedValidation.validateInternalCall(address(this));
|
|
138
|
+
_executeRoleConfigBatch(actions);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Essential Query Functions Only
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @dev Gets function schema information
|
|
145
|
+
* @param functionSelector The function selector to get information for
|
|
146
|
+
* @return functionSignature The function signature or name
|
|
147
|
+
* @return functionSelectorReturn The function selector
|
|
148
|
+
* @return operationType The operation type
|
|
149
|
+
* @return operationName The operation name
|
|
150
|
+
* @return supportedActions The supported actions
|
|
151
|
+
* @return isProtected Whether the function schema is protected
|
|
152
|
+
*/
|
|
153
|
+
function getFunctionSchema(bytes4 functionSelector) external view returns (
|
|
154
|
+
string memory functionSignature,
|
|
155
|
+
bytes4 functionSelectorReturn,
|
|
156
|
+
bytes32 operationType,
|
|
157
|
+
string memory operationName,
|
|
158
|
+
EngineBlox.TxAction[] memory supportedActions,
|
|
159
|
+
bool isProtected
|
|
160
|
+
) {
|
|
161
|
+
EngineBlox.FunctionSchema storage schema = _getSecureState().functions[functionSelector];
|
|
162
|
+
if (schema.functionSelector != functionSelector) {
|
|
163
|
+
revert SharedValidation.ResourceNotFound(bytes32(functionSelector));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Convert bitmap to array
|
|
167
|
+
supportedActions = _convertBitmapToActions(schema.supportedActionsBitmap);
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
schema.functionSignature,
|
|
171
|
+
schema.functionSelector,
|
|
172
|
+
schema.operationType,
|
|
173
|
+
schema.operationName,
|
|
174
|
+
supportedActions,
|
|
175
|
+
schema.isProtected
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @dev Gets all authorized wallets for a role
|
|
181
|
+
* @param roleHash The role hash to get wallets for
|
|
182
|
+
* @return Array of authorized wallet addresses
|
|
183
|
+
* @notice Requires caller to have any role (via _validateAnyRole) to limit information visibility
|
|
184
|
+
*/
|
|
185
|
+
function getWalletsInRole(bytes32 roleHash) public view returns (address[] memory) {
|
|
186
|
+
_validateAnyRole();
|
|
187
|
+
_validateRoleExists(roleHash);
|
|
188
|
+
|
|
189
|
+
// Get role info to determine wallet count
|
|
190
|
+
EngineBlox.Role storage role = _getSecureState().getRole(roleHash);
|
|
191
|
+
uint256 walletCount = role.walletCount;
|
|
192
|
+
|
|
193
|
+
// Build array by iterating through wallets using _getAuthorizedWalletAt
|
|
194
|
+
address[] memory wallets = new address[](walletCount);
|
|
195
|
+
for (uint256 i = 0; i < walletCount; i++) {
|
|
196
|
+
wallets[i] = _getAuthorizedWalletAt(roleHash, i);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return wallets;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ============ HELPER FUNCTIONS ============
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @dev Internal helper to execute a RBAC configuration batch
|
|
206
|
+
* @param actions Encoded role configuration actions
|
|
207
|
+
*/
|
|
208
|
+
function _executeRoleConfigBatch(RoleConfigAction[] calldata actions) internal {
|
|
209
|
+
// Validate batch size limit
|
|
210
|
+
SharedValidation.validateBatchSize(
|
|
211
|
+
actions.length,
|
|
212
|
+
EngineBlox.MAX_BATCH_SIZE
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
for (uint256 i = 0; i < actions.length; i++) {
|
|
216
|
+
RoleConfigAction calldata action = actions[i];
|
|
217
|
+
|
|
218
|
+
if (action.actionType == RoleConfigActionType.CREATE_ROLE) {
|
|
219
|
+
// Decode CREATE_ROLE action data
|
|
220
|
+
// Format: (string roleName, uint256 maxWallets, FunctionPermission[] functionPermissions)
|
|
221
|
+
// FunctionPermission is struct(bytes4 functionSelector, uint16 grantedActionsBitmap, bytes4 handlerForSelector)
|
|
222
|
+
// When encoding from JavaScript, it's encoded as tuple(bytes4,uint16,bytes4)[]
|
|
223
|
+
// Solidity can decode tuple[] directly into struct[] if the layout matches
|
|
224
|
+
(
|
|
225
|
+
string memory roleName,
|
|
226
|
+
uint256 maxWallets,
|
|
227
|
+
EngineBlox.FunctionPermission[] memory functionPermissions
|
|
228
|
+
) = abi.decode(action.data, (string, uint256, EngineBlox.FunctionPermission[]));
|
|
229
|
+
|
|
230
|
+
bytes32 roleHash = _createNewRole(roleName, maxWallets, functionPermissions);
|
|
231
|
+
|
|
232
|
+
emit RoleConfigApplied(
|
|
233
|
+
RoleConfigActionType.CREATE_ROLE,
|
|
234
|
+
roleHash,
|
|
235
|
+
bytes4(0),
|
|
236
|
+
"" // optional: abi.encode(roleName, maxWallets)
|
|
237
|
+
);
|
|
238
|
+
} else if (action.actionType == RoleConfigActionType.REMOVE_ROLE) {
|
|
239
|
+
(bytes32 roleHash) = abi.decode(action.data, (bytes32));
|
|
240
|
+
_removeRole(roleHash);
|
|
241
|
+
|
|
242
|
+
emit RoleConfigApplied(
|
|
243
|
+
RoleConfigActionType.REMOVE_ROLE,
|
|
244
|
+
roleHash,
|
|
245
|
+
bytes4(0),
|
|
246
|
+
""
|
|
247
|
+
);
|
|
248
|
+
} else if (action.actionType == RoleConfigActionType.ADD_WALLET) {
|
|
249
|
+
(bytes32 roleHash, address wallet) = abi.decode(action.data, (bytes32, address));
|
|
250
|
+
|
|
251
|
+
// Security check: Prevent editing protected roles
|
|
252
|
+
if (_getSecureState().roles[roleHash].isProtected) {
|
|
253
|
+
revert SharedValidation.CannotModifyProtected(roleHash);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
_assignWallet(roleHash, wallet);
|
|
257
|
+
|
|
258
|
+
emit RoleConfigApplied(
|
|
259
|
+
RoleConfigActionType.ADD_WALLET,
|
|
260
|
+
roleHash,
|
|
261
|
+
bytes4(0),
|
|
262
|
+
"" // optional: abi.encode(wallet)
|
|
263
|
+
);
|
|
264
|
+
} else if (action.actionType == RoleConfigActionType.REVOKE_WALLET) {
|
|
265
|
+
(bytes32 roleHash, address wallet) = abi.decode(action.data, (bytes32, address));
|
|
266
|
+
|
|
267
|
+
// Security check: Prevent editing protected roles
|
|
268
|
+
if (_getSecureState().roles[roleHash].isProtected) {
|
|
269
|
+
revert SharedValidation.CannotModifyProtected(roleHash);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
_revokeWallet(roleHash, wallet);
|
|
273
|
+
|
|
274
|
+
emit RoleConfigApplied(
|
|
275
|
+
RoleConfigActionType.REVOKE_WALLET,
|
|
276
|
+
roleHash,
|
|
277
|
+
bytes4(0),
|
|
278
|
+
"" // optional: abi.encode(wallet)
|
|
279
|
+
);
|
|
280
|
+
} else if (action.actionType == RoleConfigActionType.ADD_FUNCTION_TO_ROLE) {
|
|
281
|
+
(
|
|
282
|
+
bytes32 roleHash,
|
|
283
|
+
EngineBlox.FunctionPermission memory functionPermission
|
|
284
|
+
) = abi.decode(action.data, (bytes32, EngineBlox.FunctionPermission));
|
|
285
|
+
|
|
286
|
+
_addFunctionToRole(roleHash, functionPermission);
|
|
287
|
+
|
|
288
|
+
emit RoleConfigApplied(
|
|
289
|
+
RoleConfigActionType.ADD_FUNCTION_TO_ROLE,
|
|
290
|
+
roleHash,
|
|
291
|
+
functionPermission.functionSelector,
|
|
292
|
+
""
|
|
293
|
+
);
|
|
294
|
+
} else if (action.actionType == RoleConfigActionType.REMOVE_FUNCTION_FROM_ROLE) {
|
|
295
|
+
(bytes32 roleHash, bytes4 functionSelector) = abi.decode(action.data, (bytes32, bytes4));
|
|
296
|
+
_removeFunctionFromRole(roleHash, functionSelector);
|
|
297
|
+
|
|
298
|
+
emit RoleConfigApplied(
|
|
299
|
+
RoleConfigActionType.REMOVE_FUNCTION_FROM_ROLE,
|
|
300
|
+
roleHash,
|
|
301
|
+
functionSelector,
|
|
302
|
+
""
|
|
303
|
+
);
|
|
304
|
+
} else {
|
|
305
|
+
revert SharedValidation.NotSupported();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ============ INTERNAL ROLE / FUNCTION HELPERS ============
|
|
311
|
+
|
|
312
|
+
function _createNewRole(
|
|
313
|
+
string memory roleName,
|
|
314
|
+
uint256 maxWallets,
|
|
315
|
+
EngineBlox.FunctionPermission[] memory functionPermissions
|
|
316
|
+
) internal returns (bytes32 roleHash) {
|
|
317
|
+
SharedValidation.validateRoleNameNotEmpty(roleName);
|
|
318
|
+
SharedValidation.validateMaxWalletsGreaterThanZero(maxWallets);
|
|
319
|
+
|
|
320
|
+
roleHash = keccak256(bytes(roleName));
|
|
321
|
+
|
|
322
|
+
// Create the role in the secure state with isProtected = false
|
|
323
|
+
_createRole(roleName, maxWallets, false);
|
|
324
|
+
|
|
325
|
+
// Add all function permissions to the role
|
|
326
|
+
// NOTE: Function schemas must be registered BEFORE adding permissions to roles
|
|
327
|
+
// This is the same pattern used in _loadDefinitions: schemas first, then permissions
|
|
328
|
+
// The function selectors in functionPermissions must exist in supportedFunctionsSet
|
|
329
|
+
// (they should be registered during initialize() via RuntimeRBACDefinitions)
|
|
330
|
+
//
|
|
331
|
+
// CRITICAL: The order matters - _loadDefinitions loads schemas FIRST, then permissions
|
|
332
|
+
// In _createNewRole, we assume schemas are already registered (from initialize)
|
|
333
|
+
// If schemas aren't registered, addFunctionToRole will revert with ResourceNotFound
|
|
334
|
+
for (uint256 i = 0; i < functionPermissions.length; i++) {
|
|
335
|
+
// Add function permission to role
|
|
336
|
+
// addFunctionToRole will check:
|
|
337
|
+
// 1. Role exists in supportedRolesSet (✅ just created)
|
|
338
|
+
// 2. Function selector exists in supportedFunctionsSet (must be registered during initialize)
|
|
339
|
+
// 3. Actions are supported by function schema (via _validateMetaTxPermissions)
|
|
340
|
+
_addFunctionToRole(roleHash, functionPermissions[i]);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
pragma solidity 0.8.33;
|
|
3
|
+
|
|
4
|
+
import "../../lib/EngineBlox.sol";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @title IRuntimeRBAC
|
|
8
|
+
* @dev Interface for Runtime Role-Based Access Control system
|
|
9
|
+
*
|
|
10
|
+
* This interface defines the functions for managing runtime roles through batch operations.
|
|
11
|
+
* All role management operations are performed via the batch interface for atomic execution.
|
|
12
|
+
*
|
|
13
|
+
* Key Features:
|
|
14
|
+
* - Batch-based role configuration (atomic operations)
|
|
15
|
+
* - Runtime function schema registration
|
|
16
|
+
* - Integration with EngineBlox for secure operations
|
|
17
|
+
* - Query functions for role and permission inspection
|
|
18
|
+
*
|
|
19
|
+
* Note: This contract inherits from BaseStateMachine which provides additional query functions
|
|
20
|
+
* such as getRole(), hasRole(), getActiveRolePermissions(), getSupportedRoles(), etc.
|
|
21
|
+
*/
|
|
22
|
+
interface IRuntimeRBAC {
|
|
23
|
+
/**
|
|
24
|
+
* @dev Action types for batched RBAC configuration
|
|
25
|
+
*/
|
|
26
|
+
enum RoleConfigActionType {
|
|
27
|
+
CREATE_ROLE,
|
|
28
|
+
REMOVE_ROLE,
|
|
29
|
+
ADD_WALLET,
|
|
30
|
+
REVOKE_WALLET,
|
|
31
|
+
REGISTER_FUNCTION,
|
|
32
|
+
UNREGISTER_FUNCTION,
|
|
33
|
+
ADD_FUNCTION_TO_ROLE,
|
|
34
|
+
REMOVE_FUNCTION_FROM_ROLE,
|
|
35
|
+
LOAD_DEFINITIONS
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @dev Encodes a single RBAC configuration action in a batch
|
|
40
|
+
*/
|
|
41
|
+
struct RoleConfigAction {
|
|
42
|
+
RoleConfigActionType actionType;
|
|
43
|
+
bytes data;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @dev Unified event for all RBAC configuration changes applied via batches
|
|
48
|
+
* @param actionType The type of configuration action
|
|
49
|
+
* @param roleHash Affected role hash (if applicable, otherwise 0)
|
|
50
|
+
* @param functionSelector Affected function selector (if applicable, otherwise 0)
|
|
51
|
+
* @param data Optional action-specific payload
|
|
52
|
+
*/
|
|
53
|
+
event RoleConfigApplied(
|
|
54
|
+
RoleConfigActionType indexed actionType,
|
|
55
|
+
bytes32 indexed roleHash,
|
|
56
|
+
bytes4 indexed functionSelector,
|
|
57
|
+
bytes data
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// ============ ROLE CONFIGURATION BATCH INTERFACE ============
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @dev Creates execution params for a RBAC configuration batch
|
|
64
|
+
* @param actions Encoded role configuration actions
|
|
65
|
+
* @return The execution params for EngineBlox
|
|
66
|
+
*/
|
|
67
|
+
function roleConfigBatchExecutionParams(
|
|
68
|
+
RoleConfigAction[] memory actions
|
|
69
|
+
) external pure returns (bytes memory);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @dev Requests and approves a RBAC configuration batch using a meta-transaction
|
|
73
|
+
* @param metaTx The meta-transaction
|
|
74
|
+
* @return The transaction record
|
|
75
|
+
*/
|
|
76
|
+
function roleConfigBatchRequestAndApprove(
|
|
77
|
+
EngineBlox.MetaTransaction memory metaTx
|
|
78
|
+
) external returns (EngineBlox.TxRecord memory);
|
|
79
|
+
|
|
80
|
+
// ============ QUERY FUNCTIONS ============
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @dev Gets function schema information
|
|
84
|
+
* @param functionSelector The function selector to get information for
|
|
85
|
+
* @return functionSignature The function signature or name
|
|
86
|
+
* @return functionSelectorReturn The function selector
|
|
87
|
+
* @return operationType The operation type
|
|
88
|
+
* @return operationName The operation name
|
|
89
|
+
* @return supportedActions The supported actions
|
|
90
|
+
* @return isProtected Whether the function schema is protected
|
|
91
|
+
*/
|
|
92
|
+
function getFunctionSchema(bytes4 functionSelector) external view returns (
|
|
93
|
+
string memory functionSignature,
|
|
94
|
+
bytes4 functionSelectorReturn,
|
|
95
|
+
bytes32 operationType,
|
|
96
|
+
string memory operationName,
|
|
97
|
+
EngineBlox.TxAction[] memory supportedActions,
|
|
98
|
+
bool isProtected
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @dev Gets all authorized wallets for a role
|
|
103
|
+
* @param roleHash The role hash to get wallets for
|
|
104
|
+
* @return Array of authorized wallet addresses
|
|
105
|
+
* @notice Requires caller to have any role (via _validateAnyRole) for privacy protection
|
|
106
|
+
*/
|
|
107
|
+
function getWalletsInRole(bytes32 roleHash) external view returns (address[] memory);
|
|
108
|
+
}
|