@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.
Files changed (150) hide show
  1. package/.foundry-version +1 -0
  2. package/.github/CODEOWNERS +1 -0
  3. package/.github/workflows/auto-release-version.yml +107 -0
  4. package/.github/workflows/create-version-pr.yml +95 -0
  5. package/.github/workflows/forge-docs.yml +90 -0
  6. package/.github/workflows/forge-test.yml +59 -0
  7. package/.solhint-test.json +18 -0
  8. package/.solhint.json +16 -0
  9. package/.solhintignore +3 -0
  10. package/.solhintignore-test +2 -0
  11. package/Glossary.md +141 -0
  12. package/LICENSE +59 -0
  13. package/README.md +218 -0
  14. package/assets/chainlink-logo.svg +21 -0
  15. package/chainlink-ace-License-grants +2 -0
  16. package/foundry.toml +33 -0
  17. package/getting_started/GETTING_STARTED.md +477 -0
  18. package/getting_started/MyVault.sol +48 -0
  19. package/getting_started/advanced/.env.example +36 -0
  20. package/getting_started/advanced/GETTING_STARTED_ADVANCED.md +431 -0
  21. package/getting_started/advanced/SanctionsList.sol +25 -0
  22. package/getting_started/advanced/SanctionsPolicy.sol +58 -0
  23. package/package.json +41 -0
  24. package/packages/cross-chain-identity/README.md +148 -0
  25. package/packages/cross-chain-identity/docs/API_GUIDE.md +120 -0
  26. package/packages/cross-chain-identity/docs/API_REFERENCE.md +271 -0
  27. package/packages/cross-chain-identity/docs/CONCEPTS.md +253 -0
  28. package/packages/cross-chain-identity/docs/CREDENTIAL_FLOW.md +195 -0
  29. package/packages/cross-chain-identity/docs/SECURITY.md +70 -0
  30. package/packages/cross-chain-identity/src/CredentialRegistry.sol +245 -0
  31. package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidator.sol +339 -0
  32. package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidatorPolicy.sol +71 -0
  33. package/packages/cross-chain-identity/src/IdentityRegistry.sol +123 -0
  34. package/packages/cross-chain-identity/src/TrustedIssuerRegistry.sol +140 -0
  35. package/packages/cross-chain-identity/src/interfaces/ICredentialDataValidator.sol +30 -0
  36. package/packages/cross-chain-identity/src/interfaces/ICredentialRegistry.sol +170 -0
  37. package/packages/cross-chain-identity/src/interfaces/ICredentialRequirements.sol +192 -0
  38. package/packages/cross-chain-identity/src/interfaces/ICredentialValidator.sol +37 -0
  39. package/packages/cross-chain-identity/src/interfaces/IIdentityRegistry.sol +85 -0
  40. package/packages/cross-chain-identity/src/interfaces/IIdentityValidator.sol +18 -0
  41. package/packages/cross-chain-identity/src/interfaces/ITrustedIssuerRegistry.sol +61 -0
  42. package/packages/cross-chain-identity/test/CredentialRegistry.t.sol +220 -0
  43. package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidator.t.sol +554 -0
  44. package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidatorPolicy.t.sol +114 -0
  45. package/packages/cross-chain-identity/test/IdentityRegistry.t.sol +106 -0
  46. package/packages/cross-chain-identity/test/IdentityValidator.t.sol +969 -0
  47. package/packages/cross-chain-identity/test/TrustedIssuerRegistry.t.sol +123 -0
  48. package/packages/cross-chain-identity/test/helpers/BaseProxyTest.sol +112 -0
  49. package/packages/cross-chain-identity/test/helpers/MockCredentialDataValidator.sol +26 -0
  50. package/packages/cross-chain-identity/test/helpers/MockCredentialRegistryReverting.sol +131 -0
  51. package/packages/policy-management/README.md +197 -0
  52. package/packages/policy-management/docs/API_GUIDE.md +290 -0
  53. package/packages/policy-management/docs/API_REFERENCE.md +173 -0
  54. package/packages/policy-management/docs/CONCEPTS.md +156 -0
  55. package/packages/policy-management/docs/CUSTOM_POLICIES_TUTORIAL.md +195 -0
  56. package/packages/policy-management/docs/POLICY_ORDERING_GUIDE.md +91 -0
  57. package/packages/policy-management/docs/SECURITY.md +57 -0
  58. package/packages/policy-management/src/core/Policy.sol +124 -0
  59. package/packages/policy-management/src/core/PolicyEngine.sol +382 -0
  60. package/packages/policy-management/src/core/PolicyFactory.sol +92 -0
  61. package/packages/policy-management/src/core/PolicyProtected.sol +126 -0
  62. package/packages/policy-management/src/extractors/ComplianceTokenForceTransferExtractor.sol +57 -0
  63. package/packages/policy-management/src/extractors/ComplianceTokenFreezeUnfreezeExtractor.sol +54 -0
  64. package/packages/policy-management/src/extractors/ComplianceTokenMintBurnExtractor.sol +61 -0
  65. package/packages/policy-management/src/extractors/ERC20ApproveExtractor.sol +57 -0
  66. package/packages/policy-management/src/extractors/ERC20TransferExtractor.sol +62 -0
  67. package/packages/policy-management/src/extractors/ERC3643ForcedTransferExtractor.sol +56 -0
  68. package/packages/policy-management/src/extractors/ERC3643FreezeUnfreezeExtractor.sol +55 -0
  69. package/packages/policy-management/src/extractors/ERC3643MintBurnExtractor.sol +51 -0
  70. package/packages/policy-management/src/extractors/ERC3643SetAddressFrozenExtractor.sol +51 -0
  71. package/packages/policy-management/src/interfaces/IExtractor.sol +17 -0
  72. package/packages/policy-management/src/interfaces/IMapper.sol +17 -0
  73. package/packages/policy-management/src/interfaces/IPolicy.sol +61 -0
  74. package/packages/policy-management/src/interfaces/IPolicyEngine.sol +264 -0
  75. package/packages/policy-management/src/interfaces/IPolicyProtected.sol +48 -0
  76. package/packages/policy-management/src/policies/AllowPolicy.sol +104 -0
  77. package/packages/policy-management/src/policies/BypassPolicy.sol +90 -0
  78. package/packages/policy-management/src/policies/IntervalPolicy.sol +223 -0
  79. package/packages/policy-management/src/policies/MaxPolicy.sol +73 -0
  80. package/packages/policy-management/src/policies/OnlyAuthorizedSenderPolicy.sol +84 -0
  81. package/packages/policy-management/src/policies/OnlyOwnerPolicy.sol +35 -0
  82. package/packages/policy-management/src/policies/PausePolicy.sol +82 -0
  83. package/packages/policy-management/src/policies/README.md +632 -0
  84. package/packages/policy-management/src/policies/RejectPolicy.sol +89 -0
  85. package/packages/policy-management/src/policies/RoleBasedAccessControlPolicy.sol +162 -0
  86. package/packages/policy-management/src/policies/SecureMintPolicy.sol +271 -0
  87. package/packages/policy-management/src/policies/VolumePolicy.sol +133 -0
  88. package/packages/policy-management/src/policies/VolumeRatePolicy.sol +192 -0
  89. package/packages/policy-management/test/PolicyEngine.t.sol +368 -0
  90. package/packages/policy-management/test/PolicyFactory.t.sol +114 -0
  91. package/packages/policy-management/test/PolicyProtectedToken.t.sol +75 -0
  92. package/packages/policy-management/test/extractors/ComplianceTokenForceTransferExtractor.t.sol +59 -0
  93. package/packages/policy-management/test/extractors/ComplianceTokenFreezeUnfreezeExtractor.t.sol +74 -0
  94. package/packages/policy-management/test/extractors/ComplianceTokenMintBurnExtractor.t.sol +92 -0
  95. package/packages/policy-management/test/extractors/ERC20ApproveExtractor.t.sol +58 -0
  96. package/packages/policy-management/test/extractors/ERC3643ForcedTransferExtractor.t.sol +59 -0
  97. package/packages/policy-management/test/extractors/ERC3643FreezeUnfreezeExtractor.t.sol +74 -0
  98. package/packages/policy-management/test/extractors/ERC3643MintBurnExtractor.t.sol +73 -0
  99. package/packages/policy-management/test/extractors/ERC3643SetAddressFrozenExtractor.t.sol +56 -0
  100. package/packages/policy-management/test/helpers/BaseProxyTest.sol +75 -0
  101. package/packages/policy-management/test/helpers/CustomMapper.sol +26 -0
  102. package/packages/policy-management/test/helpers/DummyExtractor.sol +11 -0
  103. package/packages/policy-management/test/helpers/ExpectedParameterPolicy.sol +39 -0
  104. package/packages/policy-management/test/helpers/MockAggregatorV3.sol +51 -0
  105. package/packages/policy-management/test/helpers/MockToken.sol +66 -0
  106. package/packages/policy-management/test/helpers/MockTokenExtractor.sol +34 -0
  107. package/packages/policy-management/test/helpers/PolicyAlwaysAllowed.sol +45 -0
  108. package/packages/policy-management/test/helpers/PolicyAlwaysContinue.sol +23 -0
  109. package/packages/policy-management/test/helpers/PolicyAlwaysRejected.sol +23 -0
  110. package/packages/policy-management/test/helpers/PolicyFailingRun.sol +22 -0
  111. package/packages/policy-management/test/policies/AllowPolicy.t.sol +174 -0
  112. package/packages/policy-management/test/policies/BypassPolicy.t.sol +159 -0
  113. package/packages/policy-management/test/policies/IntervalPolicy.t.sol +307 -0
  114. package/packages/policy-management/test/policies/MaxPolicy.t.sol +54 -0
  115. package/packages/policy-management/test/policies/OnlyAuthorizedSenderPolicy.t.sol +95 -0
  116. package/packages/policy-management/test/policies/OnlyOwnerPolicy.t.sol +47 -0
  117. package/packages/policy-management/test/policies/PausePolicy.t.sol +75 -0
  118. package/packages/policy-management/test/policies/RejectPolicy.t.sol +182 -0
  119. package/packages/policy-management/test/policies/RoleBasedAccessControlPolicy.t.sol +223 -0
  120. package/packages/policy-management/test/policies/SecureMintPolicy.t.sol +442 -0
  121. package/packages/policy-management/test/policies/VolumePolicy.t.sol +158 -0
  122. package/packages/policy-management/test/policies/VolumeRatePolicy.t.sol +165 -0
  123. package/packages/tokens/erc-20/src/ComplianceTokenERC20.sol +345 -0
  124. package/packages/tokens/erc-20/src/ComplianceTokenStoreERC20.sol +29 -0
  125. package/packages/tokens/erc-20/test/ComplianceTokenERC20.t.sol +556 -0
  126. package/packages/tokens/erc-20/test/helpers/BaseProxyTest.sol +75 -0
  127. package/packages/tokens/erc-3643/README.md +24 -0
  128. package/packages/tokens/erc-3643/src/ComplianceTokenERC3643.sol +564 -0
  129. package/packages/tokens/erc-3643/src/ComplianceTokenStoreERC3643.sol +30 -0
  130. package/packages/tokens/erc-3643/test/ComplianceTokenERC3643.t.sol +815 -0
  131. package/packages/tokens/erc-3643/test/helpers/BaseProxyTest.sol +76 -0
  132. package/packages/tokens/erc-3643/test/helpers/ExpectedContextPolicy.sol +32 -0
  133. package/packages/vendor/erc-3643/compliance/modular/IModularCompliance.sol +220 -0
  134. package/packages/vendor/erc-3643/registry/interface/IClaimTopicsRegistry.sol +101 -0
  135. package/packages/vendor/erc-3643/registry/interface/IIdentityRegistry.sol +251 -0
  136. package/packages/vendor/erc-3643/registry/interface/IIdentityRegistryStorage.sol +191 -0
  137. package/packages/vendor/erc-3643/registry/interface/ITrustedIssuersRegistry.sol +161 -0
  138. package/packages/vendor/erc-3643/token/IToken.sol +457 -0
  139. package/packages/vendor/onchain-id/interface/IClaimIssuer.sol +53 -0
  140. package/packages/vendor/onchain-id/interface/IERC734.sol +110 -0
  141. package/packages/vendor/onchain-id/interface/IERC735.sol +105 -0
  142. package/packages/vendor/onchain-id/interface/IIdentity.sol +26 -0
  143. package/packages/vendor/onchain-id/interface/IImplementationAuthority.sol +21 -0
  144. package/remappings.txt +6 -0
  145. package/script/DeployComplianceTokenERC20.s.sol +191 -0
  146. package/script/DeployComplianceTokenERC3643.s.sol +208 -0
  147. package/script/DeploySimpleComplianceToken.s.sol +38 -0
  148. package/script/getting_started/DeployGettingStarted.s.sol +74 -0
  149. package/script/getting_started/advanced/DeployAdvancedGettingStarted.s.sol +332 -0
  150. package/script/getting_started/advanced/DeploySanctionsList.s.sol +26 -0
