Saltar al contenido principal
ingenieríaseguridadapi
Diseñar el Trading No Custodial: Alcances de las Claves API y No Tocar Nunca los Retiros

Diseñar el Trading No Custodial: Alcances de las Claves API y No Tocar Nunca los Retiros

"No custodial" suele ser una palabra de marketing. Usada con precisión, es una restricción arquitectónica, y las restricciones de este tipo son interesantes porque eliminan trabajo en lugar de añadirlo.

Un bot de trading necesita colocar órdenes en tu nombre. Los exchanges lo hacen posible con claves API, y las claves API llevan alcances: lectura, trading y, en la mayoría de las plataformas, retiro. Así que la pregunta de diseño no es si pedir permisos. Es cuáles, y qué hacer cuando obtienes más de los que pediste.

Puntos clave

  • Una promesa de no usar un permiso es más débil que no tenerlo. Rechazamos las claves que llevan permiso de retiro en lugar de aceptarlas e ignorarlas.
  • Rechazar es una garantía más fuerte que confiar, porque no depende de que nuestro código sea correcto ni de que nuestro equipo sea honesto.
  • Si un flujo de conexión escribe en la cuenta del usuario, esas escrituras deben ocurrir después de la decisión de aceptar, no antes. De lo contrario cambias la configuración de alguien de camino a decirle que no.
  • No custodiar fondos elimina toda una clase de problemas difíciles: sin libro contable de custodia, sin conciliación, sin cola de retiros.
  • Lo que lo reemplaza es más estrecho y más afilado: tu sistema debe ser correcto en tiempo real, porque nunca puede deshacer nada.

1. Rechazar un permiso supera a prometer no usarlo

La implementación obvia es pedir a los usuarios una clave con alcances de lectura y trading, y simplemente no llamar nunca a los endpoints de retiro. La mayor parte de la industria hace esto, y no es irrazonable.

Nosotros hacemos algo más estricto. Si llega una clave que lleva permiso de retiro, se rechaza. El usuario ve un mensaje que le dice exactamente qué hacer:

Esta clave API tiene el permiso de retiro habilitado. Freya nunca retira fondos, así que no se aceptan las claves con ese permiso. Crea una clave solo con Lectura y Trading.

La misma regla aplica en los tres exchanges que soportamos. No hay anulación ni excepción de administrador.

Al principio esto parece fricción por sí misma. La clave funcionaría. El usuario se tomó cierta molestia en crearla. Rechazarla significa devolverlo al exchange para que cree otra.

La razón es que los dos diseños hacen promesas diferentes, y la diferencia solo se vuelve visible en tu peor día.

  • "Nunca llamamos a los endpoints de retiro" es una afirmación sobre nuestro comportamiento. Se sostiene mientras nuestro código sea correcto, nuestras dependencias estén limpias y todos los que tienen acceso de despliegue sigan siendo honestos. Son cosas razonables de esperar. No son cosas que un usuario pueda verificar.
  • "La clave no puede retirar" es una afirmación sobre la clave. Se sostiene sin importar lo que haga nuestro código, porque el exchange lo hace cumplir, y el usuario puede confirmarlo por sí mismo en la configuración de su propio exchange.

La segunda es una petición más débil y una garantía más fuerte. Prefiere diseños cuya propiedad de seguridad sea impuesta por alguien distinto a ti, sobre todo cuando el usuario no tiene forma de auditar tu lado.

Hay un beneficio menor que importa en la práctica: hace que el modo de fallo sea ruidoso. Una clave con demasiado alcance queda atrapada en el momento de la conexión, frente a un usuario que está configurando activamente las cosas y puede arreglarlo en un minuto. La alternativa es que la clave con exceso de alcance quede ahí funcionando bien, y nadie se entere de nada hasta que importe.

2. Di que no antes de tocar nada

Este es el detalle que más querría que otro ingeniero se llevara, porque es fácil de equivocar y casi invisible cuando lo haces.

Conectar un exchange no es una operación puramente de lectura. Según la plataforma, dejar una cuenta en un estado utilizable puede implicar escribir en ella: ajustar un modo de cuenta, establecer un modo de posición, etc. Son pasos legítimos que ocurren como parte de la configuración.

Ahora considera el orden. Si la comprobación de permisos ocurre después de esas escrituras, entonces una clave rechazada aún deja rastro. El usuario te entregó una credencial, tú modificaste la configuración de su cuenta, y luego le dijiste que no. Desde su lado, nada explica por qué la configuración de su exchange es distinta de como la dejó.

