Skip to content

Withdrawing from opBNB, Optimism and Unichain

Venus is sunsetting opBNB, Optimism and Unichain. This guide explains how to close an existing position through the network’s block explorer when the Venus app no longer offers the relevant page. Your funds remain in the protocol.

Supplying and borrowing are paused. Market repayment and withdrawal remain enabled, subject to liquidity and account health. XVS Vault withdrawals and bridging have separate checks described below; the app’s XVS Bridge no longer offers these three networks.

Borrow interest keeps accruing and positions can still be liquidated, so repay first, then withdraw.

Positions on BNB Chain, Ethereum, Arbitrum, Base and ZKsync Era are separate deployments and are not affected.

  • Open the explorer for your network and connect the wallet that holds the position:
  • On each contract page, open the Contract tab. Use Read as Proxy / Write as Proxy for vTokens, the Comptroller and XVS Vault; use Read Contract / Write Contract for the NativeTokenGateway and XVS bridge. For an underlying token, use the verified read/write interface shown by the explorer. If the required functions are unavailable, stop and ask for help — do not transact against an implementation address.
  • Token function arguments use base units. Check decimals() on the token: 1 USDC with 6 decimals is 1000000. The explorer’s native-value field labelled payableAmount (OPBNB) or payableAmount (ether) uses whole BNB/ETH, not wei: 0.01 means 0.01 BNB/ETH. Divide a wei amount by 10^18 before entering it there.
  • Keep some native BNB or ETH for gas.
  • Only use the addresses in the tables below. Token names and symbols can be imitated, and Venus will never ask for your seed phrase or private key.
MarketvTokenUnderlying token
vBTCB_Core0xED827b80Bd838192EA95002C01B5c6dA8354219aBTCB 0x7c6b91D9Be155A6Db01f749217d76fF02A7227F2
vETH_Core0x509e81eF638D489936FA85BC58F52Df01190d26CETH 0xE7798f023fC62146e8Aa1b36Da45fb70855a77Ea
vFDUSD_Core0x13B492B8A03d072Bab5C54AC91Dba5b830a50917FDUSD 0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb
vUSDT_Core0xb7a01Ba126830692238521a1aA7E7A7509410b8eUSDT 0x9e5AAC1Ba1a2e6aEd6b32689DFcF62A509Ca96f3
vWBNB_Core0x53d11cB8A0e5320Cd7229C3acc80d1A0707F2672WBNB 0x4200000000000000000000000000000000000006
MarketvTokenUnderlying token
vOP_Core0x6b846E3418455804C1920fA4CC7a31A51C659A2DOP 0x4200000000000000000000000000000000000042
vUSDC_Core0x1C9406ee95B7af55F005996947b19F91B6D55b15USDC 0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85
vUSDT_Core0x37ac9731B0B02df54975cd0c7240e0977a051721USDT 0x94b008aA00579c1307B0EF2c499aD98a8ce58e58
vWBTC_Core0x9EfdCfC2373f81D3DF24647B1c46e15268884c46WBTC 0x68f180fcCe6836688e9084f035309E29Bf0A2095
vWETH_Core0x66d5AE25731Ce99D46770745385e662C8e0B4025WETH 0x4200000000000000000000000000000000000006
MarketvTokenUnderlying token
vUNI_Core0x67716D6Bf76170Af816F5735e14c4d44D0B05eD2UNI 0x8f187aA05619a017077f5308904739877ce9eA21
vUSDC_Core0xB953f92B9f759d97d2F2Dec10A8A3cf75fcE3A95USDC 0x078D782b760474a361dDA0AF3839290b0EF57AD6
vUSD₮0_Core0xDa7Ce7Ba016d266645712e2e4Ebc6cC75eA8E4CDUSD₮0 0x9151434b16b9763660705744891fA906F660EcC5
vWBTC_Core0x68e2A6F7257FAc2F5a557b9E83E1fE6D5B408CE5WBTC 0x0555E30da8f98308EdB960aa94C0Db47230d2B9c
vWETH_Core0xc219BC179C7cDb37eACB03f993f9fDc2495e3374WETH 0x4200000000000000000000000000000000000006
vweETH_Core0x0170398083eb0D0387709523baFCA6426146C218weETH 0x7DCC39B4d1C53CB31e1aBc0e358b43987FEF80f7
vwstETH_Core0xbEC19Bef402C697a7be315d3e59E5F65b89Fa1BBwstETH 0xc02fE7317D4eb8753a02c35fe019786854A92001

Open each vToken for your network and use Read as Proxy:

  • balanceOf(<your address>) — the vTokens you hold. A non-zero value means you have a supplied position.
  • borrowBalanceStored(<your address>) — what you owe, in the underlying token. Your current debt can be higher because of interest accrued since this number was last updated.

