@chainlink/ace 0.5.0 → 1.0.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/.github/workflows/npm-publish.yml +28 -0
- package/README.md +9 -1
- package/UPGRADE_GUIDE.md +754 -0
- package/getting_started/GETTING_STARTED.md +6 -0
- package/getting_started/MyVault.sol +2 -2
- package/getting_started/advanced/SanctionsPolicy.sol +6 -2
- package/package.json +3 -3
- package/packages/cross-chain-identity/docs/API_REFERENCE.md +2 -0
- package/packages/cross-chain-identity/src/CredentialRegistry.sol +9 -7
- package/packages/cross-chain-identity/src/CredentialRegistryFactory.sol +96 -0
- package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidator.sol +15 -4
- package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidatorPolicy.sol +10 -7
- package/packages/cross-chain-identity/src/IdentityRegistry.sol +33 -17
- package/packages/cross-chain-identity/src/IdentityRegistryFactory.sol +96 -0
- package/packages/cross-chain-identity/src/TrustedIssuerRegistry.sol +8 -6
- package/packages/cross-chain-identity/src/TrustedIssuerRegistryFactory.sol +96 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialRegistry.sol +6 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialRequirements.sol +2 -1
- package/packages/cross-chain-identity/src/interfaces/IIdentityRegistry.sol +7 -1
- package/packages/cross-chain-identity/src/interfaces/ITrustedIssuerRegistry.sol +6 -0
- package/packages/cross-chain-identity/test/CredentialRegistry.t.sol +1 -1
- package/packages/cross-chain-identity/test/CredentialRegistryFactory.t.sol +105 -0
- package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidator.t.sol +16 -1
- package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidatorPolicy.t.sol +58 -1
- package/packages/cross-chain-identity/test/IdentityRegistry.t.sol +140 -1
- package/packages/cross-chain-identity/test/IdentityRegistryFactory.t.sol +103 -0
- package/packages/cross-chain-identity/test/IdentityValidator.t.sol +1 -1
- package/packages/cross-chain-identity/test/TrustedIssuerRegistry.t.sol +1 -1
- package/packages/cross-chain-identity/test/TrustedIssuerRegistryFactory.t.sol +107 -0
- package/packages/cross-chain-identity/test/helpers/BaseProxyTest.sol +1 -1
- package/packages/cross-chain-identity/test/helpers/MockCredentialDataValidator.sol +1 -1
- package/packages/cross-chain-identity/test/helpers/MockCredentialRegistryReverting.sol +3 -1
- package/packages/policy-management/README.md +1 -0
- package/packages/policy-management/docs/API_GUIDE.md +2 -0
- package/packages/policy-management/docs/API_REFERENCE.md +3 -1
- package/packages/policy-management/docs/CUSTOM_POLICIES_TUTORIAL.md +10 -4
- package/packages/policy-management/src/core/Policy.sol +5 -4
- package/packages/policy-management/src/core/PolicyEngine.sol +113 -57
- package/packages/policy-management/src/core/PolicyEngineFactory.sol +102 -0
- package/packages/policy-management/src/core/PolicyFactory.sol +1 -1
- package/packages/policy-management/src/core/PolicyProtected.sol +28 -55
- package/packages/policy-management/src/core/PolicyProtectedUpgradeable.sol +134 -0
- package/packages/policy-management/src/extractors/ComplianceTokenForceTransferExtractor.sol +4 -1
- package/packages/policy-management/src/extractors/ComplianceTokenFreezeUnfreezeExtractor.sol +4 -1
- package/packages/policy-management/src/extractors/ComplianceTokenMintBurnExtractor.sol +4 -1
- package/packages/policy-management/src/extractors/ERC20ApproveExtractor.sol +4 -1
- package/packages/policy-management/src/extractors/ERC20TransferExtractor.sol +4 -1
- package/packages/policy-management/src/extractors/ERC3643ForcedTransferExtractor.sol +4 -1
- package/packages/policy-management/src/extractors/ERC3643FreezeUnfreezeExtractor.sol +4 -1
- package/packages/policy-management/src/extractors/ERC3643MintBurnExtractor.sol +4 -1
- package/packages/policy-management/src/extractors/ERC3643SetAddressFrozenExtractor.sol +4 -1
- package/packages/policy-management/src/interfaces/ICertifiedActionValidator.sol +110 -0
- package/packages/policy-management/src/interfaces/IExtractor.sol +6 -0
- package/packages/policy-management/src/interfaces/IMapper.sol +6 -0
- package/packages/policy-management/src/interfaces/IPolicy.sol +6 -0
- package/packages/policy-management/src/interfaces/IPolicyEngine.sol +90 -10
- package/packages/policy-management/src/interfaces/IPolicyProtected.sol +6 -0
- package/packages/policy-management/src/libraries/CertifiedActionLib.sol +47 -0
- package/packages/policy-management/src/policies/AllowPolicy.sol +12 -7
- package/packages/policy-management/src/policies/BypassPolicy.sol +23 -5
- package/packages/policy-management/src/policies/CertifiedActionDONValidatorPolicy.sol +156 -0
- package/packages/policy-management/src/policies/CertifiedActionERC20TransferValidatorPolicy.sol +202 -0
- package/packages/policy-management/src/policies/CertifiedActionValidatorPolicy.sol +365 -0
- package/packages/policy-management/src/policies/IntervalPolicy.sol +64 -48
- package/packages/policy-management/src/policies/MaxPolicy.sol +7 -5
- package/packages/policy-management/src/policies/OnlyAuthorizedSenderPolicy.sol +20 -4
- package/packages/policy-management/src/policies/OnlyOwnerPolicy.sol +4 -2
- package/packages/policy-management/src/policies/PausePolicy.sol +16 -15
- package/packages/policy-management/src/policies/RejectPolicy.sol +23 -5
- package/packages/policy-management/src/policies/RoleBasedAccessControlPolicy.sol +7 -5
- package/packages/policy-management/src/policies/SecureMintPolicy.sol +136 -48
- package/packages/policy-management/src/policies/VolumePolicy.sol +9 -5
- package/packages/policy-management/src/policies/VolumeRatePolicy.sol +11 -7
- package/packages/policy-management/test/PolicyEngine.t.sol +131 -23
- package/packages/policy-management/test/PolicyEngineFactory.t.sol +95 -0
- package/packages/policy-management/test/PolicyFactory.t.sol +1 -1
- package/packages/policy-management/test/{PolicyProtectedToken.t.sol → PolicyProtected.t.sol} +54 -8
- package/packages/policy-management/test/PolicyProtectedUpgradeable.t.sol +126 -0
- package/packages/policy-management/test/extractors/ComplianceTokenForceTransferExtractor.t.sol +1 -1
- package/packages/policy-management/test/extractors/ComplianceTokenFreezeUnfreezeExtractor.t.sol +1 -1
- package/packages/policy-management/test/extractors/ComplianceTokenMintBurnExtractor.t.sol +1 -1
- package/packages/policy-management/test/extractors/ERC20ApproveExtractor.t.sol +1 -1
- package/packages/policy-management/test/extractors/ERC3643ForcedTransferExtractor.t.sol +1 -1
- package/packages/policy-management/test/extractors/ERC3643FreezeUnfreezeExtractor.t.sol +1 -1
- package/packages/policy-management/test/extractors/ERC3643MintBurnExtractor.t.sol +1 -1
- package/packages/policy-management/test/extractors/ERC3643SetAddressFrozenExtractor.t.sol +1 -1
- package/packages/policy-management/test/helpers/BaseCertifiedActionTest.sol +44 -0
- package/packages/policy-management/test/helpers/BaseProxyTest.sol +88 -7
- package/packages/policy-management/test/helpers/CustomMapper.sol +3 -1
- package/packages/policy-management/test/helpers/DummyExtractor.sol +3 -1
- package/packages/policy-management/test/helpers/ExpectedParameterPolicy.sol +3 -1
- package/packages/policy-management/test/helpers/FaultyPolicyEngine.sol +54 -0
- package/packages/policy-management/test/helpers/MockCertifiedActionValidatorPolicyExtension.sol +46 -0
- package/packages/policy-management/test/helpers/MockToken.sol +2 -5
- package/packages/policy-management/test/helpers/MockTokenExtractor.sol +9 -4
- package/packages/policy-management/test/helpers/MockTokenUpgradeable.sol +66 -0
- package/packages/policy-management/test/helpers/PolicyAlwaysAllowed.sol +3 -1
- package/packages/policy-management/test/helpers/PolicyAlwaysContinue.sol +3 -1
- package/packages/policy-management/test/helpers/PolicyAlwaysRejected.sol +10 -1
- package/packages/policy-management/test/helpers/PolicyFailingRun.sol +3 -1
- package/packages/policy-management/test/policies/AllowPolicy.t.sol +39 -23
- package/packages/policy-management/test/policies/BypassPolicy.t.sol +48 -20
- package/packages/policy-management/test/policies/CertifiedActionDONValidatorPolicy.t.sol +172 -0
- package/packages/policy-management/test/policies/CertifiedActionERC20TransferValidatorPolicy.t.sol +217 -0
- package/packages/policy-management/test/policies/CertifiedActionValidatorPolicy.t.sol +1083 -0
- package/packages/policy-management/test/policies/IntervalPolicy.t.sol +105 -55
- package/packages/policy-management/test/policies/MaxPolicy.t.sol +15 -7
- package/packages/policy-management/test/policies/OnlyAuthorizedSenderPolicy.t.sol +91 -16
- package/packages/policy-management/test/policies/OnlyOwnerPolicy.t.sol +11 -7
- package/packages/policy-management/test/policies/PausePolicy.t.sol +46 -16
- package/packages/policy-management/test/policies/RejectPolicy.t.sol +52 -24
- package/packages/policy-management/test/policies/RoleBasedAccessControlPolicy.t.sol +50 -30
- package/packages/policy-management/test/policies/SecureMintPolicy.t.sol +211 -32
- package/packages/policy-management/test/policies/VolumePolicy.t.sol +20 -10
- package/packages/policy-management/test/policies/VolumeRatePolicy.t.sol +24 -18
- package/packages/tokens/erc-20/src/ComplianceTokenERC20.sol +4 -7
- package/packages/tokens/erc-20/src/ComplianceTokenStoreERC20.sol +4 -4
- package/packages/tokens/erc-20/test/ComplianceTokenERC20.t.sol +92 -82
- package/packages/tokens/erc-20/test/helpers/BaseProxyTest.sol +74 -1
- package/packages/tokens/erc-3643/src/ComplianceTokenERC3643.sol +12 -7
- package/packages/tokens/erc-3643/src/ComplianceTokenStoreERC3643.sol +4 -4
- package/packages/tokens/erc-3643/test/ComplianceTokenERC3643.t.sol +108 -119
- package/packages/tokens/erc-3643/test/helpers/BaseProxyTest.sol +74 -1
- package/packages/tokens/erc-3643/test/helpers/ExpectedContextPolicy.sol +3 -1
- package/remappings.txt +1 -0
- package/script/DeployCertifiedActionsComplianceTokenERC3643.s.sol +125 -0
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
3
|
|
|
4
4
|
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
5
|
+
import {Vm} from "forge-std/Vm.sol";
|
|
6
|
+
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
5
7
|
import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
|
|
6
8
|
import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
7
9
|
import {ERC3643MintBurnExtractor} from "@chainlink/policy-management/extractors/ERC3643MintBurnExtractor.sol";
|
|
8
10
|
import {SecureMintPolicy} from "@chainlink/policy-management/policies/SecureMintPolicy.sol";
|
|
9
|
-
import {
|
|
11
|
+
import {MockTokenUpgradeable} from "../helpers/MockTokenUpgradeable.sol";
|
|
10
12
|
import {MockAggregatorV3} from "../helpers/MockAggregatorV3.sol";
|
|
11
13
|
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
12
14
|
|
|
15
|
+
contract TokenWithoutDecimals {
|
|
16
|
+
function totalSupply() external pure returns (uint256) {
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
contract SecureMintPolicyTest is BaseProxyTest {
|
|
22
|
+
uint8 private constant TOKEN_DECIMALS = 18;
|
|
23
|
+
uint8 private constant POR_FEED_DECIMALS = 18;
|
|
14
24
|
PolicyEngine public policyEngine;
|
|
15
25
|
SecureMintPolicy public policy;
|
|
16
26
|
ERC3643MintBurnExtractor public extractor;
|
|
17
|
-
|
|
27
|
+
MockTokenUpgradeable public token;
|
|
18
28
|
MockAggregatorV3 public porFeed;
|
|
19
29
|
address public deployer;
|
|
20
30
|
address public recipient;
|
|
@@ -27,9 +37,9 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
27
37
|
|
|
28
38
|
policyEngine = _deployPolicyEngine(true, deployer);
|
|
29
39
|
|
|
30
|
-
token =
|
|
40
|
+
token = MockTokenUpgradeable(_deployMockToken(address(policyEngine)));
|
|
31
41
|
|
|
32
|
-
porFeed = new MockAggregatorV3(42 ether,
|
|
42
|
+
porFeed = new MockAggregatorV3(42 ether, POR_FEED_DECIMALS);
|
|
33
43
|
|
|
34
44
|
extractor = new ERC3643MintBurnExtractor();
|
|
35
45
|
bytes32[] memory parameterOutputFormat = new bytes32[](1);
|
|
@@ -41,12 +51,20 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
41
51
|
address(policyImpl),
|
|
42
52
|
address(policyEngine),
|
|
43
53
|
deployer,
|
|
44
|
-
abi.encode(
|
|
54
|
+
abi.encode(
|
|
55
|
+
address(porFeed),
|
|
56
|
+
SecureMintPolicy.ReserveMarginConfigs({
|
|
57
|
+
reserveMarginMode: SecureMintPolicy.ReserveMarginMode.None,
|
|
58
|
+
reserveMarginAmount: 0
|
|
59
|
+
}),
|
|
60
|
+
0,
|
|
61
|
+
SecureMintPolicy.TokenMetadata(address(token), TOKEN_DECIMALS)
|
|
62
|
+
)
|
|
45
63
|
)
|
|
46
64
|
);
|
|
47
65
|
|
|
48
|
-
policyEngine.setExtractor(
|
|
49
|
-
policyEngine.addPolicy(address(token),
|
|
66
|
+
policyEngine.setExtractor(MockTokenUpgradeable.mint.selector, address(extractor));
|
|
67
|
+
policyEngine.addPolicy(address(token), MockTokenUpgradeable.mint.selector, address(policy), parameterOutputFormat);
|
|
50
68
|
|
|
51
69
|
vm.warp(1737583804);
|
|
52
70
|
}
|
|
@@ -61,12 +79,22 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
61
79
|
emit SecureMintPolicy.ReserveMarginSet(SecureMintPolicy.ReserveMarginMode.None, 0);
|
|
62
80
|
vm.expectEmit();
|
|
63
81
|
emit SecureMintPolicy.MaxStalenessSecondsSet(600);
|
|
82
|
+
vm.expectEmit();
|
|
83
|
+
emit SecureMintPolicy.TokenMetadataSet(address(token), TOKEN_DECIMALS);
|
|
64
84
|
policy = SecureMintPolicy(
|
|
65
85
|
_deployPolicy(
|
|
66
86
|
address(policyImpl),
|
|
67
87
|
address(policyEngine),
|
|
68
88
|
deployer,
|
|
69
|
-
abi.encode(
|
|
89
|
+
abi.encode(
|
|
90
|
+
address(porFeed),
|
|
91
|
+
SecureMintPolicy.ReserveMarginConfigs({
|
|
92
|
+
reserveMarginMode: SecureMintPolicy.ReserveMarginMode.None,
|
|
93
|
+
reserveMarginAmount: 0
|
|
94
|
+
}),
|
|
95
|
+
600,
|
|
96
|
+
SecureMintPolicy.TokenMetadata(address(token), TOKEN_DECIMALS)
|
|
97
|
+
)
|
|
70
98
|
)
|
|
71
99
|
);
|
|
72
100
|
}
|
|
@@ -100,6 +128,105 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
100
128
|
policy.setReservesFeed(address(porFeed));
|
|
101
129
|
}
|
|
102
130
|
|
|
131
|
+
function test_setTokenDecimals_succeeds() public {
|
|
132
|
+
uint8 newDecimals = 6;
|
|
133
|
+
|
|
134
|
+
vm.startPrank(deployer, deployer);
|
|
135
|
+
|
|
136
|
+
vm.recordLogs();
|
|
137
|
+
policy.setTokenMetadata(address(token), newDecimals);
|
|
138
|
+
Vm.Log[] memory entries = vm.getRecordedLogs();
|
|
139
|
+
assertEq(entries.length, 1, "unexpected log count");
|
|
140
|
+
assertEq(entries[0].topics[0], keccak256("TokenMetadataSet(address,uint8)"));
|
|
141
|
+
(address loggedToken, uint8 loggedDecimals) = abi.decode(entries[0].data, (address, uint8));
|
|
142
|
+
assertEq(loggedToken, address(token));
|
|
143
|
+
assertEq(loggedDecimals, newDecimals);
|
|
144
|
+
|
|
145
|
+
bytes[] memory parameters = new bytes[](1);
|
|
146
|
+
parameters[0] = abi.encode(uint256(42 * (10 ** uint256(newDecimals))));
|
|
147
|
+
IPolicyEngine.PolicyResult result =
|
|
148
|
+
policy.run(deployer, address(token), MockTokenUpgradeable.mint.selector, parameters, bytes(""));
|
|
149
|
+
assertEq(uint256(result), uint256(IPolicyEngine.PolicyResult.Continue));
|
|
150
|
+
|
|
151
|
+
parameters[0] = abi.encode(uint256(42 * (10 ** uint256(newDecimals)) + 1));
|
|
152
|
+
vm.expectRevert(
|
|
153
|
+
abi.encodeWithSelector(IPolicyEngine.PolicyRejected.selector, "mint would exceed available reserves")
|
|
154
|
+
);
|
|
155
|
+
policy.run(deployer, address(token), MockTokenUpgradeable.mint.selector, parameters, bytes(""));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function test_setTokenDecimals_notOwner_reverts() public {
|
|
159
|
+
vm.startPrank(recipient, recipient);
|
|
160
|
+
|
|
161
|
+
vm.expectPartialRevert(OwnableUpgradeable.OwnableUnauthorizedAccount.selector);
|
|
162
|
+
policy.setTokenMetadata(address(token), 6);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function test_setTokenDecimals_tokenWithoutDecimalsInterface_succeeds() public {
|
|
166
|
+
TokenWithoutDecimals tokenWithoutDecimals = new TokenWithoutDecimals();
|
|
167
|
+
|
|
168
|
+
SecureMintPolicy policyImpl = new SecureMintPolicy();
|
|
169
|
+
SecureMintPolicy localPolicy = SecureMintPolicy(
|
|
170
|
+
_deployPolicy(
|
|
171
|
+
address(policyImpl),
|
|
172
|
+
address(policyEngine),
|
|
173
|
+
deployer,
|
|
174
|
+
abi.encode(
|
|
175
|
+
address(porFeed),
|
|
176
|
+
SecureMintPolicy.ReserveMarginMode.None,
|
|
177
|
+
0,
|
|
178
|
+
0,
|
|
179
|
+
SecureMintPolicy.TokenMetadata(address(tokenWithoutDecimals), TOKEN_DECIMALS)
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
vm.startPrank(deployer, deployer);
|
|
185
|
+
|
|
186
|
+
vm.recordLogs();
|
|
187
|
+
localPolicy.setTokenMetadata(address(tokenWithoutDecimals), 6);
|
|
188
|
+
Vm.Log[] memory entries = vm.getRecordedLogs();
|
|
189
|
+
assertEq(entries.length, 1, "unexpected log count");
|
|
190
|
+
assertEq(entries[0].topics[0], keccak256("TokenMetadataSet(address,uint8)"));
|
|
191
|
+
(address loggedToken, uint8 loggedDecimals) = abi.decode(entries[0].data, (address, uint8));
|
|
192
|
+
assertEq(loggedToken, address(tokenWithoutDecimals));
|
|
193
|
+
assertEq(loggedDecimals, 6);
|
|
194
|
+
|
|
195
|
+
vm.stopPrank();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function test_setTokenDecimals_tokenAddressMismatch_reverts() public {
|
|
199
|
+
vm.startPrank(deployer, deployer);
|
|
200
|
+
vm.expectRevert("token address mismatch");
|
|
201
|
+
policy.setTokenMetadata(makeAddr("wrong"), 6);
|
|
202
|
+
vm.stopPrank();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function test_setTokenDecimals_sameAsCurrent_reverts() public {
|
|
206
|
+
vm.startPrank(deployer, deployer);
|
|
207
|
+
vm.expectRevert("decimals same as current");
|
|
208
|
+
policy.setTokenMetadata(address(token), TOKEN_DECIMALS);
|
|
209
|
+
vm.stopPrank();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function test_setTokenDecimals_zeroDecimals_reverts() public {
|
|
213
|
+
vm.startPrank(deployer, deployer);
|
|
214
|
+
vm.expectRevert("decimals must be > 0");
|
|
215
|
+
policy.setTokenMetadata(address(token), 0);
|
|
216
|
+
vm.stopPrank();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function test_setTokenDecimals_tokenMetadataMismatch_reverts() public {
|
|
220
|
+
vm.mockCall(address(token), abi.encodeWithSelector(IERC20Metadata.decimals.selector), abi.encode(uint8(7)));
|
|
221
|
+
|
|
222
|
+
vm.startPrank(deployer, deployer);
|
|
223
|
+
vm.expectRevert("decimals mismatch with token metadata");
|
|
224
|
+
policy.setTokenMetadata(address(token), 6);
|
|
225
|
+
vm.stopPrank();
|
|
226
|
+
|
|
227
|
+
vm.clearMockedCalls();
|
|
228
|
+
}
|
|
229
|
+
|
|
103
230
|
function test_setReserveMargin_succeeds() public {
|
|
104
231
|
vm.startPrank(deployer, deployer);
|
|
105
232
|
|
|
@@ -195,8 +322,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
195
322
|
assertEq(token.balanceOf(recipient), 40 ether);
|
|
196
323
|
|
|
197
324
|
// 40 + 3 > 42, reverts
|
|
198
|
-
|
|
199
|
-
|
|
325
|
+
_expectRejectedRevert(
|
|
326
|
+
address(policy),
|
|
327
|
+
"mint would exceed available reserves",
|
|
328
|
+
MockTokenUpgradeable.mint.selector,
|
|
329
|
+
deployer,
|
|
330
|
+
abi.encode(recipient, 3 ether)
|
|
200
331
|
);
|
|
201
332
|
token.mint(recipient, 3 ether);
|
|
202
333
|
|
|
@@ -227,8 +358,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
227
358
|
policy.setReserveMargin(SecureMintPolicy.ReserveMarginMode.PositivePercentage, 10000); // 100%
|
|
228
359
|
|
|
229
360
|
// 0 + 0.1 > 0, reverts
|
|
230
|
-
|
|
231
|
-
|
|
361
|
+
_expectRejectedRevert(
|
|
362
|
+
address(policy),
|
|
363
|
+
"mint would exceed available reserves",
|
|
364
|
+
MockTokenUpgradeable.mint.selector,
|
|
365
|
+
deployer,
|
|
366
|
+
abi.encode(recipient, 0.1 ether)
|
|
232
367
|
);
|
|
233
368
|
token.mint(recipient, 0.1 ether);
|
|
234
369
|
}
|
|
@@ -244,8 +379,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
244
379
|
assertEq(token.balanceOf(recipient), 30 ether);
|
|
245
380
|
|
|
246
381
|
// 30 + 4 > 33.6, reverts
|
|
247
|
-
|
|
248
|
-
|
|
382
|
+
_expectRejectedRevert(
|
|
383
|
+
address(policy),
|
|
384
|
+
"mint would exceed available reserves",
|
|
385
|
+
MockTokenUpgradeable.mint.selector,
|
|
386
|
+
deployer,
|
|
387
|
+
abi.encode(recipient, 4 ether)
|
|
249
388
|
);
|
|
250
389
|
token.mint(recipient, 4 ether);
|
|
251
390
|
|
|
@@ -254,8 +393,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
254
393
|
assertEq(token.balanceOf(recipient), 33 ether);
|
|
255
394
|
|
|
256
395
|
// 35 + 1 > 33.6, reverts
|
|
257
|
-
|
|
258
|
-
|
|
396
|
+
_expectRejectedRevert(
|
|
397
|
+
address(policy),
|
|
398
|
+
"mint would exceed available reserves",
|
|
399
|
+
MockTokenUpgradeable.mint.selector,
|
|
400
|
+
deployer,
|
|
401
|
+
abi.encode(recipient, 1 ether)
|
|
259
402
|
);
|
|
260
403
|
token.mint(recipient, 1 ether);
|
|
261
404
|
}
|
|
@@ -285,9 +428,13 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
285
428
|
token.mint(recipient, 30 ether);
|
|
286
429
|
assertEq(token.balanceOf(recipient), 30 ether);
|
|
287
430
|
|
|
288
|
-
// 30 +
|
|
289
|
-
|
|
290
|
-
|
|
431
|
+
// 30 + 12 > 40, reverts
|
|
432
|
+
_expectRejectedRevert(
|
|
433
|
+
address(policy),
|
|
434
|
+
"mint would exceed available reserves",
|
|
435
|
+
MockTokenUpgradeable.mint.selector,
|
|
436
|
+
deployer,
|
|
437
|
+
abi.encode(recipient, 12 ether)
|
|
291
438
|
);
|
|
292
439
|
token.mint(recipient, 12 ether);
|
|
293
440
|
|
|
@@ -296,8 +443,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
296
443
|
assertEq(token.balanceOf(recipient), 40 ether);
|
|
297
444
|
|
|
298
445
|
// 40 + 1 > 40, reverts
|
|
299
|
-
|
|
300
|
-
|
|
446
|
+
_expectRejectedRevert(
|
|
447
|
+
address(policy),
|
|
448
|
+
"mint would exceed available reserves",
|
|
449
|
+
MockTokenUpgradeable.mint.selector,
|
|
450
|
+
deployer,
|
|
451
|
+
abi.encode(recipient, 1 ether)
|
|
301
452
|
);
|
|
302
453
|
token.mint(recipient, 1 ether);
|
|
303
454
|
}
|
|
@@ -310,8 +461,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
310
461
|
policy.setReserveMargin(SecureMintPolicy.ReserveMarginMode.PositiveAbsolute, 50 ether);
|
|
311
462
|
|
|
312
463
|
// 0 + 0.1 > 0, reverts (any minting should be blocked)
|
|
313
|
-
|
|
314
|
-
|
|
464
|
+
_expectRejectedRevert(
|
|
465
|
+
address(policy),
|
|
466
|
+
"mint would exceed available reserves",
|
|
467
|
+
MockTokenUpgradeable.mint.selector,
|
|
468
|
+
deployer,
|
|
469
|
+
abi.encode(recipient, 0.1 ether)
|
|
315
470
|
);
|
|
316
471
|
token.mint(recipient, 0.1 ether);
|
|
317
472
|
}
|
|
@@ -357,8 +512,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
357
512
|
assertEq(token.balanceOf(recipient), 50 ether);
|
|
358
513
|
|
|
359
514
|
// 50 + 0.5 <= 50.4, reverts
|
|
360
|
-
|
|
361
|
-
|
|
515
|
+
_expectRejectedRevert(
|
|
516
|
+
address(policy),
|
|
517
|
+
"mint would exceed available reserves",
|
|
518
|
+
MockTokenUpgradeable.mint.selector,
|
|
519
|
+
deployer,
|
|
520
|
+
abi.encode(recipient, 0.5 ether)
|
|
362
521
|
);
|
|
363
522
|
token.mint(recipient, 0.5 ether);
|
|
364
523
|
|
|
@@ -393,8 +552,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
393
552
|
assertEq(token.balanceOf(recipient), 30 ether);
|
|
394
553
|
|
|
395
554
|
// 30 + 14.1 <= 44, reverts
|
|
396
|
-
|
|
397
|
-
|
|
555
|
+
_expectRejectedRevert(
|
|
556
|
+
address(policy),
|
|
557
|
+
"mint would exceed available reserves",
|
|
558
|
+
MockTokenUpgradeable.mint.selector,
|
|
559
|
+
deployer,
|
|
560
|
+
abi.encode(recipient, 14.1 ether)
|
|
398
561
|
);
|
|
399
562
|
token.mint(recipient, 14.1 ether);
|
|
400
563
|
|
|
@@ -403,8 +566,12 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
403
566
|
assertEq(token.balanceOf(recipient), 44 ether);
|
|
404
567
|
|
|
405
568
|
// 44 + 1 > 44, reverts
|
|
406
|
-
|
|
407
|
-
|
|
569
|
+
_expectRejectedRevert(
|
|
570
|
+
address(policy),
|
|
571
|
+
"mint would exceed available reserves",
|
|
572
|
+
MockTokenUpgradeable.mint.selector,
|
|
573
|
+
deployer,
|
|
574
|
+
abi.encode(recipient, 1 ether)
|
|
408
575
|
);
|
|
409
576
|
token.mint(recipient, 1 ether);
|
|
410
577
|
}
|
|
@@ -425,7 +592,13 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
425
592
|
policy.setMaxStalenessSeconds(600);
|
|
426
593
|
|
|
427
594
|
porFeed.setUpdatedAt(block.timestamp - 601);
|
|
428
|
-
|
|
595
|
+
_expectRejectedRevert(
|
|
596
|
+
address(policy),
|
|
597
|
+
"reserve data is stale",
|
|
598
|
+
MockTokenUpgradeable.mint.selector,
|
|
599
|
+
deployer,
|
|
600
|
+
abi.encode(recipient, 1 ether)
|
|
601
|
+
);
|
|
429
602
|
token.mint(recipient, 1 ether);
|
|
430
603
|
}
|
|
431
604
|
|
|
@@ -436,7 +609,13 @@ contract SecureMintPolicyTest is BaseProxyTest {
|
|
|
436
609
|
porFeed.setPrice(-1 ether);
|
|
437
610
|
|
|
438
611
|
// should revert because the reserve is negative
|
|
439
|
-
|
|
612
|
+
_expectRejectedRevert(
|
|
613
|
+
address(policy),
|
|
614
|
+
"reserve value is negative",
|
|
615
|
+
MockTokenUpgradeable.mint.selector,
|
|
616
|
+
deployer,
|
|
617
|
+
abi.encode(recipient, 1 ether)
|
|
618
|
+
);
|
|
440
619
|
token.mint(recipient, 1 ether);
|
|
441
620
|
}
|
|
442
621
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
3
|
|
|
4
4
|
import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
|
|
5
5
|
import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
6
6
|
import {VolumePolicy} from "@chainlink/policy-management/policies/VolumePolicy.sol";
|
|
7
7
|
import {ERC20TransferExtractor} from "@chainlink/policy-management/extractors/ERC20TransferExtractor.sol";
|
|
8
|
-
import {
|
|
8
|
+
import {MockTokenUpgradeable} from "../helpers/MockTokenUpgradeable.sol";
|
|
9
9
|
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
10
10
|
|
|
11
11
|
contract VolumePolicyTest is BaseProxyTest {
|
|
12
12
|
PolicyEngine public policyEngine;
|
|
13
13
|
VolumePolicy public volumePolicy;
|
|
14
14
|
ERC20TransferExtractor public extractor;
|
|
15
|
-
|
|
15
|
+
MockTokenUpgradeable public token;
|
|
16
16
|
address public deployer;
|
|
17
17
|
address public txSender;
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ contract VolumePolicyTest is BaseProxyTest {
|
|
|
24
24
|
|
|
25
25
|
policyEngine = _deployPolicyEngine(true, deployer);
|
|
26
26
|
|
|
27
|
-
token =
|
|
27
|
+
token = MockTokenUpgradeable(_deployMockToken(address(policyEngine)));
|
|
28
28
|
|
|
29
29
|
extractor = new ERC20TransferExtractor();
|
|
30
30
|
bytes32[] memory parameterOutputFormat = new bytes32[](1);
|
|
@@ -34,9 +34,11 @@ contract VolumePolicyTest is BaseProxyTest {
|
|
|
34
34
|
volumePolicy =
|
|
35
35
|
VolumePolicy(_deployPolicy(address(volumePolicyImpl), address(policyEngine), deployer, abi.encode(100, 200)));
|
|
36
36
|
|
|
37
|
-
policyEngine.setExtractor(
|
|
37
|
+
policyEngine.setExtractor(MockTokenUpgradeable.transfer.selector, address(extractor));
|
|
38
38
|
|
|
39
|
-
policyEngine.addPolicy(
|
|
39
|
+
policyEngine.addPolicy(
|
|
40
|
+
address(token), MockTokenUpgradeable.transfer.selector, address(volumePolicy), parameterOutputFormat
|
|
41
|
+
);
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
function test_policy_initMaxBelowMin_fails() public {
|
|
@@ -116,8 +118,12 @@ contract VolumePolicyTest is BaseProxyTest {
|
|
|
116
118
|
|
|
117
119
|
vm.startPrank(txSender);
|
|
118
120
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
_expectRejectedRevert(
|
|
122
|
+
address(volumePolicy),
|
|
123
|
+
"amount outside allowed volume limits",
|
|
124
|
+
MockTokenUpgradeable.transfer.selector,
|
|
125
|
+
txSender,
|
|
126
|
+
abi.encode(recipient, 201)
|
|
121
127
|
);
|
|
122
128
|
|
|
123
129
|
token.transfer(recipient, 201);
|
|
@@ -138,8 +144,12 @@ contract VolumePolicyTest is BaseProxyTest {
|
|
|
138
144
|
|
|
139
145
|
vm.startPrank(txSender);
|
|
140
146
|
|
|
141
|
-
|
|
142
|
-
|
|
147
|
+
_expectRejectedRevert(
|
|
148
|
+
address(volumePolicy),
|
|
149
|
+
"amount outside allowed volume limits",
|
|
150
|
+
MockTokenUpgradeable.transfer.selector,
|
|
151
|
+
txSender,
|
|
152
|
+
abi.encode(recipient, 99)
|
|
143
153
|
);
|
|
144
154
|
|
|
145
155
|
token.transfer(recipient, 99);
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
3
|
|
|
4
4
|
import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
|
|
5
5
|
import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
6
6
|
import {VolumeRatePolicy} from "@chainlink/policy-management/policies/VolumeRatePolicy.sol";
|
|
7
7
|
import {ERC20TransferExtractor} from "@chainlink/policy-management/extractors/ERC20TransferExtractor.sol";
|
|
8
|
-
import {
|
|
8
|
+
import {MockTokenUpgradeable} from "../helpers/MockTokenUpgradeable.sol";
|
|
9
9
|
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
10
10
|
|
|
11
11
|
contract VolumeRatePolicyTest is BaseProxyTest {
|
|
12
12
|
PolicyEngine public policyEngine;
|
|
13
13
|
VolumeRatePolicy public volumeRatePolicy;
|
|
14
14
|
ERC20TransferExtractor public extractor;
|
|
15
|
-
|
|
15
|
+
MockTokenUpgradeable token;
|
|
16
16
|
address public deployer;
|
|
17
17
|
address public txSender;
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ contract VolumeRatePolicyTest is BaseProxyTest {
|
|
|
24
24
|
|
|
25
25
|
policyEngine = _deployPolicyEngine(true, deployer);
|
|
26
26
|
|
|
27
|
-
token =
|
|
27
|
+
token = MockTokenUpgradeable(_deployMockToken(address(policyEngine)));
|
|
28
28
|
|
|
29
29
|
extractor = new ERC20TransferExtractor();
|
|
30
30
|
bytes32[] memory parameterOutputFormat = new bytes32[](2);
|
|
@@ -36,10 +36,10 @@ contract VolumeRatePolicyTest is BaseProxyTest {
|
|
|
36
36
|
_deployPolicy(address(volumeRatePolicyImpl), address(policyEngine), deployer, abi.encode(1 days, 200))
|
|
37
37
|
);
|
|
38
38
|
|
|
39
|
-
policyEngine.setExtractor(
|
|
39
|
+
policyEngine.setExtractor(MockTokenUpgradeable.transfer.selector, address(extractor));
|
|
40
40
|
|
|
41
41
|
policyEngine.addPolicy(
|
|
42
|
-
address(token),
|
|
42
|
+
address(token), MockTokenUpgradeable.transfer.selector, address(volumeRatePolicy), parameterOutputFormat
|
|
43
43
|
);
|
|
44
44
|
vm.warp(1737583804);
|
|
45
45
|
}
|
|
@@ -93,10 +93,12 @@ contract VolumeRatePolicyTest is BaseProxyTest {
|
|
|
93
93
|
|
|
94
94
|
token.transfer(recipient, 100);
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
_expectRejectedRevert(
|
|
97
|
+
address(volumeRatePolicy),
|
|
98
|
+
"volume rate limit exceeded for time period",
|
|
99
|
+
MockTokenUpgradeable.transfer.selector,
|
|
100
|
+
txSender,
|
|
101
|
+
abi.encode(recipient, 101)
|
|
100
102
|
);
|
|
101
103
|
token.transfer(recipient, 101);
|
|
102
104
|
|
|
@@ -126,10 +128,12 @@ contract VolumeRatePolicyTest is BaseProxyTest {
|
|
|
126
128
|
token.transfer(recipient, 200);
|
|
127
129
|
assert(token.balanceOf(recipient) == 300);
|
|
128
130
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
_expectRejectedRevert(
|
|
132
|
+
address(volumeRatePolicy),
|
|
133
|
+
"volume rate limit exceeded for time period",
|
|
134
|
+
MockTokenUpgradeable.transfer.selector,
|
|
135
|
+
txSender,
|
|
136
|
+
abi.encode(recipient, 1)
|
|
133
137
|
);
|
|
134
138
|
token.transfer(recipient, 1);
|
|
135
139
|
}
|
|
@@ -145,10 +149,12 @@ contract VolumeRatePolicyTest is BaseProxyTest {
|
|
|
145
149
|
vm.assertEq(token.balanceOf(recipient), 200);
|
|
146
150
|
|
|
147
151
|
// second transfer at time period 1000 (fails)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
_expectRejectedRevert(
|
|
153
|
+
address(volumeRatePolicy),
|
|
154
|
+
"volume rate limit exceeded for time period",
|
|
155
|
+
MockTokenUpgradeable.transfer.selector,
|
|
156
|
+
txSender,
|
|
157
|
+
abi.encode(recipient, 200)
|
|
152
158
|
);
|
|
153
159
|
token.transfer(recipient, 200);
|
|
154
160
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
3
|
|
|
4
4
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
5
5
|
import {ComplianceTokenStoreERC20} from "./ComplianceTokenStoreERC20.sol";
|
|
6
|
-
import {
|
|
6
|
+
import {PolicyProtectedUpgradeable} from "@chainlink/policy-management/core/PolicyProtectedUpgradeable.sol";
|
|
7
7
|
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -32,7 +32,7 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini
|
|
|
32
32
|
* @dev Note: Alternative implementations may handle frozen tokens differently,
|
|
33
33
|
* such as automatically unfreezing tokens during operations for flexibility.
|
|
34
34
|
*/
|
|
35
|
-
contract ComplianceTokenERC20 is Initializable,
|
|
35
|
+
contract ComplianceTokenERC20 is Initializable, PolicyProtectedUpgradeable, ComplianceTokenStoreERC20, IERC20 {
|
|
36
36
|
/**
|
|
37
37
|
* @notice Emitted when a freeze has been placed on an account.
|
|
38
38
|
* @param account The address of the account whose tokens were frozen.
|
|
@@ -212,6 +212,7 @@ contract ComplianceTokenERC20 is Initializable, PolicyProtected, ComplianceToken
|
|
|
212
212
|
require(from != address(0), "transfer from the zero address");
|
|
213
213
|
require(to != address(0), "transfer to the zero address");
|
|
214
214
|
|
|
215
|
+
_checkFrozenBalance(from, amount);
|
|
215
216
|
_update(from, to, amount);
|
|
216
217
|
emit ForceTransfer(from, to, amount);
|
|
217
218
|
}
|
|
@@ -232,10 +233,6 @@ contract ComplianceTokenERC20 is Initializable, PolicyProtected, ComplianceToken
|
|
|
232
233
|
return owner();
|
|
233
234
|
}
|
|
234
235
|
|
|
235
|
-
function supportsInterface(bytes4 interfaceId) public view virtual override(PolicyProtected) returns (bool) {
|
|
236
|
-
return super.supportsInterface(interfaceId);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
236
|
function _transfer(address from, address to, uint256 amount) internal {
|
|
240
237
|
require(from != address(0), "ERC20: transfer from the zero address");
|
|
241
238
|
require(to != address(0), "ERC20: transfer to the zero address");
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
3
|
|
|
4
4
|
contract ComplianceTokenStoreERC20 {
|
|
5
|
-
/// @custom:storage-location erc7201:
|
|
5
|
+
/// @custom:storage-location erc7201:chainlink.ace.ComplianceTokenStoreERC20
|
|
6
6
|
struct ComplianceTokenStorage {
|
|
7
7
|
string name;
|
|
8
8
|
string symbol;
|
|
@@ -14,11 +14,11 @@ contract ComplianceTokenStoreERC20 {
|
|
|
14
14
|
mapping(bytes32 key => bytes data) data;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
// keccak256(abi.encode(uint256(keccak256("
|
|
17
|
+
// keccak256(abi.encode(uint256(keccak256("chainlink.ace.ComplianceTokenStoreERC20")) - 1)) &
|
|
18
18
|
// ~bytes32(uint256(0xff))
|
|
19
19
|
// solhint-disable-next-line const-name-snakecase
|
|
20
20
|
bytes32 private constant complianceTokenStorageLocation =
|
|
21
|
-
|
|
21
|
+
0xf5303d81c67def4ec0b3a192701545f023de45401e43c238517d86c501b78900;
|
|
22
22
|
|
|
23
23
|
function getComplianceTokenStorage() internal pure returns (ComplianceTokenStorage storage $) {
|
|
24
24
|
// solhint-disable-next-line no-inline-assembly
|