Precompile Registry - LP-Aligned Trailing Address Scheme
Central registry of all Lux precompile addresses using trailing LP numbers
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 Name | Technical Name | Purpose |
|---|---|---|
| LX | (umbrella) | The whole on-chain trading system |
| LXPool | LP-9010 | v4 PoolManager-compatible AMM core |
| LXOracle | LP-9011 | Multi-source price aggregation |
| LXRouter | LP-9012 | Optimized swap routing |
| LXHooks | LP-9013 | Hook contract registry |
| LXFlash | LP-9014 | Flash loan facility |
| LXBook | LP-9020 | Permissionless orderbooks + matching + advanced orders |
| LXVault | LP-9030 | Balances, margin, collateral, liquidations |
| LXFeed | LP-9040 | Price feed aggregator |
Benefits
- Zero Ambiguity: LP number directly visible in address
- Easy Discovery: Looking at address immediately tells you the LP
- Multi-Chain Consistent: Same address on all EVM chains (C-Chain, Zoo, Hanzo, SPC)
- 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)
| Address | LP | Name | Description |
|---|---|---|---|
0x0000000000000000000000000000000000009010 | LP-9010 | LXPool | v4 PoolManager-compatible AMM core |
0x0000000000000000000000000000000000009011 | LP-9011 | LXOracle | Multi-source price aggregation |
0x0000000000000000000000000000000000009012 | LP-9012 | LXRouter | Optimized swap routing |
0x0000000000000000000000000000000000009013 | LP-9013 | LXHooks | Hook contract registry |
0x0000000000000000000000000000000000009014 | LP-9014 | LXFlash | Flash loan facility |
0x0000000000000000000000000000000000009020 | LP-9020 | LXBook | Permissionless orderbooks + matching + advanced orders |
0x0000000000000000000000000000000000009030 | LP-9030 | LXVault | Balances, margin, collateral, liquidations |
0x0000000000000000000000000000000000009040 | LP-9040 | LXFeed | Price feed aggregator |
Bridge Precompiles (LP-6xxx)
| Address | LP | Name | Description |
|---|---|---|---|
0x0000000000000000000000000000000000006010 | LP-6010 | Teleport | Cross-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:
- Maximum Simplicity: No formula to remember - LP number IS the address
- Human Readable:
0x...9010is obviously LP-9010 - Universal: Same address works on all EVM chains
- 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:
| Chain | Chain ID | LXPool Address |
|---|---|---|
| Lux Mainnet | 96369 | 0x...9010 |
| Lux Testnet | 96368 | 0x...9010 |
| Zoo Mainnet | 200200 | 0x...9010 |
| Zoo Testnet | 200201 | 0x...9010 |
| Hanzo Mainnet | 36963 | 0x...9010 |
| Hanzo Testnet | 36962 | 0x...9010 |
| SPC Mainnet | 36911 | 0x...9010 |
| LuxDev (Anvil) | 1337 | 0x...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)
));
}
Backwards Compatibility
The precompile registry is additive and does not modify existing precompile addresses or behavior. Existing precompiles continue to function at their assigned addresses.
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 Range | Purpose |
|---|---|
| 6000-6999 | Bridge precompiles |
| 9000-9099 | Core LXDEX (LXPool, LXOracle, LXRouter, LXHooks, LXFlash) |
| 9100-9199 | Reserved |
| 9200-9299 | Reserved |
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
Related LPs
- 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