@chainlink/ace 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.foundry-version +1 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/workflows/auto-release-version.yml +107 -0
- package/.github/workflows/create-version-pr.yml +95 -0
- package/.github/workflows/forge-docs.yml +90 -0
- package/.github/workflows/forge-test.yml +59 -0
- package/.solhint-test.json +18 -0
- package/.solhint.json +16 -0
- package/.solhintignore +3 -0
- package/.solhintignore-test +2 -0
- package/Glossary.md +141 -0
- package/LICENSE +59 -0
- package/README.md +218 -0
- package/assets/chainlink-logo.svg +21 -0
- package/chainlink-ace-License-grants +2 -0
- package/foundry.toml +33 -0
- package/getting_started/GETTING_STARTED.md +477 -0
- package/getting_started/MyVault.sol +48 -0
- package/getting_started/advanced/.env.example +36 -0
- package/getting_started/advanced/GETTING_STARTED_ADVANCED.md +431 -0
- package/getting_started/advanced/SanctionsList.sol +25 -0
- package/getting_started/advanced/SanctionsPolicy.sol +58 -0
- package/package.json +41 -0
- package/packages/cross-chain-identity/README.md +148 -0
- package/packages/cross-chain-identity/docs/API_GUIDE.md +120 -0
- package/packages/cross-chain-identity/docs/API_REFERENCE.md +271 -0
- package/packages/cross-chain-identity/docs/CONCEPTS.md +253 -0
- package/packages/cross-chain-identity/docs/CREDENTIAL_FLOW.md +195 -0
- package/packages/cross-chain-identity/docs/SECURITY.md +70 -0
- package/packages/cross-chain-identity/src/CredentialRegistry.sol +245 -0
- package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidator.sol +339 -0
- package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidatorPolicy.sol +71 -0
- package/packages/cross-chain-identity/src/IdentityRegistry.sol +123 -0
- package/packages/cross-chain-identity/src/TrustedIssuerRegistry.sol +140 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialDataValidator.sol +30 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialRegistry.sol +170 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialRequirements.sol +192 -0
- package/packages/cross-chain-identity/src/interfaces/ICredentialValidator.sol +37 -0
- package/packages/cross-chain-identity/src/interfaces/IIdentityRegistry.sol +85 -0
- package/packages/cross-chain-identity/src/interfaces/IIdentityValidator.sol +18 -0
- package/packages/cross-chain-identity/src/interfaces/ITrustedIssuerRegistry.sol +61 -0
- package/packages/cross-chain-identity/test/CredentialRegistry.t.sol +220 -0
- package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidator.t.sol +554 -0
- package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidatorPolicy.t.sol +114 -0
- package/packages/cross-chain-identity/test/IdentityRegistry.t.sol +106 -0
- package/packages/cross-chain-identity/test/IdentityValidator.t.sol +969 -0
- package/packages/cross-chain-identity/test/TrustedIssuerRegistry.t.sol +123 -0
- package/packages/cross-chain-identity/test/helpers/BaseProxyTest.sol +112 -0
- package/packages/cross-chain-identity/test/helpers/MockCredentialDataValidator.sol +26 -0
- package/packages/cross-chain-identity/test/helpers/MockCredentialRegistryReverting.sol +131 -0
- package/packages/policy-management/README.md +197 -0
- package/packages/policy-management/docs/API_GUIDE.md +290 -0
- package/packages/policy-management/docs/API_REFERENCE.md +173 -0
- package/packages/policy-management/docs/CONCEPTS.md +156 -0
- package/packages/policy-management/docs/CUSTOM_POLICIES_TUTORIAL.md +195 -0
- package/packages/policy-management/docs/POLICY_ORDERING_GUIDE.md +91 -0
- package/packages/policy-management/docs/SECURITY.md +57 -0
- package/packages/policy-management/src/core/Policy.sol +124 -0
- package/packages/policy-management/src/core/PolicyEngine.sol +382 -0
- package/packages/policy-management/src/core/PolicyFactory.sol +92 -0
- package/packages/policy-management/src/core/PolicyProtected.sol +126 -0
- package/packages/policy-management/src/extractors/ComplianceTokenForceTransferExtractor.sol +57 -0
- package/packages/policy-management/src/extractors/ComplianceTokenFreezeUnfreezeExtractor.sol +54 -0
- package/packages/policy-management/src/extractors/ComplianceTokenMintBurnExtractor.sol +61 -0
- package/packages/policy-management/src/extractors/ERC20ApproveExtractor.sol +57 -0
- package/packages/policy-management/src/extractors/ERC20TransferExtractor.sol +62 -0
- package/packages/policy-management/src/extractors/ERC3643ForcedTransferExtractor.sol +56 -0
- package/packages/policy-management/src/extractors/ERC3643FreezeUnfreezeExtractor.sol +55 -0
- package/packages/policy-management/src/extractors/ERC3643MintBurnExtractor.sol +51 -0
- package/packages/policy-management/src/extractors/ERC3643SetAddressFrozenExtractor.sol +51 -0
- package/packages/policy-management/src/interfaces/IExtractor.sol +17 -0
- package/packages/policy-management/src/interfaces/IMapper.sol +17 -0
- package/packages/policy-management/src/interfaces/IPolicy.sol +61 -0
- package/packages/policy-management/src/interfaces/IPolicyEngine.sol +264 -0
- package/packages/policy-management/src/interfaces/IPolicyProtected.sol +48 -0
- package/packages/policy-management/src/policies/AllowPolicy.sol +104 -0
- package/packages/policy-management/src/policies/BypassPolicy.sol +90 -0
- package/packages/policy-management/src/policies/IntervalPolicy.sol +223 -0
- package/packages/policy-management/src/policies/MaxPolicy.sol +73 -0
- package/packages/policy-management/src/policies/OnlyAuthorizedSenderPolicy.sol +84 -0
- package/packages/policy-management/src/policies/OnlyOwnerPolicy.sol +35 -0
- package/packages/policy-management/src/policies/PausePolicy.sol +82 -0
- package/packages/policy-management/src/policies/README.md +632 -0
- package/packages/policy-management/src/policies/RejectPolicy.sol +89 -0
- package/packages/policy-management/src/policies/RoleBasedAccessControlPolicy.sol +162 -0
- package/packages/policy-management/src/policies/SecureMintPolicy.sol +271 -0
- package/packages/policy-management/src/policies/VolumePolicy.sol +133 -0
- package/packages/policy-management/src/policies/VolumeRatePolicy.sol +192 -0
- package/packages/policy-management/test/PolicyEngine.t.sol +368 -0
- package/packages/policy-management/test/PolicyFactory.t.sol +114 -0
- package/packages/policy-management/test/PolicyProtectedToken.t.sol +75 -0
- package/packages/policy-management/test/extractors/ComplianceTokenForceTransferExtractor.t.sol +59 -0
- package/packages/policy-management/test/extractors/ComplianceTokenFreezeUnfreezeExtractor.t.sol +74 -0
- package/packages/policy-management/test/extractors/ComplianceTokenMintBurnExtractor.t.sol +92 -0
- package/packages/policy-management/test/extractors/ERC20ApproveExtractor.t.sol +58 -0
- package/packages/policy-management/test/extractors/ERC3643ForcedTransferExtractor.t.sol +59 -0
- package/packages/policy-management/test/extractors/ERC3643FreezeUnfreezeExtractor.t.sol +74 -0
- package/packages/policy-management/test/extractors/ERC3643MintBurnExtractor.t.sol +73 -0
- package/packages/policy-management/test/extractors/ERC3643SetAddressFrozenExtractor.t.sol +56 -0
- package/packages/policy-management/test/helpers/BaseProxyTest.sol +75 -0
- package/packages/policy-management/test/helpers/CustomMapper.sol +26 -0
- package/packages/policy-management/test/helpers/DummyExtractor.sol +11 -0
- package/packages/policy-management/test/helpers/ExpectedParameterPolicy.sol +39 -0
- package/packages/policy-management/test/helpers/MockAggregatorV3.sol +51 -0
- package/packages/policy-management/test/helpers/MockToken.sol +66 -0
- package/packages/policy-management/test/helpers/MockTokenExtractor.sol +34 -0
- package/packages/policy-management/test/helpers/PolicyAlwaysAllowed.sol +45 -0
- package/packages/policy-management/test/helpers/PolicyAlwaysContinue.sol +23 -0
- package/packages/policy-management/test/helpers/PolicyAlwaysRejected.sol +23 -0
- package/packages/policy-management/test/helpers/PolicyFailingRun.sol +22 -0
- package/packages/policy-management/test/policies/AllowPolicy.t.sol +174 -0
- package/packages/policy-management/test/policies/BypassPolicy.t.sol +159 -0
- package/packages/policy-management/test/policies/IntervalPolicy.t.sol +307 -0
- package/packages/policy-management/test/policies/MaxPolicy.t.sol +54 -0
- package/packages/policy-management/test/policies/OnlyAuthorizedSenderPolicy.t.sol +95 -0
- package/packages/policy-management/test/policies/OnlyOwnerPolicy.t.sol +47 -0
- package/packages/policy-management/test/policies/PausePolicy.t.sol +75 -0
- package/packages/policy-management/test/policies/RejectPolicy.t.sol +182 -0
- package/packages/policy-management/test/policies/RoleBasedAccessControlPolicy.t.sol +223 -0
- package/packages/policy-management/test/policies/SecureMintPolicy.t.sol +442 -0
- package/packages/policy-management/test/policies/VolumePolicy.t.sol +158 -0
- package/packages/policy-management/test/policies/VolumeRatePolicy.t.sol +165 -0
- package/packages/tokens/erc-20/src/ComplianceTokenERC20.sol +345 -0
- package/packages/tokens/erc-20/src/ComplianceTokenStoreERC20.sol +29 -0
- package/packages/tokens/erc-20/test/ComplianceTokenERC20.t.sol +556 -0
- package/packages/tokens/erc-20/test/helpers/BaseProxyTest.sol +75 -0
- package/packages/tokens/erc-3643/README.md +24 -0
- package/packages/tokens/erc-3643/src/ComplianceTokenERC3643.sol +564 -0
- package/packages/tokens/erc-3643/src/ComplianceTokenStoreERC3643.sol +30 -0
- package/packages/tokens/erc-3643/test/ComplianceTokenERC3643.t.sol +815 -0
- package/packages/tokens/erc-3643/test/helpers/BaseProxyTest.sol +76 -0
- package/packages/tokens/erc-3643/test/helpers/ExpectedContextPolicy.sol +32 -0
- package/packages/vendor/erc-3643/compliance/modular/IModularCompliance.sol +220 -0
- package/packages/vendor/erc-3643/registry/interface/IClaimTopicsRegistry.sol +101 -0
- package/packages/vendor/erc-3643/registry/interface/IIdentityRegistry.sol +251 -0
- package/packages/vendor/erc-3643/registry/interface/IIdentityRegistryStorage.sol +191 -0
- package/packages/vendor/erc-3643/registry/interface/ITrustedIssuersRegistry.sol +161 -0
- package/packages/vendor/erc-3643/token/IToken.sol +457 -0
- package/packages/vendor/onchain-id/interface/IClaimIssuer.sol +53 -0
- package/packages/vendor/onchain-id/interface/IERC734.sol +110 -0
- package/packages/vendor/onchain-id/interface/IERC735.sol +105 -0
- package/packages/vendor/onchain-id/interface/IIdentity.sol +26 -0
- package/packages/vendor/onchain-id/interface/IImplementationAuthority.sol +21 -0
- package/remappings.txt +6 -0
- package/script/DeployComplianceTokenERC20.s.sol +191 -0
- package/script/DeployComplianceTokenERC3643.s.sol +208 -0
- package/script/DeploySimpleComplianceToken.s.sol +38 -0
- package/script/getting_started/DeployGettingStarted.s.sol +74 -0
- package/script/getting_started/advanced/DeployAdvancedGettingStarted.s.sol +332 -0
- package/script/getting_started/advanced/DeploySanctionsList.s.sol +26 -0
|
@@ -0,0 +1,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
|
+
}
|