LPsLux Proposals
Precompiles
LP-9015

Precompile Registry - LP-Aligned Trailing Address Scheme

Final

Central registry of all Lux precompile addresses using trailing LP numbers

Category
Core
Created
2025-12-21

Abstract

LP-9015 specifies the canonical precompile address scheme for the Lux ecosystem using a simple trailing LP number format: 0x0000000000000000000000000000000000LPNUM. This creates a direct 1:1 mapping between LP documentation numbers and precompile addresses.

Motivation

Direct LP Alignment

The trailing LP format is maximally simple:

  • LP-9010 (LXPool) → 0x0000000000000000000000000000000000009010
  • LP-9011 (LXOracle) → 0x0000000000000000000000000000000000009011
  • LP-6010 (Teleport) → 0x0000000000000000000000000000000000006010

No calculations needed. The LP number IS the address suffix.

LX Naming Convention

LX is the umbrella name for the Lux DEX stack (AMM + CLOB + vaults + feeds + routing). Individual precompiles use the LX prefix for developer-facing clarity:

Human NameTechnical NamePurpose
LX(umbrella)The whole on-chain trading system
LXPoolLP-9010v4 PoolManager-compatible AMM core
LXOracleLP-9011Multi-source price aggregation
LXRouterLP-9012Optimized swap routing
LXHooksLP-9013Hook contract registry
LXFlashLP-9014Flash loan facility
LXBookLP-9020Permissionless orderbooks + matching + advanced orders
LXVaultLP-9030Balances, margin, collateral, liquidations
LXFeedLP-9040Price feed aggregator

Benefits

  1. Zero Ambiguity: LP number directly visible in address
  2. Easy Discovery: Looking at address immediately tells you the LP
  3. Multi-Chain Consistent: Same address on all EVM chains (C-Chain, Zoo, Hanzo, SPC)
  4. Maximum Simplicity: No encoding scheme to learn or compute

Specification

Address Format

Address = 0x0000000000000000000000000000000000LPNUM

Where:
  LPNUM = The LP number (4 digits, hex-encoded)

Examples:
  LP-9010 → 0x0000000000000000000000000000000000009010
  LP-9011 → 0x0000000000000000000000000000000000009011
  LP-6010 → 0x0000000000000000000000000000000000006010

Canonical Address Registry

LX Precompiles (LP-9xxx - AMM + CLOB)

AddressLPNameDescription
0x0000000000000000000000000000000000009010LP-9010LXPoolv4 PoolManager-compatible AMM core
0x0000000000000000000000000000000000009011LP-9011LXOracleMulti-source price aggregation
0x0000000000000000000000000000000000009012LP-9012LXRouterOptimized swap routing
0x0000000000000000000000000000000000009013LP-9013LXHooksHook contract registry
0x0000000000000000000000000000000000009014LP-9014LXFlashFlash loan facility
0x0000000000000000000000000000000000009020LP-9020LXBookPermissionless orderbooks + matching + advanced orders
0x0000000000000000000000000000000000009030LP-9030LXVaultBalances, margin, collateral, liquidations
0x0000000000000000000000000000000000009040LP-9040LXFeedPrice feed aggregator

Bridge Precompiles (LP-6xxx)

AddressLPNameDescription
0x0000000000000000000000000000000000006010LP-6010TeleportCross-chain asset teleportation

Solidity Registry

// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

