3DPass Custom EVM Precompiles: PoScan, Identity, and Serial Numbers Guide

The 3DPass blockchain extends standard Ethereum compatibility with three custom EVM precompiles at addresses 2307, 2308, and 2309, enabling Solidity contracts to natively interact with the PoScan, Identity, and Serial Numbers Substrate pallets.

The 3dpass/3dp repository implements a Substrate-based network with full EVM support through Frontier. To unify the developer experience across ecosystems, the runtime registers custom EVM precompiles that forward calls from smart contracts directly to native pallets. This architecture allows Solidity developers to access complex on-chain functionality—such as 3D object scanning and identity management—without off-chain bridges or oracle dependencies.

Overview of 3DPass Custom EVM Precompiles

The runtime defines three custom precompiles in [runtime/src/precompiles.rs](https://github.com/3dpass/3dp/blob/main/runtime/src/precompiles.rs), each mapped to a specific address and Substrate pallet:

Address Precompile Type Source File Exposed Pallet
2307 PoScanPrecompile<R> precompiles/poscan/src/lib.rs PoScan (object submission & QC)
2308 IdentityPrecompile<R> precompiles/identity/src/lib.rs Identity (on-chain identity management)
2309 SerialNumbersPrecompile<R> precompiles/serial-numbers/src/lib.rs Serial Numbers (asset tracking)

Each implementation uses the precompile_utils::precompile macro to handle ABI encoding, gas metering, and event logging automatically.

PoScan Precompile (Address 2307)

The PoScan precompile at address 2307 exposes the pallet_poscan functionality to EVM environments. This pallet manages 3D object submissions, quality control (QC) workflows, ownership transfers, and reward distributions.

Core Functionality

According to the implementation in [precompiles/poscan/src/lib.rs](https://github.com/3dpass/3dp/blob/main/precompiles/poscan/src/lib.rs), the precompile provides Solidity-friendly methods for:

  • Object queries: Retrieve metadata including hashes, creation blocks, approval status, and IPFS links
  • Submission: Submit new 3D objects with category, algorithm identifiers, and proof-of-existence hashes
  • QC workflows: Manage quality control timeouts and approval requirements
  • Fee calculations: Query required fees for object submission and processing

Solidity Integration

Developers interact with the precompile by casting the decimal address 2307 to an Ethereum address. The Solidity function signatures must match the #[precompile::public(...)] attributes defined in the Rust source.

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

contract PoScanClient {
    // Precompile address: 2307
    address constant PoScan = address(2307);

    function getObject(uint32 objIdx) external view returns (
        bool isValid,
        uint8 state,
        uint64 stateBlock,
        uint8 category,
        uint64 whenCreated,
        uint64 whenApproved,
        bool isPrivate,
        bytes32[] memory hashes,
        uint8 numApprovals,
        uint32[] memory propIdx,
        uint128[] memory propMax,
        bool isReplica,
        uint32 originalObj,
        uint64 snHash,
        bool abdicated,
        bool selfProved,
        bytes32 proofOfExistence,
        bytes memory ipfsLink,
        uint32 qcTimeout
    ) {
        return PoScan.getObject(objIdx);
    }

    function submitObject(
        uint8 category,
        uint8 algo3d,
        bool isPrivate,
        bytes calldata obj,
        uint8 numApprovals,
        bytes32[] calldata hashes,
        uint32[] calldata propIdx,
        uint128[] calldata propMax,
        bool isReplica,
        uint32 originalObj,
        uint64 snHash,
        bool isSelfProved,
        bytes32 proof,
        bytes calldata ipfsLink
    ) external returns (bool) {
        return PoScan.putObject(
            category, algo3d, isPrivate, obj, numApprovals,
            hashes, propIdx, propMax, isReplica, originalObj,
            snHash, isSelfProved, proof, ipfsLink
        );
    }
}

Calls to getObject use the view modifier since they only read storage, while putObject dispatches a state-changing extrinsic to the Substrate runtime.

Identity Precompile (Address 2308)

The Identity precompile at address 2308 wraps pallet_identity, allowing smart contracts to read and manage on-chain identity information. This enables DApps to verify user identities, manage registrars, and request judgments without leaving the EVM environment.

Substrate Identity from Solidity

As implemented in [precompiles/identity/src/lib.rs](https://github.com/3dpass/3dp/blob/main/precompiles/identity/src/lib.rs), the precompile supports:

  • Identity inspection: Read an account's display name, legal name, email, web links, and verification status
  • Identity management: Set or clear identity data for the caller
  • Registrar interactions: Request judgments from on-chain registrars
  • Sub-identities: Manage sub-accounts and their relationships
pragma solidity ^0.8.0;

contract IdentityClient {
    address constant Identity = address(2308);

    function readIdentity(address account) external view returns (
        bool exists,
        string memory display,
        string memory legal,
        string memory web,
        string memory email,
        bytes32 image,
        bytes32 twitter
    ) {
        // The actual signature returns a complex tuple; this illustrates the pattern
        (exists, display, legal, web, email, image, twitter, , , , , , , , , , , ) = 
            Identity.identity(account);
    }

    function clearMyIdentity() external returns (bool) {
        return Identity.clearIdentity();
    }
}

The precompile automatically converts the caller's EVM address to a Substrate AccountId using the runtime's AddressMapping configuration before dispatching calls via RuntimeHelper::<Runtime>::try_dispatch.

Serial Numbers Precompile (Address 2309)

The Serial Numbers precompile at address 2309 provides EVM access to pallet_serial_numbers, enabling the creation, transfer, and lifecycle management of on-chain serial numbers. This is critical for tracking physical assets and supply chain verification on 3DPass.

Serial Number Management

From [precompiles/serial-numbers/src/lib.rs](https://github.com/3dpass/3dp/blob/main/precompiles/serial-numbers/src/lib.rs), exposed functions include:

  • Creation: Generate new serial numbers tied to specific block indices
  • Transfer: Move ownership between addresses
  • Expiration: Mark serial numbers as expired or used
  • Enumeration: List all serial numbers owned by a specific account
pragma solidity ^0.8.0;

contract SerialNumbersClient {
    address constant SerialNumbers = address(2309);

    function createSerialNumber(uint32 blockIdx) external returns (
        bytes16 snHash,
        uint64 snIndex,
        uint32 createdBlock
    ) {
        return SerialNumbers.createSerialNumber(blockIdx);
    }

    function getSerialNumber(uint64 snIdx) external view returns (
        bool exists,
        uint64 index,
        bytes32 hash,
        uint256 created,
        uint32 blockIdx,
        bool expired,
        uint256 expiredAt
    ) {
        return SerialNumbers.getSerialNumber(snIdx);
    }

    function transferOwnership(uint64 snIdx, address newOwner) external returns (bool) {
        return SerialNumbers.transferOwnership(snIdx, newOwner);
    }
}

How the Precompiles Bridge EVM and Substrate

The custom EVM precompiles in 3DPas follow a consistent architectural pattern that ensures type safety and gas accountability:

  1. Macro-generated boilerplate: Each precompile implements the precompile_utils::precompile macro, which generates the solve entry point required by Frontier. This macro handles automatic gas metering and reverts on pallet errors.

  2. Address mapping: The precompile reads the caller's EVM address (msg.sender in Solidity) and converts it to a Substrate AccountId using <Runtime as pallet_evm::Config>::AddressMapping::into_account_id.

  3. Dispatch mechanism: After building the appropriate pallet call, the precompile submits it to the runtime via RuntimeHelper::<Runtime>::try_dispatch, ensuring the transaction participates in Substrate's validation and weight calculation.

  4. Event compatibility: Successful operations emit Solidity-compatible events using selectors like keccak256!("ObjectSubmitted(address,uint32)"). These logs appear in standard eth_getLogs responses, enabling seamless integration with Web3.js, ethers.js, and monitoring tools like TheGraph.

Key Source Files

The following files contain the complete implementation of 3DPass's precompile architecture:

Summary

  • 3DPass provides three custom EVM precompiles at fixed addresses 2307 (PoScan), 2308 (Identity), and 2309 (Serial Numbers) that extend standard Frontier precompiles.
  • Solidity contracts can call native Substrate pallets directly without bridges, using standard function calls that handle all ABI encoding automatically.
  • The precompile_utils::precompile macro generates the required solve entry point, manages gas metering, and ensures event logs match Ethereum standards.
  • Type conversion happens transparently between EVM types (Address, U256) and Substrate primitives (AccountId, Balance) via the runtime's AddressMapping configuration.

Frequently Asked Questions

What are the exact precompile addresses for 3DPass?

The 3DPass runtime reserves decimal addresses 2307, 2308, and 2309 for custom functionality. Address 2307 hosts the PoScan precompile, 2308 hosts the Identity precompile, and 2309 hosts the Serial Numbers precompile. You can calculate the hexadecimal address by converting these integers to the low-order 20 bytes of a 256-bit value, or simply cast uint160(2307) in Solidity.

How does gas metering work for these custom precompiles?

Gas costs are calculated automatically by the precompile_utils::precompile macro based on the underlying Substrate extrinsic's weight. When a Solidity contract calls a precompile, the macro translates the EVM gas limit into Substrate weight units, executes the pallet call, and charges the appropriate gas amount to the caller. If the underlying pallet returns an error, the precompile reverts the EVM call and refunds unused gas.

Can I listen to events from these precompiles using standard Web3 tools?

Yes. The precompiles emit Solidity-compatible event logs using standard selectors (e.g., keccak256 hashes of event signatures). When a PoScan object is submitted or a serial number is transferred, the event appears in the transaction receipt's logs array. You can subscribe to these events using eth_getLogs, Web3.js, or ethers.js without any custom plugins, as the topic hashes match standard Solidity ABI specifications.

Which Substrate pallets are accessible through the 3DPass precompiles?

The three custom precompiles expose pallet_poscan (3D object scanning and quality control), pallet_identity (decentralized identity management and verifications), and pallet_serial_numbers (on-chain serial number generation and ownership tracking). These pallets handle complex business logic that would be prohibitively expensive to implement purely in Solidity, making them ideal candidates for precompile exposure.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →