Contexto
Intento de levantar el stack en local con Docker sobre Apple Silicon (ARM64) y operar contra la testnet de GRVT. Se encontraron y corrigieron los siguientes problemas. Los fixes están disponibles si el autor quiere integrarlos.
1. 🔴 Build falla en ARM64 — sqlite3 requiere glibc 2.38, Bookworm tiene 2.36
node-pre-gyp descarga un binario precompilado de sqlite3 compilado contra glibc 2.38. La imagen runtime (node:22-bookworm-slim) solo tiene glibc 2.36. El contenedor arranca y muere de inmediato:
Error: /lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.38' not found
ERR_DLOPEN_FAILED
Afecta exclusivamente a ARM64 (Apple Silicon, Raspberry Pi, instancias AWS Graviton). En x86 no se manifiesta.
Fix: añadir RUN npm rebuild sqlite3 --build-from-source en el stage bot-builder del Dockerfile, después de npm ci:
RUN npm ci --workspace=@grvt-grid/bot --include-workspace-root
RUN npm rebuild sqlite3 --build-from-source
2. 🔴 Build del dashboard falla — vite-env.d.ts eliminado en commit 4631ba9
El commit 4631ba9 (security: remove DASHBOARD_API_KEY from client bundle) eliminó vite-env.d.ts junto con VITE_DASHBOARD_API_KEY. Sin ese archivo, TypeScript no reconoce import.meta.env ni los imports de .css:
src/App.tsx(90,48): error TS2339: Property 'env' does not exist on type 'ImportMeta'.
src/lib/api-client.ts(33,30): error TS2339: Property 'env' does not exist on type 'ImportMeta'.
src/lib/ws-client.ts(45,38): error TS2339: Property 'env' does not exist on type 'ImportMeta'.
src/main.tsx(3,8): error TS2307: Cannot find module './styles/globals.css'
src/pages/settings.tsx(105,26): error TS2339: Property 'env' does not exist on type 'ImportMeta'.
Fix: recrear packages/dashboard/src/vite-env.d.ts:
/// <reference types="vite/client" />
3. 🟡 No hay soporte de testnet — URLs y chainId EIP-712 hardcodeados a mainnet
Cinco puntos de hardcode en cuatro archivos:
| Archivo |
Problema |
src/api/auth.ts (×2) |
https://edge.grvt.io/auth/api_key/login hardcodeado |
src/api/client.ts |
MARKET_DATA_URL y TRADING_URL son constantes de módulo |
src/api/order-signer.ts |
chainId: 325 hardcodeado en el domain EIP-712 |
src/dashboard/server.ts (×3) |
sub_account_id '3931648923440974' del desarrollador hardcodeado |
El chainId incorrecto es especialmente crítico: órdenes firmadas con chainId 325 enviadas a la testnet (que espera 326) son rechazadas por el exchange con error de firma.
URLs verificadas contra el SDK oficial (gravity-technologies/grvt-pysdk):
GRVT_ENV |
Edge (auth) |
Trading |
Market data |
ChainId |
prod |
edge.grvt.io |
trades.grvt.io |
market-data.grvt.io |
325 |
testnet |
edge.testnet.grvt.io |
trades.testnet.grvt.io |
market-data.testnet.grvt.io |
326 |
staging |
edge.staging.gravitymarkets.io |
trades.staging.gravitymarkets.io |
market-data.staging.gravitymarkets.io |
328 |
dev |
edge.dev.gravitymarkets.io |
trades.dev.gravitymarkets.io |
market-data.dev.gravitymarkets.io |
327 |
Fix propuesto: un archivo src/api/grvt-env.ts con la tabla completa que lee GRVT_ENV del entorno (prod por defecto).
4. 🟡 Modales inutilizables — contenido colapsado a altura mínima
<dialog> con showModal() sin height definida hace que flex-1 del div de contenido no tenga espacio al que crecer. El resultado es una modal que solo muestra el header y el footer, con el contenido colapsado.
Afecta al wizard "Crear bot nuevo" (4 pasos) y a las confirmaciones de start/pause/close.
Fix:
// packages/dashboard/src/components/primitives/modal.tsx
const SIZE_CLASS = {
regular: 'max-w-[560px] md:min-h-[380px]', // antes: sin min-h
wide: 'max-w-[720px] md:min-h-[640px]', // antes: sin min-h
};
5. 🟡 Actualización de rango bloqueada en todos los pares no-ETH
El cap de seguridad del auto-buy está en unidades base y hardcodeado a MAX_AUTO_BUY_ETH = 2.0. Para HYPE (~$60) ese cap equivale a ~$120 — cualquier ajuste de rango mínimo lo supera. El mensaje también hardcodea el literal "ETH" aunque el par sea otro:
Auto-buy deficit 6.6700 ETH exceeds safety cap of 2 ETH
…en un bot de HYPE_USDT_Perp. Afecta también a BTC, SOL y cualquier futuro instrumento.
Fix: expresar el cap en USD notional y extraer la moneda base del par:
const MAX_AUTO_BUY_USD = 10_000;
const baseCurrency = bot.pair.split('_')[0] ?? 'base'; // "HYPE_USDT_Perp" → "HYPE"
const deficitUsd = baseDeficit * currentPrice;
if (deficitUsd > MAX_AUTO_BUY_USD) {
safetyViolations.push(
`Auto-buy deficit ${baseDeficit.toFixed(4)} ${baseCurrency} ($${deficitUsd.toFixed(0)}) exceeds safety cap of $${MAX_AUTO_BUY_USD.toLocaleString()} USD`
);
}
6. 🔵 master.key no montado en docker-compose.yml
El bot busca la clave AES-256-GCM en /etc/grvt-grid/master.key pero el compose no incluye el mount. En un deploy fresco el primer guardado de credenciales GRVT falla sin mensaje claro.
Fix:
volumes:
- ./data:/app/data
- ./logs/bot:/app/logs
- ./master.key:/etc/grvt-grid/master.key:ro
Entorno
- Commit:
80ec39e
- Plataforma: macOS Apple Silicon (ARM64), Docker Desktop
- Red GRVT: testnet
Contexto
Intento de levantar el stack en local con Docker sobre Apple Silicon (ARM64) y operar contra la testnet de GRVT. Se encontraron y corrigieron los siguientes problemas. Los fixes están disponibles si el autor quiere integrarlos.
1. 🔴 Build falla en ARM64 —
sqlite3requiere glibc 2.38, Bookworm tiene 2.36node-pre-gypdescarga un binario precompilado desqlite3compilado contra glibc 2.38. La imagen runtime (node:22-bookworm-slim) solo tiene glibc 2.36. El contenedor arranca y muere de inmediato:Afecta exclusivamente a ARM64 (Apple Silicon, Raspberry Pi, instancias AWS Graviton). En x86 no se manifiesta.
Fix: añadir
RUN npm rebuild sqlite3 --build-from-sourceen el stagebot-builderdel Dockerfile, después denpm ci:2. 🔴 Build del dashboard falla —
vite-env.d.tseliminado en commit4631ba9El commit
4631ba9(security: remove DASHBOARD_API_KEY from client bundle) eliminóvite-env.d.tsjunto conVITE_DASHBOARD_API_KEY. Sin ese archivo, TypeScript no reconoceimport.meta.envni los imports de.css:Fix: recrear
packages/dashboard/src/vite-env.d.ts:/// <reference types="vite/client" />3. 🟡 No hay soporte de testnet — URLs y chainId EIP-712 hardcodeados a mainnet
Cinco puntos de hardcode en cuatro archivos:
src/api/auth.ts(×2)https://edge.grvt.io/auth/api_key/loginhardcodeadosrc/api/client.tsMARKET_DATA_URLyTRADING_URLson constantes de módulosrc/api/order-signer.tschainId: 325hardcodeado en el domain EIP-712src/dashboard/server.ts(×3)'3931648923440974'del desarrollador hardcodeadoEl chainId incorrecto es especialmente crítico: órdenes firmadas con chainId 325 enviadas a la testnet (que espera 326) son rechazadas por el exchange con error de firma.
URLs verificadas contra el SDK oficial (
gravity-technologies/grvt-pysdk):GRVT_ENVprodedge.grvt.iotrades.grvt.iomarket-data.grvt.iotestnetedge.testnet.grvt.iotrades.testnet.grvt.iomarket-data.testnet.grvt.iostagingedge.staging.gravitymarkets.iotrades.staging.gravitymarkets.iomarket-data.staging.gravitymarkets.iodevedge.dev.gravitymarkets.iotrades.dev.gravitymarkets.iomarket-data.dev.gravitymarkets.ioFix propuesto: un archivo
src/api/grvt-env.tscon la tabla completa que leeGRVT_ENVdel entorno (prodpor defecto).4. 🟡 Modales inutilizables — contenido colapsado a altura mínima
<dialog>conshowModal()sinheightdefinida hace queflex-1del div de contenido no tenga espacio al que crecer. El resultado es una modal que solo muestra el header y el footer, con el contenido colapsado.Afecta al wizard "Crear bot nuevo" (4 pasos) y a las confirmaciones de start/pause/close.
Fix:
5. 🟡 Actualización de rango bloqueada en todos los pares no-ETH
El cap de seguridad del auto-buy está en unidades base y hardcodeado a
MAX_AUTO_BUY_ETH = 2.0. Para HYPE (~$60) ese cap equivale a ~$120 — cualquier ajuste de rango mínimo lo supera. El mensaje también hardcodea el literal"ETH"aunque el par sea otro:…en un bot de
HYPE_USDT_Perp. Afecta también a BTC, SOL y cualquier futuro instrumento.Fix: expresar el cap en USD notional y extraer la moneda base del par:
6. 🔵
master.keyno montado endocker-compose.ymlEl bot busca la clave AES-256-GCM en
/etc/grvt-grid/master.keypero el compose no incluye el mount. En un deploy fresco el primer guardado de credenciales GRVT falla sin mensaje claro.Fix:
Entorno
80ec39e