Skip to content

Commit

Permalink
feat: first version
Browse files Browse the repository at this point in the history
  • Loading branch information
ashitakah committed Nov 6, 2024
1 parent 71c6b11 commit 59c312c
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 6 deletions.
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
},
"dependencies": {
"@defi-wonderland/prophet-core": "0.0.0-3afab791",
"@openzeppelin/contracts": "4.9.5",
"@openzeppelin/contracts": "5.0.0",
"solmate": "https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c"
},
"devDependencies": {
Expand Down
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;
}
}
71 changes: 71 additions & 0 deletions solidity/interfaces/modules/accessControl/IPermitAccessModule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IAccessControlModule} from
'@defi-wonderland/prophet-core/solidity/interfaces/modules/accessControl/IAccessControlModule.sol';

/**
* @title IPermitAccessModule
*/
interface IPermitAccessModule is IAccessControlModule {
/*///////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/

/**
* @notice Thrown when the deadline is invalid
*/
error PermitAccessModule_InvalidDeadline();

/**
* @notice Thrown when the signature is invalid
*/
error PermitAccessModule_InvalidSignature();

/*///////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Decode permit parameters data
* @param deadline The deadline timestamp
* @param v The signature v
* @param r The signature r
* @param s The signature s
*/
struct PermitParameters {
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}

/*///////////////////////////////////////////////////////////////
VIEWS
//////////////////////////////////////////////////////////////*/

/**
* @notice Get the domain separator
* @return _domainSeparator The domain separator
*/
function getDomainSeparator() external view returns (bytes32 _domainSeparator);

/**
* @notice Decode permit parameters data
* @param _permitData The permit data to decode
*/
function decodePermitParametersData(bytes memory _data) external pure returns (PermitParameters memory _permitData);

/**
* @notice Decode access control data
* @param _data The data to decode
* @return _accessControlData The access control data
*/
function decodeAccessControlData(bytes memory _data)
external
pure
returns (IAccessControlModule.AccessControlParameters memory _accessControlData);

/*///////////////////////////////////////////////////////////////
LOGIC
//////////////////////////////////////////////////////////////*/
}
144 changes: 144 additions & 0 deletions solidity/test/unit/modules/accessControl/PermitAccessModule.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import 'forge-std/Test.sol';

import {Helpers} from '../../../utils/Helpers.sol';

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

