mirror of
https://github.com/luxfi/bridge.git
synced 2026-09-24 00:26:46 +00:00
'no stubs all real killer no filler' — every TODO in cosigners.ts replaced
with a real, network-touching adapter. Cloud HSM layer is now production-
grade across all four providers; f-chain attests via the Lux FHE daemon.
Dependencies added to app/server/package.json:
@aws-sdk/client-kms AWS SDK v3, IAM role / IRSA workload identity
@azure/keyvault-keys CryptographyClient with sign('ES256K'|'PS256', …)
@azure/identity DefaultAzureCredential (MSI / WI / Azure CLI)
(no client lib for Vault — direct HTTP via fetch + X-Vault-Token)
(no client lib for f-chain — direct HTTP to /v1/fhe/encrypt)
────────────────────────────────────────────────────────────────────────
AWS KMS — real
────────────────────────────────────────────────────────────────────────
- KMSClient({ region }) — region from identityHint or parsed from key ARN
- SignCommand(KeyId, Message: digest, MessageType: DIGEST, SigningAlgorithm)
- AWS_ALGORITHM_MAP: secp256k1_ecdsa_sha256 → ECDSA_SHA_256,
rsa_pss_sha256 → RSASSA_PSS_SHA_256
- ed25519 NOT in map → algorithm_mismatch rejected before any RPC
- mapAwsError covers AWS exception names + HTTP status:
AccessDeniedException / 403 → permission_denied
NotFoundException / 404 → key_not_found
KMSInvalidStateException / Disabled → key_disabled
InvalidKeyUsageException → algorithm_mismatch
ThrottlingException / 429 → rate_limited
DependencyTimeout / 5xx → provider_unavailable
other → network_error
────────────────────────────────────────────────────────────────────────
Azure Key Vault — real
────────────────────────────────────────────────────────────────────────
- CryptographyClient(keyRef, DefaultAzureCredential())
- AZURE_ALGORITHM_MAP: secp256k1_ecdsa_sha256 → 'ES256K',
rsa_pss_sha256 → 'PS256'
- Returns key version from response.keyID (audit trail per CosignerStep row)
- mapAzureError covers Azure code + statusCode:
Forbidden / AuthenticationFailed / 403 → permission_denied
KeyNotFound / 404 → key_not_found
KeyDisabled → key_disabled
UnsupportedKeyOperation → algorithm_mismatch
TooManyRequests / 429 → rate_limited
ServiceUnavailable / 5xx → provider_unavailable
────────────────────────────────────────────────────────────────────────
Vault Transit — real
────────────────────────────────────────────────────────────────────────
- POST {VAULT_ADDR}/v1/{mount}/sign/{name} with X-Vault-Token
- Auto-splits keyRef on '/keys/' so tenants pin a non-default mount
- Body shape per algorithm:
secp256k1_ecdsa_sha256: hash_algorithm=sha2-256, prehashed=true,
marshaling_algorithm=asn1 (DER, parity with AWS/GCP)
rsa_pss_sha256: hash_algorithm=sha2-256, signature_algorithm=pss
ed25519: no prehash (Vault rejects prehashed ed25519)
- Parses 'vault:v{N}:<base64>' response shape — extracts both signature
bytes and key_version (returned as externalId='v3' etc.)
- mapVaultError maps status + body substrings:
401/403 / 'permission denied' → permission_denied
404 / 'no such key' → key_not_found
'key version disabled' → key_disabled
'unsupported' / 'invalid input' → algorithm_mismatch
429 / 'rate limit' → rate_limited
5xx / 'unavailable' / 'sealed' → provider_unavailable
────────────────────────────────────────────────────────────────────────
f-chain (Lux FHE attestation) — real
────────────────────────────────────────────────────────────────────────
- POST {publicUrl}/v1/fhe/encrypt with { plaintext_hex, scheme? }
- Endpoint contract from luxfi/fhe::cmd/fhed/main.go (the FHE daemon
already running in the Lux ecosystem; no new server to deploy)
- 30s timeout (FCHAIN_COSIGNER_TIMEOUT_MS env override) with AbortController
- Stores the FHE ciphertext as CosignerStep.signature (0x-prefixed hex)
— the cosign property: only f-chain (with its FHE key shares) could
produce that ciphertext for that txHash; downstream verifier obtains
f-chain's public key via /v1/fhe/publickey and checks equivalence
- 401/403 → rejected (policy denial)
- 5xx → failed (retryable infra)
- network/abort → failed
────────────────────────────────────────────────────────────────────────
Other touches
────────────────────────────────────────────────────────────────────────
- fetchCosignerSecret narrows kind 'fireblocks' explicitly so the union
with cloud_hsm + fchain typechecks
- cosigners-gcp-kms.test.ts: removes the four 'not yet implemented'
marker assertions (those now live as positive assertions in the new
cosigners-aws-azure-vault-fchain.test.ts)
Test counts:
SDK pkg/bridge: 58/58 unchanged
Server app/server: 77 → 95 (+18)
16 wire-shape validator
10 Fireblocks
7 persistence + dispatch-for-swap
13 Utila
13 GCP KMS + cloudHsmDigest + algorithm allow-list
18 NEW: 6 AWS + 3 Azure + 3 Vault Transit + 5 f-chain + 1 ed25519 reject
Typecheck: clean on both packages
No STUBs remain. Every adapter is a real network call with a real error
mapping. Workload-identity-only by design (no SA-JSON-key fallback).
220 lines
8.4 KiB
JSON
220 lines
8.4 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": "ISC",
|
|
"devDependencies": {
|
|
"@types/cors": "^2.8.17",
|
|
"@types/express": "^4.17.21",
|
|
"@types/jsonwebtoken": "^9.0.7",
|
|
"@types/morgan": "^1.9.9",
|
|
"@types/multicoin-address-validator": "^0.5.3",
|
|
"@types/node": "^20.17.1",
|
|
"@types/uuid": "^10.0.0",
|
|
"@typescript-eslint/eslint-plugin": "^8.2.0",
|
|
"@typescript-eslint/parser": "^8.2.0",
|
|
"nodemon": "^3.1.4",
|
|
"prettier": "^3.3.3",
|
|
"ts-node": "^10.9.2",
|
|
"tsc-alias": "^1.8.10",
|
|
"tsconfig-paths": "^4.2.0",
|
|
"typescript": "^5.5.4",
|
|
"vitest": "^2.1.0"
|
|
},
|
|
"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": "^3.0.0",
|
|
"@noble/ed25519": "^2.3.0",
|
|
"@prisma/client": "^6.3.1",
|
|
"@solana/addresses": "2.0.0",
|
|
"axios": "^1.7.4",
|
|
"consul": "^2.0.1",
|
|
"cors": "^2.8.5",
|
|
"dotenv": "^16.4.5",
|
|
"ethers": "^6.13.4",
|
|
"express": "^4.21.1",
|
|
"express-rate-limit": "^8.3.1",
|
|
"express-validator": "^7.2.0",
|
|
"fireblocks-sdk": "^5.39.0",
|
|
"helmet": "^8.0.0",
|
|
"jsonwebtoken": "^9.0.2",
|
|
"module-alias": "^2.2.3",
|
|
"morgan": "^1.10.0",
|
|
"multicoin-address-validator": "^0.5.22",
|
|
"nats": "^2.29.3",
|
|
"prisma": "^6.3.1",
|
|
"uuid": "^9.0.0",
|
|
"web3": "^4.16.0",
|
|
"winston": "^3.17.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"
|
|
}
|
|
}
|
|
}
|