MIP 2: Add a liquidator to sell reward tokens
|Author||Alex Scott, George Ornbo|
This MIP proposes a liquidation mechanism for reward tokens ($COMP, $LEND) accrued in the protocol. Through the liquidator mechanism tokens may be liquidated and the value of these tokens realised by SAVE.
Liquidator contract that sells the reward tokens approved in both
Compound and Aave integrations. This will allow accrued rewards tokens to be sold on DEXs and the
value returned to SAVE. This will bolster the SAVE APY and realised the value of
The protocol earns rewards from different platforms for lending stablecoins. To dat, the protocol has earned ~470 $COMP tokens for lending DAI and USDC and it is expected that the protocol will earn tokens from other platforms. This MIP offers an automated generic way to liquidate accrued tokens and to return this value to the protocol. This will bolster the SAVE APY.
The mStable protocol lends stablecoins to lending platforms and derives a return for depositors based on the Supply APY of the Platform. In addition to Supply APY rates many lending platforms offer liquidity providers rewards in the form of tokens. These tokens are tradable on DEXs and have value and provide an additional yield for liquidity provision.
The mStable protocol deposits DAI and USDC to Compound and has been accruing
$COMP tokens as a result. These tokens are valuable but the current protocol
has no way to realise the value from accrued rewards. As such these tokens
remain on a contract and the value cannot be liquidated.
For lending DAI and USDC to Compound the protocol has accrued $COMP tokens as
rewards. The $COMP that has been accrued on the
CompoundIntegration with a
balance of ~470 $COMP equivalent to $72k at the time of writing. This
value should be liquidated and distrubted to SAVE. The protocol should automate
this selling to support the push towards decentralisation.
This MIP creates a generic liquidiator that allows accrued rewards tokens to be retrieved
from a given
integration (e.g. CompoundIntegration), and sold for mUSD which is then
sent to the SavingsManager.
Liquidations are triggered once by week by any community member through an external function.
- Liquidator sells
USDC(or other) on Uniswap once per week (up to trancheAmount).
mUSDon Curve and send to SavingsManager
- SavingsManager streams mUSD to SAVE, second by second over the course of a week
There final architecture choice increases very little gas in the system - only causing 1600 gas (2x SLOAD) to a SAVE deposit. No gas costs are seen for general mint/swap/redemption. Any gas cost is incurred once a week when the liquidation is triggered.
The streaming of the mUSD to SAVE also achieves a gradual release of the realised mUSD over the course of a full week to SAVE, avoiding the scenario in which malicious actors could trigger the liquidation and jump into the SAVE contract to immediately benefit.
Capitalising on the new Curve 3Pool, it is now optimal to sell COMP for a given bAsset on Uniswap (e.g. DAI or USDC), then immediately sell that bAsset on Curve for mUSD.
There were a number of previous architecture ideas that turned out to be sub optimal, including intermittent collection from the Liquidator, and intermittent airdropping.
Liquidator.sol contract will be created that will sell
Token A for
Token B on a DEX.
Initially Uniswap and Curve will be supported but Balancer, 1inch, UniSwap and
other integrations may be added. In the short term the contract will be
upgradable with a view to it becoming immutable.
Protocol contracts that hold reward tokens will give the Liquidator infinite
approval to spend the rewards tokens. The Liquidator will then begin selling
Token A once per week, for
Token B, and then turning this
Token B into mUSD.
/** * @dev Create a liquidation * @param _integration The integration contract address from which to receive sellToken * @param _sellToken Token harvested from the integration contract * @param _bAsset The asset to buy on Uniswap * @param _curvePosition Position of the bAsset in Curves MetaPool * @param _uniswapPath The Uniswap path as an array of addresses e.g. [COMP, WETH, DAI] * @param _trancheAmount The amount of bAsset units to buy in each weekly tranche */ function createLiquidation( address _integration, address _sellToken, address _bAsset, int128 _curvePosition, address calldata _uniswapPath, uint256 _trancheAmount ) /** * @dev Triggers a liquidation, flow (once per week): * - Sells $COMP for $USDC (or other) on Uniswap (up to trancheAmount) * - Sell USDC for mUSD on Curve * - Send to SavingsManager * @param _integration Integration for which to trigger liquidation */ function triggerLiquidation(address _integration) external
CompoundIntegration (PROXY UPGRADE)
/** * @dev Approves Liquidator to spend COMP (0xc00e94Cb662C3520282E6f5717214004A7f26888) */ function approveRewardToken() external onlyGovernor
SavingsManager (MODULE UPGRADE)
Deposited mUSD from the Liquidator is streamed to the SAVE contract over the course of a full week. This means that as deposits to SAVE happen, they realise some of the value.
/** * @dev Allows the liquidator to deposit proceeds from iquidated gov tokens. * Transfers proceeds on a second by second basis to the Savings Contract over 1 week. * @param _mAsset The mAsset to transfer and distribute * @param _liquidated Units of mAsset to distribute */ function depositLiquidation(address _mAsset, uint256 _liquidated) external onlyLiquidator
Configurable Values (Via MCCP)
- TrancheAmount (max units of mUSD to purchase per week - useful for starting period)
- BuyAsset (must be some bAsset of USDC, USDT or DAI since that is the Curve 3 pool)
Copyright and related rights waived via CC0.