Skip to main content

The Contract

pragma language_version >= 0.17.0;

import CompactStandardLibrary;

// Account balances
export ledger balances: Map<Either<ZswapCoinPublicKey, ContractAddress>, Uint<128>>;

// Total token supply
export ledger totalSupply: Uint<128>;

// Get total circulating supply
export circuit getTotalSupply(): Uint<128> {
    return totalSupply;
}

// Burn your own tokens
export circuit burn(amount: Uint<128>): [] {
    const account = left<ZswapCoinPublicKey, ContractAddress>(ownPublicKey());
    _burn(account, amount);
}

// Burn tokens from another account (with approval)
export circuit burnFrom(
    account: Either<ZswapCoinPublicKey, ContractAddress>,
    amount: Uint<128>
): [] {
    const spender = left<ZswapCoinPublicKey, ContractAddress>(ownPublicKey());

    // Check and spend allowance (requires approval system)
    _spendAllowance(account, spender, amount);

    _burn(account, amount);
}

// Internal: Burn tokens
circuit _burn(
    account: Either<ZswapCoinPublicKey, ContractAddress>,
    amount: Uint<128>
): [] {
    // Get current balance
    const currentBalance = getBalance(account);

    // Check sufficient balance
    assert(currentBalance >= amount, "Burn amount exceeds balance");

    // Decrease account balance
    balances.insert(disclose(account), disclose(currentBalance - amount));

    // Decrease total supply
    totalSupply = disclose(totalSupply - amount);
}

// Helper: Get balance
circuit getBalance(account: Either<ZswapCoinPublicKey, ContractAddress>): Uint<128> {
    if (!balances.member(disclose(account))) {
        return 0;
    }
    return balances.lookup(disclose(account));
}

// Helper: Spend allowance (simplified - see Approval tutorial for full implementation)
circuit _spendAllowance(
    owner: Either<ZswapCoinPublicKey, ContractAddress>,
    spender: Either<ZswapCoinPublicKey, ContractAddress>,
    amount: Uint<128>
): [] {
    // Check allowance and decrease it
    // See Approval & Allowance tutorial for complete implementation
}

How It Works

Burning Process

circuit _burn(
    account: Either<ZswapCoinPublicKey, ContractAddress>,
    amount: Uint<128>
): [] {
    // Get current balance
    const currentBalance = getBalance(account);

    // Check sufficient balance
    assert(currentBalance >= amount, "Burn amount exceeds balance");

    // Decrease account balance
    balances.insert(disclose(account), disclose(currentBalance - amount));

    // Decrease total supply
    totalSupply = disclose(totalSupply - amount);
}
Burning flow:
  1. Get current balance: Check how many tokens account has
  2. Check sufficient balance: Ensure account has enough tokens to burn
  3. Decrease account balance: Remove tokens from account
  4. Decrease total supply: Remove tokens from circulation
Result: Tokens are permanently destroyed and removed from total supply.

Burning Your Own Tokens

export circuit burn(amount: Uint<128>): [] {
    const account = left<ZswapCoinPublicKey, ContractAddress>(ownPublicKey());
    _burn(account, amount);
}
Users can always burn their own tokens:
  • ownPublicKey(): Automatically gets caller’s address
  • Self-burn: No approval needed to burn your own tokens
  • Deflationary: Reduces circulating supply permanently
  • Voluntary: Anyone can choose to burn their tokens

Delegated Burning

export circuit burnFrom(
    account: Either<ZswapCoinPublicKey, ContractAddress>,
    amount: Uint<128>
): [] {
    const spender = left<ZswapCoinPublicKey, ContractAddress>(ownPublicKey());

    // Check allowance (requires approval system)
    _spendAllowance(account, spender, amount);

    _burn(account, amount);
}
Burn someone else’s tokens (with their approval):
  • Requires approval: Account must first approve the burner (see Approval tutorial)
  • Useful for contracts: Contracts that burn tokens as part of their logic
  • Spends allowance: Decreases the approved amount
Use case: A staking contract that burns tokens when users stake, or a buyback contract that burns purchased tokens.

What’s Next