@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,75 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {Test} from "forge-std/Test.sol";
|
|
5
|
+
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
|
6
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
7
|
+
import {PolicyEngine} from "../../src/core/PolicyEngine.sol";
|
|
8
|
+
import {Policy} from "../../src/core/Policy.sol";
|
|
9
|
+
import {MockToken} from "./MockToken.sol";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @title BaseProxyTest
|
|
13
|
+
* @notice Base contract for policy-management tests that need to deploy upgradeable contracts through proxies
|
|
14
|
+
* @dev Provides helper functions to deploy common policy-management contracts with proper proxy pattern
|
|
15
|
+
*/
|
|
16
|
+
abstract contract BaseProxyTest is Test {
|
|
17
|
+
/**
|
|
18
|
+
* @notice Deploy PolicyEngine through proxy
|
|
19
|
+
* @param defaultAllow The default policy result for the engine (true = allow, false = reject)
|
|
20
|
+
* @return The deployed PolicyEngine proxy instance
|
|
21
|
+
*/
|
|
22
|
+
function _deployPolicyEngine(bool defaultAllow, address initialOwner) internal returns (PolicyEngine) {
|
|
23
|
+
PolicyEngine policyEngineImpl = new PolicyEngine();
|
|
24
|
+
bytes memory policyEngineData = abi.encodeWithSelector(PolicyEngine.initialize.selector, defaultAllow, initialOwner);
|
|
25
|
+
ERC1967Proxy policyEngineProxy = new ERC1967Proxy(address(policyEngineImpl), policyEngineData);
|
|
26
|
+
return PolicyEngine(address(policyEngineProxy));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @notice Deploy any Policy-based contract through proxy
|
|
31
|
+
* @param policyImpl The implementation contract (must inherit from Policy)
|
|
32
|
+
* @param policyEngine The address of the policy engine contract
|
|
33
|
+
* @param owner The address of the policy owner
|
|
34
|
+
* @param parameters ABI-encoded parameters for policy initialization
|
|
35
|
+
* @return The deployed policy proxy address
|
|
36
|
+
*/
|
|
37
|
+
function _deployPolicy(
|
|
38
|
+
address policyImpl,
|
|
39
|
+
address policyEngine,
|
|
40
|
+
address owner,
|
|
41
|
+
bytes memory parameters
|
|
42
|
+
)
|
|
43
|
+
internal
|
|
44
|
+
returns (address)
|
|
45
|
+
{
|
|
46
|
+
bytes memory policyData = abi.encodeWithSelector(Policy.initialize.selector, policyEngine, owner, parameters);
|
|
47
|
+
ERC1967Proxy policyProxy = new ERC1967Proxy(policyImpl, policyData);
|
|
48
|
+
return address(policyProxy);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @notice Deploy MockToken through proxy
|
|
53
|
+
* @param policyEngine The address of the policy engine contract
|
|
54
|
+
* @return The deployed MockToken proxy address
|
|
55
|
+
*/
|
|
56
|
+
function _deployMockToken(address policyEngine) internal returns (address) {
|
|
57
|
+
// Import and create MockToken implementation
|
|
58
|
+
MockToken mockTokenImpl = new MockToken();
|
|
59
|
+
bytes memory mockTokenData = abi.encodeWithSelector(MockToken.initialize.selector, policyEngine);
|
|
60
|
+
ERC1967Proxy mockTokenProxy = new ERC1967Proxy(address(mockTokenImpl), mockTokenData);
|
|
61
|
+
return address(mockTokenProxy);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _encodeRejectedRevert(
|
|
65
|
+
bytes4 selector,
|
|
66
|
+
address policy,
|
|
67
|
+
string memory reason
|
|
68
|
+
)
|
|
69
|
+
internal
|
|
70
|
+
pure
|
|
71
|
+
returns (bytes memory)
|
|
72
|
+
{
|
|
73
|
+
return abi.encodeWithSelector(IPolicyEngine.PolicyRunRejected.selector, selector, policy, reason);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IMapper} from "../../src/interfaces/IMapper.sol";
|
|
5
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
6
|
+
|
|
7
|
+
contract CustomMapper is IMapper {
|
|
8
|
+
bytes[] private s_mappedParameters;
|
|
9
|
+
|
|
10
|
+
function setMappedParameters(bytes[] memory mappedParameters) public {
|
|
11
|
+
s_mappedParameters = mappedParameters;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function map(IPolicyEngine.Parameter[] calldata /*extractedParameters*/ )
|
|
15
|
+
external
|
|
16
|
+
view
|
|
17
|
+
override
|
|
18
|
+
returns (bytes[] memory)
|
|
19
|
+
{
|
|
20
|
+
bytes[] memory results = new bytes[](s_mappedParameters.length);
|
|
21
|
+
for (uint256 i = 0; i < s_mappedParameters.length; i++) {
|
|
22
|
+
results[i] = s_mappedParameters[i];
|
|
23
|
+
}
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IExtractor} from "../../src/interfaces/IExtractor.sol";
|
|
5
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
6
|
+
|
|
7
|
+
contract DummyExtractor is IExtractor {
|
|
8
|
+
function extract(IPolicyEngine.Payload calldata) external pure override returns (IPolicyEngine.Parameter[] memory) {
|
|
9
|
+
return new IPolicyEngine.Parameter[](0);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
5
|
+
import {Policy} from "../../src/core/Policy.sol";
|
|
6
|
+
|
|
7
|
+
contract ExpectedParameterPolicy is Policy {
|
|
8
|
+
bytes[] private s_expectedParameters;
|
|
9
|
+
|
|
10
|
+
function configure(bytes calldata parameters) internal override onlyInitializing {
|
|
11
|
+
bytes[] memory expectedParameters = abi.decode(parameters, (bytes[]));
|
|
12
|
+
s_expectedParameters = expectedParameters;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function setExpectedParameters(bytes[] memory expectedParameters) public onlyOwner {
|
|
16
|
+
s_expectedParameters = expectedParameters;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function run(
|
|
20
|
+
address, /*caller*/
|
|
21
|
+
address, /*subject*/
|
|
22
|
+
bytes4, /*selector*/
|
|
23
|
+
bytes[] calldata parameters,
|
|
24
|
+
bytes calldata /*context*/
|
|
25
|
+
)
|
|
26
|
+
public
|
|
27
|
+
view
|
|
28
|
+
override
|
|
29
|
+
returns (IPolicyEngine.PolicyResult)
|
|
30
|
+
{
|
|
31
|
+
if (
|
|
32
|
+
parameters.length == s_expectedParameters.length
|
|
33
|
+
&& keccak256(abi.encode(parameters)) == keccak256(abi.encode(s_expectedParameters))
|
|
34
|
+
) {
|
|
35
|
+
return IPolicyEngine.PolicyResult.Allowed;
|
|
36
|
+
}
|
|
37
|
+
revert IPolicyEngine.PolicyRejected("parameters do not match expected values");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity ^0.8.26;
|
|
3
|
+
|
|
4
|
+
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
|
|
5
|
+
|
|
6
|
+
contract MockAggregatorV3 is AggregatorV3Interface {
|
|
7
|
+
int256 private s_price;
|
|
8
|
+
uint8 private s_decimals;
|
|
9
|
+
uint256 private s_updatedAt;
|
|
10
|
+
|
|
11
|
+
constructor(int256 _initialPrice, uint8 _decimals) {
|
|
12
|
+
s_price = _initialPrice;
|
|
13
|
+
s_decimals = _decimals;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function setPrice(int256 newPrice) external {
|
|
17
|
+
s_price = newPrice;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setUpdatedAt(uint256 newUpdatedAt) external {
|
|
21
|
+
s_updatedAt = newUpdatedAt;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function decimals() external view override returns (uint8) {
|
|
25
|
+
return s_decimals;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function latestRoundData()
|
|
29
|
+
external
|
|
30
|
+
view
|
|
31
|
+
override
|
|
32
|
+
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
|
|
33
|
+
{
|
|
34
|
+
return (0, s_price, 0, s_updatedAt, 0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function description() external pure override returns (string memory) {
|
|
38
|
+
return "Mock Aggregator";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function version() external pure override returns (uint256) {
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getRoundData(uint80 _roundId)
|
|
46
|
+
external
|
|
47
|
+
view
|
|
48
|
+
override
|
|
49
|
+
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
|
|
50
|
+
{}
|
|
51
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {PolicyProtected} from "@chainlink/policy-management/core/PolicyProtected.sol";
|
|
5
|
+
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
6
|
+
|
|
7
|
+
contract MockToken is Initializable, PolicyProtected {
|
|
8
|
+
mapping(address account => uint256 balance) public s_balances;
|
|
9
|
+
uint256 public totalSupply = 0;
|
|
10
|
+
bool public paused;
|
|
11
|
+
|
|
12
|
+
error Paused();
|
|
13
|
+
|
|
14
|
+
modifier whenNotPaused() {
|
|
15
|
+
if (paused) {
|
|
16
|
+
revert Paused();
|
|
17
|
+
}
|
|
18
|
+
_;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function initialize(address policyEngine) external initializer {
|
|
22
|
+
__PolicyProtected_init(msg.sender, policyEngine);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function transfer(address to, uint256 amount) external whenNotPaused runPolicy {
|
|
26
|
+
s_balances[to] += amount;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function transferWithContext(
|
|
30
|
+
address to,
|
|
31
|
+
uint256 amount,
|
|
32
|
+
bytes calldata context
|
|
33
|
+
)
|
|
34
|
+
external
|
|
35
|
+
whenNotPaused
|
|
36
|
+
runPolicyWithContext(context)
|
|
37
|
+
{
|
|
38
|
+
s_balances[to] += amount;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function transferFrom(address, /*from*/ address to, uint256 amount) external whenNotPaused runPolicy {
|
|
42
|
+
s_balances[to] += amount;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function balanceOf(address account) external view returns (uint256) {
|
|
46
|
+
return s_balances[account];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function mint(address to, uint256 amount) external whenNotPaused runPolicy {
|
|
50
|
+
s_balances[to] += amount;
|
|
51
|
+
totalSupply += amount;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function burn(address to, uint256 amount) external whenNotPaused runPolicy {
|
|
55
|
+
s_balances[to] -= amount;
|
|
56
|
+
totalSupply -= amount;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function pause() external runPolicy {
|
|
60
|
+
paused = true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function unpause() external runPolicy {
|
|
64
|
+
paused = false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IExtractor} from "../../src/interfaces/IExtractor.sol";
|
|
5
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
6
|
+
import {MockToken} from "./MockToken.sol";
|
|
7
|
+
|
|
8
|
+
contract MockTokenExtractor is IExtractor {
|
|
9
|
+
bytes32 public constant PARAM_FROM = keccak256("from");
|
|
10
|
+
bytes32 public constant PARAM_TO = keccak256("to");
|
|
11
|
+
bytes32 public constant PARAM_AMOUNT = keccak256("amount");
|
|
12
|
+
|
|
13
|
+
function extract(IPolicyEngine.Payload calldata payload) public pure returns (IPolicyEngine.Parameter[] memory) {
|
|
14
|
+
address from = address(0);
|
|
15
|
+
address to = address(0);
|
|
16
|
+
uint256 amount = 0;
|
|
17
|
+
|
|
18
|
+
if (payload.selector == MockToken.transfer.selector || payload.selector == MockToken.transferWithContext.selector) {
|
|
19
|
+
from = payload.sender;
|
|
20
|
+
(to, amount) = abi.decode(payload.data, (address, uint256));
|
|
21
|
+
} else if (payload.selector == MockToken.transferFrom.selector) {
|
|
22
|
+
(from, to, amount) = abi.decode(payload.data, (address, address, uint256));
|
|
23
|
+
} else {
|
|
24
|
+
revert IPolicyEngine.UnsupportedSelector(payload.selector);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
IPolicyEngine.Parameter[] memory result = new IPolicyEngine.Parameter[](3);
|
|
28
|
+
result[0] = IPolicyEngine.Parameter(PARAM_FROM, abi.encode(from));
|
|
29
|
+
result[1] = IPolicyEngine.Parameter(PARAM_TO, abi.encode(to));
|
|
30
|
+
result[2] = IPolicyEngine.Parameter(PARAM_AMOUNT, abi.encode(amount));
|
|
31
|
+
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
5
|
+
import {Policy} from "../../src/core/Policy.sol";
|
|
6
|
+
|
|
7
|
+
contract PolicyAlwaysAllowed is Policy {
|
|
8
|
+
uint8 private s_policyNumber;
|
|
9
|
+
|
|
10
|
+
event PolicyAllowedExecuted(uint256 value);
|
|
11
|
+
|
|
12
|
+
function configure(bytes calldata parameters) internal override onlyInitializing {
|
|
13
|
+
uint8 policyNumber = abi.decode(parameters, (uint8));
|
|
14
|
+
s_policyNumber = policyNumber;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getPolicyNumber() public view returns (uint8) {
|
|
18
|
+
return s_policyNumber;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function run(
|
|
22
|
+
address,
|
|
23
|
+
address,
|
|
24
|
+
bytes4,
|
|
25
|
+
bytes[] calldata,
|
|
26
|
+
bytes calldata
|
|
27
|
+
)
|
|
28
|
+
public
|
|
29
|
+
pure
|
|
30
|
+
override
|
|
31
|
+
returns (IPolicyEngine.PolicyResult)
|
|
32
|
+
{
|
|
33
|
+
return IPolicyEngine.PolicyResult.Allowed;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function postRun(address, address, bytes4, bytes[] calldata, bytes calldata) public virtual override {
|
|
37
|
+
emit PolicyAllowedExecuted(s_policyNumber);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
contract PolicyAlwaysAllowedWithPostRunError is PolicyAlwaysAllowed {
|
|
42
|
+
function postRun(address, address, bytes4, bytes[] calldata, bytes calldata) public pure override {
|
|
43
|
+
revert("Post run error");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
|
|
3
|
+
pragma solidity 0.8.26;
|
|
4
|
+
|
|
5
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
6
|
+
import {Policy} from "../../src/core/Policy.sol";
|
|
7
|
+
|
|
8
|
+
contract PolicyAlwaysContinue is Policy {
|
|
9
|
+
function run(
|
|
10
|
+
address,
|
|
11
|
+
address,
|
|
12
|
+
bytes4,
|
|
13
|
+
bytes[] calldata,
|
|
14
|
+
bytes calldata
|
|
15
|
+
)
|
|
16
|
+
public
|
|
17
|
+
pure
|
|
18
|
+
override
|
|
19
|
+
returns (IPolicyEngine.PolicyResult)
|
|
20
|
+
{
|
|
21
|
+
return IPolicyEngine.PolicyResult.Continue;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
|
|
3
|
+
pragma solidity 0.8.26;
|
|
4
|
+
|
|
5
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
6
|
+
import {Policy} from "../../src/core/Policy.sol";
|
|
7
|
+
|
|
8
|
+
contract PolicyAlwaysRejected is Policy {
|
|
9
|
+
function run(
|
|
10
|
+
address,
|
|
11
|
+
address,
|
|
12
|
+
bytes4,
|
|
13
|
+
bytes[] calldata,
|
|
14
|
+
bytes calldata
|
|
15
|
+
)
|
|
16
|
+
public
|
|
17
|
+
pure
|
|
18
|
+
override
|
|
19
|
+
returns (IPolicyEngine.PolicyResult)
|
|
20
|
+
{
|
|
21
|
+
revert IPolicyEngine.PolicyRejected("test policy always rejects");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IPolicyEngine} from "../../src/interfaces/IPolicyEngine.sol";
|
|
5
|
+
import {Policy} from "../../src/core/Policy.sol";
|
|
6
|
+
|
|
7
|
+
contract PolicyFailingRun is Policy {
|
|
8
|
+
function run(
|
|
9
|
+
address,
|
|
10
|
+
address,
|
|
11
|
+
bytes4,
|
|
12
|
+
bytes[] calldata,
|
|
13
|
+
bytes calldata
|
|
14
|
+
)
|
|
15
|
+
public
|
|
16
|
+
pure
|
|
17
|
+
override
|
|
18
|
+
returns (IPolicyEngine.PolicyResult)
|
|
19
|
+
{
|
|
20
|
+
revert("Run error");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {IPolicyEngine, PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
5
|
+
import {ERC20TransferExtractor} from "@chainlink/policy-management/extractors/ERC20TransferExtractor.sol";
|
|
6
|
+
import {AllowPolicy} from "@chainlink/policy-management/policies/AllowPolicy.sol";
|
|
7
|
+
import {MockToken} from "../helpers/MockToken.sol";
|
|
8
|
+
import {ERC3643MintBurnExtractor} from "@chainlink/policy-management/extractors/ERC3643MintBurnExtractor.sol";
|
|
9
|
+
import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
|
|
10
|
+
|
|
11
|
+
contract AllowPolicyTest is BaseProxyTest {
|
|
12
|
+
PolicyEngine public policyEngine;
|
|
13
|
+
MockToken public token;
|
|
14
|
+
AllowPolicy public allowPolicy;
|
|
15
|
+
address public deployer;
|
|
16
|
+
address public account;
|
|
17
|
+
address public recipient;
|
|
18
|
+
|
|
19
|
+
function setUp() public {
|
|
20
|
+
deployer = makeAddr("deployer");
|
|
21
|
+
account = makeAddr("account");
|
|
22
|
+
recipient = makeAddr("recipient");
|
|
23
|
+
|
|
24
|
+
vm.startPrank(deployer, deployer);
|
|
25
|
+
|
|
26
|
+
policyEngine = _deployPolicyEngine(true, deployer);
|
|
27
|
+
|
|
28
|
+
AllowPolicy allowPolicyImpl = new AllowPolicy();
|
|
29
|
+
allowPolicy = AllowPolicy(_deployPolicy(address(allowPolicyImpl), address(policyEngine), deployer, ""));
|
|
30
|
+
// add account by default
|
|
31
|
+
allowPolicy.allowAddress(account);
|
|
32
|
+
|
|
33
|
+
token = MockToken(_deployMockToken(address(policyEngine)));
|
|
34
|
+
|
|
35
|
+
// set up the allowPolicy to check the recipient and origin of token transfers (multiple accounts)
|
|
36
|
+
ERC20TransferExtractor transferExtractor = new ERC20TransferExtractor();
|
|
37
|
+
bytes32[] memory transferPolicyParams = new bytes32[](2);
|
|
38
|
+
transferPolicyParams[0] = transferExtractor.PARAM_TO();
|
|
39
|
+
transferPolicyParams[1] = transferExtractor.PARAM_FROM();
|
|
40
|
+
policyEngine.setExtractor(MockToken.transfer.selector, address(transferExtractor));
|
|
41
|
+
policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(allowPolicy), transferPolicyParams);
|
|
42
|
+
// set up the allowPolicy to check the mint account (single account)
|
|
43
|
+
ERC3643MintBurnExtractor mintBurnExtractor = new ERC3643MintBurnExtractor();
|
|
44
|
+
bytes32[] memory mintPolicyParams = new bytes32[](1);
|
|
45
|
+
mintPolicyParams[0] = mintBurnExtractor.PARAM_ACCOUNT();
|
|
46
|
+
policyEngine.setExtractor(MockToken.mint.selector, address(mintBurnExtractor));
|
|
47
|
+
policyEngine.addPolicy(address(token), MockToken.mint.selector, address(allowPolicy), mintPolicyParams);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function test_allowAddress_succeeds() public {
|
|
51
|
+
vm.startPrank(deployer, deployer);
|
|
52
|
+
|
|
53
|
+
// Expect AddressAllowed event to be emitted with correct parameters
|
|
54
|
+
vm.expectEmit(true, true, true, true);
|
|
55
|
+
emit AllowPolicy.AddressAllowed(recipient);
|
|
56
|
+
|
|
57
|
+
// add the address to the allow list
|
|
58
|
+
allowPolicy.allowAddress(recipient);
|
|
59
|
+
vm.assertEq(allowPolicy.addressAllowed(recipient), true);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function test_allowAddress_alreadyInList_fails() public {
|
|
63
|
+
vm.startPrank(deployer, deployer);
|
|
64
|
+
|
|
65
|
+
// add the address to the allow list (setup and sanity check)
|
|
66
|
+
allowPolicy.allowAddress(recipient);
|
|
67
|
+
vm.assertEq(allowPolicy.addressAllowed(recipient), true);
|
|
68
|
+
|
|
69
|
+
// add the address to the allow list again (reverts)
|
|
70
|
+
vm.expectRevert("Account already in allow list");
|
|
71
|
+
allowPolicy.allowAddress(recipient);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function test_disallowAddress_succeeds() public {
|
|
75
|
+
vm.startPrank(deployer, deployer);
|
|
76
|
+
|
|
77
|
+
// add the address to the allow list (setup and sanity check)
|
|
78
|
+
allowPolicy.allowAddress(recipient);
|
|
79
|
+
vm.assertEq(allowPolicy.addressAllowed(recipient), true);
|
|
80
|
+
|
|
81
|
+
// Expect AddressDisallowed event to be emitted with correct parameters
|
|
82
|
+
vm.expectEmit(true, true, true, true);
|
|
83
|
+
emit AllowPolicy.AddressDisallowed(recipient);
|
|
84
|
+
|
|
85
|
+
// remove the address from the allow list
|
|
86
|
+
allowPolicy.disallowAddress(recipient);
|
|
87
|
+
vm.assertEq(allowPolicy.addressAllowed(recipient), false);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function test_disallowAddress_notInList_fails() public {
|
|
91
|
+
vm.startPrank(deployer, deployer);
|
|
92
|
+
|
|
93
|
+
// remove the address from the allow list (reverts)
|
|
94
|
+
vm.expectRevert("Account not in allow list");
|
|
95
|
+
allowPolicy.disallowAddress(recipient);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function test_transfer_inList_succeeds() public {
|
|
99
|
+
vm.startPrank(deployer, deployer);
|
|
100
|
+
|
|
101
|
+
// add the recipient to the allow list
|
|
102
|
+
allowPolicy.allowAddress(recipient);
|
|
103
|
+
vm.assertEq(allowPolicy.addressAllowed(recipient), true);
|
|
104
|
+
|
|
105
|
+
vm.startPrank(account, account);
|
|
106
|
+
|
|
107
|
+
// transfer from address to recipient
|
|
108
|
+
token.transfer(recipient, 100);
|
|
109
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function test_transfer_notInList_fails() public {
|
|
113
|
+
vm.startPrank(account, account);
|
|
114
|
+
|
|
115
|
+
// transfer from address to recipient (reverts)
|
|
116
|
+
vm.expectRevert(
|
|
117
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(allowPolicy), "address is not on allow list")
|
|
118
|
+
);
|
|
119
|
+
token.transfer(recipient, 100);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function test_transfer_removedFromList_fails() public {
|
|
123
|
+
// add the address to the allow list (setup)
|
|
124
|
+
vm.startPrank(deployer, deployer);
|
|
125
|
+
allowPolicy.allowAddress(recipient);
|
|
126
|
+
|
|
127
|
+
// transfer from address to recipient (sanity check)
|
|
128
|
+
vm.startPrank(account, account);
|
|
129
|
+
token.transfer(recipient, 100);
|
|
130
|
+
vm.assertEq(token.balanceOf(recipient), 100);
|
|
131
|
+
|
|
132
|
+
// remove from the allow list
|
|
133
|
+
vm.startPrank(deployer, deployer);
|
|
134
|
+
allowPolicy.disallowAddress(recipient);
|
|
135
|
+
|
|
136
|
+
// transfer from address to recipient (should revert after removal)
|
|
137
|
+
vm.startPrank(account, account);
|
|
138
|
+
vm.expectRevert(
|
|
139
|
+
_encodeRejectedRevert(MockToken.transfer.selector, address(allowPolicy), "address is not on allow list")
|
|
140
|
+
);
|
|
141
|
+
token.transfer(recipient, 100);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function test_mint_inList_success() public {
|
|
145
|
+
vm.startPrank(deployer, deployer);
|
|
146
|
+
// account is allowed in set up
|
|
147
|
+
token.mint(account, 100);
|
|
148
|
+
vm.assertEq(token.balanceOf(account), 100);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function test_mint_notInList_failure() public {
|
|
152
|
+
vm.startPrank(deployer, deployer);
|
|
153
|
+
vm.expectRevert(
|
|
154
|
+
_encodeRejectedRevert(MockToken.mint.selector, address(allowPolicy), "address is not on allow list")
|
|
155
|
+
);
|
|
156
|
+
token.mint(recipient, 20);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function test_misconfiguration_failure() public {
|
|
160
|
+
vm.startPrank(deployer);
|
|
161
|
+
// misconfigure the allowPolicy to check burn operations (no accounts)
|
|
162
|
+
ERC3643MintBurnExtractor mintBurnExtractor = new ERC3643MintBurnExtractor();
|
|
163
|
+
policyEngine.setExtractor(MockToken.burn.selector, address(mintBurnExtractor));
|
|
164
|
+
policyEngine.addPolicy(address(token), MockToken.burn.selector, address(allowPolicy), new bytes32[](0));
|
|
165
|
+
|
|
166
|
+
bytes memory error = abi.encodeWithSignature("Error(string)", "expected at least 1 parameter");
|
|
167
|
+
vm.expectRevert(
|
|
168
|
+
abi.encodeWithSelector(
|
|
169
|
+
IPolicyEngine.PolicyRunError.selector, MockToken.burn.selector, address(allowPolicy), error
|
|
170
|
+
)
|
|
171
|
+
);
|
|
172
|
+
token.burn(account, 100);
|
|
173
|
+
}
|
|
174
|
+
}
|