Skip to main content

Overview

This document provides a comprehensive reference for all functions available in the ZKScore Identity SBT contract. Each function includes detailed parameter descriptions, return values, gas estimates, and usage examples.
All functions that modify state require a transaction and will consume gas. View functions are free to call and return data immediately.

Core Functions

mint

Mint a new identity token for a user.
function mint(
    address to,
    string memory name,
    string memory metadataURI
) external returns (uint256 tokenId);
Parameters:
  • to (address): The address to mint the token to
  • name (string): The ZKS ID name (e.g., “alice.zks”)
  • metadataURI (string): URI pointing to the token metadata
Returns:
  • tokenId (uint256): The ID of the newly minted token
Gas Estimate: ~150,000 gas Requirements:
  • Caller must have MINTER_ROLE
  • to cannot be the zero address
  • name must be unique and valid
  • metadataURI must be a valid URI
Events Emitted:
  • IdentityMinted(address indexed to, uint256 indexed tokenId, string name)
Example Usage:
const { ethers } = require('ethers');

async function mintIdentity() {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  const signer = provider.getSigner();
  
  const contract = new ethers.Contract(
    '0x1234567890123456789012345678901234567890',
    IDENTITY_SBT_ABI,
    signer
  );
  
  const tx = await contract.mint(
    '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
    'alice.zks',
    'https://api.onzks.com/metadata/alice.zks'
  );
  
  const receipt = await tx.wait();
  const event = receipt.events.find(e => e.event === 'IdentityMinted');
  const tokenId = event.args.tokenId;
  
  console.log(`Identity minted with token ID: ${tokenId}`);
  return tokenId;
}

activate

Activate an identity token, making it soulbound.
function activate(uint256 tokenId) external;
Parameters:
  • tokenId (uint256): The ID of the token to activate
Returns: None Gas Estimate: ~50,000 gas Requirements:
  • Caller must be the owner of the token
  • Token must not already be activated
  • Token must exist
Events Emitted:
  • IdentityActivated(uint256 indexed tokenId, address indexed owner)
Example Usage:
async function activateIdentity(tokenId) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  const signer = provider.getSigner();
  
  const contract = new ethers.Contract(
    '0x1234567890123456789012345678901234567890',
    IDENTITY_SBT_ABI,
    signer
  );
  
  const tx = await contract.activate(tokenId);
  await tx.wait();
  
  console.log(`Identity ${tokenId} activated and made soulbound`);
}

View Functions

balanceOf

Get the number of tokens owned by an address.
function balanceOf(address owner) external view returns (uint256);
Parameters:
  • owner (address): The address to query
Returns:
  • uint256: The number of tokens owned by the address
Gas Estimate: ~2,000 gas Example Usage:
async function getBalance(address) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  
  const contract = new ethers.Contract(
    '0x1234567890123456789012345678901234567890',
    IDENTITY_SBT_ABI,
    provider
  );
  
  const balance = await contract.balanceOf(address);
  console.log(`Balance: ${balance.toString()}`);
  return balance;
}

ownerOf

Get the owner of a specific token.
function ownerOf(uint256 tokenId) external view returns (address);
Parameters:
  • tokenId (uint256): The ID of the token
Returns:
  • address: The owner of the token
Gas Estimate: ~2,000 gas Requirements:
  • Token must exist
Example Usage:
async function getOwner(tokenId) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  
  const contract = new ethers.Contract(
    '0x1234567890123456789012345678901234567890',
    IDENTITY_SBT_ABI,
    provider
  );
  
  const owner = await contract.ownerOf(tokenId);
  console.log(`Owner: ${owner}`);
  return owner;
}

isActivated

Check if a token is activated (soulbound).
function isActivated(uint256 tokenId) external view returns (bool);
Parameters:
  • tokenId (uint256): The ID of the token
Returns:
  • bool: True if the token is activated, false otherwise
Gas Estimate: ~2,000 gas Example Usage:
async function checkActivation(tokenId) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  
  const contract = new ethers.Contract(
    '0x1234567890123456789012345678901234567890',
    IDENTITY_SBT_ABI,
    provider
  );
  
  const isActivated = await contract.isActivated(tokenId);
  console.log(`Token ${tokenId} is ${isActivated ? 'activated' : 'not activated'}`);
  return isActivated;
}

isSoulbound

Check if a token is soulbound (cannot be transferred).
function isSoulbound(uint256 tokenId) external view returns (bool);
Parameters:
  • tokenId (uint256): The ID of the token
Returns:
  • bool: True if the token is soulbound, false otherwise
Gas Estimate: ~2,000 gas Note: This function returns the same value as isActivated() since activation makes a token soulbound.

tokenURI

Get the metadata URI for a token.
function tokenURI(uint256 tokenId) external view returns (string memory);
Parameters:
  • tokenId (uint256): The ID of the token
Returns:
  • string: The metadata URI for the token
Gas Estimate: ~3,000 gas Example Usage:
async function getTokenURI(tokenId) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  
  const contract = new ethers.Contract(
    '0x1234567890123456789012345678901234567890',
    IDENTITY_SBT_ABI,
    provider
  );
  
  const uri = await contract.tokenURI(tokenId);
  console.log(`Token URI: ${uri}`);
  return uri;
}

Metadata Functions

setTokenURI

Update the metadata URI for a token.
function setTokenURI(uint256 tokenId, string memory newURI) external;
Parameters:
  • tokenId (uint256): The ID of the token
  • newURI (string): The new metadata URI
Returns: None Gas Estimate: ~30,000 gas Requirements:
  • Caller must have METADATA_ROLE or be the token owner
  • Token must exist
  • Token must not be activated (metadata is immutable after activation)
Events Emitted:
  • MetadataUpdated(uint256 indexed tokenId, string newURI)
