メインコンテンツまでスキップ

Demo - Create a Compliant dApp

The MIZUHIKI Verified SBT can be used to provide services to verified users only. Before completing a transfer or any operation, you can easily verify if the user's wallet holds the MIZUHIKI Verified SBT.

Contract Addresses

NetworkEnvironmentContract Address
Awaji TestnetDevelopment0x7828549D695777Bb01567aE7954F7586243bd294
MIZUHIKI MainnetProductionExpected to launch in June 2026

Contract Interface

The MIZUHIKI Verified SBT implements the ERC-5484 standard:

interface IMizuhikiVerifiedSBT {
/**
* @dev Returns the number of SBTs owned by `account`
* @param account The address to query
* @return The number of SBTs owned (0 or 1 for soulbound tokens)
*/
function balanceOf(address account) external view returns (uint256);

/**
* @dev Returns true if the account has a verified SBT
* @param account The address to check
* @return True if verified, false otherwise
*/
function isVerified(address account) external view returns (bool);

/**
* @dev Burn authorization - who can burn the token
*/
enum BurnAuth {
IssuerOnly, // Only the MIZUHIKI project can burn
OwnerOnly, // Only token holder can burn
Both, // Both the MIZUHIKI project and holder can burn
Neither // Token is permanently bound
}
}

Create ERC20 Token for Verified Users Only

  1. Configure the SBT contract address for your ERC20 token:
CompliantERC20.sol
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract CompliantERC20 is ERC20, Ownable {
/**
* @notice MIZUHIKI SBT contract address
*/
address public mizuhikiSbtContract;

/**
* @notice Whitelist of addresses that can facilitate transfers without SBT e.g. DEX router addresses
*/
mapping(address => bool) public dexWhitelist;

// Events
event MizuhikiSbtContractUpdated(address indexed newContract);
event DexWhitelistUpdated(address indexed dexRouter, bool whitelisted);

// Errors
error NotVerified(address account, string message);

/**
* @notice Update the MIZUHIKI SBT contract address (only owner)
* @param _mizuhikiSbtContract New SBT contract address
*/
function updateMizuhikiSbtContract(address _mizuhikiSbtContract)
external
onlyOwner
{
mizuhikiSbtContract = _mizuhikiSbtContract;
emit MizuhikiSbtContractUpdated(_mizuhikiSbtContract);
}

/**
* @notice Add or remove a DEX router from the whitelist (only owner)
* @param _dexRouter DEX router address
* @param _whitelisted Whether the DEX should be whitelisted
*/
function updateDexWhitelist(address _dexRouter, bool _whitelisted)
external
onlyOwner
{
dexWhitelist[_dexRouter] = _whitelisted;
emit DexWhitelistUpdated(_dexRouter, _whitelisted);
}
}
  1. Create an onlyVerified modifier to check the balance of MIZUHIKI Verified SBT of the sender and recipient:
CompliantERC20.sol
modifier onlyVerified(address account) {
if (IERC721(mizuhikiSbtContract).balanceOf(account) == 0 && !dexWhitelist[account]) {
revert NotVerified(account, "Receiver must be a MIZUHIKI Verified SBT holder or a whitelisted account");
}
if (IERC721(mizuhikiSbtContract).balanceOf(msg.sender) == 0 && !dexWhitelist[msg.sender]) {
revert NotVerified(msg.sender, "Sender must be a MIZUHIKI Verified SBT holder or a whitelisted account");
}
_;
}
  1. Add the onlyVerified modifier to any operation you want to limit to verified users only:
CompliantERC20.sol
function _update(address from, address to, uint256 value)
internal
override(ERC20)
onlyVerified(to)
{
super._update(from, to, value);
}
Swap confirmationSwap error, missing SBT

Enforcing KYC requirement on the ERC20 token contract level

注記

The restriction for token transfer in this example is added to the token contract only. The DeFi contracts (Uniswap contracts) do not need to be modified.