MIP35: Peg Stability Module - Compound Mixed Exposure - With Farming

MIP35: Peg Stability Module - Compound Mixed Exposure - With Farming


MIP#: 35
Title: Peg Stability Module - Compound Mixed Exposure - With Farming
Author(s): Alexis
Contributors: None
Type: Technical
Status: Request for Comments (RFC)
Date Proposed: 2021-01-09
Date Ratified: <yyyy-mm-dd>
Dependencies: PSM, Uniswap, Vat, Join Usdc-lendler, Join Dai-lendler 
Replaces: n/a
License: AGPL3+


  • The proposed implementation is part of the dss-psm-cme - Peg Stability Compound Mixed Exposure - project.

Sentence Summary

This proposal define a new Peg Stability Module which converts USDC to DAI and DAI to USDC, during the conversion it lends and farm the gem via lender token and
leverage the position using cdai using the same technique to farm it too.

Paragraph Summary

The PSM Compound Mixed Exposure With Farming is based on the PSM Compound Mixed Exposure MIP32
but with two farming join on each token (cDai and cUsdc).

The join use the generic ‘maker join’ interface. It takes as input a collateral, lends and farm it behind the scene to compound,
on the output the join redeems the position and return the collateral.

This PSM will have 2 urns one cDai and one cUsdc which are both leverage in compound, but the maker position for this PSM is still on uscd and dai.

Component Summary

MIP35c1: The PSM Contains snippet of proposed implementation.

MIP35c2: The Lending Join

MIP35c3: The Burn Delegator

MIP35c4: The Harvest Contract

MIP35c5: Proposed Code

MIP35c6: Test cases Lists existing test cases

MIP35c7: Security considerations Comments on the security implications

MIP35c8: Licensing States the license under which the proposal and code are distributed.


Currently, the usdc token inside the PSM is inefficient and needs to be diversified.
By using cDai and cUsdc and farm them we will bring more diversification.
The farming bring more risk as the token is locked as collateral, but it is also motivated by a better outcome.


The PSM Mixed Exposure is articulated around 3 main components:

  • The PSM (entry point) - Same as MIP32

  • The New Farming Join

  • The excess delegator (excess token conversion) - Same as MIP32

  • The harvest contract - Same as MIP32

MIP35c1: The PSM

We reuse the MIP32 component and plug the new farming join on it.

It has three methods:

  • sell(address usr, uint256 gemAmt)
  • buy(address usr, uint256 gemAmt)
  • reserve()

It also has three admin methods

  • file(bytes32 what, data) : To change parameters
  • rely(address contract) : To add authorized address
  • deny(address contract) : To remove authorized address

There are three prameters:

  • tin : The fraction of the Gem → Dai transaction sent to the vow as a fee. Encoded as tin in wad units.
  • tout: The fraction of the Dai → Gem transaction sent to the vow as a fee. Encoded as tout in wad units.
  • line: The maximum amount of Usdc owns by the PSM. Encoded as line in wad units.

sell will take in input usdc, convert usdc into dai via the new farming join (usdc/dai). Then it will take the dai and convert it to dai via another farming join (Dai/Dai) and take the fees and return the Dai.

buy will take in input dai, convert the dai after fee into dai via the farming join (dai/dai). Then it will take the dai and convert it to usdc via the farming join (Dai/Usdc) and return the Usdc.

reserve will return the reserve inside the contract in dai,token - this is based on the uniswap reserve() call.

Additional specification:
The same level of debt is maintained for both positions (the leverage urn and the gem urn).

MIP35c2: The Farming Join

The Farming Join is a new Join.

It uses the same join interface as MIP32. A classic join interface with an additional method harvest() behind an allowlist.

The join has one external methods

  • exit(address guy, uint256 amount)

The join has two authenticated methods

  • join(address guy, uint256 amount)
  • harvest() : To move excess to the delegator

The join also has forth admin methods

  • file(bytes32 what, data) : To change parameters
  • rely(address contract) : To add authorized address
  • deny(address contract) : To remove authorized address
  • cage() : To cage the join

The join has seven parameters :

  • excess_delegator The delegator address.
  • excess_margin Margin amount until we start sending asserts to the delegator.
  • cf_target The compound coefficient target in WAD
  • cf_max The coefficient max in WAD. It overrides the compound provided max coefficient, this parameter is here for safety. If it is set above the compound value the join will take the compound one.
  • route The uniswap contract to swap token.
  • max_bonus_auction_amount Max amount we send to uniswap each time - to figth against eventual attack and slippage.
  • bonus_auction_duration Minimun time between two uniswap auction.

