Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: permit access module #76

Draft
wants to merge 44 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
522cb38
feat: use access control in all the necessary functions
xorsal Oct 23, 2024
3dc123e
feat: update interfaces
xorsal Oct 23, 2024
ed39f02
test: update integration tests
xorsal Oct 23, 2024
88eaddf
test: update unit tests
xorsal Oct 23, 2024
495fde5
feat: add typehash constants
xorsal Oct 23, 2024
42cb077
feat: run linter
xorsal Oct 24, 2024
73688ac
feat: add AccessControllerModule
xorsal Oct 24, 2024
f8e7113
feat: pass params to hasAccess modifier
xorsal Oct 24, 2024
b3731d3
feat: update typehashes
xorsal Oct 24, 2024
5796f29
feat: releaseUnutilizedResponse does not require access control
xorsal Oct 24, 2024
1ebcfc9
feat: update releaseUnutilizedResponse calls
xorsal Oct 24, 2024
5398e63
feat: add _defaultAccessControl to AccessControllerModule
xorsal Oct 25, 2024
f0b55fc
feat: remove accessControl param from unnecesary functions
xorsal Oct 25, 2024
463bfd6
test: use access control in corresponding functions
xorsal Oct 25, 2024
08fe1ca
docs: add access control param to natspec
xorsal Oct 25, 2024
2b28b57
docs: add natspec for _defaultAccessControl
xorsal Oct 25, 2024
a37968c
docs: add missing natspec for onlyAuthorizedCaller modifier
xorsal Oct 25, 2024
7606748
test: replace mockAC for actual access control
xorsal Oct 30, 2024
384e297
test: use pranked caller in _createAccessControl
xorsal Oct 30, 2024
7c76a8c
feat: use access control in finalize and escalate
xorsal Oct 30, 2024
cb76d9a
chore: remove unused import
xorsal Oct 30, 2024
21cd67e
feat: revealVote is now external
xorsal Oct 30, 2024
137d27e
test: add access control unit test for BondEscalationModule
xorsal Oct 30, 2024
124764a
feat: add unit for access controlled function
xorsal Oct 30, 2024
dbadc59
chore: remove comment
xorsal Oct 30, 2024
eae4ea1
feat: replace usage of msg.sender, instead use accessControl.user
xorsal Oct 31, 2024
618cc36
refactor: rework local variables to avoid stack to deep error
xorsal Oct 31, 2024
28f44e9
chore: lint
xorsal Oct 31, 2024
5f875e4
chore: run linter
xorsal Oct 31, 2024
ea1d17f
feat: declare local variable instead of using access control
xorsal Nov 1, 2024
d526ff9
feat: update circuit resolve module
xorsal Nov 2, 2024
b99f8c1
feat: add another defaultAccessControl fn
xorsal Nov 4, 2024
5fa2a04
docs: review the _isModule check
xorsal Nov 4, 2024
f65effd
test: add vm.skip(false) in a few tests to revisit them later
xorsal Nov 4, 2024
cb2a558
feat: update calldata for memory
xorsal Nov 4, 2024
ff81b35
test: resolveDispute now uses access control
xorsal Nov 4, 2024
f0b77fb
feat: resolveDispute in MockAtomicArbitrator
xorsal Nov 4, 2024
cf061e2
chore: fix conflict
xorsal Nov 4, 2024
a0d185e
Merge branch 'dev' into feat/access-control
xorsal Nov 4, 2024
879dc9d
chore: update prophet-core to canary release
xorsal Nov 4, 2024
0f5367f
chore: update yarn.lock
xorsal Nov 4, 2024
71c6b11
chore: remove commented line, uncomment snippet
xorsal Nov 5, 2024
59c312c
feat: first version
ashitakah Nov 6, 2024
e203b92
fix: merge with dev
ashitakah Nov 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ multiline_func_header = 'params_first_multi'
sort_imports = true

