mirror of
https://github.com/luxexchange/exchange.git
synced 2026-10-30 18:13:46 +00:00
343 lines
12 KiB
TypeScript
343 lines
12 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
||
import {
|
||
LUX_MAINNET_CONTRACTS,
|
||
LUX_TESTNET_CONTRACTS,
|
||
LUX_DEVNET_CONTRACTS,
|
||
LUX_DEV_CONTRACTS,
|
||
HANZO_MAINNET_CONTRACTS,
|
||
HANZO_TESTNET_CONTRACTS,
|
||
HANZO_DEVNET_CONTRACTS,
|
||
ZOO_MAINNET_CONTRACTS,
|
||
ZOO_TESTNET_CONTRACTS,
|
||
ZOO_DEVNET_CONTRACTS,
|
||
PARS_MAINNET_CONTRACTS,
|
||
PARS_TESTNET_CONTRACTS,
|
||
PARS_DEVNET_CONTRACTS,
|
||
SPC_MAINNET_CONTRACTS,
|
||
SPC_TESTNET_CONTRACTS,
|
||
SPC_DEVNET_CONTRACTS,
|
||
OSAGE_MAINNET_CONTRACTS,
|
||
OSAGE_TESTNET_CONTRACTS,
|
||
OSAGE_DEVNET_CONTRACTS,
|
||
DEX_PRECOMPILES,
|
||
PQ_CRYPTO_PRECOMPILES,
|
||
PENDING,
|
||
getContracts,
|
||
isContractDeployed,
|
||
} from '../src/contracts/addresses'
|
||
|
||
// ---- helpers ----
|
||
|
||
const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/
|
||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||
|
||
function allAddresses(obj: Record<string, string>): string[] {
|
||
return Object.values(obj)
|
||
}
|
||
|
||
function addressEntries(obj: Record<string, string>): [string, string][] {
|
||
return Object.entries(obj)
|
||
}
|
||
|
||
// Known EMPTY legacy addresses from DEPLOYMENTS.md -- these should NOT appear
|
||
// in the current production contract set.
|
||
const KNOWN_EMPTY_LEGACY = [
|
||
'0xd9a95609DbB228A13568Bd9f9A285105E7596970',
|
||
'0x1F6cbC7d3bc7D803ee76D80F0eEE25767431e674',
|
||
'0xb732BD88F25EdD9C3456638671fB37685D4B4e3f',
|
||
]
|
||
|
||
const ALL_CHAIN_SETS: [string, Record<string, string>][] = [
|
||
// Lux primary C-Chain
|
||
['LUX_MAINNET_CONTRACTS', LUX_MAINNET_CONTRACTS],
|
||
['LUX_TESTNET_CONTRACTS', LUX_TESTNET_CONTRACTS],
|
||
['LUX_DEVNET_CONTRACTS', LUX_DEVNET_CONTRACTS],
|
||
['LUX_DEV_CONTRACTS', LUX_DEV_CONTRACTS],
|
||
// Hanzo brand L1
|
||
['HANZO_MAINNET_CONTRACTS', HANZO_MAINNET_CONTRACTS],
|
||
['HANZO_TESTNET_CONTRACTS', HANZO_TESTNET_CONTRACTS],
|
||
['HANZO_DEVNET_CONTRACTS', HANZO_DEVNET_CONTRACTS],
|
||
// Zoo brand L1
|
||
['ZOO_MAINNET_CONTRACTS', ZOO_MAINNET_CONTRACTS],
|
||
['ZOO_TESTNET_CONTRACTS', ZOO_TESTNET_CONTRACTS],
|
||
['ZOO_DEVNET_CONTRACTS', ZOO_DEVNET_CONTRACTS],
|
||
// Pars brand L1
|
||
['PARS_MAINNET_CONTRACTS', PARS_MAINNET_CONTRACTS],
|
||
['PARS_TESTNET_CONTRACTS', PARS_TESTNET_CONTRACTS],
|
||
['PARS_DEVNET_CONTRACTS', PARS_DEVNET_CONTRACTS],
|
||
// SPC brand L1
|
||
['SPC_MAINNET_CONTRACTS', SPC_MAINNET_CONTRACTS],
|
||
['SPC_TESTNET_CONTRACTS', SPC_TESTNET_CONTRACTS],
|
||
['SPC_DEVNET_CONTRACTS', SPC_DEVNET_CONTRACTS],
|
||
// Osage brand L1
|
||
['OSAGE_MAINNET_CONTRACTS', OSAGE_MAINNET_CONTRACTS],
|
||
['OSAGE_TESTNET_CONTRACTS', OSAGE_TESTNET_CONTRACTS],
|
||
['OSAGE_DEVNET_CONTRACTS', OSAGE_DEVNET_CONTRACTS],
|
||
]
|
||
|
||
// ---- 1. Every chain contract set is a non-empty object ----
|
||
|
||
describe('contract set exports', () => {
|
||
it.each([
|
||
...ALL_CHAIN_SETS,
|
||
['DEX_PRECOMPILES', DEX_PRECOMPILES],
|
||
['PQ_CRYPTO_PRECOMPILES', PQ_CRYPTO_PRECOMPILES],
|
||
])('%s is a non-empty object', (_name, contracts) => {
|
||
expect(contracts).toBeDefined()
|
||
expect(typeof contracts).toBe('object')
|
||
expect(Object.keys(contracts).length).toBeGreaterThan(0)
|
||
})
|
||
})
|
||
|
||
// ---- 2. getContracts() returns correct set for every supported chain ID ----
|
||
|
||
describe('getContracts()', () => {
|
||
it.each([
|
||
// Lux primary C-Chain
|
||
[96369, LUX_MAINNET_CONTRACTS],
|
||
[96368, LUX_TESTNET_CONTRACTS],
|
||
[96370, LUX_DEVNET_CONTRACTS],
|
||
[1337, LUX_DEV_CONTRACTS],
|
||
// Hanzo brand L1
|
||
[36963, HANZO_MAINNET_CONTRACTS],
|
||
[36964, HANZO_TESTNET_CONTRACTS],
|
||
// Zoo brand L1
|
||
[200200, ZOO_MAINNET_CONTRACTS],
|
||
[200201, ZOO_TESTNET_CONTRACTS],
|
||
[200202, ZOO_DEVNET_CONTRACTS],
|
||
// Pars brand L1 (post-2026-06-05 reset mainnet uses 7070)
|
||
[7070, PARS_MAINNET_CONTRACTS],
|
||
[494950, PARS_TESTNET_CONTRACTS],
|
||
[494951, PARS_DEVNET_CONTRACTS],
|
||
// SPC brand L1
|
||
[36911, SPC_MAINNET_CONTRACTS],
|
||
[36910, SPC_TESTNET_CONTRACTS],
|
||
[36912, SPC_DEVNET_CONTRACTS],
|
||
// Osage brand L1
|
||
[1872, OSAGE_MAINNET_CONTRACTS],
|
||
[1871, OSAGE_TESTNET_CONTRACTS],
|
||
[1873, OSAGE_DEVNET_CONTRACTS],
|
||
])('chain %i returns the correct contract set', (chainId, expected) => {
|
||
expect(getContracts(chainId)).toBe(expected)
|
||
})
|
||
|
||
// ---- 3. Unknown chain IDs fall back to mainnet (not undefined) ----
|
||
|
||
it.each([999, 0, -1, 12345, 1])('unknown chain %i returns LUX_MAINNET_CONTRACTS', (chainId) => {
|
||
const result = getContracts(chainId)
|
||
expect(result).toBe(LUX_MAINNET_CONTRACTS)
|
||
expect(result).toBeDefined()
|
||
})
|
||
})
|
||
|
||
// ---- 4. All addresses are valid hex (0x + 40 hex chars) ----
|
||
|
||
describe('address format validation', () => {
|
||
it.each([
|
||
...ALL_CHAIN_SETS,
|
||
['DEX_PRECOMPILES', DEX_PRECOMPILES],
|
||
['PQ_CRYPTO_PRECOMPILES', PQ_CRYPTO_PRECOMPILES],
|
||
])('%s has valid hex addresses (0x + 40 hex chars)', (_name, contracts) => {
|
||
for (const [key, addr] of addressEntries(contracts)) {
|
||
expect(addr, `${_name}.${key} = "${addr}"`).toMatch(ADDRESS_RE)
|
||
}
|
||
})
|
||
})
|
||
|
||
// ---- 5. No duplicate addresses within a single chain (excluding PENDING sentinels) ----
|
||
|
||
describe('no duplicate addresses within a chain', () => {
|
||
it.each([
|
||
...ALL_CHAIN_SETS,
|
||
['DEX_PRECOMPILES', DEX_PRECOMPILES],
|
||
])('%s has no duplicate non-PENDING addresses', (_name, contracts) => {
|
||
// PENDING (zero address) is a valid sentinel; multiple PENDING entries are
|
||
// expected on chains where contracts haven't been deployed yet.
|
||
const addrs = allAddresses(contracts)
|
||
.map((a) => a.toLowerCase())
|
||
.filter((a) => a !== ZERO_ADDRESS)
|
||
const unique = new Set(addrs)
|
||
const dupes = addrs.filter((a, i) => addrs.indexOf(a) !== i)
|
||
expect(dupes, `${_name} has duplicates: ${dupes.join(', ')}`).toHaveLength(0)
|
||
expect(unique.size).toBe(addrs.length)
|
||
})
|
||
})
|
||
|
||
// ---- 6. Mainnet addresses don't match known EMPTY legacy addresses ----
|
||
|
||
describe('mainnet addresses are not known-empty legacy', () => {
|
||
const legacyLower = KNOWN_EMPTY_LEGACY.map((a) => a.toLowerCase())
|
||
|
||
it('LUX_MAINNET_CONTRACTS contains no legacy EMPTY addresses', () => {
|
||
for (const [key, addr] of addressEntries(LUX_MAINNET_CONTRACTS)) {
|
||
expect(
|
||
legacyLower.includes(addr.toLowerCase()),
|
||
`LUX_MAINNET_CONTRACTS.${key} matches known-empty legacy address ${addr}`,
|
||
).toBe(false)
|
||
}
|
||
})
|
||
})
|
||
|
||
// ---- 7. DEX_PRECOMPILES addresses match canonical 0x04xx block ----
|
||
|
||
describe('DEX_PRECOMPILES canonical 0x04xx addresses', () => {
|
||
const EXPECTED_SUFFIXES: [string, string][] = [
|
||
['POOL_MANAGER', '0400'],
|
||
['SWAP_ROUTER', '0401'],
|
||
['HOOKS_REGISTRY', '0402'],
|
||
['FLASH_LOAN', '0403'],
|
||
['LENDING_POOL', '0410'],
|
||
['INTEREST_RATE', '0411'],
|
||
['LIQUIDATOR', '0412'],
|
||
['PERP_ENGINE', '0420'],
|
||
['FUNDING_RATE', '0421'],
|
||
['INSURANCE_FUND', '0422'],
|
||
['LIQUID_VAULT', '0430'],
|
||
['LIQUID_FX', '0431'],
|
||
['LIQUID_TOKEN', '0432'],
|
||
['YIELD_ROUTER', '0433'],
|
||
['TELEPORT_BRIDGE', '0440'],
|
||
['OMNICHAIN_ROUTER', '0441'],
|
||
]
|
||
|
||
it.each(EXPECTED_SUFFIXES)(
|
||
'DEX_PRECOMPILES.%s ends with 0x%s',
|
||
(name, suffix) => {
|
||
const addr = (DEX_PRECOMPILES as Record<string, string>)[name]
|
||
expect(addr).toBeDefined()
|
||
expect(addr.toLowerCase()).toBe(
|
||
`0x${'0'.repeat(40 - suffix.length)}${suffix}`,
|
||
)
|
||
},
|
||
)
|
||
|
||
it('all DEX precompile addresses have leading zeros (low address space)', () => {
|
||
for (const [key, addr] of addressEntries(DEX_PRECOMPILES)) {
|
||
const body = addr.slice(2, 32)
|
||
expect(body, `DEX_PRECOMPILES.${key} should have leading zeros`).toMatch(/^0+$/)
|
||
}
|
||
})
|
||
})
|
||
|
||
// ---- 7b. PQ_CRYPTO_PRECOMPILES match LP-4200 unified PQCrypto block ----
|
||
|
||
describe('PQ_CRYPTO_PRECOMPILES LP-4200 unified block', () => {
|
||
const EXPECTED: [string, string][] = [
|
||
['ML_KEM', '012201'],
|
||
['ML_DSA', '012202'],
|
||
['SLH_DSA', '012203'],
|
||
['PULSAR', '012204'],
|
||
['P3Q', '012205'],
|
||
['CORONA', '012206'],
|
||
['MAGNETAR', '012207'],
|
||
['HQC', '012208'],
|
||
]
|
||
|
||
it.each(EXPECTED)('PQ_CRYPTO_PRECOMPILES.%s = 0x..%s', (name, suffix) => {
|
||
const addr = (PQ_CRYPTO_PRECOMPILES as Record<string, string>)[name]
|
||
expect(addr).toBeDefined()
|
||
expect(addr.toLowerCase()).toBe(
|
||
`0x${'0'.repeat(40 - suffix.length)}${suffix}`,
|
||
)
|
||
})
|
||
|
||
it('PQ precompiles are non-empty, well-formed hex', () => {
|
||
for (const [key, addr] of addressEntries(PQ_CRYPTO_PRECOMPILES)) {
|
||
expect(addr, `PQ_CRYPTO_PRECOMPILES.${key} = "${addr}"`).toMatch(ADDRESS_RE)
|
||
}
|
||
})
|
||
})
|
||
|
||
// ---- 8. Chains with live AMM deployments have non-zero V2_FACTORY/V2_ROUTER ----
|
||
|
||
describe('chains with live AMM deployments', () => {
|
||
// Only chains where V2_FACTORY+V2_ROUTER are actually live. Post-reset brand
|
||
// chains are pending redeploy and use PENDING sentinels.
|
||
const SETS_WITH_LIVE_AMM: [string, Record<string, string>][] = [
|
||
['LUX_MAINNET_CONTRACTS', LUX_MAINNET_CONTRACTS],
|
||
['LUX_TESTNET_CONTRACTS', LUX_TESTNET_CONTRACTS],
|
||
['LUX_DEV_CONTRACTS', LUX_DEV_CONTRACTS],
|
||
['ZOO_MAINNET_CONTRACTS', ZOO_MAINNET_CONTRACTS],
|
||
]
|
||
|
||
it.each(SETS_WITH_LIVE_AMM)('%s V2_FACTORY is not the zero address', (_name, contracts) => {
|
||
expect(contracts.V2_FACTORY).toBeDefined()
|
||
expect(contracts.V2_FACTORY!.toLowerCase()).not.toBe(ZERO_ADDRESS)
|
||
})
|
||
|
||
it.each(SETS_WITH_LIVE_AMM)('%s V2_ROUTER is not the zero address', (_name, contracts) => {
|
||
expect(contracts.V2_ROUTER).toBeDefined()
|
||
expect(contracts.V2_ROUTER!.toLowerCase()).not.toBe(ZERO_ADDRESS)
|
||
})
|
||
})
|
||
|
||
// ---- 9. WLUX differs across networks where deployed ----
|
||
|
||
describe('WLUX differs between networks (where deployed)', () => {
|
||
it('mainnet WLUX is different from testnet WLUX', () => {
|
||
expect(LUX_MAINNET_CONTRACTS.WLUX.toLowerCase()).not.toBe(
|
||
LUX_TESTNET_CONTRACTS.WLUX.toLowerCase(),
|
||
)
|
||
})
|
||
|
||
it('mainnet WLUX is different from dev WLUX', () => {
|
||
expect(LUX_MAINNET_CONTRACTS.WLUX.toLowerCase()).not.toBe(
|
||
LUX_DEV_CONTRACTS.WLUX.toLowerCase(),
|
||
)
|
||
})
|
||
|
||
it('testnet WLUX is different from dev WLUX', () => {
|
||
expect(LUX_TESTNET_CONTRACTS.WLUX.toLowerCase()).not.toBe(
|
||
LUX_DEV_CONTRACTS.WLUX.toLowerCase(),
|
||
)
|
||
})
|
||
})
|
||
|
||
// ---- 10. PENDING sentinel + isContractDeployed predicate ----
|
||
|
||
describe('PENDING sentinel + isContractDeployed predicate', () => {
|
||
it('PENDING is the zero address', () => {
|
||
expect(PENDING).toBe(ZERO_ADDRESS)
|
||
})
|
||
|
||
it('isContractDeployed returns true for a live contract on Lux mainnet', () => {
|
||
expect(isContractDeployed(96369, 'WLUX')).toBe(true)
|
||
expect(isContractDeployed(96369, 'V2_ROUTER')).toBe(true)
|
||
})
|
||
|
||
it('isContractDeployed returns false for PENDING contracts', () => {
|
||
// Hanzo mainnet (36963) is post-reset; V2_ROUTER pending.
|
||
expect(isContractDeployed(36963, 'V2_ROUTER')).toBe(false)
|
||
expect(isContractDeployed(36963, 'WLUX')).toBe(false)
|
||
})
|
||
|
||
it('Hanzo mainnet MULTICALL is always live (canonical address)', () => {
|
||
expect(isContractDeployed(36963, 'MULTICALL')).toBe(true)
|
||
})
|
||
})
|
||
|
||
// ---- 11. Inventory coverage — every brand L1 × env is exported ----
|
||
|
||
describe('inventory coverage — 18 brand-L1 endpoints', () => {
|
||
it('exports 6 chain-contract sets per env (lux + 5 brands)', () => {
|
||
// Lux + Hanzo + Zoo + Pars + SPC + Osage = 6 per env
|
||
expect(getContracts(96369)).toBeDefined() // lux mainnet
|
||
expect(getContracts(36963)).toBeDefined() // hanzo mainnet
|
||
expect(getContracts(200200)).toBeDefined() // zoo mainnet
|
||
expect(getContracts(7070)).toBeDefined() // pars mainnet
|
||
expect(getContracts(36911)).toBeDefined() // spc mainnet
|
||
expect(getContracts(1872)).toBeDefined() // osage mainnet
|
||
expect(getContracts(96368)).toBeDefined() // lux testnet
|
||
expect(getContracts(36964)).toBeDefined() // hanzo testnet
|
||
expect(getContracts(200201)).toBeDefined() // zoo testnet
|
||
expect(getContracts(494950)).toBeDefined() // pars testnet
|
||
expect(getContracts(36910)).toBeDefined() // spc testnet
|
||
expect(getContracts(1871)).toBeDefined() // osage testnet
|
||
expect(getContracts(96370)).toBeDefined() // lux devnet
|
||
expect(getContracts(200202)).toBeDefined() // zoo devnet
|
||
expect(getContracts(494951)).toBeDefined() // pars devnet
|
||
expect(getContracts(36912)).toBeDefined() // spc devnet
|
||
expect(getContracts(1873)).toBeDefined() // osage devnet
|
||
})
|
||
})
|