/// @title LX
/// @notice LP-aligned LX precompile address constants
/// @dev Address format: 0x0000000000000000000000000000000000LPNUM
library LX {
    // Core AMM (LP-9010 series - Uniswap v4 style)
    address internal constant LX_POOL   = 0x0000000000000000000000000000000000009010; // LP-9010 LXPool
    address internal constant LX_ORACLE = 0x0000000000000000000000000000000000009011; // LP-9011 LXOracle
    address internal constant LX_ROUTER = 0x0000000000000000000000000000000000009012; // LP-9012 LXRouter
    address internal constant LX_HOOKS  = 0x0000000000000000000000000000000000009013; // LP-9013 LXHooks
    address internal constant LX_FLASH  = 0x0000000000000000000000000000000000009014; // LP-9014 LXFlash

    // Trading & DeFi Extensions
    address internal constant LX_BOOK   = 0x0000000000000000000000000000000000009020; // LP-9020 LXBook
    address internal constant LX_VAULT  = 0x0000000000000000000000000000000000009030; // LP-9030 LXVault
    address internal constant LX_FEED   = 0x0000000000000000000000000000000000009040; // LP-9040 LXFeed

    // Bridge Precompiles (LP-6xxx)
    address internal constant TELEPORT  = 0x0000000000000000000000000000000000006010; // LP-6010

    /// @notice Generate precompile address from LP number
    function fromLP(uint16 lpNumber) internal pure returns (address) {
        return address(uint160(lpNumber));
    }

    /// @notice Extract LP number from precompile address
    function toLP(address precompile) internal pure returns (uint16) {
        return uint16(uint160(precompile));
    }

    /// @notice Check if address is an LX precompile (LP-9xxx)
    function isLXPrecompile(address addr) internal pure returns (bool) {
        uint16 lp = uint16(uint160(addr));
        return lp >= 9000 && lp < 10000;
    }

    /// @notice Check if address is a Bridge precompile (LP-6xxx)
    function isBridgePrecompile(address addr) internal pure returns (bool) {
        uint16 lp = uint16(uint160(addr));
        return lp >= 6000 && lp < 7000;
    }
}

Go Registry

package lxdex

import (
    "fmt"
    "github.com/luxfi/geth/common"
)

// LX Precompile addresses - trailing LP number format
// Address = 0x0000000000000000000000000000000000LPNUM
const (
    // Core AMM (LP-9010 series - Uniswap v4 style)
    LXPool   = "0x0000000000000000000000000000000000009010" // LP-9010 LXPool
    LXOracle = "0x0000000000000000000000000000000000009011" // LP-9011 LXOracle
    LXRouter = "0x0000000000000000000000000000000000009012" // LP-9012 LXRouter
    LXHooks  = "0x0000000000000000000000000000000000009013" // LP-9013 LXHooks
    LXFlash  = "0x0000000000000000000000000000000000009014" // LP-9014 LXFlash

    // Trading & DeFi Extensions
    LXBook  = "0x0000000000000000000000000000000000009020" // LP-9020 LXBook
    LXVault = "0x0000000000000000000000000000000000009030" // LP-9030 LXVault
    LXFeed  = "0x0000000000000000000000000000000000009040" // LP-9040 LXFeed

    // Bridge Precompiles (LP-6xxx)
    Teleport = "0x0000000000000000000000000000000000006010" // LP-6010
)

// PrecompileAddress generates address from LP number
// Example: PrecompileAddress(9010) → 0x0000...009010
func PrecompileAddress(lpNumber uint16) common.Address {
    addr := fmt.Sprintf("0x%040x", lpNumber)
    return common.HexToAddress(addr)
}

// ToLP extracts LP number from precompile address
func ToLP(addr common.Address) uint16 {
    bytes := addr.Bytes()
    return uint16(bytes[18])<<8 | uint16(bytes[19])
}

// IsLXPrecompile checks if address is in LP-9xxx range
func IsLXPrecompile(addr common.Address) bool {
    lp := ToLP(addr)
    return lp >= 9000 && lp < 10000
}

// IsBridgePrecompile checks if address is in LP-6xxx range
func IsBridgePrecompile(addr common.Address) bool {
    lp := ToLP(addr)
    return lp >= 6000 && lp < 7000
}

TypeScript Registry

import type { Address } from 'viem'

/**
 * LX Precompile addresses (LP-9xxx - Uniswap v4 style)
 * Address format: 0x0000000000000000000000000000000000LPNUM
 */
export const LX = {
  // Core AMM (LP-9010 series)
  LX_POOL:   '0x0000000000000000000000000000000000009010' as Address, // LP-9010 LXPool
  LX_ORACLE: '0x0000000000000000000000000000000000009011' as Address, // LP-9011 LXOracle
  LX_ROUTER: '0x0000000000000000000000000000000000009012' as Address, // LP-9012 LXRouter
  LX_HOOKS:  '0x0000000000000000000000000000000000009013' as Address, // LP-9013 LXHooks
  LX_FLASH:  '0x0000000000000000000000000000000000009014' as Address, // LP-9014 LXFlash

  // Trading & DeFi Extensions
  LX_BOOK:  '0x0000000000000000000000000000000000009020' as Address, // LP-9020 LXBook
  LX_VAULT: '0x0000000000000000000000000000000000009030' as Address, // LP-9030 LXVault
  LX_FEED:  '0x0000000000000000000000000000000000009040' as Address, // LP-9040 LXFeed

  // Bridges (LP-6xxx)
  TELEPORT: '0x0000000000000000000000000000000000006010' as Address, // LP-6010
} as const

