Skip to content

Commit 0e46031

Browse files
ashitakahxorsalgas1cent
authored
feat: access control (#52)
Co-authored-by: xorsal <[email protected]> Co-authored-by: Gas One Cent <[email protected]>
1 parent 96d1084 commit 0e46031

21 files changed

+1282
-290
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.19;
3+
4+
import {IAccessController} from '../interfaces/IAccessController.sol';
5+
import {IAccessModule} from '../interfaces/modules/access/IAccessModule.sol';
6+
7+
abstract contract CommonAccessController is IAccessController {
8+
/**
9+
* @notice Check whether the caller is authorized for the given parameters.
10+
* @param _accessModule The access module
11+
* @param _typehash The typehash
12+
* @param _typehashParams The params passed to the typehash
13+
* @param _accessControl The access control struct
14+
*/
15+
function _hasAccess(
16+
address _accessModule,
17+
bytes32 _typehash,
18+
bytes memory _typehashParams,
19+
AccessControl memory _accessControl
20+
) internal {
21+
bool _granted = IAccessModule(_accessModule).hasAccess(
22+
abi.encode(
23+
IAccessModule.AccessControlParameters({
24+
sender: msg.sender,
25+
accessControl: _accessControl,
26+
typehash: _typehash,
27+
typehashParams: _typehashParams
28+
})
29+
)
30+
);
31+
32+
if (!_granted) revert AccessController_NoAccess();
33+
}
34+
}

solidity/contracts/Oracle.sol

Lines changed: 114 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@ pragma solidity ^0.8.19;
33

44
import {IOracle} from '../interfaces/IOracle.sol';
55

6+
import {IAccessModule} from '../interfaces/modules/access/IAccessModule.sol';
67
import {IDisputeModule} from '../interfaces/modules/dispute/IDisputeModule.sol';
7-
88
import {IFinalityModule} from '../interfaces/modules/finality/IFinalityModule.sol';
99
import {IRequestModule} from '../interfaces/modules/request/IRequestModule.sol';
1010
import {IResolutionModule} from '../interfaces/modules/resolution/IResolutionModule.sol';
1111
import {IResponseModule} from '../interfaces/modules/response/IResponseModule.sol';
1212
import {ValidatorLib} from '../libraries/ValidatorLib.sol';
13+
import {OracleAccessController} from './OracleAccessController.sol';
14+
import {OracleTypehash} from './utils/OracleTypehash.sol';
1315

14-
contract Oracle is IOracle {
16+
contract Oracle is IOracle, OracleAccessController, OracleTypehash {
1517
using ValidatorLib for *;
1618

1719
/// @inheritdoc IOracle
@@ -44,31 +46,26 @@ contract Oracle is IOracle {
4446
/// @inheritdoc IOracle
4547
mapping(bytes32 _requestId => mapping(address _user => bool _isParticipant)) public isParticipant;
4648

49+
/// @inheritdoc IOracle
50+
uint256 public totalRequestCount;
51+
4752
/**
4853
* @notice The list of the response ids for each request
4954
*/
5055
mapping(bytes32 _requestId => bytes _responseIds) internal _responseIds;
5156

5257
/// @inheritdoc IOracle
53-
uint256 public totalRequestCount;
54-
55-
/// @inheritdoc IOracle
56-
function createRequest(Request calldata _request, bytes32 _ipfsHash) external returns (bytes32 _requestId) {
57-
_requestId = _createRequest(_request, _ipfsHash);
58-
}
58+
function getResponseIds(bytes32 _requestId) public view returns (bytes32[] memory _ids) {
59+
bytes memory _responses = _responseIds[_requestId];
60+
uint256 _length = _responses.length / 32;
5961

60-
/// @inheritdoc IOracle
61-
function createRequests(
62-
Request[] calldata _requestsData,
63-
bytes32[] calldata _ipfsHashes
64-
) external returns (bytes32[] memory _batchRequestsIds) {
65-
uint256 _requestsAmount = _requestsData.length;
66-
_batchRequestsIds = new bytes32[](_requestsAmount);
62+
assembly {
63+
for { let _i := 0 } lt(_i, _length) { _i := add(_i, 1) } {
64+
// Increase the size of the array
65+
mstore(_ids, add(mload(_ids), 1))
6766

68-
for (uint256 _i = 0; _i < _requestsAmount;) {
69-
_batchRequestsIds[_i] = _createRequest(_requestsData[_i], _ipfsHashes[_i]);
70-
unchecked {
71-
++_i;
67+
// Store the response id in the array
68+
mstore(add(_ids, add(32, mul(_i, 32))), mload(add(_responses, add(32, mul(_i, 32)))))
7269
}
7370
}
7471
}
@@ -98,11 +95,42 @@ contract Oracle is IOracle {
9895
}
9996
}
10097

98+
/// @inheritdoc IOracle
99+
function createRequest(
100+
Request calldata _request,
101+
bytes32 _ipfsHash,
102+
AccessControl calldata _accessControl
103+
) external returns (bytes32 _requestId) {
104+
_requestId = _createRequest(_request, _ipfsHash, _accessControl);
105+
}
106+
107+
/// @inheritdoc IOracle
108+
function createRequests(
109+
Request[] calldata _requestsData,
110+
bytes32[] calldata _ipfsHashes,
111+
AccessControl[] calldata _accessControl
112+
) external returns (bytes32[] memory _batchRequestsIds) {
113+
uint256 _requestsAmount = _requestsData.length;
114+
_batchRequestsIds = new bytes32[](_requestsAmount);
115+
116+
for (uint256 _i; _i < _requestsAmount;) {
117+
_batchRequestsIds[_i] = _createRequest(_requestsData[_i], _ipfsHashes[_i], _accessControl[_i]);
118+
unchecked {
119+
++_i;
120+
}
121+
}
122+
}
123+
101124
/// @inheritdoc IOracle
102125
function proposeResponse(
103126
Request calldata _request,
104-
Response calldata _response
105-
) external returns (bytes32 _responseId) {
127+
Response calldata _response,
128+
AccessControl calldata _accessControl
129+
)
130+
external
131+
hasAccess(_request.accessModule, PROPOSE_TYPEHASH, abi.encode(_request, _response), _accessControl)
132+
returns (bytes32 _responseId)
133+
{
106134
_responseId = ValidatorLib._validateResponse(_request, _response);
107135

108136
bytes32 _requestId = _response.requestId;
@@ -111,8 +139,8 @@ contract Oracle is IOracle {
111139
revert Oracle_InvalidRequest();
112140
}
113141

114-
// The caller must be the proposer, unless the response is coming from a dispute module
115-
if (msg.sender != _response.proposer && msg.sender != address(_request.disputeModule)) {
142+
// The user must be the proposer unless response comes from the dispute module
143+
if (_accessControl.user != _response.proposer && _accessControl.user != _request.disputeModule) {
116144
revert Oracle_InvalidProposer();
117145
}
118146

@@ -125,7 +153,7 @@ contract Oracle is IOracle {
125153
revert Oracle_AlreadyFinalized(_requestId);
126154
}
127155
isParticipant[_requestId][_response.proposer] = true;
128-
IResponseModule(_request.responseModule).propose(_request, _response, msg.sender);
156+
IResponseModule(_request.responseModule).propose(_request, _response, _accessControl.user);
129157
_responseIds[_requestId] = abi.encodePacked(_responseIds[_requestId], _responseId);
130158
responseCreatedAt[_responseId] = block.timestamp;
131159

@@ -136,8 +164,13 @@ contract Oracle is IOracle {
136164
function disputeResponse(
137165
Request calldata _request,
138166
Response calldata _response,
139-
Dispute calldata _dispute
140-
) external returns (bytes32 _disputeId) {
167+
Dispute calldata _dispute,
168+
AccessControl calldata _accessControl
169+
)
170+
external
171+
hasAccess(_request.accessModule, DISPUTE_TYPEHASH, abi.encode(_request, _response, _dispute), _accessControl)
172+
returns (bytes32 _disputeId)
173+
{
141174
bytes32 _responseId;
142175
(_responseId, _disputeId) = ValidatorLib._validateResponseAndDispute(_request, _response, _dispute);
143176

@@ -151,7 +184,7 @@ contract Oracle is IOracle {
151184
revert Oracle_InvalidProposer();
152185
}
153186

154-
if (_dispute.disputer != msg.sender) {
187+
if (_dispute.disputer != _accessControl.user) {
155188
revert Oracle_InvalidDisputer();
156189
}
157190

@@ -162,7 +195,7 @@ contract Oracle is IOracle {
162195
if (disputeOf[_responseId] != bytes32(0)) {
163196
revert Oracle_ResponseAlreadyDisputed(_responseId);
164197
}
165-
isParticipant[_requestId][msg.sender] = true;
198+
isParticipant[_requestId][_accessControl.user] = true;
166199
disputeStatus[_disputeId] = DisputeStatus.Active;
167200
disputeOf[_responseId] = _disputeId;
168201
disputeCreatedAt[_disputeId] = block.timestamp;
@@ -173,7 +206,15 @@ contract Oracle is IOracle {
173206
}
174207

175208
/// @inheritdoc IOracle
176-
function escalateDispute(Request calldata _request, Response calldata _response, Dispute calldata _dispute) external {
209+
function escalateDispute(
210+
Request calldata _request,
211+
Response calldata _response,
212+
Dispute calldata _dispute,
213+
AccessControl calldata _accessControl
214+
)
215+
external
216+
hasAccess(_request.accessModule, ESCALATE_TYPEHASH, abi.encode(_request, _response, _dispute), _accessControl)
217+
{
177218
(bytes32 _responseId, bytes32 _disputeId) = ValidatorLib._validateResponseAndDispute(_request, _response, _dispute);
178219

179220
if (disputeCreatedAt[_disputeId] == 0) {
@@ -194,16 +235,24 @@ contract Oracle is IOracle {
194235
// Notify the dispute module about the escalation
195236
IDisputeModule(_request.disputeModule).onDisputeStatusChange(_disputeId, _request, _response, _dispute);
196237

197-
emit DisputeEscalated(msg.sender, _disputeId, _dispute);
238+
emit DisputeEscalated(_accessControl.user, _disputeId, _dispute);
198239

199-
if (address(_request.resolutionModule) != address(0)) {
240+
if (_request.resolutionModule != address(0)) {
200241
// Initiate the resolution
201242
IResolutionModule(_request.resolutionModule).startResolution(_disputeId, _request, _response, _dispute);
202243
}
203244
}
204245

205246
/// @inheritdoc IOracle
206-
function resolveDispute(Request calldata _request, Response calldata _response, Dispute calldata _dispute) external {
247+
function resolveDispute(
248+
Request calldata _request,
249+
Response calldata _response,
250+
Dispute calldata _dispute,
251+
AccessControl calldata _accessControl
252+
)
253+
external
254+
hasAccess(_request.accessModule, RESOLVE_TYPEHASH, abi.encode(_request, _response, _dispute), _accessControl)
255+
{
207256
(bytes32 _responseId, bytes32 _disputeId) = ValidatorLib._validateResponseAndDispute(_request, _response, _dispute);
208257

209258
if (disputeCreatedAt[_disputeId] == 0) {
@@ -220,13 +269,13 @@ contract Oracle is IOracle {
220269
revert Oracle_CannotResolve(_disputeId);
221270
}
222271

223-
if (address(_request.resolutionModule) == address(0)) {
272+
if (_request.resolutionModule == address(0)) {
224273
revert Oracle_NoResolutionModule(_disputeId);
225274
}
226275

227276
IResolutionModule(_request.resolutionModule).resolveDispute(_disputeId, _request, _response, _dispute);
228277

229-
emit DisputeResolved(_disputeId, _dispute, msg.sender);
278+
emit DisputeResolved(_disputeId, _dispute);
230279
}
231280

232281
/// @inheritdoc IOracle
@@ -246,7 +295,7 @@ contract Oracle is IOracle {
246295
revert Oracle_InvalidDisputeId(_disputeId);
247296
}
248297

249-
if (msg.sender != address(_request.disputeModule) && msg.sender != address(_request.resolutionModule)) {
298+
if (msg.sender != _request.disputeModule && msg.sender != _request.resolutionModule) {
250299
revert Oracle_NotDisputeOrResolutionModule(msg.sender);
251300
}
252301
disputeStatus[_disputeId] = _status;
@@ -256,23 +305,11 @@ contract Oracle is IOracle {
256305
}
257306

258307
/// @inheritdoc IOracle
259-
function getResponseIds(bytes32 _requestId) public view returns (bytes32[] memory _ids) {
260-
bytes memory _responses = _responseIds[_requestId];
261-
uint256 _length = _responses.length / 32;
262-
263-
assembly {
264-
for { let _i := 0 } lt(_i, _length) { _i := add(_i, 1) } {
265-
// Increase the size of the array
266-
mstore(_ids, add(mload(_ids), 1))
267-
268-
// Store the response id in the array
269-
mstore(add(_ids, add(32, mul(_i, 32))), mload(add(_responses, add(32, mul(_i, 32)))))
270-
}
271-
}
272-
}
273-
274-
/// @inheritdoc IOracle
275-
function finalize(IOracle.Request calldata _request, IOracle.Response calldata _response) external {
308+
function finalize(
309+
IOracle.Request calldata _request,
310+
IOracle.Response calldata _response,
311+
AccessControl calldata _accessControl
312+
) external hasAccess(_request.accessModule, FINALIZE_TYPEHASH, abi.encode(_request, _response), _accessControl) {
276313
bytes32 _requestId;
277314
bytes32 _responseId;
278315

@@ -289,19 +326,23 @@ contract Oracle is IOracle {
289326

290327
finalizedAt[_requestId] = block.timestamp;
291328

292-
if (address(_request.finalityModule) != address(0)) {
293-
IFinalityModule(_request.finalityModule).finalizeRequest(_request, _response, msg.sender);
329+
if (_request.finalityModule != address(0)) {
330+
IFinalityModule(_request.finalityModule).finalizeRequest(_request, _response, _accessControl.user);
294331
}
295332

296-
if (address(_request.resolutionModule) != address(0)) {
297-
IResolutionModule(_request.resolutionModule).finalizeRequest(_request, _response, msg.sender);
333+
if (_request.resolutionModule != address(0)) {
334+
IResolutionModule(_request.resolutionModule).finalizeRequest(_request, _response, _accessControl.user);
298335
}
299336

300-
IDisputeModule(_request.disputeModule).finalizeRequest(_request, _response, msg.sender);
301-
IResponseModule(_request.responseModule).finalizeRequest(_request, _response, msg.sender);
302-
IRequestModule(_request.requestModule).finalizeRequest(_request, _response, msg.sender);
337+
IDisputeModule(_request.disputeModule).finalizeRequest(_request, _response, _accessControl.user);
338+
IResponseModule(_request.responseModule).finalizeRequest(_request, _response, _accessControl.user);
339+
IRequestModule(_request.requestModule).finalizeRequest(_request, _response, _accessControl.user);
340+
341+
if (_request.accessModule != address(0)) {
342+
IAccessModule(_request.accessModule).finalizeRequest(_request, _response, _accessControl.user);
343+
}
303344

304-
emit OracleRequestFinalized(_requestId, _responseId, msg.sender);
345+
emit OracleRequestFinalized(_requestId, _responseId);
305346
}
306347

307348
/**
@@ -372,14 +413,23 @@ contract Oracle is IOracle {
372413
*
373414
* @param _request The request to be created
374415
* @param _ipfsHash The hashed IPFS CID of the metadata json
416+
* @param _accessControl The access control struct
375417
* @return _requestId The id of the created request
376418
*/
377-
function _createRequest(Request memory _request, bytes32 _ipfsHash) internal returns (bytes32 _requestId) {
419+
function _createRequest(
420+
Request memory _request,
421+
bytes32 _ipfsHash,
422+
AccessControl calldata _accessControl
423+
)
424+
internal
425+
hasAccess(_request.accessModule, CREATE_TYPEHASH, abi.encode(_request), _accessControl)
426+
returns (bytes32 _requestId)
427+
{
378428
uint256 _requestNonce = totalRequestCount++;
379429

380430
if (_request.nonce == 0) _request.nonce = uint96(_requestNonce);
381431

382-
if (msg.sender != _request.requester || _requestNonce != _request.nonce) {
432+
if (_accessControl.user != _request.requester || _requestNonce != _request.nonce) {
383433
revert Oracle_InvalidRequestBody();
384434
}
385435

@@ -393,9 +443,9 @@ contract Oracle is IOracle {
393443
allowedModule[_requestId][_request.resolutionModule] = true;
394444
allowedModule[_requestId][_request.finalityModule] = true;
395445

396-
isParticipant[_requestId][msg.sender] = true;
446+
isParticipant[_requestId][_accessControl.user] = true;
397447

398-
IRequestModule(_request.requestModule).createRequest(_requestId, _request.requestModuleData, msg.sender);
448+
IRequestModule(_request.requestModule).createRequest(_requestId, _request.requestModuleData, _accessControl.user);
399449

400450
emit RequestCreated(_requestId, _request, _ipfsHash);
401451
}

0 commit comments

Comments
 (0)