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

Use Case & Applications

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 dApps 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

Explanation

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.

Code Example

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

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

/// @notice Assertions ensuring OnlyAccreditedCanMint restricts privileged actions to accredited callers
contract OnlyAccreditedCanMintAssertion is Assertion {
    AccreditedInvestorRegistry public immutable registry;

    constructor(address tokenAddress) {
        registry = AccreditedInvestorRegistry(tokenAddress);
    }

    // register the functions that will be called and used by the assertion functions below
    function triggers() external view override {
        registerCallTrigger(this.assertOnlyAccreditedMint.selector, OnlyAccreditedCanMint.mint.selector);
        registerCallTrigger(this.assertOnlyAccreditedTransfer.selector, OnlyAccreditedCanMint.transfer.selector);
    }

    /// @notice When msg.sender hits mint, if they are not in the registry, theycannot mint tokens
    function assertOnlyAccreditedMint() external {
        OnlyAccreditedCanMint token = OnlyAccreditedCanMint(ph.getAssertionAdopter());

        PhEvm.CallInputs[] memory calls = ph.getCallInputs(address(token), OnlyAccreditedCanMint.mint.selector);

        for (uint256 i = 0; i < calls.length; i++) {
            // Bundle the accreditation check into any call
            require(registry.isAccredited(calls[i].caller), "caller is not accredited");
        }
    }

    /// @notice Ensure that non-accredited callers cannot transfer tokens
    function assertOnlyAccreditedTransfer() external {
        OnlyAccreditedCanMint token = OnlyAccreditedCanMint(ph.getAssertionAdopter());

        PhEvm.CallInputs[] memory calls = ph.getCallInputs(address(token), OnlyAccreditedCanMint.transfer.selector);

        for (uint256 i = 0; i < calls.length; i++) {
            // Bundle the accreditation check into any call
            require(registry.isAccredited(calls[i].caller), "caller is not accredited");
        }
    }
}
Note: Full examples with tests available in the Phylax Assertion Examples Repository.
I