@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,123 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {ITrustedIssuerRegistry} from "../src/interfaces/ITrustedIssuerRegistry.sol";
|
|
5
|
+
import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
|
|
6
|
+
import {TrustedIssuerRegistry} from "../src/TrustedIssuerRegistry.sol";
|
|
7
|
+
import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
8
|
+
import {BaseProxyTest} from "./helpers/BaseProxyTest.sol";
|
|
9
|
+
|
|
10
|
+
contract TrustedIssuerRegistryTest is BaseProxyTest {
|
|
11
|
+
PolicyEngine internal s_policyEngine;
|
|
12
|
+
TrustedIssuerRegistry internal s_trustedIssuerRegistry;
|
|
13
|
+
address internal s_owner;
|
|
14
|
+
|
|
15
|
+
function setUp() public {
|
|
16
|
+
s_owner = makeAddr("owner");
|
|
17
|
+
|
|
18
|
+
vm.startPrank(s_owner);
|
|
19
|
+
s_policyEngine = _deployPolicyEngine(true, address(this));
|
|
20
|
+
s_trustedIssuerRegistry = _deployTrustedIssuerRegistry(address(s_policyEngine));
|
|
21
|
+
vm.stopPrank();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// -------------------------
|
|
25
|
+
// Add trusted issuer
|
|
26
|
+
// -------------------------
|
|
27
|
+
|
|
28
|
+
function test_addTrustedIssuer_success() public {
|
|
29
|
+
string memory issuerId = "did:example:issuer1";
|
|
30
|
+
bytes32 didHash = keccak256(abi.encodePacked(issuerId));
|
|
31
|
+
|
|
32
|
+
s_trustedIssuerRegistry.addTrustedIssuer(issuerId, "");
|
|
33
|
+
|
|
34
|
+
bool isTrusted = s_trustedIssuerRegistry.isTrustedIssuer(issuerId);
|
|
35
|
+
assertTrue(isTrusted);
|
|
36
|
+
|
|
37
|
+
bytes32[] memory issuers = s_trustedIssuerRegistry.getTrustedIssuers();
|
|
38
|
+
assertEq(issuers.length, 1);
|
|
39
|
+
assertEq(issuers[0], didHash);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function test_addTrustedIssuer_emptyDid_failure() public {
|
|
43
|
+
vm.expectRevert("issuerId cannot be empty");
|
|
44
|
+
s_trustedIssuerRegistry.addTrustedIssuer("", "");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function test_addTrustedIssuer_duplicate_failure() public {
|
|
48
|
+
string memory issuerId = "did:example:issuer1";
|
|
49
|
+
|
|
50
|
+
s_trustedIssuerRegistry.addTrustedIssuer(issuerId, "");
|
|
51
|
+
|
|
52
|
+
vm.expectRevert("Issuer already trusted");
|
|
53
|
+
s_trustedIssuerRegistry.addTrustedIssuer(issuerId, "");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// -------------------------
|
|
57
|
+
// Remove trusted issuer
|
|
58
|
+
// -------------------------
|
|
59
|
+
|
|
60
|
+
function test_removeTrustedIssuer_success() public {
|
|
61
|
+
string memory issuerId = "did:example:issuer1";
|
|
62
|
+
|
|
63
|
+
s_trustedIssuerRegistry.addTrustedIssuer(issuerId, "");
|
|
64
|
+
assertTrue(s_trustedIssuerRegistry.isTrustedIssuer(issuerId));
|
|
65
|
+
|
|
66
|
+
s_trustedIssuerRegistry.removeTrustedIssuer(issuerId, "");
|
|
67
|
+
|
|
68
|
+
assertFalse(s_trustedIssuerRegistry.isTrustedIssuer(issuerId));
|
|
69
|
+
|
|
70
|
+
bytes32[] memory issuers = s_trustedIssuerRegistry.getTrustedIssuers();
|
|
71
|
+
assertEq(issuers.length, 0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function test_removeTrustedIssuer_notTrusted_failure() public {
|
|
75
|
+
string memory issuerId = "did:example:nonexistent";
|
|
76
|
+
|
|
77
|
+
vm.expectRevert("Issuer not trusted");
|
|
78
|
+
s_trustedIssuerRegistry.removeTrustedIssuer(issuerId, "");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// -------------------------
|
|
82
|
+
// List management behavior
|
|
83
|
+
// -------------------------
|
|
84
|
+
|
|
85
|
+
function test_multipleIssuers_addAndRemove_listUpdatedCorrectly() public {
|
|
86
|
+
string memory did1 = "did:example:issuer1";
|
|
87
|
+
string memory did2 = "did:example:issuer2";
|
|
88
|
+
string memory did3 = "did:example:issuer3";
|
|
89
|
+
|
|
90
|
+
s_trustedIssuerRegistry.addTrustedIssuer(did1, "");
|
|
91
|
+
s_trustedIssuerRegistry.addTrustedIssuer(did2, "");
|
|
92
|
+
s_trustedIssuerRegistry.addTrustedIssuer(did3, "");
|
|
93
|
+
|
|
94
|
+
bytes32[] memory beforeRemoval = s_trustedIssuerRegistry.getTrustedIssuers();
|
|
95
|
+
assertEq(beforeRemoval.length, 3);
|
|
96
|
+
|
|
97
|
+
s_trustedIssuerRegistry.removeTrustedIssuer(did2, "");
|
|
98
|
+
|
|
99
|
+
bytes32[] memory afterRemoval = s_trustedIssuerRegistry.getTrustedIssuers();
|
|
100
|
+
assertEq(afterRemoval.length, 2);
|
|
101
|
+
|
|
102
|
+
bytes32 hash1 = keccak256(abi.encodePacked(did1));
|
|
103
|
+
bytes32 hash3 = keccak256(abi.encodePacked(did3));
|
|
104
|
+
|
|
105
|
+
assertTrue(afterRemoval[0] == hash1 || afterRemoval[1] == hash1);
|
|
106
|
+
assertTrue(afterRemoval[0] == hash3 || afterRemoval[1] == hash3);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// -------------------------
|
|
110
|
+
// View functions
|
|
111
|
+
// -------------------------
|
|
112
|
+
|
|
113
|
+
function test_isTrustedIssuer_returnsFalseWhenNotAdded() public {
|
|
114
|
+
string memory issuerId = "did:example:nonexistent";
|
|
115
|
+
bool isTrusted = s_trustedIssuerRegistry.isTrustedIssuer(issuerId);
|
|
116
|
+
assertFalse(isTrusted);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function test_getTrustedIssuers_emptyInitially() public {
|
|
120
|
+
bytes32[] memory issuers = s_trustedIssuerRegistry.getTrustedIssuers();
|
|
121
|
+
assertEq(issuers.length, 0);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
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 "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
|
|
7
|
+
import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
|
|
8
|
+
import {Policy} from "@chainlink/policy-management/core/Policy.sol";
|
|
9
|
+
import {IdentityRegistry} from "../../src/IdentityRegistry.sol";
|
|
10
|
+
import {CredentialRegistry} from "../../src/CredentialRegistry.sol";
|
|
11
|
+
import {CredentialRegistryIdentityValidator} from "../../src/CredentialRegistryIdentityValidator.sol";
|
|
12
|
+
import {CredentialRegistryIdentityValidatorPolicy} from "../../src/CredentialRegistryIdentityValidatorPolicy.sol";
|
|
13
|
+
import {ICredentialRequirements} from "../../src/interfaces/ICredentialRequirements.sol";
|
|
14
|
+
import {TrustedIssuerRegistry} from "../../src/TrustedIssuerRegistry.sol";
|
|
15
|
+
/**
|
|
16
|
+
* @title BaseProxyTest
|
|
17
|
+
* @notice Base contract for tests that need to deploy upgradeable contracts through proxies
|
|
18
|
+
* @dev Provides helper functions to deploy common contracts with proper proxy pattern
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
abstract contract BaseProxyTest is Test {
|
|
22
|
+
/**
|
|
23
|
+
* @notice Deploy PolicyEngine through proxy
|
|
24
|
+
* @param defaultAllow Whether the default policy engine rule will allow or reject the transaction
|
|
25
|
+
* @param initialOwner The address of the initial owner of the policy engine
|
|
26
|
+
* @return The deployed PolicyEngine proxy instance
|
|
27
|
+
*/
|
|
28
|
+
function _deployPolicyEngine(bool defaultAllow, address initialOwner) internal returns (PolicyEngine) {
|
|
29
|
+
PolicyEngine policyEngineImpl = new PolicyEngine();
|
|
30
|
+
bytes memory policyEngineData = abi.encodeWithSelector(PolicyEngine.initialize.selector, defaultAllow, initialOwner);
|
|
31
|
+
ERC1967Proxy policyEngineProxy = new ERC1967Proxy(address(policyEngineImpl), policyEngineData);
|
|
32
|
+
return PolicyEngine(address(policyEngineProxy));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @notice Deploy IdentityRegistry through proxy
|
|
37
|
+
* @param policyEngine The address of the policy engine contract
|
|
38
|
+
* @return The deployed IdentityRegistry proxy instance
|
|
39
|
+
*/
|
|
40
|
+
function _deployIdentityRegistry(address policyEngine) internal returns (IdentityRegistry) {
|
|
41
|
+
IdentityRegistry identityRegistryImpl = new IdentityRegistry();
|
|
42
|
+
bytes memory identityRegistryData =
|
|
43
|
+
abi.encodeWithSelector(IdentityRegistry.initialize.selector, policyEngine, address(this));
|
|
44
|
+
ERC1967Proxy identityRegistryProxy = new ERC1967Proxy(address(identityRegistryImpl), identityRegistryData);
|
|
45
|
+
return IdentityRegistry(address(identityRegistryProxy));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @notice Deploy CredentialRegistry through proxy
|
|
50
|
+
* @param policyEngine The address of the policy engine contract
|
|
51
|
+
* @return The deployed CredentialRegistry proxy instance
|
|
52
|
+
*/
|
|
53
|
+
function _deployCredentialRegistry(address policyEngine) internal returns (CredentialRegistry) {
|
|
54
|
+
CredentialRegistry credentialRegistryImpl = new CredentialRegistry();
|
|
55
|
+
bytes memory credentialRegistryData =
|
|
56
|
+
abi.encodeWithSelector(CredentialRegistry.initialize.selector, policyEngine, address(this));
|
|
57
|
+
ERC1967Proxy credentialRegistryProxy = new ERC1967Proxy(address(credentialRegistryImpl), credentialRegistryData);
|
|
58
|
+
return CredentialRegistry(address(credentialRegistryProxy));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function _deployTrustedIssuerRegistry(address policyEngine) internal returns (TrustedIssuerRegistry) {
|
|
62
|
+
TrustedIssuerRegistry impl = new TrustedIssuerRegistry();
|
|
63
|
+
bytes memory data = abi.encodeWithSelector(TrustedIssuerRegistry.initialize.selector, policyEngine, address(this));
|
|
64
|
+
ERC1967Proxy proxy = new ERC1967Proxy(address(impl), data);
|
|
65
|
+
return TrustedIssuerRegistry(address(proxy));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @notice Deploy IdentityValidator through proxy
|
|
70
|
+
* @param credentialSources Initial credential sources
|
|
71
|
+
* @param credentialRequirements Initial credential requirements
|
|
72
|
+
* @return The deployed IdentityValidator proxy instance
|
|
73
|
+
*/
|
|
74
|
+
function _deployCredentialRegistryIdentityValidator(
|
|
75
|
+
ICredentialRequirements.CredentialSourceInput[] memory credentialSources,
|
|
76
|
+
ICredentialRequirements.CredentialRequirementInput[] memory credentialRequirements
|
|
77
|
+
)
|
|
78
|
+
internal
|
|
79
|
+
returns (CredentialRegistryIdentityValidator)
|
|
80
|
+
{
|
|
81
|
+
CredentialRegistryIdentityValidator identityValidatorImpl = new CredentialRegistryIdentityValidator();
|
|
82
|
+
bytes memory identityValidatorData = abi.encodeWithSelector(
|
|
83
|
+
CredentialRegistryIdentityValidator.initialize.selector, credentialSources, credentialRequirements
|
|
84
|
+
);
|
|
85
|
+
ERC1967Proxy identityValidatorProxy = new ERC1967Proxy(address(identityValidatorImpl), identityValidatorData);
|
|
86
|
+
return CredentialRegistryIdentityValidator(address(identityValidatorProxy));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @notice Deploy CredentialRegistryIdentityValidatorPolicy through proxy
|
|
91
|
+
* @param policyEngine The address of the policy engine contract
|
|
92
|
+
* @param owner The address of the policy owner
|
|
93
|
+
* @param parameters ABI-encoded parameters for policy initialization
|
|
94
|
+
* @return The deployed CredentialRegistryIdentityValidatorPolicy proxy instance
|
|
95
|
+
*/
|
|
96
|
+
function _deployCredentialRegistryCredentialRegistryIdentityValidatorPolicy(
|
|
97
|
+
address policyEngine,
|
|
98
|
+
address owner,
|
|
99
|
+
bytes memory parameters
|
|
100
|
+
)
|
|
101
|
+
internal
|
|
102
|
+
returns (CredentialRegistryIdentityValidatorPolicy)
|
|
103
|
+
{
|
|
104
|
+
CredentialRegistryIdentityValidatorPolicy identityValidatorPolicyImpl =
|
|
105
|
+
new CredentialRegistryIdentityValidatorPolicy();
|
|
106
|
+
bytes memory identityValidatorPolicyData =
|
|
107
|
+
abi.encodeWithSelector(Policy.initialize.selector, policyEngine, owner, parameters);
|
|
108
|
+
ERC1967Proxy identityValidatorPolicyProxy =
|
|
109
|
+
new ERC1967Proxy(address(identityValidatorPolicyImpl), identityValidatorPolicyData);
|
|
110
|
+
return CredentialRegistryIdentityValidatorPolicy(address(identityValidatorPolicyProxy));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {ICredentialDataValidator} from "../../src/interfaces/ICredentialDataValidator.sol";
|
|
5
|
+
|
|
6
|
+
contract MockCredentialDataValidator is ICredentialDataValidator {
|
|
7
|
+
bool private s_dataValid;
|
|
8
|
+
|
|
9
|
+
function setDataValid(bool dataValid) public {
|
|
10
|
+
s_dataValid = dataValid;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function validateCredentialData(
|
|
14
|
+
bytes32, /*ccid*/
|
|
15
|
+
address, /*account*/
|
|
16
|
+
bytes32, /*credentialTypeId*/
|
|
17
|
+
bytes calldata, /*credentialData*/
|
|
18
|
+
bytes calldata /*context*/
|
|
19
|
+
)
|
|
20
|
+
external
|
|
21
|
+
view
|
|
22
|
+
returns (bool)
|
|
23
|
+
{
|
|
24
|
+
return s_dataValid;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {ICredentialRegistry} from "../../src/interfaces/ICredentialRegistry.sol";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @title MockCredentialRegistryReverting
|
|
8
|
+
* @notice Mock credential registry that can be configured to revert on validate() calls
|
|
9
|
+
* @dev Used for testing error handling in CredentialRegistryIdentityValidator
|
|
10
|
+
*/
|
|
11
|
+
contract MockCredentialRegistryReverting is ICredentialRegistry {
|
|
12
|
+
bool private s_shouldRevert;
|
|
13
|
+
string private s_revertMessage;
|
|
14
|
+
|
|
15
|
+
function setShouldRevert(bool shouldRevert) public {
|
|
16
|
+
s_shouldRevert = shouldRevert;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function setRevertMessage(string memory message) public {
|
|
20
|
+
s_revertMessage = message;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function validate(
|
|
24
|
+
bytes32, /*ccid*/
|
|
25
|
+
bytes32, /*credentialTypeId*/
|
|
26
|
+
bytes calldata /*context*/
|
|
27
|
+
)
|
|
28
|
+
external
|
|
29
|
+
view
|
|
30
|
+
returns (bool)
|
|
31
|
+
{
|
|
32
|
+
if (s_shouldRevert) {
|
|
33
|
+
revert(s_revertMessage);
|
|
34
|
+
}
|
|
35
|
+
return false; // Default behavior when not reverting
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Minimal implementation of required interface methods
|
|
39
|
+
function registerCredential(
|
|
40
|
+
bytes32, /*ccid*/
|
|
41
|
+
bytes32, /*credentialTypeId*/
|
|
42
|
+
uint40, /*expiresAt*/
|
|
43
|
+
bytes calldata, /*credentialData*/
|
|
44
|
+
bytes calldata /*context*/
|
|
45
|
+
)
|
|
46
|
+
external
|
|
47
|
+
{
|
|
48
|
+
revert("Not implemented");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function registerCredentials(
|
|
52
|
+
bytes32, /*ccid*/
|
|
53
|
+
bytes32[] calldata, /*credentialTypeIds*/
|
|
54
|
+
uint40, /*expiresAt*/
|
|
55
|
+
bytes[] calldata, /*credentialDatas*/
|
|
56
|
+
bytes calldata /*context*/
|
|
57
|
+
)
|
|
58
|
+
external
|
|
59
|
+
{
|
|
60
|
+
revert("Not implemented");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function renewCredential(
|
|
64
|
+
bytes32, /*ccid*/
|
|
65
|
+
bytes32, /*credentialTypeId*/
|
|
66
|
+
uint40, /*expiresAt*/
|
|
67
|
+
bytes calldata /*context*/
|
|
68
|
+
)
|
|
69
|
+
external
|
|
70
|
+
{
|
|
71
|
+
revert("Not implemented");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function revokeCredential(bytes32, /*ccid*/ bytes32, /*credentialTypeId*/ bytes calldata /*context*/ ) external {
|
|
75
|
+
revert("Not implemented");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function removeCredential(bytes32, /*ccid*/ bytes32, /*credentialTypeId*/ bytes calldata /*context*/ ) external {
|
|
79
|
+
revert("Not implemented");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getCredential(
|
|
83
|
+
bytes32, /*ccid*/
|
|
84
|
+
bytes32 /*credentialTypeId*/
|
|
85
|
+
)
|
|
86
|
+
external
|
|
87
|
+
view
|
|
88
|
+
returns (ICredentialRegistry.Credential memory)
|
|
89
|
+
{
|
|
90
|
+
revert("Not implemented");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getCredentials(
|
|
94
|
+
bytes32, /*ccid*/
|
|
95
|
+
bytes32[] calldata /*credentialTypeIds*/
|
|
96
|
+
)
|
|
97
|
+
external
|
|
98
|
+
view
|
|
99
|
+
returns (ICredentialRegistry.Credential[] memory)
|
|
100
|
+
{
|
|
101
|
+
revert("Not implemented");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function getCredentialTypes(bytes32 /*ccid*/ ) external view returns (bytes32[] memory) {
|
|
105
|
+
revert("Not implemented");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function hasCredential(bytes32, /*ccid*/ bytes32 /*credentialTypeId*/ ) external view returns (bool) {
|
|
109
|
+
revert("Not implemented");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isCredentialExpired(bytes32, /*ccid*/ bytes32 /*credentialTypeId*/ ) external view returns (bool) {
|
|
113
|
+
revert("Not implemented");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function validateAll(
|
|
117
|
+
bytes32, /*ccid*/
|
|
118
|
+
bytes32[] calldata, /*credentialTypeIds*/
|
|
119
|
+
bytes calldata /*context*/
|
|
120
|
+
)
|
|
121
|
+
external
|
|
122
|
+
view
|
|
123
|
+
returns (bool)
|
|
124
|
+
{
|
|
125
|
+
revert("Not implemented");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function supportsInterface(bytes4 /*interfaceId*/ ) external pure returns (bool) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Policy Management
|
|
2
|
+
|
|
3
|
+
**A dynamic engine to create and enforce onchain rules. Update compliance logic without redeploying your core contracts.**
|
|
4
|
+
|
|
5
|
+
## Why This Matters
|
|
6
|
+
|
|
7
|
+
Hardcoding enforcement logic makes your contracts rigid and difficult to audit. With the Policy Management component, you can separate your application's business logic from its compliance rules, allowing you to adapt to new regulations or security practices on the fly.
|
|
8
|
+
|
|
9
|
+
A contract might start with simple rules, but as it evolves, more complex logic gets added directly into the function, making it brittle and hard to maintain.
|
|
10
|
+
|
|
11
|
+
```solidity
|
|
12
|
+
// ❌ Before: All rules are hard-coded, making the function complex and inflexible.
|
|
13
|
+
contract MyToken {
|
|
14
|
+
address public owner;
|
|
15
|
+
bool public paused;
|
|
16
|
+
|
|
17
|
+
function mint(uint256 amount) public {
|
|
18
|
+
require(!paused, "Contract is paused");
|
|
19
|
+
require(msg.sender == owner, "Only owner can mint");
|
|
20
|
+
// ...
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ✅ After: The function is only concerned with its core logic.
|
|
25
|
+
// All rules (pausable, owner-only, volume limits, etc.) are now separate,
|
|
26
|
+
// composable policies attached to the Policy Engine.
|
|
27
|
+
import { PolicyProtected } from "@chainlink/policy-management/core/PolicyProtected.sol";
|
|
28
|
+
|
|
29
|
+
contract MyToken is PolicyProtected {
|
|
30
|
+
function mint(uint256 amount) public runPolicy {
|
|
31
|
+
// ...
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## How It Works: An Overview
|
|
37
|
+
|
|
38
|
+
Policy Management is built on a few core components that work together to protect your contracts:
|
|
39
|
+
|
|
40
|
+
- **`PolicyProtected`**: An abstract contract you inherit from. It provides the `runPolicy` modifier that acts as the "hook" into the policy system and includes an optional, advanced **[`context`](docs/CONCEPTS.md#the-context-parameter-a-flexible-data-channel)** for passing arbitrary data like off-chain signatures.
|
|
41
|
+
- **`PolicyEngine`**: The central orchestrator. It holds the registry of all policies and executes them in the correct order for any protected function.
|
|
42
|
+
- **`Policy`**: A self-contained contract that holds a single rule. It uses a `run()` function for read-only checks and has an optional [`postRun()`](docs/CONCEPTS.md#policy-flow-diagram) function that can modify state _after_ a check has passed.
|
|
43
|
+
- **`Extractor`**: A helper contract that parses transaction data for the policies. For most common use cases, the `PolicyEngine` handles the underlying parameter mapping automatically. You can learn more about the [Extractor and Mapper pattern in our Concepts guide](docs/CONCEPTS.md#the-extractor-and-mapper-pattern).
|
|
44
|
+
|
|
45
|
+
A `Policy` contract's `run()` function can either return a result or revert to reject the transaction:
|
|
46
|
+
|
|
47
|
+
- **`revert IPolicyEngine.PolicyRejected(reason)`**: Immediately blocks the transaction with a descriptive error message. This is a final "no" that bypasses all subsequent policies and provides clear feedback about why the transaction was rejected.
|
|
48
|
+
- **`Allowed`**: Immediately approves the transaction and also bypasses all subsequent policies in the chain. This is a final "yes".
|
|
49
|
+
- **`Continue`**: The check passed, but the decision is deferred. The engine proceeds to the next policy in the chain, or applies its default result if none remain.
|
|
50
|
+
|
|
51
|
+
This diagram illustrates the primary flow: a dApp calls a protected function, and the `PolicyEngine` intercepts the call to check the relevant policies before allowing execution to proceed.
|
|
52
|
+
|
|
53
|
+
```mermaid
|
|
54
|
+
sequenceDiagram
|
|
55
|
+
participant User
|
|
56
|
+
participant PolicyProtectedContract as Policy-Protected Contract
|
|
57
|
+
participant PolicyEngine as Policy Engine
|
|
58
|
+
participant Policy1 as Policy
|
|
59
|
+
|
|
60
|
+
User->>PolicyProtectedContract: 1. Calls a protected function()
|
|
61
|
+
PolicyProtectedContract->>PolicyEngine: 2. Asks "Is this call allowed?"
|
|
62
|
+
Note over PolicyProtectedContract: The `runPolicy` modifier triggers this.
|
|
63
|
+
|
|
64
|
+
PolicyEngine->>Policy1: 3. run()
|
|
65
|
+
|
|
66
|
+
alt Policy Rejects
|
|
67
|
+
Policy1-->>PolicyEngine: 4a. revert PolicyRejected(reason)
|
|
68
|
+
Note over PolicyEngine: Skips any subsequent policies
|
|
69
|
+
PolicyEngine-->>PolicyProtectedContract: 5a. REVERT with reason
|
|
70
|
+
else Policy Allows
|
|
71
|
+
Policy1-->>PolicyEngine: 4b. Returns `Allowed`
|
|
72
|
+
Note over PolicyEngine: Skips any subsequent policies
|
|
73
|
+
PolicyEngine-->>PolicyProtectedContract: 5b. SUCCESS
|
|
74
|
+
else Policy Continues
|
|
75
|
+
Policy1-->>PolicyEngine: 4c. Returns `Continue`
|
|
76
|
+
Note over PolicyEngine: Proceeds to next policy (if any)<br/>or applies engine's default result.
|
|
77
|
+
PolicyEngine-->>PolicyProtectedContract: 5c. Allows or Reverts (default result)
|
|
78
|
+
end
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Important note**: The `PolicyEngine` executes policies **in the order they are added**. For a detailed guide on how to add, remove, and reorder policies, see the **[Policy Ordering Guide](docs/POLICY_ORDERING_GUIDE.md)**. For a more detailed breakdown of the execution flow, see the [Policy Flow Diagram in our Concepts guide](docs/CONCEPTS.md#policy-flow-diagram).
|
|
82
|
+
|
|
83
|
+
**Key Benefits**:
|
|
84
|
+
|
|
85
|
+
- **Future-Proof**: Adapt to new regulations or security needs by adding, removing, or updating policies without changing your core contracts.
|
|
86
|
+
- **Composable & Reusable**: Chain multiple policies together to create sophisticated rulesets. Reuse the same policies across different contracts and functions.
|
|
87
|
+
- **Audit Friendly**: Isolate complex compliance logic into individual policy contracts, making them easier to audit and reason about.
|
|
88
|
+
- **Ready-to-Use Library**: Leverage a suite of pre-built, audited policies for common use cases like authorization, volume limits, and more.
|
|
89
|
+
|
|
90
|
+
## How to Use
|
|
91
|
+
|
|
92
|
+
The following example shows how to protect a `pause` function so that only a designated Security Administrator can call it. This demonstrates a clear separation of roles, where one address owns the main contract but a different, specialized address is given a specific permission.
|
|
93
|
+
|
|
94
|
+
### 1. Inherit from `PolicyProtected`
|
|
95
|
+
|
|
96
|
+
First, make your contract inherit from `PolicyProtected` and add the `runPolicy` modifier to the function you want to secure.
|
|
97
|
+
|
|
98
|
+
```solidity
|
|
99
|
+
import { PolicyProtected } from "@chainlink/policy-management/core/PolicyProtected.sol";
|
|
100
|
+
|
|
101
|
+
contract MyPausableContract is PolicyProtected {
|
|
102
|
+
bool public paused;
|
|
103
|
+
|
|
104
|
+
function pause() public virtual runPolicy {
|
|
105
|
+
paused = true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 2. Deploy and Connect the Components
|
|
111
|
+
|
|
112
|
+
> **Note:** All Policy Management components must be deployed behind a proxy because they use OpenZeppelin's upgradeable contracts pattern (disabled constructors with initializers). This typically uses `ERC1967Proxy` for upgradeability, though minimal proxies (clones) may be used for immutable components. See the **[Getting Started Guide: Deployment Script](../../getting_started/GETTING_STARTED.md#the-deployment-script)** for the complete proxy deployment pattern.
|
|
113
|
+
|
|
114
|
+
Once your components are deployed, here are the key configuration steps:
|
|
115
|
+
|
|
116
|
+
```solidity
|
|
117
|
+
// 1. Authorize who can trigger the policy
|
|
118
|
+
onlyAuthorizedSenderPolicy.authorizeSender(securityAdmin);
|
|
119
|
+
|
|
120
|
+
// 2. Register the policy with the engine
|
|
121
|
+
policyEngine.addPolicy(
|
|
122
|
+
address(myContract),
|
|
123
|
+
myContract.pause.selector,
|
|
124
|
+
address(onlyAuthorizedSenderPolicy),
|
|
125
|
+
new bytes32[](0)
|
|
126
|
+
);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
These two calls establish the relationship: the `OnlyAuthorizedSenderPolicy` is now enforced on `myContract.pause()`, and only `securityAdmin` can satisfy it. The `contractOwner` cannot call it directly, demonstrating a clear and powerful separation of roles that is difficult to achieve with simple ownership patterns.
|
|
130
|
+
|
|
131
|
+
This design also makes the contract adaptable to future requirements. For instance, if a new rule dictates that the `pause` function can only be called after a majority of partners have submitted offchain approvals, you wouldn't need to change `MyPausableContract`. You could simply deploy a new `PartnerApprovalPolicy`, and add it to the policy chain for the `pause` selector in the `PolicyEngine`. The `runPolicy` modifier ensures both the original `onlyAuthorizedSenderPolicy` and the new approval policy are checked automatically, without any changes to the core contract.
|
|
132
|
+
|
|
133
|
+
## Working with Policies
|
|
134
|
+
|
|
135
|
+
The Policy Management component offers a flexible approach, allowing you to use our library of audited, pre-built policies or to create your own for custom logic.
|
|
136
|
+
|
|
137
|
+
### Use Our Library of Pre-Built Policies
|
|
138
|
+
|
|
139
|
+
This component includes a rich library of pre-built, audited policies to accelerate development. These policies cover a wide range of common compliance and access control scenarios.
|
|
140
|
+
|
|
141
|
+
- **Access Control**: `AllowPolicy`, `BypassPolicy`, `RejectPolicy`, `OnlyOwnerPolicy`, `OnlyAuthorizedSenderPolicy`, `RoleBasedAccessControlPolicy`.
|
|
142
|
+
- **Transaction Limits**: `MaxPolicy`, `VolumePolicy`, `VolumeRatePolicy`, `SecureMintPolicy`.
|
|
143
|
+
- **Time-Based Rules**: `IntervalPolicy`, `PausePolicy`.
|
|
144
|
+
|
|
145
|
+
→ **[Explore the Full List and Configuration Guides](./src/policies/README.md)**
|
|
146
|
+
|
|
147
|
+
### Build Your Own Custom Policies
|
|
148
|
+
|
|
149
|
+
The true power of the engine comes from its extensibility. You can easily write your own custom policies to enforce any onchain rule imaginable.
|
|
150
|
+
|
|
151
|
+
- **[Read the Tutorial →](docs/CUSTOM_POLICIES_TUTORIAL.md)** A step-by-step guide to building a policy from scratch.
|
|
152
|
+
- **[Get the Boilerplate →](docs/CUSTOM_POLICIES_TUTORIAL.md#boilerplate-template-for-custom-policies)** A clean, commented template to use as a starting point.
|
|
153
|
+
|
|
154
|
+
## Integration with Other Components
|
|
155
|
+
|
|
156
|
+
Policy Management is the engine that drives the functionality of the other Chainlink ACE core contracts, allowing you to create powerful, cross-component rules.
|
|
157
|
+
|
|
158
|
+
### With Cross-Chain Identity
|
|
159
|
+
|
|
160
|
+
Use identity verification as a dynamic policy condition. The `CredentialRegistryIdentityValidatorPolicy` is a powerful example that checks a user's onchain credentials before allowing an action.
|
|
161
|
+
|
|
162
|
+
```solidity
|
|
163
|
+
// In your deployment script:
|
|
164
|
+
CredentialRegistryIdentityValidatorPolicy kycPolicy = new CredentialRegistryIdentityValidatorPolicy();
|
|
165
|
+
// ... initialize kycPolicy with your identity validator ...
|
|
166
|
+
|
|
167
|
+
// Apply the KYC check to the 'transfer' function
|
|
168
|
+
policyEngine.addPolicy(
|
|
169
|
+
address(myToken),
|
|
170
|
+
myToken.transfer.selector,
|
|
171
|
+
address(kycPolicy),
|
|
172
|
+
// ... specify parameters ...
|
|
173
|
+
);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Learn more about [Cross-Chain Identity](../cross-chain-identity/README.md).
|
|
177
|
+
|
|
178
|
+
## Security Considerations
|
|
179
|
+
|
|
180
|
+
The Policy Management component is incredibly powerful, but its security depends on correct configuration and management.
|
|
181
|
+
|
|
182
|
+
- **Policy Management is Critical**: Only authorized roles MUST be able to add, remove, or reorder policies in the `PolicyEngine`. Malicious updates could disable or circumvent all compliance rules.
|
|
183
|
+
- **Policy Order Matters**: Policies are executed in the order they are added. A policy that returns `Allowed` will bypass all subsequent policies. Ensure that high-priority checks and restrictive policies are ordered first.
|
|
184
|
+
- **Trust in Policies**: A malicious or poorly written policy can introduce vulnerabilities. Only install trusted, audited policies. The `postRun` function, in particular, can modify state and must be treated with extreme caution.
|
|
185
|
+
- **External Call Risks**: Policies that make external calls (e.g., to data sources, identity registries, or oracles) can introduce risks like denial of service or gas exhaustion. Since most policy `run()` functions are `view` (read-only), traditional reentrancy attacks are not possible, but **policy administrators** must ensure that external contracts are trusted and reliable when composing policies dynamically.
|
|
186
|
+
- **Extractor/Mapper Trust**: The `PolicyEngine` relies on `Extractors` to correctly parse transaction data. If an extractor is compromised or misrepresents data, policies may make decisions based on false information, potentially leading to bypasses.
|
|
187
|
+
|
|
188
|
+
## Next Steps
|
|
189
|
+
|
|
190
|
+
- **[Core Concepts](docs/CONCEPTS.md)**: A deep dive into the architecture and design rationale.
|
|
191
|
+
- **[Creating Custom Policies](docs/CUSTOM_POLICIES_TUTORIAL.md)**: A step-by-step guide to building your own policies.
|
|
192
|
+
- **[Get the Boilerplate](docs/CUSTOM_POLICIES_TUTORIAL.md#boilerplate-template-for-custom-policies)**: A clean, commented template to use as a starting point.
|
|
193
|
+
- **[Policy Ordering Guide](docs/POLICY_ORDERING_GUIDE.md)**: Learn how to add, remove, and reorder policies in the Policy Engine.
|
|
194
|
+
- **[API Guide](docs/API_GUIDE.md)**: A developer-focused guide for common tasks.
|
|
195
|
+
- **[API Reference](docs/API_REFERENCE.md)**: Complete interface specifications.
|
|
196
|
+
- **[Security Deep Dive](docs/SECURITY.md)**: A full checklist of security principles for a robust implementation.
|
|
197
|
+
- **[Implementation](./src/) & [Tests](./test/)**: Examine the reference implementation in `/src` and see it in action in the `/test` folder.
|