MCCP 20: Overhaul the Governance Fee Flow Source

AuthorNick Addison, mZeroNine

Simple Summary

It is proposed to overhaul the current governance fees distribution model of the mStable Protocol from the current strategy of distributing 100% of all governance fees to stakers, to instead distribute 50% to stakers, while redirecting the other 50% directly to the TreasuryDAO in the form of native mAssets (mUSD & mBTC).


Currently, 100% of generated governance fees (10% of the total yield generated by the protocol, with the remaining 90% going straight to Save users) are used to market buy MTA and distribute them to stakers of both MTA and BPT.

As of today, the TreasuryDAO (responsible for the annual management of burn rate and the long-run optimization of the project) receives 0% of the revenues generated by the protocol.

It’s essential for sustainable governance of the protocol and its contributors that mStable create organic revenue lines. We therefore propose to reroute some of these governance fees used to buyback MTA to the TreasuryDAO instead.

Primarily, this is being done to rely less on MTA Bonds (we raised 423k mUSD worth of bonds so far, with a continuous future demand for them via Olympus Pro or Solv Protocol in the future if we don’t create other income streams) and instead utilize natively generated assets from fees (mUSD & mBTC) for liquidity.

As MTA stakers already receive a considerable weekly MTA allocation every epoch and directly benefit from the revenue going to the Treasury, this should easily offset their slight dilution of rewards, as these extra rewards did not contribute to more users staking their MTA.


Before the launch of the Emissions Controller last year, the protocol used the governance fee revenue in the Buyback & Make pool on Balancer.

Since then, we reroute ****these governance fees to purchase MTA directly off the market and distribute to stakers. This leaves the treasury and protocol with no organic way of capturing revenue and accruing value back to the treasury.

mStable has grown significantly in 2021: The core contributor number doubled, we’ve earmarked the remaining MTA emissions for the ecosystem for the next 6 years, and have grown our Asset Management subDAO position significantly.

With this growth, so have the expenses that the protocol has to carry. Sustainable yield has always been a top priority, and so it comes as a logical step to do our best to recreate this sustainability on the operational level as well.


The RevenueBuyBack contract will be forked to a new RevenueSplitBuyBack contract that sends a portion of the mAssets revenue to treasury and the rest through a buy-back of reward tokens. The buy-back does a mAsset redeem to a bAsset and then a Uniswap V3 swap to the rewards token, eg MTA.

The buy-back moves the min amounts to parameters of the buyBackRewards  function instead of being stored in contract storage. This is to better protect against sandwich attacks.

The new contract will include the following:

  • The buyBackRewards function has an array of minBassetsAmountsminRewardsAmounts and uniswapPaths added as arguments to the existing array of mAssets argument.
  • Only the keeper or governor can now execute the buyBackRewards  function as setting the min amounts needs to come from a trusted account.
  • The portion of the revenue sent to the treasury account is set with setTreasuryFee where 100% = 1e18.
  • The treasury account is set with setTreasury.
  • setMassetConfig has been changed to just mapBasset as there’s now just a mapping from mAssets to bAssets. The min bAsset and rewards prices along with the Uniswap path are no longer stored in contract storage.

Deployment, initialisation and config of new RevenueSplitBuyBack contract

  • RevenueSplitBuyBack.initialize.contractor arguments
    • _nexus = 0xAFcE80b19A8cE13DEc0739a1aaB7A028d6845Eb3
    • _rewardsToken = 0xa3BeD4E1c75D00fa6f4E5E6922DB7261B5E9AcD2
    • _uniswapRouter = 0xE592427A0AEce92De3Edee1F18E0157C05861564
    • _emissionsController = 0xBa69e6FC7Df49a3b75b565068Fb91ff2d9d91780
  • RevenueSplitBuyBack.initialize arguments
    • _stakingDialIds = 0 and 1
    • _treasury = 0x3dd46846eed8D147841AE162C8425c08BD8E1b41 (Treasury sub DAO)
    • _treasuryFee = 5e17 (50%)
  • RevenueSplitBuyBack.mapBasset
    • _mAsset = 0xe2f2a5C287993345a840Db3B0845fbC70f5935a5 (mUSD)
    • _bAsset= 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 (USDC)
  • RevenueSplitBuyBack.mapBasset
    • _mAsset = 0x945Facb997494CC2570096c74b5F66A3507330a1 (mBTC)
    • _bAsset = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 (WBTC)

Call SavingsManager V1.4 (0xbc3b550e0349d74bf5148d86114a48c3b4aa856f) to set new Revenue Recipient to the new RevenueSplitBuyBack contract:

  • setRevenueRecipient(address _mAsset, address _recipient)
    • _mAsset = 0xe2f2a5C287993345a840Db3B0845fbC70f5935a5 (mUSD)
    • _recipient = newly deployed RevenueBuyBack contract
  • setRevenueRecipient(address _mAsset, address _recipient)
    • _mAsset = 0x945facb997494cc2570096c74b5f66a3507330a1 (mBTC)
    • _recipient = newly deployed RevenueBuyBack contract

Copyright and related rights waived via CC0