ZIPsZoo Proposals
ZIP-0448

ZRC-20: Fungible Token Standard

Draft

Conservation-aware fungible token standard for the Zoo ecosystem with impact tracking and auto-donation extensions

Type
Standards Track
Category
ZRC
Author
Zoo Labs Foundation
Created
2025-01-15
tokenfungibleconservationdefizrc-20

ZIP-0700: ZRC-20 Fungible Token Standard

Abstract

This proposal defines ZRC-20, the canonical fungible token standard for the Zoo L2 chain (Chain ID: 200200). ZRC-20 is fully ERC-20 compatible and extends the Lux LRC-20 standard (LP-3020) with conservation-specific functionality: on-chain impact tracking, configurable auto-donation on transfers, and a burnable-for-conservation mechanism that retires tokens in exchange for verified conservation credits. ZRC-20 also incorporates the LRC-20 extension suite -- burnable, mintable, bridgeable, capped supply, voting, permit (EIP-2612), and flash mint -- adapted for the Zoo ecosystem.

Motivation

The Zoo ecosystem requires a fungible token primitive that:

  1. ERC-20 Compatibility: Wallets, DEXs, and bridges must work without modification.
  2. Conservation Alignment: Every token transfer can contribute measurable conservation impact per ZIP-0500 ESG principles.
  3. Lux Interoperability: Tokens must bridge cleanly to Lux C-Chain via LP-3800 and LP-6000, conforming to ZIP-0013.
  4. Governance Readiness: Voting weight and delegation must be first-class features for DAO-governed conservation funding.
  5. Capital Efficiency: Flash minting and permit-based approvals reduce gas costs and improve DeFi composability.

Existing ERC-20 implementations lack any mechanism to track ecological impact or direct value flows toward conservation. ZRC-20 fills this gap while remaining a drop-in replacement for any ERC-20 consumer.

Specification

Core Interface

The ZRC-20 standard implements the full ERC-20 interface plus conservation extensions.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title IZRC20
 * @notice Zoo ecosystem fungible token standard with conservation impact tracking.
 * @dev Fully ERC-20 compatible. Extends LRC-20 (LP-3020) with impact and donation features.
 */
interface IZRC20 {
    // ──────────────────────────────────────────────
    // ERC-20 Core (unchanged)
    // ──────────────────────────────────────────────
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    // ──────────────────────────────────────────────
    // Conservation Extensions
    // ──────────────────────────────────────────────

    /**
     * @notice Returns the conservation fund address that receives auto-donations.
     */
    function conservationFund() external view returns (address);

    /**
     * @notice Returns the auto-donation rate in basis points (0-10000).
     *         A value of 50 means 0.50% of each transfer is directed to the fund.
     */
    function donationBasisPoints() external view returns (uint16);

    /**
     * @notice Returns cumulative conservation impact credits generated by this token.
     */
    function totalImpactCredits() external view returns (uint256);

    /**
     * @notice Returns impact credits attributed to a specific address.
     */
    function impactCreditsOf(address account) external view returns (uint256);

    /**
     * @notice Burns `amount` tokens from the caller and mints `amount` conservation
     *         impact credits to the caller, verified against the Zoo Impact Oracle.
     */
    function burnForConservation(uint256 amount) external returns (uint256 creditsIssued);

    /**
     * @notice Emitted when tokens are donated to the conservation fund during a transfer.
     */
    event ConservationDonation(
        address indexed from,
        address indexed to,
        uint256 transferAmount,
        uint256 donationAmount
    );

    /**
     * @notice Emitted when tokens are burned in exchange for conservation credits.
     */
    event BurnedForConservation(
        address indexed burner,
        uint256 amountBurned,
        uint256 creditsIssued
    );

    /**
     * @notice Emitted when the donation rate is updated by governance.
     */
    event DonationRateUpdated(uint16 oldRate, uint16 newRate);
}

Extension Interfaces

ZRC-20 tokens MAY implement any combination of the following extensions, each derived from the LRC-20 extension suite (LP-3020).

/**
 * @title IZRC20Burnable
 */
interface IZRC20Burnable is IZRC20 {
    function burn(uint256 amount) external;
    function burnFrom(address account, uint256 amount) external;
}

/**
 * @title IZRC20Mintable
 */
interface IZRC20Mintable is IZRC20 {
    function mint(address to, uint256 amount) external;
    event Minted(address indexed to, uint256 amount, address indexed minter);
}

/**
 * @title IZRC20Capped
 */
interface IZRC20Capped is IZRC20 {
    function cap() external view returns (uint256);
}

/**
 * @title IZRC20Votes
 * @dev Compatible with OpenZeppelin Governor and Zoo DAO governance (ZIP-0100).
 */
interface IZRC20Votes is IZRC20 {
    function getVotes(address account) external view returns (uint256);
    function getPastVotes(address account, uint256 timepoint) external view returns (uint256);
    function getPastTotalSupply(uint256 timepoint) external view returns (uint256);
    function delegates(address account) external view returns (address);
    function delegate(address delegatee) external;
    function delegateBySig(
        address delegatee,
        uint256 nonce,
        uint256 expiry,
        uint8 v, bytes32 r, bytes32 s
    ) external;
}

