# Asset Contract Address Format for Local Assets on 3DPass: Technical Specification

> Discover the asset contract address format for local assets on 3DPass. Learn how EVM addresses uniquely identify native assets using AssetIds and a specific prefix.

- Repository: [3Dpass/3dp](https://github.com/3dpass/3dp)
- Tags: technical-specification
- Published: 2026-02-23

---

**Local asset contracts on 3DPass utilize a deterministic 20-byte EVM address format comprising a 4-byte prefix (`0xFBFBFBFA`), 12 bytes of zero padding, and a 4-byte big-endian `AssetId` to uniquely identify native assets within the Ethereum Virtual Machine.**

The 3DPass blockchain facilitates seamless interoperability between its Substrate-based runtime and EVM-compatible clients through a specialized addressing scheme for local assets. Understanding the **asset contract address format for local assets on 3DPass** is critical for developers integrating ERC-20 compatible tokens, as it enables deterministic contract derivation from native `AssetId` values.

## Anatomy of the Local Asset Address Structure

Local assets on 3DPass follow a rigid 20-byte address schema that combines identification metadata with the native asset identifier:

```

0xFBFBFBFA0000000000000000xxxxxxxx

```

The format decomposes into three distinct segments:

- **Prefix (4 bytes)** – `0xFBFBFBFA` (the constant `LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX`) signals that the address belongs to the *local* ERC-20 asset precompile set rather than foreign assets or standard contracts.
- **Padding (12 bytes)** – Zero-filled bytes (`000000000000`) required to fill the standard EVM address space between the prefix and the asset identifier.
- **Asset ID (4 bytes)** – The asset's `AssetId` encoded as a **big-endian `u32`**, occupying the final four bytes of the address.

When an EVM call targets such an address, the runtime extracts the last 4 bytes as the asset identifier and routes the call to the `Erc20AssetsPrecompileSet` configured for local assets.

## Source Code Implementation

The conversion logic and prefix definitions reside in the 3DPass runtime, specifically within the precompiles and core runtime modules.

### Prefix Definition in [`precompiles.rs`](https://github.com/3dpass/3dp/blob/main/precompiles.rs)

In [`runtime/src/precompiles.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/precompiles.rs), the 4-byte prefix is declared as a constant byte array that marks addresses as local asset precompiles:

```rust
// Lines 64-70 in runtime/src/precompiles.rs
pub const LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8; 4] = &[251, 251, 251, 250];
// Hexadecimal representation: 0xFBFBFBFA

```

This prefix distinguishes local assets from foreign asset precompiles and standard EVM contracts within the 3DPass runtime.

### Address Conversion Logic in [`lib.rs`](https://github.com/3dpass/3dp/blob/main/lib.rs)

The `Runtime` structure in [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs) implements the `AccountIdAssetIdConversion` trait to handle bidirectional translation between Substrate `AssetId` values and EVM-compatible H160 addresses.

**Extracting Asset IDs** (`account_to_asset_id`, lines 100-115):

```rust
// Validates the prefix and extracts the u32 AssetId from the trailing bytes
fn account_to_asset_id(account: AccountId) -> Option<(Vec<u8>, AssetId)>

```

This function verifies that the first 4 bytes of the provided H160 address match `LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX`, then reads the final 4 bytes as the `AssetId`.

**Building Addresses** (`asset_id_to_account`, lines 119-126):

```rust
// Constructs the 20-byte address by concatenating:
// 1. The 4-byte prefix
// 2. 12 bytes of zero padding  
// 3. The 4-byte big-endian AssetId
fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId

```

## Practical Code Examples

### Generating a Contract Address from an Asset ID

To calculate the EVM contract address for local asset ID `42`:

```rust
use runtime::{asset_id_to_account, LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX};

let asset_id: u32 = 42;
let prefix = LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX; // &[251, 251, 251, 250]
let address = asset_id_to_account(prefix, asset_id);

// Result: 0xFBFBFBFA00000000000000002A
// (where 0x2A is 42 in big-endian hexadecimal)

```

### Parsing an Address to Extract the Asset ID

To validate an incoming address and retrieve the corresponding native asset identifier:

```rust
use runtime::account_to_asset_id;
use sp_core::H160;

let address: H160 = "0xFBFBFBFA00000000000000002A".parse().unwrap();

if let Some((prefix, asset_id)) = account_to_asset_id(address.into()) {
    // prefix == &[251, 251, 251, 250]
    // asset_id == 42u32
}

```

## EVM Routing and Precompile Execution

When the 3DPass EVM receives a transaction targeting an address starting with `0xFBFBFBFA`, the runtime:

1. Validates the 20-byte address length
2. Confirms the 4-byte prefix matches `LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX`
3. Extracts the trailing 4 bytes as a big-endian `u32` asset identifier
4. Routes the call to the `Erc20AssetsPrecompileSet` implementation for local assets

This deterministic routing allows standard Ethereum tooling such as MetaMask or Web3.js to interact with native 3DPass assets using seemingly standard ERC-20 contract addresses.

## Summary

- Local asset addresses are **20-byte EVM addresses** with the deterministic structure: `prefix (4) + padding (12) + asset_id (4)`.
- The **prefix `0xFBFBFBFA`** is defined as `LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX` in [`runtime/src/precompiles.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/precompiles.rs) (lines 64-70).
- **Bidirectional conversion** is handled by `account_to_asset_id` and `asset_id_to_account` in [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs) (lines 100-126).
- Asset identifiers are encoded as **big-endian u32** values in the final 4 bytes, supporting IDs from 0 to 4,294,967,295.
- The format enables seamless interaction from standard EVM clients while maintaining native runtime integration.

## Frequently Asked Questions

### What is the exact hex prefix for 3DPass local asset contracts?

The prefix is **`0xFBFBFBFA`**, defined in [`runtime/src/precompiles.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/precompiles.rs) as the byte array `&[251, 251, 251, 250]`. This constant occupies the first 4 bytes of every local asset contract address and tells the runtime to treat the target as a local ERC-20 precompile.

### How is the asset ID encoded within the address?

The asset ID is encoded as a **big-endian unsigned 32-bit integer (u32)** occupying the final 4 bytes of the 20-byte address. For example, asset ID `42` (`0x0000002A`) appears as `0000002A` in the trailing bytes, resulting in the full address `0xFBFBFBFA00000000000000002A`.

### Where is the address conversion logic implemented in the 3DPass codebase?

The conversion logic is implemented in [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs) within the `Runtime` type's implementation of `AccountIdAssetIdConversion`. Specifically, `account_to_asset_id` (lines 100-115) handles address parsing, while `asset_id_to_account` (lines 119-126) handles address construction. The prefix constant is defined separately in [`runtime/src/precompiles.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/precompiles.rs).

### Can I interact with local assets using standard Ethereum wallets?

Yes. Because local asset addresses are valid 20-byte EVM addresses (H160), wallets like MetaMask, Trust Wallet, or hardware wallets can send transactions to them. The 3DPass runtime automatically detects the `0xFBFBFBFA` prefix and routes the call to the appropriate native asset through the `Erc20AssetsPrecompileSet`, allowing standard ERC-20 functions like `transfer`, `balanceOf`, and `approve` to work transparently.