Check warning on line 8 in solidity/test/unit/modules/accessControl/PermitAccessModule.t.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 {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

Check warning on line 10 in solidity/test/unit/modules/accessControl/PermitAccessModule.t.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

imported name IERC20 is not used

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

import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/IAccessController.sol';

/**
* @title Access Control Module Unit tests
*/
contract BaseTest is Test, Helpers {
// Mock Oracle
IOracle public oracle;

// Access Control Module
PermitAccessModule public permitAccessModule;

/**
* @notice Deploy the target and mock oracle
*/
function setUp() public {
oracle = IOracle(makeAddr('Oracle'));
vm.etch(address(oracle), hex'069420');

permitAccessModule = new PermitAccessModule(oracle);
}
}

contract AccessControlModule_Unit_Constructor is BaseTest {
/**
* @notice Test the constructor
*/
function test_constructor() public view {
// Assert the oracle address
assertEq(address(permitAccessModule.ORACLE()), address(oracle));
}
}

contract AccessControlModule_Unit_DecodeAccessControlData is BaseTest {
/**
* @notice Test the decodeAccessControlData function
*/
function test_decodeAccessControlData() public view {
// Encode the access control data
IAccessControlModule.AccessControlParameters memory _accessControlData = IAccessControlModule
.AccessControlParameters({
sender: address(0x1),
typehash: hex'1234',
accessControl: IAccessController.AccessControl({user: address(0x2), data: hex'5678'}),
params: hex'9abc'
});

// Decode the access control data
IAccessControlModule.AccessControlParameters memory _decodedAccessControlData =
permitAccessModule.decodeAccessControlData(abi.encode(_accessControlData));

// Assert the decoded access control data
assertEq(_decodedAccessControlData.sender, _accessControlData.sender);
assertEq(_decodedAccessControlData.typehash, _accessControlData.typehash);
assertEq(_decodedAccessControlData.accessControl.user, _accessControlData.accessControl.user);
assertEq(_decodedAccessControlData.accessControl.data, _accessControlData.accessControl.data);
assertEq(_decodedAccessControlData.params, _accessControlData.params);
}
}

contract AccessControlModule_Unit_DecodePermitParametersData is BaseTest {
/**
* @notice Test the decodePermitParametersData function
*/
function test_decodePermitParametersData() public view {
// Encode the permit parameters data
IPermitAccessModule.PermitParameters memory _permitData =
IPermitAccessModule.PermitParameters({deadline: 1, v: 2, r: hex'1234', s: hex'5678'});

// Decode the permit parameters data
IPermitAccessModule.PermitParameters memory _decodedPermitData =
permitAccessModule.decodePermitParametersData(abi.encode(_permitData));

// Assert the decoded permit parameters data
assertEq(_decodedPermitData.deadline, _permitData.deadline);
assertEq(_decodedPermitData.v, _permitData.v);
assertEq(_decodedPermitData.r, _permitData.r);
assertEq(_decodedPermitData.s, _permitData.s);
}
}

contract AccessControlModule_Unit_ModuleName is BaseTest {
/**
* @notice Test the moduleName function
*/
function test_ModuleName() public view {
// Assert the module name
assertEq(permitAccessModule.moduleName(), 'PermitAccessModule');
}
}

contract AccessControlModule_Unit_HasAccess is BaseTest {
/**
* @notice Test the hasAccess function
*/
function test_hasAccess_true() public {
bytes32 _permitHash = keccak256(
abi.encodePacked(
'\x19\x01',
permitAccessModule.getDomainSeparator(),
keccak256(abi.encode(keccak256('1234'), address(0x2), address(0x1), permitAccessModule.nonces(address(0x2)), 1))
)
);

(uint8 _v, bytes32 _r, bytes32 _s) = vm.sign(_permitHash);

// Encode the permit parameters data
IPermitAccessModule.PermitParameters memory _permitData =
IPermitAccessModule.PermitParameters({deadline: 1, v: _v, r: _r, s: _s});

bytes memory _permitDataEncoded = abi.encode(_permitData);

// Encode the access control data
IAccessControlModule.AccessControlParameters memory _accessControlData = IAccessControlModule
.AccessControlParameters({
sender: address(0x1),
typehash: keccak256('1234'),
accessControl: IAccessController.AccessControl({user: address(0x2), data: _permitDataEncoded}),
params: hex'9abc'
});

bytes memory _accessControlDataEncoded = abi.encode(_accessControlData);

// Assert the has access
assertEq(permitAccessModule.hasAccess(_accessControlDataEncoded), true);
}
}
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,10 @@
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.2.tgz#1cb2d5e4d3360141a17dbc45094a8cad6aac16c1"
integrity sha512-mO+y6JaqXjWeMh9glYVzVu8HYPGknAAnWyxTRhGeckOruyXQMNnlcW6w/Dx9ftLeIQk6N+ZJFuVmTwF7lEIFrg==

"@openzeppelin/contracts@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.5.tgz#1eed23d4844c861a1835b5d33507c1017fa98de8"
integrity sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg==
"@openzeppelin/contracts@5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.0.tgz#ee0e4b4564f101a5c4ee398cd4d73c0bd92b289c"
integrity sha512-bv2sdS6LKqVVMLI5+zqnNrNU/CA+6z6CmwFXm/MzmOPBRSO5reEJN7z0Gbzvs0/bv/MZZXNklubpwy3v2+azsw==

"@solidity-parser/parser@^0.14.1":
version "0.14.5"
Expand Down

0 comments on commit 59c312c

Please sign in to comment.