# Salir sin la web

> Cómo funciona BotradixSalida: petición, ejecución propia a las 24 horas, retiros y cancelación de órdenes, con sus límites.

Source: https://docs.botradix.com/es/exit/

BotradixSalida ofrece funciones para pedir la salida del DEX, ejecutar tu propia salida, retirar fondos disponibles y cancelar órdenes sin usar la web de BotRadix. Las funciones de tu cuenta toman la wallet que envía la transacción como titular; no permiten elegir otro destinatario. El contrato de salida no guarda tu colateral: se comunica con el router y los pagos salen de CrossMargin hacia tu wallet.

> [!CAUTION]
> Usa solo la dirección `0x43473B3684ccB5d9d57D119f2A6bc7B9B1f5EEe5`, en Base. Escríbela tú en basescan.org o compárala carácter a carácter; no sigas direcciones ni enlaces recibidos por mensajes, anuncios o redes, aunque digan venir de BotRadix. En la pestaña **Contract**, BaseScan debe mostrar el código de esa dirección como verificado; si no lo muestra, no continúes. Esta salida no necesita tu frase de recuperación ni tu clave privada: no las compartas con nadie.

> [!IMPORTANT]
> Esta guía describe el mecanismo, no el estado de una cuenta ni la configuración del router en este momento. Los plazos y límites son los del router para el que se desplegó Salida; consulta sus lecturas antes de actuar. **No hay un plazo garantizado de cierre ni de cobro.**

## Paso a paso

Resumen de la salida completa. Cada paso se explica con detalle en las secciones de abajo; los nombres son los del código verificado de BotradixSalida (inglés / español, hacen lo mismo).

