Final NATS/per-bridge-MPC residue swept. All bridge → mpcd traffic now
flows through the canonical MPCClient HTTP wire protocol — same one as
~/work/lux/kms/pkg/mpc/client.go in Go.
────────────────────────────────────────────────────────────────────────
mpc-signer.ts (153 → 184 LOC; net simpler — one round-trip vs polling)
────────────────────────────────────────────────────────────────────────
Was: axios.get(/api/v1/wallets/{id}) + axios.post(/api/v1/transactions)
+ 30-iter 2s poll loop reading /api/v1/transactions/{id} for status
transitions. Static MPC_API_TOKEN bearer (no IAM-minted JWT).
Now: MPCClient.getWallet(walletId) → resolves ETH address (single GET)
MPCClient.sign({ walletId, keyType, message }) → single POST,
threshold round
completes inside
mpcd; returns
r/s/v atomically.
Env (brand-neutral): MPC_API_URL/TOKEN/WALLET_ID replaced with
BRIDGE_MPC_URL + BRIDGE_IAM_ISSUER + BRIDGE_IAM_CLIENT_ID +
BRIDGE_IAM_CLIENT_SECRET + BRIDGE_MPC_WALLET_ID. isMPCSigningEnabled()
short-circuits to false when any are missing; swaps.ts falls back to
LUX_SIGNER (legacy private key) cleanly in standalone mode.
Robustness: if mpcd returns the compact 65-byte signature in
result.signature (hex) instead of separate r/s/v, mpc-signer splits it
manually as a fallback. v < 27 is normalized to v + 27 for EIP-1559
ethers compatibility.
────────────────────────────────────────────────────────────────────────
mpc-wallet.ts (createMPCWalletForDeposit refactor)
────────────────────────────────────────────────────────────────────────
Was: raw fetch(`${MPC_API_URL}/keygen`) — POST with { wallet_id },
auth via no header (or relying on cluster ingress), parsed a
bridge-specific MPCKeygenResult shape.
Now: MPCClient.keygen({ vaultId, name, keyType, protocol }) then
MPCClient.getWallet(walletId) to resolve per-chain-family
addresses (eth/btc/sol/ton/dot/xrp). Protocol pinned per
chain family:
eth/btc/xrp → cggmp21 (secp256k1)
sol/ton/dot → frost (ed25519)
Env: drops MPC_API_URL / MPC_DASHBOARD_URL. Adds BRIDGE_MPC_VAULT_ID
(default 'bridge') for vault scoping.
The Utila-compatible return shape ({ name, addresses: [{ address }] })
is preserved so call-sites in domain/swaps.ts stay unchanged.
────────────────────────────────────────────────────────────────────────
MPCClient.getWallet (new method)
────────────────────────────────────────────────────────────────────────
GET /v1/wallets/{walletId}. Returns the full WalletInfo type
(id/walletId/vaultId/keyType/protocol/ethAddress/btcAddress/solAddress
/ecdsaPubKey/eddsaPubKey/status). Accepts both camelCase and snake_case
fields from the wire so mpcd flavors that emit either shape work.
────────────────────────────────────────────────────────────────────────
Net effect
────────────────────────────────────────────────────────────────────────
Bridge backend has zero per-bridge MPC HTTP client code remaining.
Every threshold sign + keygen call goes through src/clients/mpc.ts
which implements the canonical Lux MPC HTTP API (matches the Go
reference at ~/work/lux/kms/pkg/mpc/client.go). Brand-neutral env vars
(BRIDGE_*) throughout.
Tests: 58 SDK + 123 server = 181. Typecheck clean on both packages.
bridge/server
The Lux Bridge Server is an API server that facilitates communication with Multi-Party Computation (MPC) nodes and manages asset swaps.
Prerequisites
• Node.js: Version 20 or higher.
• pnpm: Version 9.10.0 or higher.
• Docker: Ensure Docker is installed and running.
• Kubernetes: Access to a Kubernetes cluster for deployment.
Installation
1. Clone the Repository:
git clone https://github.com/luxfi/bridge.git
2. Install Dependencies:
pnpm install (from root or any project subdir)
Development
-
go into server dir
cd server -
generate prisma artifacts
pnpx prisma generate -
set up prisma to use sqlite
in
prisma/schema.prisma
datasource db {
//provider = "postgresql"
provider = "sqlite"
url = env("POSTGRES_URL")
directUrl = env("POSTGRES_URL")
}
-
set env variable to point to sqlite
in
.envPOSTGRESQL_URL=file:./dev.sqlite -
create the local
sqliteinstancepnpx prisma db push -
Start the dev server
pnpm dev
This command uses nodemon to watch for file changes and restarts the server automatically.
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src/**/*
[nodemon] watching extensions: ts,js
[nodemon] starting `node -r tsconfig-paths/register -r ts-node/register ./src/server.ts`
>> Server is Running At: Port 5000
Building the Project
• Build the Project:
pnpm build
This command compiles TypeScript files, resolves module aliases, and generates the Prisma client.
Docker Operations
• Build Docker Image:
pnpm docker:build
This command builds the Docker image using Buildx for the linux/amd64 platform.
• Log in to GitHub Container Registry:
pnpm docker:login
Ensure that the environment variables GH_USER and GH_TOKEN are set with your GitHub username and personal access token, respectively.
• Push Docker Image:
pnpm docker:push
This command pushes the Docker image to the GitHub Container Registry.
Kubernetes Deployment
• Apply Kubernetes Configuration:
pnpm k8s:apply
This command applies the Kubernetes deployment and service configurations located in the k8s directory.
• Scale Deployment:
pnpm k8s:scale
Set the REPLICAS environment variable to the desired number of replicas before running this command.
• Create Kubernetes Secret:
pnpm k8s:create-secret
Ensure the POSTGRESQL_URL environment variable is set with your PostgreSQL connection string.
• Restart Deployment:
pnpm k8s:restart
• Check Deployment Status:
pnpm k8s:status
This command retrieves the status of deployments, services, and pods labeled app=bridge-server.
Linting and Formatting
• Lint Code:
pnpm lint
• Format Code:
pnpm format
Environment Variables
The server utilizes environment variables for configuration. Create a .env file in the server directory with the following variables:
POSTGRESQL_URL=your_postgres_connection_string GH_USER=your_github_username GH_TOKEN=your_github_token REPLICAS=number_of_replicas LUX_SIGNER=
Ensure that sensitive information is kept secure and not committed to version control.