[profile.default]
solc_version = '0.8.19'
solc_version = '0.8.20'
src = 'solidity'
test = 'solidity/test'
out = 'out'
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
"package.json": "sort-package-json"
},
"dependencies": {
"@defi-wonderland/prophet-core": "0.0.0-4d28a0ec",
"@openzeppelin/contracts": "4.9.5",
"@defi-wonderland/prophet-core": "0.0.0-3afab791",
"@openzeppelin/contracts": "5.0.0",
"solmate": "https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions solidity/contracts/extensions/BondEscalationAccounting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ contract BondEscalationAccounting is AccountingExtension, IBondEscalationAccount
}
}

/// @notice Checks if the caller is an authorized caller
modifier onlyAuthorizedCaller() {
if (!authorizedCallers[msg.sender]) revert BondEscalationAccounting_UnauthorizedCaller();
_;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {AccessController} from '@defi-wonderland/prophet-core/solidity/contracts/AccessController.sol';
import {Module} from '@defi-wonderland/prophet-core/solidity/contracts/Module.sol';
import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol';

abstract contract AccessControllerModule is AccessController, Module {
constructor(IOracle _oracle) Module(_oracle) {}

/**
* @notice Returns an access control object using the contract address as user and the given data
* @dev should only be used by modules as the self-access-control object
* @param _data Arbitrary data
* @return _accessControl The self access control for this contract.
*/
function _defaultAccessControl(bytes memory _data) internal view returns (AccessControl memory _accessControl) {
_accessControl = AccessControl({user: address(this), data: _data});
}

/**
* // todo: update name to _selfAccessControl
* @notice Returns an access control object using the contract address as user, and empty data
*
* @dev should only be used by modules as the self-access-control object
* @return _accessControl The self access control for this contract.
*/
function _defaultAccessControl() internal view returns (AccessControl memory _accessControl) {
_accessControl = _defaultAccessControl(bytes(''));
}
}
70 changes: 70 additions & 0 deletions solidity/contracts/modules/accessControl/PermitAccessModule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IModule, Module} from '@defi-wonderland/prophet-core/solidity/contracts/Module.sol';

Check warning on line 4 in solidity/contracts/modules/accessControl/PermitAccessModule.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

imported name IModule is not used
import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol';

import {
IAccessControlModule, IPermitAccessModule
} from '../../../interfaces/modules/accessControl/IPermitAccessModule.sol';

import {Nonces} from '@openzeppelin/contracts/utils/Nonces.sol';
import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol';

contract PermitAccessModule is Module, IPermitAccessModule, EIP712, Nonces {
constructor(IOracle _oracle) Module(_oracle) EIP712('PermitAccessModule', '1') {}

/// @inheritdoc IPermitAccessModule
function decodeAccessControlData(bytes memory _data)
public
pure
returns (IAccessControlModule.AccessControlParameters memory _accessControlData)
{
_accessControlData = abi.decode(_data, (IAccessControlModule.AccessControlParameters));
}

/// @inheritdoc IPermitAccessModule
function decodePermitParametersData(bytes memory _data) public pure returns (PermitParameters memory _permitData) {
_permitData = abi.decode(_data, (PermitParameters));
}

/// @inheritdoc IModule
function moduleName() external pure returns (string memory _moduleName) {
_moduleName = 'PermitAccessModule';
}

/// @inheritdoc IPermitAccessModule
function getDomainSeparator() external view returns (bytes32 _domainSeparator) {
_domainSeparator = _domainSeparatorV4();
}

/// @inheritdoc IAccessControlModule
function hasAccess(bytes memory _data) external returns (bool _hasAccess) {
IAccessControlModule.AccessControlParameters memory _accessControlData = decodeAccessControlData(_data);
PermitParameters memory _permitData = decodePermitParametersData(_accessControlData.accessControl.data);

if (block.timestamp > _permitData.deadline) {
revert PermitAccessModule_InvalidDeadline();
}

bytes32 _structHash = keccak256(
abi.encode(

Check failure on line 52 in solidity/contracts/modules/accessControl/PermitAccessModule.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

Missing named parameters. Max unnamed parameters value is 4
_accessControlData.typehash,
_accessControlData.accessControl.user,
_accessControlData.sender,
_useNonce(_accessControlData.accessControl.user),
_permitData.deadline
)
);

bytes32 _hash = _hashTypedDataV4(_structHash);

address _signer = ECDSA.recover(_hash, _permitData.v, _permitData.r, _permitData.s);
if (_signer != _accessControlData.accessControl.user) {
revert PermitAccessModule_InvalidSignature();
}

_hasAccess = true;
}
}
57 changes: 43 additions & 14 deletions solidity/contracts/modules/dispute/BondEscalationModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {FixedPointMathLib} from 'solmate/src/utils/FixedPointMathLib.sol';

