Skip to content

Commit e5aca96

Browse files
CardealCardeal
authored andcommitted
fix: audit corrections — clean build + VPS deployment artifacts
Audit fixes (multisig system): - hsm-signer.ts: remove dead DER key code in LocalSigner.sign(), replace dynamic import('tweetnacl') with static import nacl, remove unused GetPublicKeyCommand import from AWS KMS - vault-executor.ts: fix critical bug — sendAndConfirmTransaction with empty signers array would fail at runtime. Now uses sendRawTransaction + confirmTransaction for pre-signed txs. Also sets recentBlockhash and feePayer before signing. - redis-store.ts: remove unused CircuitState import Build fixes (pre-existing errors): - index.ts: add missing PublicKey import from @solana/web3.js - index.ts: fix TS7030/TS2322 in Express routes — replace 'return res.status().json()' with 'res..json(); return;' pattern for Promise<void> handlers (6 routes fixed) - usdt-fee-collector.ts: fix TS2555 — subscribeToEvents does not exist on ContractPromise.query. Use api.query.system.events subscription instead. - Add src/contracts/tax_manager.json (copy from build output) - Add tweetnacl as runtime dependency VPS deployment artifacts: - scripts/setup-vps-bridge.sh: bootstrap Docker+Redis+Vault - scripts/init-vault-transit.sh: init Vault, create ed25519 key, scoped token with bridge-signer policy - scripts/lusdt-bridge.service: systemd unit for bridge-service - bridge-service/env-vps.example: production .env template - Docs/VPS_DEPLOYMENT_BRIDGE.md: step-by-step runbook Tests: 72 passing | Build: 0 errors
1 parent bce9a19 commit e5aca96

13 files changed

Lines changed: 2346 additions & 82 deletions

Docs/VPS_DEPLOYMENT_BRIDGE.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# VPS Deployment Runbook (Bridge + Vault + Redis)
2+
3+
## 1) Bootstrap VPS
4+
5+
```bash
6+
sudo bash scripts/setup-vps-bridge.sh
7+
```
8+
9+
Isso instala Docker/Compose e sobe `redis` + `vault` localmente.
10+
11+
## 2) Inicializar Vault Transit
12+
13+
```bash
14+
sudo bash scripts/init-vault-transit.sh
15+
```
16+
17+
Gera token restrito para assinatura e salva em `/opt/lusdt/secrets/bridge-vault.env`.
18+
19+
## 3) Publicar código na VPS
20+
21+
```bash
22+
mkdir -p /opt/lusdt/bridge-service
23+
# copie o repositório para /opt/lusdt/bridge-service
24+
```
25+
26+
## 4) Configurar .env de produção
27+
28+
Use como base:
29+
30+
- `bridge-service/env-vps.example`
31+
- `/opt/lusdt/secrets/bridge-vault.env`
32+
33+
Arquivo final em:
34+
35+
```bash
36+
/opt/lusdt/bridge-service/.env
37+
```
38+
39+
## 5) Build do bridge-service
40+
41+
```bash
42+
cd /opt/lusdt/bridge-service/bridge-service
43+
pnpm install --frozen-lockfile
44+
pnpm build
45+
```
46+
47+
## 6) Instalar systemd service
48+
49+
```bash
50+
sudo cp /opt/lusdt/bridge-service/scripts/lusdt-bridge.service /etc/systemd/system/lusdt-bridge.service
51+
sudo systemctl daemon-reload
52+
sudo systemctl enable lusdt-bridge
53+
sudo systemctl start lusdt-bridge
54+
sudo systemctl status lusdt-bridge
55+
```
56+
57+
## 7) Verificações
58+
59+
```bash
60+
curl -s http://127.0.0.1:3001/health
61+
journalctl -u lusdt-bridge -f
62+
docker ps
63+
```
64+
65+
## 8) Hardening mínimo recomendado
66+
67+
1. Fechar portas públicas de Redis/Vault (bind localhost já aplicado).
68+
2. Colocar Nginx/Caddy com TLS na frente da API.
69+
3. Guardar `/opt/lusdt/secrets/vault-init.json` offline.
70+
4. Rotacionar `VAULT_TOKEN` periodicamente.
71+
5. Ativar backup de `/opt/lusdt/vault/data` e banco Postgres.

