@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,159 @@
|
|
|
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 {BypassPolicy} from "@chainlink/policy-management/policies/BypassPolicy.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 BypassPolicyTest is BaseProxyTest {
|
|
12
|
+
PolicyEngine public policyEngine;
|
|
13
|
+
MockToken public token;
|
|
14
|
+
BypassPolicy public bypassPolicy;
|
|
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(false, deployer);
|
|
27
|
+
|
|
28
|
+
BypassPolicy bypassPolicyImpl = new BypassPolicy();
|
|
29
|
+
bypassPolicy = BypassPolicy(_deployPolicy(address(bypassPolicyImpl), address(policyEngine), deployer, ""));
|
|
30
|
+
// add account by default
|
|
31
|
+
bypassPolicy.allowAddress(account);
|
|
32
|
+
|
|
33
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
34
|
+
|
|
35
|
+
// set up the bypassPolicy to check the recipient and origin address of token transfers
|
|
36
|
+
ERC20TransferExtractor transferExtractor = new ERC20TransferExtractor();
|
|
37
|
+
bytes32[] memory transferPolicyParams = new bytes32[](2);
|
|
38
|
+
transferPolicyParams[0] = transferExtractor.PARAM_TO();
|
|
39
|
+
transferPolicyParams[1] = transferExtractor.PARAM_FROM();
|
|
40
|
+
policyEngine.setExtractor(MockToken.transfer.selector, address(transferExtractor));
|
|
41
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(bypassPolicy), transferPolicyParams);
|
|
42
|
+
// set up the bypassPolicy to check the mint account (single account)
|
|
43
|
+
ERC3643MintBurnExtractor mintBurnExtractor = new ERC3643MintBurnExtractor();
|
|
44
|
+
bytes32[] memory mintPolicyParams = new bytes32[](1);
|
|
45
|
+
mintPolicyParams[0] = mintBurnExtractor.PARAM_ACCOUNT();
|
|
46
|
+
policyEngine.setExtractor(MockToken.mint.selector, address(mintBurnExtractor));
|
|
47
|
+
policyEngine.addPolicy(address(token), MockToken.mint.selector, address(bypassPolicy), mintPolicyParams);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function test_allowAddress_succeeds() public {
|
|
51
|
+
vm.startPrank(deployer, deployer);
|
|
52
|
+
|
|
53
|
+
// add the address to the allow list
|
|
54
|
+
bypassPolicy.allowAddress(recipient);
|
|
55
|
+
vm.assertEq(bypassPolicy.addressAllowed(recipient), true);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function test_allowAddress_alreadyInList_fails() public {
|
|
59
|
+
vm.startPrank(deployer, deployer);
|
|
60
|
+
|
|
61
|
+
// add the address to the bypass list (setup and sanity check)
|
|
62
|
+
bypassPolicy.allowAddress(recipient);
|
|
63
|
+
vm.assertEq(bypassPolicy.addressAllowed(recipient), true);
|
|
64
|
+
|
|
65
|
+
// add the address to the bypass list again (reverts)
|
|
66
|
+
vm.expectRevert("Account already in bypass list");
|
|
67
|
+
bypassPolicy.allowAddress(recipient);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function test_disallowAddress_succeeds() public {
|
|
71
|
+
vm.startPrank(deployer, deployer);
|
|
72
|
+
|
|
73
|
+
// add the address to the bypass list (setup and sanity check)
|
|
74
|
+
bypassPolicy.allowAddress(recipient);
|
|
75
|
+
vm.assertEq(bypassPolicy.addressAllowed(recipient), true);
|
|
76
|
+
|
|
77
|
+
// remove the address from the bypass list
|
|
78
|
+
bypassPolicy.disallowAddress(recipient);
|
|
79
|
+
vm.assertEq(bypassPolicy.addressAllowed(recipient), false);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function test_disallowAddress_notInList_fails() public {
|
|
83
|
+
vm.startPrank(deployer, deployer);
|
|
84
|
+
|
|
85
|
+
// remove the address from the bypass list (reverts)
|
|
86
|
+
vm.expectRevert("Account not in bypass list");
|
|
87
|
+
bypassPolicy.disallowAddress(recipient);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function test_transfer_inList_succeeds() public {
|
|
91
|
+
vm.startPrank(deployer, deployer);
|
|
92
|
+
|
|
93
|
+
// add the recipient to the bypass list
|
|
94
|
+
bypassPolicy.allowAddress(recipient);
|
|
95
|
+
vm.assertEq(bypassPolicy.addressAllowed(recipient), true);
|
|
96
|
+
|
|
97
|
+
vm.startPrank(account, account);
|
|
98
|
+
|
|
99
|
+
// transfer from address to recipient
|
|
100
|
+
token.transfer(recipient, 100);
|
|
101
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function test_transfer_notInList_defaultReject_fails() public {
|
|
105
|
+
vm.startPrank(account, account);
|
|
106
|
+
|
|
107
|
+
// transfer from address to recipient (reverts)
|
|
108
|
+
vm.expectRevert(_encodeRejectedRevert(0, address(0), "no policy allowed the action and default is reject"));
|
|
109
|
+
token.transfer(recipient, 100);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function test_transfer_removedFromList_defaultReject_fails() public {
|
|
113
|
+
// add the address to the bypass list (setup)
|
|
114
|
+
vm.startPrank(deployer, deployer);
|
|
115
|
+
bypassPolicy.allowAddress(recipient);
|
|
116
|
+
|
|
117
|
+
// transfer from address to recipient (sanity check)
|
|
118
|
+
vm.startPrank(account, account);
|
|
119
|
+
token.transfer(recipient, 100);
|
|
120
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
121
|
+
|
|
122
|
+
// remove from the bypass list
|
|
123
|
+
vm.startPrank(deployer, deployer);
|
|
124
|
+
bypassPolicy.disallowAddress(recipient);
|
|
125
|
+
|
|
126
|
+
// transfer from address to recipient (should revert after removal)
|
|
127
|
+
vm.startPrank(account, account);
|
|
128
|
+
vm.expectRevert(_encodeRejectedRevert(0, address(0), "no policy allowed the action and default is reject"));
|
|
129
|
+
token.transfer(recipient, 100);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function test_mint_inList_success() public {
|
|
133
|
+
vm.startPrank(deployer, deployer);
|
|
134
|
+
token.mint(account, 100);
|
|
135
|
+
vm.assertEq(token.balanceOf(account), 100);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function test_mint_notInList_defaultReject_failure() public {
|
|
139
|
+
vm.startPrank(deployer, deployer);
|
|
140
|
+
vm.expectRevert(_encodeRejectedRevert(0, address(0), "no policy allowed the action and default is reject"));
|
|
141
|
+
token.mint(recipient, 100);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function test_misconfiguration_failure() public {
|
|
145
|
+
vm.startPrank(deployer);
|
|
146
|
+
// misconfigure the bypassPolicy to check burn operations (no accounts)
|
|
147
|
+
ERC3643MintBurnExtractor mintBurnExtractor = new ERC3643MintBurnExtractor();
|
|
148
|
+
policyEngine.setExtractor(MockToken.burn.selector, address(mintBurnExtractor));
|
|
149
|
+
policyEngine.addPolicy(address(token), MockToken.burn.selector, address(bypassPolicy), new bytes32[](0));
|
|
150
|
+
|
|
151
|
+
bytes memory error = abi.encodeWithSignature("Error(string)", "expected at least 1 parameter");
|
|
152
|
+
vm.expectRevert(
|
|
153
|
+
abi.encodeWithSelector(
|
|
154
|
+
IPolicyEngine.PolicyRunError.selector, MockToken.burn.selector, address(bypassPolicy), error
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
token.burn(account, 100);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
|
|
5
|
+
import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
6
|
+
import {IntervalPolicy} from "@chainlink/policy-management/policies/IntervalPolicy.sol";
|
|
7
|
+
import {MockToken} from "../helpers/MockToken.sol";
|
|
8
|
+
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
9
|
+
|
|
10
|
+
contract IntervalPolicyTest is BaseProxyTest {
|
|
11
|
+
PolicyEngine public policyEngine;
|
|
12
|
+
IntervalPolicy public intervalPolicy;
|
|
13
|
+
MockToken public token;
|
|
14
|
+
address public deployer;
|
|
15
|
+
address public recipient;
|
|
16
|
+
uint256 public OFFSET_TIMESTAMP = 1737470407; // Tue Jan 21 2025 14:40:07
|
|
17
|
+
|
|
18
|
+
function setUp() public {
|
|
19
|
+
deployer = makeAddr("deployer");
|
|
20
|
+
recipient = makeAddr("recipient");
|
|
21
|
+
|
|
22
|
+
vm.startPrank(deployer);
|
|
23
|
+
|
|
24
|
+
policyEngine = _deployPolicyEngine(true, deployer);
|
|
25
|
+
|
|
26
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
27
|
+
|
|
28
|
+
IntervalPolicy intervalPolicyImpl = new IntervalPolicy();
|
|
29
|
+
bytes memory configParamBytes = abi.encode(
|
|
30
|
+
11, // start slot
|
|
31
|
+
17, // end slot
|
|
32
|
+
1 hours, // slot duration
|
|
33
|
+
24, // cycle size (24 slots for 24 hours)
|
|
34
|
+
0 // cycle offset
|
|
35
|
+
);
|
|
36
|
+
intervalPolicy =
|
|
37
|
+
IntervalPolicy(_deployPolicy(address(intervalPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
38
|
+
|
|
39
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(intervalPolicy), new bytes32[](0));
|
|
40
|
+
vm.warp(OFFSET_TIMESTAMP);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function generateTimestampForTargetHour(uint256 targetHour) private view returns (uint256) {
|
|
44
|
+
uint256 currentTimestamp = block.timestamp;
|
|
45
|
+
uint256 currentHour = (currentTimestamp / 3600) % 24;
|
|
46
|
+
if (targetHour > currentHour) {
|
|
47
|
+
uint256 hoursToAdd = targetHour - currentHour;
|
|
48
|
+
return currentTimestamp + (hoursToAdd * 3600);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
uint256 hoursToDecrease = currentHour - targetHour;
|
|
52
|
+
return currentTimestamp - (hoursToDecrease * 3600);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function generateTimestampForTargetDayAndHour(uint256 targetDay, uint256 targetHour) private view returns (uint256) {
|
|
56
|
+
uint256 currentTimestamp = block.timestamp;
|
|
57
|
+
uint256 timestampWithHour = generateTimestampForTargetHour(targetHour);
|
|
58
|
+
uint256 currentDay = (currentTimestamp / 86400 + 4) % 7;
|
|
59
|
+
uint256 daysToAdd = (targetDay + 7 - currentDay) % 7;
|
|
60
|
+
uint256 newTimestamp = timestampWithHour + (daysToAdd * 86400);
|
|
61
|
+
return newTimestamp;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function test_transfer_timeWithinInterval_succeeds() public {
|
|
65
|
+
uint256 timestamp = generateTimestampForTargetHour(16);
|
|
66
|
+
vm.warp(timestamp);
|
|
67
|
+
token.transfer(recipient, 100);
|
|
68
|
+
|
|
69
|
+
assert(token.balanceOf(recipient) == 100);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function test_transfer_timeExtractorExtractsTimeBelowLowerBoundInterval_reverts() public {
|
|
73
|
+
uint256 timestamp = generateTimestampForTargetHour(10);
|
|
74
|
+
vm.warp(timestamp);
|
|
75
|
+
vm.expectRevert(
|
|
76
|
+
_encodeRejectedRevert(
|
|
77
|
+
MockToken.transfer.selector, address(intervalPolicy), "execution outside allowed time interval"
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
token.transfer(recipient, 100);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function test_transfer_timeExtractorExtractsTimeAboveUpperBoundInterval_reverts() public {
|
|
84
|
+
uint256 timestamp = generateTimestampForTargetHour(18);
|
|
85
|
+
vm.warp(timestamp);
|
|
86
|
+
vm.expectRevert(
|
|
87
|
+
_encodeRejectedRevert(
|
|
88
|
+
MockToken.transfer.selector, address(intervalPolicy), "execution outside allowed time interval"
|
|
89
|
+
)
|
|
90
|
+
);
|
|
91
|
+
token.transfer(recipient, 100);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function test_transfer_timeExtractorWithTwoPoliciesExtractsTimeWithinInterval_succeeds() public {
|
|
95
|
+
vm.startPrank(deployer);
|
|
96
|
+
IntervalPolicy dayIntervalPolicyImpl = new IntervalPolicy();
|
|
97
|
+
bytes memory configParamBytes = abi.encode(1, 6, 1 days, 7, 4);
|
|
98
|
+
IntervalPolicy dayIntervalPolicy =
|
|
99
|
+
IntervalPolicy(_deployPolicy(address(dayIntervalPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
100
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(dayIntervalPolicy), new bytes32[](0));
|
|
101
|
+
|
|
102
|
+
uint256 timestamp = generateTimestampForTargetDayAndHour(2, 13);
|
|
103
|
+
vm.warp(timestamp);
|
|
104
|
+
token.transfer(recipient, 100);
|
|
105
|
+
|
|
106
|
+
assert(token.balanceOf(recipient) == 100);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function test_transfer_timeExtractorWithTwoPoliciesHourBelowLowerBoundInterval_reverts() public {
|
|
110
|
+
vm.startPrank(deployer);
|
|
111
|
+
IntervalPolicy dayIntervalPolicyImpl = new IntervalPolicy();
|
|
112
|
+
bytes memory configParamBytes = abi.encode(1, 6, 1 days, 7, 4);
|
|
113
|
+
IntervalPolicy dayIntervalPolicy =
|
|
114
|
+
IntervalPolicy(_deployPolicy(address(dayIntervalPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
115
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(dayIntervalPolicy), new bytes32[](0));
|
|
116
|
+
|
|
117
|
+
uint256 timestamp = generateTimestampForTargetDayAndHour(2, 10);
|
|
118
|
+
vm.warp(timestamp);
|
|
119
|
+
vm.expectRevert(
|
|
120
|
+
_encodeRejectedRevert(
|
|
121
|
+
MockToken.transfer.selector, address(intervalPolicy), "execution outside allowed time interval"
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
token.transfer(recipient, 100);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function test_transfer_timeExtractorWithTwoPoliciesHourAboveUpperBoundInterval_reverts() public {
|
|
128
|
+
vm.startPrank(deployer);
|
|
129
|
+
IntervalPolicy dayIntervalPolicyImpl = new IntervalPolicy();
|
|
130
|
+
bytes memory configParamBytes = abi.encode(1, 6, 1 days, 7, 4);
|
|
131
|
+
IntervalPolicy dayIntervalPolicy =
|
|
132
|
+
IntervalPolicy(_deployPolicy(address(dayIntervalPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
133
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(dayIntervalPolicy), new bytes32[](0));
|
|
134
|
+
|
|
135
|
+
uint256 timestamp = generateTimestampForTargetDayAndHour(2, 18);
|
|
136
|
+
vm.warp(timestamp);
|
|
137
|
+
vm.expectRevert(
|
|
138
|
+
_encodeRejectedRevert(
|
|
139
|
+
MockToken.transfer.selector, address(intervalPolicy), "execution outside allowed time interval"
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
token.transfer(recipient, 100);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function test_transfer_timeExtractorWithTwoPoliciesDayBelowLowerBoundInterval_reverts() public {
|
|
146
|
+
vm.startPrank(deployer);
|
|
147
|
+
IntervalPolicy dayIntervalPolicyImpl = new IntervalPolicy();
|
|
148
|
+
bytes memory configParamBytes = abi.encode(1, 6, 1 days, 7, 4);
|
|
149
|
+
IntervalPolicy dayIntervalPolicy =
|
|
150
|
+
IntervalPolicy(_deployPolicy(address(dayIntervalPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
151
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(dayIntervalPolicy), new bytes32[](0));
|
|
152
|
+
|
|
153
|
+
uint256 timestamp = generateTimestampForTargetDayAndHour(0, 14);
|
|
154
|
+
vm.warp(timestamp);
|
|
155
|
+
vm.expectRevert(
|
|
156
|
+
_encodeRejectedRevert(
|
|
157
|
+
MockToken.transfer.selector, address(dayIntervalPolicy), "execution outside allowed time interval"
|
|
158
|
+
)
|
|
159
|
+
);
|
|
160
|
+
token.transfer(recipient, 100);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function test_transfer_timeExtractorWithTwoPoliciesDayAboveUpperBoundInterval_reverts() public {
|
|
164
|
+
vm.startPrank(deployer);
|
|
165
|
+
IntervalPolicy dayIntervalPolicyImpl = new IntervalPolicy();
|
|
166
|
+
bytes memory configParamBytes = abi.encode(1, 6, 1 days, 7, 4);
|
|
167
|
+
IntervalPolicy dayIntervalPolicy =
|
|
168
|
+
IntervalPolicy(_deployPolicy(address(dayIntervalPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
169
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(dayIntervalPolicy), new bytes32[](0));
|
|
170
|
+
|
|
171
|
+
uint256 timestamp = generateTimestampForTargetDayAndHour(6, 14);
|
|
172
|
+
vm.warp(timestamp);
|
|
173
|
+
vm.expectRevert(
|
|
174
|
+
_encodeRejectedRevert(
|
|
175
|
+
MockToken.transfer.selector, address(dayIntervalPolicy), "execution outside allowed time interval"
|
|
176
|
+
)
|
|
177
|
+
);
|
|
178
|
+
token.transfer(recipient, 100);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function test_setUpEndGreaterThanTimePeriodWindow_reverts() public {
|
|
182
|
+
vm.startPrank(deployer);
|
|
183
|
+
vm.expectRevert("End slot must be greater than start slot");
|
|
184
|
+
intervalPolicy.setEndSlot(2);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function test_configure_emitsAllEvents() public {
|
|
188
|
+
vm.startPrank(deployer);
|
|
189
|
+
|
|
190
|
+
IntervalPolicy intervalPolicyImpl = new IntervalPolicy();
|
|
191
|
+
bytes memory configParamBytes = abi.encode(
|
|
192
|
+
5, // start slot
|
|
193
|
+
15, // end slot
|
|
194
|
+
2 hours, // slot duration
|
|
195
|
+
24, // cycle size
|
|
196
|
+
2 // cycle offset
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
vm.expectEmit(true, true, true, true);
|
|
200
|
+
emit IntervalPolicy.StartSlotSet(5);
|
|
201
|
+
vm.expectEmit(true, true, true, true);
|
|
202
|
+
emit IntervalPolicy.EndSlotSet(15);
|
|
203
|
+
vm.expectEmit(true, true, true, true);
|
|
204
|
+
emit IntervalPolicy.CycleParametersSet(2 hours, 24, 2);
|
|
205
|
+
|
|
206
|
+
IntervalPolicy(_deployPolicy(address(intervalPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function test_setStartSlot_emitsEvent() public {
|
|
210
|
+
vm.startPrank(deployer);
|
|
211
|
+
|
|
212
|
+
vm.expectEmit(true, true, true, true);
|
|
213
|
+
emit IntervalPolicy.StartSlotSet(5);
|
|
214
|
+
intervalPolicy.setStartSlot(5);
|
|
215
|
+
|
|
216
|
+
assertEq(intervalPolicy.getStartSlot(), 5);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function test_setEndSlot_emitsEvent() public {
|
|
220
|
+
vm.startPrank(deployer);
|
|
221
|
+
|
|
222
|
+
vm.expectEmit(true, true, true, true);
|
|
223
|
+
emit IntervalPolicy.EndSlotSet(20);
|
|
224
|
+
intervalPolicy.setEndSlot(20);
|
|
225
|
+
|
|
226
|
+
assertEq(intervalPolicy.getEndSlot(), 20);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function test_setCycleParameters_emitsEvent() public {
|
|
230
|
+
vm.startPrank(deployer);
|
|
231
|
+
|
|
232
|
+
intervalPolicy.setEndSlot(23);
|
|
233
|
+
|
|
234
|
+
vm.expectEmit(true, true, true, true);
|
|
235
|
+
emit IntervalPolicy.CycleParametersSet(30 minutes, 48, 5);
|
|
236
|
+
intervalPolicy.setCycleParameters(30 minutes, 48, 5);
|
|
237
|
+
|
|
238
|
+
(uint256 slotDuration, uint256 cycleSize, uint256 cycleOffset) = intervalPolicy.getCycleParameters();
|
|
239
|
+
assertEq(slotDuration, 30 minutes);
|
|
240
|
+
assertEq(cycleSize, 48);
|
|
241
|
+
assertEq(cycleOffset, 5);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function test_canSetEndSlotEqualToCycleSize_succeeds() public {
|
|
245
|
+
vm.startPrank(deployer);
|
|
246
|
+
|
|
247
|
+
IntervalPolicy lastSlotPolicyImpl = new IntervalPolicy();
|
|
248
|
+
bytes memory configParamBytes = abi.encode(5, 12, 1 hours, 12, 0);
|
|
249
|
+
|
|
250
|
+
IntervalPolicy lastSlotPolicy =
|
|
251
|
+
IntervalPolicy(_deployPolicy(address(lastSlotPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
252
|
+
|
|
253
|
+
assertEq(lastSlotPolicy.getStartSlot(), 5);
|
|
254
|
+
assertEq(lastSlotPolicy.getEndSlot(), 12);
|
|
255
|
+
(, uint256 cycleSize,) = lastSlotPolicy.getCycleParameters();
|
|
256
|
+
assertEq(cycleSize, 12);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function test_firstSlotAndlastSlotExecution_succeds() public {
|
|
260
|
+
vm.startPrank(deployer);
|
|
261
|
+
|
|
262
|
+
policyEngine.removePolicy(address(token), MockToken.transfer.selector, address(intervalPolicy));
|
|
263
|
+
|
|
264
|
+
IntervalPolicy lastSlotPolicyImpl = new IntervalPolicy();
|
|
265
|
+
bytes memory configParamBytes = abi.encode(
|
|
266
|
+
5, // start slot
|
|
267
|
+
12, // end slot (equal to cycle size - now allowed)
|
|
268
|
+
1 hours, // slot duration
|
|
269
|
+
12, // cycle size
|
|
270
|
+
0 // cycle offset
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
IntervalPolicy lastSlotPolicy =
|
|
274
|
+
IntervalPolicy(_deployPolicy(address(lastSlotPolicyImpl), address(policyEngine), deployer, configParamBytes));
|
|
275
|
+
|
|
276
|
+
assertEq(lastSlotPolicy.getStartSlot(), 5);
|
|
277
|
+
assertEq(lastSlotPolicy.getEndSlot(), 12);
|
|
278
|
+
(, uint256 cycleSize,) = lastSlotPolicy.getCycleParameters();
|
|
279
|
+
assertEq(cycleSize, 12);
|
|
280
|
+
|
|
281
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(lastSlotPolicy), new bytes32[](0));
|
|
282
|
+
|
|
283
|
+
uint256 baseTimestamp = (12 * 3600);
|
|
284
|
+
|
|
285
|
+
uint256 slot5Timestamp = baseTimestamp + (5 * 3600);
|
|
286
|
+
vm.warp(slot5Timestamp);
|
|
287
|
+
|
|
288
|
+
token.transfer(recipient, 50);
|
|
289
|
+
assertEq(token.balanceOf(recipient), 50);
|
|
290
|
+
|
|
291
|
+
uint256 slot4Timestamp = baseTimestamp + (4 * 3600);
|
|
292
|
+
vm.warp(slot4Timestamp);
|
|
293
|
+
|
|
294
|
+
vm.expectRevert(
|
|
295
|
+
_encodeRejectedRevert(
|
|
296
|
+
MockToken.transfer.selector, address(lastSlotPolicy), "execution outside allowed time interval"
|
|
297
|
+
)
|
|
298
|
+
);
|
|
299
|
+
token.transfer(recipient, 25);
|
|
300
|
+
|
|
301
|
+
uint256 slot11Timestamp = baseTimestamp + (11 * 3600);
|
|
302
|
+
vm.warp(slot11Timestamp);
|
|
303
|
+
|
|
304
|
+
token.transfer(recipient, 100);
|
|
305
|
+
assertEq(token.balanceOf(recipient), 150);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
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 {MaxPolicy} from "@chainlink/policy-management/policies/MaxPolicy.sol";
|
|
6
|
+
import {ERC20TransferExtractor} from "@chainlink/policy-management/extractors/ERC20TransferExtractor.sol";
|
|
7
|
+
import {MockToken} from "../helpers/MockToken.sol";
|
|
8
|
+
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
9
|
+
|
|
10
|
+
contract MaxPolicyTest is BaseProxyTest {
|
|
11
|
+
PolicyEngine public policyEngine;
|
|
12
|
+
MockToken public token;
|
|
13
|
+
MaxPolicy public policy;
|
|
14
|
+
address public deployer;
|
|
15
|
+
address public recipient;
|
|
16
|
+
|
|
17
|
+
function setUp() public {
|
|
18
|
+
deployer = makeAddr("deployer");
|
|
19
|
+
recipient = makeAddr("recipient");
|
|
20
|
+
|
|
21
|
+
vm.startPrank(deployer);
|
|
22
|
+
|
|
23
|
+
policyEngine = _deployPolicyEngine(true, deployer);
|
|
24
|
+
|
|
25
|
+
MaxPolicy policyImpl = new MaxPolicy();
|
|
26
|
+
policy = MaxPolicy(_deployPolicy(address(policyImpl), address(policyEngine), deployer, abi.encode(100)));
|
|
27
|
+
ERC20TransferExtractor extractor = new ERC20TransferExtractor();
|
|
28
|
+
bytes32[] memory parameterOutputFormat = new bytes32[](1);
|
|
29
|
+
parameterOutputFormat[0] = extractor.PARAM_AMOUNT();
|
|
30
|
+
|
|
31
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
32
|
+
|
|
33
|
+
policyEngine.setExtractor(MockToken.transfer.selector, address(extractor));
|
|
34
|
+
|
|
35
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(policy), parameterOutputFormat);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function test_setMax_success() public {
|
|
39
|
+
policy.setMax(200);
|
|
40
|
+
vm.assertEq(policy.getMax(), 200);
|
|
41
|
+
token.transfer(recipient, 200);
|
|
42
|
+
vm.assertEq(token.balanceOf(recipient), 200);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function test_transfer_success() public {
|
|
46
|
+
token.transfer(recipient, 100);
|
|
47
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function test_transfer_overMax_reverts() public {
|
|
51
|
+
vm.expectRevert(_encodeRejectedRevert(MockToken.transfer.selector, address(policy), "amount exceeds maximum limit"));
|
|
52
|
+
token.transfer(recipient, 200);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
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 {OnlyAuthorizedSenderPolicy} from "@chainlink/policy-management/policies/OnlyAuthorizedSenderPolicy.sol";
|
|
6
|
+
import {MockToken} from "../helpers/MockToken.sol";
|
|
7
|
+
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
8
|
+
|
|
9
|
+
contract OnlyAuthorizedSenderPolicyTest is BaseProxyTest {
|
|
10
|
+
PolicyEngine public policyEngine;
|
|
11
|
+
MockToken public token;
|
|
12
|
+
OnlyAuthorizedSenderPolicy public policy;
|
|
13
|
+
address public deployer;
|
|
14
|
+
address public sender;
|
|
15
|
+
address public recipient;
|
|
16
|
+
|
|
17
|
+
function setUp() public {
|
|
18
|
+
deployer = makeAddr("deployer");
|
|
19
|
+
sender = makeAddr("sender");
|
|
20
|
+
recipient = makeAddr("recipient");
|
|
21
|
+
|
|
22
|
+
vm.startPrank(deployer, deployer);
|
|
23
|
+
|
|
24
|
+
policyEngine = _deployPolicyEngine(true, deployer);
|
|
25
|
+
|
|
26
|
+
OnlyAuthorizedSenderPolicy policyImpl = new OnlyAuthorizedSenderPolicy();
|
|
27
|
+
policy = OnlyAuthorizedSenderPolicy(_deployPolicy(address(policyImpl), address(policyEngine), deployer, ""));
|
|
28
|
+
|
|
29
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
30
|
+
|
|
31
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(policy), new bytes32[](0));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function test_authorizeSender_succeeds() public {
|
|
35
|
+
vm.startPrank(deployer, deployer);
|
|
36
|
+
|
|
37
|
+
// add the sender to the authorized list
|
|
38
|
+
policy.authorizeSender(sender);
|
|
39
|
+
vm.assertEq(policy.senderAuthorized(sender), true);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function test_authorizeSender_alreadyInList_fails() public {
|
|
43
|
+
vm.startPrank(deployer, deployer);
|
|
44
|
+
|
|
45
|
+
// add the sender to the authorized list (setup and sanity check)
|
|
46
|
+
policy.authorizeSender(sender);
|
|
47
|
+
vm.assertEq(policy.senderAuthorized(sender), true);
|
|
48
|
+
|
|
49
|
+
// add the sender to the authorized list again (reverts)
|
|
50
|
+
vm.expectRevert("Account already in authorized list");
|
|
51
|
+
policy.authorizeSender(sender);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function test_unauthorizeSender_succeeds() public {
|
|
55
|
+
vm.startPrank(deployer, deployer);
|
|
56
|
+
|
|
57
|
+
// add the sender to the authorized list (setup and sanity check)
|
|
58
|
+
policy.authorizeSender(sender);
|
|
59
|
+
vm.assertEq(policy.senderAuthorized(sender), true);
|
|
60
|
+
|
|
61
|
+
// remove the sender from the authorized list
|
|
62
|
+
policy.unauthorizeSender(sender);
|
|
63
|
+
vm.assertEq(policy.senderAuthorized(sender), false);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function test_unauthorizeSender_notInList_fails() public {
|
|
67
|
+
vm.startPrank(deployer, deployer);
|
|
68
|
+
|
|
69
|
+
// remove the sender from the authorized list (reverts)
|
|
70
|
+
vm.expectRevert("Account not in authorized list");
|
|
71
|
+
policy.unauthorizeSender(sender);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function test_transfer_inList_succeeds() public {
|
|
75
|
+
vm.startPrank(deployer, deployer);
|
|
76
|
+
|
|
77
|
+
// add the sender to the allow list
|
|
78
|
+
policy.authorizeSender(sender);
|
|
79
|
+
vm.assertEq(policy.senderAuthorized(sender), true);
|
|
80
|
+
|
|
81
|
+
vm.startPrank(sender, sender);
|
|
82
|
+
|
|
83
|
+
// transfer from sender to recipient
|
|
84
|
+
token.transfer(recipient, 100);
|
|
85
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function test_transfer_notInList_fails() public {
|
|
89
|
+
vm.startPrank(sender, sender);
|
|
90
|
+
|
|
91
|
+
// transfer from sender to recipient (reverts)
|
|
92
|
+
vm.expectRevert(_encodeRejectedRevert(MockToken.transfer.selector, address(policy), "sender is not authorized"));
|
|
93
|
+
token.transfer(recipient, 100);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
5
|
+
import {IPolicyEngine, PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
6
|
+
import {OnlyOwnerPolicy} from "@chainlink/policy-management/policies/OnlyOwnerPolicy.sol";
|
|
7
|
+
import {MockToken} from "../helpers/MockToken.sol";
|
|
8
|
+
|
|
9
|
+
contract OnlyOwnerPolicyTest is BaseProxyTest {
|
|
10
|
+
PolicyEngine public policyEngine;
|
|
11
|
+
MockToken public token;
|
|
12
|
+
OnlyOwnerPolicy public policy;
|
|
13
|
+
address public deployer;
|
|
14
|
+
address public account;
|
|
15
|
+
address public recipient;
|
|
16
|
+
|
|
17
|
+
function setUp() public {
|
|
18
|
+
deployer = makeAddr("deployer");
|
|
19
|
+
account = makeAddr("account");
|
|
20
|
+
recipient = makeAddr("recipient");
|
|
21
|
+
|
|
22
|
+
vm.startPrank(deployer, deployer);
|
|
23
|
+
|
|
24
|
+
policyEngine = PolicyEngine(_deployPolicyEngine(true, deployer));
|
|
25
|
+
|
|
26
|
+
OnlyOwnerPolicy policyImpl = new OnlyOwnerPolicy();
|
|
27
|
+
policy = OnlyOwnerPolicy(_deployPolicy(address(policyImpl), address(policyEngine), deployer, new bytes(0)));
|
|
28
|
+
|
|
29
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
30
|
+
|
|
31
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(policy), new bytes32[](0));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function test_transfer_owner_success() public {
|
|
35
|
+
vm.startPrank(deployer, deployer);
|
|
36
|
+
token.transfer(recipient, 100);
|
|
37
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function test_transfer_notOwner_reverts() public {
|
|
41
|
+
vm.startPrank(account, account);
|
|
42
|
+
vm.expectRevert(
|
|
43
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(policy), "caller is not the policy owner")
|
|
44
|
+
);
|
|
45
|
+
token.transfer(recipient, 100);
|
|
46
|
+
}
|
|
47
|
+
}
|