A borrow can exist even when balanceOf is zero, so check every market in the table rather than only the tokens visible in your wallet.

Skip to Step 3 if borrowBalanceStored is zero in every market. Otherwise, for each market with debt:

  1. Open the underlying token from the table and call approve(spender, amount). spender is the vToken address, and amount should be slightly above your debt so it still covers the interest accrued by the time the next transaction lands.
  2. Open the vToken → Write as Proxy → repayBorrow(repayAmount). To repay in full, enter 115792089237316195423570985008687907853269984665640564039457584007913129639935. The contract takes only what you actually owe.

If you owe WBNB or WETH and hold native BNB or ETH: open your network’s NativeTokenGateway → Write Contract → wrapAndRepay(), and enter the amount in whole BNB/ETH in the payableAmount (OPBNB) / payableAmount (ether) field. Send enough to cover accrued interest, keeping gas separate. It wraps your native token, repays the debt and refunds any excess.

Anyone can repay on your behalf with repayBorrowBehalf(borrower, repayAmount) after approving the vToken from their own wallet.

Afterwards, re-check borrowBalanceStored(<your address>) — it must be 0. Then revoke the leftover allowance on the underlying token with approve(<vToken address>, 0).

For each market where balanceOf is non-zero, open the vToken → Write as Proxy:

  • redeem(redeemTokens) — enter the full value returned by balanceOf(<your address>) to withdraw everything. Use this for a full exit.
  • redeemUnderlying(redeemAmount) — a partial withdrawal, in the underlying token’s base units. Rounding means it will not cleanly empty the position.

Withdrawing from a WBNB or WETH market gives you the wrapped token. To receive native BNB or ETH instead, use the NativeTokenGateway:

  1. Comptroller → Write as Proxy → updateDelegate(<gateway address>, true).
  2. Gateway → Write Contract → redeemAndUnwrap(redeemTokens) for a full exit, or redeemUnderlyingAndUnwrap(redeemAmount) for part of it.
  3. Comptroller → updateDelegate(<gateway address>, false) to revoke the permission.

Confirm that balanceOf(<your address>) is back to 0 and that the tokens reached your wallet.

opBNB and Optimism have no Core Pool rewards. On Unichain no new rewards accrue, but anything already earned is still claimable.

Read as Proxy → rewardTokenAccrued(<your address>) shows what has been recorded so far. Write as Proxy → claimRewardToken(holder) with your address claims it. No approval is needed, and claiming is independent of repaying and withdrawing.

XVS staked in the XVS Vault is separate from your market positions. There is a 7-day lock between requesting a withdrawal and receiving the tokens. Before submitting either withdrawal transaction, read vaultPaused(); if it is true, withdrawals are blocked until governance unpauses the vault. On October 29, 2026 the opBNB vault was paused; Optimism and Unichain were unpaused. Recheck before acting.

NetworkXVS Vault proxyXVS token
opBNB0x7dc969122450749A8B0777c0e324522d677379880x3E2e61F1c075881F3fB8dd568043d8c221fd5c61
Optimism0x133120607C018c949E91AE333785519F6d947e010x4a971e87ad1F61f7f3081645f52a99277AE917cF
Unichain0x5ECa0FBBc5e7bf49dbFb1953a92784F8e4248eF60x81908BBaad3f6fC74093540Ab2E9B749BB62aA0d

Each network has one pool, so every call below takes that network’s XVS address as the reward token and 0 as the pool id.

  1. Check your stake — Read as Proxy → getUserInfo(<XVS address>, 0, <your address>).
  2. Request the withdrawal — Write as Proxy → requestWithdrawal(<XVS address>, 0, <amount>), with the amount in XVS base units (18 decimals). Request no more than amount − pendingWithdrawals from getUserInfo; tokens already requested do not need another request. This also pays out pending rewards and starts the 7-day lock.
  3. After 7 days, check eligibility — getEligibleWithdrawalAmount(<XVS address>, 0, <your address>).
  4. Execute — executeWithdrawal(<XVS address>, 0) sends the unlocked XVS back to your wallet.

If the vault cannot pay a reward in full it records the remainder, which stays claimable and can be read with pendingRewardTransfers(<XVS address>, <your address>). Unstaking itself is not affected.

The app no longer lists these source networks. Their non-upgradeable XVS bridge contracts can be called through Read Contract / Write Contract. This is an advanced step: use a wallet address you control on both networks and verify every field before signing.

