> ## Documentation Index
> Fetch the complete documentation index at: https://docs.relay.link/llms.txt
> Use this file to discover all available pages before exploring further.

# Withdrawing from Relay Vaults

> Withdraw your liquidity from Relay Vaults directly onchain, without the Relay UI

<Warning>
  Relay Vaults are being wound down. New deposits are no longer supported: do not deposit into the vaults. The contracts themselves still accept deposits, so anything sent to them must be withdrawn the same way as any other position.
</Warning>

Relay Vaults are [ERC4626](https://ethereum.org/en/developers/docs/standards/tokens/erc-4626/) contracts, so you can withdraw by calling the vault contract directly, up to the liquidity currently available (see [Limits](#limits)). You do not need the Relay UI, the Relay API, or any other Relay service, only a wallet and an RPC endpoint or block explorer.

The [withdrawal UI](https://relay.link/vaults) stays available until **December 31, 2026**. After that date, use the steps on this page.

## Vault addresses

Both vaults hold WETH and issue `WETH-REL` shares with 18 decimals.

| Chain | Chain ID | Vault | Asset (WETH) | Native gateway |
| - | - | - | - | - |
| Ethereum | `1` | `0x57b68c4ea221ee8da6eb14ebdfccee5177567771` | `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2` | `0xed8a2a23bf9d6818651527daaf3bf4ffeb53945f` |
| Arbitrum | `42161` | `0xc7273772b87860097373d91b3880fd4cc61fba2d` | `0x82af49447d8a07e3bd95bd0d56f35241523fbab1` | `0x67defe8d90c8cd013fd527669e76e0be420f1208` |

ABIs are published in the [`@relay-vaults/abis`](https://www.npmjs.com/package/@relay-vaults/abis) package (`RelayPool`, `RelayPoolNativeGateway`). See the [RelayPool](/references/protocol/vaults/contracts/RelayPool) and [RelayPoolNativeGateway](/references/protocol/vaults/contracts/RelayPoolNativeGateway) references for the full interfaces.

## Check your balance

Read these view functions on the vault contract, from a block explorer's **Read Contract** tab or any RPC client:

* **`balanceOf(you)`** — your share balance.
* **`convertToAssets(shares)`** — the WETH value of those shares.
* **`yieldPool()`** — the yield pool that holds the vault's liquid WETH.

Then call **`maxWithdraw(vault)`** on the yield pool address. This is the WETH the vault can pay out right now, across all LPs.

If `convertToAssets(balanceOf(you))` is at or below the yield pool's `maxWithdraw(vault)`, you can withdraw your whole position in one transaction. Otherwise, convert that WETH amount to shares by calling `convertToShares(amount)` on the **vault**, not the yield pool, and redeem slightly fewer shares than the result: the limit is shared by all LPs and can move before your transaction lands. The example below keeps a 0.1% margin. See [Limits](#limits).

If you have trouble withdrawing, reach out to [Relay support](/resources/support).

## Withdraw as WETH

Withdrawing as WETH takes one transaction on the vault and needs no approval.

1. Pick the shares to redeem: your `balanceOf(you)`, or the liquidity cap in shares from [Check your balance](#check-your-balance) if that is lower.
2. Call `redeem(shares, receiver, owner)` with `receiver` set to the address that should receive WETH, and `owner` set to your address.

To withdraw an exact WETH amount instead, call `withdraw(assets, receiver, owner)` with `assets` at or below both your position's value and the yield pool's `maxWithdraw(vault)`.

## Withdraw as native ETH

The `RelayPoolNativeGateway` redeems your shares, unwraps the WETH, and sends ETH to the receiver. It takes two transactions because the gateway redeems on your behalf and needs a share allowance.

1. Pick the shares to redeem: your `balanceOf(you)`, or the liquidity cap in shares from [Check your balance](#check-your-balance) if that is lower. On the **vault**, call `approve(gateway, shares)`.
2. On the **gateway**, call `redeem(vault, shares, receiver, minAssetsOut)`. Set `minAssetsOut` slightly below `previewRedeem(shares)` to protect against rounding.

The gateway also exposes `withdraw(vault, assets, receiver, maxSharesIn)` for an exact ETH amount. Approve at least `maxSharesIn` shares first.

## Example

The script below redeems as many of your shares as current liquidity allows, as WETH, using [viem](https://viem.sh). To withdraw on Arbitrum, import `arbitrum` from `viem/chains`, use it in place of `mainnet`, and set `VAULT` to the Arbitrum vault address.

```typescript theme={null}
import { createPublicClient, createWalletClient, http, parseAbi, formatEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'

const VAULT = '0x57b68c4ea221ee8da6eb14ebdfccee5177567771'
const abi = parseAbi([
  'function balanceOf(address) view returns (uint256)',
  'function yieldPool() view returns (address)',
  'function maxWithdraw(address) view returns (uint256)',
  'function convertToShares(uint256) view returns (uint256)',
  'function previewRedeem(uint256) view returns (uint256)',
  'function redeem(uint256 shares, address receiver, address owner) returns (uint256)',
])

// Never paste a funded private key into a file you might commit
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const publicClient = createPublicClient({ chain: mainnet, transport: http() })
const walletClient = createWalletClient({ account, chain: mainnet, transport: http() })

// 1. Read your shares and the vault's available liquidity
const balance = await publicClient.readContract({ address: VAULT, abi, functionName: 'balanceOf', args: [account.address] })
const yieldPool = await publicClient.readContract({ address: VAULT, abi, functionName: 'yieldPool' })
const liquid = await publicClient.readContract({ address: yieldPool, abi, functionName: 'maxWithdraw', args: [VAULT] })

// 2. Redeem your full balance, or only the shares current liquidity covers.
//    Keep a 0.1% margin: other LPs share the same liquidity and it can move before inclusion.
const liquidShares = await publicClient.readContract({ address: VAULT, abi, functionName: 'convertToShares', args: [liquid * 999n / 1000n] })
const shares = balance < liquidShares ? balance : liquidShares
if (shares === 0n) {
  throw new Error('Nothing to redeem right now. If you still hold shares, retry when liquidity returns.')
}
const assets = await publicClient.readContract({ address: VAULT, abi, functionName: 'previewRedeem', args: [shares] })
console.log(`Redeeming ${formatEther(shares)} shares for ~${formatEther(assets)} WETH`)

// 3. Redeem to your own address
const hash = await walletClient.writeContract({
  address: VAULT,
  abi,
  functionName: 'redeem',
  args: [shares, account.address, account.address],
})
await publicClient.waitForTransactionReceipt({ hash })
```

You can also use the `pool:withdraw` Hardhat task from the [relay-vaults repository](https://github.com/relayprotocol/relay-vaults/tree/main/smart-contracts). Set `DEPLOYER_PRIVATE_KEY` to the LP wallet's key and pass the vault address explicitly, for example `yarn run hardhat pool:withdraw --network ethereum --pool 0x57b68c4ea221ee8da6eb14ebdfccee5177567771`. When prompted, enter an amount at or below the yield pool's `maxWithdraw(vault)`: `all` redeems your entire balance and reverts while liquidity is short.

## Limits

* **Liquidity cap** — withdrawals are limited to the yield pool's `maxWithdraw(vault)`. Funds still outstanding in bridges cannot be withdrawn until they return to the vault, and high utilization in the underlying lending market (Aave) can also lower the limit temporarily. If liquidity is short, withdraw what is available and keep the remaining shares: they stay redeemable once liquidity returns. The limit is shared by all LPs, so if a withdrawal at the limit reverts with `ERC4626: withdraw more than max`, retry with a slightly smaller amount. If you cannot withdraw your full position, reach out to [Relay support](/resources/support).
* **No cooldown** — withdrawals take effect in the same transaction. There is no lock-up or withdrawal queue.
* **No pause** — the vault contracts have no pause function and no withdrawal allowlist. The vault owner can still move the vault's assets to a different yield pool with `updateYieldPool`; see [RelayPool](/references/protocol/vaults/contracts/RelayPool).
* **Gas** — you pay gas in ETH on the vault's chain (Ethereum or Arbitrum). The native ETH path costs two transactions.
* **Yield** — yield streams into the vault over a streaming period (currently 7 days), so `convertToAssets` can increase slightly between reads.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.