@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,245 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {ICredentialRegistry} from "./interfaces/ICredentialRegistry.sol";
|
|
5
|
+
import {ICredentialValidator} from "./interfaces/ICredentialValidator.sol";
|
|
6
|
+
import {PolicyProtected} from "@chainlink/policy-management/core/PolicyProtected.sol";
|
|
7
|
+
|
|
8
|
+
contract CredentialRegistry is PolicyProtected, ICredentialRegistry {
|
|
9
|
+
/// @custom:storage-location erc7201:cross-chain-identity.CredentialRegistry
|
|
10
|
+
struct CredentialRegistryStorage {
|
|
11
|
+
mapping(bytes32 ccid => bytes32[] credentialTypeIds) credentialTypeIdsByCCID;
|
|
12
|
+
mapping(bytes32 ccid => mapping(bytes32 credentialTypeId => Credential credentials)) credentials;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// keccak256(abi.encode(uint256(keccak256("cross-chain-identity.CredentialRegistry")) - 1)) &
|
|
16
|
+
// ~bytes32(uint256(0xff))
|
|
17
|
+
// solhint-disable-next-line const-name-snakecase
|
|
18
|
+
bytes32 private constant credentialRegistryStorageLocation =
|
|
19
|
+
0xda878a21d431ff897bdb535b211ae68088a4b0265066b239bc4db2e51d9a8200;
|
|
20
|
+
|
|
21
|
+
function _credentialRegistryStorage() private pure returns (CredentialRegistryStorage storage $) {
|
|
22
|
+
// solhint-disable-next-line no-inline-assembly
|
|
23
|
+
assembly {
|
|
24
|
+
$.slot := credentialRegistryStorageLocation
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @dev Initializes the credential registry and sets the policy engine.
|
|
30
|
+
* @param policyEngine The address of the policy engine contract.
|
|
31
|
+
* @param initialOwner The address that will own the newly created registry contract.
|
|
32
|
+
*/
|
|
33
|
+
function initialize(address policyEngine, address initialOwner) public virtual initializer {
|
|
34
|
+
__CredentialRegistry_init(policyEngine, initialOwner);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function __CredentialRegistry_init(address policyEngine, address initialOwner) internal onlyInitializing {
|
|
38
|
+
__CredentialRegistry_init_unchained();
|
|
39
|
+
__PolicyProtected_init(initialOwner, policyEngine);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// solhint-disable-next-line no-empty-blocks
|
|
43
|
+
function __CredentialRegistry_init_unchained() internal onlyInitializing {}
|
|
44
|
+
|
|
45
|
+
/// @inheritdoc ICredentialRegistry
|
|
46
|
+
function registerCredential(
|
|
47
|
+
bytes32 ccid,
|
|
48
|
+
bytes32 credentialTypeId,
|
|
49
|
+
uint40 expiresAt,
|
|
50
|
+
bytes calldata credentialData,
|
|
51
|
+
bytes calldata context
|
|
52
|
+
)
|
|
53
|
+
public
|
|
54
|
+
virtual
|
|
55
|
+
override
|
|
56
|
+
runPolicyWithContext(context)
|
|
57
|
+
{
|
|
58
|
+
if (expiresAt > 0 && expiresAt <= block.timestamp) {
|
|
59
|
+
revert InvalidCredentialConfiguration("Invalid expiration time");
|
|
60
|
+
}
|
|
61
|
+
_registerCredential(ccid, credentialTypeId, expiresAt, credentialData);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// @inheritdoc ICredentialRegistry
|
|
65
|
+
function registerCredentials(
|
|
66
|
+
bytes32 ccid,
|
|
67
|
+
bytes32[] calldata credentialTypeIds,
|
|
68
|
+
uint40 expiresAt,
|
|
69
|
+
bytes[] calldata credentialDatas,
|
|
70
|
+
bytes calldata context
|
|
71
|
+
)
|
|
72
|
+
public
|
|
73
|
+
virtual
|
|
74
|
+
override
|
|
75
|
+
runPolicyWithContext(context)
|
|
76
|
+
{
|
|
77
|
+
if (credentialTypeIds.length == 0 || credentialTypeIds.length != credentialDatas.length) {
|
|
78
|
+
revert InvalidCredentialConfiguration("Invalid input length");
|
|
79
|
+
}
|
|
80
|
+
if (expiresAt > 0 && expiresAt <= block.timestamp) {
|
|
81
|
+
revert InvalidCredentialConfiguration("Invalid expiration time");
|
|
82
|
+
}
|
|
83
|
+
for (uint256 i = 0; i < credentialTypeIds.length; i++) {
|
|
84
|
+
_registerCredential(ccid, credentialTypeIds[i], expiresAt, credentialDatas[i]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// @inheritdoc ICredentialRegistry
|
|
89
|
+
function removeCredential(
|
|
90
|
+
bytes32 ccid,
|
|
91
|
+
bytes32 credentialTypeId,
|
|
92
|
+
bytes calldata context
|
|
93
|
+
)
|
|
94
|
+
public
|
|
95
|
+
virtual
|
|
96
|
+
override
|
|
97
|
+
runPolicyWithContext(context)
|
|
98
|
+
{
|
|
99
|
+
uint256 length = _credentialRegistryStorage().credentialTypeIdsByCCID[ccid].length;
|
|
100
|
+
for (uint256 i = 0; i < length; i++) {
|
|
101
|
+
if (_credentialRegistryStorage().credentialTypeIdsByCCID[ccid][i] == credentialTypeId) {
|
|
102
|
+
_credentialRegistryStorage().credentialTypeIdsByCCID[ccid][i] =
|
|
103
|
+
_credentialRegistryStorage().credentialTypeIdsByCCID[ccid][length - 1];
|
|
104
|
+
_credentialRegistryStorage().credentialTypeIdsByCCID[ccid].pop();
|
|
105
|
+
delete _credentialRegistryStorage().credentials[ccid][credentialTypeId];
|
|
106
|
+
|
|
107
|
+
emit CredentialRemoved(ccid, credentialTypeId);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
revert CredentialNotFound(ccid, credentialTypeId);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// @inheritdoc ICredentialRegistry
|
|
115
|
+
function renewCredential(
|
|
116
|
+
bytes32 ccid,
|
|
117
|
+
bytes32 credentialTypeId,
|
|
118
|
+
uint40 expiresAt,
|
|
119
|
+
bytes calldata context
|
|
120
|
+
)
|
|
121
|
+
public
|
|
122
|
+
virtual
|
|
123
|
+
override
|
|
124
|
+
runPolicyWithContext(context)
|
|
125
|
+
{
|
|
126
|
+
if (expiresAt > 0 && expiresAt <= block.timestamp) {
|
|
127
|
+
revert InvalidCredentialConfiguration("Invalid expiration time");
|
|
128
|
+
}
|
|
129
|
+
uint256 length = _credentialRegistryStorage().credentialTypeIdsByCCID[ccid].length;
|
|
130
|
+
for (uint256 i = 0; i < length; i++) {
|
|
131
|
+
if (_credentialRegistryStorage().credentialTypeIdsByCCID[ccid][i] == credentialTypeId) {
|
|
132
|
+
uint40 currentExpiresAt = _credentialRegistryStorage().credentials[ccid][credentialTypeId].expiresAt;
|
|
133
|
+
|
|
134
|
+
_credentialRegistryStorage().credentials[ccid][credentialTypeId].expiresAt = expiresAt;
|
|
135
|
+
emit CredentialRenewed(ccid, credentialTypeId, currentExpiresAt, expiresAt);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
revert CredentialNotFound(ccid, credentialTypeId);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function isCredentialExpired(bytes32 ccid, bytes32 credentialTypeId) public view returns (bool) {
|
|
143
|
+
return _credentialRegistryStorage().credentials[ccid][credentialTypeId].expiresAt > 0
|
|
144
|
+
&& _credentialRegistryStorage().credentials[ccid][credentialTypeId].expiresAt <= block.timestamp;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// @inheritdoc ICredentialRegistry
|
|
148
|
+
function getCredentialTypes(bytes32 ccid) public view virtual override returns (bytes32[] memory) {
|
|
149
|
+
return _credentialRegistryStorage().credentialTypeIdsByCCID[ccid];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/// @inheritdoc ICredentialRegistry
|
|
153
|
+
function getCredential(bytes32 ccid, bytes32 credentialTypeId) public view returns (Credential memory) {
|
|
154
|
+
for (uint256 i = 0; i < _credentialRegistryStorage().credentialTypeIdsByCCID[ccid].length; i++) {
|
|
155
|
+
if (_credentialRegistryStorage().credentialTypeIdsByCCID[ccid][i] == credentialTypeId) {
|
|
156
|
+
return _credentialRegistryStorage().credentials[ccid][credentialTypeId];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
revert CredentialNotFound(ccid, credentialTypeId);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/// @inheritdoc ICredentialRegistry
|
|
163
|
+
function getCredentials(
|
|
164
|
+
bytes32 ccid,
|
|
165
|
+
bytes32[] calldata credentialTypeIds
|
|
166
|
+
)
|
|
167
|
+
external
|
|
168
|
+
view
|
|
169
|
+
returns (Credential[] memory)
|
|
170
|
+
{
|
|
171
|
+
uint8 length = uint8(credentialTypeIds.length);
|
|
172
|
+
Credential[] memory credentials = new Credential[](length);
|
|
173
|
+
for (uint256 i = 0; i < length; i++) {
|
|
174
|
+
credentials[i] = getCredential(ccid, credentialTypeIds[i]);
|
|
175
|
+
}
|
|
176
|
+
return credentials;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/// @inheritdoc ICredentialValidator
|
|
180
|
+
function validate(
|
|
181
|
+
bytes32 ccid,
|
|
182
|
+
bytes32 credentialTypeId,
|
|
183
|
+
bytes calldata context
|
|
184
|
+
)
|
|
185
|
+
public
|
|
186
|
+
view
|
|
187
|
+
virtual
|
|
188
|
+
override
|
|
189
|
+
returns (bool)
|
|
190
|
+
{
|
|
191
|
+
return _validate(ccid, credentialTypeId, context);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// @inheritdoc ICredentialValidator
|
|
195
|
+
function validateAll(
|
|
196
|
+
bytes32 ccid,
|
|
197
|
+
bytes32[] calldata credentialTypeIds,
|
|
198
|
+
bytes calldata context
|
|
199
|
+
)
|
|
200
|
+
public
|
|
201
|
+
view
|
|
202
|
+
virtual
|
|
203
|
+
override
|
|
204
|
+
returns (bool)
|
|
205
|
+
{
|
|
206
|
+
for (uint256 i = 0; i < credentialTypeIds.length; i++) {
|
|
207
|
+
if (!_validate(ccid, credentialTypeIds[i], context)) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function _validate(bytes32 ccid, bytes32 credentialTypeId, bytes calldata /*context*/ ) internal view returns (bool) {
|
|
215
|
+
uint256 length = _credentialRegistryStorage().credentialTypeIdsByCCID[ccid].length;
|
|
216
|
+
for (uint256 i = 0; i < length; i++) {
|
|
217
|
+
if (_credentialRegistryStorage().credentialTypeIdsByCCID[ccid][i] == credentialTypeId) {
|
|
218
|
+
return (
|
|
219
|
+
_credentialRegistryStorage().credentials[ccid][credentialTypeId].expiresAt == 0
|
|
220
|
+
|| _credentialRegistryStorage().credentials[ccid][credentialTypeId].expiresAt > block.timestamp
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function _registerCredential(
|
|
228
|
+
bytes32 ccid,
|
|
229
|
+
bytes32 credentialTypeId,
|
|
230
|
+
uint40 expiresAt,
|
|
231
|
+
bytes calldata credentialData
|
|
232
|
+
)
|
|
233
|
+
internal
|
|
234
|
+
{
|
|
235
|
+
uint256 length = _credentialRegistryStorage().credentialTypeIdsByCCID[ccid].length;
|
|
236
|
+
for (uint256 i = 0; i < length; i++) {
|
|
237
|
+
if (_credentialRegistryStorage().credentialTypeIdsByCCID[ccid][i] == credentialTypeId) {
|
|
238
|
+
revert CredentialAlreadyRegistered(ccid, credentialTypeId);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
_credentialRegistryStorage().credentialTypeIdsByCCID[ccid].push(credentialTypeId);
|
|
242
|
+
_credentialRegistryStorage().credentials[ccid][credentialTypeId] = Credential(expiresAt, credentialData);
|
|
243
|
+
emit CredentialRegistered(ccid, credentialTypeId, expiresAt, credentialData);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {ICredentialRequirements} from "./interfaces/ICredentialRequirements.sol";
|
|
5
|
+
import {IIdentityValidator} from "./interfaces/IIdentityValidator.sol";
|
|
6
|
+
import {ICredentialDataValidator} from "./interfaces/ICredentialDataValidator.sol";
|
|
7
|
+
import {IIdentityRegistry} from "./interfaces/IIdentityRegistry.sol";
|
|
8
|
+
import {ICredentialRegistry} from "./interfaces/ICredentialRegistry.sol";
|
|
9
|
+
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
10
|
+
|
|
11
|
+
contract CredentialRegistryIdentityValidator is OwnableUpgradeable, ICredentialRequirements, IIdentityValidator {
|
|
12
|
+
uint256 private constant MAX_REQUIREMENTS = 8;
|
|
13
|
+
uint256 private constant MAX_REQUIREMENT_SOURCES = 8;
|
|
14
|
+
|
|
15
|
+
/// @custom:storage-location erc7201:cross-chain-identity.CredentialRegistryIdentityValidator
|
|
16
|
+
struct CredentialRegistryIdentityValidatorStorage {
|
|
17
|
+
bytes32[] requirements;
|
|
18
|
+
mapping(bytes32 requirementId => CredentialRequirement credentialRequirement) credentialRequirementMap;
|
|
19
|
+
mapping(bytes32 credential => CredentialSource[] sources) credentialSources;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// keccak256(abi.encode(uint256(keccak256("cross-chain-identity.CredentialRegistryIdentityValidator")) - 1)) &
|
|
23
|
+
// ~bytes32(uint256(0xff))
|
|
24
|
+
// solhint-disable-next-line const-name-snakecase
|
|
25
|
+
bytes32 private constant credentialRegistryIdentityValidatorStorageLocation =
|
|
26
|
+
0xc27301a28eb510a5458d7558b8bccbf4cdde3a4546d3bf041997133950e7d200;
|
|
27
|
+
|
|
28
|
+
function _credentialRegistryIdentityValidatorStorage()
|
|
29
|
+
private
|
|
30
|
+
pure
|
|
31
|
+
returns (CredentialRegistryIdentityValidatorStorage storage $)
|
|
32
|
+
{
|
|
33
|
+
// solhint-disable-next-line no-inline-assembly
|
|
34
|
+
assembly {
|
|
35
|
+
$.slot := credentialRegistryIdentityValidatorStorageLocation
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @dev Initializes the credential validator and sets the initial credential sources and requirements.
|
|
41
|
+
* @param credentialSourceInputs The credential sources to add.
|
|
42
|
+
* @param credentialRequirementInputs The credential requirements to add.
|
|
43
|
+
*/
|
|
44
|
+
function initialize(
|
|
45
|
+
CredentialSourceInput[] memory credentialSourceInputs,
|
|
46
|
+
CredentialRequirementInput[] memory credentialRequirementInputs
|
|
47
|
+
)
|
|
48
|
+
public
|
|
49
|
+
virtual
|
|
50
|
+
initializer
|
|
51
|
+
{
|
|
52
|
+
__CredentialRegistryIdentitityValidator_init(credentialSourceInputs, credentialRequirementInputs);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function __CredentialRegistryIdentitityValidator_init(
|
|
56
|
+
CredentialSourceInput[] memory credentialSourceInputs,
|
|
57
|
+
CredentialRequirementInput[] memory credentialRequirementInputs
|
|
58
|
+
)
|
|
59
|
+
internal
|
|
60
|
+
onlyInitializing
|
|
61
|
+
{
|
|
62
|
+
__Ownable_init(msg.sender);
|
|
63
|
+
__CredentialRegistryIdentitityValidator_init_unchained(credentialSourceInputs, credentialRequirementInputs);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function __CredentialRegistryIdentitityValidator_init_unchained(
|
|
67
|
+
CredentialSourceInput[] memory credentialSourceInputs,
|
|
68
|
+
CredentialRequirementInput[] memory credentialRequirementInputs
|
|
69
|
+
)
|
|
70
|
+
internal
|
|
71
|
+
onlyInitializing
|
|
72
|
+
{
|
|
73
|
+
uint256 length = credentialSourceInputs.length;
|
|
74
|
+
for (uint256 i = 0; i < length; i++) {
|
|
75
|
+
_addCredentialSource(credentialSourceInputs[i]);
|
|
76
|
+
}
|
|
77
|
+
length = credentialRequirementInputs.length;
|
|
78
|
+
for (uint256 i = 0; i < length; i++) {
|
|
79
|
+
_addCredentialRequirement(credentialRequirementInputs[i]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function _addCredentialRequirement(CredentialRequirementInput memory input) internal {
|
|
84
|
+
uint256 minValidations = input.minValidations;
|
|
85
|
+
if (minValidations == 0) {
|
|
86
|
+
revert InvalidRequirementConfiguration("minValidations must be greater than 0");
|
|
87
|
+
}
|
|
88
|
+
uint256 length = _credentialRegistryIdentityValidatorStorage().requirements.length;
|
|
89
|
+
if (length >= MAX_REQUIREMENTS) {
|
|
90
|
+
revert InvalidRequirementConfiguration("Max requirements reached");
|
|
91
|
+
}
|
|
92
|
+
bytes32 requirementId = input.requirementId;
|
|
93
|
+
for (uint256 i = 0; i < length; i++) {
|
|
94
|
+
if (_credentialRegistryIdentityValidatorStorage().requirements[i] == requirementId) {
|
|
95
|
+
revert RequirementExists(requirementId);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
bytes32[] memory credentialTypeIds = input.credentialTypeIds;
|
|
99
|
+
_credentialRegistryIdentityValidatorStorage().requirements.push(requirementId);
|
|
100
|
+
_credentialRegistryIdentityValidatorStorage().credentialRequirementMap[requirementId] =
|
|
101
|
+
CredentialRequirement(credentialTypeIds, minValidations, input.invert);
|
|
102
|
+
emit CredentialRequirementAdded(requirementId, credentialTypeIds, minValidations, input.invert);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// @inheritdoc ICredentialRequirements
|
|
106
|
+
function addCredentialRequirement(CredentialRequirementInput memory input) public virtual override onlyOwner {
|
|
107
|
+
_addCredentialRequirement(input);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// @inheritdoc ICredentialRequirements
|
|
111
|
+
function removeCredentialRequirement(bytes32 requirementId) public virtual override onlyOwner {
|
|
112
|
+
uint256 length = _credentialRegistryIdentityValidatorStorage().requirements.length;
|
|
113
|
+
for (uint256 i = 0; i < length; i++) {
|
|
114
|
+
if (_credentialRegistryIdentityValidatorStorage().requirements[i] == requirementId) {
|
|
115
|
+
_credentialRegistryIdentityValidatorStorage().requirements[i] =
|
|
116
|
+
_credentialRegistryIdentityValidatorStorage().requirements[length - 1];
|
|
117
|
+
_credentialRegistryIdentityValidatorStorage().requirements.pop();
|
|
118
|
+
|
|
119
|
+
CredentialRequirement memory requirement =
|
|
120
|
+
_credentialRegistryIdentityValidatorStorage().credentialRequirementMap[requirementId];
|
|
121
|
+
|
|
122
|
+
emit CredentialRequirementRemoved(
|
|
123
|
+
requirementId, requirement.credentialTypeIds, requirement.minValidations, requirement.invert
|
|
124
|
+
);
|
|
125
|
+
delete _credentialRegistryIdentityValidatorStorage().credentialRequirementMap[requirementId];
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
revert RequirementNotFound(requirementId);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// @inheritdoc ICredentialRequirements
|
|
133
|
+
function getCredentialRequirement(bytes32 requirementId)
|
|
134
|
+
public
|
|
135
|
+
view
|
|
136
|
+
virtual
|
|
137
|
+
override
|
|
138
|
+
returns (CredentialRequirement memory)
|
|
139
|
+
{
|
|
140
|
+
return _credentialRegistryIdentityValidatorStorage().credentialRequirementMap[requirementId];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// @inheritdoc ICredentialRequirements
|
|
144
|
+
function getCredentialRequirementIds() public view virtual override returns (bytes32[] memory) {
|
|
145
|
+
return _credentialRegistryIdentityValidatorStorage().requirements;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function _addCredentialSource(CredentialSourceInput memory input) internal {
|
|
149
|
+
address identityRegistry = input.identityRegistry;
|
|
150
|
+
address credentialRegistry = input.credentialRegistry;
|
|
151
|
+
bytes32 credentialTypeId = input.credentialTypeId;
|
|
152
|
+
bytes32 sourceId = keccak256(abi.encodePacked(identityRegistry, credentialRegistry));
|
|
153
|
+
uint256 length = _credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId].length;
|
|
154
|
+
if (length >= MAX_REQUIREMENT_SOURCES) {
|
|
155
|
+
revert InvalidRequirementConfiguration("Max credential sources reached for credential type");
|
|
156
|
+
}
|
|
157
|
+
for (uint256 i = 0; i < length; i++) {
|
|
158
|
+
// Load the entire source struct into memory once
|
|
159
|
+
CredentialSource memory existingSource =
|
|
160
|
+
_credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId][i];
|
|
161
|
+
|
|
162
|
+
bytes32 foundSourceId =
|
|
163
|
+
keccak256(abi.encodePacked(existingSource.identityRegistry, existingSource.credentialRegistry));
|
|
164
|
+
if (foundSourceId == sourceId) {
|
|
165
|
+
revert SourceExists(credentialTypeId, identityRegistry, credentialRegistry);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
address dataValidator = input.dataValidator;
|
|
169
|
+
_credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId].push(
|
|
170
|
+
CredentialSource(identityRegistry, credentialRegistry, dataValidator)
|
|
171
|
+
);
|
|
172
|
+
emit CredentialSourceAdded(credentialTypeId, identityRegistry, credentialRegistry, dataValidator);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/// @inheritdoc ICredentialRequirements
|
|
176
|
+
function addCredentialSource(CredentialSourceInput memory input) public virtual override onlyOwner {
|
|
177
|
+
_addCredentialSource(input);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/// @inheritdoc ICredentialRequirements
|
|
181
|
+
function removeCredentialSource(
|
|
182
|
+
bytes32 credentialTypeId,
|
|
183
|
+
address identityRegistry,
|
|
184
|
+
address credentialRegistry
|
|
185
|
+
)
|
|
186
|
+
public
|
|
187
|
+
virtual
|
|
188
|
+
override
|
|
189
|
+
onlyOwner
|
|
190
|
+
{
|
|
191
|
+
bytes32 sourceId = keccak256(abi.encodePacked(identityRegistry, credentialRegistry));
|
|
192
|
+
uint256 length = _credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId].length;
|
|
193
|
+
for (uint256 i = 0; i < length; i++) {
|
|
194
|
+
// Load the entire source struct into memory once
|
|
195
|
+
CredentialSource memory existingSource =
|
|
196
|
+
_credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId][i];
|
|
197
|
+
|
|
198
|
+
bytes32 foundSourceId =
|
|
199
|
+
keccak256(abi.encodePacked(existingSource.identityRegistry, existingSource.credentialRegistry));
|
|
200
|
+
if (foundSourceId == sourceId) {
|
|
201
|
+
_credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId][i] =
|
|
202
|
+
_credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId][length - 1];
|
|
203
|
+
_credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId].pop();
|
|
204
|
+
emit CredentialSourceRemoved(
|
|
205
|
+
credentialTypeId, identityRegistry, credentialRegistry, existingSource.dataValidator
|
|
206
|
+
);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
revert CredentialSourceNotFound(credentialTypeId, identityRegistry, credentialRegistry);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// @inheritdoc ICredentialRequirements
|
|
214
|
+
function getCredentialSources(bytes32 credential) public view virtual override returns (CredentialSource[] memory) {
|
|
215
|
+
return _credentialRegistryIdentityValidatorStorage().credentialSources[credential];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/// @inheritdoc IIdentityValidator
|
|
219
|
+
function validate(address account, bytes calldata context) public view virtual override returns (bool) {
|
|
220
|
+
uint256 length = _credentialRegistryIdentityValidatorStorage().requirements.length;
|
|
221
|
+
for (uint256 i = 0; i < length; i++) {
|
|
222
|
+
if (!_validateRequirement(account, _credentialRegistryIdentityValidatorStorage().requirements[i], context)) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function _validateRequirement(
|
|
230
|
+
address account,
|
|
231
|
+
bytes32 requirementId,
|
|
232
|
+
bytes calldata context
|
|
233
|
+
)
|
|
234
|
+
internal
|
|
235
|
+
view
|
|
236
|
+
virtual
|
|
237
|
+
returns (bool)
|
|
238
|
+
{
|
|
239
|
+
CredentialRequirement memory requirement =
|
|
240
|
+
_credentialRegistryIdentityValidatorStorage().credentialRequirementMap[requirementId];
|
|
241
|
+
uint256 validations = 0;
|
|
242
|
+
for (uint256 i = 0; i < requirement.credentialTypeIds.length; i++) {
|
|
243
|
+
validations = _validateCredential(
|
|
244
|
+
account, requirement.credentialTypeIds[i], validations, requirement.minValidations, requirement.invert, context
|
|
245
|
+
);
|
|
246
|
+
if (validations >= requirement.minValidations) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function _validateCredential(
|
|
254
|
+
address account,
|
|
255
|
+
bytes32 credentialTypeId,
|
|
256
|
+
uint256 currentValidations,
|
|
257
|
+
uint256 minValidations,
|
|
258
|
+
bool invert,
|
|
259
|
+
bytes calldata context
|
|
260
|
+
)
|
|
261
|
+
internal
|
|
262
|
+
view
|
|
263
|
+
virtual
|
|
264
|
+
returns (uint256)
|
|
265
|
+
{
|
|
266
|
+
uint256 validations = currentValidations;
|
|
267
|
+
uint256 length = _credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId].length;
|
|
268
|
+
for (uint256 i = 0; i < length; i++) {
|
|
269
|
+
CredentialSource memory source =
|
|
270
|
+
_credentialRegistryIdentityValidatorStorage().credentialSources[credentialTypeId][i];
|
|
271
|
+
bytes32 ccid = IIdentityRegistry(source.identityRegistry).getIdentity(account);
|
|
272
|
+
if (ccid == 0) {
|
|
273
|
+
continue; // identity not found in this registry
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (
|
|
277
|
+
_validateCredentialWithRegistry(
|
|
278
|
+
ccid, account, source.credentialRegistry, source.dataValidator, credentialTypeId, invert, context
|
|
279
|
+
)
|
|
280
|
+
) {
|
|
281
|
+
validations++;
|
|
282
|
+
}
|
|
283
|
+
if (validations >= minValidations) {
|
|
284
|
+
return validations;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return validations;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function _validateCredentialWithRegistry(
|
|
291
|
+
bytes32 ccid,
|
|
292
|
+
address account,
|
|
293
|
+
address credentialRegistry,
|
|
294
|
+
address dataValidator,
|
|
295
|
+
bytes32 credential,
|
|
296
|
+
bool invert,
|
|
297
|
+
bytes calldata context
|
|
298
|
+
)
|
|
299
|
+
internal
|
|
300
|
+
view
|
|
301
|
+
virtual
|
|
302
|
+
returns (bool)
|
|
303
|
+
{
|
|
304
|
+
// Check if credential exists and is valid in registry
|
|
305
|
+
bool credentialExists;
|
|
306
|
+
try ICredentialRegistry(credentialRegistry).validate(ccid, credential, context) returns (bool valid) {
|
|
307
|
+
credentialExists = valid;
|
|
308
|
+
} catch {
|
|
309
|
+
// If validation throws, we return false because the credential is not valid despite the value of invert
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// For inverted credentials: return true only if credential doesn't exist
|
|
314
|
+
if (invert) {
|
|
315
|
+
return !credentialExists;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// For normal credentials: credential must exist to proceed
|
|
319
|
+
if (!credentialExists) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// No data validator means credential is valid
|
|
324
|
+
if (dataValidator == address(0)) {
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Validate credential data
|
|
329
|
+
bytes memory credentialData = ICredentialRegistry(credentialRegistry).getCredential(ccid, credential).credentialData;
|
|
330
|
+
|
|
331
|
+
try ICredentialDataValidator(dataValidator).validateCredentialData(
|
|
332
|
+
ccid, account, credential, credentialData, context
|
|
333
|
+
) returns (bool valid) {
|
|
334
|
+
return valid;
|
|
335
|
+
} catch {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {CredentialRegistryIdentityValidator} from "./CredentialRegistryIdentityValidator.sol";
|
|
5
|
+
import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
|
|
6
|
+
import {Policy} from "@chainlink/policy-management/core/Policy.sol";
|
|
7
|
+
import {ICredentialRequirements} from "@chainlink/cross-chain-identity/interfaces/ICredentialRequirements.sol";
|
|
8
|
+
|
|
9
|
+
contract CredentialRegistryIdentityValidatorPolicy is Policy, CredentialRegistryIdentityValidator {
|
|
10
|
+
/**
|
|
11
|
+
* @notice Configures the policy by setting up credential sources and credential requirements.
|
|
12
|
+
* @dev The `parameters` input must be the ABI encoding of two dynamic arrays:
|
|
13
|
+
* - An array of `CredentialSourceInput` structs (credential sources).
|
|
14
|
+
* - An array of `CredentialRequirementInput` structs (credential requirements).
|
|
15
|
+
*
|
|
16
|
+
* The function expects the parameters to be tightly packed together, meaning that the entire calldata
|
|
17
|
+
* should decode as `(CredentialSourceInput[], CredentialRequirementInput[])`.
|
|
18
|
+
*
|
|
19
|
+
* @param parameters ABI-encoded bytes containing two arrays: one of `CredentialSourceInput` and one of
|
|
20
|
+
* `CredentialRequirementInput`.
|
|
21
|
+
*/
|
|
22
|
+
function configure(bytes calldata parameters) internal override onlyInitializing {
|
|
23
|
+
if (parameters.length == 0) {
|
|
24
|
+
__CredentialRegistryIdentitityValidator_init_unchained(
|
|
25
|
+
new ICredentialRequirements.CredentialSourceInput[](0),
|
|
26
|
+
new ICredentialRequirements.CredentialRequirementInput[](0)
|
|
27
|
+
);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
(
|
|
32
|
+
ICredentialRequirements.CredentialSourceInput[] memory credentialSourceInputs,
|
|
33
|
+
ICredentialRequirements.CredentialRequirementInput[] memory credentialRequirementInputs
|
|
34
|
+
) = abi.decode(
|
|
35
|
+
parameters,
|
|
36
|
+
(ICredentialRequirements.CredentialSourceInput[], ICredentialRequirements.CredentialRequirementInput[])
|
|
37
|
+
);
|
|
38
|
+
// We call the init_unchained_() method to avoid calling _Ownable__init_() twice (Policy has called it before
|
|
39
|
+
// invoking configure), likely changing the owner (Policy uses the initialOwner param and IdentityValidator the
|
|
40
|
+
// msg.sender global variable).
|
|
41
|
+
__CredentialRegistryIdentitityValidator_init_unchained(credentialSourceInputs, credentialRequirementInputs);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function run(
|
|
45
|
+
address, /*caller*/
|
|
46
|
+
address, /*subject*/
|
|
47
|
+
bytes4, /*selector*/
|
|
48
|
+
bytes[] calldata parameters,
|
|
49
|
+
bytes calldata context
|
|
50
|
+
)
|
|
51
|
+
public
|
|
52
|
+
view
|
|
53
|
+
override
|
|
54
|
+
returns (IPolicyEngine.PolicyResult)
|
|
55
|
+
{
|
|
56
|
+
// expected parameters: [account(address)]
|
|
57
|
+
if (parameters.length != 1) {
|
|
58
|
+
revert IPolicyEngine.InvalidConfiguration("expected 1 parameter");
|
|
59
|
+
}
|
|
60
|
+
address account = abi.decode(parameters[0], (address));
|
|
61
|
+
|
|
62
|
+
if (!validate(account, context)) {
|
|
63
|
+
revert IPolicyEngine.PolicyRejected("account identity validation failed");
|
|
64
|
+
}
|
|
65
|
+
return IPolicyEngine.PolicyResult.Continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function supportsInterface(bytes4 interfaceId) public view override(Policy) returns (bool) {
|
|
69
|
+
return super.supportsInterface(interfaceId);
|
|
70
|
+
}
|
|
71
|
+
}
|