Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.phylax.systems/llms.txt

Use this file to discover all available pages before exploring further.

Assert that only KYC-verified addresses can perform privileged actions across multiple dapps using a shared registry

When to Use This Pattern

Since regulated funds and prime brokerages can only gain exposure into regulated products, a DeFi protocol may want to attract greater fund deployment by proving itself as a compliant venue. This assertion is a simple proof-of-concept that demonstrates a single, shared registry that multiple applications can reference. It’s designed such that
  • Users complete KYC once and gain access to all integrated protocols; no redundant process to verify on each protocol
  • The protocol can adopt KYC requirements without implementing their own verification systems
  • Registry owners maintain centralized control over access permissions, the owner may revoke an investor accrediation once and have it impact access for all integrated protocols

What This Pattern Checks

What you should know about this KYC assertion example:
  • It is triggered on a specific function call. For example, a mint or transfer request on the implementation contract.
  • When triggered, the assertion references a shared registry contract, here named the AccreditedInvestorRegistry which maintains the whitelist of KYC-verified addresses.
  • The assertion validates that msg.sender exists in the KYC registry before allowing execution of protected functions. This prevents non-KYC addresses from interacting with regulated tokens or permissioned protocol functions.
  • It is assumed the admin that controls the Registry may be different than the integrating protocol’s admin.

Assertion Pattern

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Assertion} from "credible-std/Assertion.sol";
import {AssertionSpec} from "credible-std/SpecRecorder.sol";
import {PhEvm} from "credible-std/PhEvm.sol";
import {OnlyAccreditedCanMint} from "../../src/ass4-only-accredited-can-mint.sol";
import {AccreditedInvestorRegistry} from "../../src/AccreditedInvestorRegistry.sol";

contract OnlyAccreditedCanMintAssertion is Assertion {
    AccreditedInvestorRegistry public immutable registry;

    constructor(address registry_) {
        registerAssertionSpec(AssertionSpec.Reshiram);
        registry = AccreditedInvestorRegistry(registry_);
    }

    function triggers() external view override {
        registerFnCallTrigger(this.assertOnlyAccreditedMint.selector, OnlyAccreditedCanMint.mint.selector);
        registerFnCallTrigger(this.assertOnlyAccreditedTransfer.selector, OnlyAccreditedCanMint.transfer.selector);
    }

    /// @notice Checks that the caller of `mint` is accredited.
    function assertOnlyAccreditedMint() external view {
        _assertMatchingCallersAccredited(OnlyAccreditedCanMint.mint.selector);
    }

    /// @notice Checks that the caller of `transfer` is accredited.
    function assertOnlyAccreditedTransfer() external view {
        _assertMatchingCallersAccredited(OnlyAccreditedCanMint.transfer.selector);
    }

    function _assertMatchingCallersAccredited(bytes4 selector) internal view {
        PhEvm.TriggerCall[] memory calls = ph.matchingCalls(ph.getAssertionAdopter(), selector, _successfulCalls(), 32);
        for (uint256 i = 0; i < calls.length; i++) {
            require(registry.isAccredited(calls[i].caller), "caller is not accredited");
        }
    }

    function _successfulCalls() internal pure returns (PhEvm.CallFilter memory filter) {
        filter.callType = 1;
        filter.successOnly = true;
    }
}
Full examples and mock protocol code are available in credible-std.