ERC-8047: Forensic Token (Forest)

Discussion topic for ERC-8047: Forensic Token (Forest)

Update Log

  • 2025-10-13: Initiate topic for discussion
  • 2025-11-13: Update Specification and Rationale Section
  • 2025-11-14: Update Specification Section (URI Schema)

External Reviews

  • None as of 2025-10-13

Outstanding Issue

  • None as of 2025-10-13

After a pull request is created and an ERC number is assigned, all changes will be managed through pull requests. This topic provides an initial draft version to help those who are not familiar with using GitHub.
Note: This topic will be updated over time to stay in sync with the pull request, but updates may be slow.

Abstract

Forest is a DAG-inspired token model designed to enhance traceability and regulatory compliance in digital currency systems. By introducing hierarchical token tracking, it enables efficient enforcement on any token linked to suspicious activity with level/root. Enforcement actions, such as freezing specific tokens or partitioning all tokens with relational links, are optimized to operate at O(1) complexity.

Motivation

The present-day Central Bank Digital Currency (CBDC) and Private Money concept aims to utilize the advantages of blockchain or Distributed Ledger Technology (DLT) that provide immutability, transparency, and security, and it adopts smart contracts, which play a key role in creating programmable money. However, technology itself gives an advantage and eliminates the ideal problem of compliance with the regulator and the Anti-Money Laundering and Countering the Financing of Terrorism (AML/CFT) standard, but it does not seem practical to be done in the real world and is not efficiently responsible for the financial crime or incidents that occur in the open network of economics.

Specification

The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Compatible implementations MUST implement the IERC8047 interface and MUST inherit from ERC-1155 and ERC-5615 interfaces. All functions defined in the interface MUST be present and all function behavior MUST meet the behavior specification requirements below.

// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.8.0 <0.9.0;

/**
 * @title ERC-8047 interface
 */

interface IERC8047 is IERC1155, IERC5615 {
    /**
     * @dev Emitted when a new token is created within a DAG.
     * @param root The root token ID of the DAG to which the new token belongs.
     * @param id The ID of the newly created token.
     * @param from The address that created/minted the token.
     */
    event TokenCreated(
        uint256 indexed root,
        uint256 id,
        address indexed from
    );

    /**
     * @dev Emitted when a token is spent or partially spent.
     * @param id The ID of the token being spent.
     * @param value The amount of the token that was spent.
     */
    event TokenSpent(
        uint256 indexed id,
        uint256 value
    );

    /**
     * @dev Returns the latest (highest) level of the DAG that a given token belongs to.
     * @param id The ID of the token.
     * @return uint256 The latest DAG level for the token.
     */
    function latestDAGLevelOf(uint256 id) external view returns (uint256);

    /**
     * @dev Returns the level of token within its DAG.
     * @param id The ID of the token.
     * @return uint256 The level of the token in the DAG.
     */
    function levelOf(uint256 id) external view returns (uint256);

    /**
     * @dev Returns the owner of a given token.
     * @param id The ID of the token.
     * @return address The address that owns the token.
     */
    function ownerOf(uint256 id) external view returns (address);

    /**
     * @dev Returns the parent token ID of a given token.
     * @param id The ID of the token.
     * @return uint256 The ID of the parent token. Returns 0 if the token is a root.
     */
    function parentOf(uint256 id) external view returns (uint256);

    /**
     * @dev Returns the root token ID of the DAG to which a given token belongs.
     * @param id The ID of the token.
     * @return uint256 The root token ID of the DAG.
     */
    function rootOf(uint256 id) external view returns (uint256);

    /**
     * @dev Returns total supply of all token.
     * @custom:overloading of {IERC5615.totalSupply}
     * @return uint256 The total supply of all token.
     */
    function totalSupply() external view returns (uint256);
}

Behavior Specification

Minting

  • When mint a token, the id MUST NOT be supplied by the minter, the id MUST be generate by the contract itself.

  • The value of the id MUST NOT be 0. If value is 0, the mint operation MUST revert.

  • The events TokenCreated MUST emit when the mint operation is successful.

Burning

  • When burn a token, the id MUST NOT be deleted from the DAG. Instead, its value MUST be set to 0, and the operation MUST NOT create a new transaction to the zero address.

  • The events TokenSpent MUST emit when the burn operation is successful.

Transferring

  • The safeTransferFrom MUST verify that the id exists. If it does not, the function MUST revert.
  • The sender MUST be the owner of the id or an approved operator.
  • The value to be spent MUST NOT exceed the value of the id. If it does, the function MUST revert.
  • The safeTransferFrom function MUST mint a new id as a child of the id being spent. The new id MUST have its parent set to the id that was spent. and its level MUST be incremented by 1 relative to the parent.
  • The events TokenSpent MUST emit when spending transaction.

Merging

  • To merge two or more id into a new id, all tokens MUST be part of the same DAG (i.e., share the same root).
    new id from merging will be
k : The highest level from token ids that will be merging.
newTokenIdLevel = k + 1
  • The TokenSpent event MUST be emitted for all id involved in the merge when the merging operation is successful.

ERC-8047 URI JSON Schema

