@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,969 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ pragma solidity 0.8.26;
3
+
4
+ import {ICredentialRequirements} from "../src/interfaces/ICredentialRequirements.sol";
5
+ import {ICredentialRegistry} from "../src/interfaces/ICredentialRegistry.sol";
6
+ import {IPolicyEngine} from "@chainlink/policy-management/interfaces/IPolicyEngine.sol";
7
+ import {IdentityRegistry} from "../src/IdentityRegistry.sol";
8
+ import {CredentialRegistry} from "../src/CredentialRegistry.sol";
9
+ import {CredentialRegistryIdentityValidator} from "../src/CredentialRegistryIdentityValidator.sol";
10
+ import {PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
11
+ import {MockCredentialDataValidator} from "./helpers/MockCredentialDataValidator.sol";
12
+ import {BaseProxyTest} from "./helpers/BaseProxyTest.sol";
13
+
14
+ contract CredentialRegistryIdentityValidatorTest is BaseProxyTest {
15
+ bytes32 public constant REQUIREMENT_KYC = keccak256("KYC");
16
+ bytes32 public constant REQUIREMENT_ACCREDITED = keccak256("ACCREDITED");
17
+ bytes32 public constant CREDENTIAL_KYC = keccak256("common.kyc");
18
+ bytes32 public constant CREDENTIAL_PEP = keccak256("common.pep");
19
+ bytes32 public constant CREDENTIAL_ACCREDITED = keccak256("common.accredited");
20
+ bytes32 public constant CREDENTIAL_INVALID_NATIONALITY = keccak256("common.invalid.nationality");
21
+ bytes32 public constant CREDENTIAL_BANK_1_KYC = keccak256("com.bank1.KYC");
22
+ bytes32 public constant CREDENTIAL_BANK_2_KYC = keccak256("com.bank2.KYC");
23
+ bytes32 public constant CREDENTIAL_BANK_1_PEP = keccak256("com.bank1.PEP");
24
+ bytes32 public constant CREDENTIAL_BANK_2_PEP = keccak256("com.bank2.PEP");
25
+ bytes32 public constant CREDENTIAL_SOURCE1_COUNTRY_A = keccak256("source1.residence.CountryA");
26
+ bytes32 public constant CREDENTIAL_SOURCE2_COUNTRY_A = keccak256("source2.residence.CountryA");
27
+ bytes32 public constant CREDENTIAL_SOURCE1_COUNTRY_B = keccak256("source1.residence.CountryB");
28
+ bytes32 public constant CREDENTIAL_SOURCE2_COUNTRY_B = keccak256("source2.residence.CountryB");
29
+ bytes32 public constant CREDENTIAL_SOURCE1_COUNTRY_C = keccak256("source1.residence.CountryC");
30
+ bytes32 public constant CREDENTIAL_SOURCE2_COUNTRY_C = keccak256("source2.residence.CountryC");
31
+ bytes32 public constant CREDENTIAL_SOURCE1_COUNTRY_D = keccak256("source1.residence.CountryD");
32
+ bytes32 public constant CREDENTIAL_SOURCE2_COUNTRY_D = keccak256("source2.residence.CountryD");
33
+ bytes32 public constant CREDENTIAL_COMMON_COUNTRY_E = keccak256("common.residence.CountryE");
34
+ bytes32 public constant CREDENTIAL_COMMON_COUNTRY_F = keccak256("common.residence.CountryF");
35
+ bytes32 public constant CREDENTIAL_COMMON_COUNTRY_G = keccak256("common.residence.CountryG");
36
+
37
+ bytes32[] internal s_credentials_kyc;
38
+ bytes32[] internal s_credentials_accredited;
39
+ bytes32[] internal s_credentials_invalid_nationality;
40
+
41
+ PolicyEngine internal s_policyEngine;
42
+ IdentityRegistry internal s_identityRegistry;
43
+ CredentialRegistry internal s_credentialRegistry;
44
+ CredentialRegistryIdentityValidator internal s_identityValidator;
45
+ address internal s_owner;
46
+
47
+ function setUp() public {
48
+ s_owner = makeAddr("owner");
49
+
50
+ vm.startPrank(s_owner);
51
+
52
+ s_credentials_kyc = new bytes32[](1);
53
+ s_credentials_kyc[0] = CREDENTIAL_KYC;
54
+
55
+ s_credentials_accredited = new bytes32[](1);
56
+ s_credentials_accredited[0] = CREDENTIAL_ACCREDITED;
57
+
58
+ s_credentials_invalid_nationality = new bytes32[](1);
59
+ s_credentials_invalid_nationality[0] = CREDENTIAL_INVALID_NATIONALITY;
60
+
61
+ // Deploy PolicyEngine through proxy
62
+ s_policyEngine = _deployPolicyEngine(true, address(this));
63
+
64
+ // Deploy IdentityRegistry through proxy
65
+ s_identityRegistry = _deployIdentityRegistry(address(s_policyEngine));
66
+
67
+ // Deploy CredentialRegistry through proxy
68
+ s_credentialRegistry = _deployCredentialRegistry(address(s_policyEngine));
69
+
70
+ // Deploy CredentialRegistryIdentityValidator through proxy
71
+ s_identityValidator = _deployCredentialRegistryIdentityValidator(
72
+ new ICredentialRequirements.CredentialSourceInput[](0),
73
+ new ICredentialRequirements.CredentialRequirementInput[](0)
74
+ );
75
+
76
+ s_identityValidator.addCredentialRequirement(
77
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_KYC, s_credentials_kyc, 1, false)
78
+ );
79
+ s_identityValidator.addCredentialSource(
80
+ ICredentialRequirements.CredentialSourceInput(
81
+ CREDENTIAL_KYC, address(s_identityRegistry), address(s_credentialRegistry), address(0)
82
+ )
83
+ );
84
+ }
85
+
86
+ function test_validate_success() public {
87
+ address account1 = makeAddr("account1");
88
+ bytes32 ccid = keccak256("account1");
89
+
90
+ s_identityRegistry.registerIdentity(ccid, account1, "");
91
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, 0, "", "");
92
+
93
+ assertTrue(s_identityValidator.validate(account1, ""));
94
+ }
95
+
96
+ function test_validate_altKyc_success() public {
97
+ address account1 = makeAddr("account1");
98
+ bytes32 ccid = keccak256("account1");
99
+
100
+ // switch credentialValidator requirement to be either type of KYC
101
+ s_credentials_kyc = new bytes32[](2);
102
+ s_credentials_kyc[0] = CREDENTIAL_KYC;
103
+ s_credentials_kyc[1] = CREDENTIAL_BANK_2_KYC;
104
+ s_identityValidator.removeCredentialRequirement(REQUIREMENT_KYC);
105
+ s_identityValidator.addCredentialRequirement(
106
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_KYC, s_credentials_kyc, 1, false)
107
+ );
108
+ // new kyc type can also be validated at the same registry
109
+ s_identityValidator.addCredentialSource(
110
+ ICredentialRequirements.CredentialSourceInput(
111
+ CREDENTIAL_BANK_2_KYC, address(s_identityRegistry), address(s_credentialRegistry), address(0)
112
+ )
113
+ );
114
+
115
+ s_identityRegistry.registerIdentity(ccid, account1, "");
116
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_BANK_2_KYC, 0, "", "");
117
+
118
+ assertTrue(s_identityValidator.validate(account1, ""));
119
+ }
120
+
121
+ function test_validate_futureExpires_success() public {
122
+ address account1 = makeAddr("account1");
123
+ bytes32 ccid = keccak256("account1");
124
+
125
+ s_identityRegistry.registerIdentity(ccid, account1, "");
126
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, uint40(block.timestamp + 30), "", "");
127
+
128
+ vm.warp(block.timestamp + 10);
129
+
130
+ assertTrue(s_identityValidator.validate(account1, ""));
131
+ }
132
+
133
+ function test_validate_expired_invalid() public {
134
+ address account1 = makeAddr("account1");
135
+ bytes32 ccid = keccak256("account1");
136
+
137
+ s_identityRegistry.registerIdentity(ccid, account1, "");
138
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, uint40(block.timestamp + 2), "", "");
139
+
140
+ vm.warp(block.timestamp + 10);
141
+
142
+ assertFalse(s_identityValidator.validate(account1, ""));
143
+ }
144
+
145
+ function test_validate_renew_success() public {
146
+ address account1 = makeAddr("account1");
147
+ bytes32 ccid = keccak256("account1");
148
+
149
+ s_identityRegistry.registerIdentity(ccid, account1, "");
150
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, uint40(block.timestamp + 2), "", "");
151
+
152
+ vm.warp(block.timestamp + 10);
153
+
154
+ assertFalse(s_identityValidator.validate(account1, ""));
155
+
156
+ s_credentialRegistry.renewCredential(ccid, CREDENTIAL_KYC, uint40(block.timestamp + 30), "");
157
+ vm.warp(block.timestamp + 10);
158
+
159
+ assertTrue(s_identityValidator.validate(account1, ""));
160
+ }
161
+
162
+ function test_validate_unknownIdentity_invalid() public {
163
+ address account1 = makeAddr("account1");
164
+
165
+ assertFalse(s_identityValidator.validate(account1, ""));
166
+ }
167
+
168
+ function test_validate_missingCredential_invalid() public {
169
+ address account1 = makeAddr("account1");
170
+ bytes32 ccid = keccak256("account1");
171
+
172
+ s_identityRegistry.registerIdentity(ccid, account1, "");
173
+
174
+ assertFalse(s_identityValidator.validate(account1, ""));
175
+ }
176
+
177
+ function test_validate_multiSource_success() public {
178
+ address account1 = makeAddr("account1");
179
+ bytes32 ccid = keccak256("account1");
180
+
181
+ s_identityValidator.addCredentialRequirement(
182
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_ACCREDITED, s_credentials_accredited, 1, false)
183
+ );
184
+
185
+ IdentityRegistry identityRegistry2 = _deployIdentityRegistry(address(s_policyEngine));
186
+ vm.label(address(identityRegistry2), "IdentityRegistry2");
187
+ CredentialRegistry credentialRegistry2 = _deployCredentialRegistry(address(s_policyEngine));
188
+ vm.label(address(credentialRegistry2), "CredentialRegistry2");
189
+
190
+ s_identityValidator.addCredentialSource(
191
+ ICredentialRequirements.CredentialSourceInput(
192
+ CREDENTIAL_ACCREDITED, address(identityRegistry2), address(credentialRegistry2), address(0)
193
+ )
194
+ );
195
+
196
+ s_identityRegistry.registerIdentity(ccid, account1, "");
197
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, 0, "", "");
198
+
199
+ identityRegistry2.registerIdentity(ccid, account1, "");
200
+ credentialRegistry2.registerCredential(ccid, CREDENTIAL_ACCREDITED, 0, "", "");
201
+
202
+ assertTrue(s_identityValidator.validate(account1, ""));
203
+ }
204
+
205
+ function test_validate_multiSourceMissingCredential_invalid() public {
206
+ address account1 = makeAddr("account1");
207
+ bytes32 ccid = keccak256("account1");
208
+
209
+ s_identityValidator.addCredentialRequirement(
210
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_ACCREDITED, s_credentials_accredited, 1, false)
211
+ );
212
+
213
+ IdentityRegistry identityRegistry2 = _deployIdentityRegistry(address(s_policyEngine));
214
+ vm.label(address(identityRegistry2), "IdentityRegistry2");
215
+ CredentialRegistry credentialRegistry2 = _deployCredentialRegistry(address(s_policyEngine));
216
+ vm.label(address(credentialRegistry2), "CredentialRegistry2");
217
+
218
+ s_identityValidator.addCredentialSource(
219
+ ICredentialRequirements.CredentialSourceInput(
220
+ CREDENTIAL_ACCREDITED, address(identityRegistry2), address(credentialRegistry2), address(0)
221
+ )
222
+ );
223
+
224
+ identityRegistry2.registerIdentity(ccid, account1, "");
225
+ credentialRegistry2.registerCredential(ccid, CREDENTIAL_ACCREDITED, 0, "", "");
226
+
227
+ assertFalse(s_identityValidator.validate(account1, ""));
228
+ }
229
+
230
+ function test_validate_multiSource_multiCredential_success() public {
231
+ address account1 = makeAddr("account1");
232
+ bytes32 ccid = keccak256("account1");
233
+
234
+ s_identityValidator.addCredentialRequirement(
235
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_ACCREDITED, s_credentials_accredited, 2, false)
236
+ );
237
+
238
+ IdentityRegistry identityRegistry2 = _deployIdentityRegistry(address(s_policyEngine));
239
+ vm.label(address(identityRegistry2), "IdentityRegistry2");
240
+ CredentialRegistry credentialRegistry2 = _deployCredentialRegistry(address(s_policyEngine));
241
+ vm.label(address(credentialRegistry2), "CredentialRegistry2");
242
+
243
+ s_identityValidator.addCredentialSource(
244
+ ICredentialRequirements.CredentialSourceInput(
245
+ CREDENTIAL_ACCREDITED, address(s_identityRegistry), address(s_credentialRegistry), address(0)
246
+ )
247
+ );
248
+ s_identityValidator.addCredentialSource(
249
+ ICredentialRequirements.CredentialSourceInput(
250
+ CREDENTIAL_ACCREDITED, address(identityRegistry2), address(credentialRegistry2), address(0)
251
+ )
252
+ );
253
+
254
+ s_identityRegistry.registerIdentity(ccid, account1, "");
255
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, 0, "", "");
256
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_ACCREDITED, 0, "", "");
257
+
258
+ identityRegistry2.registerIdentity(ccid, account1, "");
259
+ credentialRegistry2.registerCredential(ccid, CREDENTIAL_ACCREDITED, 0, "", "");
260
+
261
+ assertTrue(s_identityValidator.validate(account1, ""));
262
+ }
263
+
264
+ function test_validate_multiSource_multiCredentialMissing_invalid() public {
265
+ address account1 = makeAddr("account1");
266
+ bytes32 ccid = keccak256("account1");
267
+
268
+ s_identityValidator.addCredentialRequirement(
269
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_ACCREDITED, s_credentials_accredited, 2, false)
270
+ );
271
+
272
+ IdentityRegistry identityRegistry2 = _deployIdentityRegistry(address(s_policyEngine));
273
+ vm.label(address(identityRegistry2), "IdentityRegistry2");
274
+ CredentialRegistry credentialRegistry2 = _deployCredentialRegistry(address(s_policyEngine));
275
+ vm.label(address(credentialRegistry2), "CredentialRegistry2");
276
+
277
+ s_identityValidator.addCredentialSource(
278
+ ICredentialRequirements.CredentialSourceInput(
279
+ CREDENTIAL_ACCREDITED, address(s_identityRegistry), address(s_credentialRegistry), address(0)
280
+ )
281
+ );
282
+ s_identityValidator.addCredentialSource(
283
+ ICredentialRequirements.CredentialSourceInput(
284
+ CREDENTIAL_ACCREDITED, address(identityRegistry2), address(credentialRegistry2), address(0)
285
+ )
286
+ );
287
+
288
+ // no ACCREDITED credential in this registry
289
+ s_identityRegistry.registerIdentity(ccid, account1, "");
290
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, 0, "", "");
291
+
292
+ identityRegistry2.registerIdentity(ccid, account1, "");
293
+ credentialRegistry2.registerCredential(ccid, CREDENTIAL_ACCREDITED, 0, "", "");
294
+
295
+ assertFalse(s_identityValidator.validate(account1, ""));
296
+ }
297
+
298
+ function test_credentialRole_success() public {
299
+ bytes32 ccid = keccak256("account1");
300
+
301
+ CredentialRegistry credentialRegistry2 = _deployCredentialRegistry(address(s_policyEngine));
302
+ vm.label(address(credentialRegistry2), "CredentialRegistry2");
303
+
304
+ vm.expectEmit();
305
+ emit ICredentialRegistry.CredentialRegistered(ccid, CREDENTIAL_ACCREDITED, 0, "");
306
+
307
+ credentialRegistry2.registerCredential(ccid, CREDENTIAL_ACCREDITED, 0, "", "");
308
+ }
309
+
310
+ function test_validate_credentialRequirementInvert_invalid() public {
311
+ address account1 = makeAddr("account1");
312
+ bytes32 ccid = keccak256("account1");
313
+
314
+ s_identityRegistry.registerIdentity(ccid, account1, "");
315
+
316
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, 0, "", "");
317
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_INVALID_NATIONALITY, 0, "", "");
318
+
319
+ s_identityValidator.addCredentialRequirement(
320
+ ICredentialRequirements.CredentialRequirementInput(
321
+ CREDENTIAL_INVALID_NATIONALITY, s_credentials_invalid_nationality, 1, true
322
+ )
323
+ );
324
+ s_identityValidator.addCredentialSource(
325
+ ICredentialRequirements.CredentialSourceInput(
326
+ CREDENTIAL_INVALID_NATIONALITY, address(s_identityRegistry), address(s_credentialRegistry), address(0)
327
+ )
328
+ );
329
+
330
+ assertFalse(s_identityValidator.validate(account1, ""));
331
+ }
332
+
333
+ function test_validate_credentialRequirementInvertCredentialExists_invalid() public {
334
+ address account1 = makeAddr("account1");
335
+ bytes32 ccid = keccak256("account1");
336
+
337
+ bytes32 requirement = keccak256("mock requirement");
338
+ bytes32[] memory credential_ids = new bytes32[](1);
339
+ credential_ids[0] = keccak256("mock credential type");
340
+
341
+ s_identityValidator.addCredentialRequirement(
342
+ ICredentialRequirements.CredentialRequirementInput(requirement, credential_ids, 1, true)
343
+ );
344
+ s_identityValidator.addCredentialSource(
345
+ ICredentialRequirements.CredentialSourceInput(
346
+ credential_ids[0], address(s_identityRegistry), address(s_credentialRegistry), address(0)
347
+ )
348
+ );
349
+
350
+ s_identityRegistry.registerIdentity(ccid, account1, "");
351
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, 0, "", "");
352
+ s_credentialRegistry.registerCredential(ccid, credential_ids[0], 0, abi.encode("mock data"), "");
353
+
354
+ // For inverted credentials: if credential exists in registry, validation fails (no data validation performed)
355
+ assertFalse(s_identityValidator.validate(account1, ""));
356
+ }
357
+
358
+ function test_validate_credentialRequirementInvertNotPresent_succeeds() public {
359
+ address account1 = makeAddr("account1");
360
+ bytes32 ccid = keccak256("account1");
361
+
362
+ s_identityRegistry.registerIdentity(ccid, account1, "");
363
+
364
+ s_credentialRegistry.registerCredential(ccid, CREDENTIAL_KYC, 0, "", "");
365
+
366
+ s_identityValidator.addCredentialRequirement(
367
+ ICredentialRequirements.CredentialRequirementInput(
368
+ CREDENTIAL_INVALID_NATIONALITY, s_credentials_invalid_nationality, 1, true
369
+ )
370
+ );
371
+ s_identityValidator.addCredentialSource(
372
+ ICredentialRequirements.CredentialSourceInput(
373
+ CREDENTIAL_INVALID_NATIONALITY, address(s_identityRegistry), address(s_credentialRegistry), address(0)
374
+ )
375
+ );
376
+
377
+ assertTrue(s_identityValidator.validate(account1, ""));
378
+ }
379
+
380
+ function test_validate_invertCredentialRequirementNotPresentButOtherCredentialMissing_invalid() public {
381
+ address account1 = makeAddr("account1");
382
+ bytes32 ccid = keccak256("account1");
383
+
384
+ s_identityRegistry.registerIdentity(ccid, account1, "");
385
+
386
+ s_identityValidator.addCredentialRequirement(
387
+ ICredentialRequirements.CredentialRequirementInput(
388
+ CREDENTIAL_INVALID_NATIONALITY, s_credentials_invalid_nationality, 1, true
389
+ )
390
+ );
391
+ s_identityValidator.addCredentialSource(
392
+ ICredentialRequirements.CredentialSourceInput(
393
+ CREDENTIAL_INVALID_NATIONALITY, address(s_identityRegistry), address(s_credentialRegistry), address(0)
394
+ )
395
+ );
396
+
397
+ assertFalse(s_identityValidator.validate(account1, ""));
398
+ }
399
+
400
+ function test_addCredentialRequirement_zeroMinValidations_invalid() public {
401
+ vm.expectRevert();
402
+ s_identityValidator.addCredentialRequirement(
403
+ ICredentialRequirements.CredentialRequirementInput(
404
+ CREDENTIAL_INVALID_NATIONALITY, s_credentials_invalid_nationality, 0, false
405
+ )
406
+ );
407
+ }
408
+
409
+ function test_getCredentialRequirement_success() public {
410
+ s_credentials_kyc = new bytes32[](2);
411
+ s_credentials_kyc[0] = CREDENTIAL_KYC;
412
+ s_credentials_kyc[1] = CREDENTIAL_BANK_2_KYC;
413
+ s_identityValidator.removeCredentialRequirement(REQUIREMENT_KYC);
414
+ s_identityValidator.addCredentialRequirement(
415
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_KYC, s_credentials_kyc, 1, false)
416
+ );
417
+
418
+ ICredentialRequirements.CredentialRequirement memory credRequirement =
419
+ s_identityValidator.getCredentialRequirement(REQUIREMENT_KYC);
420
+ assert(credRequirement.minValidations == 1);
421
+ assert(credRequirement.credentialTypeIds[0] == CREDENTIAL_KYC);
422
+ assert(credRequirement.credentialTypeIds[1] == CREDENTIAL_BANK_2_KYC);
423
+ assert(credRequirement.invert == false);
424
+ }
425
+
426
+ function test_getCredentialRequirement_duplicated_failure() public {
427
+ s_credentials_kyc = new bytes32[](2);
428
+ s_credentials_kyc[0] = CREDENTIAL_KYC;
429
+ s_credentials_kyc[1] = CREDENTIAL_BANK_2_KYC;
430
+
431
+ vm.expectPartialRevert(ICredentialRequirements.RequirementExists.selector);
432
+ s_identityValidator.addCredentialRequirement(
433
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_KYC, s_credentials_kyc, 1, false)
434
+ );
435
+ }
436
+
437
+ function test_getCredentialRequirementIds_success() public {
438
+ s_credentials_kyc = new bytes32[](2);
439
+ s_credentials_kyc[0] = CREDENTIAL_KYC;
440
+ s_credentials_kyc[1] = CREDENTIAL_BANK_2_KYC;
441
+ s_identityValidator.removeCredentialRequirement(REQUIREMENT_KYC);
442
+ s_identityValidator.addCredentialRequirement(
443
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_KYC, s_credentials_kyc, 1, false)
444
+ );
445
+
446
+ bytes32[] memory requirementIds = s_identityValidator.getCredentialRequirementIds();
447
+ assert(requirementIds.length == 1);
448
+ assert(requirementIds[0] == REQUIREMENT_KYC);
449
+ }
450
+
451
+ function test_addCredentialSource_success() public {
452
+ s_identityValidator.addCredentialSource(
453
+ ICredentialRequirements.CredentialSourceInput(
454
+ CREDENTIAL_BANK_2_KYC, address(s_identityRegistry), address(s_credentialRegistry), address(0)
455
+ )
456
+ );
457
+
458
+ ICredentialRequirements.CredentialSource[] memory credSourcesBeforeRemoval =
459
+ s_identityValidator.getCredentialSources(CREDENTIAL_BANK_2_KYC);
460
+ assert(credSourcesBeforeRemoval.length == 1);
461
+
462
+ s_identityValidator.removeCredentialSource(
463
+ CREDENTIAL_BANK_2_KYC, address(s_identityRegistry), address(s_credentialRegistry)
464
+ );
465
+
466
+ ICredentialRequirements.CredentialSource[] memory credSourcesAfterRemoval =
467
+ s_identityValidator.getCredentialSources(CREDENTIAL_BANK_2_KYC);
468
+ assert(credSourcesAfterRemoval.length == 0);
469
+ }
470
+
471
+ function test_addCredentialSource_duplicated_failure() public {
472
+ s_identityValidator.addCredentialSource(
473
+ ICredentialRequirements.CredentialSourceInput(
474
+ CREDENTIAL_BANK_2_KYC, address(s_identityRegistry), address(s_credentialRegistry), address(0)
475
+ )
476
+ );
477
+
478
+ vm.expectPartialRevert(ICredentialRequirements.SourceExists.selector);
479
+ s_identityValidator.addCredentialSource(
480
+ ICredentialRequirements.CredentialSourceInput(
481
+ CREDENTIAL_BANK_2_KYC, address(s_identityRegistry), address(s_credentialRegistry), address(0)
482
+ )
483
+ );
484
+ }
485
+
486
+ function test_removeCredentialRequirement_notFound_failure() public {
487
+ vm.expectPartialRevert(ICredentialRequirements.RequirementNotFound.selector);
488
+ s_identityValidator.removeCredentialRequirement(keccak256("unknown"));
489
+ }
490
+
491
+ function test_removeCredentialSource_notFound_failure() public {
492
+ vm.expectPartialRevert(ICredentialRequirements.CredentialSourceNotFound.selector);
493
+ s_identityValidator.removeCredentialSource(
494
+ CREDENTIAL_BANK_2_KYC, address(s_identityRegistry), address(s_credentialRegistry)
495
+ );
496
+ }
497
+
498
+ function test_requireKYC_and_rejectPEP() public {
499
+ CredentialRegistryIdentityValidator validator = _deployCredentialRegistryIdentityValidator(
500
+ new ICredentialRequirements.CredentialSourceInput[](0),
501
+ new ICredentialRequirements.CredentialRequirementInput[](0)
502
+ );
503
+
504
+ IdentityRegistry identityReg = _deployIdentityRegistry(address(s_policyEngine));
505
+ CredentialRegistry credentialReg = _deployCredentialRegistry(address(s_policyEngine));
506
+
507
+ bytes32[] memory kycCredentials = new bytes32[](1);
508
+ kycCredentials[0] = CREDENTIAL_KYC;
509
+ bytes32 REQUIREMENT_REQUIRE_KYC = keccak256("Require to have KYC");
510
+
511
+ validator.addCredentialSource(
512
+ ICredentialRequirements.CredentialSourceInput(
513
+ CREDENTIAL_KYC, address(identityReg), address(credentialReg), address(0)
514
+ )
515
+ );
516
+
517
+ validator.addCredentialRequirement(
518
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_REQUIRE_KYC, kycCredentials, 1, false)
519
+ );
520
+
521
+ bytes32[] memory pepCredentials = new bytes32[](1);
522
+ pepCredentials[0] = CREDENTIAL_PEP;
523
+ bytes32 REQUIREMENT_REJECT_PEP = keccak256("Reject if PEP");
524
+
525
+ validator.addCredentialSource(
526
+ ICredentialRequirements.CredentialSourceInput(
527
+ CREDENTIAL_PEP, address(identityReg), address(credentialReg), address(0)
528
+ )
529
+ );
530
+
531
+ validator.addCredentialRequirement(
532
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_REJECT_PEP, pepCredentials, 1, true)
533
+ );
534
+
535
+ address user1 = makeAddr("user1");
536
+ address user2 = makeAddr("user2");
537
+ address user3 = makeAddr("user3");
538
+ bytes32 ccid1 = keccak256("user1");
539
+ bytes32 ccid2 = keccak256("user2");
540
+ bytes32 ccid3 = keccak256("user3");
541
+
542
+ // User has KYC but is PEP, should fail
543
+ identityReg.registerIdentity(ccid1, user1, "");
544
+ credentialReg.registerCredential(ccid1, CREDENTIAL_KYC, 0, "", "");
545
+ credentialReg.registerCredential(ccid1, CREDENTIAL_PEP, 0, "", "");
546
+ assertFalse(validator.validate(user1, ""), "User with KYC but is PEP should fail");
547
+
548
+ // User has KYC and is not PEP, should pass
549
+ identityReg.registerIdentity(ccid2, user2, "");
550
+ credentialReg.registerCredential(ccid2, CREDENTIAL_KYC, 0, "", "");
551
+ assertTrue(validator.validate(user2, ""), "User with KYC and not PEP should pass");
552
+
553
+ // User is not PEP but has no KYC, should fail
554
+ identityReg.registerIdentity(ccid3, user3, "");
555
+ assertFalse(validator.validate(user3, ""), "User without KYC should fail even if not PEP");
556
+ }
557
+
558
+ /// Same logical credential, multiple sources, whitelist
559
+ /// Accept if user has KYC in any listed bank
560
+ /// Config: One requirement. credentialTypeIds = [com.bank1.KYC, com.bank2.KYC], invert = false, minValidations = 1
561
+ function test_sameLogicalCredential_multilpleSources_whitelist() public {
562
+ CredentialRegistryIdentityValidator validator = _deployCredentialRegistryIdentityValidator(
563
+ new ICredentialRequirements.CredentialSourceInput[](0),
564
+ new ICredentialRequirements.CredentialRequirementInput[](0)
565
+ );
566
+
567
+ IdentityRegistry bank1IdentityRegistry = _deployIdentityRegistry(address(s_policyEngine));
568
+ vm.label(address(bank1IdentityRegistry), "Bank1IdentityRegistry");
569
+ CredentialRegistry bank1CredentialRegistry = _deployCredentialRegistry(address(s_policyEngine));
570
+ vm.label(address(bank1CredentialRegistry), "Bank1CredentialRegistry");
571
+
572
+ IdentityRegistry bank2IdentityRegistry = _deployIdentityRegistry(address(s_policyEngine));
573
+ vm.label(address(bank2IdentityRegistry), "Bank2IdentityRegistry");
574
+ CredentialRegistry bank2CredentialRegistry = _deployCredentialRegistry(address(s_policyEngine));
575
+ vm.label(address(bank2CredentialRegistry), "Bank2CredentialRegistry");
576
+
577
+ bytes32[] memory kycCredentials = new bytes32[](2);
578
+ kycCredentials[0] = CREDENTIAL_BANK_1_KYC;
579
+ kycCredentials[1] = CREDENTIAL_BANK_2_KYC;
580
+
581
+ bytes32 REQUIREMENT_REQUIRE_ANY_KYC = keccak256("Require KYC from Bank 1 or Bank 2");
582
+
583
+ validator.addCredentialSource(
584
+ ICredentialRequirements.CredentialSourceInput(
585
+ CREDENTIAL_BANK_1_KYC, address(bank1IdentityRegistry), address(bank1CredentialRegistry), address(0)
586
+ )
587
+ );
588
+ validator.addCredentialSource(
589
+ ICredentialRequirements.CredentialSourceInput(
590
+ CREDENTIAL_BANK_2_KYC, address(bank2IdentityRegistry), address(bank2CredentialRegistry), address(0)
591
+ )
592
+ );
593
+
594
+ validator.addCredentialRequirement(
595
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_REQUIRE_ANY_KYC, kycCredentials, 1, false)
596
+ );
597
+
598
+ address user1 = makeAddr("user1");
599
+ address user2 = makeAddr("user2");
600
+ address user3 = makeAddr("user3");
601
+ bytes32 ccid1 = keccak256("user1");
602
+ bytes32 ccid2 = keccak256("user2");
603
+ bytes32 ccid3 = keccak256("user3");
604
+
605
+ //User has KYC only from 1, should pass
606
+ bank1IdentityRegistry.registerIdentity(ccid1, user1, "");
607
+ bank1CredentialRegistry.registerCredential(ccid1, CREDENTIAL_BANK_1_KYC, 0, "", "");
608
+ assertTrue(validator.validate(user1, ""), "User with only Bank 1 KYC should pass");
609
+
610
+ // User has KYC only from Bank 2, should pass
611
+ bank2IdentityRegistry.registerIdentity(ccid2, user2, "");
612
+ bank2CredentialRegistry.registerCredential(ccid2, CREDENTIAL_BANK_2_KYC, 0, "", "");
613
+ assertTrue(validator.validate(user2, ""), "User with only Bank 2 KYC should pass");
614
+
615
+ // User has KYC from both, should pass
616
+ bank1IdentityRegistry.registerIdentity(ccid3, user3, "");
617
+ bank1CredentialRegistry.registerCredential(ccid3, CREDENTIAL_BANK_1_KYC, 0, "", "");
618
+ bank2IdentityRegistry.registerIdentity(ccid3, user3, "");
619
+ bank2CredentialRegistry.registerCredential(ccid3, CREDENTIAL_BANK_2_KYC, 0, "", "");
620
+ assertTrue(validator.validate(user3, ""), "User with both Bank 1 and Bank 2 KYC should pass");
621
+
622
+ // User has no KYC, should fail
623
+ address user4 = makeAddr("user4");
624
+ assertFalse(validator.validate(user4, ""), "User with no KYC should fail");
625
+ }
626
+
627
+ function test_sameLogicalCredential_multilpleSources_whitelist_bothSourcesRequired() public {
628
+ CredentialRegistryIdentityValidator validator = _deployCredentialRegistryIdentityValidator(
629
+ new ICredentialRequirements.CredentialSourceInput[](0),
630
+ new ICredentialRequirements.CredentialRequirementInput[](0)
631
+ );
632
+
633
+ IdentityRegistry bank1IdentityRegistry = _deployIdentityRegistry(address(s_policyEngine));
634
+ vm.label(address(bank1IdentityRegistry), "Bank1IdentityRegistry");
635
+ CredentialRegistry bank1CredentialRegistry = _deployCredentialRegistry(address(s_policyEngine));
636
+ vm.label(address(bank1CredentialRegistry), "Bank1CredentialRegistry");
637
+
638
+ IdentityRegistry bank2IdentityRegistry = _deployIdentityRegistry(address(s_policyEngine));
639
+ vm.label(address(bank2IdentityRegistry), "Bank2IdentityRegistry");
640
+ CredentialRegistry bank2CredentialRegistry = _deployCredentialRegistry(address(s_policyEngine));
641
+ vm.label(address(bank2CredentialRegistry), "Bank2CredentialRegistry");
642
+
643
+ bytes32[] memory kycCredentials = new bytes32[](2);
644
+ kycCredentials[0] = CREDENTIAL_BANK_1_KYC;
645
+ kycCredentials[1] = CREDENTIAL_BANK_2_KYC;
646
+
647
+ bytes32 REQUIREMENT_REQUIRE_BOTH_KYCs = keccak256("Require KYC from Bank 1 and Bank 2");
648
+
649
+ validator.addCredentialSource(
650
+ ICredentialRequirements.CredentialSourceInput(
651
+ CREDENTIAL_BANK_1_KYC, address(bank1IdentityRegistry), address(bank1CredentialRegistry), address(0)
652
+ )
653
+ );
654
+ validator.addCredentialSource(
655
+ ICredentialRequirements.CredentialSourceInput(
656
+ CREDENTIAL_BANK_2_KYC, address(bank2IdentityRegistry), address(bank2CredentialRegistry), address(0)
657
+ )
658
+ );
659
+
660
+ validator.addCredentialRequirement(
661
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_REQUIRE_BOTH_KYCs, kycCredentials, 2, false)
662
+ );
663
+
664
+ address user1 = makeAddr("user1");
665
+ address user2 = makeAddr("user2");
666
+ bytes32 ccid1 = keccak256("user1");
667
+ bytes32 ccid2 = keccak256("user2");
668
+
669
+ // User has KYC only from Bank 1, should fail
670
+ bank1IdentityRegistry.registerIdentity(ccid1, user1, "");
671
+ bank1CredentialRegistry.registerCredential(ccid1, CREDENTIAL_BANK_1_KYC, 0, "", "");
672
+ assertFalse(validator.validate(user1, ""), "User with only 1 source should fail when minValidations = 2");
673
+
674
+ // User has KYC from both Bank 1 and Bank 2, should pass
675
+ bank1IdentityRegistry.registerIdentity(ccid2, user2, "");
676
+ bank1CredentialRegistry.registerCredential(ccid2, CREDENTIAL_BANK_1_KYC, 0, "", "");
677
+ bank2IdentityRegistry.registerIdentity(ccid2, user2, "");
678
+ bank2CredentialRegistry.registerCredential(ccid2, CREDENTIAL_BANK_2_KYC, 0, "", "");
679
+ assertTrue(validator.validate(user2, ""), "User with 2 sources should pass when minValidations = 2");
680
+ }
681
+
682
+ /// Denylist across multiple sources
683
+ /// Reject if user is PEP in any source
684
+ /// Config: One requirement. credentialTypeIds = [bank1.PEP, bank2.PEP], invert = true, minValidations = 2
685
+ function test_denylistWithMultipleSources_mustBeCleanInAllSources() public {
686
+ CredentialRegistryIdentityValidator validator = _deployCredentialRegistryIdentityValidator(
687
+ new ICredentialRequirements.CredentialSourceInput[](0),
688
+ new ICredentialRequirements.CredentialRequirementInput[](0)
689
+ );
690
+
691
+ IdentityRegistry bank1IdentityRegistry = _deployIdentityRegistry(address(s_policyEngine));
692
+ vm.label(address(bank1IdentityRegistry), "Bank1IdentityRegistry");
693
+ CredentialRegistry bank1CredentialRegistry = _deployCredentialRegistry(address(s_policyEngine));
694
+ vm.label(address(bank1CredentialRegistry), "Bank1CredentialRegistry");
695
+
696
+ IdentityRegistry bank2IdentityRegistry = _deployIdentityRegistry(address(s_policyEngine));
697
+ vm.label(address(bank2IdentityRegistry), "Bank2IdentityRegistry");
698
+ CredentialRegistry bank2CredentialRegistry = _deployCredentialRegistry(address(s_policyEngine));
699
+ vm.label(address(bank2CredentialRegistry), "Bank2CredentialRegistry");
700
+
701
+ bytes32[] memory pepCredentials = new bytes32[](2);
702
+ pepCredentials[0] = CREDENTIAL_BANK_1_PEP;
703
+ pepCredentials[1] = CREDENTIAL_BANK_2_PEP;
704
+
705
+ bytes32 REQUIREMENT_NOT_PEP = keccak256("Require not to have PEP");
706
+
707
+ validator.addCredentialSource(
708
+ ICredentialRequirements.CredentialSourceInput(
709
+ CREDENTIAL_BANK_1_PEP, address(bank1IdentityRegistry), address(bank1CredentialRegistry), address(0)
710
+ )
711
+ );
712
+ validator.addCredentialSource(
713
+ ICredentialRequirements.CredentialSourceInput(
714
+ CREDENTIAL_BANK_2_PEP, address(bank2IdentityRegistry), address(bank2CredentialRegistry), address(0)
715
+ )
716
+ );
717
+
718
+ validator.addCredentialRequirement(
719
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_NOT_PEP, pepCredentials, 2, true)
720
+ );
721
+
722
+ address user1 = makeAddr("user1");
723
+ address user2 = makeAddr("user2");
724
+ address user3 = makeAddr("user3");
725
+ address user4 = makeAddr("user4");
726
+ bytes32 ccid1 = keccak256("user1");
727
+ bytes32 ccid2 = keccak256("user2");
728
+ bytes32 ccid3 = keccak256("user3");
729
+ bytes32 ccid4 = keccak256("user4");
730
+
731
+ // User is PEP in Bank 1, should fail
732
+ bank1IdentityRegistry.registerIdentity(ccid1, user1, "");
733
+ bank1CredentialRegistry.registerCredential(ccid1, CREDENTIAL_BANK_1_PEP, 0, "", "");
734
+ bank2IdentityRegistry.registerIdentity(ccid1, user1, "");
735
+ assertFalse(validator.validate(user1, ""), "User who is PEP in Bank 1 should fail");
736
+
737
+ // User is PEP in Bank 2, should fail
738
+ bank1IdentityRegistry.registerIdentity(ccid2, user2, "");
739
+ bank2IdentityRegistry.registerIdentity(ccid2, user2, "");
740
+ bank2CredentialRegistry.registerCredential(ccid2, CREDENTIAL_BANK_2_PEP, 0, "", "");
741
+ assertFalse(validator.validate(user2, ""), "User who is PEP in Bank 2 should fail");
742
+
743
+ // User is PEP in both, should fail
744
+ bank1IdentityRegistry.registerIdentity(ccid3, user3, "");
745
+ bank1CredentialRegistry.registerCredential(ccid3, CREDENTIAL_BANK_1_PEP, 0, "", "");
746
+ bank2IdentityRegistry.registerIdentity(ccid3, user3, "");
747
+ bank2CredentialRegistry.registerCredential(ccid3, CREDENTIAL_BANK_2_PEP, 0, "", "");
748
+ assertFalse(validator.validate(user3, ""), "User who is PEP in both should fail");
749
+
750
+ // User is not PEP in either source, should pass
751
+ bank1IdentityRegistry.registerIdentity(ccid4, user4, "");
752
+ bank2IdentityRegistry.registerIdentity(ccid4, user4, "");
753
+ assertTrue(validator.validate(user4, ""), "User who is not PEP in any source should pass");
754
+ }
755
+
756
+ /// Jurisdiction whitelist
757
+ /// User must belong to any allowed residence
758
+ /// Config: One requirement. credentialTypeIds = [common.residence.CountryE, common.residence.CountryF,
759
+ /// common.residence.CountryG], invert = false, minValidations = 1
760
+ function test_jurisdictionWhitelist_ifOneCredentialIsPresentItMustSucceed() public {
761
+ CredentialRegistryIdentityValidator validator = _deployCredentialRegistryIdentityValidator(
762
+ new ICredentialRequirements.CredentialSourceInput[](0),
763
+ new ICredentialRequirements.CredentialRequirementInput[](0)
764
+ );
765
+
766
+ IdentityRegistry identityReg = _deployIdentityRegistry(address(s_policyEngine));
767
+ CredentialRegistry credentialReg = _deployCredentialRegistry(address(s_policyEngine));
768
+
769
+ bytes32[] memory jurisdictionCredentials = new bytes32[](3);
770
+ jurisdictionCredentials[0] = CREDENTIAL_COMMON_COUNTRY_E;
771
+ jurisdictionCredentials[1] = CREDENTIAL_COMMON_COUNTRY_F;
772
+ jurisdictionCredentials[2] = CREDENTIAL_COMMON_COUNTRY_G;
773
+
774
+ bytes32 REQUIREMENT_REQUIRE_ANY_JURISDICTION = keccak256("Require any of the allowed jurisdictions");
775
+
776
+ validator.addCredentialSource(
777
+ ICredentialRequirements.CredentialSourceInput(
778
+ CREDENTIAL_COMMON_COUNTRY_E, address(identityReg), address(credentialReg), address(0)
779
+ )
780
+ );
781
+ validator.addCredentialSource(
782
+ ICredentialRequirements.CredentialSourceInput(
783
+ CREDENTIAL_COMMON_COUNTRY_F, address(identityReg), address(credentialReg), address(0)
784
+ )
785
+ );
786
+ validator.addCredentialSource(
787
+ ICredentialRequirements.CredentialSourceInput(
788
+ CREDENTIAL_COMMON_COUNTRY_G, address(identityReg), address(credentialReg), address(0)
789
+ )
790
+ );
791
+
792
+ validator.addCredentialRequirement(
793
+ ICredentialRequirements.CredentialRequirementInput(
794
+ REQUIREMENT_REQUIRE_ANY_JURISDICTION, jurisdictionCredentials, 1, false
795
+ )
796
+ );
797
+
798
+ address user1 = makeAddr("user1");
799
+ address user2 = makeAddr("user2");
800
+ address user3 = makeAddr("user3");
801
+ bytes32 ccid1 = keccak256("user1");
802
+ bytes32 ccid2 = keccak256("user2");
803
+ bytes32 ccid3 = keccak256("user3");
804
+
805
+ // User is CountryE resident, should pass
806
+ identityReg.registerIdentity(ccid1, user1, "");
807
+ credentialReg.registerCredential(ccid1, CREDENTIAL_COMMON_COUNTRY_E, 0, "", "");
808
+ assertTrue(validator.validate(user1, ""), "CountryE resident should pass");
809
+
810
+ // User is CountryF resident, should pass
811
+ identityReg.registerIdentity(ccid2, user2, "");
812
+ credentialReg.registerCredential(ccid2, CREDENTIAL_COMMON_COUNTRY_F, 0, "", "");
813
+ assertTrue(validator.validate(user2, ""), "CountryF resident should pass");
814
+
815
+ // User is CountryG resident, should pass
816
+ identityReg.registerIdentity(ccid3, user3, "");
817
+ credentialReg.registerCredential(ccid3, CREDENTIAL_COMMON_COUNTRY_G, 0, "", "");
818
+ assertTrue(validator.validate(user3, ""), "CountryG resident should pass");
819
+ }
820
+
821
+ /// Jurisdiction denylist
822
+ /// User must not be in any of the banned jurisdictions
823
+ /// Config: One requirement per jurisdiction, each with its own sources
824
+ /// For CountryA: credentialTypeIds = [source1.CountryA, source2.CountryA], invert = true, minValidations = 2
825
+ /// And so on for each banned jurisdiction...
826
+ function test_jurisdictionDenylist_mustNotBeInAnyOfTheBannedJurisdictions() public {
827
+ CredentialRegistryIdentityValidator validator = _deployCredentialRegistryIdentityValidator(
828
+ new ICredentialRequirements.CredentialSourceInput[](0),
829
+ new ICredentialRequirements.CredentialRequirementInput[](0)
830
+ );
831
+
832
+ IdentityRegistry source1IdentityReg = _deployIdentityRegistry(address(s_policyEngine));
833
+ vm.label(address(source1IdentityReg), "Source1IdentityRegistry");
834
+ CredentialRegistry source1CredentialReg = _deployCredentialRegistry(address(s_policyEngine));
835
+ vm.label(address(source1CredentialReg), "Source1CredentialRegistry");
836
+
837
+ IdentityRegistry source2IdentityReg = _deployIdentityRegistry(address(s_policyEngine));
838
+ vm.label(address(source2IdentityReg), "Source2IdentityRegistry");
839
+ CredentialRegistry source2CredentialReg = _deployCredentialRegistry(address(s_policyEngine));
840
+ vm.label(address(source2CredentialReg), "Source2CredentialRegistry");
841
+
842
+ bytes32[] memory countryACredentials = new bytes32[](2);
843
+ countryACredentials[0] = CREDENTIAL_SOURCE1_COUNTRY_A;
844
+ countryACredentials[1] = CREDENTIAL_SOURCE2_COUNTRY_A;
845
+
846
+ bytes32 REQUIREMENT_NOT_COUNTRY_A = keccak256("Require not to be CountryA resident");
847
+
848
+ validator.addCredentialSource(
849
+ ICredentialRequirements.CredentialSourceInput(
850
+ CREDENTIAL_SOURCE1_COUNTRY_A, address(source1IdentityReg), address(source1CredentialReg), address(0)
851
+ )
852
+ );
853
+ validator.addCredentialSource(
854
+ ICredentialRequirements.CredentialSourceInput(
855
+ CREDENTIAL_SOURCE2_COUNTRY_A, address(source2IdentityReg), address(source2CredentialReg), address(0)
856
+ )
857
+ );
858
+
859
+ validator.addCredentialRequirement(
860
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_NOT_COUNTRY_A, countryACredentials, 2, true)
861
+ );
862
+
863
+ bytes32[] memory countryBCredentials = new bytes32[](2);
864
+ countryBCredentials[0] = CREDENTIAL_SOURCE1_COUNTRY_B;
865
+ countryBCredentials[1] = CREDENTIAL_SOURCE2_COUNTRY_B;
866
+
867
+ bytes32 REQUIREMENT_NOT_COUNTRY_B = keccak256("Require not to be CountryB resident");
868
+
869
+ validator.addCredentialSource(
870
+ ICredentialRequirements.CredentialSourceInput(
871
+ CREDENTIAL_SOURCE1_COUNTRY_B, address(source1IdentityReg), address(source1CredentialReg), address(0)
872
+ )
873
+ );
874
+ validator.addCredentialSource(
875
+ ICredentialRequirements.CredentialSourceInput(
876
+ CREDENTIAL_SOURCE2_COUNTRY_B, address(source2IdentityReg), address(source2CredentialReg), address(0)
877
+ )
878
+ );
879
+
880
+ validator.addCredentialRequirement(
881
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_NOT_COUNTRY_B, countryBCredentials, 2, true)
882
+ );
883
+
884
+ bytes32[] memory countryCCredentials = new bytes32[](2);
885
+ countryCCredentials[0] = CREDENTIAL_SOURCE1_COUNTRY_C;
886
+ countryCCredentials[1] = CREDENTIAL_SOURCE2_COUNTRY_C;
887
+
888
+ bytes32 REQUIREMENT_NOT_COUNTRY_C = keccak256("Require not to be CountryC resident");
889
+
890
+ validator.addCredentialSource(
891
+ ICredentialRequirements.CredentialSourceInput(
892
+ CREDENTIAL_SOURCE1_COUNTRY_C, address(source1IdentityReg), address(source1CredentialReg), address(0)
893
+ )
894
+ );
895
+
896
+ validator.addCredentialSource(
897
+ ICredentialRequirements.CredentialSourceInput(
898
+ CREDENTIAL_SOURCE2_COUNTRY_C, address(source2IdentityReg), address(source2CredentialReg), address(0)
899
+ )
900
+ );
901
+
902
+ validator.addCredentialRequirement(
903
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_NOT_COUNTRY_C, countryCCredentials, 2, true)
904
+ );
905
+
906
+ bytes32[] memory countryDCredentials = new bytes32[](2);
907
+ countryDCredentials[0] = CREDENTIAL_SOURCE1_COUNTRY_D;
908
+ countryDCredentials[1] = CREDENTIAL_SOURCE2_COUNTRY_D;
909
+
910
+ bytes32 REQUIREMENT_NOT_COUNTRY_D = keccak256("Require not to be CountryD resident");
911
+
912
+ validator.addCredentialSource(
913
+ ICredentialRequirements.CredentialSourceInput(
914
+ CREDENTIAL_SOURCE1_COUNTRY_D, address(source1IdentityReg), address(source1CredentialReg), address(0)
915
+ )
916
+ );
917
+
918
+ validator.addCredentialSource(
919
+ ICredentialRequirements.CredentialSourceInput(
920
+ CREDENTIAL_SOURCE2_COUNTRY_D, address(source2IdentityReg), address(source2CredentialReg), address(0)
921
+ )
922
+ );
923
+
924
+ validator.addCredentialRequirement(
925
+ ICredentialRequirements.CredentialRequirementInput(REQUIREMENT_NOT_COUNTRY_D, countryDCredentials, 2, true)
926
+ );
927
+
928
+ address user1 = makeAddr("user1");
929
+ address user2 = makeAddr("user2");
930
+ address user3 = makeAddr("user3");
931
+ address user4 = makeAddr("user4");
932
+ address user5 = makeAddr("user5");
933
+ bytes32 ccid1 = keccak256("user1");
934
+ bytes32 ccid2 = keccak256("user2");
935
+ bytes32 ccid3 = keccak256("user3");
936
+ bytes32 ccid4 = keccak256("user4");
937
+ bytes32 ccid5 = keccak256("user5");
938
+
939
+ // User is CountryA resident in source1, should fail
940
+ source1IdentityReg.registerIdentity(ccid1, user1, "");
941
+ source1CredentialReg.registerCredential(ccid1, CREDENTIAL_SOURCE1_COUNTRY_A, 0, "", "");
942
+ source2IdentityReg.registerIdentity(ccid1, user1, "");
943
+ assertFalse(validator.validate(user1, ""), "CountryA resident should fail");
944
+
945
+ // User is CountryB resident in source2, should fail
946
+ source1IdentityReg.registerIdentity(ccid2, user2, "");
947
+ source2IdentityReg.registerIdentity(ccid2, user2, "");
948
+ source2CredentialReg.registerCredential(ccid2, CREDENTIAL_SOURCE2_COUNTRY_B, 0, "", "");
949
+ assertFalse(validator.validate(user2, ""), "CountryB resident should fail");
950
+
951
+ // User is CountryC resident in both sources, should fail
952
+ source1IdentityReg.registerIdentity(ccid3, user3, "");
953
+ source1CredentialReg.registerCredential(ccid3, CREDENTIAL_SOURCE1_COUNTRY_C, 0, "", "");
954
+ source2IdentityReg.registerIdentity(ccid3, user3, "");
955
+ source2CredentialReg.registerCredential(ccid3, CREDENTIAL_SOURCE2_COUNTRY_C, 0, "", "");
956
+ assertFalse(validator.validate(user3, ""), "CountryC resident should fail");
957
+
958
+ // User is CountryD resident in source1, should fail
959
+ source1IdentityReg.registerIdentity(ccid4, user4, "");
960
+ source1CredentialReg.registerCredential(ccid4, CREDENTIAL_SOURCE1_COUNTRY_D, 0, "", "");
961
+ source2IdentityReg.registerIdentity(ccid4, user4, "");
962
+ assertFalse(validator.validate(user4, ""), "CountryD resident should fail");
963
+
964
+ // User is not in banned jurisdictions, should PASS
965
+ source1IdentityReg.registerIdentity(ccid5, user5, "");
966
+ source2IdentityReg.registerIdentity(ccid5, user5, "");
967
+ assertTrue(validator.validate(user5, ""), "Clean user should pass");
968
+ }
969
+ }