Skip to main content

Self-Custodial Withdrawals (Escape Hatch)

Updated this week

Derive is a self-custodial exchange, meaning you always have custody of your assets. In the case of exchange failure (including failure or downtime of the trading interface, or off-chain matching engine), there is still a permissionless way to withdraw funds from Derive.

This guide is written assuming you onboarded via the trading interface (app.derive.xyz), and have deposited funds into a trading account (subaccount), which in turn is owned by your Smart Contract Wallet (SCW) deployed when your account was created on Derive’s rollup.

This guide is broken up into several steps.

  1. Fund your owner wallet with native ETH

  2. Withdraw subaccount from the Exchange’s Matching system

  3. Withdraw collaterals from subaccount

  4. Bridge funds from SCW to another chain

You can only withdraw collaterals, so ensure you have closed all open positions (perps/options), or wait until their expiry before proceeding.

If you have open perp positions and cannot access the exchange, withdraw the maximum available amount of collateral in step 3. This will likely trigger a liquidation / closure of your open perp position, which will allow you to withdraw more collateral.

1. Fund owner wallet with native ETH

Bridge a minimal amount (0.0005) of ETH from mainnet to Derive using the superbridge app. This is used for gas to execute transactions on Derive’s layer-2 rollup: https://superbridge.app/?fromChainId=1&toChainId=957

2. Withdraw SubAccounts from Derive Matching system

2.1 Get your SCW (Derive Wallet) address

Call: getAddress(<Owner address>, 0)

This will return your SCW (Derive wallet) address. Save this.

2.2 Get a list of your owned subaccounts

Easier Option:

Find the list of your owned subaccounts from the interface.

Harder Option:

Add your SCW to the following query and post it in your browser URL. This will return a list of subaccounts that your SCW has ever historically deposited to the matching contract.

https://explorer.derive.xyz/api
?module=logs
&action=getLogs
&fromBlock=0
&toBlock=latest
&address=0xeB8d770ec18DB98Db922E9D83260A585b9F0DeAD
&topic0=0x043a568d47b1a65cdc989ff14c921411b62abf40132dc4b5e78675ba8d0bc9df
&topic2=0x000000000000000000000000<Your SCW address without 0x prefix>
&topic0_2_opr=and

Example response, you may see more than one row:

Under “topics” you will see your subaccountId in hexadecimal as the 2nd “topic”. E.g.

1c0f = 7183. See: Hexadecimal Converter.

2.3 Start your subaccount withdrawal

2.3.1 Get the calldata for the withdrawal

  • Select requestWithdrawAccount

  • Enter your subaccountId under accountId

  • Hit “Copy calldata”

  • Save this value somewhere (Should look something like “0x0297d9210000000000000000000000000000000000000000000000000000000000002b67” ) - this will be used in step 2.3.2

  • Also select completeWithdrawAccount, enter subaccountId and “Copy calldata”, and save this for step 2.3.3

  • Repeat for every subaccount, save each calldata

2.3.2 Execute initiate withdrawal

Navigate to your SCW page on the explorer. Then go to Contract → Read/Write proxy → Write → execute

Connect your owner wallet

Call execute with:

dest: 0xeB8d770ec18DB98Db922E9D83260A585b9F0DeAD
value: 0
func: <requestWithdrawAccount Calldata>

Repeat for every subaccount

This removes your subaccount from the exchange and starts a 30min cooldown before the next step can proceed

2.3.3 Complete the subaccount withdrawal

After waiting 30min, follow the same steps as 2.3.2, but use the completeWithdrawAccount calldata. This will move your subaccounts from the matching system to be held by your SCW.

dest: 0xeB8d770ec18DB98Db922E9D83260A585b9F0DeAD
value: 0
func: <completeWithdrawAccount Calldata>

3. Withdraw collaterals from subaccount

This step will be tricky if you hold multiple different collateral assets but still have perp or short option positions. If you have open positions, it may be easiest to just borrow the max amount of USDC to withdraw, and then return later when you get liquidated to withdraw the remainder.

  • 3.1a - no short positions open

  • 3.1b - withdrawing max USDC from an account with open perps or short options

After this you should have one or more assets held by the SCW, withdrawn from the protocol, that can now be bridged

3.1a Get Available collaterals

3.1b Withdraw maximum possible USDC

This step can fail as margin requirements change, you may need to reduce the amount or call getMargin again

4. Bridge from derive

Withdrawing from derive can be done via a “wrapper” that converts some of the tokens to ETH to pay the bridging fee.

You will have to execute 2 functions for each token. Firstly approve and then the bridge.

For each token in step 3 (Find these on your SCW page under the “Tokens” drop down):

    • Go to the ERC20 page on the explorer

    • Ensure there is enough liquidity on the chain you want to withdraw to

    • Copy the “controller” and “connector Out”

  • Navigate to the ERC20 page on the explorer → Contract → Read/Write Contract → Write → “approve”

  • Enter:

  • Then “Copy calldata” → Navigate to your SCW address → execute:

    • dest: Token address

    • value: 0

    • calldata: <approve calldata>

  • For function “withdrawToChain” enter:

    • token: <the ERC20 address>

    • amount: <your balance>

    • recipient: <your owner address>

    • socketController: <the controller address from the “pool-view” link above>

    • connector: <the connector address from specific chain you want to withdraw to from the “pool-view” link above>

    • gasLimit: 100000

  • Then “Copy calldata” → Navigate to your SCW address → execute:

    • dest: Token address

    • value: 0

    • calldata: <withdrawToChain calldata>

Did this answer your question?