Skip to content

Commit

Permalink
Tests (#4)
Browse files Browse the repository at this point in the history
* init tests

* added tests

* covered core 100%
  • Loading branch information
dovgopoly committed Apr 2, 2024
1 parent 58e0abd commit 7f06c81
Show file tree
Hide file tree
Showing 19 changed files with 1,047 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .solcover.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
skipFiles: [],
skipFiles: ["interfaces/", "mock/"],
configureYulOptimizer: true,
};
10 changes: 8 additions & 2 deletions contracts/core/TokenF.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {IRegulatoryCompliance} from "../interfaces/IRegulatoryCompliance.sol";

import {AgentAccessControl} from "./AgentAccessControl.sol";
import {TokenFStorage} from "./storages/TokenFStorage.sol";
import {RegulatoryComplianceStorage} from "./storages/RegulatoryComplianceStorage.sol";
import {KYCComplianceStorage} from "./storages/KYCComplianceStorage.sol";

/**
* @notice The TokenF contract
Expand Down Expand Up @@ -44,16 +46,20 @@ abstract contract TokenF is TokenFStorage, Diamond, DiamondERC20, AgentAccessCon
bytes memory initRegulatory_,
bytes memory initKYC_
) internal virtual onlyInitializing(TOKEN_F_STORAGE_SLOT) {
bytes4[] memory rComplianceSelectors_ = new bytes4[](4);
bytes4[] memory rComplianceSelectors_ = new bytes4[](6);
rComplianceSelectors_[0] = IRegulatoryCompliance.addRegulatoryModules.selector;
rComplianceSelectors_[1] = IRegulatoryCompliance.removeRegulatoryModules.selector;
rComplianceSelectors_[2] = IRegulatoryCompliance.transferred.selector;
rComplianceSelectors_[3] = IRegulatoryCompliance.canTransfer.selector;
rComplianceSelectors_[4] = RegulatoryComplianceStorage.getRegulatoryModules.selector;
rComplianceSelectors_[5] = RegulatoryComplianceStorage.getRegulatoryModulesCount.selector;

bytes4[] memory kycComplianceSelectors_ = new bytes4[](3);
bytes4[] memory kycComplianceSelectors_ = new bytes4[](5);
kycComplianceSelectors_[0] = IKYCCompliance.addKYCModules.selector;
kycComplianceSelectors_[1] = IKYCCompliance.removeKYCModules.selector;
kycComplianceSelectors_[2] = IKYCCompliance.isKYCed.selector;
kycComplianceSelectors_[3] = KYCComplianceStorage.getKYCModules.selector;
kycComplianceSelectors_[4] = KYCComplianceStorage.getKYCModulesCount.selector;

Facet[] memory facets_ = new Facet[](2);
facets_[0] = Facet(regulatoryCompliance_, FacetAction.Add, rComplianceSelectors_);
Expand Down
17 changes: 17 additions & 0 deletions contracts/mock/core/AgentAccessControlMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {AgentAccessControl} from "../../core/AgentAccessControl.sol";

contract AgentAccessControlMock is AgentAccessControl {
function __AgentAccessControlMock_init()
external
initializer(AGENT_ACCESS_CONTROL_STORAGE_SLOT)
{
__AgentAccessControl_init();
}

function __AgentAccessControlDirect_init() external {
__AgentAccessControl_init();
}
}
14 changes: 14 additions & 0 deletions contracts/mock/core/ComplianceFalseHooksMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {TokenF} from "../../core/TokenF.sol";

contract ComplianceFalseHooksMock {
function isKYCed(TokenF.Context calldata) external returns (bool) {
return false;
}

function canTransfer(TokenF.Context calldata) external returns (bool) {
return false;
}
}
18 changes: 18 additions & 0 deletions contracts/mock/core/ComplianceRevertHooksMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {TokenF} from "../../core/TokenF.sol";

contract ComplianceRevertHooksMock {
function transferred(TokenF.Context calldata) external {
revert("ComplianceRevertHooksMock: revert");
}

function isKYCed(TokenF.Context calldata) external view returns (bool) {
revert("ComplianceRevertHooksMock: revert");
}

function canTransfer(TokenF.Context calldata) external view returns (bool) {
revert("ComplianceRevertHooksMock: revert");
}
}
8 changes: 8 additions & 0 deletions contracts/mock/core/FacetMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract FacetMock {
function mockFunction() external view returns (bool) {
return true;
}
}
24 changes: 24 additions & 0 deletions contracts/mock/core/KYCComplianceMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {KYCCompliance} from "../../core/KYCCompliance.sol";

contract KYCComplianceMock is KYCCompliance {
bytes32 public constant KYC_COMPLIANCE_ROLE = keccak256("KYC_COMPLIANCE_ROLE");

function __KYCComplianceMock_init() external initializer(KYC_COMPLIANCE_STORAGE_SLOT) {
__KYCCompliance_init();
}

function __KYCComplianceDirect_init() external {
__KYCCompliance_init();
}

function defaultKYCComplianceRole() external view returns (bytes32) {
return super._KYCComplianceRole();
}

function _KYCComplianceRole() internal view override returns (bytes32) {
return KYC_COMPLIANCE_ROLE;
}
}
27 changes: 27 additions & 0 deletions contracts/mock/core/RegulatoryComplianceMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {RegulatoryCompliance} from "../../core/RegulatoryCompliance.sol";

contract RegulatoryComplianceMock is RegulatoryCompliance {
bytes32 public constant REGULATORY_COMPLIANCE_ROLE = keccak256("REGULATORY_COMPLIANCE_ROLE");

function __RegulatoryComplianceMock_init()
external
initializer(REGULATORY_COMPLIANCE_STORAGE_SLOT)
{
__RegulatoryCompliance_init();
}

function __RegulatoryComplianceDirect_init() external {
__RegulatoryCompliance_init();
}

function defaultRegulatoryComplianceRole() external view returns (bytes32) {
return super._regulatoryComplianceRole();
}

function _regulatoryComplianceRole() internal view override returns (bytes32) {
return REGULATORY_COMPLIANCE_ROLE;
}
}
76 changes: 76 additions & 0 deletions contracts/mock/core/TokenFMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {TokenF} from "../../core/TokenF.sol";

contract TokenFMock is TokenF {
bytes32 public constant MINT_ROLE = keccak256("MINT_ROLE");
bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE");
bytes32 public constant FORCED_TRANSFER_ROLE = keccak256("FORCED_TRANSFER_ROLE");
bytes32 public constant RECOVERY_ROLE = keccak256("RECOVERY_ROLE");
bytes32 public constant DIAMOND_CUT_ROLE = keccak256("DIAMOND_CUT_ROLE");

function __TokenFMock_init(
string memory name_,
string memory symbol_,
address rCompliance_,
address kycCompliance_,
bytes memory initRegulatory_,
bytes memory initKYC_
)
external
initializer(DIAMOND_ERC20_STORAGE_SLOT)
initializer(DIAMOND_ACCESS_CONTROL_STORAGE_SLOT)
initializer(AGENT_ACCESS_CONTROL_STORAGE_SLOT)
initializer(TOKEN_F_STORAGE_SLOT)
{
__DiamondAccessControl_init();
__DiamondERC20_init(name_, symbol_);
__AgentAccessControl_init();
__TokenF_init(rCompliance_, kycCompliance_, initRegulatory_, initKYC_);
}

function __TokenFDirect_init() external {
__TokenF_init(address(0), address(0), "", "");
}

function defaultMintRole() external view returns (bytes32) {
return super._mintRole();
}

function defaultBurnRole() external view returns (bytes32) {
return super._burnRole();
}

function defaultForcedTransferRole() external view returns (bytes32) {
return super._forcedTransferRole();
}

function defaultRecoveryRole() external view returns (bytes32) {
return super._recoveryRole();
}

function defaultDiamondCutRole() external view returns (bytes32) {
return super._diamondCutRole();
}

function _mintRole() internal pure override returns (bytes32) {
return MINT_ROLE;
}

function _burnRole() internal pure override returns (bytes32) {
return BURN_ROLE;
}

function _forcedTransferRole() internal pure override returns (bytes32) {
return FORCED_TRANSFER_ROLE;
}

function _recoveryRole() internal pure override returns (bytes32) {
return RECOVERY_ROLE;
}

function _diamondCutRole() internal pure override returns (bytes32) {
return DIAMOND_CUT_ROLE;
}
}
13 changes: 13 additions & 0 deletions contracts/mock/modules/kyc/KYCCorrectModuleMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {TokenF} from "../../../core/TokenF.sol";
import {AbstractKYCModule} from "../../../modules/AbstractKYCModule.sol";

contract KYCCorrectModuleMock is AbstractKYCModule {
function _handlerer() internal override {}

function isKYCed(TokenF.Context calldata) public pure override returns (bool) {
return true;
}
}
13 changes: 13 additions & 0 deletions contracts/mock/modules/kyc/KYCIncorrectModuleMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {TokenF} from "../../../core/TokenF.sol";
import {AbstractKYCModule} from "../../../modules/AbstractKYCModule.sol";

contract KYCIncorrectModuleMock is AbstractKYCModule {
function _handlerer() internal override {}

function isKYCed(TokenF.Context calldata) public pure override returns (bool) {
return false;
}
}
15 changes: 15 additions & 0 deletions contracts/mock/modules/regulatory/RegulatoryCorrectModuleMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {TokenF} from "../../../core/TokenF.sol";
import {AbstractRegulatoryModule} from "../../../modules/AbstractRegulatoryModule.sol";

contract RegulatoryCorrectModuleMock is AbstractRegulatoryModule {
function _handlerer() internal override {}

function transferred(TokenF.Context calldata) public override {}

function canTransfer(TokenF.Context calldata) public pure override returns (bool) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {TokenF} from "../../../core/TokenF.sol";
import {AbstractRegulatoryModule} from "../../../modules/AbstractRegulatoryModule.sol";
import {IRegulatoryCompliance} from "../../../interfaces/IRegulatoryCompliance.sol";

contract RegulatoryIncorrectModuleMock is AbstractRegulatoryModule {
function _handlerer() internal override {}

function transferred(TokenF.Context calldata ctx_) public override {}

function canTransfer(TokenF.Context calldata) public pure override returns (bool) {
return false;
}
}
1 change: 1 addition & 0 deletions scripts/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const ZERO_ADDR = "0x0000000000000000000000000000000000000000";
export const ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
export const ETHER_ADDR = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";

export const SECONDS_IN_DAY = 86400;
Expand Down
81 changes: 81 additions & 0 deletions test/core/AgentAccessControl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { ethers } from "hardhat";
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";
import { expect } from "chai";
import { Reverter } from "@/test/helpers/reverter";
import { TokenFMock, AgentAccessControlMock } from "@ethers-v6";
import { ADMIN_ROLE, AGENT_ROLE, DIAMOND_CUT_ROLE, hasRoleErrorMessage } from "@/test/helpers/utils";

describe("AgentAccessControl", () => {
const reverter = new Reverter();

let owner: SignerWithAddress;
let agent: SignerWithAddress;

let tokenF: TokenFMock;
let accessControl: AgentAccessControlMock;
let accessControlProxy: AgentAccessControlMock;

before("setup", async () => {
[owner, agent] = await ethers.getSigners();

const TokenFMock = await ethers.getContractFactory("TokenFMock");
const AgentAccessControlMock = await ethers.getContractFactory("AgentAccessControlMock");
const KYCComplianceMock = await ethers.getContractFactory("KYCComplianceMock");
const RegulatoryComplianceMock = await ethers.getContractFactory("RegulatoryComplianceMock");

tokenF = await TokenFMock.deploy();
const kycCompliance = await KYCComplianceMock.deploy();
const rCompliance = await RegulatoryComplianceMock.deploy();

const initRegulatory = rCompliance.interface.encodeFunctionData("__RegulatoryComplianceMock_init");
const initKYC = kycCompliance.interface.encodeFunctionData("__KYCComplianceMock_init");

await tokenF.__TokenFMock_init("TokenF", "TF", rCompliance, kycCompliance, initRegulatory, initKYC);

accessControl = await AgentAccessControlMock.deploy();
accessControlProxy = AgentAccessControlMock.attach(tokenF) as AgentAccessControlMock;

await tokenF.grantRole(DIAMOND_CUT_ROLE, agent);

await reverter.snapshot();
});

afterEach(reverter.revert);

describe("access", () => {
it("should initialize only once", async () => {
await expect(
tokenF
.connect(agent)
[
"diamondCut((address,uint8,bytes4[])[],address,bytes)"
]([], accessControl, accessControl.interface.encodeFunctionData("__AgentAccessControlMock_init")),
).to.be.revertedWith("Initializable: contract is already initialized");
});

it("should initialize only by top level contract", async () => {
await expect(
tokenF
.connect(agent)
[
"diamondCut((address,uint8,bytes4[])[],address,bytes)"
]([], accessControl, accessControl.interface.encodeFunctionData("__AgentAccessControlDirect_init")),
).to.be.revertedWith("Initializable: contract is not initializing");
});
});

describe("checkRole", () => {
it("should revert if no role", async () => {
await expect(accessControlProxy.checkRole(AGENT_ROLE, agent)).to.be.revertedWith(
await hasRoleErrorMessage(agent, AGENT_ROLE),
);
});

it("should not revert if has role", async () => {
await accessControlProxy.grantRole(AGENT_ROLE, agent);

await expect(accessControlProxy.checkRole(AGENT_ROLE, agent)).to.not.be.reverted;
await expect(accessControlProxy.checkRole(ADMIN_ROLE, owner)).to.not.be.reverted;
});
});
});
Loading

0 comments on commit 7f06c81

Please sign in to comment.