@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,477 @@
1
+ # ACE Getting Started: Integrate Policy-Based Compliance
2
+
3
+ This guide provides a fast path to integrating your smart contract with Chainlink Automated Compliance Engine (ACE).
4
+
5
+ **Why integrate ACE?** Prepare your contracts for future regulatory requirements without rewriting your core logic. Add, remove, or update compliance rules after deployment through modular policies.
6
+
7
+ **What you'll learn:** The 3-step pattern to make any contract policy-protected.
8
+
9
+ **What you'll build:** A simple vault with pauseable functions.
10
+
11
+ > **Building a token?** The pattern is identical—just use our audited [tokens](../packages/tokens) instead. We use a vault here to keep the example focused on ACE integration, not token complexity.
12
+
13
+ ## A quick note before you start
14
+
15
+ This guide gets you hands-on fast. But if you find yourself asking "why?", these quick reads will help:
16
+
17
+ - **[What is Policy Management?](../packages/policy-management/README.md)** - Core concepts
18
+ - **[How do policies execute?](../packages/policy-management/docs/POLICY_ORDERING_GUIDE.md)** - Understanding `Allowed`, `Continue`, and `PolicyRejected` error
19
+
20
+ ## Part 1: What you need to integrate ACE
21
+
22
+ Integrating ACE into your contract requires three key steps. Each step is simple and modular, allowing you to adopt ACE without rewriting your contract's core business logic.
23
+
24
+ ### Step 1: Inherit from `PolicyProtected`
25
+
26
+ **What it is:** [`PolicyProtected`](../packages/policy-management/src/core/PolicyProtected.sol) is an abstract contract that provides the connection between your contract and the ACE compliance system.
27
+
28
+ **What you need to do:** Add `PolicyProtected` to your contract's inheritance list.
29
+
30
+ ```solidity
31
+ import {PolicyProtected} from "@chainlink/policy-management/core/PolicyProtected.sol";
32
+
33
+ contract YourContract is PolicyProtected {
34
+ // Your contract code...
35
+ }
36
+ ```
37
+
38
+ > **Note on Imports:** In this repo, the `@chainlink/...` imports work via Foundry remappings defined in `remappings.txt`. These point to the local `packages/` directory in this repository, not npm packages. If you're integrating ACE into your own project, ensure your `remappings.txt` includes:
39
+ >
40
+ > ```
41
+ > @chainlink/policy-management/=packages/policy-management/src/
42
+ > @chainlink/cross-chain-identity/=packages/cross-chain-identity/src/
43
+ > ```
44
+
45
+ **What this gives you:**
46
+
47
+ - Access to the `runPolicy` and `runPolicyWithContext` modifiers, which are the hooks into the policy system.
48
+ - Functions to attach and manage your contract's connection to a `PolicyEngine`.
49
+ - The ability to pass additional context data (like off-chain signatures) to your policies.
50
+
51
+ > **Important:** `PolicyProtected` is an upgradeable base contract, which means **your contract must be deployed through a proxy** (like `ERC1967Proxy`). See the [deployment script example](#the-deployment-script) below for the pattern.
52
+
53
+ ### Step 2: Protect your functions with the `runPolicy` modifier
54
+
55
+ **What it is:** The `runPolicy` modifier is a function modifier that intercepts calls to your contract's functions and routes them through the `PolicyEngine` for validation before executing your core logic.
56
+
57
+ **What you need to do:** Add the `runPolicy` modifier to any function you want to protect with onchain compliance rules.
58
+
59
+ ```solidity
60
+ function transfer(address to, uint256 amount) public runPolicy returns (bool) {
61
+ // Your transfer logic...
62
+ }
63
+
64
+ function mint(address to, uint256 amount) public runPolicy {
65
+ // Your minting logic...
66
+ }
67
+ ```
68
+
69
+ **What this gives you:**
70
+
71
+ - **Flexible compliance enforcement:** Before your function's code runs, the `PolicyEngine` will check all registered policies for that function.
72
+ - **Zero core logic changes:** You don't modify your business logic. The modifier handles all compliance checks separately.
73
+ - **Dynamic updates:** You can add, remove, or reorder policies without ever touching this function again.
74
+
75
+ > **Note:** You can add the `runPolicy` modifier to any function in your contract. It works for standard functions (like `transfer`), administrative functions (like `mint`), or any custom function you define.
76
+
77
+ ### Step 3: Deploy and configure a `PolicyEngine`
78
+
79
+ **What it is:** The [`PolicyEngine`](../packages/policy-management/src/core/PolicyEngine.sol) is the central orchestrator of your compliance system. It stores all your policies and executes them in order whenever a protected function is called.
80
+
81
+ **What you need to do:** Deploy and configure a `PolicyEngine`, then connect it to your contract and attach policies.
82
+
83
+ **Step 3a: Deploy and initialize the PolicyEngine**
84
+
85
+ ```solidity
86
+ // Deploy the PolicyEngine implementation
87
+ PolicyEngine policyEngineImpl = new PolicyEngine();
88
+
89
+ // Encode the initialization data
90
+ bytes memory initData = abi.encodeWithSelector(
91
+ PolicyEngine.initialize.selector,
92
+ true, // defaultAllow: true = allow by default, false = reject by default
93
+ owner
94
+ );
95
+
96
+ // Deploy the proxy and initialize in one step
97
+ ERC1967Proxy proxy = new ERC1967Proxy(address(policyEngineImpl), initData);
98
+ PolicyEngine policyEngine = PolicyEngine(address(proxy));
99
+ ```
100
+
101
+ The `defaultAllow` parameter (boolean) sets what happens when no policies are attached or when all policies return `Continue`:
102
+
103
+ - `true` - Transaction proceeds (permissive default, recommended for gradual adoption)
104
+ - `false` - Transaction is blocked (restrictive default)
105
+
106
+ > **Note:** When policies return `Allowed`, the engine immediately allows the transaction and stops evaluating further policies. When a policy reverts with a `PolicyRejected` error, the entire transaction reverts immediately. Only `Continue` results proceed to the next policy in the chain. Learn more in [How It Works](../packages/policy-management/README.md#how-it-works-an-overview).
107
+
108
+ **Step 3b: Deploy your contract and connect it to the PolicyEngine**
109
+
110
+ ```solidity
111
+ // Deploy your contract implementation
112
+ MyContract contractImpl = new MyContract();
113
+
114
+ // Encode the initialization data (connects to PolicyEngine)
115
+ bytes memory contractInitData = abi.encodeWithSelector(
116
+ MyContract.initialize.selector,
117
+ owner,
118
+ address(policyEngine)
119
+ );
120
+
121
+ // Deploy the proxy
122
+ ERC1967Proxy contractProxy = new ERC1967Proxy(address(contractImpl), contractInitData);
123
+ MyContract myContract = MyContract(address(contractProxy));
124
+ ```
125
+
126
+ Your contract is now connected to the `PolicyEngine`, and the `runPolicy` modifiers will route function calls through this engine for validation.
127
+
128
+ **Step 3c: Deploy and attach policies to specific functions**
129
+
130
+ ```solidity
131
+ // 1. Deploy a policy through a proxy
132
+ PausePolicy policyImpl = new PausePolicy();
133
+ bytes memory policyData = abi.encodeWithSelector(
134
+ Policy.initialize.selector,
135
+ address(policyEngine),
136
+ owner,
137
+ configData
138
+ );
139
+ ERC1967Proxy policyProxy = new ERC1967Proxy(address(policyImpl), policyData);
140
+ PausePolicy pausePolicy = PausePolicy(address(policyProxy));
141
+
142
+ // 2. Attach it to a specific function on your contract
143
+ policyEngine.addPolicy(
144
+ address(yourContract), // The protected contract
145
+ yourContract.transfer.selector, // The function to protect
146
+ address(pausePolicy), // The policy to enforce
147
+ new bytes32[](0) // Parameter names (if the policy needs them)
148
+ );
149
+ ```
150
+
151
+ You can attach multiple policies to the same function—they'll execute in the order you add them.
152
+
153
+ **What this gives you:**
154
+
155
+ - **A modular compliance system:** Policies are separate contracts that can be added, removed, or upgraded independently. See a list of [ready-to-use policies](../packages/policy-management/src/policies/README.md) for common use cases or [create your own](../packages/policy-management/docs/CUSTOM_POLICIES_TUTORIAL.md).
156
+ - **Composable rules and fine-grained control:** Chain multiple policies together to create sophisticated compliance logic, and attach different policies to different functions. See the [Policy Ordering Guide](../packages/policy-management/docs/POLICY_ORDERING_GUIDE.md) for details on how policy ordering works and why it matters.
157
+
158
+ ## Part 2: An example implementation
159
+
160
+ Now that you understand the integration requirements, here's a complete, working example. This example shows how to protect a simple vault contract's `deposit` and `withdraw` functions with a `PausePolicy`.
161
+
162
+ This example includes:
163
+
164
+ 1. A simple vault contract that inherits from `PolicyProtected` ([`MyVault.sol`](./MyVault.sol)).
165
+ 2. A deployment script that sets up the `PolicyEngine` and attaches a `PausePolicy` ([`DeployGettingStarted.s.sol`](../script/getting_started/DeployGettingStarted.s.sol)).
166
+ 3. Test commands to demonstrate pausing and unpausing vault operations.
167
+
168
+ ### The vault contract
169
+
170
+ Here's the vault contract ([`getting_started/MyVault.sol`](./MyVault.sol)):
171
+
172
+ ```solidity
173
+ // SPDX-License-Identifier: MIT
174
+ pragma solidity 0.8.26;
175
+
176
+ import {PolicyProtected} from "@chainlink/policy-management/core/PolicyProtected.sol";
177
+
178
+ contract MyVault is PolicyProtected {
179
+ mapping(address => uint256) public deposits;
180
+
181
+ function initialize(address initialOwner, address policyEngine) public initializer {
182
+ __PolicyProtected_init(initialOwner, policyEngine);
183
+ }
184
+
185
+ // The runPolicy modifier protects this function
186
+ function deposit(uint256 amount) public runPolicy {
187
+ deposits[msg.sender] += amount;
188
+ }
189
+
190
+ // The runPolicy modifier protects this function too
191
+ function withdraw(uint256 amount) public runPolicy {
192
+ require(deposits[msg.sender] >= amount, "Insufficient balance");
193
+ deposits[msg.sender] -= amount;
194
+ }
195
+ }
196
+ ```
197
+
198
+ **Key takeaways:**
199
+
200
+ - Inheritance from `PolicyProtected` (an upgradeable base contract)
201
+ - `initialize()` function sets up the owner and connects to the `PolicyEngine`
202
+ - Multiple functions can be protected with the `runPolicy` modifier
203
+ - Each function can have different policies attached via the `PolicyEngine`
204
+
205
+ ### The deployment script
206
+
207
+ Here's the deployment script ([`DeployGettingStarted.s.sol`](../script/getting_started/DeployGettingStarted.s.sol)):
208
+
209
+ > **Note on Proxy Deployment:** All ACE components must be deployed behind a proxy because they use OpenZeppelin's upgradeable contracts pattern (disabled constructors with initializers). This guide uses `ERC1967Proxy`, which enables upgradeability—you can update contract logic while preserving state and addresses. In production, you may also encounter minimal proxies (clones) for components that don't require upgradeability.
210
+
211
+ ```solidity
212
+ // SPDX-License-Identifier: BUSL-1.1
213
+ pragma solidity 0.8.26;
214
+
215
+ import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
216
+ import {Script} from "forge-std/Script.sol";
217
+ import {console} from "forge-std/console.sol";
218
+ import {MyVault} from "../getting_started/MyVault.sol";
219
+ import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
220
+ import {Policy} from "@chainlink/policy-management/core/Policy.sol";
221
+ import {PausePolicy} from "@chainlink/policy-management/policies/PausePolicy.sol";
222
+ import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
223
+
224
+ contract DeployGettingStarted is Script {
225
+ function run() external {
226
+ uint256 deployerPK = vm.envUint("PRIVATE_KEY");
227
+ address deployer = vm.addr(deployerPK);
228
+
229
+ vm.startBroadcast(deployerPK);
230
+
231
+ // 1. Deploy the PolicyEngine through a proxy
232
+ PolicyEngine policyEngineImpl = new PolicyEngine();
233
+ bytes memory policyEngineData = abi.encodeWithSelector(
234
+ PolicyEngine.initialize.selector,
235
+ true, // defaultAllow = true (allow by default)
236
+ deployer
237
+ );
238
+ ERC1967Proxy policyEngineProxy = new ERC1967Proxy(address(policyEngineImpl), policyEngineData);
239
+ PolicyEngine policyEngine = PolicyEngine(address(policyEngineProxy));
240
+
241
+ // 2. Deploy your vault through a proxy
242
+ MyVault vaultImpl = new MyVault();
243
+ bytes memory vaultData = abi.encodeWithSelector(
244
+ MyVault.initialize.selector,
245
+ deployer,
246
+ address(policyEngine)
247
+ );
248
+ ERC1967Proxy vaultProxy = new ERC1967Proxy(address(vaultImpl), vaultData);
249
+ MyVault vault = MyVault(address(vaultProxy));
250
+
251
+ // 3. Deploy the PausePolicy through a proxy
252
+ PausePolicy pausePolicyImpl = new PausePolicy();
253
+ bytes memory pausePolicyConfig = abi.encode(false); // Not paused by default
254
+ bytes memory pausePolicyData = abi.encodeWithSelector(
255
+ Policy.initialize.selector,
256
+ address(policyEngine),
257
+ deployer,
258
+ pausePolicyConfig
259
+ );
260
+ ERC1967Proxy pausePolicyProxy = new ERC1967Proxy(address(pausePolicyImpl), pausePolicyData);
261
+ PausePolicy pausePolicy = PausePolicy(address(pausePolicyProxy));
262
+
263
+ // 4. Add the PausePolicy to both deposit and withdraw functions
264
+ policyEngine.addPolicy(
265
+ address(vault),
266
+ vault.deposit.selector,
267
+ address(pausePolicy),
268
+ new bytes32[](0) // No parameters needed for PausePolicy
269
+ );
270
+
271
+ policyEngine.addPolicy(
272
+ address(vault),
273
+ vault.withdraw.selector,
274
+ address(pausePolicy),
275
+ new bytes32[](0)
276
+ );
277
+
278
+ vm.stopBroadcast();
279
+
280
+ console.log("--- Deployed Contracts ---");
281
+ console.log("MyVault deployed at:", address(vault));
282
+ console.log("PolicyEngine deployed at:", address(policyEngine));
283
+ console.log("PausePolicy deployed at:", address(pausePolicy));
284
+ }
285
+ }
286
+ ```
287
+
288
+ ### Testing your compliant vault
289
+
290
+ You can now test your policy-protected vault on a local Anvil chain.
291
+
292
+ #### Prerequisites
293
+
294
+ - [Node.js](https://nodejs.org/en/download/) (v18 or later)
295
+ - [Foundry](https://book.getfoundry.sh/getting-started/installation) (v0.3.0 or later)
296
+ - [pnpm](https://pnpm.io/installation)
297
+
298
+ #### Setup
299
+
300
+ 1. **Clone and enter the repository:**
301
+
302
+ ```bash
303
+ git clone https://github.com/smartcontractkit/chainlink-ace.git
304
+ cd chainlink-ace
305
+ ```
306
+
307
+ 2. **Install dependencies:**
308
+
309
+ ```bash
310
+ pnpm install
311
+ ```
312
+
313
+ 3. **Build the project:**
314
+
315
+ ```bash
316
+ pnpm build
317
+ ```
318
+
319
+ #### Start Anvil Chain
320
+
321
+ From a new terminal, start a new anvil chain by running:
322
+
323
+ ```bash
324
+ anvil
325
+ ```
326
+
327
+ **Note:** Keep this terminal open - anvil runs on `http://localhost:8545` by default.
328
+
329
+ #### Deploy the System
330
+
331
+ Now you're ready to deploy your policy-protected vault:
332
+
333
+ ```bash
334
+ export ETH_RPC_URL=http://localhost:8545
335
+ export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
336
+
337
+ forge script script/getting_started/DeployGettingStarted.s.sol:DeployGettingStarted --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast
338
+ ```
339
+
340
+ #### Test the compliance system
341
+
342
+ **Set up your environment** (replace with your deployed addresses from the logs above):
343
+
344
+ ```bash
345
+ export VAULT_ADDRESS=<Your_Deployed_MyVault_Address>
346
+ export PAUSE_POLICY_ADDRESS=<Your_Deployed_PausePolicy_Address>
347
+ ```
348
+
349
+ > **Tip:** After running the deploy command, you'll see the deployed addresses in the output logs:
350
+ >
351
+ > ```
352
+ > == Logs ==
353
+ > --- Deployed Contracts ---
354
+ > MyVault deployed at: 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
355
+ > PolicyEngine deployed at: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
356
+ > PausePolicy deployed at: 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707
357
+ > ```
358
+ >
359
+ > Use these addresses for `VAULT_ADDRESS` and `PAUSE_POLICY_ADDRESS`.
360
+
361
+ **Run the tests:**
362
+
363
+ 1. **Make a deposit of 100:**
364
+
365
+ ```bash
366
+ cast send $VAULT_ADDRESS "deposit(uint256)" 100 --private-key $PRIVATE_KEY
367
+ ```
368
+
369
+ **Expected:** Success!
370
+
371
+ 2. **Check your deposit:**
372
+
373
+ ```bash
374
+ cast call $VAULT_ADDRESS "deposits(address)" 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 | cast --to-dec
375
+ ```
376
+
377
+ **Expected:** 100
378
+
379
+ 3. **Pause the vault:**
380
+
381
+ ```bash
382
+ cast send $PAUSE_POLICY_ADDRESS "pause()" --private-key $PRIVATE_KEY
383
+ ```
384
+
385
+ **Expected:** Success!
386
+
387
+ 4. **Attempt a deposit:**
388
+
389
+ ```bash
390
+ cast send $VAULT_ADDRESS "deposit(uint256)" 50 --private-key $PRIVATE_KEY
391
+ ```
392
+
393
+ **Expected:** `Error: PolicyRunRejected` with reason "contract is paused"
394
+
395
+ 5. **Attempt a withdrawal:**
396
+
397
+ ```bash
398
+ cast send $VAULT_ADDRESS "withdraw(uint256)" 10 --private-key $PRIVATE_KEY
399
+ ```
400
+
401
+ **Expected:** `Error: PolicyRunRejected` with reason "contract is paused"
402
+
403
+ 6. **Unpause the vault:**
404
+
405
+ ```bash
406
+ cast send $PAUSE_POLICY_ADDRESS "unpause()" --private-key $PRIVATE_KEY
407
+ ```
408
+
409
+ **Expected:** Success!
410
+
411
+ 7. **Withdraw funds:**
412
+
413
+ ```bash
414
+ cast send $VAULT_ADDRESS "withdraw(uint256)" 10 --private-key $PRIVATE_KEY
415
+ ```
416
+
417
+ **Expected:** Success!
418
+
419
+ 8. **Verify the updated balance:**
420
+
421
+ ```bash
422
+ cast call $VAULT_ADDRESS "deposits(address)" 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 | cast --to-dec
423
+ ```
424
+
425
+ **Expected:** 90 (100 - 10)
426
+
427
+ ## Next steps
428
+
429
+ You now understand the core ACE integration pattern:
430
+
431
+ 1. Inherit from `PolicyProtected`
432
+ 2. Protect functions with the `runPolicy` modifier
433
+ 3. Deploy a `PolicyEngine` and attach policies
434
+
435
+ ### Where to go from here
436
+
437
+ Choose your path based on what you want to build:
438
+
439
+ #### **Learn more about Policy Management**
440
+
441
+ You've seen one policy (`PausePolicy`) on two functions. Ready to level up?
442
+
443
+ **Understand the system:**
444
+
445
+ - **[How the Policy Flow Works](../packages/policy-management/README.md#how-it-works-an-overview)** - Understand `Allowed`, `Continue`, and `PolicyRejected` error
446
+ - **[Policy Ordering Matters](../packages/policy-management/docs/POLICY_ORDERING_GUIDE.md)** - Learn how policy execution order affects security
447
+
448
+ **Use Policies:**
449
+
450
+ - **[Policy Library](../packages/policy-management/src/policies/README.md)** - Explore ready-to-use policies: `MaxPolicy`, `VolumePolicy`, `OnlyOwnerPolicy`, `RoleBasedAccessControlPolicy`, and more
451
+ - **[Create a Custom Policy](../packages/policy-management/docs/CUSTOM_POLICIES_TUTORIAL.md)** - Step-by-step tutorial with boilerplate template
452
+
453
+ ---
454
+
455
+ #### **Build a compliant token**
456
+
457
+ Don't reinvent the wheel. Use our audited, production-ready token implementations:
458
+
459
+ - **[ComplianceTokenERC20](../packages/tokens/erc-20/src/ComplianceTokenERC20.sol)**
460
+ - **[ComplianceTokenERC3643](../packages/tokens/erc-3643/src/ComplianceTokenERC3643.sol)**
461
+ - **[Example Deployment Scripts](../script/)** - See how to deploy and configure these tokens
462
+
463
+ ---
464
+
465
+ #### **Add Cross-Chain Identity & credentials**
466
+
467
+ Ready to add identity and credential verification (KYC, AML, accreditation, etc.)? Integrate the Cross-Chain Identity component:
468
+
469
+ **Start with the advanced tutorial:**
470
+
471
+ - **[Advanced Getting Started: Tokenized Fund](./advanced/GETTING_STARTED_ADVANCED.md)** - Build a complete system with KYC checks, sanctions screening, and identity management across multiple roles
472
+
473
+ **Deep dive into identity:**
474
+
475
+ - **[Cross-Chain Identity Overview](../packages/cross-chain-identity/README.md)** - Understand CCIDs, credentials, and credential issuers
476
+ - **[Credential Flow Diagram](../packages/cross-chain-identity/docs/CREDENTIAL_FLOW.md)** - Visual walkthrough of the complete issuance process
477
+ - **[Security Considerations](../packages/cross-chain-identity/docs/SECURITY.md)** - Privacy, CCID correlation, and data protection
@@ -0,0 +1,48 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ pragma solidity 0.8.26;
3
+
4
+ import {PolicyProtected} from "@chainlink/policy-management/core/PolicyProtected.sol";
5
+
6
+ /**
7
+ * @title MyVault
8
+ * @notice A simple vault contract with policy-protected deposits and withdrawals.
9
+ * @dev This example demonstrates the minimal integration required to make a contract compliant with ACE.
10
+ * Both the `deposit` and `withdraw` functions are protected with the `runPolicy` modifier.
11
+ * This contract is designed to be deployed behind a proxy for upgradeability.
12
+ */
13
+ contract MyVault is PolicyProtected {
14
+ mapping(address => uint256) public deposits;
15
+
16
+ function initialize(address initialOwner, address policyEngine) public initializer {
17
+ __PolicyProtected_init(initialOwner, policyEngine);
18
+ }
19
+
20
+ /**
21
+ * @notice Deposits funds into the vault for the caller.
22
+ * @dev This function is protected by the `runPolicy` modifier, which routes the call
23
+ * through the PolicyEngine for validation before executing the deposit.
24
+ * @param amount The amount to deposit.
25
+ */
26
+ function deposit(uint256 amount) public runPolicy {
27
+ deposits[msg.sender] += amount;
28
+ }
29
+
30
+ /**
31
+ * @notice Withdraws funds from the vault for the caller.
32
+ * @dev This function is protected by the `runPolicy` modifier, which routes the call
33
+ * through the PolicyEngine for validation before executing the withdrawal.
34
+ * @param amount The amount to withdraw.
35
+ */
36
+ function withdraw(uint256 amount) public runPolicy {
37
+ require(deposits[msg.sender] >= amount, "Insufficient balance");
38
+ deposits[msg.sender] -= amount;
39
+ }
40
+
41
+ /**
42
+ * @notice Returns the total deposits in the vault.
43
+ * @return The sum of all deposits.
44
+ */
45
+ function totalDeposits() public view returns (uint256) {
46
+ return address(this).balance;
47
+ }
48
+ }
@@ -0,0 +1,36 @@
1
+ # The main MMF Token Contract
2
+ export TOKEN_ADDRESS=0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE
3
+ # The Policy Engine that governs the token
4
+ export POLICY_ENGINE_ADDRESS=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
5
+ # The registries for Identity and Credentials
6
+ export IDENTITY_REGISTRY_ADDRESS=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
7
+ export CREDENTIAL_REGISTRY_ADDRESS=0x5FC8d32690cc91D4c39d9d3abcBD16989F875707
8
+ # Our mock on-chain data source for sanctions
9
+ export SANCTIONS_LIST_ADDRESS=0x057ef64E23666F000b34aE31332854aCBd1c8544
10
+ # The policy that acts as the admin for the registries
11
+ export IDENTITY_ONLY_AUTHORIZED_POLICY_ADDRESS=0xa513E6E4b8f2a923D98304ec87F64353C4D5C853
12
+
13
+ # --- The Actors ---
14
+ # The Fund Manager (and default admin for this example)
15
+ export FUND_MANAGER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
16
+ export FUND_MANAGER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
17
+
18
+ # The Verification Issuer (Anvil Account #9)
19
+ export CREDENTIAL_ISSUER_PRIVATE_KEY=0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
20
+ export CREDENTIAL_ISSUER_ADDRESS=0xa0Ee7A142d267C1f36714E4a8F75612F20a79720
21
+
22
+ # The Sanctions List Provider (Anvil Account #3)
23
+ export SANCTIONS_PROVIDER_PRIVATE_KEY=0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6
24
+ export SANCTIONS_PROVIDER_ADDRESS=0x90F79bf6EB2c4f870365E785982E1f101E93b906
25
+
26
+ # Alice, a verified investor (Anvil Account #1)
27
+ export ALICE_PRIVATE_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
28
+ export ALICE_ADDRESS=0x70997970C51812dc3A010C7d01b50e0d17dc79C8
29
+ export ALICE_CCID=`cast keccak "ALICE_INVESTOR_ID"`
30
+
31
+ # Charlie, a verified but sanctioned investor (Anvil Account #2)
32
+ export CHARLIE_ADDRESS=0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC
33
+ export CHARLIE_CCID=`cast keccak "CHARLIE_INVESTOR_ID"`
34
+
35
+ # The required KYC credential
36
+ export KYC_CREDENTIAL=`cast keccak "common.kyc"`