In ERC-8047, each token has a unique id to track its movement in the DAG (like serial numbers), but all tokens representing the same asset share a single metadata URI. This reflects the fungible nature of the asset (like fiat currency)

  • All tokens of the same asset MUST reference the same URI, regardless of their individual id.
  • Implementations SHOULD follow the JSON Schema definition provided below for consistency across client implementations.
{
  "title": "Token Metadata",
  "description": "Metadata schema for ERC-8047: Forensic Token (Forest).",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Human-readable name of the asset represented by this token."
    },
    "symbol": {
      "type": "string",
      "description": "Ticker symbol or shorthand identifier for the token."
    },
    "decimals": {
      "type": "integer",
      "description": "Number of decimal places used to display token amounts. For example, 18 means the token amount should be divided by 10^18 to get its user representation."
    },
    "description": {
      "type": "string",
      "description": "Detailed description of the asset represented by this token."
    },
    "image": {
      "type": "string",
      "format": "uri",
      "description": "A URI pointing to an image (MIME type image/*) that visually represents the asset. Recommended image width: 320–1080 pixels; aspect ratio: between 1.91:1 and 4:5."
    },
    "properties": {
      "type": "object",
      "description": "Container for extended metadata such as compliance, traceability, and DAG lineage.",
      "properties": {
        "compliance": {
          "type": "object",
          "description": "Compliance and policy information for the asset.",
          "properties": {
            "issuer": {
              "type": "string",
              "description": "Legal entity responsible for issuing or managing this asset."
            },
            "jurisdiction": {
              "type": "string",
              "description": "Legal jurisdiction or regulatory domain governing this asset."
            },
            "policies": {
              "type": "string",
              "format": "uri",
              "description": "URI linking to AML/CFT, compliance, or risk policy documentation."
            },
            "enforcement_authority": {
              "type": "string",
              "format": "uri",
              "description": "URI to the entity or endpoint responsible for enforcement actions (e.g., freeze, revoke)."
            }
          },
          "required": ["issuer", "policies"]
        }
      },
      "required": ["compliance"]
    }
  },
  "required": ["name", "description", "image", "properties"]
}

A complete JSON Schema reference for ERC-8047 metadata is provided below for validation and implementation guidance.

{
  "name": "United States Dollar",
  "symbol": "USD",
  "decimals": 18,
  "description": "A compliant, traceable digital representation of the U.S. Dollar using the ERC-8047: Forensic Token (Forest).",
  "image": "https://acmee-finance.com/assets/images/USD_icon.png",
  "properties": {
    "compliance": {
      "issuer": "Acmee Finance Inc.",
      "jurisdiction": "US-NY",
      "policies": "https://acmee-finance.com/policies",
      "enforcement_authority": "https://acmee-finance.com/enforcement"
    }
  }
}

Rationale

Features ERC-20 UTXO Forest
Freeze the sender account.
Freeze the recipient account.
Freeze the certain partial amount token.
Freeze the specifics id.
Freeze the specifics id that are relevant to the root.
Freeze all id before or after specific hierarchy level.
  • ERC-20 provide events and keep tracking each Transfer,
    but the problem is the ERC-20 model can’t separate clean money from dirty money,
    due to the ERC-20not have id to keep tracking each token when it’s moved.
  • UTXO facing challenge to combine multiple UnspentTransaction and spent as one,
    in case, user want to spend value that greater that selected UnspentTransaction.
    Possible solution: prepare and batch as an array.
    UTXO maintain the amount of money or group of money in each individual transaction.
    Each UnspentTransaction is not underlying any account,
    so to spend the transaction, the caller needs to be the owner of the transaction that needs to be spent.
  • Forest use to modify an existing state rather than create a new transaction, like in UTXO do,
    it allows spending the token multiple times till it’s met 0, The Forest model enables tracking of child/subtree structures.
    providing a hierarchical view of token flows and relationships,
    which is not possible in traditional token standards like ERC-20, ERC-1400, and ERC-3643.

Granular Policy Enforcement

  • Restrict the transaction with specific id.
  • Restrict all transactions with specific tokenLevel.
    • before tokenLevel x
    • after tokenLevel x
    • between tokenLevel x and y
  • Restrict all transactions with specific root id.

Reverse Topological Ordering of Transactions

One of the key benefits of the Forest is that it natively supports reverse topological traversal. Each token stores a reference to its parent token, allowing to efficiently iterate parentOf back to the root of the DAG.

This back-to-root traversal differs from a full DAG traversal. It only follows the lineage of a specific token id up to its root, rather than visiting all transactions in the DAG.

Spendable balance via off-chain

On-chain iteration to retrieve spendableBalanceOf can be gas-intensive and inefficient, especially for large DAGs or multiple sets of DAGs. To address this, the current spendableBalanceOf account can be determined off-chain by deploying a service that subscribes to events emitted by the contract. This service calculates the spendable balance by reconciling the account’s total balanceOf with any tokens that have been frozen or restricted due to hierarchical or forensic rules, providing an accurate representation of the amount available for transfer.

Backwards Compatibility

This standard is fully compatible with ERC-1155 and ERC-5615

Security Considerations

Denial Of Service

Run out of gas problem due to the operation consuming more gas if transferring in safeBatchTransferFrom.

Gas Limit Vulnerabilities

Exceeds block gas limit if the blockchain has a block gas limit lower than the gas used in the transaction.

Data Fragmentation

The Forest model tracks all assets within the system, which can be represented mathematically as

A^d: The decimals of the asset.  
A^t: The total supply of the asset.  
A^s: The possible asset is represented in the id.
A^s = A^t x A^d

While this ensures precision, the high granularity can increase storage needs.
Traditional finance often uses simpler decimals like 2, 4 or 6, avoiding excessive detail.
Adopting similar strategies could help balance granularity with efficiency. Or limit value as MINIMUM_AMOUNT check before spending.

Confidentiality

Maybe it can be linked to identity. from spending and behavior usage

High Complexity

Forest may introduce potential vulnerabilities such as reentrancy or misbehavior when applied with other smart contracts.

Standard and knowledge-based that might related to this topic

Historical links related to this topic

[WIP] Reference implementation

1 Like