Files
zeekay f21c8303d0 bridge: Cardano gets a Cardano address
You were right that the crypto is already there. Cardano signs with the
same Ed25519 key Solana does, through FROST, which luxfi/threshold and
luxfi/mpc support natively. The key was never the problem.

The address was. Solana's address IS the public key, base58. Cardano's
is blake2b-224 of that key inside a typed, network-tagged bech32
envelope. NETWORK_ADDRESS_TYPE mapped CARDANO_MAINNET to 'sol' — the
comment beside it said "placeholder" — so the bridge handed out a
Solana-shaped string and told people to send ADA to it. That is offered
on bridge-api.lux.network today.

cardano-address.ts builds the CIP-19 enterprise address: payment
credential only, no staking part, which is the right shape for custody —
a base address would commit to a staking credential the committee does
not hold.

blake2b-224 is NOT blake2b-512 truncated. Blake2b takes its digest
length into the parameter block, so they differ from the first byte, and
Node's fixed-length blake2b512 cannot be used. There is a test asserting
exactly that, so anyone substituting a truncating implementation finds
out immediately rather than after the funds move.

Also asserted: the address is not the public key (the bug this
replaces), the network tag distinguishes mainnet from testnet, a key
that is not 32 bytes is refused rather than hashed into a plausible
address for a key that does not exist, and encode/decode agree.

The type union gained 'ada' rather than the map being widened to string,
so the next family added has to be handled in the switch instead of
falling through to 'eth' — which is how Cardano would have got an
Ethereum address if the default had caught it.

25 networks in the config now. Nineteen EVM, all assemblable; Bitcoin,
Solana, TON, XRP, Polkadot and Cardano correctly excluded from the EVM
assembler.

NOT VERIFIED against a live Cardano node — the encoder is
self-consistent and matches CIP-19 as written, but no address produced
here has been used on chain. Worth one testnet deposit before mainnet
funds move through it.
2026-08-30 17:10:41 -07:00

220 lines
8.5 KiB
JSON

