@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,632 @@
1
+ # Common Policies
2
+
3
+ - [AllowPolicy](#allowpolicy)
4
+ - [BypassPolicy](#bypasspolicy)
5
+ - [IntervalPolicy](#intervalpolicy)
6
+ - [MaxPolicy](#maxpolicy)
7
+ - [OnlyAuthorizedSenderPolicy](#onlyauthorizedsenderpolicy)
8
+ - [OnlyOwnerPolicy](#onlyownerpolicy)
9
+ - [PausePolicy](#pausepolicy)
10
+ - [RejectPolicy](#rejectpolicy)
11
+ - [RoleBasedAccessControlPolicy](#rolebasedaccesscontrolpolicy)
12
+ - [SecureMintPolicy](#securemintpolicy)
13
+ - [VolumePolicy](#volumepolicy)
14
+ - [VolumeRatePolicy](#volumeratepolicy)
15
+
16
+ ## Common Initialization Pattern
17
+
18
+ All policies in this repository follow a standard initialization pattern to ensure consistent configuration and deployment.
19
+
20
+ When a policy contract is deployed, it must be properly initialized using the following two-step process:
21
+
22
+ 1. initialize(address policyEngine, address initialOwner, bytes configParams)
23
+
24
+ - This function is part of the abstract Policy contract and must be called first.
25
+ - It initializes the core components:
26
+ - Sets the Policy Engine reference
27
+ - Assigns ownership (OwnableUpgradeable)
28
+ - Sets up any common inherited modules (ERC165Upgradeable, etc.)
29
+
30
+ 2. configure(bytes configParams). Immediately after core initialization, the initialize function automatically calls configure(configParams).
31
+ - Each policy implementation defines its own logic inside configure(bytes) to handle policy-specific parameters.
32
+ - The configParams are expected to be ABI-encoded parameters.
33
+ - For example, a policy that requires a maximum transfer quota might decode a single uint256 value from configParams.
34
+ - Validation and state assignment happen inside configure().
35
+
36
+ Important: configure(bytes) is designed to be called only once during initialization.
37
+
38
+ ## AllowPolicy
39
+
40
+ ### Overview
41
+
42
+ The `AllowPolicy` implements access control through an allowlist. The policy immediately rejects the transaction if the `sender` is not on the list, halting any subsequent policy checks.
43
+
44
+ ### Specific Configuration
45
+
46
+ 1. **Allowlist Management**
47
+
48
+ The contract [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) can:
49
+
50
+ - **`allowSender(address account)`**: Adds `account` to the allowlist.
51
+ - **`disallowSender(address account)`**: Removes `account` from the allowlist.
52
+
53
+ 2. **View Functions**
54
+ - **`senderAllowed(address account) -> bool`**: Returns `true` if `account` is on the allowlist.
55
+
56
+ ### Policy Parameters and Context
57
+
58
+ This policy expects a variable number of parameters, which are the addresses to check against the allowlist. Each parameter
59
+ MUST be an address. If ANY of the addresses provided are NOT present in the allowlist, the transaction will be rejected.
60
+
61
+ ### Policy Behavior
62
+
63
+ - **`run(...)`**
64
+
65
+ - Reverts if any of the parameters is not present on the allowlist.
66
+ - Returns `PolicyResult.Continue` otherwise
67
+
68
+ - **`postRun(...)`**
69
+ - Not implemented (no state changes required)
70
+
71
+ ### Example Use Cases
72
+
73
+ - **Regulated Access**: Provide access only to a select group of addresses.
74
+ - **Gradual Access**: Start with a restrictive allowlist, gradually adding trusted addresses.
75
+
76
+ ## BypassPolicy
77
+
78
+ ### Overview
79
+
80
+ The `BypassPolicy` implements access control through an allowlist. The policy immediately allows the transaction if the `sender` is on the list, bypassing any subsequent policy checks.
81
+
82
+ ### Specific Configuration
83
+
84
+ 1. **Allowlist Management**
85
+
86
+ The contract [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) can:
87
+
88
+ - **`allowSender(address account)`**: Adds `account` to the allowlist.
89
+ - **`disallowSender(address account)`**: Removes `account` from the allowlist.
90
+
91
+ 2. **View Functions**
92
+ - **`senderAllowed(address account) -> bool`**: Returns `true` if `account` is on the allowlist.
93
+
94
+ ### Policy Parameters and Context
95
+
96
+ This policy expects a variable number of parameters, which are the addresses to check against the allowlist. Each parameter
97
+ MUST be an address. If ALL addresses provided are present in the allowlist, the transaction will be allowed, bypassing
98
+ all subsequent policies.
99
+
100
+ ### Policy Behavior
101
+
102
+ - **`run(...)`**
103
+
104
+ - Returns `PolicyResult.Allowed` if all parameters are present on the allowlist
105
+ - Returns `PolicyResult.Continue` otherwise
106
+
107
+ - **`postRun(...)`**
108
+ - Not implemented (no state changes required)
109
+
110
+ ### Example Use Cases
111
+
112
+ - **Privileged Access**: Allow specific addresses to bypass other policy checks.
113
+ - **Layered Permissions**: Combine with other policies—e.g., the transaction proceeds as normal unless the caller is on the allowlist.
114
+
115
+ ## IntervalPolicy
116
+
117
+ ### Overview
118
+
119
+ The `IntervalPolicy` limits transaction execution to specific **time slots** within a **repeating cycle**. The policy accepts or rejects transactions based on whether the **current slot** (derived from block time) falls within a configured **start slot** and **end slot**.
120
+
121
+ ### Specific Configuration
122
+
123
+ - **Slot Duration (`s_slotDuration`)**
124
+ The length of each slot in seconds (e.g., `3600` for 1 hour, `86400` for 1 day).
125
+
126
+ - **Cycle Size (`s_cycleSize`)**
127
+ The total number of slots in each repeating cycle (e.g., `24` slots for 24 hours in a day, `7` slots for days in a week).
128
+
129
+ - **Cycle Offset (`s_cycleOffset`)**
130
+ An offset (in slots) added after computing the raw current slot. This shifts where slot `0` is effectively located in each cycle.
131
+
132
+ - **Start Slot (`s_startSlot`)** and **End Slot (`s_endSlot`)**
133
+ The inclusive and exclusive slot indices (within `[0, s_cycleSize)`) that define when transactions are permitted. A transaction is allowed only if the computed current slot is in `[s_startSlot, s_endSlot)`.
134
+
135
+ These values can be set in the constructor or changed by the contract [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) via:
136
+
137
+ - `setStartSlot(uint256 _startSlot)`
138
+ - `setEndSlot(uint256 _endSlot)`
139
+ - `setCycleParameters(uint256 _slotDuration, uint256 _cycleSize, uint256 _cycleOffset)`
140
+
141
+ ### Policy Parameters
142
+
143
+ | Parameter Name | Type | Description |
144
+ | --------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
145
+ | _No parameters_ | _N/A_ | The policy does not decode or use any parameters from the Extractor/Mapper. It relies solely on `block.timestamp` and its configured slot cycle to make decisions. |
146
+
147
+ Because `IntervalPolicy` ignores the `parameters` array passed into `run(...)`, it only uses the current block timestamp, combined with `s_slotDuration`, `s_cycleSize`, `s_cycleOffset`, etc., to determine if the transaction falls within the allowed slot range.
148
+
149
+ ### Policy Behavior
150
+
151
+ - **`run(...)`**
152
+
153
+ 1. Computes the current slot as:
154
+ ```solidity
155
+ uint256 currentSlot =
156
+ ((block.timestamp / s_slotDuration) % s_cycleSize + s_cycleOffset) % s_cycleSize;
157
+ ```
158
+ 2. Returns `PolicyResult.Continue` if `currentSlot` is within `[s_startSlot, s_endSlot)`, otherwise reverts.
159
+
160
+ - **`postRun(...)`**
161
+ - Not used in this policy (no state changes needed after `run`).
162
+
163
+ ### Configuration Examples
164
+
165
+ 1. **Daily Business Hours (9 AM - 5 PM UTC)**
166
+
167
+ ```solidity
168
+ new IntervalPolicy(
169
+ 9, // startSlot = 9
170
+ 17, // endSlot = 17
171
+ 3600, // 1-hour slot duration
172
+ 24, // 24 slots in each daily cycle
173
+ 0 // no cycle offset
174
+ );
175
+
176
+ ```
177
+
178
+ 2. **Weekday Operations (Monday-Friday)**
179
+ ```solidity
180
+ new IntervalPolicy(
181
+ 1, // startSlot = 1 (Monday)
182
+ 6, // endSlot = 6 (Saturday, but exclusive -> stops before Saturday)
183
+ 86400, // 1-day slot duration
184
+ 7, // 7 slots in each weekly cycle
185
+ 0 // no cycle offset
186
+ );
187
+ ```
188
+
189
+ ### Example Use Cases
190
+
191
+ - **Hourly or Daily Windows**: Permit specific hours in the day (e.g., 9 AM to 5 PM).
192
+ - **Weekly or Monthly Cycles**: Restrict transactions to certain days of the week or specific days in a month.
193
+ - **Maintenance Windows**: Automatically disallow transactions outside scheduled operating hours.
194
+
195
+ ## MaxPolicy
196
+
197
+ ### Overview
198
+
199
+ The `MaxPolicy` enforces a maximum value constraint. The policy compares a provided usage value against a configured maximum and rejects transactions that would exceed this limit.
200
+
201
+ For example, to enforce a maximum transfer amount of 1000 tokens:
202
+
203
+ ```solidity
204
+ // Create policy that caps transfers at 1000 tokens
205
+ MaxPolicy transferCapPolicy = new MaxPolicy();
206
+ policy.initialize(address(policyEngine), owner, abi.encode(1000));
207
+
208
+ // Usage:
209
+ // used <= 1000: PolicyResult.Continue
210
+ // used > 1000: revert
211
+ ```
212
+
213
+ ### Specific Configuration
214
+
215
+ 1. **Deployment Parameter**
216
+
217
+ - **`uint256 max`**: The initial maximum. If a transaction's `amount` (`uint256`) value exceeds this value, the policy rejects the transaction.
218
+
219
+ 2. **Owner Controls**
220
+
221
+ - **`setMax(uint256 max)`**: Updates the maximum.
222
+ - **`getMax()`**: Returns the current maximum.
223
+
224
+ The contract [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) manages these functions.
225
+
226
+ ### Policy Parameters
227
+
228
+ | Parameter Name | Type | Description |
229
+ | -------------- | --------- | ----------------------------------------------- |
230
+ | `amount` | `uint256` | A usage value that must not exceed the maximum. |
231
+
232
+ No additional `context` is required.
233
+
234
+ ### Policy Behavior
235
+
236
+ - **`run(...)`**
237
+
238
+ - Expects exactly one parameter, `amount` (`uint256`).
239
+ - Compares `amount` to the current `s_max`.
240
+ - Reverts if `amount > s_max`.
241
+ - Returns `PolicyResult.Continue` otherwise.
242
+
243
+ - **`postRun(...)`**
244
+ - Not implemented (no state changes required).
245
+
246
+ ### Example Use Cases
247
+
248
+ - **API Call Limits**: Restrict the number of calls or resource usage per transaction.
249
+ - **Token Spending Caps**: Enforce that a user does not exceed a certain token allowance in a single operation.
250
+ - **Resource Quotas**: Limit the maximum usage of onchain functionality in a one-off or per-transaction basis.
251
+
252
+ ## OnlyAuthorizedSenderPolicy
253
+
254
+ ### Overview
255
+
256
+ The `OnlyAuthorizedSenderPolicy` implements access control through an authorized list. The policy rejects the transaction if the `sender` is **NOT** on the list.
257
+
258
+ ### Specific Configuration
259
+
260
+ 1. **Authorized List Management**
261
+
262
+ The contract [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) can:
263
+
264
+ - **`authorizeSender(address account)`**: Adds `account` to the authorized list.
265
+ - **`unauthorizeSender(address account)`**: Removes `account` from the authorized list.
266
+
267
+ 2. **View Functions**
268
+ - **`senderAuthorized(address account) -> bool`**: Returns `true` if `account` is on the authorized list.
269
+
270
+ ### Policy Parameters and Context
271
+
272
+ | Parameter Name | Type | Description |
273
+ | --------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------- |
274
+ | _No parameters_ | _N/A_ | This policy does **not** require any parameters from the Policy Engine's configured Extractor and Mapper. It checks `sender` directly. |
275
+
276
+ ### Policy Behavior
277
+
278
+ - **`run(...)`**
279
+
280
+ - Returns `PolicyResult.Continue` if `sender` is on the authorized list
281
+ - Reverts otherwise
282
+
283
+ - **`postRun(...)`**
284
+ - Not implemented (no state changes required)
285
+
286
+ ### Example Use Cases
287
+
288
+ - **Restricted Access**: Only allow specific addresses operate the contract methods.
289
+
290
+ ## OnlyOwnerPolicy
291
+
292
+ ### Overview
293
+
294
+ The `OnlyOwnerPolicy` that only allows the policy owner to call the method, similar to `Ownable` from OpenZeppelin.
295
+
296
+ ### Policy Parameters and Context
297
+
298
+ | Parameter Name | Type | Description |
299
+ | --------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------- |
300
+ | _No parameters_ | _N/A_ | This policy does **not** require any parameters from the Policy Engine's configured Extractor and Mapper. It checks `sender` directly. |
301
+
302
+ ### Policy Behavior
303
+
304
+ - **`run(...)`**
305
+
306
+ - Returns `PolicyResult.Continue` if `sender` is the owner of the policy
307
+ - Reverts otherwise
308
+
309
+ - **`postRun(...)`**
310
+ - Not implemented (no state changes required)
311
+
312
+ ### Example Use Cases
313
+
314
+ - **Restricted Access**: Only allow contract deployer to operate the contract methods.
315
+
316
+ ## PausePolicy
317
+
318
+ ### Overview
319
+
320
+ The `PausePolicy` allows an [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) to enable or disable ("pause") all transactions. When the policy is paused, all incoming transactions will be rejected. When unpaused, the policy defers the decision (returns `PolicyResult.Continue`) so that other policies or the default policy engine logic can take effect.
321
+
322
+ ### Specific Configuration
323
+
324
+ 1. **Deployment Parameter**
325
+
326
+ - **`bool _paused`**: The initial pause state. If set to `true`, the policy starts off rejecting all transactions. If `false`, it starts in a "normal" state allowing transactions to continue.
327
+
328
+ 2. **Owner Controls**
329
+
330
+ - **`pause()`**: Sets the policy to a paused state (`s_paused = true`), rejecting all subsequent transactions.
331
+ - **`unpause()`**: Resets the policy to an unpaused state (`s_paused = false`), allowing transactions to continue.
332
+
333
+ ### Policy Parameters
334
+
335
+ | Parameter Name | Type | Description |
336
+ | --------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
337
+ | _No parameters_ | _N/A_ | The policy does not inspect or decode parameters from the Extractor/Mapper. It relies solely on its internal pause flag (`s_paused`) to decide whether to reject or continue a transaction. |
338
+
339
+ Since `PausePolicy` ignores the `parameters` array passed into `run(...)`, it uses the `s_paused` boolean to immediately reverts when paused, or defer (`PolicyResult.Continue`) when unpaused.
340
+
341
+ ### Policy Behavior
342
+
343
+ - **`run(...)`**
344
+ - Reverts if `s_paused == true`.
345
+ - Returns `PolicyResult.Continue` if `s_paused == false`.
346
+
347
+ ### Example Use Cases
348
+
349
+ - **Emergency Stop**: Quickly block all sensitive functions in a contract during an emergency or maintenance window.
350
+ - **Maintenance Mode**: Temporarily pause interactions for upgrades or migrations.
351
+ - **Gradual Rollout**: Deploy paused, then activate when ready.
352
+
353
+ ## RejectPolicy
354
+
355
+ ### Overview
356
+
357
+ The `RejectPolicy` implements access control through a denylist. The policy immediately rejects the transaction if one of the supplied addresses is on the denylist, halting any subsequent policy checks.
358
+
359
+ ### Specific Configuration
360
+
361
+ 1. **Denylist Management**
362
+
363
+ The contract [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) can:
364
+
365
+ - **`rejectAddress(address account)`**: Adds `account` to the denylist.
366
+ - **`unrejectAddress(address account)`**: Removes `account` from the denylist.
367
+
368
+ 2. **View Functions**
369
+ - **`addressRejected(address account) -> bool`**: Returns `true` if `account` is on the denylist.
370
+
371
+ ### Policy Parameters and Context
372
+
373
+ This policy expects a variable number of parameters, which are the addresses to check against the denylist. Each parameter
374
+ MUST be an address. If ANY of the addresses provided are present in the denylist, the transaction will be rejected.
375
+
376
+ ### Policy Behavior
377
+
378
+ - **`run(...)`**
379
+
380
+ - Reverts if any of the parameters is present on the denylist.
381
+ - Returns `PolicyResult.Continue` otherwise
382
+
383
+ - **`postRun(...)`**
384
+ - Not implemented (no state changes required)
385
+
386
+ ### Example Use Cases
387
+
388
+ - **Account Blocking**: Block malicious addresses, such as known hackers or compromised accounts.
389
+
390
+ ## RoleBasedAccessControlPolicy
391
+
392
+ ### Overview
393
+
394
+ The `RoleBasedAccessControlPolicy` utilize [OpenZeppelin's `AccessControlUpgradeable`](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/access/AccessControlUpgradeable.sol) to implement a flexible role-based access control system.
395
+
396
+ For example, to manage a transfer operation:
397
+
398
+ ```solidity
399
+ bytes4 TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
400
+ bytes32 ADMIN_ROLE = keccak256("ADMIN_ROLE");
401
+
402
+ RoleBasedAccessControlPolicy policy = new RoleBasedAccessControlPolicy();
403
+
404
+ policy.grantRole(ADMIN_ROLE, bob);
405
+ policy.grantOperationAllowanceToRole(TRANSFER_SELECTOR, ADMIN_ROLE);
406
+ ```
407
+
408
+ A transaction proceeds only if the sender holds a role that has been granted permission for the operation.
409
+
410
+ ### Specific Configuration
411
+
412
+ 1. **Role-Based Operation Allowance**
413
+
414
+ - **`grantOperationAllowanceToRole(bytes4 operation, bytes32 role)`**: Adds a role to the list of roles that can perform the operation.
415
+ - **`removeOperationAllowanceFromRole(bytes4 operation, bytes32 role)`**: Removes a role from that list.
416
+
417
+ 2. **Account Role Management**
418
+
419
+ - **`grantRole(bytes32 role, address account)`**: Assigns a role to a specific account.
420
+ - **`revokeRole(bytes32 role, address account)`**: Revokes a role from an account.
421
+
422
+ 3. **View Functions**
423
+ - **`hasAllowedRole(bytes4 operation, address account) -> bool`**: Checks if the account has any of the roles that are allowed to perform the operation.
424
+ - **`supportsInterface(bytes4 interfaceId) -> bool`**: Implements ERC165-style interface detection (inherited from `AccessControl` and `Policy`).
425
+
426
+ ### Policy Parameters
427
+
428
+ | Parameter Name | Type | Description |
429
+ | --------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------- |
430
+ | _No parameters_ | _N/A_ | This policy does **not** require any parameters from the Policy Engine's configured Extractor and Mapper. It checks `sender` directly. |
431
+
432
+ No additional `context` is used or expected.
433
+
434
+ ### Policy Behavior
435
+
436
+ - **`run(...)`**
437
+
438
+ - Extracts the `operation (bytes4)` from the single parameter.
439
+ - Checks whether the `sender` holds one of the roles with allowance for the `operation`.
440
+ - If `hasAllowedRole` is `false`, reverts; otherwise, returns `PolicyResult.Continue`.
441
+
442
+ - **`postRun(...)`**
443
+ - Not implemented in this policy (no state changes after `run`).
444
+
445
+ ### Example Use Cases
446
+
447
+ - **Granular Function Permissions**: Each `operation` corresponds to a function selector. Certain roles can call only specific functions.
448
+ - **Decentralized Team Management**: Owner can quickly grant or revoke privileges to multiple operations across multiple roles.
449
+
450
+ ## SecureMintPolicy
451
+
452
+ ### Overview
453
+
454
+ The `SecureMintPolicy` ensures the total supply of a token does not exceed the actual reserves of the underlying asset. It retrieves reserves data from a Chainlink Proof of Reserve contract (or any contract compatible with the Data Feed interface) and compares it against the total supply of the token.
455
+
456
+ ### Specific Configuration
457
+
458
+ 1. **Reserves Feed**
459
+
460
+ - **`setReservesFeed(address reservesFeed)`**: Updates the Chainlink data feed used for reserve validation.
461
+
462
+ 2. **Reserve Margin**
463
+
464
+ - **`enum ReserveMarginMode`**
465
+ - `None`: No reserve margin. Policy will compare total supply against reserves directly.
466
+ - `PositivePercentage`: Reserve margin is a positive percentage of the reserves, meaning total supply must be less than the reserves by a certain amount. e.g. If reserves = 1000 and margin = 10%, then total supply must be less than 900.
467
+ - `PositiveAbsolute`: Reserve margin is a positive absolute value. e.g. If reserves = 1000 and margin = 50, then total supply must be less than 950.
468
+ - `NegativePercentage`: Reserve margin is a negative percentage of the reserves, meaning total supply limit is greater than the reserves by a certain amount. e.g. If reserves = 1000 and margin = -10%, then total supply limit will be 1100.
469
+ - `NegativeAbsolute`: Reserve margin is a negative absolute value. e.g. If reserves = 1000 and margin = -50, then total supply limit will be 1050.
470
+ - **`setReserveMargin(ReserveMarginMode mode, uint256 amount)`**: Sets the reserve margin mode and amount. If the reserveMarginMode is percentage-based, amount will be interpreted as hundredths of a percent (e.g. 12.34% = 1234).
471
+
472
+ 3. **Reserve Staleness**
473
+
474
+ - **`setMaxStalenessSeconds(uint256 value)`**: Set the maximum staleness of the reserves data. Set to 0 to accept infinite staleness. If the data is older than this value, the policy will reject the transaction.
475
+
476
+ 4. **View Functions**
477
+
478
+ - **`reservesFeed() -> address`**: Returns the current reserves feed address.
479
+ - **`maxStalenessSeconds() -> uint256`**: Returns the current maximum staleness value.
480
+ - **`reserveMarginMode() -> ReserveMarginMode`**: Returns the current reserve margin mode.
481
+ - **`reserveMarginAmount() -> uint256`**: Returns the current reserve margin amount.
482
+
483
+ ### Policy Parameters
484
+
485
+ | Parameter Name | Type | Description |
486
+ | --- | --- | --- |
487
+ | `reservesFeed` | `address` | The address of the Chainlink Data Feed contract. |
488
+ | `reserveMarginMode` | `ReserveMarginMode` | The reserve margin mode. |
489
+ | `reserveMarginAmount` | `uint256` | The reserve margin amount. Interpreted as hundredths of a percent if `reserveMarginMode` is percentage-based. |
490
+ | `maxStalenessSeconds` | `uint256` | The maximum staleness of the reserves data. |
491
+
492
+ ### Policy Behavior
493
+
494
+ - **`run(...)`**
495
+
496
+ - Extracts the `amount (uint256)` from parameters.
497
+ - Get latest reserves data from the reserves feed.
498
+ - If `maxStalenessSeconds` is not 0 and the data is older than this value, revert.
499
+ - Calculates the total backed supply of the token using the reserves value, `reserveMarginMode` and `reserveMarginAmount`.
500
+ - If the total supply of the token is greater than the backed supply, revert.
501
+ - If the total supply of the token is less than or equal to the backed supply, returns `PolicyResult.Continue`.
502
+
503
+ - **`postRun(...)`**
504
+ - Not implemented in this policy (no state changes after `run`).
505
+
506
+ ### Example Use Cases
507
+ - **Collateralized Token Minting**: Ensure that the total supply of a token does not exceed the actual reserves of the underlying asset.
508
+
509
+ ## VolumePolicy
510
+
511
+ #### Overview
512
+
513
+ The `VolumePolicy` enforces minimum and maximum value constraints. The policy compares a provided amount against configured bounds and rejects transactions that fall outside these limits.
514
+
515
+ For example, to limit transfers between 100 and 1000 tokens:
516
+
517
+ ```solidity
518
+ VolumePolicy volumePolicy = new VolumePolicy();
519
+ volumePolicy.setMin(100); // Minimum amount allowed
520
+ volumePolicy.setMax(1000); // Maximum amount allowed (0 means no upper limit)
521
+ ```
522
+
523
+ ### Specific Configuration
524
+
525
+ 1. **Minimum / Maximum Amount**
526
+
527
+ - **`s_minAmount`**: The minimum allowed amount.
528
+ - **`s_maxAmount`**: The maximum allowed amount (0 indicates no maximum limit).
529
+
530
+ 2. **Owner Controls**
531
+
532
+ The contract [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) can:
533
+
534
+ - **`setMin(uint256 minAmount)`**: Updates the minimum allowed amount. Must be strictly less than the current max (unless max is 0).
535
+ - **`setMax(uint256 maxAmount)`**: Updates the maximum allowed amount. Must be strictly greater than the current min (unless min is 0).
536
+
537
+ 3. **View Functions**
538
+ - **`getMax() -> uint256`**: Returns the current maximum amount.
539
+ - **`getMin() -> uint256`**: Returns the current minimum amount.
540
+
541
+ ### Policy Parameters
542
+
543
+ The **VolumePolicy** expects **one** parameter in the `parameters` array:
544
+
545
+ | Parameter Name | Type | Description |
546
+ | -------------- | --------- | ------------------------------------------------------------------- |
547
+ | `amount` | `uint256` | The numeric value to check against `s_minAmount` and `s_maxAmount`. |
548
+
549
+ The policy expects no additional context.
550
+
551
+ ### Policy Behavior
552
+
553
+ - **`run(...)`**
554
+
555
+ - Validates parameter count equals 1
556
+ - Decodes the parameter: `amount (uint256)`.
557
+ - If `amount < s_minAmount` **or** `amount > s_maxAmount` (when `s_maxAmount != 0`), reverts.
558
+ - Otherwise, returns `PolicyResult.Continue`.
559
+
560
+ - **`postRun(...)`**
561
+ - Not used in this policy (no state changes after `run`).
562
+
563
+ ### Example Use Cases
564
+
565
+ - **Purchase Limits**: Restrict transaction amounts to a certain range.
566
+ - **Rate Controls**: Ensure that any single transaction doesn’t fall below a minimum or exceed a maximum allowed value.
567
+ - **Resource/Token-Transfer Rules**: Protect a system from extremely small or large transfers that could be disruptive.
568
+
569
+ ## VolumeRatePolicy
570
+
571
+ ### Overview
572
+
573
+ The `VolumeRatePolicy` enforces per-account volume limits within configurable time periods. The policy tracks cumulative amounts and rejects transactions that would exceed the maximum allowed volume in the current period.
574
+
575
+ For example, to limit transfers to 1000 tokens per hour:
576
+
577
+ ```solidity
578
+ // Create policy with 1-hour period and 1000 token limit
579
+ VolumeRatePolicy policy = new VolumeRatePolicy(
580
+ 3600, // Time period (1 hour in seconds)
581
+ 1000 // Max amount per period
582
+ );
583
+ ```
584
+
585
+ ### Specific Configuration
586
+
587
+ 1. **Time Period (`s_timePeriod`)**
588
+
589
+ - The duration (in seconds) of a repeating window (e.g., 3600 for hourly).
590
+
591
+ 2. **Max Amount (`s_maxAmount`)**
592
+
593
+ - The upper bound on total volume permitted per account in each time period.
594
+ - If a transaction plus the existing volume in the current time period exceeds this limit, the policy rejects the transaction.
595
+
596
+ 3. **Owner Controls**
597
+ The contract [owner](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) can:
598
+
599
+ - **`setMaxAmount(uint256 _maxAmount)`**: Updates the maximum volume limit.
600
+ - **`setTimePeriod(uint256 _timePeriod)`**: Updates the time period length in seconds.
601
+ - **`getMaxAmount()`** / **`getTimePeriod()`**: View functions for the current configuration.
602
+
603
+ ### Policy Parameters
604
+
605
+ The **VolumeRatePolicy** expects exactly **two** parameters in the `parameters` array, in this order:
606
+
607
+ | Parameter Name | Type | Description |
608
+ | -------------- | --------- | -------------------------------------------- |
609
+ | `amount` | `uint256` | The amount being transferred. |
610
+ | `account` | `address` | The address for which the volume is tracked. |
611
+
612
+ No additional `context` is used.
613
+
614
+ ### Policy Behavior
615
+
616
+ 1. **`run(...)`**
617
+
618
+ - Validates parameter count equals 2.
619
+ - Derives the current time period (`currentPeriod = block.timestamp / s_timePeriod`).
620
+ - Compares the stored `timePeriod` and `amount` for `account` against the `currentPeriod` and the incoming `amount`.
621
+ - If the current period matches, checks whether `existingVolume + newAmount` exceeds `s_maxAmount`. If so, reverts; else, `PolicyResult.Continue`.
622
+ - If the period is new for this account and `newAmount` exceeds `s_maxAmount`, reverts; otherwise, `PolicyResult.Continue`.
623
+
624
+ 2. **`postRun(...)`**
625
+ - If the transaction wasn’t rejected, updates the stored record for that account in the current time period by adding `amount`.
626
+ - If this is a new period, the policy resets the stored amount to `amount`.
627
+
628
+ ### Example Use Cases
629
+
630
+ - **Rate Limiting**: Enforce maximum transfer amounts per hour/day
631
+ - **Usage Quotas**: Prevent resource exhaustion by single accounts
632
+ - **Compliance**: Implement regulatory transfer limits per time window