Makes XRP withdrawal safe to enable (testnet on; mainnet staged-gated) by closing
the fund-loss + gate-bypass vectors a red/blue loop surfaced over three rounds.
DESTINATION TAG (else a tag-less payout to an exchange pool is lost):
- internal/xrpl: ValidateDestination (reject X-addresses + validate r-address);
parseAccount recover-wrapper (fixes a rippledata base58 panic-DoS reachable in
the signing goroutine); tag set on the tx BEFORE SigningHash so it is committed
into the SHA-512Half the MPC signs (unstrippable, proven).
- internal/txassembler: XRPSpec.DestinationTag *uint32 -> PaymentUnsigned.
- cmd/bridge: Swap.DestinationTag, createSwapReq accepts+range-checks it [0,2^32),
signOneXRP threads it + re-validates the destination (terminal-fail on bad addr).
AUTHORITATIVE WITHDRAWAL GATE (was cosmetic — read only by the SPA list):
- config.go: WithdrawalEnabled/DepositEnabled now enforced server-side. Case-
INSENSITIVE (network,asset) match + default-DENY for wired non-EVM families
(BTC/SOL/TON/XRP/DOT) so an asset-case variant ('xrp'), empty asset, or network-
case variant ('bitcoin_testnet') can't dodge a disabled row into a release pool
(gate key now aligns with the network-only, case-folded signer routing). EVM
stays default-on.
- Enforced at CREATE (swapsCreateNative 403), SIGN (signOne skip = kill-switch),
BROADCAST (broadcastOne holds already-signed in-flight swaps), and the operator
INJECT path (swapsInjectRawTxNative 403). signOne also gains a defer-recover
backstop so one swap's panic can't crash the daemon.
Tests: tag carried+committed+on-wire; X-addr/bad-addr/panic-input rejected; tag
range boundaries; gate variant-bypass closed; create/sign/broadcast/inject all
honor the gate; kill-switch holds then resumes. cmd/bridge + xrpl + txassembler
green, full module green, vet clean.
KNOWN FOLLOW-UPS (pre-existing, bridge-wide, NOT XRP-specific; tracked):
- /admin/swaps/:id/{reset,inject-raw-tx} have no auth middleware (bounded by
64-bit random swap IDs + the now-gated inject). Gate behind operator token/mTLS.
- GET /v1/bridge/swaps has no tenant scoping (IDOR). Both are mainnet-readiness
items; mainnet XRP withdrawal stays isWithdrawalEnabled:false until addressed +
a live testnet tag-carrying-payout proof.
Lux Bridge
Bridge monorepo for Lux Network — a decentralized cross-chain bridge using Multi-Party Computation (MPC) for secure asset transfers.
Embed the bridge SDK
To embed bridge.lux.network in another app, install @luxfi/bridge:
pnpm add @luxfi/bridge react react-dom
import { mountBridge } from '@luxfi/bridge'
mountBridge({
config: {
apiHost: 'https://api.bridge.lux.network',
env: 'mainnet',
brand: { name: 'Lux Bridge', primaryColor: '#0066ff' },
},
})
@luxfi/bridge is the only package consumers import. All @luxbridge/*
packages are internal workspace deps and are never published.
Package scopes
| Scope | Visibility | Role |
|---|---|---|
@luxfi/bridge |
public (npm) | Canonical SDK — embed bridge UI into a host app. |
@luxfi/core |
public (npm) | Shared types (Asset, Network, Contract, ...). |
@luxfi/threshold |
public (npm) | T-Chain MPC threshold-signature SDK. |
@luxfi/utila |
public (npm) | Utila protobuf client. |
@luxbridge/lux-tenant |
private (workspace) | Slim Vite SPA for bridge.lux.network — consumes @luxfi/bridge. |
@luxbridge/settings |
private (workspace) | Network + asset registry. |
@luxbridge/explorer |
private (workspace) | On-chain explorer UI. |
@luxbridge/server |
private (workspace) | Bridge API daemon. |
@luxbridge/ui-automation |
private (workspace) | Selenium UI test harness. |
One canonical SDK name. One mount function. One config shape.
Prerequisites
- Node.js v20+
- pnpm v9.15.0+
- Go 1.22+ (for MPC tools)
- Docker (for infrastructure services)
Quick Start
1. Install Dependencies
# Install pnpm if needed
npm install -g pnpm
# Install project dependencies
pnpm install
# Install MPC tools via Go
make install-mpc
2. Start Infrastructure
# Start infrastructure services (Lux ID, KMS, databases, etc.)
make up
This starts:
- Lux ID (Casdoor) - Port 8000 - Unified authentication
- KMS (Vault) - Port 8200 - Key management
- NATS - Port 4223 - Messaging
- Consul - Port 8501 - Service discovery
- PostgreSQL - Port 5433 - Bridge database
- Lux ID DB - Port 5434 - Auth database
3. Start MPC Network
# Start 3-node MPC network
make start-mpc-nodes
This runs MPC nodes on:
- Node 0: HTTP 6000, gRPC 9090
- Node 1: HTTP 6001, gRPC 9091
- Node 2: HTTP 6002, gRPC 9092
4. Start Application Services
In separate terminals:
# Terminal 1: Bridge API Server
cd app/server && pnpm dev
# Terminal 2: Bridge UI
cd app/bridge && pnpm dev
5. Access Services
- Bridge UI: http://localhost:3001
- Bridge API: http://localhost:5000
- Lux ID Admin: http://localhost:8000
- Consul UI: http://localhost:8501
Architecture
Tenant app (Lux, Hanzo, Zoo, …)
imports @luxfi/bridge + @<org>/brand
│
▼
@luxfi/bridge (pkg/bridge)
Bridge UI inlined under src/app/
Direct deps: @hanzo/gui, @luxfi/threshold, wagmi, viem
│
┌───────┴────────┐
▼ ▼
app/server @luxfi/threshold
Express+Prisma MPC SDK (also consumed by app/server)
│
▼
m-chain (public MPC, 2-of-3 threshold)
+ optional private cluster (treasury fees)
+ optional layered cosigners (Utila / Fireblocks)
See docs/LLM.md for the full topology, MPC protocol list
(cggmp21, frost, bls, doerner, pulsar, corona, magnetar),
layered-cosigner pattern, and explorer-migration plan.
Key Features
- MPC Security: 2-of-3 threshold signatures (also PQ-safe lattice variants)
- Layered cosigners (since SDK v1.0.3): optional Utila / Fireblocks cosign on top of native MPC for institutional flows
- Multi-Chain: Support for EVM and non-EVM chains
- Unified Auth: Lux ID (Casdoor) integration
- Key Management: Secure key storage in KMS
- Service Discovery: Consul for dynamic configuration
Development
# Run tests
pnpm test
# Check MPC status
lux-mpc-cli status --url http://localhost:6000
# View logs
tail -f logs/mpc-node-0.log
# Stop services
make stop-mpc-nodes # Stop MPC
make down # Stop infrastructure
Documentation
docs/LLM.md— canonical AI/onboarding doc: architecture, package layout, MPC topology, runtime config, publishing status, layered cosigners, explorer migration plan- Nextra docs site under
docs/—pnpm --filter @luxfi/bridge-docs buildbuilds the public site (Home / Architecture / Integrations / Operator Runbook / Deploy Guide / Lux ID). Sources live atdocs/content/docs/*.mdx, pages atdocs/pages/*.mdx. pkg/bridge/README.md— consumer-facing SDK README (mountBridge,BridgeConfig, all config blocks)
For the new bridge dev: issue #392 is the entry point — read order, repo map, open issues by priority.
Tips
Since "pnpm" is a finger twister, many people alias it to "pn". For example, with bash, put alias pn='pnpm' in .bashrc.