The collateral is register against the vat and allow borrowing on it exactly like a normal collateral, but the farming join lends, and farm the collateral with compound.
The join is an auth-join type accessible only by allow list.

  • The exposure is adjusted to the coefficient target each time we remove or add some assert to the vault. Join(), exit() and harvest().

  • The coefficient target is calculated by using the minimum between :
    - 98% of the compound maximum coefficient
    - 98% of cf_max
    - cf_target

    If cf_target is set above the maximum coefficient we use 98% of the maximum coefficient for target as safety.

  • After join(), exit() and harvest() we check with compound the status of our position and reject the transaction if the vault in a liquidation stage.

  • We wind and Unwind our position using a loop, we borrow and mint or redeemUnderlying and repayBorrow up to 99% of the max allowed by compound to reach the cf_target.
    The last iteration will exit the loop.

harvest() method will first check if we have a position superior at 100.1% in compound of the underlying collateral to allow a exit from the join in good order. Please Note, Farming can bring a risk of losing some part of the main collateral.

  • if we don’t hold the position and if we hold COMP we process to an uniswap auction using the parameters max_bonus_auction_amount and bonus_auction_duration
    to limit the frequency and the amount. We auction an amount up to max comp or the corresponding dai to go up to 100.1% + excess_margin

  • if we hold the position

    • we move the excess token minus the excess_margin to the delegator.
    • we move the bonus token to the delegator.

MIP35c3: The Burn Delegator

We reuse the MIP32 component
This delegator has three public methods:

  • processUsdc() convert the usdc to dai via the psm.
  • processComp() convert token bonus to dai via uniswap.
  • processDai() convert dai to MKR via uniswap and burn the MKR.

The join also has forth admin methods

  • file(bytes32 what, data) : To change parameters
  • rely(address contract) : To add authorized address
  • deny(address contract) : To remove authorized address
  • cage() : To cage the join

There are six parameters :

  • psm : psm address - can be changed
  • route : uniswap route address - can be changed
  • bonus_auction_duration: min time is sec between 2 uniswap swap
  • max_bonus_auction_amount : max comp amount by swap.
  • dai_auction_duration: min time is sec between 2 uniswap swap
  • max_dai_auction_amount : max dai amount by swap.

MIP35c4: The Harvest contract

This contract will have only one external method harvest() which calls harvest from the join.
Two contract will be deployed to call both join.

This contract has only one public methods:

  • harvest() call harvest from the join

We separated this method from the PSM to allow more flexibility for update.

MIP35c5: Proposed code

The code : dds-psm-cme

MIP35c6: Test cases

Unit tests:

MIP35c7: Security considerations

Compound technical risk

Errors or security vulnerabilities in the Compound system could result in the underlying USDC deposits to be lost or stolen.

Implementation technical risk

In addition to the technical risk inherent to Compound, the adapter implementation itself is non-trivial and could increase the attack/error surface.

Due to the design of multi-collateral DAI, worst-case losses should be limited to the collateral deposited in the adapter, and the debt ceiling should be set with this in mind.

There is security consideration about the code itself, compound tokens.
In this implementation as we use leverage on compound, the c-token can be sized.
By using leverage on compound we also expose ourself to a lost of the assert which is currently compensated by COMP token.

Another risk: uniswap interaction, but limited to the extra bonus.

MIP35c8: Licensing


Moved the harvest to a separated contract

Oh, it looks good, I hope it will be online soon.

1 Like

Compound had a problem with the Coinbase DAI price feed a few months ago. The problem caused some unexpected liquidations if I remember well. Is that fixed and how?

EDIT: source: https://cointelegraph.com/news/compound-liquidator-makes-4m-as-oracles-post-inflated-dai-price

EDIT2: more sources:

Not Yet Bit. Looks like they want to follow in the footsteps of Maker:

1 Like

We don’t cross assert so this oracle issue is not applicable here.

However, with the farm join we have to enter into the “compound market” here.
Which unflag a safety that allows the token to be liquidated, while there is no logical reason to be liquidated there is a compound attack vector.

  • No logical reason meaning as we know the exact exposure due to the unique assert and no market gap/ oracle gap can be generated with the same assert.

That is why there is two joins of them MIP35 and MIP32, I believe there is an under evaluated risk here but the reward is higher too.

1 Like

Thanks for the update. It looks to me that they chose the worst option. I wonder why they can’t add the Maker and the Uniswap oracle.

I will reconsider my Compound exposure and check if Aave and others are more secure options. I guess Maker has already done that homework and it still considers Compound to be the most secure platform.

1 Like

To be honest, I have got no feedback, no review, no comment.
No fork, No PR, The only person who looked at it is Tokenman.

I really don’t feel comfortable to push it to prod, and the main issue that lead to build is also gone by now.

overall, I am a bit skeptical about the “Request For Comment” state. It looks to me point-less, except for the owner to take time to rethink it is work.

1 Like

Well for one, This is the “PSM” which cannot be touted by Foundation Teams (this will change when they free themselves), and two, or dos, how could anybody in the community NOT love MKR being burned when all we need to do is:

  1. convert the usdc to dai via the psm.
  2. convert token bonus to dai via uniswap.
  3. convert dai to MKR via uniswap and burn the MKR.

Since I am not technical, I must say, it looks like a win-win!
Hence, why the RFC period here has been quiet so far, IMO.

