@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.
Files changed (126) hide show
  1. package/.github/workflows/npm-publish.yml +28 -0
  2. package/README.md +9 -1
  3. package/UPGRADE_GUIDE.md +754 -0
  4. package/getting_started/GETTING_STARTED.md +6 -0
  5. package/getting_started/MyVault.sol +2 -2
  6. package/getting_started/advanced/SanctionsPolicy.sol +6 -2
  7. package/package.json +3 -3
  8. package/packages/cross-chain-identity/docs/API_REFERENCE.md +2 -0
  9. package/packages/cross-chain-identity/src/CredentialRegistry.sol +9 -7
  10. package/packages/cross-chain-identity/src/CredentialRegistryFactory.sol +96 -0
  11. package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidator.sol +15 -4
  12. package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidatorPolicy.sol +10 -7
  13. package/packages/cross-chain-identity/src/IdentityRegistry.sol +33 -17
  14. package/packages/cross-chain-identity/src/IdentityRegistryFactory.sol +96 -0
  15. package/packages/cross-chain-identity/src/TrustedIssuerRegistry.sol +8 -6
  16. package/packages/cross-chain-identity/src/TrustedIssuerRegistryFactory.sol +96 -0
  17. package/packages/cross-chain-identity/src/interfaces/ICredentialRegistry.sol +6 -0
  18. package/packages/cross-chain-identity/src/interfaces/ICredentialRequirements.sol +2 -1
  19. package/packages/cross-chain-identity/src/interfaces/IIdentityRegistry.sol +7 -1
  20. package/packages/cross-chain-identity/src/interfaces/ITrustedIssuerRegistry.sol +6 -0
  21. package/packages/cross-chain-identity/test/CredentialRegistry.t.sol +1 -1
  22. package/packages/cross-chain-identity/test/CredentialRegistryFactory.t.sol +105 -0
  23. package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidator.t.sol +16 -1
  24. package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidatorPolicy.t.sol +58 -1
  25. package/packages/cross-chain-identity/test/IdentityRegistry.t.sol +140 -1
  26. package/packages/cross-chain-identity/test/IdentityRegistryFactory.t.sol +103 -0
  27. package/packages/cross-chain-identity/test/IdentityValidator.t.sol +1 -1
  28. package/packages/cross-chain-identity/test/TrustedIssuerRegistry.t.sol +1 -1
  29. package/packages/cross-chain-identity/test/TrustedIssuerRegistryFactory.t.sol +107 -0
  30. package/packages/cross-chain-identity/test/helpers/BaseProxyTest.sol +1 -1
  31. package/packages/cross-chain-identity/test/helpers/MockCredentialDataValidator.sol +1 -1
  32. package/packages/cross-chain-identity/test/helpers/MockCredentialRegistryReverting.sol +3 -1
  33. package/packages/policy-management/README.md +1 -0
  34. package/packages/policy-management/docs/API_GUIDE.md +2 -0
  35. package/packages/policy-management/docs/API_REFERENCE.md +3 -1
  36. package/packages/policy-management/docs/CUSTOM_POLICIES_TUTORIAL.md +10 -4
  37. package/packages/policy-management/src/core/Policy.sol +5 -4
  38. package/packages/policy-management/src/core/PolicyEngine.sol +113 -57
  39. package/packages/policy-management/src/core/PolicyEngineFactory.sol +102 -0
  40. package/packages/policy-management/src/core/PolicyFactory.sol +1 -1
  41. package/packages/policy-management/src/core/PolicyProtected.sol +28 -55
  42. package/packages/policy-management/src/core/PolicyProtectedUpgradeable.sol +134 -0
  43. package/packages/policy-management/src/extractors/ComplianceTokenForceTransferExtractor.sol +4 -1
  44. package/packages/policy-management/src/extractors/ComplianceTokenFreezeUnfreezeExtractor.sol +4 -1
  45. package/packages/policy-management/src/extractors/ComplianceTokenMintBurnExtractor.sol +4 -1
  46. package/packages/policy-management/src/extractors/ERC20ApproveExtractor.sol +4 -1
  47. package/packages/policy-management/src/extractors/ERC20TransferExtractor.sol +4 -1
  48. package/packages/policy-management/src/extractors/ERC3643ForcedTransferExtractor.sol +4 -1
  49. package/packages/policy-management/src/extractors/ERC3643FreezeUnfreezeExtractor.sol +4 -1
  50. package/packages/policy-management/src/extractors/ERC3643MintBurnExtractor.sol +4 -1
  51. package/packages/policy-management/src/extractors/ERC3643SetAddressFrozenExtractor.sol +4 -1
  52. package/packages/policy-management/src/interfaces/ICertifiedActionValidator.sol +110 -0
  53. package/packages/policy-management/src/interfaces/IExtractor.sol +6 -0
  54. package/packages/policy-management/src/interfaces/IMapper.sol +6 -0
  55. package/packages/policy-management/src/interfaces/IPolicy.sol +6 -0
  56. package/packages/policy-management/src/interfaces/IPolicyEngine.sol +90 -10
  57. package/packages/policy-management/src/interfaces/IPolicyProtected.sol +6 -0
  58. package/packages/policy-management/src/libraries/CertifiedActionLib.sol +47 -0
  59. package/packages/policy-management/src/policies/AllowPolicy.sol +12 -7
  60. package/packages/policy-management/src/policies/BypassPolicy.sol +23 -5
  61. package/packages/policy-management/src/policies/CertifiedActionDONValidatorPolicy.sol +156 -0
  62. package/packages/policy-management/src/policies/CertifiedActionERC20TransferValidatorPolicy.sol +202 -0
  63. package/packages/policy-management/src/policies/CertifiedActionValidatorPolicy.sol +365 -0
  64. package/packages/policy-management/src/policies/IntervalPolicy.sol +64 -48
  65. package/packages/policy-management/src/policies/MaxPolicy.sol +7 -5
  66. package/packages/policy-management/src/policies/OnlyAuthorizedSenderPolicy.sol +20 -4
  67. package/packages/policy-management/src/policies/OnlyOwnerPolicy.sol +4 -2
  68. package/packages/policy-management/src/policies/PausePolicy.sol +16 -15
  69. package/packages/policy-management/src/policies/RejectPolicy.sol +23 -5
  70. package/packages/policy-management/src/policies/RoleBasedAccessControlPolicy.sol +7 -5
  71. package/packages/policy-management/src/policies/SecureMintPolicy.sol +136 -48
  72. package/packages/policy-management/src/policies/VolumePolicy.sol +9 -5
  73. package/packages/policy-management/src/policies/VolumeRatePolicy.sol +11 -7
  74. package/packages/policy-management/test/PolicyEngine.t.sol +131 -23
  75. package/packages/policy-management/test/PolicyEngineFactory.t.sol +95 -0
  76. package/packages/policy-management/test/PolicyFactory.t.sol +1 -1
  77. package/packages/policy-management/test/{PolicyProtectedToken.t.sol → PolicyProtected.t.sol} +54 -8
  78. package/packages/policy-management/test/PolicyProtectedUpgradeable.t.sol +126 -0
  79. package/packages/policy-management/test/extractors/ComplianceTokenForceTransferExtractor.t.sol +1 -1
  80. package/packages/policy-management/test/extractors/ComplianceTokenFreezeUnfreezeExtractor.t.sol +1 -1
  81. package/packages/policy-management/test/extractors/ComplianceTokenMintBurnExtractor.t.sol +1 -1
  82. package/packages/policy-management/test/extractors/ERC20ApproveExtractor.t.sol +1 -1
  83. package/packages/policy-management/test/extractors/ERC3643ForcedTransferExtractor.t.sol +1 -1
  84. package/packages/policy-management/test/extractors/ERC3643FreezeUnfreezeExtractor.t.sol +1 -1
  85. package/packages/policy-management/test/extractors/ERC3643MintBurnExtractor.t.sol +1 -1
  86. package/packages/policy-management/test/extractors/ERC3643SetAddressFrozenExtractor.t.sol +1 -1
  87. package/packages/policy-management/test/helpers/BaseCertifiedActionTest.sol +44 -0
  88. package/packages/policy-management/test/helpers/BaseProxyTest.sol +88 -7
  89. package/packages/policy-management/test/helpers/CustomMapper.sol +3 -1
  90. package/packages/policy-management/test/helpers/DummyExtractor.sol +3 -1
  91. package/packages/policy-management/test/helpers/ExpectedParameterPolicy.sol +3 -1
  92. package/packages/policy-management/test/helpers/FaultyPolicyEngine.sol +54 -0
  93. package/packages/policy-management/test/helpers/MockCertifiedActionValidatorPolicyExtension.sol +46 -0
  94. package/packages/policy-management/test/helpers/MockToken.sol +2 -5
  95. package/packages/policy-management/test/helpers/MockTokenExtractor.sol +9 -4
  96. package/packages/policy-management/test/helpers/MockTokenUpgradeable.sol +66 -0
  97. package/packages/policy-management/test/helpers/PolicyAlwaysAllowed.sol +3 -1
  98. package/packages/policy-management/test/helpers/PolicyAlwaysContinue.sol +3 -1
  99. package/packages/policy-management/test/helpers/PolicyAlwaysRejected.sol +10 -1
  100. package/packages/policy-management/test/helpers/PolicyFailingRun.sol +3 -1
  101. package/packages/policy-management/test/policies/AllowPolicy.t.sol +39 -23
  102. package/packages/policy-management/test/policies/BypassPolicy.t.sol +48 -20
  103. package/packages/policy-management/test/policies/CertifiedActionDONValidatorPolicy.t.sol +172 -0
  104. package/packages/policy-management/test/policies/CertifiedActionERC20TransferValidatorPolicy.t.sol +217 -0
  105. package/packages/policy-management/test/policies/CertifiedActionValidatorPolicy.t.sol +1083 -0
  106. package/packages/policy-management/test/policies/IntervalPolicy.t.sol +105 -55
  107. package/packages/policy-management/test/policies/MaxPolicy.t.sol +15 -7
  108. package/packages/policy-management/test/policies/OnlyAuthorizedSenderPolicy.t.sol +91 -16
  109. package/packages/policy-management/test/policies/OnlyOwnerPolicy.t.sol +11 -7
  110. package/packages/policy-management/test/policies/PausePolicy.t.sol +46 -16
  111. package/packages/policy-management/test/policies/RejectPolicy.t.sol +52 -24
  112. package/packages/policy-management/test/policies/RoleBasedAccessControlPolicy.t.sol +50 -30
  113. package/packages/policy-management/test/policies/SecureMintPolicy.t.sol +211 -32
  114. package/packages/policy-management/test/policies/VolumePolicy.t.sol +20 -10
  115. package/packages/policy-management/test/policies/VolumeRatePolicy.t.sol +24 -18
  116. package/packages/tokens/erc-20/src/ComplianceTokenERC20.sol +4 -7
  117. package/packages/tokens/erc-20/src/ComplianceTokenStoreERC20.sol +4 -4
  118. package/packages/tokens/erc-20/test/ComplianceTokenERC20.t.sol +92 -82
  119. package/packages/tokens/erc-20/test/helpers/BaseProxyTest.sol +74 -1
  120. package/packages/tokens/erc-3643/src/ComplianceTokenERC3643.sol +12 -7
  121. package/packages/tokens/erc-3643/src/ComplianceTokenStoreERC3643.sol +4 -4
  122. package/packages/tokens/erc-3643/test/ComplianceTokenERC3643.t.sol +108 -119
  123. package/packages/tokens/erc-3643/test/helpers/BaseProxyTest.sol +74 -1
  124. package/packages/tokens/erc-3643/test/helpers/ExpectedContextPolicy.sol +3 -1
  125. package/remappings.txt +1 -0
  126. package/script/DeployCertifiedActionsComplianceTokenERC3643.s.sol +125 -0
