Skip to content

Commit

Permalink
store as exps
Browse files Browse the repository at this point in the history
  • Loading branch information
maxwolff committed Aug 15, 2020
1 parent 02194c5 commit 24c1661
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 41 deletions.
59 changes: 31 additions & 28 deletions contracts/Rho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ interface RhoInterface {
) external;
}

/* Notes:
* CTokens are used as collateral. "Underlying" in Rho refers to the collateral CToken's underlying token.
* An Exp is a data type with 18 decimals, used for scaling up and precise calculations.
*/

contract Rho is RhoInterface, Math {

InterestRateModelInterface public interestRateModel;
Expand All @@ -58,13 +63,12 @@ contract Rho is RhoInterface, Math {
int public parBlocksPayingFixed;

/* Per block fixed / float interest rates used in collateral calculations */
uint public avgFixedRateReceivingMantissa;
uint public avgFixedRatePayingMantissa;
Exp public avgFixedRateReceiving;
Exp public avgFixedRatePaying;

/* Per block float rate bounds used in collateral calculations */
//TODO: store mantissas as structs too?
uint public maxFloatRateMantissa;
uint public minFloatRateMantissa;
Exp public maxFloatRate;
Exp public minFloatRate;

/* Protocol PnL */
uint public supplyIndex;
Expand Down Expand Up @@ -140,8 +144,8 @@ contract Rho is RhoInterface, Math {
benchmark = benchmark_;
cTokenCollateral = cTokenCollateral_;
comp = comp_;
minFloatRateMantissa = minFloatRateMantissa_;
maxFloatRateMantissa = maxFloatRateMantissa_;
minFloatRate = _exp(minFloatRateMantissa_);
maxFloatRate = _exp(maxFloatRateMantissa_);
SWAP_MIN_DURATION = swapMinDuration_;
SUPPLY_MIN_DURATION = supplyMinDuration_;
admin = admin_;
Expand Down Expand Up @@ -282,15 +286,15 @@ contract Rho is RhoInterface, Math {
int parBlocksReceivingFixedNew = _add(parBlocksReceivingFixed, _mul(SWAP_MIN_DURATION, notionalAmount));

/* avgFixedRateReceivingNew = (avgFixedRateReceiving * notionalReceivingFixed + notionalAmount * swapFixedRate) / (notionalReceivingFixed + notionalAmount);*/
Exp memory priorFixedReceivingRate = _mul(_exp(avgFixedRateReceivingMantissa), notionalReceivingFixed);
Exp memory priorFixedReceivingRate = _mul(avgFixedRateReceiving, notionalReceivingFixed);
Exp memory orderFixedReceivingRate = _mul(swapFixedRate, notionalAmount);
Exp memory avgFixedRateReceivingNew = _div(_add(priorFixedReceivingRate, orderFixedReceivingRate), notionalReceivingFixedNew);

userCollateralCTokens = getPayFixedInitCollateral(swapFixedRate, notionalAmount, cTokenExchangeRate);

notionalPayingFloat = notionalPayingFloatNew;
notionalReceivingFixed = notionalReceivingFixedNew;
avgFixedRateReceivingMantissa = avgFixedRateReceivingNew.mantissa;
avgFixedRateReceiving = avgFixedRateReceivingNew;
parBlocksReceivingFixed = parBlocksReceivingFixedNew;

return userCollateralCTokens;
Expand All @@ -304,15 +308,15 @@ contract Rho is RhoInterface, Math {
int parBlocksPayingFixedNew = _add(parBlocksPayingFixed, _mul(SWAP_MIN_DURATION, notionalAmount));

/* avgFixedRatePayingNew = (avgFixedRatePaying * notionalPayingFixed + notionalAmount * swapFixedRate) / (notionalPayingFixed + notionalAmount) */
Exp memory priorFixedPayingRate = _mul(_exp(avgFixedRatePayingMantissa), notionalPayingFixed);
Exp memory priorFixedPayingRate = _mul(avgFixedRatePaying, notionalPayingFixed);
Exp memory orderFixedPayingRate = _mul(swapFixedRate, notionalAmount);
Exp memory avgFixedRatePayingNew = _div(_add(priorFixedPayingRate, orderFixedPayingRate), notionalPayingFixedNew);

userCollateralCTokens = getReceiveFixedInitCollateral(swapFixedRate, notionalAmount, cTokenExchangeRate);

notionalReceivingFloat = notionalReceivingFloatNew;
notionalPayingFixed = notionalPayingFixedNew;
avgFixedRatePayingMantissa = avgFixedRatePayingNew.mantissa;
avgFixedRatePaying = avgFixedRatePayingNew;
parBlocksPayingFixed = parBlocksPayingFixedNew;

return userCollateralCTokens;
Expand Down Expand Up @@ -384,13 +388,12 @@ contract Rho is RhoInterface, Math {
uint notionalReceivingFixedNew = _sub(notionalReceivingFixed, notionalAmount);
uint notionalPayingFloatNew = _sub(notionalPayingFloat, _mul(notionalAmount, benchmarkIndexRatio));


/* avgFixedRateReceiving = avgFixedRateReceiving * notionalReceivingFixed - swapFixedRateMantissa * notionalAmount / notionalReceivingFixedNew */
/* avgFixedRateReceiving = avgFixedRateReceiving * notionalReceivingFixed - swapFixedRate * notionalAmount / notionalReceivingFixedNew */
Exp memory avgFixedRateReceivingNew;
if (notionalReceivingFixedNew == 0){
avgFixedRateReceivingNew = _exp(0);
} else {
Exp memory numerator = _sub(_mul(_exp(avgFixedRateReceivingMantissa), notionalReceivingFixed), _mul(swapFixedRate, notionalAmount));
Exp memory numerator = _sub(_mul(avgFixedRateReceiving, notionalReceivingFixed), _mul(swapFixedRate, notionalAmount));
avgFixedRateReceivingNew = _div(numerator, notionalReceivingFixedNew);
}

Expand All @@ -406,7 +409,7 @@ contract Rho is RhoInterface, Math {
notionalReceivingFixed = notionalReceivingFixedNew;
notionalPayingFloat = notionalPayingFloatNew;
parBlocksReceivingFixed = parBlocksReceivingFixedNew;
avgFixedRateReceivingMantissa = avgFixedRateReceivingNew.mantissa;
avgFixedRateReceiving = avgFixedRateReceivingNew;

return userPayout;
}
Expand All @@ -423,12 +426,12 @@ contract Rho is RhoInterface, Math {
uint notionalPayingFixedNew = _sub(notionalPayingFixed, notionalAmount);
uint notionalReceivingFloatNew = _sub(notionalReceivingFloat, _mul(notionalAmount, benchmarkIndexRatio));

/* avgFixedRatePaying = avgFixedRatePaying * notionalPayingFixed - swapFixedRateMantissa * notionalAmount / notionalReceivingFixedNew */
/* avgFixedRatePaying = avgFixedRatePaying * notionalPayingFixed - swapFixedRate * notionalAmount / notionalReceivingFixedNew */
Exp memory avgFixedRatePayingNew;
if (notionalPayingFixedNew == 0) {
avgFixedRatePayingNew = _exp(0);
} else {
Exp memory numerator = _sub(_mul(_exp(avgFixedRatePayingMantissa), notionalPayingFixed), _mul(swapFixedRate, notionalAmount));
Exp memory numerator = _sub(_mul(avgFixedRatePaying, notionalPayingFixed), _mul(swapFixedRate, notionalAmount));
avgFixedRatePayingNew = _div(numerator, notionalReceivingFloatNew);
}

Expand All @@ -444,7 +447,7 @@ contract Rho is RhoInterface, Math {
notionalPayingFixed = notionalPayingFixedNew;
notionalReceivingFloat = notionalReceivingFloatNew;
parBlocksPayingFixed = parBlocksPayingFixedNew;
avgFixedRatePayingMantissa = avgFixedRatePayingNew.mantissa;
avgFixedRatePaying = avgFixedRatePayingNew;

return userPayout;
}
Expand Down Expand Up @@ -521,11 +524,11 @@ contract Rho is RhoInterface, Math {
parBlocksPayingFixedNew = _sub(parBlocksPayingFixed, _mul(accruedBlocks, notionalPayingFixed));

// Par blocks can be negative during the first or last ever swap, so floor them to 0
uint minFloatToReceive = _mul(_floor(parBlocksPayingFixedNew), _exp(minFloatRateMantissa));
uint maxFloatToPay = _mul(_floor(parBlocksReceivingFixedNew), _exp(maxFloatRateMantissa));
uint minFloatToReceive = _mul(_floor(parBlocksPayingFixedNew), minFloatRate);
uint maxFloatToPay = _mul(_floor(parBlocksReceivingFixedNew), maxFloatRate);

uint fixedToReceive = _mul(_floor(parBlocksReceivingFixedNew), _exp(avgFixedRateReceivingMantissa));
uint fixedToPay = _mul(_floor(parBlocksPayingFixedNew), _exp(avgFixedRatePayingMantissa));
uint fixedToReceive = _mul(_floor(parBlocksReceivingFixedNew), avgFixedRateReceiving);
uint fixedToPay = _mul(_floor(parBlocksPayingFixedNew), avgFixedRatePaying);

uint minCredit = _add(fixedToReceive, minFloatToReceive);
uint maxDebt = _add(fixedToPay, maxFloatToPay);
Expand All @@ -543,8 +546,8 @@ contract Rho is RhoInterface, Math {
function getSupplierLiquidity(uint accruedBlocks, Exp memory floatRate, Exp memory cTokenExchangeRate) public view returns (CTokenAmount memory supplierLiquidityNew) {
uint floatPaid = _mul(notionalPayingFloat, floatRate);
uint floatReceived = _mul(notionalReceivingFloat, floatRate);
uint fixedPaid = _mul(accruedBlocks, _mul(notionalPayingFixed, _exp(avgFixedRatePayingMantissa)));
uint fixedReceived = _mul(accruedBlocks, _mul(notionalReceivingFixed, _exp(avgFixedRateReceivingMantissa)));
uint fixedPaid = _mul(accruedBlocks, _mul(notionalPayingFixed, avgFixedRatePaying));
uint fixedReceived = _mul(accruedBlocks, _mul(notionalReceivingFixed, avgFixedRateReceiving));
// TODO: safely handle supplierLiquidity going negative?
supplierLiquidityNew = _sub(_add(supplierLiquidity, toCTokens(_add(fixedReceived, floatReceived), cTokenExchangeRate)), toCTokens(_add(fixedPaid, floatPaid), cTokenExchangeRate));
}
Expand All @@ -570,15 +573,15 @@ contract Rho is RhoInterface, Math {
// @dev The amount that must be locked up for the payFixed leg of a swap paying fixed. Used to calculate both the protocol and user's collateral.
// = notionalAmount * SWAP_MIN_DURATION * (swapFixedRate - minFloatRate)
function getPayFixedInitCollateral(Exp memory fixedRate, uint notionalAmount, Exp memory cTokenExchangeRate) public view returns (CTokenAmount memory) {
Exp memory rateDelta = _sub(fixedRate, _exp(minFloatRateMantissa));
Exp memory rateDelta = _sub(fixedRate, minFloatRate);
uint amt = _mul(_mul(SWAP_MIN_DURATION, notionalAmount), rateDelta);
return toCTokens(amt, cTokenExchangeRate);
}

// @dev The amount that must be locked up for the receiveFixed leg of a swap receiving fixed. Used to calculate both the protocol and user's collateral.
// = notionalAmount * SWAP_MIN_DURATION * (maxFloatRate - swapFixedRate)
function getReceiveFixedInitCollateral(Exp memory fixedRate, uint notionalAmount, Exp memory cTokenExchangeRate) public view returns (CTokenAmount memory) {
Exp memory rateDelta = _sub(_exp(maxFloatRateMantissa), fixedRate);
Exp memory rateDelta = _sub(maxFloatRate, fixedRate);
uint amt = _mul(_mul(SWAP_MIN_DURATION, notionalAmount), rateDelta);
return toCTokens(amt, cTokenExchangeRate);
}
Expand Down Expand Up @@ -613,8 +616,8 @@ contract Rho is RhoInterface, Math {
require(maxFloatRateMantissa_ > 1e10, "Max float rate below minimum");

emit SetCollateralRequirements(minFloatRateMantissa_, maxFloatRateMantissa_);
minFloatRateMantissa = minFloatRateMantissa_;
maxFloatRateMantissa = maxFloatRateMantissa_;
minFloatRate = _exp(minFloatRateMantissa_);
maxFloatRate = _exp(maxFloatRateMantissa_);
}

function _pause(bool isPaused_) external {
Expand Down
2 changes: 1 addition & 1 deletion tests/forkTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { ethers } = require("ethers");
describe.skip('Fork', () => {
it.todo("write");
// it('basic ', async() => {
// const provider = new ethers.providers.Web3Provider(web3.providers.HttpProvide)
// const provider = new ethers.providers.Web3Provider(web3.providers.HttpProvider)
// console.log(await provider.getBlockNumber());
// })
});
25 changes: 13 additions & 12 deletions tests/protocolTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,9 @@ describe('Protocol Unit Tests', () => {
*/
const {lockedCollateral, unlockedCollateral} = await call(rhoLens, 'getSupplyCollateralState', []);
expect(lockedCollateral.val).toEqNum(1.5552e8);

expect(
await call(rho, 'avgFixedRateReceivingMantissa', [])
await call(rho, 'avgFixedRateReceiving', [])
).toEqNum(swapFixedRate);
expect(await call(rho, 'notionalReceivingFixed', [])).toEqNum(
orderSize
Expand Down Expand Up @@ -372,7 +373,7 @@ describe('Protocol Unit Tests', () => {
await send(rho, 'harnessAccrueInterest', []);

expect(
await call(rho, 'avgFixedRateReceivingMantissa', [])
await call(rho, 'avgFixedRateReceiving', [])
).toEqNum(swapFixedRate);
expect(await call(rho, 'notionalReceivingFixed', [])).toEqNum(
orderSize
Expand Down Expand Up @@ -410,7 +411,7 @@ describe('Protocol Unit Tests', () => {
await prep(rho._address, mantissa(1), cTokenCollateral, a2);
await send(rho, 'open', [true, orderSize, 2e10], { from: a2 });
expect(
await call(rho, 'avgFixedRateReceivingMantissa', [])
await call(rho, 'avgFixedRateReceiving', [])
).toEqNum(1.5e10);
});
});
Expand Down Expand Up @@ -471,7 +472,7 @@ describe('Protocol Unit Tests', () => {
const {lockedCollateral} = await call(rhoLens, 'getSupplyCollateralState', []);
expect(lockedCollateral.val).toEqNum(0.1728e8);
expect(
await call(rho, 'avgFixedRatePayingMantissa', [])
await call(rho, 'avgFixedRatePaying', [])
).toEqNum(swapFixedRate);
expect(await call(rho, 'notionalPayingFixed', [])).toEqNum(
orderSize
Expand Down Expand Up @@ -501,7 +502,7 @@ describe('Protocol Unit Tests', () => {
await send(rho, 'harnessAccrueInterest', []);

expect(
await call(rho, 'avgFixedRatePayingMantissa', [])
await call(rho, 'avgFixedRatePaying', [])
).toEqNum(swapFixedRate);
expect(await call(rho, 'notionalPayingFixed', [])).toEqNum(
orderSize
Expand Down Expand Up @@ -537,7 +538,7 @@ describe('Protocol Unit Tests', () => {
await prep(rho._address, mantissa(1), cTokenCollateral, a2);
await send(rho, 'open', [userPayingFixed, orderSize, 2e10], { from: a2 });
expect(
await call(rho, 'avgFixedRatePayingMantissa', [])
await call(rho, 'avgFixedRatePaying', [])
).toEqNum(1.5e10);

});
Expand Down Expand Up @@ -567,7 +568,7 @@ describe('Protocol Unit Tests', () => {
await send(rho, 'close', closeArgs);

expect(
await call(rho, 'avgFixedRateReceivingMantissa', [])
await call(rho, 'avgFixedRateReceiving', [])
).toEqNum(0);
expect(await call(rho, 'notionalReceivingFixed', [])).toEqNum(0);
expect(await call(rho, 'notionalPayingFloat', [])).toEqNum(0);
Expand Down Expand Up @@ -610,7 +611,7 @@ describe('Protocol Unit Tests', () => {
await send(rho, 'close', closeArgs);

expect(
await call(rho, 'avgFixedRateReceivingMantissa', [])
await call(rho, 'avgFixedRateReceiving', [])
).toEqNum(2e10);
expect(await call(rho, 'notionalReceivingFixed', [])).toEqNum(
orderSize
Expand Down Expand Up @@ -654,7 +655,7 @@ describe('Protocol Unit Tests', () => {
await send(rho, 'close', closeArgs);

expect(
await call(rho, 'avgFixedRatePayingMantissa', [])
await call(rho, 'avgFixedRatePaying', [])
).toEqNum(0);
expect(await call(rho, 'notionalPayingFixed', [])).toEqNum(0);
expect(await call(rho, 'notionalReceivingFloat', [])).toEqNum(0);
Expand Down Expand Up @@ -696,7 +697,7 @@ describe('Protocol Unit Tests', () => {
await send(rho, 'close', closeArgs);

expect(
await call(rho, 'avgFixedRatePayingMantissa', [])
await call(rho, 'avgFixedRatePaying', [])
).toEqNum(2e10);
expect(await call(rho, 'notionalPayingFixed', [])).toEqNum(
orderSize
Expand Down Expand Up @@ -731,8 +732,8 @@ describe('Protocol Unit Tests', () => {
await expect(send(rho, '_setCollateralRequirements',[1e12, 1e11], {from:root})).rejects.toRevert('Min float rate must be below max float rate');
// TODO test more reverts?
await send(rho, '_setCollateralRequirements',[0.5e10, 0.5e11], {from:root});
expect(await call(rho, 'minFloatRateMantissa',[])).toEqNum(0.5e10);
expect(await call(rho, 'maxFloatRateMantissa',[])).toEqNum(0.5e11);
expect(await call(rho, 'minFloatRate',[])).toEqNum(0.5e10);
expect(await call(rho, 'maxFloatRate',[])).toEqNum(0.5e11);
});

it('should change admin', async () => {
Expand Down

0 comments on commit 24c1661

Please sign in to comment.