{
"name": "@luxbridge/server",
"version": "1.0.0",
"private": true,
"description": "",
"main": "src/server.ts",
"_moduleAliases": {
"@": "dist"
},
"scripts": {
"dev": "nodemon",
"db": "node dist/db.js",
"rm": "node dist/delete.js",
"nodes": "node dist/nodes.js",
"tc": "tsc",
"typecheck": "tsc",
"test": "vitest run",
"clean": "rm -rf ./node_modules",
"prisma:gen": "pnpm exec prisma generate",
"build": "pnpm exec prisma generate && tsc && tsc-alias",
"start": "node dist/server.js",
"lint": "eslint src/**/*.ts",
"format": "eslint src/**/*.ts --fix",
"update-db": "kubectl exec -it $(kubectl get pod -l app=bridge-server -o jsonpath='{.items[0].metadata.name}') -- pnpm run db",
"colima:start": "colima start --arch aarch64,x86_64",
"docker:build": "cd ../.. && docker buildx build --load --platform linux/amd64 -t ghcr.io/luxfi/bridge-server:latest -f app/server/docker/Dockerfile .",
"docker:login": "docker login --username $GH_USER --password $GH_TOKEN ghcr.io",
"docker:push": "docker push ghcr.io/luxfi/bridge/server:latest",
"k8s:apply": "kubectl apply -f k8s/bridge-deployment.yaml && kubectl apply -f k8s/bridge-service.yaml",
"k8s:logs": "kubectl logs -l app=bridge-server -f",
"k8s:scale": "kubectl scale deployment bridge-server --replicas=$REPLICAS",
"k8s:create-secret": "kubectl create secret generic bridge-server-secret --from-literal=POSTGRESQL_URL=\"$POSTGRESQL_URL\" --dry-run=client -o yaml | kubectl apply -f -",
"k8s:restart": "kubectl rollout restart deployment bridge-server",
"k8s:status": "kubectl get deployments,service,pods -l app=bridge-server -o wide",
"k8s:stop": "kubectl delete deployment bridge-server || true && kubectl delete service bridge-service || true"
},
"prisma": {
"schema": "prisma/schema.prisma"
},
"keywords": [],
"author": "",
"license": "BSD-3-Clause",
"devDependencies": {
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"@types/jsonwebtoken": "^9.0.10",
"@types/morgan": "^1.9.10",
"@types/multicoin-address-validator": "^0.5.3",
"@types/node": "^25.9.1",
"@types/uuid": "^11.0.0",
"@typescript-eslint/eslint-plugin": "^8.59.4",
"@typescript-eslint/parser": "^8.59.4",
"nodemon": "^3.1.14",
"prettier": "^3.8.3",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.17",
"tsconfig-paths": "^4.2.0",
"typescript": "^6.0.3",
"vitest": "^4.1.7"
},
"dependencies": {
"@aws-sdk/client-kms": "^3.1053.0",
"@azure/identity": "^4.13.1",
"@azure/keyvault-keys": "^4.10.0",
"@google-cloud/kms": "^5.5.0",
"@luxfi/core": "workspace:*",
"@luxfi/utila": "workspace:^",
"@noble/ed25519": "^3.1.0",
"@noble/hashes": "^2.4.0",
"@prisma/client": "^6.19.3",
"@scure/base": "^2.4.0",
"@solana/addresses": "6.9.0",
"axios": "^1.16.1",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
"ethers": "^6.16.0",
"express": "^5.2.1",
"express-rate-limit": "^8.5.2",
"express-validator": "^7.3.2",
"fireblocks-sdk": "^5.39.0",
"helmet": "^8.2.0",
"jsonwebtoken": "^9.0.3",
"module-alias": "^2.3.4",
"morgan": "^1.10.1",
"multicoin-address-validator": "^0.5.26",
"prisma": "^6.19.3",
"uuid": "^14.0.0",
"web3": "^4.16.0",
"winston": "^3.19.0"
},
"pnpm": {
"overrides": {
"color-string@<1.5.5": ">=1.5.5",
"tar@<6.2.1": ">=6.2.1",
"axios@>=0.8.1 <0.28.0": ">=0.28.0",
"tough-cookie@<4.1.3": ">=4.1.3",
"ws@>=8.0.0 <8.17.1": ">=8.17.1",
"ws@>=7.0.0 <7.5.10": ">=7.5.10",
"ws@>=2.1.0 <5.2.4": ">=5.2.4",
"zod@<=3.22.2": ">=3.22.3",
"next@>=14.0.0 <14.2.21": ">=14.2.21",
"undici@>=6.0.0 <6.21.1": ">=6.21.1",
"undici@>=4.5.0 <5.28.5": ">=5.28.5",
"esbuild@<=0.24.2": ">=0.25.0",
"vite@>=5.0.0 <=5.4.11": ">=5.4.12",
"elliptic@<=6.6.0": ">=6.6.1",
"vite@>=5.0.0 <5.4.15": ">=5.4.15",
"@remix-run/express@>=2.11.1 <2.16.3": ">=2.16.3",
"estree-util-value-to-estree@<3.3.3": ">=3.3.3",
"vite@>=5.0.0 <5.4.18": ">=5.4.18",
"cookie@<0.7.0": ">=0.7.0",
"@babel/runtime@<7.26.10": ">=7.26.10",
"@babel/helpers@<7.26.10": ">=7.26.10",
"vite@>=5.0.0 <=5.4.18": ">=5.4.19",
"base-x@<=3.0.10": ">=3.0.11",
"base-x@=4.0.0": ">=4.0.1",
"vite@>=5.0.0 <5.4.17": ">=5.4.17",
"image-size@>=1.1.0 <1.2.1": ">=1.2.1",
"brace-expansion@>=1.0.0 <=1.1.11": ">=1.1.12",
"brace-expansion@>=2.0.0 <=2.0.1": ">=2.0.2",
"next@>=13.0 <14.2.30": ">=14.2.30",
"pbkdf2@>=3.0.10 <=3.1.2": ">=3.1.3",
"@eslint/plugin-kit@<0.3.4": ">=0.3.4",
"on-headers@<1.1.0": ">=1.1.0",
"next@>=0.9.9 <14.2.31": ">=14.2.31",
"vite@<=5.4.19": ">=5.4.20",
"next@>=0.9.9 <14.2.32": ">=14.2.32",
"@metamask/sdk-communication-layer@>=0.16.0 <=0.33.0": ">=0.33.1",
"@metamask/sdk@>=0.16.0 <=0.33.0": ">=0.33.1",
"next@>=0.9.9 <14.2.24": ">=14.2.24",
"vite@>=5.2.6 <=5.4.20": ">=5.4.21",
"validator@<13.15.20": ">=13.15.20",
"tar-fs@>=2.0.0 <2.1.4": ">=2.1.4",
"tar-fs@>=3.0.0 <3.1.1": ">=3.1.1",
"sha.js@<=2.4.11": ">=2.4.12",
"tmp@<=0.2.3": ">=0.2.4",
"form-data@>=4.0.0 <4.0.4": ">=4.0.4",
"form-data@<2.5.4": ">=2.5.4",
"tar-fs@>=3.0.0 <3.0.9": ">=3.0.9",
"tar-fs@>=2.0.0 <2.1.3": ">=2.1.3",
"tar-fs@>=3.0.0 <3.0.7": ">=3.0.7",
"tar-fs@>=2.0.0 <2.1.2": ">=2.1.2",
"elliptic@>=4.0.0 <=6.5.6": ">=6.5.7",
"elliptic@>=2.0.0 <=6.5.6": ">=6.5.7",
"elliptic@>=5.2.1 <=6.5.6": ">=6.5.7",
"min-document@<=2.19.0": ">=2.19.1",
"glob@>=10.2.0 <10.5.0": ">=10.5.0",
"valibot@>=0.31.0 <1.2.0": ">=1.2.0",
"node-forge@<1.3.2": ">=1.3.2",
"axios@<0.30.0": ">=0.30.0",
"axios@>=1.0.0 <1.8.2": ">=1.8.2",
"elliptic@<6.6.0": ">=6.6.0",
"elliptic@<6.5.6": ">=6.5.6",
"jws@<3.2.3": ">=3.2.3",
"next@>=13.3.0 <14.2.34": ">=14.2.34",
"@remix-run/server-runtime@<=2.17.2": ">=2.17.3",
"@remix-run/router@<=1.23.1": ">=1.23.2",
"@remix-run/react@<2.17.3": ">=2.17.3",
"react-router@>=6.0.0 <6.30.2": ">=6.30.2",
"@remix-run/node@<=2.17.1": ">=2.17.2",
"@remix-run/react@>=1.15.0 <=2.17.0": ">=2.17.1",
"next@>=13.3.1-canary.0 <14.2.35": ">=14.2.35",
"h3@<=1.15.4": ">=1.15.5",
"axios@>=1.0.0 <1.12.0": ">=1.12.0",
"@coinbase/wallet-sdk@>=4.0.0-beta.0 <4.3.0": ">=4.3.0",
"lodash-es@>=4.0.0 <=4.17.22": ">=4.17.23",
"lodash@>=4.0.0 <=4.17.22": ">=4.17.23",
"undici@<6.23.0": ">=6.23.0",
"vite@>=5.0.0 <5.4.16": ">=5.4.16",
"next@>=10.0.0 <15.5.10": ">=15.5.10",
"next@>=13.0.0 <15.0.8": ">=15.0.8",
"tar@<7.5.7": ">=7.5.7",
"diff@>=4.0.0 <4.0.4": ">=4.0.4",
"diff@>=5.0.0 <5.2.2": ">=5.2.2",
"validator@<13.15.22": ">=13.15.22",
"js-yaml@<3.14.2": ">=3.14.2",
"js-yaml@>=4.0.0 <4.1.1": ">=4.1.1",
"semver@>=2.0.0-alpha <5.7.2": ">=5.7.2",
"webpack@>=5.49.0 <=5.104.0": ">=5.104.1",
"webpack@>=5.49.0 <5.104.0": ">=5.104.0",
"mdast-util-to-hast@>=13.0.0 <13.2.1": ">=13.2.1",
"undici@>=6.0.0 <6.21.2": ">=6.21.2",
"undici@<5.29.0": ">=5.29.0",
"qs@>=6.7.0 <=6.14.1": ">=6.14.2",
"pbkdf2@>=1.0.0 <=3.1.2": ">=3.1.3",
"axios@<=0.30.2": ">=0.30.3",
"axios@>=1.0.0 <=1.13.4": ">=1.13.5",
"tar@<=7.5.2": ">=7.5.3",
"tar@<7.5.8": ">=7.5.8",
"bn.js@>=5.0.0 <5.2.3": ">=5.2.3",
"bn.js@<4.12.3": ">=4.12.3",
"minimatch@<3.1.3": ">=3.1.3",
"minimatch@>=5.0.0 <5.1.7": ">=5.1.7",
"minimatch@>=9.0.0 <9.0.6": ">=9.0.6",
"rollup@>=4.0.0 <4.59.0": ">=4.59.0",
"rollup@<2.80.0": ">=2.80.0",
"minimatch@>=5.0.0 <5.1.8": ">=5.1.8",
"minimatch@>=9.0.0 <9.0.7": ">=9.0.7",
"minimatch@<3.1.4": ">=3.1.4",
"serialize-javascript@<=7.0.2": ">=7.0.3",
"next@>=14.0.0 <14.2.25": ">=14.2.25",
"ajv@<6.14.0": ">=6.14.0",
"ajv@>=7.0.0-alpha.0 <8.18.0": ">=8.18.0",
"qs@<6.14.1": ">=6.14.1",
"svgo@>=3.0.0 <3.3.3": ">=3.3.3",
"svgo@>=2.1.0 <2.8.1": ">=2.8.1",
"tar@<=7.5.9": ">=7.5.10",
"tar@<=7.5.10": ">=7.5.11",
"flatted@<3.4.0": ">=3.4.0",
"undici@>=6.0.0 <6.24.0": ">=6.24.0",
"undici@<6.24.0": ">=6.24.0",
"tar@<=7.5.3": ">=7.5.4",
"next@>=9.5.0 <15.5.13": ">=15.5.13",
"next@>=10.0.0 <16.1.7": ">=16.1.7",
"h3@<1.15.6": ">=1.15.6",
"socket.io-parser@>=4.0.0 <4.2.6": ">=4.2.6"
}
}
}