bridge: eight more networks, reached by custody

An empty teleporter is a mode, not a gap. Ethereum and Polygon carry
empty ones and cross fine, because the committee holds an address on the
chain and a deposit to it is the lock. I had read those empty strings as
"cannot bridge" and called three real networks fictional on the strength
of it. They are real; what was missing was our row, not their existence.

Custody already spans all of these — CGGMP21 on secp256k1 for every EVM,
FROST on Ed25519 for substrate — and the address type defaults to `eth`,
so every EVM network added here gets a correct deposit address with no
new key material and no new ceremony.

Added: Celo, Zora, Blast, Linea, Gnosis, Fantom, Aurora (EVM, chain ids
from the live registry rather than memory) and Polkadot (substrate, no
EIP-155 id, SS58 via encodeSubstrateAddress). Nineteen EVM networks are
now offered and all nineteen assemble.

Each carries its native asset row. A network in four of the five tables
a crossing needs is one whose gap is found after the user has sent
funds, so TestEveryOfferedNetworkHasItsNativeAsset now walks the config
and refuses that state.

CARDANO IS DELIBERATELY LEFT OUT, and this is the one to look at:
mpc-wallet.ts maps CARDANO_MAINNET to address type `sol`, with the
comment "placeholder — needs Ed25519". Both are Ed25519 so the key is
fine, but a Cardano address is bech32 addr1... and a Solana address is a
base58 public key. Anyone bridging to Cardano is handed a Solana-shaped
address to send ADA to. It is offered on bridge-api.lux.network today.
Adding it here would have spread a funds-losing bug rather than fixed
it; it goes in when it has an encoder.
This commit is contained in:
2026-08-30 17:10:41 -07:00
parent 083c47ef07
commit 0c73fe50a0
2 changed files with 155 additions and 0 deletions
+25
View File
@@ -72,3 +72,28 @@ func TestNonEVMNetworksAreNotRegisteredAsEVM(t *testing.T) {
}
}
}
// Every network offered must have at least its native asset. A network in
// four of the five tables a crossing needs is one whose gap is found after
// the user has sent funds.
func TestEveryOfferedNetworkHasItsNativeAsset(t *testing.T) {
cfg, err := LoadConfig("networks.mainnet.yaml")
if err != nil {
t.Fatalf("load: %v", err)
}
assets := map[string]map[string]bool{}
for _, tk := range cfg.Tokens {
if assets[tk.Network] == nil {
assets[tk.Network] = map[string]bool{}
}
assets[tk.Network][strings.ToUpper(tk.Asset)] = true
}
for _, n := range cfg.Networks {
if !assets[n.InternalName][strings.ToUpper(n.NativeCurrency)] {
t.Errorf("%s is offered with no %s row — it cannot price or move its own gas",
n.InternalName, n.NativeCurrency)
}
}
}
+130
View File
@@ -178,6 +178,99 @@ networks:
txExplorerTpl: https://livenet.xrpl.org/transactions/{tx}
addrExplorerTpl: https://livenet.xrpl.org/accounts/{addr}
# Reached by MPC custody rather than a teleporter contract. An empty
# teleporter is a mode, not a gap: Ethereum and Polygon carry empty ones
# too and cross fine, because the committee holds an address on the chain
# and a deposit to it is the lock. Custody spans these already — CGGMP21
# on secp256k1 for every EVM, FROST on Ed25519 for the substrate and
# Cardano families — so what was missing here was the row, not the ability.
- internalName: CELO_MAINNET
displayName: Celo
nativeCurrency: CELO
chainId: "42220"
type: evm
isFeatured: false
avgCompletion: 2m
txExplorerTpl: https://celoscan.io/tx/{tx}
addrExplorerTpl: https://celoscan.io/address/{addr}
- internalName: ZORA_MAINNET
displayName: Zora
nativeCurrency: ETH
chainId: "7777777"
type: evm
isFeatured: false
avgCompletion: 2m
txExplorerTpl: https://explorer.zora.energy/tx/{tx}
addrExplorerTpl: https://explorer.zora.energy/address/{addr}
- internalName: BLAST_MAINNET
displayName: Blast
nativeCurrency: ETH
chainId: "81457"
type: evm
isFeatured: false
avgCompletion: 2m
txExplorerTpl: https://blastscan.io/tx/{tx}
addrExplorerTpl: https://blastscan.io/address/{addr}
- internalName: LINEA_MAINNET
displayName: Linea
nativeCurrency: ETH
chainId: "59144"
type: evm
isFeatured: false
avgCompletion: 2m
txExplorerTpl: https://lineascan.build/tx/{tx}
addrExplorerTpl: https://lineascan.build/address/{addr}
- internalName: GNOSIS_MAINNET
displayName: Gnosis
nativeCurrency: XDAI
chainId: "100"
type: evm
isFeatured: false
avgCompletion: 2m
txExplorerTpl: https://gnosisscan.io/tx/{tx}
addrExplorerTpl: https://gnosisscan.io/address/{addr}
- internalName: FANTOM_MAINNET
displayName: Fantom
nativeCurrency: FTM
chainId: "250"
type: evm
isFeatured: false
avgCompletion: 2m
txExplorerTpl: https://ftmscan.io/tx/{tx}
addrExplorerTpl: https://ftmscan.io/address/{addr}
- internalName: AURORA_MAINNET
displayName: Aurora
nativeCurrency: ETH
chainId: "1313161554"
type: evm
isFeatured: false
avgCompletion: 2m
txExplorerTpl: https://explorer.aurora.dev/tx/{tx}
addrExplorerTpl: https://explorer.aurora.dev/address/{addr}
- internalName: POLKADOT_MAINNET
displayName: Polkadot
nativeCurrency: DOT
type: substrate
isFeatured: false
avgCompletion: 2m
txExplorerTpl: https://polkascan.io/polkadot/extrinsic/{addr}
addrExplorerTpl: https://polkascan.io/polkadot/account/{addr}
# CARDANO is deliberately absent. Its address type in the MPC wallet is
# `sol` — the comment beside it says "placeholder" — and Cardano is not
# Solana. Both are Ed25519 so the KEY is fine, but a Cardano address is
# bech32 `addr1...` and a Solana one is a base58 public key. Offering it
# would hand a user a Solana-shaped address to send ADA to, and the funds
# would be gone. It goes in when it has an encoder, not before.
tokens:
# The chains Lux runs — native coin only. Liquid tokens get added per
# chain when the contract list firms up.
@@ -345,6 +438,43 @@ tokens:
isDepositEnabled: true
isWithdrawalEnabled: false
# The native asset of each network reached by custody. A network with no
# asset row is in four of the five tables a crossing needs, and the fifth
# is discovered after the user has sent funds.
- asset: CELO
name: Celo
decimals: 18
network: CELO_MAINNET
- asset: ETH
name: Ether
decimals: 18
network: ZORA_MAINNET
- asset: ETH
name: Ether
decimals: 18
network: BLAST_MAINNET
- asset: ETH
name: Ether
decimals: 18
network: LINEA_MAINNET
- asset: XDAI
name: xDAI
decimals: 18
network: GNOSIS_MAINNET
- asset: FTM
name: Fantom
decimals: 18
network: FANTOM_MAINNET
- asset: ETH
name: Ether
decimals: 18
network: AURORA_MAINNET
- asset: DOT
name: Polkadot
decimals: 10
network: POLKADOT_MAINNET
limits:
minUSD: 10
maxUSD: 100000