@zentity/fhevm-contracts 0.1.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/README.md +160 -0
- package/abi/ComplianceRules.json +352 -0
- package/abi/CompliantERC20.json +493 -0
- package/abi/IdentityRegistry.json +712 -0
- package/abi/index.d.ts +3 -0
- package/abi/index.js +9 -0
- package/contracts/ARCHITECTURE.md +66 -0
- package/contracts/ARCHITECTURE_EXPLAINER.md +77 -0
- package/contracts/compliance/ComplianceRules.sol +255 -0
- package/contracts/core/IdentityRegistry.sol +352 -0
- package/contracts/interfaces/IIdentityRegistry.sol +226 -0
- package/contracts/mocks/.gitkeep +0 -0
- package/contracts/tokens/CompliantERC20.sol +379 -0
- package/deployments/hardhat/addresses.json +20 -0
- package/deployments/localhost/.chainId +1 -0
- package/deployments/localhost/ComplianceRules.json +662 -0
- package/deployments/localhost/CompliantERC20.json +888 -0
- package/deployments/localhost/IdentityRegistry.json +1093 -0
- package/deployments/localhost/solcInputs/e36969353329df673b4fae03d39e01c4.json +60 -0
- package/deployments/sepolia/.chainId +1 -0
- package/deployments/sepolia/.gitkeep +0 -0
- package/deployments/sepolia/ComplianceRules.json +662 -0
- package/deployments/sepolia/CompliantERC20.json +888 -0
- package/deployments/sepolia/IdentityRegistry.json +1093 -0
- package/deployments/sepolia/solcInputs/93d280ff0d4e798a18947a9ed6015031.json +60 -0
- package/dist/index.d.ts +459 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +135 -0
- package/package.json +110 -0
- package/typechain-types/@fhevm/index.ts +5 -0
- package/typechain-types/@fhevm/solidity/config/ZamaConfig.sol/ZamaConfig.ts +69 -0
- package/typechain-types/@fhevm/solidity/config/ZamaConfig.sol/ZamaEthereumConfig.ts +90 -0
- package/typechain-types/@fhevm/solidity/config/ZamaConfig.sol/index.ts +5 -0
- package/typechain-types/@fhevm/solidity/config/index.ts +5 -0
- package/typechain-types/@fhevm/solidity/index.ts +7 -0
- package/typechain-types/@fhevm/solidity/lib/FHE.sol/FHE.ts +112 -0
- package/typechain-types/@fhevm/solidity/lib/FHE.sol/IKMSVerifier.ts +108 -0
- package/typechain-types/@fhevm/solidity/lib/FHE.sol/index.ts +5 -0
- package/typechain-types/@fhevm/solidity/lib/Impl.sol/IACL.ts +190 -0
- package/typechain-types/@fhevm/solidity/lib/Impl.sol/IFHEVMExecutor.ts +623 -0
- package/typechain-types/@fhevm/solidity/lib/Impl.sol/IInputVerifier.ts +90 -0
- package/typechain-types/@fhevm/solidity/lib/Impl.sol/index.ts +6 -0
- package/typechain-types/@fhevm/solidity/lib/index.ts +7 -0
- package/typechain-types/common.ts +131 -0
- package/typechain-types/contracts/compliance/ComplianceRules.ts +479 -0
- package/typechain-types/contracts/compliance/index.ts +4 -0
- package/typechain-types/contracts/core/IdentityRegistry.ts +874 -0
- package/typechain-types/contracts/core/index.ts +4 -0
- package/typechain-types/contracts/index.ts +11 -0
- package/typechain-types/contracts/interfaces/IIdentityRegistry.ts +798 -0
- package/typechain-types/contracts/interfaces/index.ts +4 -0
- package/typechain-types/contracts/tokens/CompliantERC20.sol/CompliantERC20.ts +572 -0
- package/typechain-types/contracts/tokens/CompliantERC20.sol/IComplianceChecker.ts +95 -0
- package/typechain-types/contracts/tokens/CompliantERC20.sol/index.ts +5 -0
- package/typechain-types/contracts/tokens/index.ts +5 -0
- package/typechain-types/factories/@fhevm/index.ts +4 -0
- package/typechain-types/factories/@fhevm/solidity/config/ZamaConfig.sol/ZamaConfig__factory.ts +69 -0
- package/typechain-types/factories/@fhevm/solidity/config/ZamaConfig.sol/ZamaEthereumConfig__factory.ts +43 -0
- package/typechain-types/factories/@fhevm/solidity/config/ZamaConfig.sol/index.ts +5 -0
- package/typechain-types/factories/@fhevm/solidity/config/index.ts +4 -0
- package/typechain-types/factories/@fhevm/solidity/index.ts +5 -0
- package/typechain-types/factories/@fhevm/solidity/lib/FHE.sol/FHE__factory.ts +88 -0
- package/typechain-types/factories/@fhevm/solidity/lib/FHE.sol/IKMSVerifier__factory.ts +54 -0
- package/typechain-types/factories/@fhevm/solidity/lib/FHE.sol/index.ts +5 -0
- package/typechain-types/factories/@fhevm/solidity/lib/Impl.sol/IACL__factory.ts +121 -0
- package/typechain-types/factories/@fhevm/solidity/lib/Impl.sol/IFHEVMExecutor__factory.ts +810 -0
- package/typechain-types/factories/@fhevm/solidity/lib/Impl.sol/IInputVerifier__factory.ts +32 -0
- package/typechain-types/factories/@fhevm/solidity/lib/Impl.sol/index.ts +6 -0
- package/typechain-types/factories/@fhevm/solidity/lib/index.ts +5 -0
- package/typechain-types/factories/contracts/compliance/ComplianceRules__factory.ts +437 -0
- package/typechain-types/factories/contracts/compliance/index.ts +4 -0
- package/typechain-types/factories/contracts/core/IdentityRegistry__factory.ts +777 -0
- package/typechain-types/factories/contracts/core/index.ts +4 -0
- package/typechain-types/factories/contracts/index.ts +7 -0
- package/typechain-types/factories/contracts/interfaces/IIdentityRegistry__factory.ts +640 -0
- package/typechain-types/factories/contracts/interfaces/index.ts +4 -0
- package/typechain-types/factories/contracts/tokens/CompliantERC20.sol/CompliantERC20__factory.ts +581 -0
- package/typechain-types/factories/contracts/tokens/CompliantERC20.sol/IComplianceChecker__factory.ts +44 -0
- package/typechain-types/factories/contracts/tokens/CompliantERC20.sol/index.ts +5 -0
- package/typechain-types/factories/contracts/tokens/index.ts +4 -0
- package/typechain-types/factories/index.ts +5 -0
- package/typechain-types/hardhat.d.ts +261 -0
- package/typechain-types/index.ts +32 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Zentity FHEVM Architecture (Web3 Data Flow)
|
|
2
|
+
|
|
3
|
+
This document focuses on the Web3 data flow and where encryption happens in the
|
|
4
|
+
fhEVM flow. It is meant to be a high-level map for developers and reviewers.
|
|
5
|
+
|
|
6
|
+
## Web3 Data Flow (Encrypted State + Compliance)
|
|
7
|
+
|
|
8
|
+
```mermaid
|
|
9
|
+
flowchart TD
|
|
10
|
+
User["User Wallet + Zama SDK"] -- "1) Encrypt input: externalEuint" --> EncIn["Ciphertext handle + proof"]
|
|
11
|
+
EncIn -- "2) tx call" --> IR["IdentityRegistry"]
|
|
12
|
+
EncIn -- "2) tx call" --> ERC["CompliantERC20"]
|
|
13
|
+
|
|
14
|
+
subgraph OnChain["On-chain fhEVM"]
|
|
15
|
+
IR -- "3) Stores encrypted attrs" --> IRState["Encrypted attributes: birthYear/country/kyc/blacklist"]
|
|
16
|
+
IR -- "4) ACL grants" --> ACL["ACL per ciphertext handle"]
|
|
17
|
+
ERC -- "5) calls" --> CR["ComplianceRules"]
|
|
18
|
+
CR -- "6) queries" --> IR
|
|
19
|
+
CR -- "7) returns ebool" --> ERC
|
|
20
|
+
ERC -- "8) select transfer amount" --> ERCState["Encrypted balances"]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
subgraph OffChain["Off-chain FHE coprocessor"]
|
|
24
|
+
FHE["FHE Coprocessor"] <--> OnChain
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
User -- "9) grantAccessTo ComplianceRules" --> IR
|
|
28
|
+
IR -- "10) AccessGranted event" --> UI["UI / dApp"]
|
|
29
|
+
|
|
30
|
+
note1["Encryption happens client-side. Values are stored on-chain as ciphertext handles with ACL permissions."]
|
|
31
|
+
note2["ComplianceRules evaluates only for allowed callers; results are encrypted and ACL-protected."]
|
|
32
|
+
|
|
33
|
+
note1 -.-> User
|
|
34
|
+
note2 -.-> CR
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Key points
|
|
38
|
+
- **Encryption happens client-side** using the Zama SDK. Inputs are submitted as
|
|
39
|
+
`externalEuint*` handles with a proof.
|
|
40
|
+
- **On-chain storage is always encrypted** (ciphertext handles), guarded by the
|
|
41
|
+
ACL. No plaintext identity data is stored on-chain.
|
|
42
|
+
- **Ciphertexts remain polymorphically encrypted** under FHE operations, so
|
|
43
|
+
computation happens without decryption and without changing confidentiality.
|
|
44
|
+
- **Compliance is evaluated under encryption** in `ComplianceRules`, and the
|
|
45
|
+
encrypted boolean is consumed by `CompliantERC20` using `FHE.select`.
|
|
46
|
+
- **Access grants are explicit**: users must call `IdentityRegistry.grantAccessTo`
|
|
47
|
+
for any contract to read or compute on their identity ciphertexts.
|
|
48
|
+
- **Silent failure**: if compliance or balance checks fail, the transfer silently
|
|
49
|
+
becomes a zero transfer to avoid leaking sensitive conditions.
|
|
50
|
+
|
|
51
|
+
## How encryption is saved on-chain
|
|
52
|
+
- Encrypted values are stored as **ciphertext handles** in contract state.
|
|
53
|
+
- The ACL contract enforces who may use each handle for computation or decryption.
|
|
54
|
+
- `grantAccessTo` updates ACL rights for the user's ciphertext handles.
|
|
55
|
+
|
|
56
|
+
## Contracts involved
|
|
57
|
+
- `IdentityRegistry`: encrypted identity attributes + ACL grants.
|
|
58
|
+
- `ComplianceRules`: encrypted compliance checks (authorized or self-only).
|
|
59
|
+
- `CompliantERC20`: encrypted balances, compliance-gated transfers.
|
|
60
|
+
|
|
61
|
+
## Ownership and admin safety
|
|
62
|
+
- These contracts use **two-step ownership transfer**:
|
|
63
|
+
1. `transferOwnership(newOwner)` by current owner
|
|
64
|
+
2. `acceptOwnership()` by pending owner
|
|
65
|
+
- This reduces the risk of accidental loss of admin control.
|
|
66
|
+
- For production, transfer ownership to a multisig once deployments are verified.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Zentity Architecture Explainer (Web2 -> Web3 Flow)
|
|
2
|
+
|
|
3
|
+
This document explains the end-to-end flow from Web2 verification to Web3
|
|
4
|
+
attestation and encrypted compliance checks.
|
|
5
|
+
|
|
6
|
+
## Web2 -> Web3 Data Flow
|
|
7
|
+
|
|
8
|
+
```mermaid
|
|
9
|
+
sequenceDiagram
|
|
10
|
+
autonumber
|
|
11
|
+
actor User
|
|
12
|
+
participant UI as Zentity Web App (Web2)
|
|
13
|
+
participant BE as Zentity Backend (Web2)
|
|
14
|
+
participant KYC as KYC/Liveness Services (Web2)
|
|
15
|
+
participant Registrar as Registrar Wallet (Web3)
|
|
16
|
+
participant IR as IdentityRegistry (fhEVM)
|
|
17
|
+
participant CR as ComplianceRules (fhEVM)
|
|
18
|
+
participant ERC as CompliantERC20 (fhEVM)
|
|
19
|
+
|
|
20
|
+
User->>UI: Complete verification flow (docs + liveness)
|
|
21
|
+
UI->>BE: Submit verification data
|
|
22
|
+
BE->>KYC: Verify identity and liveness
|
|
23
|
+
KYC-->>BE: KYC result + attributes
|
|
24
|
+
|
|
25
|
+
BE->>UI: Verification complete (Web2)
|
|
26
|
+
UI->>Registrar: Request on-chain attestation
|
|
27
|
+
|
|
28
|
+
Note over UI,Registrar: Identity attributes are encrypted client-side<br/>and sent as externalEuint handles + proof.
|
|
29
|
+
|
|
30
|
+
Registrar->>IR: attestIdentity(user, encAttrs, proof)
|
|
31
|
+
IR-->>Registrar: Encrypted state stored + ACL for user
|
|
32
|
+
|
|
33
|
+
User->>IR: grantAccessTo(ComplianceRules)
|
|
34
|
+
IR-->>User: AccessGranted event
|
|
35
|
+
|
|
36
|
+
User->>ERC: transfer(to, encAmount, proof)
|
|
37
|
+
ERC->>CR: checkCompliance(user)
|
|
38
|
+
CR->>IR: read encrypted attributes (ACL-protected)
|
|
39
|
+
CR-->>ERC: encrypted compliance result
|
|
40
|
+
ERC-->>User: transaction confirmed (silent failure if non-compliant)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## What stays in Web2 vs Web3
|
|
44
|
+
|
|
45
|
+
### Web2 (Zentity Backend)
|
|
46
|
+
- **Collects and verifies identity data** (documents, liveness, etc.).
|
|
47
|
+
- **Produces the final KYC result** and attribute set.
|
|
48
|
+
- **Never stores plaintext on-chain**. Only encrypted attributes are sent to
|
|
49
|
+
Web3 via the registrar flow.
|
|
50
|
+
|
|
51
|
+
### Web3 (fhEVM + Zama)
|
|
52
|
+
- **Stores encrypted identity attributes** in `IdentityRegistry` as ciphertext
|
|
53
|
+
handles.
|
|
54
|
+
- **Enforces access via ACL**. Only explicitly granted contracts/users can use
|
|
55
|
+
a given handle.
|
|
56
|
+
- **Computes compliance under encryption** in `ComplianceRules`.
|
|
57
|
+
- **Transfers are guarded** by encrypted compliance checks in `CompliantERC20`.
|
|
58
|
+
|
|
59
|
+
## Why the flow is secure (and complex)
|
|
60
|
+
- **Confidentiality** is preserved because the EVM never sees plaintext values.
|
|
61
|
+
- **Integrity** is enforced through ACL permissions and explicit caller checks.
|
|
62
|
+
- **Non-reverting patterns** (silent failure) prevent information leakage.
|
|
63
|
+
|
|
64
|
+
## Operational responsibilities
|
|
65
|
+
- **Users** must grant access to `ComplianceRules` once per network.
|
|
66
|
+
- **Deployments** must authorize `CompliantERC20` as an allowed caller in
|
|
67
|
+
`ComplianceRules`.
|
|
68
|
+
- **UI** should surface access requirements and avoid caching access state
|
|
69
|
+
locally (rely on on-chain events).
|
|
70
|
+
- **Owners** should transfer ownership to a multisig using the two-step flow
|
|
71
|
+
(`transferOwnership` → `acceptOwnership`) after deployments are verified.
|
|
72
|
+
|
|
73
|
+
## Practical checklist for integrators
|
|
74
|
+
- Ensure `grantAccessTo(ComplianceRules)` is called before any transfer attempts.
|
|
75
|
+
- Ensure `ComplianceRules.setAuthorizedCaller(tokenAddress, true)` is done at deploy.
|
|
76
|
+
- Handle silent failures in the UI (show effective transfer or warning).
|
|
77
|
+
- Avoid exposing arbitrary external calls from privileged contracts.
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.27;
|
|
3
|
+
|
|
4
|
+
import {FHE, ebool} from "@fhevm/solidity/lib/FHE.sol";
|
|
5
|
+
import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
|
|
6
|
+
import {IIdentityRegistry} from "../interfaces/IIdentityRegistry.sol";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title ComplianceRules
|
|
10
|
+
* @author Gustavo Valverde
|
|
11
|
+
* @notice Combines multiple compliance checks using FHE operations
|
|
12
|
+
* @dev Part of zentity-fhevm-contracts - Builder Track
|
|
13
|
+
*
|
|
14
|
+
* @custom:category compliance
|
|
15
|
+
* @custom:concept Combining encrypted compliance checks with FHE.and()
|
|
16
|
+
* @custom:difficulty intermediate
|
|
17
|
+
*
|
|
18
|
+
* This contract aggregates compliance checks from IdentityRegistry and returns
|
|
19
|
+
* encrypted boolean results. Consumer contracts (like CompliantERC20) can use
|
|
20
|
+
* these results with FHE.select() for branch-free logic.
|
|
21
|
+
*
|
|
22
|
+
* Key patterns demonstrated:
|
|
23
|
+
* 1. FHE.and() for combining multiple encrypted conditions
|
|
24
|
+
* 2. Integration with IdentityRegistry
|
|
25
|
+
* 3. Configurable compliance parameters
|
|
26
|
+
* 4. Encrypted result caching
|
|
27
|
+
*/
|
|
28
|
+
contract ComplianceRules is ZamaEthereumConfig {
|
|
29
|
+
// ============ State ============
|
|
30
|
+
|
|
31
|
+
/// @notice Reference to the identity registry
|
|
32
|
+
IIdentityRegistry public immutable identityRegistry;
|
|
33
|
+
|
|
34
|
+
/// @notice Owner/admin
|
|
35
|
+
address public owner;
|
|
36
|
+
/// @notice Pending owner for two-step ownership transfer
|
|
37
|
+
address public pendingOwner;
|
|
38
|
+
|
|
39
|
+
/// @notice Minimum KYC level required for compliance
|
|
40
|
+
uint8 public minKycLevel;
|
|
41
|
+
|
|
42
|
+
/// @notice Store last compliance check result for each user
|
|
43
|
+
mapping(address user => ebool result) private complianceResults;
|
|
44
|
+
|
|
45
|
+
/// @notice Authorized callers that can request compliance checks for others
|
|
46
|
+
mapping(address caller => bool authorized) public authorizedCallers;
|
|
47
|
+
|
|
48
|
+
// ============ Events ============
|
|
49
|
+
|
|
50
|
+
/// @notice Emitted when the minimum KYC level requirement is updated
|
|
51
|
+
/// @param newLevel The new minimum KYC level required for compliance
|
|
52
|
+
event MinKycLevelUpdated(uint8 indexed newLevel);
|
|
53
|
+
|
|
54
|
+
/// @notice Emitted when a compliance check is performed for a user
|
|
55
|
+
/// @param user Address of the user whose compliance was checked
|
|
56
|
+
event ComplianceChecked(address indexed user);
|
|
57
|
+
|
|
58
|
+
/// @notice Emitted when a caller's authorization is updated
|
|
59
|
+
/// @param caller Address being authorized or revoked
|
|
60
|
+
/// @param allowed Whether the caller is allowed
|
|
61
|
+
event AuthorizedCallerUpdated(address indexed caller, bool allowed);
|
|
62
|
+
|
|
63
|
+
/// @notice Emitted when ownership transfer is initiated
|
|
64
|
+
/// @param currentOwner Current owner address
|
|
65
|
+
/// @param pendingOwner Address that can accept ownership
|
|
66
|
+
event OwnershipTransferStarted(address indexed currentOwner, address indexed pendingOwner);
|
|
67
|
+
|
|
68
|
+
/// @notice Emitted when ownership transfer is completed
|
|
69
|
+
/// @param previousOwner Previous owner address
|
|
70
|
+
/// @param newOwner New owner address
|
|
71
|
+
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
|
72
|
+
|
|
73
|
+
// ============ Errors ============
|
|
74
|
+
|
|
75
|
+
/// @notice Thrown when caller is not the contract owner
|
|
76
|
+
error OnlyOwner();
|
|
77
|
+
/// @notice Thrown when caller is not the pending owner
|
|
78
|
+
error OnlyPendingOwner();
|
|
79
|
+
/// @notice Thrown when new owner is the zero address
|
|
80
|
+
error InvalidOwner();
|
|
81
|
+
|
|
82
|
+
/// @notice Thrown when registry address is zero
|
|
83
|
+
error RegistryNotSet();
|
|
84
|
+
|
|
85
|
+
/// @notice Thrown when caller is not authorized to check another user
|
|
86
|
+
error CallerNotAuthorized();
|
|
87
|
+
|
|
88
|
+
/// @notice Thrown when caller lacks permission for encrypted result
|
|
89
|
+
error AccessProhibited();
|
|
90
|
+
|
|
91
|
+
// ============ Modifiers ============
|
|
92
|
+
|
|
93
|
+
modifier onlyOwner() {
|
|
94
|
+
if (msg.sender != owner) revert OnlyOwner();
|
|
95
|
+
_;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
modifier onlyAuthorizedOrSelf(address user) {
|
|
99
|
+
if (msg.sender != user && !authorizedCallers[msg.sender]) {
|
|
100
|
+
revert CallerNotAuthorized();
|
|
101
|
+
}
|
|
102
|
+
_;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ============ Constructor ============
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @notice Initialize with identity registry reference
|
|
109
|
+
* @param registry Address of the IdentityRegistry contract
|
|
110
|
+
* @param initialMinKycLevel Initial minimum KYC level (default: 1)
|
|
111
|
+
*/
|
|
112
|
+
constructor(address registry, uint8 initialMinKycLevel) {
|
|
113
|
+
if (registry == address(0)) revert RegistryNotSet();
|
|
114
|
+
identityRegistry = IIdentityRegistry(registry);
|
|
115
|
+
owner = msg.sender;
|
|
116
|
+
minKycLevel = initialMinKycLevel;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ============ Admin Functions ============
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @notice Update minimum KYC level
|
|
123
|
+
* @param newLevel New minimum level
|
|
124
|
+
*/
|
|
125
|
+
function setMinKycLevel(uint8 newLevel) external onlyOwner {
|
|
126
|
+
minKycLevel = newLevel;
|
|
127
|
+
emit MinKycLevelUpdated(newLevel);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @notice Allow or revoke a caller to check compliance for other users
|
|
132
|
+
* @param caller Address to update
|
|
133
|
+
* @param allowed Whether the caller is allowed
|
|
134
|
+
*/
|
|
135
|
+
function setAuthorizedCaller(address caller, bool allowed) external onlyOwner {
|
|
136
|
+
authorizedCallers[caller] = allowed;
|
|
137
|
+
emit AuthorizedCallerUpdated(caller, allowed);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @notice Initiate transfer of contract ownership
|
|
142
|
+
* @param newOwner Address that can accept ownership
|
|
143
|
+
*/
|
|
144
|
+
function transferOwnership(address newOwner) external onlyOwner {
|
|
145
|
+
if (newOwner == address(0)) revert InvalidOwner();
|
|
146
|
+
pendingOwner = newOwner;
|
|
147
|
+
emit OwnershipTransferStarted(owner, newOwner);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @notice Accept ownership transfer
|
|
152
|
+
*/
|
|
153
|
+
function acceptOwnership() external {
|
|
154
|
+
if (msg.sender != pendingOwner) revert OnlyPendingOwner();
|
|
155
|
+
address previousOwner = owner;
|
|
156
|
+
owner = pendingOwner;
|
|
157
|
+
pendingOwner = address(0);
|
|
158
|
+
emit OwnershipTransferred(previousOwner, owner);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ============ Compliance Checks ============
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @notice Check if user passes all compliance requirements
|
|
165
|
+
* @dev Combines: hasMinKycLevel AND isNotBlacklisted
|
|
166
|
+
* @param user Address to check
|
|
167
|
+
* @return Encrypted boolean indicating compliance status
|
|
168
|
+
*
|
|
169
|
+
* Note: This function makes external calls to IdentityRegistry which
|
|
170
|
+
* computes and stores verification results. The combined result is
|
|
171
|
+
* stored locally for later retrieval.
|
|
172
|
+
*/
|
|
173
|
+
function checkCompliance(address user) external onlyAuthorizedOrSelf(user) returns (ebool) {
|
|
174
|
+
// Check if user is attested
|
|
175
|
+
if (!identityRegistry.isAttested(user)) {
|
|
176
|
+
ebool notAttestedResult = FHE.asEbool(false);
|
|
177
|
+
FHE.allowThis(notAttestedResult);
|
|
178
|
+
FHE.allow(notAttestedResult, msg.sender);
|
|
179
|
+
complianceResults[user] = notAttestedResult;
|
|
180
|
+
return notAttestedResult;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Get individual compliance checks
|
|
184
|
+
ebool hasKyc = identityRegistry.hasMinKycLevel(user, minKycLevel);
|
|
185
|
+
ebool notBlacklisted = identityRegistry.isNotBlacklisted(user);
|
|
186
|
+
|
|
187
|
+
// Combine all conditions
|
|
188
|
+
ebool result = FHE.and(hasKyc, notBlacklisted);
|
|
189
|
+
|
|
190
|
+
// Store and grant permissions
|
|
191
|
+
complianceResults[user] = result;
|
|
192
|
+
FHE.allowThis(result);
|
|
193
|
+
FHE.allow(result, msg.sender);
|
|
194
|
+
|
|
195
|
+
emit ComplianceChecked(user);
|
|
196
|
+
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @notice Check compliance with additional country restriction
|
|
202
|
+
* @param user Address to check
|
|
203
|
+
* @param allowedCountry Country code that is allowed
|
|
204
|
+
* @return Encrypted boolean indicating compliance status
|
|
205
|
+
*/
|
|
206
|
+
function checkComplianceWithCountry(
|
|
207
|
+
address user,
|
|
208
|
+
uint16 allowedCountry
|
|
209
|
+
) external onlyAuthorizedOrSelf(user) returns (ebool) {
|
|
210
|
+
// Check if user is attested
|
|
211
|
+
if (!identityRegistry.isAttested(user)) {
|
|
212
|
+
ebool notAttestedResult = FHE.asEbool(false);
|
|
213
|
+
FHE.allowThis(notAttestedResult);
|
|
214
|
+
FHE.allow(notAttestedResult, msg.sender);
|
|
215
|
+
return notAttestedResult;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Get individual compliance checks
|
|
219
|
+
ebool hasKyc = identityRegistry.hasMinKycLevel(user, minKycLevel);
|
|
220
|
+
ebool notBlacklisted = identityRegistry.isNotBlacklisted(user);
|
|
221
|
+
ebool isFromAllowedCountry = identityRegistry.isFromCountry(user, allowedCountry);
|
|
222
|
+
|
|
223
|
+
// Combine all conditions
|
|
224
|
+
ebool result = FHE.and(FHE.and(hasKyc, notBlacklisted), isFromAllowedCountry);
|
|
225
|
+
|
|
226
|
+
// Grant permissions
|
|
227
|
+
FHE.allowThis(result);
|
|
228
|
+
FHE.allow(result, msg.sender);
|
|
229
|
+
|
|
230
|
+
emit ComplianceChecked(user);
|
|
231
|
+
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* @notice Get the last compliance check result for a user
|
|
237
|
+
* @dev Call checkCompliance first to compute and store the result
|
|
238
|
+
* @param user Address to get result for
|
|
239
|
+
* @return Encrypted boolean result
|
|
240
|
+
*/
|
|
241
|
+
function getComplianceResult(address user) external view returns (ebool) {
|
|
242
|
+
ebool result = complianceResults[user];
|
|
243
|
+
if (!FHE.isSenderAllowed(result)) revert AccessProhibited();
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @notice Check if compliance result exists for user
|
|
249
|
+
* @param user Address to check
|
|
250
|
+
* @return Whether a cached result exists
|
|
251
|
+
*/
|
|
252
|
+
function hasComplianceResult(address user) external view returns (bool) {
|
|
253
|
+
return FHE.isInitialized(complianceResults[user]);
|
|
254
|
+
}
|
|
255
|
+
}
|