Skip to content

Commit

Permalink
pass exchange rate as param optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
maxwolff committed Aug 15, 2020
1 parent a9a1c6e commit 02194c5
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 101 deletions.
5 changes: 1 addition & 4 deletions contracts/Math.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,12 @@ contract Types {
contract Math is Types {

uint constant EXP_SCALE = 1e18;
Exp ONE_EXP = Exp({mantissa: EXP_SCALE});

function _exp(uint num) pure internal returns (Exp memory) {
return Exp({mantissa: num});
}

function _oneExp() pure internal returns (Exp memory) {
return Exp({mantissa: EXP_SCALE});
}

function _floor(int a) pure internal returns (uint) {
return a > 0 ? uint(a) : 0;
}
Expand Down
133 changes: 72 additions & 61 deletions contracts/Rho.sol

Large diffs are not rendered by default.

22 changes: 12 additions & 10 deletions contracts/RhoLens.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,31 @@ contract RhoLensV1 is Math {
}

function getHypotheticalOrderInfo(bool userPayingFixed, uint notionalAmount) external view returns (uint swapFixedRateMantissa, uint userCollateralCTokens) {
(CTokenAmount memory lockedCollateral, CTokenAmount memory supplierLiquidity) = getSupplyCollateralState();
(Exp memory swapFixedRate,) = rho.getSwapRate(userPayingFixed, notionalAmount, lockedCollateral, supplierLiquidity);
(CTokenAmount memory lockedCollateral, CTokenAmount memory supplierLiquidity, Exp memory cTokenExchangeRate) = getSupplyCollateralState();
(Exp memory swapFixedRate,) = rho.getSwapRate(userPayingFixed, notionalAmount, lockedCollateral, supplierLiquidity, cTokenExchangeRate);

CTokenAmount memory userCollateral;
if (userPayingFixed) {
userCollateral = rho.getPayFixedInitCollateral(swapFixedRate, notionalAmount);
CTokenAmount memory lockedCollateralHypothetical = _add(lockedCollateral, rho.getReceiveFixedInitCollateral(swapFixedRate, notionalAmount));
userCollateral = rho.getPayFixedInitCollateral(swapFixedRate, notionalAmount, cTokenExchangeRate);
CTokenAmount memory lockedCollateralHypothetical = _add(lockedCollateral, rho.getReceiveFixedInitCollateral(swapFixedRate, notionalAmount, cTokenExchangeRate));
require(_lte(lockedCollateralHypothetical, supplierLiquidity), "Insufficient protocol collateral");
} else {
userCollateral = rho.getReceiveFixedInitCollateral(swapFixedRate, notionalAmount);
CTokenAmount memory lockedCollateralHypothetical = _add(lockedCollateral, rho.getPayFixedInitCollateral(swapFixedRate, notionalAmount));
userCollateral = rho.getReceiveFixedInitCollateral(swapFixedRate, notionalAmount, cTokenExchangeRate);
CTokenAmount memory lockedCollateralHypothetical = _add(lockedCollateral, rho.getPayFixedInitCollateral(swapFixedRate, notionalAmount, cTokenExchangeRate));
require(_lte(lockedCollateralHypothetical, supplierLiquidity), "Insufficient protocol collateral");
}
return (swapFixedRate.mantissa, userCollateral.val);
}

function getSupplyCollateralState() public view returns (CTokenAmount memory lockedCollateral, CTokenAmount memory supplierLiquidity) {
function getSupplyCollateralState() public view returns (CTokenAmount memory lockedCollateral, CTokenAmount memory supplierLiquidity, Exp memory cTokenExchangeRate) {
cTokenExchangeRate = rho.getExchangeRate();

uint accruedBlocks = rho.getBlockNumber() - rho.lastAccrualBlock();
(lockedCollateral,,) = rho.getLockedCollateral(accruedBlocks);
(lockedCollateral,,) = rho.getLockedCollateral(accruedBlocks, cTokenExchangeRate);

Exp memory benchmarkIndexRatio = _div(_exp(rho.getBenchmarkIndex()), _exp(rho.benchmarkIndexStored()));
Exp memory floatRate = _sub(benchmarkIndexRatio, _oneExp());
Exp memory floatRate = _sub(benchmarkIndexRatio, ONE_EXP);

supplierLiquidity = rho.getSupplierLiquidity(accruedBlocks, floatRate);
supplierLiquidity = rho.getSupplierLiquidity(accruedBlocks, floatRate, cTokenExchangeRate);
}
}
2 changes: 1 addition & 1 deletion contracts/test/MockRho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ contract MockRho is Rho {
}

function harnessAccrueInterest() public returns (CTokenAmount memory lockedCollateralNew){
return super.accrue();
return accrue(getExchangeRate());
}

function advanceBlocks(uint blocks) public {
Expand Down
11 changes: 6 additions & 5 deletions script/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ const INIT_EXCHANGE_RATE = bn(2e8);
const SWAP_MIN_DURATION = bn(345600);// 60 days in blocks, assuming 15s blocks
const SUPPLY_MIN_DURATION = bn(172800);

const yOffset = bn(0.05e18);
const yOffset = bn(2.5e10);
const slopeFactor = bn(0.5e36);
const rateFactorSensitivity = bn(0.000075e18);
const feeBase = bn(0.001e18);
const feeSensitivity = bn(0.003e18);
const range = bn(0.5e18);
const range = bn(2.5e10);

const rateFactorSensitivity = bn(7.5e13);
const feeBase = bn(5e9);
const feeSensitivity = bn(3e9);


/* PROVIDER="http://localhost:8545/" npx saddle -n development script deploy */
Expand Down
76 changes: 56 additions & 20 deletions tests/protocolTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ const prep = async (spender, amount, token, who) => {
await send(token, "approve", [spender, amount], { from: who });
};

let print = (msg, src) => {
console.log(msg, require('util').inspect(src, false, null, true));
};

const getCloseArgs = (openTx) => {
const vals = openTx.events.OpenSwap.returnValues;
return [vals.userPayingFixed, vals.benchmarkIndexInit, vals.initBlock, vals.swapFixedRateMantissa, vals.notionalAmount, vals.userCollateralCTokens, vals.owner];
Expand Down Expand Up @@ -69,7 +65,7 @@ describe('Constructor', () => {
describe('Protocol Integration Tests', () => {
const [root, lp, a1, a2, ...accounts] = saddle.accounts;
let benchmark, model, cTokenCollateral, rho, rhoLens, comp;
const supplyAmount = bn(100e18).div(INIT_EXCHANGE_RATE);//50e8
const supplyAmount = bn(100e18).div(INIT_EXCHANGE_RATE);
const block = 100;
const benchmarkIndexInit = mantissa(1.2);

Expand Down Expand Up @@ -127,10 +123,10 @@ describe('Protocol Unit Tests', () => {
});

it('should update account struct', async () => {
const acct = await call(rho, 'supplyAccounts', [lp]);
expect(acct.amount).toEqNum(supplyAmount);
expect(acct.lastBlock).toEqNum(block);
expect(acct.index).toEqNum(mantissa(1));
const {amount, lastBlock, index} = await call(rho, 'supplyAccounts', [lp]);
expect(amount).toEqNum(supplyAmount);
expect(lastBlock).toEqNum(block);
expect(index).toEqNum(mantissa(1));
});

it('should update globals', async () => {
Expand All @@ -140,9 +136,54 @@ describe('Protocol Unit Tests', () => {
);
});

it.todo('if second time, trues up');
it('should trues up on second supply', async () => {
// Prep a swap that increases the supply idx: same as closePayFixed/"should close swap and profit protocol"

const swapFixedRate = bn(3e10);
const orderSize = mantissa(10);
await prep(rho._address, mantissa(1), cTokenCollateral, a1);
await send(model, 'setRate', [swapFixedRate]);
const tx = await send(rho, 'open', [true, orderSize, swapFixedRate], {
from: a1
});
await send(rho, 'advanceBlocks', [bn(SWAP_MIN_DURATION).add(400)]);
await send(benchmark, 'setBorrowIndex', [mantissa(1.212)]);
await send(rho, 'close', getCloseArgs(tx));
expect(await call(rho, 'supplyIndex', [])).toEqNum(1.0038e18);

await prep(rho._address, 10e8, cTokenCollateral, lp);
await send(rho, 'supply', [10e8], {
from: lp,
});

// 50e8 * 1.0038 + 10e8 = 60.19
let {amount, lastBlock, index} = await call(rho, 'supplyAccounts', [lp]);
expect(amount).toEqNum(60.19e8);
const blockNum = await call(rho, 'getBlockNumber', []);
expect(lastBlock).toEqNum(blockNum);
expect(index).toEqNum(1.0038e18);

// if previously fully withdrawn, should correctly supply again
await send(rho, 'setBlockNumber', [600000]);
await send(rho, 'remove', [-1], {from: lp});

it.todo('if previously fully withdrawn, correctly supply again');
({amount, lastBlock, index} = await call(rho, 'supplyAccounts', [lp]));
expect(amount).toEqNum(0);
expect(lastBlock).toEqNum(600000);
expect(index).toEqNum(1.0038e18);

await send(rho, 'setBlockNumber', [600001]);

await prep(rho._address, 10e8, cTokenCollateral, lp);
await send(rho, 'supply', [10e8], {
from: lp,
});

({amount, lastBlock, index} = await call(rho, 'supplyAccounts', [lp]));
expect(amount).toEqNum(10e8);
expect(lastBlock).toEqNum(600001);
expect(index).toEqNum(1.0038e18);
});
});

describe('Remove liquidity', () => {
Expand Down Expand Up @@ -243,15 +284,6 @@ describe('Protocol Unit Tests', () => {
await send(rho, 'harnessAccrueInterest', []);
expect(newIdx).toEqNum(await call(rho, 'benchmarkIndexStored', []));
});

it.todo(
'test locked collateral increases in accrue interest after open pay fixed swap'
);

/*
* TODO: locked collateral min
* total liquidity = 0
*/
});

describe('open user paying fixed', () => {
Expand Down Expand Up @@ -549,6 +581,7 @@ describe('Protocol Unit Tests', () => {
const userProfit = bal2.sub(bal1);
expect(userProfit).toEqNum(-0.19e8);
expect(await call(rho, 'supplierLiquidity', [])).toEqNum(supplyAmount.sub(userProfit));
expect(await call(rho, 'supplyIndex', [])).toEqNum(1.0038e18);
});


Expand All @@ -564,6 +597,7 @@ describe('Protocol Unit Tests', () => {
const userProfit = bal2.sub(bal1);
expect(userProfit).toEqNum(3.27e8);
expect(await call(rho, 'supplierLiquidity', [])).toEqNum(supplyAmount.sub(userProfit));
expect(await call(rho, 'supplyIndex', [])).toEqNum(0.9346e18);
});

// open swap, open second at end of first, close first.
Expand Down Expand Up @@ -633,6 +667,7 @@ describe('Protocol Unit Tests', () => {
const userProfit = bal2.sub(bal1);
expect(userProfit).toEqNum(0.19e8);
expect(await call(rho, 'supplierLiquidity', [])).toEqNum(supplyAmount.sub(userProfit));
expect(await call(rho, 'supplyIndex', [])).toEqNum(0.9962e18);
});


Expand All @@ -648,6 +683,7 @@ describe('Protocol Unit Tests', () => {
const userProfit = bal2.sub(bal1);
expect(userProfit).toEqNum(-3.27e8);
expect(await call(rho, 'supplierLiquidity', [])).toEqNum(supplyAmount.sub(userProfit));
expect(await call(rho, 'supplyIndex', [])).toEqNum(1.0654e18);
});

// open swap, open second at end of first, close first.
Expand Down

0 comments on commit 02194c5

Please sign in to comment.