import {IBondEscalationModule} from '../../../interfaces/modules/dispute/IBondEscalationModule.sol';

contract BondEscalationModule is Module, IBondEscalationModule {
import {_PLEDGE_AGAINST_DISPUTE_TYPEHASH, _PLEDGE_FOR_DISPUTE_TYPEHASH} from '../../utils/Typehash.sol';
import {AccessControllerModule} from '../accessControl/AccessControllerModule.sol';

contract BondEscalationModule is AccessControllerModule, IBondEscalationModule {
/// @inheritdoc IBondEscalationModule
mapping(bytes32 _requestId => mapping(address _pledger => uint256 pledges)) public pledgesForDispute;

Expand All @@ -19,7 +22,7 @@ contract BondEscalationModule is Module, IBondEscalationModule {
*/
mapping(bytes32 _requestId => BondEscalation) internal _escalations;

constructor(IOracle _oracle) Module(_oracle) {}
constructor(IOracle _oracle) AccessControllerModule(_oracle) {}

/// @inheritdoc IModule
function moduleName() external pure returns (string memory _moduleName) {
Expand Down Expand Up @@ -61,7 +64,7 @@ contract BondEscalationModule is Module, IBondEscalationModule {
_escalation.disputeId = _disputeId;
emit BondEscalationStatusUpdated(_dispute.requestId, _disputeId, BondEscalationStatus.Active);
} else if (_disputeId != _escalation.disputeId) {
ORACLE.escalateDispute(_request, _response, _dispute);
ORACLE.escalateDispute(_request, _response, _dispute, _defaultAccessControl());
}
}

Expand Down Expand Up @@ -208,39 +211,62 @@ contract BondEscalationModule is Module, IBondEscalationModule {
////////////////////////////////////////////////////////////////////

/// @inheritdoc IBondEscalationModule
function pledgeForDispute(IOracle.Request calldata _request, IOracle.Dispute calldata _dispute) external {
function pledgeForDispute(
IOracle.Request calldata _request,
IOracle.Dispute calldata _dispute,
AccessControl calldata _accessControl
)
external
hasAccess(_request.accessControlModule, _PLEDGE_FOR_DISPUTE_TYPEHASH, abi.encode(_request, _dispute), _accessControl)
{
bytes32 _disputeId = _getId(_dispute);
RequestParameters memory _params = _pledgeChecks(_request, _dispute, true);

address _pledger = _accessControl.user;

_escalations[_dispute.requestId].amountOfPledgesForDispute += 1;
pledgesForDispute[_dispute.requestId][msg.sender] += 1;
pledgesForDispute[_dispute.requestId][_pledger] += 1;
_params.accountingExtension.pledge({
_pledger: msg.sender,
_pledger: _pledger,
_request: _request,
_dispute: _dispute,
_token: _params.bondToken,
_amount: _params.bondSize
});

emit PledgedForDispute(_disputeId, msg.sender, _params.bondSize);
emit PledgedForDispute(_disputeId, _pledger, _params.bondSize);
}

/// @inheritdoc IBondEscalationModule
function pledgeAgainstDispute(IOracle.Request calldata _request, IOracle.Dispute calldata _dispute) external {
function pledgeAgainstDispute(
IOracle.Request calldata _request,
IOracle.Dispute calldata _dispute,
AccessControl calldata _accessControl
)
external
hasAccess(
_request.accessControlModule,
_PLEDGE_AGAINST_DISPUTE_TYPEHASH,
abi.encode(_request, _dispute),
_accessControl
)
{
bytes32 _disputeId = _getId(_dispute);
RequestParameters memory _params = _pledgeChecks(_request, _dispute, false);

address _pledger = _accessControl.user;

_escalations[_dispute.requestId].amountOfPledgesAgainstDispute += 1;
pledgesAgainstDispute[_dispute.requestId][msg.sender] += 1;
pledgesAgainstDispute[_dispute.requestId][_pledger] += 1;
_params.accountingExtension.pledge({
_pledger: msg.sender,
_pledger: _pledger,
_request: _request,
_dispute: _dispute,
_token: _params.bondToken,
_amount: _params.bondSize
});

emit PledgedAgainstDispute(_disputeId, msg.sender, _params.bondSize);
emit PledgedAgainstDispute(_disputeId, _pledger, _params.bondSize);
}

/// @inheritdoc IBondEscalationModule
Expand Down Expand Up @@ -274,9 +300,12 @@ contract BondEscalationModule is Module, IBondEscalationModule {

emit BondEscalationStatusUpdated(_dispute.requestId, _disputeId, _escalation.status);

ORACLE.updateDisputeStatus(
_request, _response, _dispute, _disputersWon ? IOracle.DisputeStatus.Won : IOracle.DisputeStatus.Lost
);
ORACLE.updateDisputeStatus({
_request: _request,
_response: _response,
_dispute: _dispute,
_status: _disputersWon ? IOracle.DisputeStatus.Won : IOracle.DisputeStatus.Lost
});
}

/**
Expand Down
15 changes: 9 additions & 6 deletions solidity/contracts/modules/dispute/CircuitResolverModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle
import {IProphetVerifier} from '../../../interfaces/IProphetVerifier.sol';
import {ICircuitResolverModule} from '../../../interfaces/modules/dispute/ICircuitResolverModule.sol';

contract CircuitResolverModule is Module, ICircuitResolverModule {
import {AccessControllerModule} from '../accessControl/AccessControllerModule.sol';

contract CircuitResolverModule is AccessControllerModule, ICircuitResolverModule {
/// @notice Keeps track of the correct responses to requests
mapping(bytes32 _requestId => bytes _correctResponse) internal _correctResponses;

constructor(IOracle _oracle) Module(_oracle) {}
constructor(IOracle _oracle) AccessControllerModule(_oracle) {}

/// @inheritdoc IModule
function moduleName() external pure returns (string memory _moduleName) {
Expand All @@ -32,6 +34,7 @@ contract CircuitResolverModule is Module, ICircuitResolverModule {
) external onlyOracle {
RequestParameters memory _params = decodeRequestData(_request.disputeModuleData);
IOracle.DisputeStatus _status = ORACLE.disputeStatus(_disputeId);
AccessControl memory _accessControl = _defaultAccessControl();

if (_status == IOracle.DisputeStatus.Won) {
_params.accountingExtension.pay({
Expand All @@ -50,12 +53,12 @@ contract CircuitResolverModule is Module, ICircuitResolverModule {

emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: IOracle.DisputeStatus.Won});

ORACLE.proposeResponse(_request, _newResponse);
ORACLE.finalize(_request, _newResponse);
ORACLE.proposeResponse(_request, _newResponse, _accessControl);
ORACLE.finalize(_request, _newResponse, _accessControl);
} else {
emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: IOracle.DisputeStatus.Lost});

ORACLE.finalize(_request, _response);
ORACLE.finalize(_request, _response, _accessControl);
}

delete _correctResponses[_dispute.requestId];
Expand Down Expand Up @@ -88,7 +91,7 @@ contract CircuitResolverModule is Module, ICircuitResolverModule {
_dispute: _dispute
});

ORACLE.updateDisputeStatus(_request, _response, _dispute, _status);
ORACLE.updateDisputeStatus({_request: _request, _response: _response, _dispute: _dispute, _status: _status});
}

/// @inheritdoc IModule
Expand Down
14 changes: 8 additions & 6 deletions solidity/contracts/modules/dispute/RootVerificationModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle

import {IRootVerificationModule} from '../../../interfaces/modules/dispute/IRootVerificationModule.sol';
import {MerkleLib} from '../../libraries/MerkleLib.sol';
import {AccessControllerModule} from '../accessControl/AccessControllerModule.sol';

contract RootVerificationModule is Module, IRootVerificationModule {
contract RootVerificationModule is AccessControllerModule, IRootVerificationModule {
using MerkleLib for MerkleLib.Tree;

/**
* @notice The calculated correct root for a given request
*/
mapping(bytes32 _requestId => bytes32 _correctRoot) internal _correctRoots;

constructor(IOracle _oracle) Module(_oracle) {}
constructor(IOracle _oracle) AccessControllerModule(_oracle) {}

/// @inheritdoc IModule
function moduleName() external pure returns (string memory _moduleName) {
Expand All @@ -36,6 +37,7 @@ contract RootVerificationModule is Module, IRootVerificationModule {
) external onlyOracle {
RequestParameters memory _params = decodeRequestData(_request.disputeModuleData);
IOracle.DisputeStatus _status = ORACLE.disputeStatus(_disputeId);
AccessControl memory _accessControl = _defaultAccessControl();

if (_status == IOracle.DisputeStatus.Won) {
_params.accountingExtension.pay({
Expand All @@ -54,11 +56,11 @@ contract RootVerificationModule is Module, IRootVerificationModule {

emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: IOracle.DisputeStatus.Won});

ORACLE.proposeResponse(_request, _newResponse);
ORACLE.finalize(_request, _newResponse);
ORACLE.proposeResponse(_request, _newResponse, _accessControl);
ORACLE.finalize(_request, _newResponse, _accessControl);
} else {
emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: IOracle.DisputeStatus.Lost});
ORACLE.finalize(_request, _response);
ORACLE.finalize(_request, _response, _accessControl);
}

delete _correctRoots[_dispute.requestId];
Expand Down Expand Up @@ -86,7 +88,7 @@ contract RootVerificationModule is Module, IRootVerificationModule {
_dispute: _dispute
});

ORACLE.updateDisputeStatus(_request, _response, _dispute, _status);
ORACLE.updateDisputeStatus({_request: _request, _response: _response, _dispute: _dispute, _status: _status});
}

/// @inheritdoc IModule
Expand Down
10 changes: 6 additions & 4 deletions solidity/contracts/modules/resolution/ArbitratorModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle
import {IArbitrator} from '../../../interfaces/IArbitrator.sol';
import {IArbitratorModule} from '../../../interfaces/modules/resolution/IArbitratorModule.sol';

contract ArbitratorModule is Module, IArbitratorModule {
import {AccessControllerModule} from '../accessControl/AccessControllerModule.sol';

contract ArbitratorModule is AccessControllerModule, IArbitratorModule {
/**
* @notice The status of all disputes
*/
mapping(bytes32 _disputeId => ArbitrationStatus _status) internal _disputeData;

constructor(IOracle _oracle) Module(_oracle) {}
constructor(IOracle _oracle) AccessControllerModule(_oracle) {}

/// @inheritdoc IModule
function moduleName() external pure returns (string memory _moduleName) {
Expand Down Expand Up @@ -41,7 +43,7 @@ contract ArbitratorModule is Module, IArbitratorModule {
if (_params.arbitrator == address(0)) revert ArbitratorModule_InvalidArbitrator();

_disputeData[_disputeId] = ArbitrationStatus.Active;
IArbitrator(_params.arbitrator).resolve(_request, _response, _dispute);
IArbitrator(_params.arbitrator).resolve(_request, _response, _dispute, _defaultAccessControl());

emit ResolutionStarted(_dispute.requestId, _disputeId);
}
Expand All @@ -61,7 +63,7 @@ contract ArbitratorModule is Module, IArbitratorModule {
if (_status <= IOracle.DisputeStatus.Escalated) revert ArbitratorModule_InvalidResolutionStatus();
_disputeData[_disputeId] = ArbitrationStatus.Resolved;

ORACLE.updateDisputeStatus(_request, _response, _dispute, _status);
ORACLE.updateDisputeStatus({_request: _request, _response: _response, _dispute: _dispute, _status: _status});

emit DisputeResolved(_dispute.requestId, _disputeId, _status);
}
Expand Down
Loading
Loading