Update cUSDT interest rate model

Following Dharma’s lead, I believe that all stable-coins should have their interest rate model updated to match. DAI has already been updated to the latest and greatest interest rate model but USDC and USDT lag behind.

As USDC is a legacy cToken, upgrading the interest rate model for it will require a new contract, but USDT can have a new interest rate model using the JumpRateModelV2 built by Dharma. I propose setting USDT interest rate model to a new JumpRateModelV2 deployed with the same parameters as the current DAI interest rate model: base rate of 0%, 4% at kink, kink at 80% utilization, and 25% at 100% utilization.

Update: Interest rate model deployed here.


The DAI model seems to have had the desired effect of the utilization dropping back to 80% adding a larger buffer and reducing risk. Makes sense to upgrade all tokens that can be upgraded to the latest and align the parameters. I’m also wondering why the reserve factors are so different between market?


(Unsurprisingly) we are very supportive.


If the community is able to verify that the model matches the repo, and behaves as expected, migrating cUSDT to this model would be a no-brainer.

Going forward, both DAI and USDT rates will be able to be set through governance without deploying additional contracts; and could be made to match with a single proposal. That’s a nice improvement!


“another option” we could use the already deployed DAI’s interest rate model address for USDT aswell so there is no new contract in this case, since we want them to be the “same”, though it has advantages and disadvantages too, if we would like them to be seperated in the future it would require a new contract deployed.


That’s also mostly correct; the only “wonkiness” is that the interest rate model contract uses an assumed reserve factor in order to derive the supply interest rate, from the borrowing interest rate.

In this case, cDAI and cUSDT have different reserve factors.

For correctness, the interest rate model shouldn’t have this property at all (the cToken, which knows its reserve factor, utilization, etc can derive the supply interest rate).


The assumed reserve factor is currently only used when calculating base rate for DAI. The supply interest rate function has the reserve factor as a parameter in the header:

function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) public view returns (uint)

My issue with tying together USDT and DAI is that I don’t know if we want USDT interest rate to change with MakerDAO actions. I think keeping them separate for now with equal parameters is the way to go.

1 Like

Proposal live here: https://compound.finance/governance/proposals/20

1 Like

What steps have been taken to ensure that the deployed contract matches the rate model in the repo? Any way to compare the bytecode, or point to community review?

Excited to see this as a proposal @arr00 :comp:

Personally, I’ve ran the saddle verify method which compares bytecode and it all checks out. As I have deployed it, this doesn’t mean much coming from me. Someone else should check too! I’m thinking I’ll write a medium post on doing this just to make sure the community knows how it’s done.

Another important parameter to check now is that the owner was set to the Timelock correctly. You can see the owner in the read contract tab on etherscan.

We think some of the changes are good but the parameter choices seem somewhat arbitrary. While we are supportive of this particular proposal as a form of dollar-denominated rate equalization, we think that future rate changes should de minimis be chosen in a data driven manner and ideally via simulation. Given the rapid changes in rates due to yield farming powered by Dai and COMP, data driven rates will provide significantly more leeway for the protocol to react to adverse farming events.

Below, we propose a few simple models for a data-driven IR model:

  1. Base Rate: Should be the risk-free rate of the asset e.g. for DAI, the base rate can be either DSR or stability fee rate. For ETH, the base rate can be the ETH 2.0 staking interest rate.

  2. Kinks at x% utilization: this number should depend on the suppliers’ supply asset distribution. For example, using 1 - top supplier supply % to define the Kink. The intuition for this heuristic is as follows: when the asset’s liquidity is too low such that the top holder can’t withdraw all his supplied assets, the system will try to aggressively push the interest rate up. If the asset supply is more centralized, the utilization to trigger crossing the kink will be lower. If we apply this simple methodology to the three stablecoins in Compound we find that:

  1. Borrow rate at kink: Have this match the empirical highest APR for supplying assets in the other platform, e.g. Curve or Uniswap LP return. This rate should be risk adjusted based on current yield farming behavior (e.g. force be more conservative when there is a multiple sigma event due to farming)

  2. Borrow rate at 100% utilization: not sure whether there is a good way to come up with a reasonable number, since the goal for this is just to disincentivize borrowing demand. It could be 3x or 5x of the borrow interest rate at kink.

Given these methodological constraints, we believe that a 0% base rate and a kink at 80% utilization would be a safe, conservative route [0]. Based on USDC’s 73.4% utilization, we project that the current equilibrium point for USDT is around 10% borrow interest rate [1].

— Gauntlet Team

[0] We note that the implied 4% borrow rate at the kink might be too low and will effectively push the utilization to a neighborhood of the kink. Validating this conclusion with simulation is future work that we aim to perform.

[1] We’re doing a back-of-the-envelope calculation to rescale USDT’s behavior to that of USDC, where we have a much higher empirical utilization (partially due to Dai creation).

1 Like

Thanks for your contribution @arr00 :+1:

Before voting 20th proposal, I’d like to check how to work this code.(actually, who is calling this contract)

I’m not a smart contract developer so I just depends on its rationale/discussion and evidence to cast a voting on specific proposal. I’d like to understand its working process thoroughly as possible as I can.

I understand and agree the intention to achieve with this proposal. (I think that making standard for stable coins is good idea)

But I don’t understand how to apply it (technically)

For technical side, I thought that there is some PR to replace the existing interest rate model contract address to this new one.

Which code will actually set up this new interest rate model contract address?

and I’m not sure how many dev review this contract code.
Does it some evidence(some comments for codes reviews) this code was taking enough code review?

The new contract was deployed by arr00, using the source from compound’s github “JumpRateModelV2”, the contract admin is the Compound’s Timelock address “0x6d903f6003cca6255D85CcA4D3B5E5146dC33925”

I did verify the deployed contract bytecode and the source from compound’s github that anyone can do.

npx saddle match 0xFB564da37B41b2F6B6EDcc3e56FbF523bD9F2012 JumpRateModelV2 0 40000000000000000 1090000000000000000 800000000000000000 0x6d903f6003cca6255D85CcA4D3B5E5146dC33925 -n mainnet
Using network mainnet https://mainnet-eth.compound.finance
Matching contract at 0xFB564da37B41b2F6B6EDcc3e56FbF523bD9F2012 to JumpRateModelV2 with args [0,“40000000000000000”,“1090000000000000000”,“800000000000000000”,“0x6d903f6003cca6255D85CcA4D3B5E5146dC33925”]
:white_check_mark: Successfully matched JumpRateModelV2 to 0xFB564da37B41b2F6B6EDcc3e56FbF523bD9F2012 with args [0,“40000000000000000”,“1090000000000000000”,“800000000000000000”,“0x6d903f6003cca6255D85CcA4D3B5E5146dC33925”]

The proposal contains the necessery contract interactions that replaces the cUSDT interestratemodel address to 0xFB564da37B41b2F6B6EDcc3e56FbF523bD9F2012, when its ready to be executed anyone can do it.


Congratulations on the successful proposal!