Develop an OnchainVerifiable Contract
The OnchainVerifier contract is already deployed. Anyone can use it immediately when writing smart contracts in GIWA.
isVerified
function isVerified(address addr, DojangAttesterId attesterId) external view returns (bool);
This is a view function to check whether a specific wallet is verified. With this, DeFi protocols, wallets, or any system requiring gatekeeping can easily enforce policies such as “available only to verified users.”
Deployed OnchainVerifiable contract
Network
OnchainVerifier contract Address
Verfier ID
Testnet
0xd99b42e778498aa3c9c1f6a012359130252780511687a35982e8e52735453034
Example
Verified ERC20
This example extends the OpenZeppelin ERC20 standard by calling the isVerified function from the OnchainVerifiable contract to allow or deny transfers.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
type DojangAttesterId is bytes32;
interface IVerifier {
function isVerified(address primaryAddress, DojangAttesterId attesterId) external view returns (bool);
}
contract VerifiedERC20 is ERC20 {
IVerifier public immutable verifier;
DojangAttesterId public immutable attesterId;
error NotVerified(address addr);
constructor(
string memory name_,
string memory symbol_,
address verifier_,
DojangAttesterId attesterId_,
uint256 initialSupply
) ERC20(name_, symbol_) {
require(verifier_ != address(0), "verifier is zero");
verifier = IVerifier(verifier_);
attesterId = attesterId_;
_mint(msg.sender, initialSupply);
}
// OZ v5: single hook that manages all transactions (mint/burn/transfer)
function _update(address from, address to, uint256 value) internal override {
// Only verifiable for normal transfer (= both sides non-zero)
if (from != address(0) && to != address(0)) {
// Token holder (from) must be verified
if (!verifier.isVerified(from, attesterId)) revert NotVerified(from);
// Optionally verify caller (the spender in transferFrom)
if (!verifier.isVerified(_msgSender(), attesterId)) revert NotVerified(_msgSender());
// Optionally verify recipient (to)
if (!verifier.isVerified(to, attesterId)) revert NotVerified(to);
}
super._update(from, to, value);
}
}
Verified ERC721
This example extends OpenZeppelin ERC721 standard by calling external isVerified function from the OnchainVerifiable contract to allow or deny NFT transfer.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
type DojangAttesterId is bytes32;
interface IVerifier {
function isVerified(address addr, DojangAttesterId attesterId) external view returns (bool);
}
contract VerifiedERC721 is ERC721, Ownable {
IVerifier public immutable verifier;
DojangAttesterId public constant UPBIT_KOREA =
DojangAttesterId.wrap(0xd99b42e778498aa3c9c1f6a012359130252780511687a35982e8e52735453034);
error NotVerified(address account);
constructor(
string memory name_,
string memory symbol_,
address verifier_
) ERC721(name_, symbol_) Ownable(msg.sender) {
require(verifier_ != address(0), "verifier is zero");
verifier = IVerifier(verifier_);
}
function mint(address to, uint256 tokenId) external onlyOwner {
if (!verifier.isVerified(to, UPBIT_KOREA)) revert NotVerified(to);
_mint(to, tokenId);
}
/**
* OpenZeppelin v5 single hook: min/burn/transfer all go through this function
* Signature in ERC721: _update(to, tokenId, auth) returns (address from)
*/
function _update(address to, uint256 tokenId, address auth)
internal
override
returns (address from)
{
// Determine the "existing owner" before state change (address(0) if mint)
address prevOwner = _ownerOf(tokenId);
// Only verify on normal transfers (exclude mint/burn)
if (prevOwner != address(0) && to != address(0)) {
if (!verifier.isVerified(prevOwner, UPBIT_KOREA)) revert NotVerified(prevOwner);
if (!verifier.isVerified(_msgSender(), UPBIT_KOREA)) revert NotVerified(_msgSender());
if (!verifier.isVerified(to, UPBIT_KOREA)) revert NotVerified(to);
}
// Perform the actual state update (returned from is the previous owner)
return super._update(to, tokenId, auth);
}
}
Last updated