/**
 * Generate precompile address from LP number
 */
export function fromLP(lpNumber: number): Address {
  return `0x${lpNumber.toString(16).padStart(40, '0')}` as Address
}

/**
 * Extract LP number from precompile address
 */
export function toLP(address: Address): number {
  return parseInt(address.slice(-4), 16)
}

/**
 * Check if address is an LX precompile (LP-9xxx)
 */
export function isLXPrecompile(address: Address): boolean {
  const lp = toLP(address)
  return lp >= 9000 && lp < 10000
}

Rationale

Why Trailing LP Numbers?

The trailing LP scheme was chosen for:

  1. Maximum Simplicity: No formula to remember - LP number IS the address
  2. Human Readable: 0x...9010 is obviously LP-9010
  3. Universal: Same address works on all EVM chains
  4. Debuggable: Easy to identify precompile calls in traces

Previous Schemes Deprecated

The old 0x0200...00XX scheme was deprecated because:

  • Wasted 38 zero bytes with no benefit
  • Required complex encoding/decoding
  • No relationship to LP documentation
  • Limited extensibility

The intermediate BASE + PCII scheme was also rejected:

  • Required knowing the formula
  • Different addresses per chain
  • Added unnecessary complexity

Multi-Chain Deployment

All precompiles use identical addresses across all Lux EVM chains:

ChainChain IDLXPool Address
Lux Mainnet963690x...9010
Lux Testnet963680x...9010
Zoo Mainnet2002000x...9010
Zoo Testnet2002010x...9010
Hanzo Mainnet369630x...9010
Hanzo Testnet369620x...9010
SPC Mainnet369110x...9010
LuxDev (Anvil)13370x...9010

Test Cases

function testAddressFromLP() public {
    assertEq(
        LXDEX.fromLP(9010),
        address(0x0000000000000000000000000000000000009010)
    );
    assertEq(
        LXDEX.fromLP(6010),
        address(0x0000000000000000000000000000000000006010)
    );
}

function testLPFromAddress() public {
    assertEq(
        LXDEX.toLP(address(0x0000000000000000000000000000000000009010)),
        9010
    );
}

function testIsLXDEXPrecompile() public {
    assertTrue(LXDEX.isLXDEXPrecompile(
        address(0x0000000000000000000000000000000000009010)
    ));
    assertFalse(LXDEX.isLXDEXPrecompile(
        address(0x0000000000000000000000000000000000006010)
    ));
}

Security Considerations

Address Validation

Applications should validate precompile addresses:

function validateLXDEXPrecompile(address addr) internal pure {
    require(
        LXDEX.isLXDEXPrecompile(addr),
        "Not an LXDEX precompile"
    );
}

Reserved Ranges

LP RangePurpose
6000-6999Bridge precompiles
9000-9099Core LXDEX (LXPool, LXOracle, LXRouter, LXHooks, LXFlash)
9100-9199Reserved
9200-9299Reserved

Implementation Status

All repositories have been updated to use the LP-aligned format with LXDEX naming:

  • ~/work/lux/precompile/registry/registry.go - Canonical Go registry
  • ~/work/lux/precompile/dex/module.go - LXDEX precompile implementation
  • ~/work/lux/dex/pkg/gateway/lux/provider.go - LXDEX gateway
  • ~/work/lux/exchange/packages/dex/src/precompile/addresses.ts - TypeScript registry
  • LP-0099: LP Numbering Scheme and Chain Organization
  • LP-9010: LXPool - v4 PoolManager-Compatible AMM Core
  • LP-9011: LXOracle - Multi-Source Price Aggregation
  • LP-6010: Teleport Bridge Precompile