@chainlink/ace 0.5.0
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/.foundry-version +1 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/workflows/auto-release-version.yml +107 -0
- package/.github/workflows/create-version-pr.yml +95 -0
- package/.github/workflows/forge-docs.yml +90 -0
- package/.github/workflows/forge-test.yml +59 -0
- package/.solhint-test.json +18 -0
- package/.solhint.json +16 -0
- package/.solhintignore +3 -0
- package/.solhintignore-test +2 -0
- package/Glossary.md +141 -0
- package/LICENSE +59 -0
- package/README.md +218 -0
- package/assets/chainlink-logo.svg +21 -0
- package/chainlink-ace-License-grants +2 -0
- package/foundry.toml +33 -0
- package/getting_started/GETTING_STARTED.md +477 -0
- package/getting_started/MyVault.sol +48 -0
- package/getting_started/advanced/.env.example +36 -0
- package/getting_started/advanced/GETTING_STARTED_ADVANCED.md +431 -0
- package/getting_started/advanced/SanctionsList.sol +25 -0
- package/getting_started/advanced/SanctionsPolicy.sol +58 -0
- package/package.json +41 -0
- package/packages/cross-chain-identity/README.md +148 -0
- package/packages/cross-chain-identity/docs/API_GUIDE.md +120 -0
- package/packages/cross-chain-identity/docs/API_REFERENCE.md +271 -0
- package/packages/cross-chain-identity/docs/CONCEPTS.md +253 -0
- package/packages/cross-chain-identity/docs/CREDENTIAL_FLOW.md +195 -0
- package/packages/cross-chain-identity/docs/SECURITY.md +70 -0
- package/packages/cross-chain-identity/src/CredentialRegistry.sol +245 -0
- package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidator.sol +339 -0
- package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidatorPolicy.sol +71 -0
- package/packages/cross-chain-identity/src/IdentityRegistry.sol +123 -0
- package/packages/cross-chain-identity/src/TrustedIssuerRegistry.sol +140 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialDataValidator.sol +30 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialRegistry.sol +170 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialRequirements.sol +192 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialValidator.sol +37 -0
- package/packages/cross-chain-identity/src/interfaces/IIdentityRegistry.sol +85 -0
- package/packages/cross-chain-identity/src/interfaces/IIdentityValidator.sol +18 -0
- package/packages/cross-chain-identity/src/interfaces/ITrustedIssuerRegistry.sol +61 -0
- package/packages/cross-chain-identity/test/CredentialRegistry.t.sol +220 -0
- package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidator.t.sol +554 -0
- package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidatorPolicy.t.sol +114 -0
- package/packages/cross-chain-identity/test/IdentityRegistry.t.sol +106 -0
- package/packages/cross-chain-identity/test/IdentityValidator.t.sol +969 -0
- package/packages/cross-chain-identity/test/TrustedIssuerRegistry.t.sol +123 -0
- package/packages/cross-chain-identity/test/helpers/BaseProxyTest.sol +112 -0
- package/packages/cross-chain-identity/test/helpers/MockCredentialDataValidator.sol +26 -0
- package/packages/cross-chain-identity/test/helpers/MockCredentialRegistryReverting.sol +131 -0
- package/packages/policy-management/README.md +197 -0
- package/packages/policy-management/docs/API_GUIDE.md +290 -0
- package/packages/policy-management/docs/API_REFERENCE.md +173 -0
- package/packages/policy-management/docs/CONCEPTS.md +156 -0
- package/packages/policy-management/docs/CUSTOM_POLICIES_TUTORIAL.md +195 -0
- package/packages/policy-management/docs/POLICY_ORDERING_GUIDE.md +91 -0
- package/packages/policy-management/docs/SECURITY.md +57 -0
- package/packages/policy-management/src/core/Policy.sol +124 -0
- package/packages/policy-management/src/core/PolicyEngine.sol +382 -0
- package/packages/policy-management/src/core/PolicyFactory.sol +92 -0
- package/packages/policy-management/src/core/PolicyProtected.sol +126 -0
- package/packages/policy-management/src/extractors/ComplianceTokenForceTransferExtractor.sol +57 -0
- package/packages/policy-management/src/extractors/ComplianceTokenFreezeUnfreezeExtractor.sol +54 -0
- package/packages/policy-management/src/extractors/ComplianceTokenMintBurnExtractor.sol +61 -0
- package/packages/policy-management/src/extractors/ERC20ApproveExtractor.sol +57 -0
- package/packages/policy-management/src/extractors/ERC20TransferExtractor.sol +62 -0
- package/packages/policy-management/src/extractors/ERC3643ForcedTransferExtractor.sol +56 -0
- package/packages/policy-management/src/extractors/ERC3643FreezeUnfreezeExtractor.sol +55 -0
- package/packages/policy-management/src/extractors/ERC3643MintBurnExtractor.sol +51 -0
- package/packages/policy-management/src/extractors/ERC3643SetAddressFrozenExtractor.sol +51 -0
- package/packages/policy-management/src/interfaces/IExtractor.sol +17 -0
- package/packages/policy-management/src/interfaces/IMapper.sol +17 -0
- package/packages/policy-management/src/interfaces/IPolicy.sol +61 -0
- package/packages/policy-management/src/interfaces/IPolicyEngine.sol +264 -0
- package/packages/policy-management/src/interfaces/IPolicyProtected.sol +48 -0
- package/packages/policy-management/src/policies/AllowPolicy.sol +104 -0
- package/packages/policy-management/src/policies/BypassPolicy.sol +90 -0
- package/packages/policy-management/src/policies/IntervalPolicy.sol +223 -0
- package/packages/policy-management/src/policies/MaxPolicy.sol +73 -0
- package/packages/policy-management/src/policies/OnlyAuthorizedSenderPolicy.sol +84 -0
- package/packages/policy-management/src/policies/OnlyOwnerPolicy.sol +35 -0
- package/packages/policy-management/src/policies/PausePolicy.sol +82 -0
- package/packages/policy-management/src/policies/README.md +632 -0
- package/packages/policy-management/src/policies/RejectPolicy.sol +89 -0
- package/packages/policy-management/src/policies/RoleBasedAccessControlPolicy.sol +162 -0
- package/packages/policy-management/src/policies/SecureMintPolicy.sol +271 -0
- package/packages/policy-management/src/policies/VolumePolicy.sol +133 -0
- package/packages/policy-management/src/policies/VolumeRatePolicy.sol +192 -0
- package/packages/policy-management/test/PolicyEngine.t.sol +368 -0
- package/packages/policy-management/test/PolicyFactory.t.sol +114 -0
- package/packages/policy-management/test/PolicyProtectedToken.t.sol +75 -0
- package/packages/policy-management/test/extractors/ComplianceTokenForceTransferExtractor.t.sol +59 -0
- package/packages/policy-management/test/extractors/ComplianceTokenFreezeUnfreezeExtractor.t.sol +74 -0
- package/packages/policy-management/test/extractors/ComplianceTokenMintBurnExtractor.t.sol +92 -0
- package/packages/policy-management/test/extractors/ERC20ApproveExtractor.t.sol +58 -0
- package/packages/policy-management/test/extractors/ERC3643ForcedTransferExtractor.t.sol +59 -0
- package/packages/policy-management/test/extractors/ERC3643FreezeUnfreezeExtractor.t.sol +74 -0
- package/packages/policy-management/test/extractors/ERC3643MintBurnExtractor.t.sol +73 -0
- package/packages/policy-management/test/extractors/ERC3643SetAddressFrozenExtractor.t.sol +56 -0
- package/packages/policy-management/test/helpers/BaseProxyTest.sol +75 -0
- package/packages/policy-management/test/helpers/CustomMapper.sol +26 -0
- package/packages/policy-management/test/helpers/DummyExtractor.sol +11 -0
- package/packages/policy-management/test/helpers/ExpectedParameterPolicy.sol +39 -0
- package/packages/policy-management/test/helpers/MockAggregatorV3.sol +51 -0
- package/packages/policy-management/test/helpers/MockToken.sol +66 -0
- package/packages/policy-management/test/helpers/MockTokenExtractor.sol +34 -0
- package/packages/policy-management/test/helpers/PolicyAlwaysAllowed.sol +45 -0
- package/packages/policy-management/test/helpers/PolicyAlwaysContinue.sol +23 -0
- package/packages/policy-management/test/helpers/PolicyAlwaysRejected.sol +23 -0
- package/packages/policy-management/test/helpers/PolicyFailingRun.sol +22 -0
- package/packages/policy-management/test/policies/AllowPolicy.t.sol +174 -0
- package/packages/policy-management/test/policies/BypassPolicy.t.sol +159 -0
- package/packages/policy-management/test/policies/IntervalPolicy.t.sol +307 -0
- package/packages/policy-management/test/policies/MaxPolicy.t.sol +54 -0
- package/packages/policy-management/test/policies/OnlyAuthorizedSenderPolicy.t.sol +95 -0
- package/packages/policy-management/test/policies/OnlyOwnerPolicy.t.sol +47 -0
- package/packages/policy-management/test/policies/PausePolicy.t.sol +75 -0
- package/packages/policy-management/test/policies/RejectPolicy.t.sol +182 -0
- package/packages/policy-management/test/policies/RoleBasedAccessControlPolicy.t.sol +223 -0
- package/packages/policy-management/test/policies/SecureMintPolicy.t.sol +442 -0
- package/packages/policy-management/test/policies/VolumePolicy.t.sol +158 -0
- package/packages/policy-management/test/policies/VolumeRatePolicy.t.sol +165 -0
- package/packages/tokens/erc-20/src/ComplianceTokenERC20.sol +345 -0
- package/packages/tokens/erc-20/src/ComplianceTokenStoreERC20.sol +29 -0
- package/packages/tokens/erc-20/test/ComplianceTokenERC20.t.sol +556 -0
- package/packages/tokens/erc-20/test/helpers/BaseProxyTest.sol +75 -0
- package/packages/tokens/erc-3643/README.md +24 -0
- package/packages/tokens/erc-3643/src/ComplianceTokenERC3643.sol +564 -0
- package/packages/tokens/erc-3643/src/ComplianceTokenStoreERC3643.sol +30 -0
- package/packages/tokens/erc-3643/test/ComplianceTokenERC3643.t.sol +815 -0
- package/packages/tokens/erc-3643/test/helpers/BaseProxyTest.sol +76 -0
- package/packages/tokens/erc-3643/test/helpers/ExpectedContextPolicy.sol +32 -0
- package/packages/vendor/erc-3643/compliance/modular/IModularCompliance.sol +220 -0
- package/packages/vendor/erc-3643/registry/interface/IClaimTopicsRegistry.sol +101 -0
- package/packages/vendor/erc-3643/registry/interface/IIdentityRegistry.sol +251 -0
- package/packages/vendor/erc-3643/registry/interface/IIdentityRegistryStorage.sol +191 -0
- package/packages/vendor/erc-3643/registry/interface/ITrustedIssuersRegistry.sol +161 -0
- package/packages/vendor/erc-3643/token/IToken.sol +457 -0
- package/packages/vendor/onchain-id/interface/IClaimIssuer.sol +53 -0
- package/packages/vendor/onchain-id/interface/IERC734.sol +110 -0
- package/packages/vendor/onchain-id/interface/IERC735.sol +105 -0
- package/packages/vendor/onchain-id/interface/IIdentity.sol +26 -0
- package/packages/vendor/onchain-id/interface/IImplementationAuthority.sol +21 -0
- package/remappings.txt +6 -0
- package/script/DeployComplianceTokenERC20.s.sol +191 -0
- package/script/DeployComplianceTokenERC3643.s.sol +208 -0
- package/script/DeploySimpleComplianceToken.s.sol +38 -0
- package/script/getting_started/DeployGettingStarted.s.sol +74 -0
- package/script/getting_started/advanced/DeployAdvancedGettingStarted.s.sol +332 -0
- package/script/getting_started/advanced/DeploySanctionsList.s.sol +26 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IPolicyEngine, PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
5
|
+
import {PausePolicy} from "@chainlink/policy-management/policies/PausePolicy.sol";
|
|
6
|
+
import {MockToken} from "../helpers/MockToken.sol";
|
|
7
|
+
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
8
|
+
|
|
9
|
+
contract PausePolicyTest is BaseProxyTest {
|
|
10
|
+
PolicyEngine public policyEngine;
|
|
11
|
+
MockToken public token;
|
|
12
|
+
PausePolicy public pausePolicy;
|
|
13
|
+
address public deployer;
|
|
14
|
+
address public recipient;
|
|
15
|
+
|
|
16
|
+
function setUp() public {
|
|
17
|
+
deployer = makeAddr("deployer");
|
|
18
|
+
recipient = makeAddr("recipient");
|
|
19
|
+
|
|
20
|
+
vm.startPrank(deployer);
|
|
21
|
+
|
|
22
|
+
policyEngine = _deployPolicyEngine(true, deployer);
|
|
23
|
+
|
|
24
|
+
PausePolicy pausePolicyImpl = new PausePolicy();
|
|
25
|
+
bytes memory configParamBytes = abi.encode(false); // Initial paused state is false
|
|
26
|
+
pausePolicy =
|
|
27
|
+
PausePolicy(_deployPolicy(address(pausePolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
28
|
+
|
|
29
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
30
|
+
|
|
31
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(pausePolicy), new bytes32[](0));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function test_transfer_whenPaused_reverts() public {
|
|
35
|
+
vm.startPrank(deployer);
|
|
36
|
+
pausePolicy.pause();
|
|
37
|
+
|
|
38
|
+
vm.expectRevert(_encodeRejectedRevert(MockToken.transfer.selector, address(pausePolicy), "contract is paused"));
|
|
39
|
+
token.transfer(recipient, 100);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function test_transfer_whenNotPaused_succeeds() public {
|
|
43
|
+
token.transfer(recipient, 100);
|
|
44
|
+
assert(token.balanceOf(recipient) == 100);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function test_transfer_afterUnpause_succeeds() public {
|
|
48
|
+
vm.startPrank(deployer);
|
|
49
|
+
pausePolicy.pause();
|
|
50
|
+
assert(pausePolicy.s_paused() == true);
|
|
51
|
+
pausePolicy.unpause();
|
|
52
|
+
|
|
53
|
+
token.transfer(recipient, 100);
|
|
54
|
+
assert(token.balanceOf(recipient) == 100);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function test_pause_whenAlreadyPaused_reverts() public {
|
|
58
|
+
vm.startPrank(deployer);
|
|
59
|
+
|
|
60
|
+
pausePolicy.pause();
|
|
61
|
+
assert(pausePolicy.s_paused() == true);
|
|
62
|
+
|
|
63
|
+
vm.expectRevert("already paused");
|
|
64
|
+
pausePolicy.pause();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function test_unpause_whenAlreadyUnpaused_reverts() public {
|
|
68
|
+
vm.startPrank(deployer);
|
|
69
|
+
|
|
70
|
+
assert(pausePolicy.s_paused() == false);
|
|
71
|
+
|
|
72
|
+
vm.expectRevert("already unpaused");
|
|
73
|
+
pausePolicy.unpause();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IPolicyEngine, PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
5
|
+
import {ERC20TransferExtractor} from "@chainlink/policy-management/extractors/ERC20TransferExtractor.sol";
|
|
6
|
+
import {RejectPolicy} from "@chainlink/policy-management/policies/RejectPolicy.sol";
|
|
7
|
+
import {MockToken} from "../helpers/MockToken.sol";
|
|
8
|
+
import {ERC3643MintBurnExtractor} from "@chainlink/policy-management/extractors/ERC3643MintBurnExtractor.sol";
|
|
9
|
+
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
10
|
+
|
|
11
|
+
contract RejectPolicyTest is BaseProxyTest {
|
|
12
|
+
PolicyEngine public policyEngine;
|
|
13
|
+
MockToken public token;
|
|
14
|
+
RejectPolicy public rejectPolicy;
|
|
15
|
+
address public deployer;
|
|
16
|
+
address public account;
|
|
17
|
+
address public recipient;
|
|
18
|
+
|
|
19
|
+
function setUp() public {
|
|
20
|
+
deployer = makeAddr("deployer");
|
|
21
|
+
account = makeAddr("account");
|
|
22
|
+
recipient = makeAddr("recipient");
|
|
23
|
+
|
|
24
|
+
vm.startPrank(deployer, deployer);
|
|
25
|
+
|
|
26
|
+
policyEngine = _deployPolicyEngine(true, deployer);
|
|
27
|
+
|
|
28
|
+
RejectPolicy rejectPolicyImpl = new RejectPolicy();
|
|
29
|
+
rejectPolicy = RejectPolicy(_deployPolicy(address(rejectPolicyImpl), address(policyEngine), deployer, ""));
|
|
30
|
+
|
|
31
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
32
|
+
|
|
33
|
+
// set up the rejectPolicy to check the recipient and origin address of token transfers
|
|
34
|
+
ERC20TransferExtractor transferExtractor = new ERC20TransferExtractor();
|
|
35
|
+
bytes32[] memory policyParameters = new bytes32[](2);
|
|
36
|
+
policyParameters[0] = transferExtractor.PARAM_TO();
|
|
37
|
+
policyParameters[1] = transferExtractor.PARAM_FROM();
|
|
38
|
+
policyEngine.setExtractor(MockToken.transfer.selector, address(transferExtractor));
|
|
39
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(rejectPolicy), policyParameters);
|
|
40
|
+
// set up the rejectPolicy to check the mint account (single account)
|
|
41
|
+
ERC3643MintBurnExtractor mintBurnExtractor = new ERC3643MintBurnExtractor();
|
|
42
|
+
bytes32[] memory mintPolicyParams = new bytes32[](1);
|
|
43
|
+
mintPolicyParams[0] = mintBurnExtractor.PARAM_ACCOUNT();
|
|
44
|
+
policyEngine.setExtractor(MockToken.mint.selector, address(mintBurnExtractor));
|
|
45
|
+
policyEngine.addPolicy(address(token), MockToken.mint.selector, address(rejectPolicy), mintPolicyParams);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function test_rejectAddress_succeeds() public {
|
|
49
|
+
vm.startPrank(deployer, deployer);
|
|
50
|
+
|
|
51
|
+
// add the sender to the reject list
|
|
52
|
+
rejectPolicy.rejectAddress(account);
|
|
53
|
+
vm.assertEq(rejectPolicy.addressRejected(account), true);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function test_addressRejected_alreadyInList_fails() public {
|
|
57
|
+
vm.startPrank(deployer, deployer);
|
|
58
|
+
|
|
59
|
+
// add the sender to the reject list (setup and sanity check)
|
|
60
|
+
rejectPolicy.rejectAddress(account);
|
|
61
|
+
vm.assertEq(rejectPolicy.addressRejected(account), true);
|
|
62
|
+
|
|
63
|
+
// add the sender to the reject list again (reverts)
|
|
64
|
+
vm.expectRevert("Account already in reject list");
|
|
65
|
+
rejectPolicy.rejectAddress(account);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function test_unrejectAddress_succeeds() public {
|
|
69
|
+
vm.startPrank(deployer, deployer);
|
|
70
|
+
|
|
71
|
+
// add the sender to the reject list (setup and sanity check)
|
|
72
|
+
rejectPolicy.rejectAddress(account);
|
|
73
|
+
vm.assertEq(rejectPolicy.addressRejected(account), true);
|
|
74
|
+
|
|
75
|
+
// remove the sender from the reject list
|
|
76
|
+
rejectPolicy.unrejectAddress(account);
|
|
77
|
+
vm.assertEq(rejectPolicy.addressRejected(account), false);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function test_unrejectAddress_notInList_fails() public {
|
|
81
|
+
vm.startPrank(deployer, deployer);
|
|
82
|
+
|
|
83
|
+
// remove the sender from the reject list (reverts)
|
|
84
|
+
vm.expectRevert("Account not in reject list");
|
|
85
|
+
rejectPolicy.unrejectAddress(account);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function test_transfer_notInList_succeeds() public {
|
|
89
|
+
vm.startPrank(account, account);
|
|
90
|
+
|
|
91
|
+
// transfer from sender to recipient
|
|
92
|
+
token.transfer(recipient, 100);
|
|
93
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function test_transfer_inList_reverts() public {
|
|
97
|
+
vm.startPrank(deployer, deployer);
|
|
98
|
+
|
|
99
|
+
// add the recipient to the reject list
|
|
100
|
+
rejectPolicy.rejectAddress(recipient);
|
|
101
|
+
vm.assertEq(rejectPolicy.addressRejected(recipient), true);
|
|
102
|
+
|
|
103
|
+
vm.startPrank(account, account);
|
|
104
|
+
|
|
105
|
+
// transfer from sender to recipient (reverts)
|
|
106
|
+
vm.expectRevert(
|
|
107
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(rejectPolicy), "address is on reject list")
|
|
108
|
+
);
|
|
109
|
+
token.transfer(recipient, 100);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function test_transfer_allInList_reverts() public {
|
|
113
|
+
vm.startPrank(deployer, deployer);
|
|
114
|
+
|
|
115
|
+
// add the account and recipient to the reject list
|
|
116
|
+
rejectPolicy.rejectAddress(recipient);
|
|
117
|
+
vm.assertEq(rejectPolicy.addressRejected(recipient), true);
|
|
118
|
+
rejectPolicy.rejectAddress(account);
|
|
119
|
+
vm.assertEq(rejectPolicy.addressRejected(account), true);
|
|
120
|
+
|
|
121
|
+
vm.startPrank(account, account);
|
|
122
|
+
|
|
123
|
+
// transfer from sender to recipient (reverts)
|
|
124
|
+
vm.expectRevert(
|
|
125
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(rejectPolicy), "address is on reject list")
|
|
126
|
+
);
|
|
127
|
+
token.transfer(recipient, 100);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function test_transfer_removedFromList_succeeds() public {
|
|
131
|
+
// add the address to the reject list (setup)
|
|
132
|
+
vm.startPrank(deployer, deployer);
|
|
133
|
+
rejectPolicy.rejectAddress(recipient);
|
|
134
|
+
|
|
135
|
+
// transfer from address to recipient (sanity check)
|
|
136
|
+
vm.startPrank(account, account);
|
|
137
|
+
vm.expectRevert(
|
|
138
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(rejectPolicy), "address is on reject list")
|
|
139
|
+
);
|
|
140
|
+
token.transfer(recipient, 100);
|
|
141
|
+
|
|
142
|
+
// remove from the reject list
|
|
143
|
+
vm.startPrank(deployer, deployer);
|
|
144
|
+
rejectPolicy.unrejectAddress(recipient);
|
|
145
|
+
|
|
146
|
+
// transfer from address to recipient
|
|
147
|
+
vm.startPrank(account, account);
|
|
148
|
+
token.transfer(recipient, 100);
|
|
149
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function test_mint_notInList_success() public {
|
|
153
|
+
vm.startPrank(deployer, deployer);
|
|
154
|
+
token.mint(account, 100);
|
|
155
|
+
vm.assertEq(token.balanceOf(account), 100);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function test_mint_inList_failure() public {
|
|
159
|
+
vm.startPrank(deployer, deployer);
|
|
160
|
+
// add account as rejected
|
|
161
|
+
rejectPolicy.rejectAddress(account);
|
|
162
|
+
vm.assertEq(rejectPolicy.addressRejected(account), true);
|
|
163
|
+
vm.expectRevert(_encodeRejectedRevert(MockToken.mint.selector, address(rejectPolicy), "address is on reject list"));
|
|
164
|
+
token.mint(account, 100);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function test_misconfiguration_failure() public {
|
|
168
|
+
vm.startPrank(deployer);
|
|
169
|
+
// misconfigure the rejectPolicy to check mint operations
|
|
170
|
+
ERC3643MintBurnExtractor mintExtractor = new ERC3643MintBurnExtractor();
|
|
171
|
+
policyEngine.setExtractor(MockToken.burn.selector, address(mintExtractor));
|
|
172
|
+
policyEngine.addPolicy(address(token), MockToken.burn.selector, address(rejectPolicy), new bytes32[](0));
|
|
173
|
+
|
|
174
|
+
bytes memory error = abi.encodeWithSignature("Error(string)", "expected at least 1 parameter");
|
|
175
|
+
vm.expectRevert(
|
|
176
|
+
abi.encodeWithSelector(
|
|
177
|
+
IPolicyEngine.PolicyRunError.selector, MockToken.burn.selector, address(rejectPolicy), error
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
token.burn(recipient, 100);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
|
|
5
|
+
import {RoleBasedAccessControlPolicy} from "@chainlink/policy-management/policies/RoleBasedAccessControlPolicy.sol";
|
|
6
|
+
import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
|
|
7
|
+
import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
8
|
+
import {MockToken} from "../helpers/MockToken.sol";
|
|
9
|
+
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
10
|
+
|
|
11
|
+
contract RoleBasedAccessControlPolicyTest is BaseProxyTest {
|
|
12
|
+
RoleBasedAccessControlPolicy policy;
|
|
13
|
+
PolicyEngine public policyEngine;
|
|
14
|
+
MockToken public token;
|
|
15
|
+
address public deployer;
|
|
16
|
+
address public txSender;
|
|
17
|
+
address public recipient;
|
|
18
|
+
|
|
19
|
+
function setUp() public {
|
|
20
|
+
deployer = makeAddr("deployer");
|
|
21
|
+
txSender = makeAddr("txSender");
|
|
22
|
+
|
|
23
|
+
vm.startPrank(deployer);
|
|
24
|
+
|
|
25
|
+
policyEngine = _deployPolicyEngine(true, deployer);
|
|
26
|
+
|
|
27
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
28
|
+
|
|
29
|
+
RoleBasedAccessControlPolicy policyImpl = new RoleBasedAccessControlPolicy();
|
|
30
|
+
policy = RoleBasedAccessControlPolicy(_deployPolicy(address(policyImpl), address(policyEngine), deployer, ""));
|
|
31
|
+
|
|
32
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(policy), new bytes32[](0));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function test_grantRoleRevokeRole_deployer_succeeds() public {
|
|
36
|
+
bytes32 someRole = keccak256("someRole");
|
|
37
|
+
|
|
38
|
+
vm.startPrank(deployer);
|
|
39
|
+
|
|
40
|
+
vm.expectEmit();
|
|
41
|
+
emit IAccessControl.RoleGranted(someRole, txSender, deployer);
|
|
42
|
+
policy.grantRole(someRole, txSender);
|
|
43
|
+
assertEq(policy.hasRole(someRole, txSender), true);
|
|
44
|
+
vm.expectEmit();
|
|
45
|
+
emit IAccessControl.RoleRevoked(someRole, txSender, deployer);
|
|
46
|
+
policy.revokeRole(someRole, txSender);
|
|
47
|
+
assertEq(policy.hasRole(someRole, txSender), false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function test_grantRoleRevokeRole_nonDeployer_fails() public {
|
|
51
|
+
bytes32 someRole = keccak256("someRole");
|
|
52
|
+
address nonDeployer = makeAddr("nonDeployer");
|
|
53
|
+
|
|
54
|
+
vm.startPrank(nonDeployer);
|
|
55
|
+
|
|
56
|
+
vm.expectRevert(abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, nonDeployer, 0x00));
|
|
57
|
+
policy.grantRole(someRole, txSender);
|
|
58
|
+
vm.expectRevert(abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, nonDeployer, 0x00));
|
|
59
|
+
policy.revokeRole(someRole, txSender);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function test_grantRoleRevokeRole_roleAdmin_succeeds() public {
|
|
63
|
+
bytes32 someRole = keccak256("someRole");
|
|
64
|
+
address admin = makeAddr("admin");
|
|
65
|
+
|
|
66
|
+
// grant admin role of "someRole" to admin
|
|
67
|
+
vm.startPrank(deployer);
|
|
68
|
+
policy.grantRole(policy.getRoleAdmin(someRole), admin);
|
|
69
|
+
|
|
70
|
+
vm.startPrank(admin);
|
|
71
|
+
vm.expectEmit();
|
|
72
|
+
emit IAccessControl.RoleGranted(someRole, txSender, admin);
|
|
73
|
+
policy.grantRole(someRole, txSender);
|
|
74
|
+
assertEq(policy.hasRole(someRole, txSender), true);
|
|
75
|
+
vm.expectEmit();
|
|
76
|
+
emit IAccessControl.RoleRevoked(someRole, txSender, admin);
|
|
77
|
+
policy.revokeRole(someRole, txSender);
|
|
78
|
+
assertEq(policy.hasRole(someRole, txSender), false);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function test_grantOperationAllowanceToRole_succeeds() public {
|
|
82
|
+
bytes32 role = keccak256("role");
|
|
83
|
+
vm.startPrank(deployer);
|
|
84
|
+
|
|
85
|
+
// grant operation allowance to role
|
|
86
|
+
vm.expectEmit();
|
|
87
|
+
emit RoleBasedAccessControlPolicy.OperationAllowanceGrantedToRole(MockToken.transfer.selector, role);
|
|
88
|
+
policy.grantOperationAllowanceToRole(MockToken.transfer.selector, role);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function test_grantOperationAllowanceToRole_alreadyExist_fails() public {
|
|
92
|
+
bytes32 role = keccak256("role");
|
|
93
|
+
vm.startPrank(deployer);
|
|
94
|
+
|
|
95
|
+
// grant operation allowance to role (sanity check)
|
|
96
|
+
vm.expectEmit();
|
|
97
|
+
emit RoleBasedAccessControlPolicy.OperationAllowanceGrantedToRole(MockToken.transfer.selector, role);
|
|
98
|
+
policy.grantOperationAllowanceToRole(MockToken.transfer.selector, role);
|
|
99
|
+
|
|
100
|
+
// grant again (revert)
|
|
101
|
+
vm.expectRevert("Role already has operation allowance");
|
|
102
|
+
policy.grantOperationAllowanceToRole(MockToken.transfer.selector, role);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function test_removeOperationAllowanceFromRole_succeeds() public {
|
|
106
|
+
bytes32 role = keccak256("role");
|
|
107
|
+
vm.startPrank(deployer);
|
|
108
|
+
|
|
109
|
+
// grant operation allowance to role (sanity check)
|
|
110
|
+
vm.expectEmit();
|
|
111
|
+
emit RoleBasedAccessControlPolicy.OperationAllowanceGrantedToRole(MockToken.transfer.selector, role);
|
|
112
|
+
policy.grantOperationAllowanceToRole(MockToken.transfer.selector, role);
|
|
113
|
+
|
|
114
|
+
// remove operation allowance from role
|
|
115
|
+
vm.expectEmit();
|
|
116
|
+
emit RoleBasedAccessControlPolicy.OperationAllowanceRemovedFromRole(MockToken.transfer.selector, role);
|
|
117
|
+
policy.removeOperationAllowanceFromRole(MockToken.transfer.selector, role);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function test_removeOperationAllowanceFromRole_invalidOperation_fails() public {
|
|
121
|
+
bytes32 role = keccak256("role");
|
|
122
|
+
vm.startPrank(deployer);
|
|
123
|
+
|
|
124
|
+
// remove invalid operation allowance from role (revert)
|
|
125
|
+
vm.expectRevert("Role does not have operation allowance");
|
|
126
|
+
policy.removeOperationAllowanceFromRole(MockToken.transfer.selector, role);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function test_transfer_senderWithoutRole_reverts() public {
|
|
130
|
+
vm.startPrank(txSender);
|
|
131
|
+
|
|
132
|
+
vm.expectRevert(
|
|
133
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(policy), "caller lacks required role for operation")
|
|
134
|
+
);
|
|
135
|
+
token.transfer(recipient, 100);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function test_transfer_withRoleAssociatedToOperation_succeeds() public {
|
|
139
|
+
vm.startPrank(deployer);
|
|
140
|
+
bytes32 allowedRole = keccak256("allowedRole");
|
|
141
|
+
policy.grantOperationAllowanceToRole(MockToken.transfer.selector, allowedRole);
|
|
142
|
+
policy.grantRole(allowedRole, txSender);
|
|
143
|
+
|
|
144
|
+
vm.startPrank(txSender);
|
|
145
|
+
|
|
146
|
+
token.transfer(recipient, 100);
|
|
147
|
+
|
|
148
|
+
assert(token.balanceOf(recipient) == 100);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function test_transfer_withRoleAssignedToUserButNotAssociatedToOperation_reverts() public {
|
|
152
|
+
vm.startPrank(deployer);
|
|
153
|
+
bytes32 someRole = keccak256("someRole");
|
|
154
|
+
policy.grantRole(someRole, txSender);
|
|
155
|
+
|
|
156
|
+
vm.startPrank(txSender);
|
|
157
|
+
|
|
158
|
+
vm.expectRevert(
|
|
159
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(policy), "caller lacks required role for operation")
|
|
160
|
+
);
|
|
161
|
+
token.transfer(recipient, 100);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function test_transfer_withRoleAssignedToUserAndRevokedFromOperation_reverts() public {
|
|
165
|
+
vm.startPrank(deployer);
|
|
166
|
+
bytes32 allowedRole = keccak256("allowedRole");
|
|
167
|
+
policy.grantOperationAllowanceToRole(MockToken.transfer.selector, allowedRole);
|
|
168
|
+
policy.grantRole(allowedRole, txSender);
|
|
169
|
+
|
|
170
|
+
// sanity check
|
|
171
|
+
vm.startPrank(txSender);
|
|
172
|
+
token.transfer(recipient, 100);
|
|
173
|
+
assertEq(token.balanceOf(recipient), 100);
|
|
174
|
+
|
|
175
|
+
vm.startPrank(deployer);
|
|
176
|
+
policy.removeOperationAllowanceFromRole(MockToken.transfer.selector, allowedRole);
|
|
177
|
+
|
|
178
|
+
vm.startPrank(txSender);
|
|
179
|
+
vm.expectRevert(
|
|
180
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(policy), "caller lacks required role for operation")
|
|
181
|
+
);
|
|
182
|
+
token.transfer(recipient, 100);
|
|
183
|
+
assertEq(token.balanceOf(recipient), 100);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function test_transfer_senderWithRoleAssociatedToOperationButRevoked_reverts() public {
|
|
187
|
+
vm.startPrank(deployer);
|
|
188
|
+
bytes32 allowedRole = keccak256("allowedRole");
|
|
189
|
+
policy.grantOperationAllowanceToRole(MockToken.transfer.selector, allowedRole);
|
|
190
|
+
policy.grantRole(allowedRole, txSender);
|
|
191
|
+
|
|
192
|
+
// sanity check
|
|
193
|
+
vm.startPrank(txSender);
|
|
194
|
+
token.transfer(recipient, 100);
|
|
195
|
+
assert(token.balanceOf(recipient) == 100);
|
|
196
|
+
|
|
197
|
+
vm.startPrank(deployer);
|
|
198
|
+
policy.revokeRole(allowedRole, txSender);
|
|
199
|
+
|
|
200
|
+
vm.startPrank(txSender);
|
|
201
|
+
vm.expectRevert(
|
|
202
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(policy), "caller lacks required role for operation")
|
|
203
|
+
);
|
|
204
|
+
token.transfer(recipient, 100);
|
|
205
|
+
|
|
206
|
+
assert(token.balanceOf(recipient) == 100);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function test_transfer_senderWithDifferentRole_reverts() public {
|
|
210
|
+
vm.startPrank(deployer);
|
|
211
|
+
bytes32 allowedRole = keccak256("allowedRole");
|
|
212
|
+
policy.grantOperationAllowanceToRole(MockToken.transfer.selector, allowedRole);
|
|
213
|
+
|
|
214
|
+
bytes32 anotherRole = keccak256("anotherRole");
|
|
215
|
+
policy.grantRole(anotherRole, txSender);
|
|
216
|
+
|
|
217
|
+
vm.startPrank(txSender);
|
|
218
|
+
vm.expectRevert(
|
|
219
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(policy), "caller lacks required role for operation")
|
|
220
|
+
);
|
|
221
|
+
token.transfer(recipient, 100);
|
|
222
|
+
}
|
|
223
|
+
}
|