@@ -0,0 +1,815 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ pragma solidity 0.8.26;
3
+
4
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5
+ import {IToken} from "../../../vendor/erc-3643/token/IToken.sol";
6
+ import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
7
+ import {ComplianceTokenERC3643} from "../src/ComplianceTokenERC3643.sol";
8
+ import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
9
+ import {IPolicy} from "@chainlink/policy-management/interfaces/IPolicy.sol";
10
+ import {OnlyOwnerPolicy} from "@chainlink/policy-management/policies/OnlyOwnerPolicy.sol";
11
+ import {ExpectedContextPolicy} from "./helpers/ExpectedContextPolicy.sol";
12
+ import {BaseProxyTest} from "./helpers/BaseProxyTest.sol";
13
+ import {OnlyAuthorizedSenderPolicy} from "@chainlink/policy-management/policies/OnlyAuthorizedSenderPolicy.sol";
14
+ import {VolumePolicy} from "@chainlink/policy-management/policies/VolumePolicy.sol";
15
+ import {ERC3643MintBurnExtractor} from "@chainlink/policy-management/extractors/ERC3643MintBurnExtractor.sol";
16
+ import {ERC3643FreezeUnfreezeExtractor} from
17
+ "@chainlink/policy-management/extractors/ERC3643FreezeUnfreezeExtractor.sol";
18
+ import {ERC3643ForcedTransferExtractor} from
19
+ "@chainlink/policy-management/extractors/ERC3643ForcedTransferExtractor.sol";
20
+ import {ERC20TransferExtractor} from "@chainlink/policy-management/extractors/ERC20TransferExtractor.sol";
21
+ import {ERC3643SetAddressFrozenExtractor} from
22
+ "@chainlink/policy-management/extractors/ERC3643SetAddressFrozenExtractor.sol";
23
+
24
+ contract ComplianceTokenERC3643Test is BaseProxyTest {
25
+ PolicyEngine internal s_policyEngine;
26
+ ComplianceTokenERC3643 internal s_token;
27
+ address internal s_owner;
28
+ address internal s_bridge;
29
+ address internal s_enforcer;
30
+ OnlyOwnerPolicy internal onlyOwnerPolicy;
31
+ OnlyAuthorizedSenderPolicy internal minterBurnerList;
32
+ OnlyAuthorizedSenderPolicy internal freezingList;
33
+ VolumePolicy internal volumePolicy;
34
+
35
+ function setUp() public {
36
+ s_owner = makeAddr("owner");
37
+ s_bridge = makeAddr("bridge");
38
+ s_enforcer = makeAddr("enforcer");
39
+
40
+ vm.startPrank(s_owner);
41
+
42
+ s_policyEngine = _deployPolicyEngine(true, s_owner);
43
+
44
+ ERC20TransferExtractor transferExtractor = new ERC20TransferExtractor();
45
+ s_policyEngine.setExtractor(IERC20.transfer.selector, address(transferExtractor));
46
+ s_policyEngine.setExtractor(IERC20.transferFrom.selector, address(transferExtractor));
47
+ ERC3643MintBurnExtractor mintBurnExtractor = new ERC3643MintBurnExtractor();
48
+ s_policyEngine.setExtractor(IToken.mint.selector, address(mintBurnExtractor));
49
+ s_policyEngine.setExtractor(IToken.burn.selector, address(mintBurnExtractor));
50
+ ERC3643FreezeUnfreezeExtractor freezeUnfreezeExtractor = new ERC3643FreezeUnfreezeExtractor();
51
+ s_policyEngine.setExtractor(IToken.freezePartialTokens.selector, address(freezeUnfreezeExtractor));
52
+ s_policyEngine.setExtractor(IToken.unfreezePartialTokens.selector, address(freezeUnfreezeExtractor));
53
+ s_policyEngine.setExtractor(IToken.forcedTransfer.selector, address(new ERC3643ForcedTransferExtractor()));
54
+ s_policyEngine.setExtractor(IToken.setAddressFrozen.selector, address(new ERC3643SetAddressFrozenExtractor()));
55
+
56
+ // to protect admin methods
57
+ OnlyOwnerPolicy onlyOwnerPolicyImpl = new OnlyOwnerPolicy();
58
+ onlyOwnerPolicy =
59
+ OnlyOwnerPolicy(_deployPolicy(address(onlyOwnerPolicyImpl), address(s_policyEngine), s_owner, new bytes(0)));
60
+ // to protect mint/burn with admin list
61
+ OnlyAuthorizedSenderPolicy minterBurnerListImpl = new OnlyAuthorizedSenderPolicy();
62
+ minterBurnerList = OnlyAuthorizedSenderPolicy(
63
+ _deployPolicy(address(minterBurnerListImpl), address(s_policyEngine), s_owner, new bytes(0))
64
+ );
65
+ minterBurnerList.authorizeSender(s_owner);
66
+ minterBurnerList.authorizeSender(s_bridge);
67
+ // to protect freezing features with admin list
68
+ OnlyAuthorizedSenderPolicy freezingListImpl = new OnlyAuthorizedSenderPolicy();
69
+ freezingList = OnlyAuthorizedSenderPolicy(
70
+ _deployPolicy(address(freezingListImpl), address(s_policyEngine), s_owner, new bytes(0))
71
+ );
72
+ freezingList.authorizeSender(s_owner);
73
+ freezingList.authorizeSender(s_enforcer);
74
+ // to enforce transaction limits
75
+ VolumePolicy volumePolicyImpl = new VolumePolicy();
76
+ volumePolicy =
77
+ VolumePolicy(_deployPolicy(address(volumePolicyImpl), address(s_policyEngine), s_owner, abi.encode(100, 200)));
78
+
79
+ s_token = _deployComplianceTokenERC3643("Test Token", "TST", 18, address(s_policyEngine));
80
+
81
+ bytes32[] memory volumeParams = new bytes32[](1);
82
+ volumeParams[0] = mintBurnExtractor.PARAM_AMOUNT();
83
+
84
+ // admin methods - onlyOwner
85
+ s_policyEngine.addPolicy(address(s_token), IToken.setName.selector, address(onlyOwnerPolicy), new bytes32[](0));
86
+ s_policyEngine.addPolicy(address(s_token), IToken.setSymbol.selector, address(onlyOwnerPolicy), new bytes32[](0));
87
+ s_policyEngine.addPolicy(address(s_token), IToken.pause.selector, address(onlyOwnerPolicy), new bytes32[](0));
88
+ s_policyEngine.addPolicy(address(s_token), IToken.unpause.selector, address(onlyOwnerPolicy), new bytes32[](0));
89
+ s_policyEngine.addPolicy(
90
+ address(s_token), IToken.forcedTransfer.selector, address(onlyOwnerPolicy), new bytes32[](0)
91
+ );
92
+ // mint - onlyAuthorized - volume
93
+ s_policyEngine.addPolicy(address(s_token), IToken.mint.selector, address(minterBurnerList), new bytes32[](0));
94
+ s_policyEngine.addPolicy(address(s_token), IToken.mint.selector, address(volumePolicy), volumeParams);
95
+ // burn - onlyAuthorized
96
+ s_policyEngine.addPolicy(address(s_token), IToken.burn.selector, address(minterBurnerList), new bytes32[](0));
97
+ // freezing methods - onlyAuthorized
98
+ s_policyEngine.addPolicy(
99
+ address(s_token), IToken.freezePartialTokens.selector, address(freezingList), new bytes32[](0)
100
+ );
101
+ s_policyEngine.addPolicy(
102
+ address(s_token), IToken.unfreezePartialTokens.selector, address(freezingList), new bytes32[](0)
103
+ );
104
+ s_policyEngine.addPolicy(
105
+ address(s_token), IToken.setAddressFrozen.selector, address(freezingList), new bytes32[](0)
106
+ );
107
+ // transfer methods - volume
108
+ s_policyEngine.addPolicy(address(s_token), IERC20.transfer.selector, address(volumePolicy), volumeParams);
109
+ s_policyEngine.addPolicy(address(s_token), IERC20.transferFrom.selector, address(volumePolicy), volumeParams);
110
+ }
111
+
112
+ function test_token_metadata_success() public {
113
+ assertEq(s_token.name(), "Test Token");
114
+ assertEq(s_token.symbol(), "TST");
115
+ assertEq(s_token.decimals(), 18);
116
+ assertEq(s_token.onchainID(), address(0));
117
+ assertEq(s_token.version(), "1.0.0");
118
+
119
+ s_token.setName("New Name");
120
+ s_token.setSymbol("NME");
121
+
122
+ assertEq(s_token.name(), "New Name");
123
+ assertEq(s_token.symbol(), "NME");
124
+ }
125
+
126
+ function test_token_name_notOwner_failure() public {
127
+ vm.startPrank(s_bridge);
128
+
129
+ vm.expectRevert(
130
+ abi.encodeWithSelector(
131
+ IPolicyEngine.PolicyRunRejected.selector,
132
+ IToken.setName.selector,
133
+ address(onlyOwnerPolicy),
134
+ "caller is not the policy owner"
135
+ )
136
+ );
137
+ s_token.setName("New Name");
138
+ }
139
+
140
+ function test_token_symbol_notOwner_failure() public {
141
+ vm.startPrank(s_bridge);
142
+
143
+ vm.expectRevert(
144
+ abi.encodeWithSelector(
145
+ IPolicyEngine.PolicyRunRejected.selector,
146
+ IToken.setSymbol.selector,
147
+ address(onlyOwnerPolicy),
148
+ "caller is not the policy owner"
149
+ )
150
+ );
151
+ s_token.setSymbol("NME");
152
+ }
153
+
154
+ function test_mint_success() public {
155
+ address alice = makeAddr("alice");
156
+
157
+ s_token.mint(alice, 120);
158
+
159
+ assertEq(s_token.balanceOf(alice), 120);
160
+ assertEq(s_token.totalSupply(), 120);
161
+ }
162
+
163
+ function test_mint_WithContext_success() public {
164
+ address alice = makeAddr("alice");
165
+
166
+ ExpectedContextPolicy expectedContextPolicyImpl = new ExpectedContextPolicy();
167
+ ExpectedContextPolicy expectedContextPolicy = ExpectedContextPolicy(
168
+ _deployPolicy(
169
+ address(expectedContextPolicyImpl), address(s_policyEngine), address(this), abi.encode("mint context")
170
+ )
171
+ );
172
+
173
+ s_policyEngine.addPolicy(address(s_token), IToken.mint.selector, address(expectedContextPolicy), new bytes32[](0));
174
+
175
+ s_token.setContext("mint context");
176
+ s_token.mint(alice, 110);
177
+
178
+ assertEq(s_token.balanceOf(alice), 110);
179
+ assertEq(s_token.totalSupply(), 110);
180
+
181
+ // second mint fails because context was cleared after the last mint
182
+ vm.expectRevert(
183
+ abi.encodeWithSelector(
184
+ IPolicyEngine.PolicyRunRejected.selector,
185
+ IToken.mint.selector,
186
+ address(expectedContextPolicy),
187
+ "context does not match expected value"
188
+ )
189
+ );
190
+ s_token.mint(alice, 110);
191
+ }
192
+
193
+ function test_mint_bridge_success() public {
194
+ address alice = makeAddr("alice");
195
+
196
+ vm.stopPrank();
197
+ vm.startPrank(s_bridge);
198
+ s_token.mint(alice, 120);
199
+
200
+ assertEq(s_token.balanceOf(alice), 120);
201
+ assertEq(s_token.totalSupply(), 120);
202
+ }
203
+
204
+ function test_mint_over_failure() public {
205
+ address alice = makeAddr("alice");
206
+
207
+ vm.expectRevert(
208
+ abi.encodeWithSelector(
209
+ IPolicyEngine.PolicyRunRejected.selector,
210
+ IToken.mint.selector,
211
+ address(volumePolicy),
212
+ "amount outside allowed volume limits"
213
+ )
214
+ );
215
+ s_token.mint(alice, 220);
216
+ }
217
+
218
+ function test_mint_under_failure() public {
219
+ address alice = makeAddr("alice");
220
+
221
+ vm.expectRevert(
222
+ abi.encodeWithSelector(
223
+ IPolicyEngine.PolicyRunRejected.selector,
224
+ IToken.mint.selector,
225
+ address(volumePolicy),
226
+ "amount outside allowed volume limits"
227
+ )
228
+ );
229
+ s_token.mint(alice, 50);
230
+ }
231
+
232
+ function test_mint_notAuthorized_revert() public {
233
+ address alice = makeAddr("alice");
234
+
235
+ vm.stopPrank();
236
+ vm.startPrank(alice);
237
+
238
+ vm.expectRevert(
239
+ abi.encodeWithSelector(
240
+ IPolicyEngine.PolicyRunRejected.selector,
241
+ IToken.mint.selector,
242
+ address(minterBurnerList),
243
+ "sender is not authorized"
244
+ )
245
+ );
246
+ s_token.mint(alice, 10);
247
+ }
248
+
249
+ function test_burn_success() public {
250
+ address alice = makeAddr("alice");
251
+
252
+ s_token.mint(alice, 120);
253
+ assertEq(s_token.balanceOf(alice), 120);
254
+
255
+ s_token.burn(alice, 70);
256
+
257
+ assertEq(s_token.balanceOf(alice), 50);
258
+ assertEq(s_token.totalSupply(), 50);
259
+ }
260
+
261
+ function test_burn_bridge_success() public {
262
+ address alice = makeAddr("alice");
263
+ s_token.mint(alice, 120);
264
+ assertEq(s_token.balanceOf(alice), 120);
265
+
266
+ vm.stopPrank();
267
+ vm.startPrank(s_bridge);
268
+
269
+ s_token.burn(alice, 70);
270
+
271
+ assertEq(s_token.balanceOf(alice), 50);
272
+ assertEq(s_token.totalSupply(), 50);
273
+ }
274
+
275
+ function test_burn_notAuthorized_failure() public {
276
+ address alice = makeAddr("alice");
277
+ s_token.mint(alice, 120);
278
+ assertEq(s_token.balanceOf(alice), 120);
279
+
280
+ vm.stopPrank();
281
+ vm.startPrank(alice);
282
+
283
+ vm.expectRevert(
284
+ abi.encodeWithSelector(
285
+ IPolicyEngine.PolicyRunRejected.selector,
286
+ IToken.burn.selector,
287
+ address(minterBurnerList),
288
+ "sender is not authorized"
289
+ )
290
+ );
291
+ s_token.burn(alice, 70);
292
+ }
293
+
294
+ function test_transfer_success() public {
295
+ address alice = makeAddr("alice");
296
+ address bob = makeAddr("bob");
297
+
298
+ s_token.mint(alice, 120);
299
+
300
+ vm.stopPrank();
301
+ vm.startPrank(alice);
302
+
303
+ s_token.transfer(bob, 110);
304
+
305
+ assertEq(s_token.balanceOf(alice), 10);
306
+ assertEq(s_token.balanceOf(bob), 110);
307
+ }
308
+
309
+ function test_transfer_over_failure() public {
310
+ address alice = makeAddr("alice");
311
+ address bob = makeAddr("bob");
312
+
313
+ s_token.mint(alice, 120);
314
+ s_token.mint(alice, 120);
315
+ assertEq(s_token.balanceOf(alice), 240);
316
+
317
+ vm.stopPrank();
318
+ vm.startPrank(alice);
319
+
320
+ vm.expectRevert(
321
+ abi.encodeWithSelector(
322
+ IPolicyEngine.PolicyRunRejected.selector,
323
+ IERC20.transfer.selector,
324
+ address(volumePolicy),
325
+ "amount outside allowed volume limits"
326
+ )
327
+ );
328
+ s_token.transfer(bob, 210);
329
+ }
330
+
331
+ function test_transfer_under_failure() public {
332
+ address alice = makeAddr("alice");
333
+ address bob = makeAddr("bob");
334
+
335
+ s_token.mint(alice, 120);
336
+
337
+ vm.stopPrank();
338
+ vm.startPrank(alice);
339
+
340
+ vm.expectRevert(
341
+ abi.encodeWithSelector(
342
+ IPolicyEngine.PolicyRunRejected.selector,
343
+ IERC20.transfer.selector,
344
+ address(volumePolicy),
345
+ "amount outside allowed volume limits"
346
+ )
347
+ );
348
+ s_token.transfer(bob, 50);
349
+ }
350
+
351
+ function test_transfer_paused_revert() public {
352
+ address alice = makeAddr("alice");
353
+ address bob = makeAddr("bob");
354
+
355
+ s_token.mint(alice, 120);
356
+
357
+ s_token.pause();
358
+ assertEq(s_token.paused(), true);
359
+
360
+ vm.stopPrank();
361
+ vm.startPrank(alice);
362
+
363
+ vm.expectRevert("Pausable: paused");
364
+ s_token.transfer(bob, 110);
365
+ }
366
+
367
+ function test_transfer_pause_notOwner_revert() public {
368
+ address alice = makeAddr("alice");
369
+ vm.startPrank(alice);
370
+
371
+ vm.expectRevert(
372
+ abi.encodeWithSelector(
373
+ IPolicyEngine.PolicyRunRejected.selector,
374
+ IToken.pause.selector,
375
+ address(onlyOwnerPolicy),
376
+ "caller is not the policy owner"
377
+ )
378
+ );
379
+ s_token.pause();
380
+ }
381
+
382
+ function test_transfer_pausedUnpaused_success() public {
383
+ address alice = makeAddr("alice");
384
+ address bob = makeAddr("bob");
385
+
386
+ s_token.mint(alice, 120);
387
+
388
+ s_token.pause();
389
+ assertEq(s_token.paused(), true);
390
+
391
+ s_token.unpause();
392
+ assertEq(s_token.paused(), false);
393
+
394
+ vm.stopPrank();
395
+ vm.startPrank(alice);
396
+
397
+ s_token.transfer(bob, 110);
398
+ assertEq(s_token.balanceOf(alice), 10);
399
+ assertEq(s_token.balanceOf(bob), 110);
400
+ }
401
+
402
+ function test_transfer_unpaused_notOwner_failure() public {
403
+ address alice = makeAddr("alice");
404
+ s_token.pause();
405
+ assertEq(s_token.paused(), true);
406
+
407
+ vm.stopPrank();
408
+ vm.startPrank(alice);
409
+
410
+ vm.expectRevert(
411
+ abi.encodeWithSelector(
412
+ IPolicyEngine.PolicyRunRejected.selector,
413
+ IToken.unpause.selector,
414
+ address(onlyOwnerPolicy),
415
+ "caller is not the policy owner"
416
+ )
417
+ );
418
+ s_token.unpause();
419
+ }
420
+
421
+ function test_transfer_frozenUnfrozen_success() public {
422
+ address alice = makeAddr("alice");
423
+ address bob = makeAddr("bob");
424
+
425
+ s_token.mint(alice, 120);
426
+
427
+ s_token.setAddressFrozen(alice, true);
428
+ assertEq(s_token.isFrozen(alice), true);
429
+
430
+ vm.stopPrank();
431
+ vm.startPrank(alice);
432
+
433
+ vm.expectRevert("wallet is frozen");
434
+ s_token.transfer(bob, 110);
435
+
436
+ vm.stopPrank();
437
+ vm.startPrank(s_owner);
438
+
439
+ s_token.setAddressFrozen(alice, false);
440
+ assertEq(s_token.isFrozen(alice), false);
441
+
442
+ vm.stopPrank();
443
+ vm.startPrank(alice);
444
+
445
+ s_token.transfer(bob, 110);
446
+ assertEq(s_token.balanceOf(alice), 10);
447
+ assertEq(s_token.balanceOf(bob), 110);
448
+ }
449
+
450
+ function test_frozenUnfrozen_enforcer_success() public {
451
+ address alice = makeAddr("alice");
452
+ address bob = makeAddr("bob");
453
+
454
+ s_token.mint(alice, 120);
455
+
456
+ vm.startPrank(s_enforcer);
457
+ s_token.setAddressFrozen(alice, true);
458
+ assertEq(s_token.isFrozen(alice), true);
459
+
460
+ vm.stopPrank();
461
+ vm.startPrank(alice);
462
+
463
+ vm.expectRevert("wallet is frozen");
464
+ s_token.transfer(bob, 110);
465
+
466
+ vm.stopPrank();
467
+ vm.startPrank(s_enforcer);
468
+
469
+ s_token.setAddressFrozen(alice, false);
470
+ assertEq(s_token.isFrozen(alice), false);
471
+
472
+ vm.stopPrank();
473
+ vm.startPrank(alice);
474
+
475
+ s_token.transfer(bob, 110);
476
+ assertEq(s_token.balanceOf(alice), 10);
477
+ assertEq(s_token.balanceOf(bob), 110);
478
+ }
479
+
480
+ function test_frozen_notAuthorized_failure() public {
481
+ address alice = makeAddr("alice");
482
+
483
+ s_token.mint(alice, 120);
484
+
485
+ vm.startPrank(alice);
486
+ vm.expectRevert(
487
+ abi.encodeWithSelector(
488
+ IPolicyEngine.PolicyRunRejected.selector,
489
+ IToken.setAddressFrozen.selector,
490
+ address(freezingList),
491
+ "sender is not authorized"
492
+ )
493
+ );
494
+ s_token.setAddressFrozen(alice, true);
495
+ }
496
+
497
+ function test_transferFrom_success() public {
498
+ address alice = makeAddr("alice");
499
+ address bob = makeAddr("bob");
500
+ address charlie = makeAddr("charlie");
501
+
502
+ s_token.mint(alice, 199);
503
+
504
+ vm.stopPrank();
505
+ vm.startPrank(alice);
506
+
507
+ s_token.approve(charlie, 110);
508
+
509
+ vm.stopPrank();
510
+ vm.startPrank(charlie);
511
+
512
+ s_token.transferFrom(alice, bob, 110);
513
+
514
+ assertEq(s_token.balanceOf(alice), 89);
515
+ assertEq(s_token.balanceOf(bob), 110);
516
+ }
517
+
518
+ function test_transferFrom_increasedAllowance_success() public {
519
+ address alice = makeAddr("alice");
520
+ address bob = makeAddr("bob");
521
+ address charlie = makeAddr("charlie");
522
+
523
+ s_token.mint(alice, 150);
524
+
525
+ vm.stopPrank();
526
+ vm.startPrank(alice);
527
+
528
+ s_token.approve(charlie, 50);
529
+ s_token.increaseAllowance(charlie, 60);
530
+ assertEq(s_token.allowance(alice, charlie), 110);
531
+
532
+ vm.stopPrank();
533
+ vm.startPrank(charlie);
534
+
535
+ s_token.transferFrom(alice, bob, 110);
536
+
537
+ assertEq(s_token.balanceOf(alice), 40);
538
+ assertEq(s_token.balanceOf(bob), 110);
539
+ }
540
+
541
+ function test_approve_paused_revert() public {
542
+ address alice = makeAddr("alice");
543
+ address charlie = makeAddr("charlie");
544
+
545
+ s_token.mint(alice, 110);
546
+ s_token.pause();
547
+
548
+ vm.stopPrank();
549
+ vm.startPrank(alice);
550
+
551
+ vm.expectRevert("Pausable: paused");
552
+ s_token.approve(charlie, 5);
553
+ }
554
+
555
+ function test_transferFrom_paused_revert() public {
556
+ address alice = makeAddr("alice");
557
+ address charlie = makeAddr("charlie");
558
+
559
+ s_token.mint(alice, 150);
560
+
561
+ vm.stopPrank();
562
+ vm.startPrank(alice);
563
+
564
+ s_token.approve(charlie, 50);
565
+
566
+ vm.stopPrank();
567
+ vm.startPrank(s_owner);
568
+ s_token.pause();
569
+
570
+ vm.stopPrank();
571
+ vm.startPrank(alice);
572
+
573
+ vm.expectRevert("Pausable: paused");
574
+ s_token.approve(charlie, 60);
575
+ }
576
+
577
+ function test_transferFrom_insufficientAllowance_revert() public {
578
+ address alice = makeAddr("alice");
579
+ address bob = makeAddr("bob");
580
+ address charlie = makeAddr("charlie");
581
+
582
+ s_token.mint(alice, 150);
583
+
584
+ vm.stopPrank();
585
+ vm.startPrank(alice);
586
+
587
+ s_token.approve(charlie, 50);
588
+
589
+ vm.stopPrank();
590
+ vm.startPrank(charlie);
591
+
592
+ vm.expectRevert(); // panic: arithmetic underflow or overflow
593
+ s_token.transferFrom(alice, bob, 110);
594
+ }
595
+
596
+ function test_transferFrom_decreaseAllowance_revert() public {
597
+ address alice = makeAddr("alice");
598
+ address bob = makeAddr("bob");
599
+ address charlie = makeAddr("charlie");
600
+
601
+ s_token.mint(alice, 150);
602
+
603
+ vm.stopPrank();
604
+ vm.startPrank(alice);
605
+
606
+ s_token.approve(charlie, 110);
607
+ s_token.decreaseAllowance(charlie, 20);
608
+
609
+ vm.stopPrank();
610
+ vm.startPrank(charlie);
611
+
612
+ vm.expectRevert(); // panic: arithmetic underflow or overflow
613
+ s_token.transferFrom(alice, bob, 110);
614
+ }
615
+
616
+ function test_transferFrom_frozenBalance_revert() public {
617
+ address alice = makeAddr("alice");
618
+ address bob = makeAddr("bob");
619
+ address charlie = makeAddr("charlie");
620
+
621
+ s_token.mint(alice, 150);
622
+
623
+ s_token.freezePartialTokens(alice, 60);
624
+ assertEq(s_token.getFrozenTokens(alice), 60);
625
+
626
+ vm.stopPrank();
627
+ vm.startPrank(alice);
628
+
629
+ s_token.approve(charlie, 50);
630
+
631
+ vm.stopPrank();
632
+ vm.startPrank(charlie);
633
+
634
+ vm.expectRevert("Insufficient Balance");
635
+ s_token.transferFrom(alice, bob, 110);
636
+ }
637
+
638
+ function test_transfer_frozenBalance_revert() public {
639
+ address alice = makeAddr("alice");
640
+ address bob = makeAddr("bob");
641
+
642
+ s_token.mint(alice, 120);
643
+ s_token.freezePartialTokens(alice, 50);
644
+
645
+ vm.stopPrank();
646
+ vm.startPrank(alice);
647
+
648
+ vm.expectRevert("Insufficient Balance");
649
+ s_token.transfer(bob, 110);
650
+ }
651
+
652
+ function test_transfer_partialUnfrozen_success() public {
653
+ address alice = makeAddr("alice");
654
+ address bob = makeAddr("bob");
655
+
656
+ s_token.mint(alice, 120);
657
+ s_token.freezePartialTokens(alice, 10);
658
+
659
+ vm.stopPrank();
660
+ vm.startPrank(alice);
661
+
662
+ s_token.transfer(bob, 105);
663
+
664
+ assertEq(s_token.balanceOf(alice), 15);
665
+ assertEq(s_token.balanceOf(bob), 105);
666
+ }
667
+
668
+ function test_transfer_partialUnfrozen_enforcer_success() public {
669
+ address alice = makeAddr("alice");
670
+ address bob = makeAddr("bob");
671
+
672
+ s_token.mint(alice, 120);
673
+ vm.startPrank(s_enforcer);
674
+ s_token.freezePartialTokens(alice, 10);
675
+
676
+ vm.stopPrank();
677
+ vm.startPrank(alice);
678
+
679
+ s_token.transfer(bob, 105);
680
+
681
+ assertEq(s_token.balanceOf(alice), 15);
682
+ assertEq(s_token.balanceOf(bob), 105);
683
+ }
684
+
685
+ function test_transfer_partialFreeze_notAuthorized_failure() public {
686
+ address alice = makeAddr("alice");
687
+
688
+ s_token.mint(alice, 120);
689
+ vm.startPrank(alice);
690
+ vm.expectRevert(
691
+ abi.encodeWithSelector(
692
+ IPolicyEngine.PolicyRunRejected.selector,
693
+ IToken.freezePartialTokens.selector,
694
+ address(freezingList),
695
+ "sender is not authorized"
696
+ )
697
+ );
698
+ s_token.freezePartialTokens(alice, 10);
699
+ }
700
+
701
+ function test_transfer_unfreezeBalance_success() public {
702
+ address alice = makeAddr("alice");
703
+ address bob = makeAddr("bob");
704
+
705
+ s_token.mint(alice, 120);
706
+ s_token.freezePartialTokens(alice, 50);
707
+ assertEq(s_token.getFrozenTokens(alice), 50);
708
+
709
+ vm.stopPrank();
710
+ vm.startPrank(alice);
711
+
712
+ vm.expectRevert("Insufficient Balance");
713
+ s_token.transfer(bob, 110);
714
+
715
+ vm.stopPrank();
716
+ vm.startPrank(s_owner);
717
+
718
+ s_token.unfreezePartialTokens(alice, 40);
719
+ assertEq(s_token.getFrozenTokens(alice), 10);
720
+
721
+ vm.stopPrank();
722
+ vm.startPrank(alice);
723
+
724
+ s_token.transfer(bob, 110);
725
+
726
+ assertEq(s_token.balanceOf(alice), 10);
727
+ assertEq(s_token.balanceOf(bob), 110);
728
+ }
729
+
730
+ function test_transfer_partialUnfrozen_notAuthorized_failure() public {
731
+ address alice = makeAddr("alice");
732
+
733
+ s_token.mint(alice, 120);
734
+ s_token.freezePartialTokens(alice, 50);
735
+
736
+ vm.startPrank(alice);
737
+ vm.expectRevert(
738
+ abi.encodeWithSelector(
739
+ IPolicyEngine.PolicyRunRejected.selector,
740
+ IToken.unfreezePartialTokens.selector,
741
+ address(freezingList),
742
+ "sender is not authorized"
743
+ )
744
+ );
745
+ s_token.unfreezePartialTokens(alice, 10);
746
+ }
747
+
748
+ function test_forcedTransfer_success() public {
749
+ address alice = makeAddr("alice");
750
+ address bob = makeAddr("bob");
751
+
752
+ s_token.mint(alice, 110);
753
+
754
+ s_token.forcedTransfer(alice, bob, 60);
755
+
756
+ assertEq(s_token.balanceOf(alice), 50);
757
+ assertEq(s_token.balanceOf(bob), 60);
758
+ }
759
+
760
+ function test_forcedTransfer_frozenBalance_success() public {
761
+ address alice = makeAddr("alice");
762
+ address bob = makeAddr("bob");
763
+
764
+ s_token.mint(alice, 150);
765
+
766
+ s_token.freezePartialTokens(alice, 90);
767
+
768
+ s_token.forcedTransfer(alice, bob, 90);
769
+
770
+ assertEq(s_token.balanceOf(alice), 60);
771
+ assertEq(s_token.balanceOf(bob), 90);
772
+ }
773
+
774
+ function test_forcedTransfer_notOwner_revert() public {
775
+ address alice = makeAddr("alice");
776
+ address bob = makeAddr("bob");
777
+
778
+ s_token.mint(alice, 150);
779
+
780
+ vm.stopPrank();
781
+ vm.startPrank(bob);
782
+
783
+ vm.expectRevert(
784
+ abi.encodeWithSelector(
785
+ IPolicyEngine.PolicyRunRejected.selector,
786
+ IToken.forcedTransfer.selector,
787
+ address(onlyOwnerPolicy),
788
+ "caller is not the policy owner"
789
+ )
790
+ );
791
+ s_token.forcedTransfer(alice, bob, 60);
792
+ }
793
+
794
+ function test_setOnchainID_revert() public {
795
+ vm.expectRevert("Not implemented");
796
+ s_token.setOnchainID(makeAddr("onchainID"));
797
+ }
798
+
799
+ function test_setIdentityRegistry_revert() public {
800
+ vm.expectRevert("Not implemented");
801
+ s_token.setIdentityRegistry(makeAddr("IdentityRegistry"));
802
+ assertEq(address(s_token.identityRegistry()), address(0));
803
+ }
804
+
805
+ function test_setCompliance_revert() public {
806
+ vm.expectRevert("Not implemented");
807
+ s_token.setCompliance(makeAddr("ModularCompliance"));
808
+ assertEq(address(s_token.compliance()), address(0));
809
+ }
810
+
811
+ function test_recoveryAddress_revert() public {
812
+ vm.expectRevert("Not implemented");
813
+ s_token.recoveryAddress(makeAddr("old"), makeAddr("new"), makeAddr("onchainId"));
814
+ }
815
+ }