Así que la regla en la que nos asentamos: una credencial rechazada debe dejar la cuenta del usuario exactamente como se encontró. Cualquier paso que escriba pertenece después de la decisión de aceptar, nunca antes de ella. El rechazo tiene que ser alcanzable sin efectos secundarios.

Generalizado, esto no es más que pensamiento transaccional aplicado al sistema de otra persona. No puedes revertir una escritura en una cuenta de terceros, así que el orden es tu única protección. Cuando no puedes deshacer, secuencia con cuidado.

Una nota de implementación que nos salvó de toda una categoría de bugs: el rechazo se expresa como un resultado inválido en lugar de una bandera especial, así que cada ruta que consume un resultado de validación lo maneja sin tener que saber que existe. Tenemos dos flujos de conexión, y ambos heredan el mismo rechazo porque ninguno tuvo que acordarse de preguntar por él. Codificar una regla en un tipo que todos los consumidores ya leen supera a documentarla y esperar.

3. Lo que la restricción elimina

Aquí es donde el intercambio se vuelve claramente favorable.

Los fondos nunca salen de la cuenta del exchange del usuario. Los bots operan con claves de lectura y trading, y el saldo se queda donde empezó. Lo que se sigue de esto es una larga lista de cosas que simplemente no existen en nuestro sistema:

  • Sin libro contable de custodia, así que sin conciliación entre un saldo interno y uno externo
  • Sin cola de retiros, sin flujo de aprobación, sin límites diarios sobre el capital de trading
  • Sin división de billeteras calientes y frías para ese capital, y sin gestión de claves a su alrededor
  • Sin la pregunta de qué pasa con los fondos del usuario si la empresa desaparece

Cada una de esas es un subsistema entero en un producto custodial, y cada una es un lugar donde el dinero puede desaparecer. Aquí están ausentes no porque los resolviéramos sino porque nunca asumimos lo que los crea.

Quiero ser preciso en lugar de tajante, eso sí: esto aplica al capital de trading. Los saldos de plataforma usados para las suscripciones son un asunto aparte con su propio manejo. La propiedad no custodial trata del dinero que opera, y ese es el dinero que más importa.

4. Lo que no arregla

Una restricción que elimina problemas también elimina las herramientas que usarías para arreglar errores, y vale la pena ser honesto al respecto.

Las operaciones son definitivas. Con custodia, una transferencia interna puede en principio revertirse. Una orden ejecutada en la cuenta del exchange de otra persona no. Todo el peso de la ingeniería se traslada a ser correcto antes de que la solicitud salga, en lugar de conciliar después de que aterrice. Esa es una disciplina más dura de lo que suena, y es la razón por la que tanto de nuestro trabajo trata sobre validación, precisión e idempotencia.

El permiso de trading sigue siendo un permiso real. Una clave de lectura y trading filtrada no puede vaciar una cuenta hacia una dirección externa, que es el resultado que la gente realmente teme. Pero puede colocar órdenes. El radio de impacto está acotado, no es cero, y sería deshonesto describirlo como cero.

El usuario aún tiene obligaciones. La rotación de claves, no reutilizar claves entre servicios y vigilar qué más tiene acceso a la misma cuenta siguen siendo suyas. Nuestra arquitectura acota el daño; no vuelve inofensiva la clave.

Lo que le diría a otro equipo

  • Pide el alcance más estrecho, luego verifica que lo obtuviste. Solicitar menos no es lo mismo que recibir menos.
  • Prefiere garantías impuestas fuera de tu propio código, en particular las que el usuario puede comprobar sin confiar en ti.
  • Haz que el rechazo esté libre de efectos secundarios. Si tu flujo escribe en una cuenta de terceros, todo lo que escribe va después de la decisión de aceptar.
  • Codifica la regla donde los consumidores ya miran. Una regla expresada en un tipo compartido no necesita que cada llamador la recuerde.

El punto más amplio es que "no haremos X" y "no podemos hacer X" se leen de forma parecida en una landing page y son completamente distintos en un incidente. Siempre que puedas mover una promesa de la primera categoría a la segunda, el coste suele ser pequeño y el beneficio aparece justo cuando todo lo demás va mal.


Lecturas Relacionadas

Crea una cuenta

Pon en práctica lo que aprendiste y abre una cuenta de Freya hoy.

Regístrate ahora
Este contenido es solo con fines educativos y no constituye asesoramiento financiero. El trading de criptomonedas conlleva riesgos significativos. Nunca invierta más de lo que puede permitirse perder.