StabilityPool¶
Overview¶
StabilityPool
is a core contract of the RAAC protocol that acts as the first line of defence for the LendingPool during liquidations.
Users can deposit rToken (currently rcrvUSD
) into the pool and receive a 1 : 1 representation called deToken. These deposits are used to repay the debt of unhealthy borrowers that are liquidated through a dedicated strategy contract.
In return, depositors maintain exposure to the underlying rToken and can withdraw it at any time while the contract is not paused.
Token Mechanics & Yield Distribution
The StabilityPool maintains a 1:1 relationship between rToken and deToken:
- rToken is the yield-bearing token deposited by users
- deToken is the representation token minted 1:1 for deposits
- deToken increases in value as the underlying rToken accrues yield from the lending pool
- This ensures depositors earn the normal yield from the lending pool while maintaining their position in the StabilityPool
Staking deToken for Additional Yield
After receiving deToken from the StabilityPool, users can further stake their deToken in the Curve lending pool.
This provides exposure to Curve LP tokens, which can then be staked in the RAAC Gauge to earn protocol emissions and rental yield.
This layered staking approach allows depositors to maximize their yield by participating in both Curve and RAAC incentive programs.
Flow:
- Deposit rToken into StabilityPool → receive deToken (1:1)
- Stake deToken in Curve lending pool → receive Curve LP tokens
- Stake Curve LP tokens in RAAC Gauge → earn emissions & rental yield
This mechanism is optional and designed for users seeking additional yield opportunities beyond the base StabilityPool rewards.
Purpose¶
- Accept user deposits of rToken and issue deToken (1 : 1 peg)
- Provide liquidity that covers borrower debt during liquidations
- Delegate the actual liquidation logic to the liquidation module
- Maintain a list of managers allowed to trigger liquidations
- Route seized collateral to the RWA Vault and handle accounting via the Treasury contract
- Support flexible configuration of how collateral proceeds are split (mint, burn, swap, liquidity)
Manager-Only Liquidations & No Incentives
Only delegated managers (not the general public) are permitted to trigger liquidations in the StabilityPool.
There is no direct incentivization for performing liquidations—this is a deliberate design choice due to the large size and complexity of the underlying assets.
Liquidations are expected to be carried out timely by managers to ensure sufficient liquidity is available in the Curve LP to process liquidations efficiently.
Managers are responsible for monitoring the system and considering factors such as gas fees and current slippage before executing a liquidation.
This approach helps maintain protocol stability and avoids unnecessary or poorly-timed liquidations that could negatively impact the system or its users.
Withdrawal Timelock Mechanism
The StabilityPool implements a withdrawal timelock to prevent panic withdrawals during liquidations:
- Users must request withdrawal via
requestWithdraw()
before they can withdraw - A timelock duration must pass before the withdrawal becomes available
- Users have a limited time window to execute their withdrawal after the timelock expires
- Depositing cancels any pending withdrawal request
- This mechanism ensures liquidity stability during critical liquidation periods
Timelock Configuration:
- withdrawTimelockDuration
: Time before withdrawal becomes available (default: 30 minutes)
- withdrawTimelockDelay
: Time window to execute withdrawal after timelock expires (default: 2 days)
- Both parameters are configurable by the owner
Key Functions¶
Function | Description | Access | Parameters |
---|---|---|---|
initialize |
Initializes the upgradeable proxy instance | initializer |
_rToken , _deToken , _crvUSDToken , _lendingPool , _treasury , _liquidationStrategyProxy , _initialOwner |
deposit |
Deposit rToken and mint the same amount of deToken | public |
scaledAmount – rToken to deposit (scaled amount from RToken.balanceOf) |
requestWithdraw |
Request withdrawal with timelock to prevent panic withdrawals during liquidations | public |
amount – deToken amount to withdraw (0 to cancel) |
withdraw |
Burn deToken and withdraw the same amount of rToken (after timelock expires) | public |
deTokenAmount – deToken to burn |
liquidateBorrower |
Delegate call to the liquidation module to liquidate unhealthy positions | manager or owner |
poolAdapter , vaultAdapter , user , data , minSharesOut |
collectDust |
Collect dust tokens from the stability pool | owner |
token , recipient , amount |
setRWAVault |
Update the vault receiving seized collateral | owner |
_rwaVault |
setLiquidationModule |
Update liquidation module | owner |
_liquidationProxy |
setLiquidationVaultTokenSplit |
Configure split of liquidation proceeds (mint/burn/swap/liquidity). Must sum to 10000 bps |
manager or owner |
mintBps , burnBps , swapBps , liquidityBps |
setLiquidationSwap |
Update contract used for swapping collateral | owner |
_liquidationSwap |
setFeeCollector |
Update the fee collector address | owner |
_feeCollector |
setWithdrawTimelockDuration |
Set the duration of the withdrawal timelock | owner |
_withdrawTimelockDuration |
setWithdrawTimelockDelay |
Set the delay period for withdrawal timelock expiration | owner |
_withdrawTimelockDelay |
addManager |
Grant manager rights | owner |
manager |
removeManager |
Revoke manager rights | owner |
manager |
pause / unpause |
Emergency circuit-breaker | owner |
– |
View Functions | Query manager list, deposits, balances, and timelock status | view |
– |
Accounting Simplicity
deToken is always minted/burned 1 : 1 with rToken, ensuring no internal exchange rate math or interest accrual.
View Functions¶
Function | Description | Parameters | Returns |
---|---|---|---|
getManagerList |
Get list of all manager addresses | – | address[] – manager list |
isAddressManager |
Check if an address is a manager | manager – address to check |
bool – true if manager |
getUserDeposit |
Get deposit amount for a specific user | user – user address |
uint256 – deposit amount |
getTotalDeposits |
Get total deposits in the pool | – | uint256 – total deposits |
balanceOf |
Get balance of a user (alias for getUserDeposit) | user – user address |
uint256 – user balance |
getPoolIndex |
Get current pool index from lending pool | – | uint256 – pool index |
getRawTotalDeposits |
Get raw total supply of deToken | – | uint256 – raw total |
getUserIndex |
Get user's index for interest calculation | user – user address |
uint256 – user index |
getScaledDeposit |
Get scaled deposit amount for a user (with interest) | user – user address |
uint256 – scaled amount |
isUserDepositInSameBlock |
Check if user deposited in the current block (prevents same-block withdraw) | user – user address |
bool – true if same block |
Expand to View Implementation Details
- Built with OpenZeppelin’s upgradeable modules:
Initializable
,OwnableUpgradeable
,PausableUpgradeable
. - Protected with
ReentrancyGuard
. - Uses
SafeERC20
for secure transfers. - Liquidations executed via delegatecall to the liquidation module → upgradeable strategies without fund migration.
- Manager addresses stored on-chain for easy enumeration.
- Configurable
LiquidationVaultTokenSplit
provides flexible handling of collateral proceeds.
Expand to View Interactions
- RToken: ERC20 deposited by users (e.g. rcrvUSD)
- DEToken: ERC20 representing depositor shares
- LendingPool: queried for borrower debt
- Liquidation Module: delegate-called liquidation logic
- Treasury: receives protocol fees
- RWA Vault: stores seized collateral (NFTs/tokens)
- Compliance Registry: blocks blacklisted addresses
Additional Features & Notes¶
- Upgradeable & Pausable – owner can pause all state-changing functions.
- Manager Role – multiple addresses can act on behalf of the pool without ownership transfer.
- 1 : 1 Accounting – deToken ↔ rToken peg is fixed.
- Flexible Liquidation Flow – new strategies can be deployed with no downtime.
- Withdrawal Timelock – prevents panic withdrawals during liquidations.
- Dust Collection – owner can collect excess tokens (only delta between deToken and rToken for rToken).
- Same-Block Protection – prevents deposit and withdrawal in the same block.
- Compliance Integration – blacklisted addresses cannot interact with the pool.
Liquidation Responsibility
Liquidation is only triggered through the liquidation module. Managers and owners must ensure correct configuration, as seized collateral flows directly to the RWA Vault.
Dust Collection Safety
The collectDust
function has built-in safety for rToken:
- Only the delta between deToken total supply and rToken balance can be collected
- This prevents accidental removal of user funds
- Other tokens can be collected in full (use with caution)