Example Usage:
async function updateTokenURI(tokenId, newURI) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  const signer = provider.getSigner();
  
  const contract = new ethers.Contract(
    '0x1234567890123456789012345678901234567890',
    IDENTITY_SBT_ABI,
    signer
  );
  
  const tx = await contract.setTokenURI(tokenId, newURI);
  await tx.wait();
  
  console.log(`Token ${tokenId} metadata updated to: ${newURI}`);
}

Access Control Functions

grantRole

Grant a role to an address.
function grantRole(bytes32 role, address account) external;
Parameters:
  • role (bytes32): The role to grant
  • account (address): The address to grant the role to
Returns: None Gas Estimate: ~50,000 gas Requirements:
  • Caller must have the admin role for the specified role
Example Usage:
async function grantMinterRole(account) {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_KEY');
  const signer = provider.getSigner();
  
  const contract = new ethers.Contract(
    '0x1234567890123456789012345678901234567890',
    IDENTITY_SBT_ABI,
    signer
  );
  
  const MINTER_ROLE = await contract.MINTER_ROLE();
  const tx = await contract.grantRole(MINTER_ROLE, account);
  await tx.wait();
  
  console.log(`Minter role granted to ${account}`);
}

revokeRole

Revoke a role from an address.
function revokeRole(bytes32 role, address account) external;
Parameters:
  • role (bytes32): The role to revoke
  • account (address): The address to revoke the role from
Returns: None Gas Estimate: ~50,000 gas Requirements:
  • Caller must have the admin role for the specified role

hasRole

Check if an address has a specific role.
function hasRole(bytes32 role, address account) external view returns (bool);
Parameters:
  • role (bytes32): The role to check
  • account (address): The address to check
Returns:
  • bool: True if the address has the role, false otherwise
Gas Estimate: ~2,000 gas

Transfer Functions

transferFrom

Transfer a token from one address to another.
function transferFrom(address from, address to, uint256 tokenId) external;
Parameters:
  • from (address): The current owner of the token
  • to (address): The new owner of the token
  • tokenId (uint256): The ID of the token to transfer
Returns: None Gas Estimate: ~80,000 gas (before activation), reverts (after activation) Requirements:
  • Token must not be activated (soulbound)
  • Caller must be authorized to transfer the token
  • to cannot be the zero address
Note: This function will revert if the token is activated (soulbound).

safeTransferFrom

Safely transfer a token from one address to another.
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) external;
Parameters:
  • from (address): The current owner of the token
  • to (address): The new owner of the token
  • tokenId (uint256): The ID of the token to transfer
  • data (bytes, optional): Additional data to send with the transfer
Returns: None Gas Estimate: ~80,000 gas (before activation), reverts (after activation) Requirements:
  • Token must not be activated (soulbound)
  • Caller must be authorized to transfer the token
  • to cannot be the zero address
Note: This function will revert if the token is activated (soulbound).

Approval Functions

approve

Approve an address to transfer a specific token.
function approve(address to, uint256 tokenId) external;
Parameters:
  • to (address): The address to approve
  • tokenId (uint256): The ID of the token to approve
Returns: None Gas Estimate: ~50,000 gas (before activation), reverts (after activation) Requirements:
  • Caller must be the owner of the token
  • Token must not be activated (soulbound)
Note: This function will revert if the token is activated (soulbound).

getApproved

Get the approved address for a specific token.
function getApproved(uint256 tokenId) external view returns (address);
Parameters:
  • tokenId (uint256): The ID of the token
Returns:
  • address: The approved address (zero address if none)
Gas Estimate: ~2,000 gas

setApprovalForAll

Approve or revoke approval for all tokens.
function setApprovalForAll(address operator, bool approved) external;
Parameters:
  • operator (address): The address to approve or revoke
  • approved (bool): True to approve, false to revoke
Returns: None Gas Estimate: ~50,000 gas Note: This function works for all tokens, but individual transfers will still revert if the token is activated.

isApprovedForAll

Check if an operator is approved for all tokens.
function isApprovedForAll(address owner, address operator) external view returns (bool);
Parameters:
  • owner (address): The owner of the tokens
  • operator (address): The operator to check
Returns:
  • bool: True if the operator is approved, false otherwise
Gas Estimate: ~2,000 gas

Error Handling

Common Errors

ErrorDescriptionSolution
"Token is soulbound"Attempting to transfer an activated tokenCheck if token is activated before transfer
"Not token owner"Caller is not the owner of the tokenEnsure caller is the token owner
"Already activated"Token is already activatedCheck activation status before calling activate
"Token does not exist"Token ID does not existVerify token ID is valid
"AccessControl: account is missing role"Caller lacks required roleGrant appropriate role to caller

Error Handling Examples

async function safeMint(to, name, metadataURI) {
  try {
    const tx = await contract.mint(to, name, metadataURI);
    const receipt = await tx.wait();
    return receipt;
  } catch (error) {
    if (error.message.includes('AccessControl')) {
      console.error('Insufficient permissions to mint');
    } else if (error.message.includes('name already exists')) {
      console.error('Name is already taken');
    } else {
      console.error('Minting failed:', error.message);
    }
    throw error;
  }
}

Gas Optimization Tips

Batch Operations

// Batch multiple operations in a single transaction
async function batchMint(identities) {
  const tx = await contract.batchMint(identities);
  const receipt = await tx.wait();
  return receipt;
}

Gas Estimation

// Estimate gas before sending transaction
async function estimateGasMint(to, name, metadataURI) {
  const gasEstimate = await contract.estimateGas.mint(to, name, metadataURI);
  console.log(`Estimated gas: ${gasEstimate.toString()}`);
  return gasEstimate;
}