@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,564 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ pragma solidity 0.8.26;
3
+
4
+ import {IToken} from "../../../vendor/erc-3643/token/IToken.sol";
5
+ import {IIdentityRegistry} from "../../../vendor/erc-3643/registry/interface/IIdentityRegistry.sol";
6
+ import {IModularCompliance} from "../../../vendor/erc-3643/compliance/modular/IModularCompliance.sol";
7
+ import {ComplianceTokenStoreERC3643} from "./ComplianceTokenStoreERC3643.sol";
8
+ import {PolicyProtected} from "@chainlink/policy-management/core/PolicyProtected.sol";
9
+ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
10
+
11
+ contract ComplianceTokenERC3643 is Initializable, PolicyProtected, ComplianceTokenStoreERC3643, IToken {
12
+ string private constant TOKEN_VERSION = "1.0.0";
13
+
14
+ /// modifiers
15
+
16
+ /// @dev Modifier to make a function callable only when the contract is not paused.
17
+ modifier whenNotPaused() {
18
+ require(!getComplianceTokenStorage().tokenPaused, "Pausable: paused");
19
+ _;
20
+ }
21
+
22
+ /**
23
+ * @dev Initializes the contract with the provided token metadata and assigns policy engine.
24
+ * @param tokenName The name of the token.
25
+ * @param tokenSymbol The symbol of the token.
26
+ * @param tokenDecimals The number of decimals to use for display purposes.
27
+ * @param policyEngine The address of the policy engine contract.
28
+ */
29
+ function initialize(
30
+ string calldata tokenName,
31
+ string calldata tokenSymbol,
32
+ uint8 tokenDecimals,
33
+ address policyEngine
34
+ )
35
+ public
36
+ virtual
37
+ initializer
38
+ {
39
+ __ComplianceTokenERC3643_init(tokenName, tokenSymbol, tokenDecimals, policyEngine);
40
+ }
41
+
42
+ /**
43
+ * @dev Upgradeable init function to be used by a token implementation contract.
44
+ * @param tokenName The name of the token.
45
+ * @param tokenSymbol The symbol of the token.
46
+ * @param tokenDecimals The number of decimals to use for display purposes.
47
+ * @param policyEngine The address of the policy engine contract.
48
+ */
49
+ function __ComplianceTokenERC3643_init(
50
+ string memory tokenName,
51
+ string memory tokenSymbol,
52
+ uint8 tokenDecimals,
53
+ address policyEngine
54
+ )
55
+ internal
56
+ onlyInitializing
57
+ {
58
+ __PolicyProtected_init(msg.sender, policyEngine);
59
+ __ComplianceTokenERC3643_init_unchained(tokenName, tokenSymbol, tokenDecimals);
60
+ }
61
+
62
+ /**
63
+ * @dev Unchained upgradeable init function to be used by a token implementation contract.
64
+ * @param tokenName The name of the token.
65
+ * @param tokenSymbol The symbol of the token.
66
+ * @param tokenDecimals The number of decimals to use for display purposes.
67
+ */
68
+ function __ComplianceTokenERC3643_init_unchained(
69
+ string memory tokenName,
70
+ string memory tokenSymbol,
71
+ uint8 tokenDecimals
72
+ )
73
+ internal
74
+ onlyInitializing
75
+ {
76
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
77
+ $.tokenName = tokenName;
78
+ $.tokenSymbol = tokenSymbol;
79
+ $.tokenDecimals = tokenDecimals;
80
+ }
81
+
82
+ /**
83
+ * @dev See {IERC20-approve}.
84
+ */
85
+ function approve(address _spender, uint256 _amount) external virtual override whenNotPaused runPolicy returns (bool) {
86
+ _approve(msg.sender, _spender, _amount);
87
+ return true;
88
+ }
89
+
90
+ /**
91
+ * @dev Increases the allowance granted to `_spender` by the caller.
92
+ * This is an OpenZeppelin extension to ERC20, not part of the core ERC20 standard.
93
+ */
94
+ function increaseAllowance(
95
+ address _spender,
96
+ uint256 _addedValue
97
+ )
98
+ external
99
+ virtual
100
+ whenNotPaused
101
+ runPolicy
102
+ returns (bool)
103
+ {
104
+ _approve(msg.sender, _spender, getComplianceTokenStorage().allowances[msg.sender][_spender] + (_addedValue));
105
+ return true;
106
+ }
107
+
108
+ /**
109
+ * @dev Decreases the allowance granted to `_spender` by the caller.
110
+ * This is an OpenZeppelin extension to ERC20, not part of the core ERC20 standard.
111
+ */
112
+ function decreaseAllowance(
113
+ address _spender,
114
+ uint256 _subtractedValue
115
+ )
116
+ external
117
+ virtual
118
+ whenNotPaused
119
+ runPolicy
120
+ returns (bool)
121
+ {
122
+ _approve(msg.sender, _spender, getComplianceTokenStorage().allowances[msg.sender][_spender] - _subtractedValue);
123
+ return true;
124
+ }
125
+
126
+ /**
127
+ * @dev See {IToken-setName}.
128
+ */
129
+ function setName(string calldata _name) external override runPolicy {
130
+ require(keccak256(abi.encode(_name)) != keccak256(abi.encode("")), "invalid argument - empty string");
131
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
132
+ $.tokenName = _name;
133
+ emit UpdatedTokenInformation($.tokenName, $.tokenSymbol, $.tokenDecimals, TOKEN_VERSION, address(0));
134
+ }
135
+
136
+ /**
137
+ * @dev See {IToken-setSymbol}.
138
+ */
139
+ function setSymbol(string calldata _symbol) external override runPolicy {
140
+ require(keccak256(abi.encode(_symbol)) != keccak256(abi.encode("")), "invalid argument - empty string");
141
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
142
+ $.tokenSymbol = _symbol;
143
+ emit UpdatedTokenInformation($.tokenName, $.tokenSymbol, $.tokenDecimals, TOKEN_VERSION, address(0));
144
+ }
145
+
146
+ /**
147
+ * @dev See {IToken-setOnchainID}.
148
+ * if _onchainID is set at zero address it means no ONCHAINID is bound to this token
149
+ */
150
+ function setOnchainID(address /*_onchainID*/ ) external pure override {
151
+ revert("Not implemented");
152
+ }
153
+
154
+ /**
155
+ * @dev See {IToken-pause}.
156
+ */
157
+ function pause() external override runPolicy {
158
+ getComplianceTokenStorage().tokenPaused = true;
159
+ emit Paused(msg.sender);
160
+ }
161
+
162
+ /**
163
+ * @dev See {IToken-unpause}.
164
+ */
165
+ function unpause() external override runPolicy {
166
+ getComplianceTokenStorage().tokenPaused = false;
167
+ emit Unpaused(msg.sender);
168
+ }
169
+
170
+ /**
171
+ * @dev See {IToken-batchTransfer}.
172
+ */
173
+ function batchTransfer(address[] calldata _toList, uint256[] calldata _amounts) external override {
174
+ for (uint256 i = 0; i < _toList.length; i++) {
175
+ transfer(_toList[i], _amounts[i]);
176
+ }
177
+ }
178
+
179
+ /**
180
+ * @notice ERC-20 overridden function that include logic to check for trade validity.
181
+ * Require that the from and to addresses are not frozen.
182
+ * Require that the value should not exceed available balance .
183
+ * Require that the to address is a verified address
184
+ * Skips emitting an {Approval} event indicating an allowance update.
185
+ * @param _from The address of the sender
186
+ * @param _to The address of the receiver
187
+ * @param _amount The number of tokens to transfer
188
+ * @return `true` if successful and revert if unsuccessful
189
+ */
190
+ function transferFrom(
191
+ address _from,
192
+ address _to,
193
+ uint256 _amount
194
+ )
195
+ external
196
+ override
197
+ whenNotPaused
198
+ runPolicy
199
+ returns (bool)
200
+ {
201
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
202
+
203
+ require(!$.frozen[_to] && !$.frozen[_from], "wallet is frozen");
204
+ require(_amount <= $.balances[_from] - ($.frozenTokens[_from]), "Insufficient Balance");
205
+ _approve(_from, msg.sender, $.allowances[_from][msg.sender] - (_amount), false);
206
+ _transfer(_from, _to, _amount);
207
+ return true;
208
+ }
209
+
210
+ /**
211
+ * @dev See {IToken-batchForcedTransfer}.
212
+ */
213
+ function batchForcedTransfer(
214
+ address[] calldata _fromList,
215
+ address[] calldata _toList,
216
+ uint256[] calldata _amounts
217
+ )
218
+ external
219
+ override
220
+ {
221
+ for (uint256 i = 0; i < _fromList.length; i++) {
222
+ forcedTransfer(_fromList[i], _toList[i], _amounts[i]);
223
+ }
224
+ }
225
+
226
+ /**
227
+ * @dev See {IToken-batchMint}.
228
+ */
229
+ function batchMint(address[] calldata _toList, uint256[] calldata _amounts) external override {
230
+ for (uint256 i = 0; i < _toList.length; i++) {
231
+ mint(_toList[i], _amounts[i]);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * @dev See {IToken-batchBurn}.
237
+ */
238
+ function batchBurn(address[] calldata _userAddresses, uint256[] calldata _amounts) external override {
239
+ for (uint256 i = 0; i < _userAddresses.length; i++) {
240
+ burn(_userAddresses[i], _amounts[i]);
241
+ }
242
+ }
243
+
244
+ /**
245
+ * @dev See {IToken-batchSetAddressFrozen}.
246
+ */
247
+ function batchSetAddressFrozen(address[] calldata _userAddresses, bool[] calldata _freeze) external override {
248
+ for (uint256 i = 0; i < _userAddresses.length; i++) {
249
+ setAddressFrozen(_userAddresses[i], _freeze[i]);
250
+ }
251
+ }
252
+
253
+ /**
254
+ * @dev See {IToken-batchFreezePartialTokens}.
255
+ */
256
+ function batchFreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external override {
257
+ for (uint256 i = 0; i < _userAddresses.length; i++) {
258
+ freezePartialTokens(_userAddresses[i], _amounts[i]);
259
+ }
260
+ }
261
+
262
+ /**
263
+ * @dev See {IToken-batchUnfreezePartialTokens}.
264
+ */
265
+ function batchUnfreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external override {
266
+ for (uint256 i = 0; i < _userAddresses.length; i++) {
267
+ unfreezePartialTokens(_userAddresses[i], _amounts[i]);
268
+ }
269
+ }
270
+
271
+ /**
272
+ * @dev See {IToken-recoveryAddress}.
273
+ */
274
+ function recoveryAddress(
275
+ address, /*_lostWallet */
276
+ address, /*_newWallet */
277
+ address /*_investorOnchainID */
278
+ )
279
+ external
280
+ pure
281
+ override
282
+ returns (bool)
283
+ {
284
+ revert("Not implemented");
285
+ }
286
+
287
+ /**
288
+ * @dev See {IERC20-totalSupply}.
289
+ */
290
+ function totalSupply() external view override returns (uint256) {
291
+ return getComplianceTokenStorage().totalSupply;
292
+ }
293
+
294
+ /**
295
+ * @dev See {IERC20-allowance}.
296
+ */
297
+ function allowance(address _owner, address _spender) external view virtual override returns (uint256) {
298
+ return getComplianceTokenStorage().allowances[_owner][_spender];
299
+ }
300
+
301
+ /**
302
+ * @dev See {IToken-identityRegistry}.
303
+ */
304
+ function identityRegistry() external pure override returns (IIdentityRegistry) {
305
+ return IIdentityRegistry(address(0));
306
+ }
307
+
308
+ /**
309
+ * @dev See {IToken-compliance}.
310
+ */
311
+ function compliance() external pure override returns (IModularCompliance) {
312
+ return IModularCompliance(address(0));
313
+ }
314
+
315
+ /**
316
+ * @dev See {IToken-paused}.
317
+ */
318
+ function paused() external view override returns (bool) {
319
+ return getComplianceTokenStorage().tokenPaused;
320
+ }
321
+
322
+ /**
323
+ * @dev See {IToken-isFrozen}.
324
+ */
325
+ function isFrozen(address _userAddress) external view override returns (bool) {
326
+ return getComplianceTokenStorage().frozen[_userAddress];
327
+ }
328
+
329
+ /**
330
+ * @dev See {IToken-getFrozenTokens}.
331
+ */
332
+ function getFrozenTokens(address _userAddress) external view override returns (uint256) {
333
+ return getComplianceTokenStorage().frozenTokens[_userAddress];
334
+ }
335
+
336
+ /**
337
+ * @dev See {IToken-decimals}.
338
+ */
339
+ function decimals() external view override returns (uint8) {
340
+ return getComplianceTokenStorage().tokenDecimals;
341
+ }
342
+
343
+ /**
344
+ * @dev See {IToken-name}.
345
+ */
346
+ function name() external view override returns (string memory) {
347
+ return getComplianceTokenStorage().tokenName;
348
+ }
349
+
350
+ /**
351
+ * @dev See {IToken-onchainID}.
352
+ */
353
+ function onchainID() external pure override returns (address) {
354
+ return address(0);
355
+ }
356
+
357
+ /**
358
+ * @dev See {IToken-symbol}.
359
+ */
360
+ function symbol() external view override returns (string memory) {
361
+ return getComplianceTokenStorage().tokenSymbol;
362
+ }
363
+
364
+ /**
365
+ * @dev See {IToken-version}.
366
+ */
367
+ function version() external pure override returns (string memory) {
368
+ return TOKEN_VERSION;
369
+ }
370
+
371
+ /**
372
+ * @notice ERC-20 overridden function that include logic to check for trade validity.
373
+ * Require that the msg.sender and to addresses are not frozen.
374
+ * Require that the value should not exceed available balance .
375
+ * Require that the to address is a verified address
376
+ * @param _to The address of the receiver
377
+ * @param _amount The number of tokens to transfer
378
+ * @return `true` if successful and revert if unsuccessful
379
+ */
380
+ function transfer(address _to, uint256 _amount) public override whenNotPaused runPolicy returns (bool) {
381
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
382
+
383
+ require(!$.frozen[_to] && !$.frozen[msg.sender], "wallet is frozen");
384
+ require(_amount <= $.balances[msg.sender] - ($.frozenTokens[msg.sender]), "Insufficient Balance");
385
+ _transfer(msg.sender, _to, _amount);
386
+ return true;
387
+ }
388
+
389
+ /**
390
+ * @dev See {IToken-forcedTransfer}.
391
+ */
392
+ function forcedTransfer(address _from, address _to, uint256 _amount) public override runPolicy returns (bool) {
393
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
394
+
395
+ require($.balances[_from] >= _amount, "sender balance too low");
396
+ uint256 freeBalance = $.balances[_from] - ($.frozenTokens[_from]);
397
+ if (_amount > freeBalance) {
398
+ uint256 tokensToUnfreeze = _amount - (freeBalance);
399
+ $.frozenTokens[_from] = $.frozenTokens[_from] - (tokensToUnfreeze);
400
+ emit TokensUnfrozen(_from, tokensToUnfreeze);
401
+ }
402
+ _transfer(_from, _to, _amount);
403
+ return true;
404
+ }
405
+
406
+ /**
407
+ * @dev Mints tokens to a specified address as defined by the ERC-3643 IToken interface.
408
+ */
409
+ function mint(address _to, uint256 _amount) public override runPolicy {
410
+ _mint(_to, _amount);
411
+ }
412
+
413
+ /**
414
+ * @dev Burns tokens from a specified address as defined by the ERC-3643 IToken interface.
415
+ */
416
+ function burn(address _userAddress, uint256 _amount) public override runPolicy {
417
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
418
+
419
+ require($.balances[_userAddress] >= _amount, "cannot burn more than balance");
420
+ uint256 freeBalance = $.balances[_userAddress] - $.frozenTokens[_userAddress];
421
+ if (_amount > freeBalance) {
422
+ uint256 tokensToUnfreeze = _amount - (freeBalance);
423
+ $.frozenTokens[_userAddress] = $.frozenTokens[_userAddress] - (tokensToUnfreeze);
424
+ emit TokensUnfrozen(_userAddress, tokensToUnfreeze);
425
+ }
426
+ _burn(_userAddress, _amount);
427
+ }
428
+
429
+ /**
430
+ * @dev See {IToken-setAddressFrozen}.
431
+ */
432
+ function setAddressFrozen(address _userAddress, bool _freeze) public override runPolicy {
433
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
434
+
435
+ $.frozen[_userAddress] = _freeze;
436
+ emit AddressFrozen(_userAddress, _freeze, msg.sender);
437
+ }
438
+
439
+ /**
440
+ * @dev See {IToken-freezePartialTokens}.
441
+ */
442
+ function freezePartialTokens(address _userAddress, uint256 _amount) public override runPolicy {
443
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
444
+
445
+ uint256 balance = $.balances[_userAddress];
446
+ require(balance >= $.frozenTokens[_userAddress] + _amount, "Amount exceeds available balance");
447
+ $.frozenTokens[_userAddress] = $.frozenTokens[_userAddress] + (_amount);
448
+ emit TokensFrozen(_userAddress, _amount);
449
+ }
450
+
451
+ /**
452
+ * @dev See {IToken-unfreezePartialTokens}.
453
+ */
454
+ function unfreezePartialTokens(address _userAddress, uint256 _amount) public override runPolicy {
455
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
456
+
457
+ require($.frozenTokens[_userAddress] >= _amount, "Amount should be less than or equal to frozen tokens");
458
+ $.frozenTokens[_userAddress] = $.frozenTokens[_userAddress] - (_amount);
459
+ emit TokensUnfrozen(_userAddress, _amount);
460
+ }
461
+
462
+ /**
463
+ * @dev See {IToken-setIdentityRegistry}.
464
+ */
465
+ function setIdentityRegistry(address /*_identityRegistry*/ ) public pure override {
466
+ revert("Not implemented");
467
+ }
468
+
469
+ /**
470
+ * @dev See {IToken-setCompliance}.
471
+ */
472
+ function setCompliance(address /*_compliance*/ ) public pure override {
473
+ revert("Not implemented");
474
+ }
475
+
476
+ /**
477
+ * @dev See {IERC20-balanceOf}.
478
+ */
479
+ function balanceOf(address _userAddress) public view override returns (uint256) {
480
+ return getComplianceTokenStorage().balances[_userAddress];
481
+ }
482
+
483
+ function getCCIPAdmin() public view virtual returns (address) {
484
+ return owner();
485
+ }
486
+
487
+ function supportsInterface(bytes4 interfaceId) public view virtual override(PolicyProtected) returns (bool) {
488
+ return super.supportsInterface(interfaceId);
489
+ }
490
+
491
+ /**
492
+ * @dev See {ERC20-_transfer}.
493
+ */
494
+ function _transfer(address _from, address _to, uint256 _amount) internal virtual {
495
+ require(_from != address(0), "ERC20: transfer from the zero address");
496
+ require(_to != address(0), "ERC20: transfer to the zero address");
497
+
498
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
499
+
500
+ _beforeTokenTransfer(_from, _to, _amount);
501
+
502
+ $.balances[_from] = $.balances[_from] - _amount;
503
+ $.balances[_to] = $.balances[_to] + _amount;
504
+ emit Transfer(_from, _to, _amount);
505
+ }
506
+
507
+ /**
508
+ * @dev See {ERC20-_mint}.
509
+ */
510
+ function _mint(address _userAddress, uint256 _amount) internal virtual {
511
+ require(_userAddress != address(0), "ERC20: mint to the zero address");
512
+
513
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
514
+
515
+ _beforeTokenTransfer(address(0), _userAddress, _amount);
516
+
517
+ $.totalSupply = $.totalSupply + _amount;
518
+ $.balances[_userAddress] = $.balances[_userAddress] + _amount;
519
+ emit Transfer(address(0), _userAddress, _amount);
520
+ }
521
+
522
+ /**
523
+ * @dev See {ERC20-_burn}.
524
+ */
525
+ function _burn(address _userAddress, uint256 _amount) internal virtual {
526
+ require(_userAddress != address(0), "ERC20: burn from the zero address");
527
+
528
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
529
+
530
+ _beforeTokenTransfer(_userAddress, address(0), _amount);
531
+
532
+ $.balances[_userAddress] = $.balances[_userAddress] - _amount;
533
+ $.totalSupply = $.totalSupply - _amount;
534
+ emit Transfer(_userAddress, address(0), _amount);
535
+ }
536
+
537
+ /**
538
+ * @dev See {ERC20-_approve}.
539
+ */
540
+ function _approve(address _owner, address _spender, uint256 _amount) internal virtual {
541
+ _approve(_owner, _spender, _amount, true);
542
+ }
543
+
544
+ /**
545
+ * @dev See {ERC20-_approve}.
546
+ */
547
+ function _approve(address _owner, address _spender, uint256 _amount, bool emitEvent) internal virtual {
548
+ require(_owner != address(0), "ERC20: approve from the zero address");
549
+ require(_spender != address(0), "ERC20: approve to the zero address");
550
+
551
+ ComplianceTokenStorage storage $ = getComplianceTokenStorage();
552
+
553
+ $.allowances[_owner][_spender] = _amount;
554
+ if (emitEvent) {
555
+ emit Approval(_owner, _spender, _amount);
556
+ }
557
+ }
558
+
559
+ /**
560
+ * @dev See {ERC20-_beforeTokenTransfer}.
561
+ */
562
+ // solhint-disable-next-line no-empty-blocks
563
+ function _beforeTokenTransfer(address _from, address _to, uint256 _amount) internal virtual {}
564
+ }
@@ -0,0 +1,30 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ pragma solidity 0.8.26;
3
+
4
+ contract ComplianceTokenStoreERC3643 {
5
+ /// @custom:storage-location erc7201:compliance-token-erc3643.ComplianceTokenStoreERC3643
6
+ struct ComplianceTokenStorage {
7
+ string tokenName;
8
+ string tokenSymbol;
9
+ uint8 tokenDecimals;
10
+ bool tokenPaused;
11
+ uint256 totalSupply;
12
+ mapping(address userAddress => uint256 balance) balances;
13
+ mapping(address userAddress => mapping(address spender => uint256 allowance)) allowances;
14
+ mapping(address userAddress => bool isFrozen) frozen;
15
+ mapping(address userAddress => uint256 amount) frozenTokens;
16
+ }
17
+
18
+ // keccak256(abi.encode(uint256(keccak256("compliance-token-erc3643.ComplianceTokenStoreERC3643")) - 1)) &
19
+ // ~bytes32(uint256(0xff))
20
+ // solhint-disable-next-line const-name-snakecase
21
+ bytes32 private constant complianceTokenStorageLocation =
22
+ 0xdc918d90baf191b8d972d59f66f8d1c2691d3df52961983ba712e24ad9fcd600;
23
+
24
+ function getComplianceTokenStorage() internal pure returns (ComplianceTokenStorage storage $) {
25
+ // solhint-disable-next-line no-inline-assembly
26
+ assembly {
27
+ $.slot := complianceTokenStorageLocation
28
+ }
29
+ }
30
+ }