Skip to main content

GhostERC20

A privacy-enabled ERC20 token that supports Ghost Protocol commit and reveal operations. GhostERC20 tokens are standard ERC20 tokens with additional mint/burn functions restricted to the CommitRevealVault.

Interface

interface IGhostERC20 is IERC20 {
// View functions
function vault() external view returns (address);
function factory() external view returns (address);
function tokenIdHash() external view returns (bytes32);
function isGhostEnabled() external view returns (bool);

// Vault-only functions
function mint(address to, uint256 amount) external;
function burn(address from, uint256 amount) external;

// Factory-only function
function enableGhost() external;
}

Standard ERC20 operations

GhostERC20 tokens behave like any ERC20 token for standard operations:

const token = new ethers.Contract(tokenAddress, [
'function balanceOf(address) view returns (uint256)',
'function transfer(address to, uint256 amount) returns (bool)',
'function approve(address spender, uint256 amount) returns (bool)',
'function allowance(address owner, address spender) view returns (uint256)',
], signer);

// Check balance
const balance = await token.balanceOf(myAddress);

// Transfer tokens
await token.transfer(recipient, ethers.parseEther('10'));

// Approve vault for commit
await token.approve('0x443434113980Ab9d5Eef0Ace7d1A29AB68Af6c70', ethers.parseEther('10'));

Ghost Protocol operations

When a GhostERC20 token is committed through the vault:

  1. The vault calls token.burn(from, amount) — destroys the tokens
  2. A Poseidon commitment is stored in the Merkle tree
  3. The tokenIdHash identifies this token type in the circuit

When revealing:

  1. The vault calls token.mint(recipient, amount) — creates fresh tokens
  2. The nullifier is registered to prevent double-reveal

Token ID hash

Each GhostERC20 has a unique tokenIdHash that identifies it in the ZK circuit:

cast call $TOKEN_ADDRESS "tokenIdHash()(bytes32)" \
--rpc-url https://testnet.specterchain.com

This hash is used as one of the public inputs to the Groth16 proof, ensuring you can only reveal the same type of token that was committed.

Deployed tokens

TokenAddress
gUSDC0x65c9091a6A45Db302a343AF460657C298FAA222D
gWETH0x923295a3e3bE5eDe29Fc408A507dA057ee044E81
gLABS0x062f8a68f6386c1b448b3379abd369825bec9aa2