BotradixSalida provides functions to request a DEX exit, execute your own exit, withdraw available funds and cancel orders without using the BotRadix website. Your account functions use the wallet sending the transaction as the owner; they do not let you choose another recipient. The exit contract does not hold your collateral: it communicates with the router, and payments go from CrossMargin to your wallet.
Caution
Use only the address 0x43473B3684ccB5d9d57D119f2A6bc7B9B1f5EEe5, on Base. Type it yourself on basescan.org or compare it character by character; do not follow addresses or links received in messages, ads or social networks, even if they claim to come from BotRadix. In the Contract tab, BaseScan must show the code at that address as verified; if it does not, do not continue. This exit never needs your recovery phrase or private key: do not share them with anyone.
Important
This guide describes the mechanism, not the state of an account or the router configuration at this moment. The periods and limits are those of the router Salida was deployed for; check its read functions before acting. There is no guaranteed deadline for closing positions or receiving payment.
Step by step#
A summary of the full exit. Each step is detailed in the sections below; the names are those of BotradixSalida's verified code (English / Spanish, they do the same).
- Open Salida on BaseScan. On basescan.org, type the address
0x43473B3684ccB5d9d57D119f2A6bc7B9B1f5EEe5yourself and check that the Contract tab shows the code as verified. - Read your status. In Contract → Read Contract, expand
status(orestado). In theaccount(orcuenta) field enter your wallet address and click Query. Check thatforwarderis the Salida address and noterequestedAt,openPositionsandopenOrders. - Connect your wallet. In Contract → Write Contract, click Connect to Web3. Use the wallet that owns the account, on Base (chain ID 8453), with some ETH on Base for gas.
- Request the exit. In Write Contract,
exitDex(orsalirDelDex), with no parameters: click Write and confirm in your wallet. Your account stops accepting new positions. If you had no positions or orders, the exit can complete in that same transaction. - Cancel your orders, if
openOrdersis above 0.cancelOrders(orcancelarOrdenes); in theidsfield enter the list of your order IDs in brackets, for example[123,456](how to find them: section 2). - Wait for the period. The BotRadix keeper may close your positions earlier. Otherwise, from
selfExecutableAt, 24 hours after the request, you can execute the exit yourself. With a confirmed emergency (emergencyAtother than 0) there is no wait, but only positions in fixed markets close. - Execute your exit.
executeMyExit(orejecutarMiSalida): the block without fields attempts to close up to 8 positions; the one withmaxPositions(ormaxPosiciones) accepts 1 to 16. Repeat whileopenPositionsis above 0 and valid prices are available. Before confirming, raise the gas limit in your wallet to 8,000,000 by hand (16,000,000 if you usemaxPositions16): with the limit the wallet computes, the transaction can succeed without closing any position, because the contract skips the closes it has no gas left for. You only pay for the gas used. - Withdraw everything. With
openPositionsat 0 and no orders,withdrawAll(orretirarTodo), with no parameters. Check the USDC and BAQ transfers to your wallet in the transaction and readstatusagain. If withdrawals are paused, repeat after the pause. - If something reverts or makes no progress, do not repeat the same call: read
statusand find your case in If it reverts or makes no progress. If you cannot find the cause, keep the hash and write to support@botradix.com.
Want to cancel the request instead of exiting? Use cancelExit (or cancelarSalida), with no parameters. None of this guarantees a deadline for closing or payment: it depends on prices, orders, debts, pauses and liquidity (Terms, section 22).
Before starting#
- Open BotradixSalida on basescan.org. Check the full address,
0x43473B3684ccB5d9d57D119f2A6bc7B9B1f5EEe5, and that the Contract tab shows the code as verified. - Before connecting or sending anything, open Contract → Read Contract. Expand
status(aliasestado), enter your wallet address inaccount(orcuenta) and click Query. In the returned tuple,forwardermust be the Salida address above. If it is zero, different, or the read fails, do not continue through this Salida: check the address and router configuration. Also readROUTER()and compare it with the official addresses. - Set your wallet to Base mainnet, chain ID 8453, with ETH on Base for gas. Use the wallet that owns the positions and collateral; your account functions act on the signer.
- At the same Salida address, open Write Contract, click Connect to Web3, choose your wallet and check the connected account and network. Connecting does not execute an exit.
- For each action below, expand the block with that name, fill in its parameters, click Write and confirm the transaction in your wallet. Open its hash, wait for confirmation and query
status(yourAddress)again in Read Contract. Recheckforwarderbefore further actions; an earlier read does not prevent later router changes.
Reads do not change state or require a transaction. Dates are Unix timestamps in seconds, not countdowns or local times.
Field in status(yourAddress) | How to interpret it |
|---|---|
requestedAt | Zero: no pending request. A nonzero value: the request timestamp. |
selfExecutableAt | The ordinary time from which you can execute your exit; a prior request is required. A confirmed emergency skips the wait even if this field still shows the ordinary time. |
openPositions, openOrders | Counts of remaining positions and orders. These are not ID lists. |
withdrawalsPaused, withdrawalsPausedUntil | Whether withdrawals are paused and when the pause ends. |
emergencyChallengeAt, emergencyAt | The first indicates a challenge; only emergencyAt != 0 indicates a confirmed emergency. |
emergencyPending, unsettledAccounts, distributionOpenedAt | Your account's pending settlement, the global count of unsettled accounts, and the distribution opening time (0: not open yet). |
emergencyClaimUSDC, deferredUSDC | Emergency claim and deferred payment; these are not free funds already received. |
Your account functions#
The functions have Spanish and English aliases that follow the same path.
| Action | Spanish name | English name |
|---|---|---|
| Request an exit | salirDelDex() | exitDex() |
| Execute your exit | ejecutarMiSalida() or ejecutarMiSalida(uint256) | executeMyExit() or executeMyExit(uint256) |
| Withdraw what is available | retirarTodo() | withdrawAll() |
| Cancel your orders | cancelarOrdenes(uint256[]) | cancelOrders(uint256[]) |
| Cancel the exit request | cancelarSalida() | cancelExit() |
The return values described below are contract results. A receipt marked Success does not usually display those values or prove that everything was withdrawn: check the status reads and the transfers to your wallet. SalidaUsada identifies the action sent, not completion of the process.
1. Request an exit#
In Write Contract, use exitDex() or salirDelDex(), with no parameters. It records the request and locks new positions for the account. If there are no open positions or orders, it attempts to complete withdrawal in that transaction, subject to the other checks. Repeating a pending request keeps its original timestamp; it does not restart the 24-hour wait.
It returns 1 if the exit completed in that transaction and 0 if it remains pending. Check requestedAt, selfExecutableAt, openPositions and openOrders. A 0 is not itself a failure: continue with pending orders and positions. A 1 does not guarantee payment of unbacked deferred amounts or unpaid claims.
The keeper can cancel orders and close positions using valid prices observed at or after the request. Execution within seconds is not promised. Price, funding and liquidation risk remain during the wait.
2. Cancel pending orders#
The IDs this function takes are those of the router's DexOrderCreated events, the router being the address returned by ROUTER(). On BaseScan, open that address and look in its Events for the DexOrderCreated events of your wallet: in that event, the first indexed value is the order ID, the second the owner wallet and the third the pairId. Copy only the order IDs, never the pairId. Return to Salida's Write Contract, expand cancelOrders or cancelarOrdenes and enter the list in ids, for example [123,456], replacing those numbers with your actual IDs.
It needs no prices and returns no value. Check that openOrders goes down. An order of yours that was already executed or cancelled is ignored; an order of another wallet, or an ID that is not yours, reverts the whole transaction.
Cancelling orders does not by itself close all positions. The self-execution function does not enumerate and automatically cancel all your entry orders: check openOrders and cancel any remaining ones so the exit can complete and their reserves can be released.
3. Execute your exit after 24 hours#
If the request remains pending, read status(yourAddress) and use executeMyExit or ejecutarMiSalida in Write Contract once selfExecutableAt is reached, 24 hours after the request. A confirmed emergency (emergencyAt != 0) removes that wait, but you must still request the exit with exitDex() first; opening a challenge is not enough.
BaseScan shows two versions with the same name: the block without input fields attempts to close up to 8 positions; the one with maxPositions (or maxPosiciones) lets you enter a batch size of 1 to 16. Available gas can reduce the amount processed. Multiple calls may be needed.
For an unfrozen market, both price legs must have an open session, have been observed at or after the request, be at most 10 minutes old, not be dated in the future and meet their confidence limits. A frozen market uses its fixed price. During an emergency, only positions in frozen markets can close. Positions without a usable price are skipped and remain open.
It returns (closed, remaining, finished): positions closed in this call, positions still open, and 1 if the exit completed (0 otherwise). Check status(yourAddress) after each batch. Repeat while positions remain and price conditions are met; if there is no progress, check the causes below. If orders, debts, an effective pause or pending emergency settlement remain, closing the last position may not complete withdrawal. During an emergency, finish with withdrawAll(), even if no positions remain. Reaching 24 hours enables a call; it does not trigger a transaction or guarantee available prices or funds.
4. Withdraw what is available#
Once openPositions is 0, cancel any remaining orders first and use withdrawAll() or retirarTodo() in Write Contract, with no parameters. It needs no prices or prior exit request. With open positions it reverts with DexPositionsOpen. It attempts to settle and collect applicable emergency payments, claim deferred payments that now have backing, and withdraw available free USDC and BAQ to the owner wallet.
It returns no value: check the USDC and BAQ transfers to your wallet in that transaction and the new state. A successful transaction can reflect a partial withdrawal or a zero amount; it does not by itself prove that nothing remains pending. During a pause the router emits DexExitAwaitingWithdrawal and stops withdrawal without necessarily reverting the transaction. Repeat once the pause ends.
Order reserves are not withdrawn; cross debt or pending settlement can also prevent completion. Calling this function does not turn an unbacked deferred payment into withdrawable balance. During an emergency, distribution requires no open position anywhere in the DEX and every account to be settled. If distributionOpenedAt is still 0 or a claim remains, call again once those conditions are met; payment may be partial, with a deferred remainder.
Cancel the request#
To cancel a pending request, use cancelExit() or cancelarSalida(), with no parameters, in Write Contract. It returns no value: check that requestedAt is back to 0. It removes that request's lock on new positions; it does not remove an emergency or other protocol restrictions. It does not restore closed positions or cancelled orders, or reverse confirmed transactions. A later exit request starts a new ordinary wait.
If it reverts or makes no progress#
If BaseScan or the wallet warns that the call would revert, check the cause before signing. A transaction confirmed as failed keeps no changes from that call but consumes gas. Do not repeat it without addressing the condition that prevents it. Salida forwards the call to the router: if the router's code does not appear as verified on BaseScan, the error reason may show as a hexadecimal code instead of a name. The status and market reads tell you which situation you are in.
| Situation | What to do |
|---|---|
executeMyExit() or cancelExit() would fail and requestedAt is 0 | There is no pending request. If you want to exit and positions remain, request the exit with exitDex() first. If the exit already completed, you do not need to cancel it. |
executeMyExit() would fail before selfExecutableAt | Wait until that time, unless an emergency is confirmed (emergencyAt != 0). |
withdrawAll() reverts with DexPositionsOpen | Positions remain: request an exit if needed, close them with executeMyExit() when eligible and read the state again. |
| Any of your account functions would fail with no other visible cause | Check that forwarder is this Salida address, the connected account and, for cancelOrders, that every ID belongs to an order of your wallet. Adding gas does not fix it. |
DexExitAwaitingWithdrawal or withdrawalsPaused == true | Withdrawal is waiting, not necessarily reverting. Read withdrawalsPausedUntil and retry withdrawal after the pause. |
withdrawAll() succeeds but not everything arrives | A pause, orders with reserved funds, cross debt, a pending settlement or an unbacked deferred payment may remain. Check openOrders, deferredUSDC, emergencyPending and the pause; if the reads do not explain it, report the hash to support. |
No positions closed, or finished == 0 | There may be no valid price, too little gas for another position, orders, debt or pending settlement. Read the counters and market state; during an emergency the market may still need fixing. A successful call does not force those conditions to be met. |
| Insufficient gas | Check ETH on Base and the estimate. For self-execution, try a smaller batch, such as maxPositions = 1; split order lists into smaller batches. |
| A community function would fail | The challenge or emergency is not in the required state, or its period has not elapsed. Read status (emergencyChallengeAt, emergencyAt) and market(pairId) (challengeOpenedAt, settleAfter, frozenKind) again before retrying. |
confirmEmergency would fail with a market list | Read the complete, ascending list from marketsWithPositions() again; do not invent IDs or use a shortened list. |
settleMarket would fail although settleAfter has passed | There may be no observation to fix the price with: reaching the deadline does not create a price. Check market(pairId) and report the problem. |
If you cannot identify the cause, keep the hash and visible error and contact support@botradix.com. Waiting or repeating the same call is not guaranteed to complete it.
Pauses, missing prices and emergency#
Under the rules of the router Salida was deployed for, each withdrawal pause expires after 72 hours, requires 24 hours without a pause before the next one and does not apply during a confirmed emergency. Other payment constraints can remain after expiry.
The community functions are also in Salida's Write Contract. Anyone can pay gas to call them when their conditions are met. Results and payments belong to each account owner; submitting the transaction gives no right to anyone else's funds. They do not activate automatically when your request reaches 24 hours.
| English function / Spanish alias | Conditions and result |
|---|---|
openEmergencyChallenge() / abrirDesafioEmergencia() | Opens the public 72-hour challenge if positions exist in the DEX and there is no emergency yet. Read emergencyChallengeAt. |
confirmEmergency(markets) / confirmarEmergencia(mercados) | After 72 hours, get the complete, ascending bytes32[] list from marketsWithPositions() / mercadosConPosiciones() in Read Contract and paste it into markets (or mercados) in Write Contract. Returns true if it activates the emergency. An observation of USDC or a market with positions since the challenge opened, even with a closed session, clears the challenge and returns false. Check emergencyAt. |
fixEmergencyMarkets(markets) / fijarMercadosEmergencia(mercados) | During an emergency, fixes the remaining markets with positions; returns how many it fixed. Use the market IDs from the read above and repeat if gas left work pending. Price and funding are fixed at the emergency instant even if fixing finishes later. |
challengeMarket(pairId) / desafiarMercado(pairId) | Opens the 3-day challenge for a market with positions that is not frozen. pairId is the pair's number, not a bytes32 market ID. Read market(pairId) / mercado(pairId), including challengeOpenedAt and settleAfter. |
settleMarket(pairId) / liquidarMercado(pairId) | From settleAfter, with no observations since the challenge, freezes the market at its last observed price and fixes its funding. Returns true when it freezes the market; a later observation clears the challenge and returns false. Check frozenKind and frozenPriceX18 in market. |
closeFrozen(positions, orders) / cerrarCongeladas(posiciones, ordenes) | Takes two ID lists, closes positions in frozen markets and cancels their orders; during an emergency it can cancel any order. Returns (positions closed, orders cancelled). Batches may be needed; results stay in the owners' accounts. |
settleAccounts(accounts) / liquidarCuentas(cuentas) | During an emergency, settles the listed accounts with no positions or orders; returns how many it settled. Net gain: a claim. Net loss: cash, then committed BAQ backing. Accounts not yet eligible are skipped. |
payEmergencyClaims(accounts) / cobrarReparto(cuentas) | With no positions anywhere in the DEX and all accounts settled, opens distribution and credits each owner's share to their CrossMargin account. Returns the total amount paid, not the number of accounts; 0 can mean distribution cannot open yet. Each owner finishes with withdrawAll() to withdraw to their wallet. |
A confirmed emergency is final for this DEX and stops trading; the administrator can declare it without the public challenge. Distribution applies the same fixed percentage to everyone: the smaller of 100% and available liquidity (vault, insurance and emergency reserves, excluding reserves for earlier deferred payments) divided by claims, subject to rounding. Any shortfall remains deferred, without a guaranteed payment deadline. Challenges, batches and distribution require transactions; no clock executes them automatically.
What this exit depends on#
BotradixSalida has no administrator or upgrade mechanism of its own, but depends on the router and CrossMargin. The router must recognize it as the forwarder. While configuration is open, administration can replace or disconnect it using setDexExitForwarder(address(0)) and can change the logic processing exits without mandatory advance notice. A return to an earlier router version can leave Salida unusable even if its address still exists. After the sealing provided for by this code, Salida can no longer be disconnected and router modules can only change through the advance-notice gate, with a committed minimum of at least 72 hours. This describes the sealing rules; it does not claim sealing is active. Administrative changes are public transactions on Base.
Leaving without the website removes dependence on that interface, but not on the Base network, prices, deployed code, account conditions or liquidity. See Security and contracts, Risks and Terms §22: independent exit, pauses and emergency, together with sections 23–24 on administration and deferred payments.