/**
 * @title IZRC20Permit
 * @dev EIP-2612 gasless approvals.
 */
interface IZRC20Permit is IZRC20 {
    function permit(
        address owner, address spender, uint256 value,
        uint256 deadline, uint8 v, bytes32 r, bytes32 s
    ) external;
    function nonces(address owner) external view returns (uint256);
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

/**
 * @title IZRC20FlashMint
 * @dev EIP-3156 flash loan support.
 */
interface IZRC20FlashMint is IZRC20 {
    function maxFlashLoan(address token) external view returns (uint256);
    function flashFee(address token, uint256 amount) external view returns (uint256);
    function flashLoan(
        address receiver, address token, uint256 amount, bytes calldata data
    ) external returns (bool);
}

/**
 * @title IZRC20Bridgeable
 * @dev LP-3800 / LP-6000 bridgeable asset interface for Lux cross-chain transfers.
 */
interface IZRC20Bridgeable is IZRC20 {
    function bridge() external view returns (address);
    function mintFromBridge(address to, uint256 amount, bytes32 sourceChainTxHash) external;
    function burnForBridge(uint256 amount, bytes32 destinationChainId) external;
    event BridgeMint(address indexed to, uint256 amount, bytes32 indexed sourceTxHash);
    event BridgeBurn(address indexed from, uint256 amount, bytes32 indexed destChainId);
}

Auto-Donation Mechanism

On every transfer and transferFrom call where donationBasisPoints > 0:

  1. Compute donationAmount = amount * donationBasisPoints / 10000.
  2. Transfer donationAmount to conservationFund().
  3. Transfer amount - donationAmount to the recipient.
  4. Emit ConservationDonation(from, to, amount, donationAmount).

The donation rate is updatable only by the token's governance (typically a ZooGovernor timelock). The rate MUST NOT exceed 500 basis points (5%).

Burn-for-Conservation

The burnForConservation function:

  1. Burns amount tokens from msg.sender, reducing totalSupply.
  2. Queries the Zoo Impact Oracle (a trusted on-chain oracle registered in ZIP-0100) for the current conservation credit exchange rate.
  3. Mints creditsIssued impact credits to the caller's impact balance.
  4. Emits BurnedForConservation(msg.sender, amount, creditsIssued).

Impact credits are non-transferable soulbound records. They serve as on-chain proof of conservation contribution per ZIP-0501.

Token Registration

All ZRC-20 tokens deployed on Zoo L2 MUST register in the Zoo Contract Registry (ZIP-0100) with the following metadata:

FieldTypeDescription
standardstring"ZRC-20"
extensionsstring[]List of implemented extension names
conservationFundaddressFund receiving auto-donations
donationBasisPointsuint16Current donation rate
impactOracleAddressaddressOracle used for credit pricing

Rationale

Why extend ERC-20 rather than create a new standard? Compatibility. Every wallet, DEX, aggregator, and bridge that speaks ERC-20 works with ZRC-20 out of the box. The conservation extensions are additive -- contracts unaware of them simply see a standard ERC-20.

Why auto-donation instead of a transfer tax? Transparency. A tax is hidden in the transfer amount. Auto-donation explicitly splits the transfer into a user amount and a donation amount, with a dedicated event. Users and UIs can clearly display both.

Why soulbound impact credits? Impact credits represent verified conservation contributions. Making them transferable would create a speculative market that decouples price from actual ecological impact, undermining the mission per ZIP-0500.

Why cap the donation rate at 5%? To prevent governance capture where a majority votes to extract excessive value from transfers. The 5% ceiling protects minority holders and DeFi composability.

Backwards Compatibility

ZRC-20 is fully backwards compatible with ERC-20 (EIP-20). Any contract or off-chain tool that interacts with standard ERC-20 functions will work without modification. The conservation extensions use separate function selectors that do not conflict with ERC-20, ERC-165, or any standard Ethereum interface.

Tokens bridged from Lux C-Chain via LP-6000 are wrapped as ZRC-20 with donationBasisPoints = 0 by default, preserving exact transfer semantics for bridged assets.

Security Considerations

  1. Reentrancy: The burnForConservation function interacts with an external oracle. Implementations MUST follow checks-effects-interactions and use reentrancy guards.
  2. Oracle Manipulation: The Impact Oracle must be resistant to flash loan manipulation. Implementations SHOULD use time-weighted average pricing (TWAP) or multi-source aggregation.
  3. Donation Rate Governance: Changes to donationBasisPoints MUST go through a timelock (minimum 48 hours) to prevent flash governance attacks.
  4. Bridge Security: mintFromBridge MUST only be callable by the registered bridge contract. Implementations MUST verify the source chain transaction hash has not been replayed.
  5. Flash Mint Caps: Flash minting MUST NOT exceed totalSupply to prevent economic attacks on downstream protocols.
  6. Rounding: Donation amount calculation must round down to prevent dust accumulation or transfer failures on small amounts.

References

Copyright

Copyright and related rights waived via CC0.