bridge-service/env-vps.example

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Bridge Service - VPS Production Example
2+
NODE_ENV=production
3+
PORT=3001
4+
5+
# RPCs
6+
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
7+
LUNES_RPC_URL=wss://ws.lunes.io
8+
9+
# Bridge auth
10+
BRIDGE_API_KEY=change_me_api_key
11+
BRIDGE_API_SECRET=change_me_hmac_secret
12+
OPS_BASIC_AUTH_USER=ops
13+
OPS_BASIC_AUTH_PASS=change_me_ops_password
14+
15+
# Wallet / contracts
16+
SOLANA_MULTISIG_VAULT=replace_with_squads_or_vault_address
17+
USDT_TOKEN_MINT=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
18+
LUNES_WALLET_SEED=replace_with_secure_seed
19+
LUSDT_CONTRACT_ADDRESS=replace_with_contract
20+
TAX_MANAGER_CONTRACT_ADDRESS=replace_with_tax_manager
21+
22+
# Fee wallets
23+
DEV_SOLANA_WALLET=replace_dev_wallet
24+
INSURANCE_SOLANA_WALLET=replace_insurance_wallet
25+
STAKING_REWARDS_SOLANA_WALLET=replace_staking_wallet
26+
27+
# DB / cache
28+
DATABASE_URL=postgresql://bridge_user:strong_password@127.0.0.1:5432/bridge_db
29+
REDIS_URL=redis://127.0.0.1:6379
30+
31+
# HSM - Vault (recommended for self-hosted VPS)
32+
HSM_TYPE=hashicorp_vault
33+
VAULT_URL=http://127.0.0.1:8200
34+
VAULT_TOKEN=replace_with_bridge_policy_token
35+
VAULT_KEY_PATH=transit
36+
VAULT_KEY_NAME=solana-bridge
37+
38+
# Multisig policy
39+
REQUIRE_MULTISIG_VAULT=true
40+
BOT_ORIGIN_SECRET=replace_origin_secret
41+
BOT_RISK_SECRET=replace_risk_secret
42+
BOT_BACKUP_SECRET=replace_backup_secret
43+
MULTISIG_REQUIRED_APPROVALS=2
44+
MULTISIG_TOTAL_BOTS=3
45+
MULTISIG_HIGH_VALUE_THRESHOLD=5000
46+
MULTISIG_TIMELOCK_MS=600000
47+
MULTISIG_PROPOSAL_TTL_MS=300000
48+
49+
# Limits
50+
HOT_WALLET_SINGLE_TX_LIMIT=10000
51+
HOT_WALLET_DAILY_LIMIT=50000
52+
TREASURY_MIN_BALANCE=50000
53+
MAX_TRANSACTION_VALUE=100000
54+
55+
# Alerts
56+
DISCORD_WEBHOOK_URL=
57+
ALERT_EMAIL=ops@yourdomain.com

bridge-service/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"helmet": "^7.1.0",
3535
"ioredis": "^5.9.3",
3636
"pg": "^8.11.3",
37+
"tweetnacl": "^1.0.3",
3738
"winston": "^3.11.0"
3839
},
3940
"devDependencies": {

bridge-service/src/bridge/usdt-fee-collector.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,18 @@ export class UsdtFeeCollector {
155155
logger.info('👂 Starting to listen for UsdtBridgeFeeMarked events');
156156

157157
try {
158-
// Subscribe to contract events / Assinar eventos do contrato
159-
await this.taxManagerContract.query
160-
.subscribeToEvents((event: any) => {
161-
this.handleFeeEvent(event).catch((error) => {
162-
logger.error('❌ Error handling fee event', { error });
163-
});
158+
// Subscribe to contract events via system events
159+
const api = (this.taxManagerContract as any).api;
160+
await api.query.system.events((events: any[]) => {
161+
events.forEach((record: any) => {
162+
const { event } = record;
163+
if (event && event.section === 'contracts' && event.method === 'ContractEmitted') {
164+
this.handleFeeEvent(event).catch((error: any) => {
165+
logger.error('❌ Error handling fee event', { error });
166+
});
167+
}
164168
});
169+
});
165170

166171
logger.info('✅ Successfully subscribed to TaxManager events');
167172
} catch (error) {

0 commit comments

Comments
 (0)