1 Like

How that can be linked to PSM? The overall logic is different. Even the code based is now totally different.

Is it just the name that blocked the all process?
For my disclaim I probably missed part of the story about it.

I have 5 MIPs opened with different name and that didn’t change anything.

I have a hard time even understanding what this is saying TBH. You take usdc and then turn it into dai which you then turn into more dai? and you then repay some dai somewhere.

Further I would really love to get an accountant to look at this to make sure that the underlying idea is sound / legal.

1 Like

Hi Andy,

Thanks for the replay, I will try to reexplain it, we have two farming join:
one is cUsdc and the other is cDai.

the first join take usdc return dai.
the second join take dai and return dai.

Here the module, plug them in series so usdc -> dai then dai -> dai.
so the end user will have a usdc -> dai conversion.
But on our end you will have 1 cUsdc and 1 cDai in each vault.

There is no magic our main limitation here is the Dai supply as the convertor is used the supply will increase and the dai price will fail twice as fast as a normal psm.
The main issue with the PSM is that it levels the dai at one price 1.01or 0.99 this one will actually push the peg down or up.

I don’t think, there is no accounting issue here. Actually I don’t think I understand what you mean by accountant to look at the legal behind it.

What i mean by accounting issues really boils down to whether or not there is an issue with lending an encumbered asset. Would that be considered legal for a traditional company?

DAI isn’t just some 1 dollar currency to the protocol. Its an obligation to provide 1 dollars worth of collateral back at emergency shutdown. IMO that is why @SebVentures calls it a liability in this post.

So like seb says in order to buy anything the protocol “expands it balance sheet” and purchases the asset in question be that a loan or usdc or whatever, but what this basically means it is doing is that it is minting a new liability that it uses to purchase the asset in question.

In a sense, these new liabilities (i.e new DAI) basically gives the bearer a lien on the asset that was bought. This is because that dai is redeemable for $1 worth of collateral at ES (see this post explaining ES). That being the case, would it be legal for maker (assuming it existed in the traditional fiance world) to give a purchased asset (which has a lien associated with it) to compound and then receive some cToken that is supposed to be redeemable for the face value of the initial collateral + interest.

I know i can’t just give my house to someone and receive some IOU from them for a bigger house without paying back my lender first.

My guess (im not a lawyer or an accountant) is that isn’t legal unless you first have equity in the underlying asset. Meaning you first need to pay down the DAI liability to some extent before you are able to give any USDC to compound for investment purposes.

1 Like


the join() will convert to cToken and increase its leverage to match the CF.
the exit() will decrease its leverage and redeem the value in usd/dai from the cToken.

Concretely the vault contains in theory at any time more than 100% of underlying collateral (USDC/DAI) equivalent cToken with leverage. so 100% of exit() call can withdraw the position at anytime. - Emergency Shutdown -

I believe the liability is on the cToken, and the assert value is the underlying assert minus the leverage position taken.

During the “harvest()” call
If we are under 100.1% of the join value in usdc, we sell COMP inside the join to top up the underlying collateral with the product of the sell.
If we are over we send excess to the delegator.

The 100.1% is here to cover the eventuality of a negative interest with no COMP - it gives us probably around 2 weeks to take action ( with 0.1% over collateralization).

However, there is a risk that cToken can’t provide the full amount promised during the redeem - sort of real world company bankruptcy where you get only 1/2 of your money -. This risk is probably the same with any others collateral. I believe the overall risk is the same as the cropJoin one which has been evaluated already for cUsdc risk evaluation .

Yeah so what i am really trying to question here is the legality of converting the USDC to cUSDC in the join. Not sure that would be allowed in real world finance, and if it isn’t i think we need to wrangle with the idea that it would be a limitation that we should impose on ourself as well.

Further in the event that of a compound insolvency issue. Where does the buck stop? Who is on the hook for the protocols DAI liabilities?

CropJoin does exactly the same.

Real world finance do exactly the same at a level up, last example is : gameStop.
You deposit money in your account they lend it to the central bank.
You deposit share in your account they lend it to hedge found.
You take a credit for your house they package it and sell it as an exotic product.

Also here the Dai overall liability is not on this vault it is on the all system.

All line inside this vault is own by us at the difference of cropJoin.
Maker is the only owner of this assert, therefore we don’t have liability to return it.

Not a specific asset, but $1 of assets. Someone can borrow from a vault (using the loan on the vault as collateral) buy some USDC from a third party and at some point clear the debt and the vault. The third-party having DAI still has a claim on Maker even if the originating vault doesn’t exist anymore.

Sure but i think this explanation still skirts the question at hand. Can maker (the party with the DAI liability) transfer ownership of the asset (the loan in the quote here / the USDC used to mint dai in this MIP) to some other entity such as compound without first paying down that liability.

I get that the claim on the asset (i.e Collateral) is fungible. I just don’t really know where to draw the line about transferring ownership of these assets, and I think in the real world a transfer of ownership would require us to pay down the liability first.