@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,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
+ }