All withdrawals from RYUSD on Arbitrum (0x392B1E6905bb8449d26af701Cdea6Ff47bF6e5A8) are being routed to the withdrawal queue because totalAssetsWithdrawable reports only $3.97 USDC out of $29,303 total assets (0.014% liquid). The ~$27,300 in Aave V3 aToken positions are not counted as withdrawable due to two compounding configuration issues in the Aave V3 aToken Adaptor.
| Metric | Value |
|---|---|
| Total Assets | $29,303 USDC |
| Total Assets Withdrawable | $3.97 USDC |
| Aave aUSDC (pos 10, holding) | $14,174 |
| Aave aUSDC.e (pos 11) | $2,512 |
| Aave aDAI (pos 12) | $8,166 |
| Aave aUSDT (pos 13) | $2,451 |
| Raw USDC balance (pos 1) | $3.97 |
| Raw DAI balance (pos 3) | $627 |
| Raw USDT balance (pos 4) | $1,365 |
| Aave Debt (variableDebtArbUSDCn) | $1.16 |
| Aave Health Factor | 22,346x |
| Aave EMode | 1 (stablecoin) |
The Aave V3 aToken Adaptor V1.2 (0x4AEC526182F64d4c75DaDf43c8A86a69F91ef5AE) has two independent checks in its withdrawableFrom() function that each independently force a return of 0:
From AaveV3ATokenAdaptor.sol line 172-175:
// If Cellar has no Aave debt, then return the cellars balance of the aToken.
if (totalDebtBase == 0) return ERC20(address(token)).balanceOf(msg.sender);
// Cellar has Aave debt, so if cellar is entered into a non zero emode, return 0.
if (pool.getUserEMode(msg.sender) != 0) return 0;The cellar has $1.16 of USDC variable debt AND is in EMode category 1. This causes an immediate return of 0 for ALL four Aave positions (~$27,300 blocked).
All four Aave aToken positions (10, 11, 12, 13) have configurationData = 0x00. The adaptor interprets this as "the strategist does not want users to withdraw from this position":
From AaveV3ATokenAdaptor.sol lines 178-181:
uint256 minHealthFactor = abi.decode(configData, (uint256));
// Check if minimum health factor is set.
// If not the strategist does not want users to withdraw from this position.
if (minHealthFactor == 0) return 0;Even if Issue 1 were resolved, this would still block all Aave withdrawals.
The ERC20 Adaptor (0x2fD86717d9Bba566Fe637Ac6D3C69369CE998555) also uses configurationData to gate withdrawals. From the trace:
- Position 1 (USDC):
configurationData = 0x01→ withdrawable (returns $3.97) - Position 2 (USDC.e):
configurationData = 0x00→ returns 0 - Position 3 (DAI):
configurationData = 0x00→ returns 0 (despite $627 balance) - Position 4 (USDT):
configurationData = 0x00→ returns 0 (despite $1,365 balance)
Only USDC (position 1) has its configurationData set to allow withdrawals.
- User submits
redeem()on the cellar contract - The cellar's
_withdrawInOrder()iterates credit positions, calling_withdrawableFrom()on each - Every position except USDC returns 0, so the cellar can only service ~$3.97 of redemptions
- For any meaningful withdrawal amount,
redeem()reverts withCellar__IncompleteWithdraw - The frontend catches this, checks
totalAssetsWithdrawable < redeemAmount, and routes to the withdrawal queue modal
- Repay the $1.16 USDC variable debt via strategist
callOnAdaptor - Call
changeEMode(0)to exit stablecoin EMode - Set
configurationDatato a non-zerominimumHealthFactor(e.g.,abi.encode(1.05e18)) on at least one Aave position
This removes the EMode block. With no debt, withdrawableFrom returns the full aToken balance regardless of configurationData.
- Repay the $1.16 debt
- Keep EMode but ensure
totalDebtBase == 0so the adaptor takes the early-return path at line 172 (returns full balance when no debt)
- Set
configurationDatato non-zerominimumHealthFactoron exactly ONE Aave position (the adaptor docs specify only one should have it set to avoid blocking) - Optionally also set
configurationData = 0x01on DAI and USDT ERC20 positions to make those withdrawable too
| Contract | Address | Chain |
|---|---|---|
| RYUSD Cellar | 0x392B1E6905bb8449d26af701Cdea6Ff47bF6e5A8 |
Arbitrum |
| Registry | 0xB7f57c1a22E9cBac58016cd01749433f390091BB |
Arbitrum |
| Withdraw Queue | 0x516AD60801b62fCABCCDA7be178e4478D4018071 |
Arbitrum |
| ERC20 Adaptor | 0x2fD86717d9Bba566Fe637Ac6D3C69369CE998555 |
Arbitrum |
| Aave V3 aToken Adaptor | 0x4AEC526182F64d4c75DaDf43c8A86a69F91ef5AE |
Arbitrum |
| Aave V3 Debt Adaptor | 0xDC238246E8Cd154170D27Ea452Cb6Bb0216d2443 |
Arbitrum |
| UniV3 Adaptor | 0x92c3363D3c7a313C3f1A929294aAd981Bf8a283B |
Arbitrum |
| Aave V3 Pool | 0x794a61358D6845594F94dc1DB02A252b5b4814aD |
Arbitrum |
Analysis performed by tracing totalAssetsWithdrawable() via cast call --trace against the live Arbitrum state, then cross-referencing the verified Aave V3 aToken Adaptor source from Arbiscan.