ComplianceChecker
Purpose
ComplianceChecker
evaluates whether an address satisfies any configured ComplianceOption. Each option is a conjunctive set of required SBTs; an address is compliant with an option if it satisfies all SBT checks in that option. The contract exposes both a boolean check and an enforcing requireCompliant
gate.
Imports
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {IComplianceChecker, ComplianceOption} from "./interfaces/IComplianceChecker.sol";
ComplianceOption (from your interface) contains:
struct ComplianceOption { IVerificationSBT[] requiredSBTs; }
(Inferred from usage:
_complianceOptions[i].requiredSBTs[j].isVerificationSBTValid(user)
.)
Roles
bytes32 public constant COMPLIANCE_ADMIN_ROLE = keccak256("COMPLIANCE_ADMIN_ROLE");
DEFAULT_ADMIN_ROLE: top-level role admin.
COMPLIANCE_ADMIN_ROLE: can update the compliance options.
Storage
ComplianceOption[] internal _complianceOptions;
The full set of allowed “paths” to compliance. Users must pass all SBT checks inside any one option to be considered compliant.
Constructor
constructor(address defaultAdmin, address complianceAdmin) {
_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
_grantRole(COMPLIANCE_ADMIN_ROLE, complianceAdmin);
}
Events
event ComplianceSetupChanged(ComplianceOption[] complianceOptions);
Errors
error ComplianceCheckFailed();
(used byrequireCompliant
)
Public / External
getComplianceOptions
function getComplianceOptions() external view returns (ComplianceOption[] memory);
Returns the full array of configured options (deep-copied to memory).
setComplianceOptions
function setComplianceOptions(ComplianceOption[] calldata complianceOptions)
public onlyRole(COMPLIANCE_ADMIN_ROLE);
What it does
Replaces the entire configuration of compliance options in one call.
Effects
delete _complianceOptions;
then pushes each provided option.Emits:
ComplianceSetupChanged(complianceOptions)
.
Notes
This is an overwrite, not an append. Callers should provide the full desired set each time.
isCompliant
function isCompliant(address user) public view returns (bool);
Logic
For each
ComplianceOption
in_complianceOptions
:For each
requiredSBT
in the option:If any
requiredSBT.isVerificationSBTValid(user) == false
→ this option fails.
If all SBTs in the option pass → return true.
If no option passes → return false.
Complexity
O(options × sbts per option); view-only.
requireCompliant
function requireCompliant(address user) public view;
Enforces compliance: require(isCompliant(user), ComplianceCheckFailed());
Used by:
CompliantDepositRegistry.getDepositAddress
andregisterDepositAddress
.Your other modules (e.g.,
Whitelist
) can also call it for hard gating.
Integration Notes
Configure options for different flows (e.g., KYC vs KYB) as separate
ComplianceOption
entries. A user needs to pass one of them entirely.Each SBT contract must expose
isVerificationSBTValid(address)
and should be trustworthy (correctly attesting identity/sanctions/age/etc.).Changes are immediate: once
setComplianceOptions
is called, all downstream checks reflect the new policy.
Security Considerations
Centralized policy:
COMPLIANCE_ADMIN_ROLE
can tighten/loosen requirements instantly; use a multi-sig or governance process.SBT trust: the system correctness depends on SBT issuers and their
isVerificationSBTValid
logic.
Quick Call Examples
Admin: add a batch, open challenge window, finalize automatically after period
// roles already granted
registry.addDepositAddresses(new string);
// wait until block.timestamp > latestBatchUnlockTime
// investors can now self-register from this finalized space
Canceler: challenge the latest batch before unlock
registry.challengeLatestBatch(); // pops the entire latest batch
Investor: register & read address (gates on compliance)
string memory addr = registry.registerDepositAddress();
// later queries will re-check compliance:
string memory same = registry.getDepositAddress(msg.sender);
Last updated