@@ -1,20 +1,30 @@
1
1
  // SPDX-License-Identifier: BUSL-1.1
2
- pragma solidity 0.8.26;
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 {MockToken} from "../helpers/MockToken.sol";
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
- MockToken public token;
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 = MockToken(_deployMockToken(address(policyEngine)));
40
+ token = MockTokenUpgradeable(_deployMockToken(address(policyEngine)));
31
41
 
32
- porFeed = new MockAggregatorV3(42 ether, 18);
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(address(porFeed), SecureMintPolicy.ReserveMarginMode.None, 0, 0)
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(MockToken.mint.selector, address(extractor));
49
- policyEngine.addPolicy(address(token), MockToken.mint.selector, address(policy), parameterOutputFormat);
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(address(porFeed), SecureMintPolicy.ReserveMarginMode.None, 0, 600)
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
- vm.expectRevert(
199
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(
231
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(
248
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(
258
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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 + 15 > 40, reverts
289
- vm.expectRevert(
290
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(
300
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(
314
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(
361
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(
397
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(
407
- _encodeRejectedRevert(MockToken.mint.selector, address(policy), "mint would exceed available reserves")
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
- vm.expectRevert(_encodeRejectedRevert(MockToken.mint.selector, address(policy), "reserve data is stale"));
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
- vm.expectRevert(_encodeRejectedRevert(MockToken.mint.selector, address(policy), "reserve value is negative"));
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.26;
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 {MockToken} from "../helpers/MockToken.sol";
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
- MockToken public token;
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 = MockToken(_deployMockToken(address(policyEngine)));
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(MockToken.transfer.selector, address(extractor));
37
+ policyEngine.setExtractor(MockTokenUpgradeable.transfer.selector, address(extractor));
38
38
 
39
- policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(volumePolicy), parameterOutputFormat);
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
- vm.expectRevert(
120
- _encodeRejectedRevert(MockToken.transfer.selector, address(volumePolicy), "amount outside allowed volume limits")
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
- vm.expectRevert(
142
- _encodeRejectedRevert(MockToken.transfer.selector, address(volumePolicy), "amount outside allowed volume limits")
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.26;
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 {MockToken} from "../helpers/MockToken.sol";
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
- MockToken token;
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 = MockToken(_deployMockToken(address(policyEngine)));
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(MockToken.transfer.selector, address(extractor));
39
+ policyEngine.setExtractor(MockTokenUpgradeable.transfer.selector, address(extractor));
40
40
 
41
41
  policyEngine.addPolicy(
42
- address(token), MockToken.transfer.selector, address(volumeRatePolicy), parameterOutputFormat
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
- vm.expectRevert(
97
- _encodeRejectedRevert(
98
- MockToken.transfer.selector, address(volumeRatePolicy), "volume rate limit exceeded for time period"
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
- vm.expectRevert(
130
- _encodeRejectedRevert(
131
- MockToken.transfer.selector, address(volumeRatePolicy), "volume rate limit exceeded for time period"
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
- vm.expectRevert(
149
- _encodeRejectedRevert(
150
- MockToken.transfer.selector, address(volumeRatePolicy), "volume rate limit exceeded for time period"
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.26;
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 {PolicyProtected} from "@chainlink/policy-management/core/PolicyProtected.sol";
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, PolicyProtected, ComplianceTokenStoreERC20, IERC20 {
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.26;
2
+ pragma solidity ^0.8.20;
3
3
 
4
4
  contract ComplianceTokenStoreERC20 {
5
- /// @custom:storage-location erc7201:compliance-token-erc20.ComplianceTokenStoreERC20
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("compliance-token-erc20.ComplianceTokenStoreERC20")) - 1)) &
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
- 0xeb7f727e418fdce2e00aa1f4b00053561f65d67239278319bdbcc2711bc43500;
21
+ 0xf5303d81c67def4ec0b3a192701545f023de45401e43c238517d86c501b78900;
22
22
 
23
23
  function getComplianceTokenStorage() internal pure returns (ComplianceTokenStorage storage $) {
24
24
  // solhint-disable-next-line no-inline-assembly