Source networkXVS bridgeLayerZero source ID
opBNB0x100D331C1B5Dcd41eACB1eCeD0e83DCEbf3498B2202
Optimism0xbBe46bAec851355c3FC4856914c47eB6Cea0B8B4111
Unichain0x9c95f8aa28fFEB7ECdC0c407B9F632419c5daAF8320

The destination is 102, BNB Chain’s LayerZero ID, not its EVM chain ID 56. The BNB receiving bridge is 0xf8F46791E3dB29a029Ec6c9d946226f3c613e854.

  1. Check availability first. On the source bridge, paused() must be false, token() must match the XVS token above, and the first of the seven values returned by isEligibleToSend(<your address>, 102, <amount>) must be true. If the read reverts or that first value is false, stop. On October 29, 2026 the opBNB eligibility read reverted with invalid resilient oracle price even though its bridge was unpaused; a fee quote alone does not establish that a transfer can succeed.
  2. Check the receiving side. On the BNB bridge, paused() must be false. Read chainIdToMaxSingleReceiveTransactionLimit(<source ID>), chainIdToMaxDailyReceiveLimit(<source ID>), chainIdToLast24HourReceived(<source ID>) and chainIdToLast24HourReceiveWindowStart(<source ID>). These limits are in USD with 18 decimals, shared by all users of the route, and can be tighter than the source limits. The receiving side uses its own XVS price: read oracle() and token() on the BNB bridge, then getPrice(<token address>) on that oracle. For XVS, the transfer value in the limits’ units is amount × price / 10^18. Stop if the price read fails, and leave headroom for price changes and other transfers. A 24-hour window resets on the next transfer after it expires. If either side lacks capacity, wait; splitting a transfer does not bypass the daily cap. Exceeding a receive limit can leave a message awaiting recovery after the source transaction has succeeded.
  3. Prepare the fields. amount is in XVS base units (18 decimals); bridge precision is 8 decimals, so use a multiple of 10000000000 base units. Smaller dust remains on the source chain. recipient is your 20-byte address left-padded with 12 zero bytes: 0x000000000000000000000000 followed by your address without its 0x.
  4. Quote the fee. Read minDstGasLookup(102, 0). At the October 29 check it was 300000 on all three bridges, giving version-1 adapter parameters 0x000100000000000000000000000000000000000000000000000000000000000493e0. Use this value only while that minimum is unchanged; if it changes, obtain updated parameters before continuing. Call estimateSendFee(102, <recipient>, <amount>, false, <adapter params>); the first result is the native fee in wei.
  5. Send from the wallet holding the XVS. Call sendFrom with the fields below. These destination-chain bridges burn the caller’s XVS directly, so no ERC-20 approval is needed. Do not transfer XVS to the bridge address.
sendFrom fieldValue
_fromYour connected wallet address
_dstChainId102
_toAddressYour padded 32-byte recipient
_amountXVS base units
_callParams.refundAddressYour connected wallet address
_callParams.zroPaymentAddress0x0000000000000000000000000000000000000000
_callParams.adapterParamsThe adapter parameters used for the quote

_callParams is one tuple containing the last three fields, not three additional top-level arguments. For a single _callParams (tuple) text box, paste the following JSON array, replacing <your address> with your connected wallet address. This example uses the 300000-gas adapter parameters verified in step 4; if those change, replace the third value with the parameters used for your new quote.

["<your address>","0x0000000000000000000000000000000000000000","0x000100000000000000000000000000000000000000000000000000000000000493e0"]

If the explorer instead expands the tuple into three fields, enter each value separately in the order shown above. If the input is rejected, stop and ask for help.

Set payableAmount (OPBNB) / payableAmount (ether) in whole BNB/ETH: divide the fresh wei fee quote by 10^18 and add a small buffer. For example, a quote of 1000000000000000 wei is 0.001 BNB/ETH before the buffer. Excess is refunded. Keep additional native currency for transaction gas.

Delivery is asynchronous. Track the source transaction on LayerZero Scan and check your XVS balance on BNB Chain. If delivery is delayed or fails, retain the source transaction hash and seek help; do not send the same amount again, because the original message can still execute.

Do not keep resubmitting. Open your network’s Comptroller under Read as Proxy and check:

  • isMarketListed(<vToken address>) returns true.
  • actionPaused(<vToken address>, 3) returns false — repayment is allowed.
  • actionPaused(<vToken address>, 1) returns false — withdrawal is allowed.
  • getAccountLiquidity(<your address>) returns no shortfall. If it does, repay before trying to withdraw again.

Also confirm that you hold enough of the underlying token and that your allowance covers the repayment.

If it still fails, ask for help on the Venus community forum with the network, your wallet address, the contract address and the transaction hash or revert data. Never share your seed phrase or private key.