1. **Abre la Salida en BaseScan.** En **basescan.org**, escribe tú la dirección `0x43473B3684ccB5d9d57D119f2A6bc7B9B1f5EEe5` y comprueba en la pestaña **Contract** que el código aparece como verificado.
2. **Lee tu estado.** En **Contract → Read Contract**, abre `status` (o `estado`). En el campo `account` (o `cuenta`) pon la dirección de tu wallet y pulsa **Query**. Comprueba que `forwarder` es la dirección de Salida y anota `requestedAt`, `openPositions` y `openOrders`.
3. **Conecta tu wallet.** En **Contract → Write Contract**, pulsa **Connect to Web3**. Usa la wallet titular de la cuenta, en **Base (chain ID 8453)** y con algo de **ETH en Base** para el gas.
4. **Pide la salida.** En Write Contract, `exitDex` (o `salirDelDex`), sin parámetros: pulsa **Write** y confirma en tu wallet. Tu cuenta deja de aceptar posiciones nuevas. Si no tenías posiciones ni órdenes, la salida puede terminar en esa misma transacción.
5. **Cancela tus órdenes, si `openOrders` es mayor que 0.** `cancelOrders` (o `cancelarOrdenes`); en el campo `ids` pon la lista de IDs de tus órdenes entre corchetes, por ejemplo `[123,456]` (cómo encontrarlos: sección 2).
6. **Espera el plazo.** El keeper de BotRadix puede cerrar tus posiciones antes. Si no, a partir de `selfExecutableAt`, **24 horas** después de la petición, puedes ejecutar tú la salida. Con una emergencia confirmada (`emergencyAt` distinto de 0) no hay espera, pero solo cierran las posiciones de mercados fijados.
7. **Ejecuta tu salida.** `executeMyExit` (o `ejecutarMiSalida`): el bloque sin campos intenta cerrar hasta **8** posiciones; el de `maxPositions` (o `maxPosiciones`) admite de **1 a 16**. Repite mientras `openPositions` sea mayor que 0 y haya precios válidos. **Antes de confirmar, sube a mano el límite de gas en tu wallet a 8.000.000** (16.000.000 si usas `maxPositions` 16): con el límite que calcula la wallet la transacción puede terminar bien sin cerrar ninguna posición, porque el contrato salta los cierres para los que no queda gas. Solo pagas el gas que se usa.
8. **Retira todo.** Con `openPositions` en 0 y sin órdenes, `withdrawAll` (o `retirarTodo`), sin parámetros. Comprueba en la transacción las transferencias de USDC y BAQ a tu wallet y vuelve a leer `status`. Si hay una pausa de retiros, repite cuando termine.
9. **Si algo revierte o no avanza**, no repitas la misma llamada: lee `status` y busca tu caso en [Si revierte o no avanza](#si-revierte-o-no-avanza). Si no encuentras la causa, guarda el hash y escribe a [support@botradix.com](mailto:support@botradix.com).

¿Quieres anular la petición en lugar de salir? Usa `cancelExit` (o `cancelarSalida`), sin parámetros. Nada de esto garantiza un plazo de cierre ni de cobro: depende de precios, órdenes, deudas, pausas y liquidez (Términos, sección 22).

## Antes de empezar

1. Abre [BotradixSalida en basescan.org](https://basescan.org/address/0x43473B3684ccB5d9d57D119f2A6bc7B9B1f5EEe5#code). Comprueba la dirección completa, `0x43473B3684ccB5d9d57D119f2A6bc7B9B1f5EEe5`, y que la pestaña **Contract** muestra el código como verificado.
2. **Antes de conectar o enviar nada**, entra en **Contract → Read Contract**. Abre `status` (alias `estado`), introduce la dirección de tu wallet en `account` (o `cuenta`) y pulsa **Query**. En la tupla devuelta, `forwarder` debe ser **la dirección de Salida anterior**. Si es cero, distinta o la lectura falla, no continúes por esta Salida: revisa la dirección y la configuración del router. Consulta también `ROUTER()` y contrástalo con las [direcciones oficiales](https://docs.botradix.com/es/security-contracts/).
3. Configura tu wallet en **Base mainnet, chain ID 8453**, con **ETH en Base para el gas**. Usa la wallet titular de las posiciones y el colateral; las funciones de tu cuenta actúan sobre quien firma.
4. En la misma dirección de Salida, abre **Write Contract**, pulsa **Connect to Web3**, elige tu wallet y comprueba la cuenta conectada y la red. Conectar no ejecuta la salida.
5. Para cada acción de abajo, abre el bloque con ese nombre, rellena solo sus parámetros, pulsa **Write** y confirma la transacción en tu wallet. Abre el hash, espera su confirmación y vuelve a consultar `status(tuDirección)` en **Read Contract**. Repite la comprobación de `forwarder` antes de nuevas acciones; una lectura anterior no impide cambios posteriores del router.

Las lecturas no cambian el estado ni requieren una transacción. Las fechas son marcas Unix en **segundos**, no cuentas atrás ni horas locales.

| Campo de `status(tuDirección)` | Cómo interpretarlo |
|---|---|
| `requestedAt` | Cero: no hay petición pendiente. Un valor distinto de cero: fecha de la petición. |
| `selfExecutableAt` | Fecha ordinaria a partir de la que puedes ejecutar tu salida; requiere petición previa. En emergencia confirmada se omite la espera, aunque este campo siga mostrando la fecha ordinaria. |
| `openPositions`, `openOrders` | Cuántas posiciones y órdenes quedan. No son listas de IDs. |
| `withdrawalsPaused`, `withdrawalsPausedUntil` | Si el retiro está pausado y cuándo termina la pausa. |
| `emergencyChallengeAt`, `emergencyAt` | El primero indica un desafío; solo `emergencyAt != 0` indica emergencia confirmada. |
| `emergencyPending`, `unsettledAccounts`, `distributionOpenedAt` | Liquidación pendiente de tu cuenta, cuentas pendientes globalmente y apertura del reparto (`0`: aún no abierto). |
| `emergencyClaimUSDC`, `deferredUSDC` | Reclamación de emergencia y pago diferido; no equivalen a dinero libre ya cobrado. |

## Las funciones de tu cuenta

Las funciones tienen alias en español e inglés que siguen el mismo camino.

| Acción | Nombre en español | Nombre en inglés |
|---|---|---|
| Pedir la salida | `salirDelDex()` | `exitDex()` |
| Ejecutar tu salida | `ejecutarMiSalida()` o `ejecutarMiSalida(uint256)` | `executeMyExit()` o `executeMyExit(uint256)` |
| Retirar lo disponible | `retirarTodo()` | `withdrawAll()` |
| Cancelar órdenes propias | `cancelarOrdenes(uint256[])` | `cancelOrders(uint256[])` |
| Cancelar la petición de salida | `cancelarSalida()` | `cancelExit()` |

Los valores de retorno descritos abajo son los del contrato. **Un recibo con `Success` no suele mostrar esos valores ni demuestra que hayas retirado todo**: comprueba las lecturas de `status` y las transferencias a tu wallet. `SalidaUsada` indica la acción enviada, no que el proceso haya terminado.

### 1. Pedir la salida

En **Write Contract**, usa `exitDex()` o `salirDelDex()`, sin parámetros. Registra la petición y bloquea nuevas aperturas de la cuenta. Si no hay posiciones ni órdenes abiertas, intenta completar la retirada en esa misma transacción, sujeto a los demás controles. Repetir una petición pendiente conserva la fecha original; no reinicia las 24 horas.

Devuelve `1` si completó la salida en esa transacción y `0` si sigue pendiente. Comprueba `requestedAt`, `selfExecutableAt`, `openPositions` y `openOrders`. Un `0` no es por sí solo un fallo: continúa con las órdenes y posiciones pendientes. Un `1` no garantiza haber cobrado pagos diferidos sin respaldo ni reclamaciones aún no pagadas.

El keeper puede cancelar órdenes y cerrar posiciones usando precios válidos observados **en el instante de la petición o después**. No se promete que lo haga en segundos. Durante la espera siguen existiendo riesgo de precio, funding y liquidación.

### 2. Cancelar órdenes pendientes

Los IDs que pide esta función son los de los eventos `DexOrderCreated` del router, la dirección que devuelve `ROUTER()`. En BaseScan, abre esa dirección y busca en sus **Events** los `DexOrderCreated` de tu wallet: en ese evento, el primer valor indexado es el ID de la orden, el segundo la wallet titular y el tercero el `pairId`. Copia solo los IDs de orden, nunca el `pairId`. Vuelve a **Write Contract de Salida**, abre `cancelOrders` o `cancelarOrdenes` y pega en `ids` la lista, por ejemplo `[123,456]` **sustituyendo esos números por tus IDs reales**.

No necesita precios ni devuelve un valor. Comprueba que `openOrders` baja. Una orden tuya que ya estaba ejecutada o cancelada se ignora; una orden de otra wallet o un ID que no sea tuyo hace revertir la transacción completa.

Cancelar órdenes no cierra por sí solo todas las posiciones. La función de ejecución propia no enumera ni cancela automáticamente todas tus órdenes de entrada: revisa `openOrders` y cancela las que queden para poder completar la salida y liberar sus reservas.

### 3. Ejecutar tu salida a partir de las 24 horas

Si sigue pendiente, consulta `status(tuDirección)` y usa `executeMyExit` o `ejecutarMiSalida` en **Write Contract** una vez alcanzado `selfExecutableAt`, **24 horas después de la petición**. En una emergencia confirmada (`emergencyAt != 0`) no se exige esa espera, pero sigue haciendo falta pedir la salida con `exitDex()`; abrir un desafío no basta.

BaseScan muestra dos versiones con el mismo nombre: el bloque **sin campos** intenta cerrar hasta **8 posiciones**; el que tiene `maxPositions` (o `maxPosiciones`) permite introducir una tanda de **1 a 16**. El gas disponible puede reducir lo procesado. Puede ser necesario repetir llamadas.

Para un mercado no congelado, las dos patas del precio deben estar en sesión abierta, haberse observado en el instante de la petición o después, tener como máximo **10 minutos** de antigüedad, no estar fechadas en el futuro y cumplir sus límites de confianza. Un mercado congelado utiliza su precio fijado. **En emergencia solo se cierran posiciones de mercados congelados.** Las posiciones sin precio utilizable se omiten y permanecen abiertas.

Devuelve `(cerradas, pendientes, terminada)`: posiciones cerradas en esta llamada, posiciones que siguen abiertas y `1` si completó la salida (`0` si no). Revisa `status(tuDirección)` después de cada tanda. Repite mientras queden posiciones y se cumplan las condiciones de precio; si no hay progreso, consulta las causas de abajo. Si quedan órdenes, deudas, una pausa efectiva o una liquidación de emergencia pendiente, cerrar la última posición puede no completar el retiro. **En emergencia, termina con `withdrawAll()`**, aunque ya no queden posiciones. Llegar a las 24 horas habilita una llamada, no dispara una transacción ni garantiza disponer de precios o fondos.

### 4. Retirar lo disponible

Cuando `openPositions` sea `0`, cancela antes las órdenes que queden y usa `withdrawAll()` o `retirarTodo()` en **Write Contract**, sin parámetros. No necesita precios ni una petición de salida previa. Con posiciones abiertas revierte con `DexPositionsOpen`. Intenta liquidar y cobrar lo que corresponda en emergencia, reclamar los pagos diferidos que ya tengan respaldo y retirar el USDC libre y BAQ disponibles a la wallet titular.

No devuelve un valor: comprueba las transferencias de USDC y BAQ a tu wallet en esa transacción y el nuevo estado. Una transacción correcta puede reflejar una retirada parcial o de importe cero; no demuestra por sí sola que no quede nada pendiente. Durante una pausa, el router emite `DexExitAwaitingWithdrawal` y detiene el retiro **sin que necesariamente revierta la transacción**. Repite cuando termine la pausa.

Las reservas de órdenes no se retiran; la deuda cruzada o una liquidación pendiente también pueden impedir completar el proceso. Un pago diferido sin respaldo no se convierte en saldo retirable por llamar a esta función. En emergencia, el reparto requiere que no quede ninguna posición abierta en todo el DEX y que todas las cuentas estén liquidadas. Si `distributionOpenedAt` sigue en `0` o queda una reclamación, vuelve a llamar cuando se cumplan esas condiciones; puede haber un reparto parcial y un resto diferido.

### Cancelar la petición

Si quieres anular una petición pendiente, usa `cancelExit()` o `cancelarSalida()`, sin parámetros, en **Write Contract**. No devuelve un valor: comprueba que `requestedAt` vuelve a `0`. Quita el bloqueo de aperturas de esa petición; no elimina una emergencia ni otros bloqueos del protocolo. No restaura posiciones ya cerradas ni órdenes canceladas, y no revierte transacciones confirmadas. Si después pides otra salida, comienza una nueva espera ordinaria.

## Si revierte o no avanza

Si BaseScan o la wallet avisan de que la llamada revertiría, revisa la causa antes de firmar. Una transacción confirmada como fallida no conserva cambios de esa llamada, pero consume gas. No repitas sin cambiar la condición que la impide. Salida reenvía la llamada al router: si el código del router no aparece verificado en BaseScan, el motivo del error puede mostrarse como un código hexadecimal en lugar de un nombre. Las lecturas de `status` y `market` te dicen en qué situación estás.

| Situación | Qué hacer |
|---|---|
| Fallaría `executeMyExit()` o `cancelExit()` y `requestedAt` es `0` | No hay petición pendiente. Si quieres salir y quedan posiciones, pide antes la salida con `exitDex()`. Si la salida ya terminó, no necesitas cancelarla. |
| Fallaría `executeMyExit()` antes de `selfExecutableAt` | Espera a esa fecha, salvo emergencia confirmada (`emergencyAt != 0`). |
| `withdrawAll()` revierte con `DexPositionsOpen` | Quedan posiciones: pide la salida si hace falta, ciérralas con `executeMyExit()` cuando proceda y vuelve a leer el estado. |
| Fallaría cualquier función de tu cuenta sin otra causa visible | Revisa que `forwarder` sea esta dirección de Salida, la cuenta conectada y, en `cancelOrders`, que todos los IDs sean de órdenes de tu wallet. Añadir gas no lo arregla. |
| `DexExitAwaitingWithdrawal` o `withdrawalsPaused == true` | Es una espera de retiro, no necesariamente un revert. Consulta `withdrawalsPausedUntil` y reintenta el retiro después de la pausa. |
| `withdrawAll()` se confirma pero no llega todo | Puede quedar una pausa, órdenes con fondos reservados, deuda cruzada, una liquidación pendiente o un pago diferido sin respaldo. Revisa `openOrders`, `deferredUSDC`, `emergencyPending` y la pausa; si las lecturas no lo explican, comunica el hash a soporte. |
| Cero posiciones cerradas, o `terminada == 0` | Puede faltar precio válido, haber poco gas para otra posición, órdenes, deuda o liquidación pendiente. Consulta los contadores y el mercado; en emergencia puede faltar fijarlo. Una llamada exitosa no fuerza esas condiciones. |
| Falta de gas | Comprueba ETH en Base y la estimación. Para ejecución propia, prueba una tanda menor, por ejemplo `maxPositions = 1`; para listas de órdenes, usa lotes más pequeños. |
| Fallaría una función «de todos» | El desafío o la emergencia no están en el estado requerido o su plazo no se ha cumplido. Vuelve a leer `status` (`emergencyChallengeAt`, `emergencyAt`) y `market(pairId)` (`challengeOpenedAt`, `settleAfter`, `frozenKind`) antes de repetir. |
| Fallaría `confirmEmergency` con una lista de mercados | Vuelve a obtener la lista completa y ascendente de `marketsWithPositions()`; no inventes IDs ni uses una lista recortada. |
| Fallaría `settleMarket` aunque se cumpla `settleAfter` | Puede faltar una observación con la que fijar el precio: el plazo cumplido no crea un precio. Revisa `market(pairId)` y comunica el problema. |

Si no puedes identificar la causa, conserva el hash y el error visible y consulta [support@botradix.com](mailto:support@botradix.com). No hay garantía de que esperar o repetir la misma llamada permita completarla.

## Pausas, falta de precios y emergencia

Con las reglas del router para el que se desplegó Salida, cada pausa de retiros caduca a las 72 horas, exige 24 horas sin pausa antes de la siguiente y no rige en emergencia confirmada. Aun después de caducar, pueden quedar otros impedimentos al cobro.

Las funciones **«de todos»** también están en **Write Contract de Salida**. Cualquiera puede pagar el gas para llamarlas cuando se cumplan sus condiciones. Los resultados y pagos corresponden a cada titular; enviarlas no da derecho a cobrar fondos ajenos. No se activan automáticamente al vencer las 24 horas de tu petición.

| Función en inglés / alias en español | Condiciones y resultado |
|---|---|
| `openEmergencyChallenge()` / `abrirDesafioEmergencia()` | Abre el desafío público de **72 horas** si hay posiciones en el DEX y aún no hay emergencia. Lee `emergencyChallengeAt`. |
| `confirmEmergency(markets)` / `confirmarEmergencia(mercados)` | Tras las 72 horas, obtén en **Read Contract** la lista `bytes32[]` **completa y ascendente** de `marketsWithPositions()` / `mercadosConPosiciones()` y pégala en `markets` (o `mercados`) de **Write Contract**. Devuelve `true` si activa la emergencia. Una observación de USDC o de un mercado con posiciones desde la apertura, incluso con sesión cerrada, anula el desafío y devuelve `false`. Comprueba `emergencyAt`. |
| `fixEmergencyMarkets(markets)` / `fijarMercadosEmergencia(mercados)` | En emergencia, fija los mercados con posiciones que falten; devuelve cuántos fijó. Usa los IDs de mercados de la lectura anterior y repite si el gas dejó trabajo pendiente. Precio y funding se fijan al instante de la emergencia, aunque la fijación se complete después. |
| `challengeMarket(pairId)` / `desafiarMercado(pairId)` | Abre el desafío de **3 días** de un mercado con posiciones y aún no congelado. `pairId` es el número del par, no el `marketId` de tipo `bytes32`. Lee `market(pairId)` / `mercado(pairId)`, incluidos `challengeOpenedAt` y `settleAfter`. |
| `settleMarket(pairId)` / `liquidarMercado(pairId)` | Desde `settleAfter`, sin observaciones desde el desafío, congela el mercado al último precio observado y fija su funding. Devuelve `true` al congelarlo; una observación posterior anula el desafío y devuelve `false`. Comprueba `frozenKind` y `frozenPriceX18` en `market`. |
| `closeFrozen(positions, orders)` / `cerrarCongeladas(posiciones, ordenes)` | Recibe dos listas de IDs, cierra posiciones de mercados congelados y cancela sus órdenes; en emergencia puede cancelar cualquier orden. Devuelve `(posiciones cerradas, órdenes canceladas)`. Puede requerir tandas; los resultados quedan en las cuentas de sus titulares. |
| `settleAccounts(accounts)` / `liquidarCuentas(cuentas)` | En emergencia, liquida las cuentas indicadas sin posiciones ni órdenes; devuelve cuántas liquidó. Ganancia neta: reclamación. Pérdida neta: efectivo y después respaldo comprometido en BAQ. Las cuentas aún no liquidables se omiten. |
| `payEmergencyClaims(accounts)` / `cobrarReparto(cuentas)` | Sin posiciones en todo el DEX y con todas las cuentas liquidadas, abre el reparto y abona la parte correspondiente a cada cuenta en CrossMargin. Devuelve el importe total pagado, no el número de cuentas; `0` puede significar que el reparto aún no puede abrirse. Cada titular termina con `withdrawAll()` para retirarlo a su wallet. |

La emergencia confirmada es definitiva para este DEX y detiene el trading; el administrador puede declararla sin el desafío público. El reparto aplica a todos el mismo porcentaje fijado: el menor entre el 100 % y la liquidez disponible (vault, seguro y emergencia, excluidas las reservas para pagos diferidos anteriores) dividida por las reclamaciones, sujeto a redondeo. Lo no cubierto queda diferido, sin plazo garantizado de pago. Los desafíos, las tandas y el reparto necesitan transacciones; ningún reloj los ejecuta por sí solo.

## Dependencias de esta salida

BotradixSalida no tiene administrador ni mecanismo de actualización propio, pero **depende del router y de CrossMargin**. El router debe reconocerlo como `forwarder`. Mientras la configuración esté abierta, la administración puede sustituirlo o desconectarlo mediante `setDexExitForwarder(address(0))` y puede cambiar la lógica que procesa la salida sin aviso previo obligatorio. Una vuelta a una versión anterior del router puede dejar Salida sin uso aunque su dirección siga existiendo. Tras el sellado previsto por este código, la Salida ya no se puede desconectar y los módulos del router solo se pueden cambiar mediante la puerta de aviso previo, con un mínimo comprometido de 72 horas o más. Esto describe las reglas del sellado, no afirma que esté activo. Los cambios administrativos son transacciones públicas en Base.

Salir sin la web elimina la dependencia de esa interfaz, pero no la de la red Base, los precios, el código desplegado, las condiciones de la cuenta o la liquidez. Consulta [Seguridad y contratos](https://docs.botradix.com/es/security-contracts/), [Riesgos](https://docs.botradix.com/es/risks/) y los [Términos §22: salida independiente, pausas y emergencia](https://botradix.com/terms?lang=es#dex-salida), junto con las secciones 23–24 sobre administración y pagos diferidos.
