Skip to content
This repository has been archived by the owner on Sep 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #98 from makerdao/feature/expand-managed-cdp-funct…
Browse files Browse the repository at this point in the history
…ions

Feature/expand managed cdp functions
  • Loading branch information
shkfnly authored Apr 25, 2019
2 parents e15c3d3 + 5fdd29d commit 09a73fe
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 31 deletions.
57 changes: 48 additions & 9 deletions lib/dai-plugin-mcd/src/CdpType.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export default class CdpType {
this.currency = currency;
this.ilk = ilk;
this._ilkBytes = stringToBytes(this.ilk);
this._getPar();
this._getVatInfo();
this._getCatInfo();
this._getSpotInfo();
this._getJugInfo();
}

async getTotalCollateral(unit = this.currency) {
Expand All @@ -39,45 +44,46 @@ export default class CdpType {
}

async getTotalDebt() {
const { Art, rate } = await this.ilkInfo();
const { Art, rate } = await this._getVatInfo();
return MDAI.wei(Art)
.times(rate)
.shiftedBy(-27);
}

async getDebtCeiling() {
const { line } = await this.ilkInfo();
const { line } = await this._getVatInfo();
return MDAI.rad(line);
}

async getLiquidationRatio() {
const { mat } = await this.ilkInfo('spot');
return new BigNumber(mat.toString()).dividedBy(RAY).toNumber();
const { mat } = await this._getSpotInfo();
const ratio = createCurrencyRatio(USD, MDAI);
return ratio(new BigNumber(mat.toString()).dividedBy(RAY).toString());
}

async getPrice() {
const [ilkInfo, liqRatio, par] = await Promise.all([
this.ilkInfo(),
this._getVatInfo(),
this.getLiquidationRatio(),
this._systemData.spot.par()
this._getPar()
]);
const parBN = new BigNumber(par.toString()).dividedBy(RAY);
const spot = new BigNumber(ilkInfo.spot.toString()).dividedBy(RAY);
const ratio = createCurrencyRatio(USD, this.currency);
const price = spot.times(parBN).times(liqRatio);
const price = spot.times(parBN).times(liqRatio.toNumber());
return ratio(price);
}

async getLiquidationPenalty() {
const { chop } = await this.ilkInfo('cat');
const { chop } = await this._getCatInfo();
return new BigNumber(chop.toString())
.dividedBy(RAY)
.minus(1)
.toNumber();
}

async getAnnualStabilityFee() {
const { duty } = await this.ilkInfo('jug');
const { duty } = await this._getJugInfo();
const dutyBigNumber = new BigNumber(duty.toString()).dividedBy(RAY);
const secondsPerYear = 60 * 60 * 24 * 365;
BigNumber.config({ POW_PRECISION: 100 });
Expand All @@ -95,4 +101,37 @@ export default class CdpType {
const contract = 'PIP_' + this.currency.symbol;
return this._systemData.get('smartContract').getContractAddress(contract);
}

async _getPar() {
if (!this._parPromise) this._parPromise = this._systemData.spot.par();
return this._parPromise;
}

async _getVatInfo() {
if (!this._vatInfoPromise) this._vatInfoPromise = this.ilkInfo();
return this._vatInfoPromise;
}

async _getCatInfo() {
if (!this._catInfoPromise) this._catInfoPromise = this.ilkInfo('cat');
return this._catInfoPromise;
}

async _getSpotInfo() {
if (!this._spotInfoPromise) this._spotInfoPromise = this.ilkInfo('spot');
return this._spotInfoPromise;
}

async _getJugInfo() {
if (!this._jugInfoPromise) this._jugInfoPromise = this.ilkInfo('jug');
return this._jugInfoPromise;
}

async reset() {
this._parPromise = null;
this._vatInfoPromise = null;
this._catInfoPromise = null;
this._spotInfoPromise = null;
this._jugInfoPromise = null;
}
}
113 changes: 97 additions & 16 deletions lib/dai-plugin-mcd/src/ManagedCdp.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,88 @@ export default class ManagedCdp {

assert(ilk && typeof ilk === 'string', 'Must specify ilk');
this.ilk = ilk;

this._cdpManager = cdpManager;
this.currency = cdpManager
.get(ServiceRoles.CDP_TYPE)
.getCdpType(null, ilk).currency;
this.type = cdpManager.get(ServiceRoles.CDP_TYPE).getCdpType(null, ilk);
this.currency = this.type.currency;
this._getUrnInfo();
this._getIlkInfo();
}

async getCollateralAmount() {
return this.currency.wei((await this._getUrnInfo()).ink);
}

async getCollateralValue() {
return this.currency.wei((await this._urnInfo()).ink);
const [collateral, price] = await Promise.all([
this.getCollateralAmount(),
this.type.getPrice()
]);
return collateral.times(price);
}

async getDebtValue() {
const cdpType = this._cdpManager
.get(ServiceRoles.CDP_TYPE)
.getCdpType(this.currency, this.ilk);
const { rate } = await cdpType.ilkInfo();
const art = MDAI.wei((await this._urnInfo()).art);
return art.times(rate).shiftedBy(-27);
const [ilkInfo, urnInfo] = await Promise.all([
this._getIlkInfo(),
this._getUrnInfo()
]);
const art = MDAI.wei(urnInfo.art);
return art.times(ilkInfo.rate).shiftedBy(-27);
}

async getCollateralizationRatio() {
const [collateral, debt] = await Promise.all([
this.getCollateralValue(),
this.getDebtValue()
]);
assert(debt.gt(0), 'Debt cannot be zero');
return collateral.div(debt);
}

async getLiquidationPrice() {
const [liquidationRatio, debt, collateral] = await Promise.all([
this.type.getLiquidationRatio(),
this.getDebtValue(),
this.getCollateralAmount()
]);
assert(collateral.gt(0), 'Collateral cannot be zero');
return debt.times(liquidationRatio).div(collateral);
}

async isSafe() {
const [liqPrice, collPrice] = await Promise.all([
this.getLiquidationPrice(),
this.type.getPrice()
]);
return collPrice.gte(liqPrice);
}

async minCollateral() {
const [debt, liquidationRatio, price, collateral] = await Promise.all([
this.getDebtValue(),
this.type.getLiquidationRatio(),
this.type.getPrice(),
this.getCollateralAmount()
]);
const minSafe = debt.times(liquidationRatio).div(price);
return minSafe.gt(collateral) ? collateral : minSafe;
}

async getCollateralAvailable() {
const [collateral, lockedCollateral] = await Promise.all([
this.getCollateralAmount(),
this.minCollateral()
]);
return collateral.minus(lockedCollateral);
}

async getDaiAvailable() {
const [collateral, liquidationRatio, debt] = await Promise.all([
this.getCollateralValue(),
this.type.getLiquidationRatio(),
this.getDebtValue()
]);
const dai = collateral.div(liquidationRatio).minus(debt);
return dai.gte(0) ? dai : MDAI(0);
}

lockCollateral(amount, { promise } = {}) {
Expand Down Expand Up @@ -84,11 +148,28 @@ export default class ManagedCdp {
);
}

async _urnInfo() {
return this._cdpManager.vat.urns(
stringToBytes(this.ilk),
this._cdpManager.getUrn(this.id)
);
async _getUrnInfo() {
if (!this._urnInfoPromise)
this._urnInfoPromise = this._cdpManager.vat.urns(
stringToBytes(this.ilk),
this._cdpManager.getUrn(this.id)
);
return this._urnInfoPromise;
}

async _getIlkInfo() {
if (!this._ilkInfoPromise) {
let _cdpType = this._cdpManager
.get(ServiceRoles.CDP_TYPE)
.getCdpType(this.currency, this.ilk);
this._ilkInfoPromise = _cdpType.ilkInfo();
}
return this._ilkInfoPromise;
}

async reset() {
this._urnInfoPromise = null;
this._ilkInfoPromise = null;
}
}

Expand Down
3 changes: 2 additions & 1 deletion lib/dai-plugin-mcd/test/CdpTypeService.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe.each(scenarios)('%s', (ilk, GEM) => {
beforeAll(async () => {
service = maker.service(CDP_TYPE);
cdpType = service.getCdpType(GEM, ilk);
cdpType.reset();
ratio = createCurrencyRatio(USD, GEM);

// await setupPriceFeed(maker, ilk, GEM);
Expand Down Expand Up @@ -76,7 +77,7 @@ describe.each(scenarios)('%s', (ilk, GEM) => {

test('get liquidation ratio', async () => {
const ratio = await cdpType.getLiquidationRatio();
expect(ratio).toBe(1.5);
expect(ratio.toNumber()).toBe(1.5);
});

test('get price', async () => {
Expand Down
52 changes: 51 additions & 1 deletion lib/dai-plugin-mcd/test/ManagedCdp.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ test('prevent freeing the wrong collateral type', async () => {
});

async function expectValues(cdp, { collateral, debt, myGem, myDai }) {
cdp.reset();
if (collateral !== undefined) {
expect(await cdp.getCollateralValue()).toEqual(cdp.currency(collateral));
expect(await cdp.getCollateralAmount()).toEqual(cdp.currency(collateral));
}
if (debt !== undefined) {
expect(await cdp.getDebtValue()).toEqual(MDAI(debt));
Expand All @@ -58,6 +59,47 @@ async function expectValues(cdp, { collateral, debt, myGem, myDai }) {
}
}

async function expectUtilValues(cdp, { val, ratio, isSafe, dai }) {
const [
debtValue,
collateralValue,
collateralAmount,
collateralizationRatio,
safe,
minCollateral,
availCollateral,
daiAvailable
] = await Promise.all([
cdp.getDebtValue(),
cdp.getCollateralValue(),
cdp.getCollateralAmount(),
cdp.getCollateralizationRatio(),
cdp.isSafe(),
cdp.minCollateral(),
cdp.getCollateralAvailable(),
cdp.getDaiAvailable()
]);

const minVal = debtValue.div(val);

if (val !== undefined) {
expect(collateralValue.eq(val)).toBeTruthy();
expect(minCollateral.toNumber()).toBe(minVal.toNumber());
expect(availCollateral.toNumber()).toBe(
collateralAmount.minus(minVal.toNumber()).toNumber()
);
}
if (ratio !== undefined) {
expect(collateralizationRatio.eq(ratio)).toBeTruthy();
}
if (safe !== undefined) {
expect(safe).toBe(isSafe);
}
if (dai !== undefined) {
daiAvailable.eq(MDAI(dai));
}
}

describe.each([
[
'ETH-A',
Expand Down Expand Up @@ -128,6 +170,14 @@ describe.each([
myDai: startingDaiBalance.plus(1),
myGem: startingGemBalance.minus(1)
});
cdp.type.reset();
const price = await cdp.type.getPrice();
await expectUtilValues(cdp, {
val: price.toNumber(),
ratio: price.toNumber(),
isSafe: true,
dai: '149'
});

const sameCdp = await mgr.getCdp(cdp.id);
await expectValues(sameCdp, { collateral: 1, debt: 1 });
Expand Down
7 changes: 3 additions & 4 deletions test/eth/GasService.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,9 @@ test('fetches gas station data', async () => {
test('returns a valid gas price', async () => {
const gasStationData = await gasService._gasStationDataPromise;
const gasPrice = await gasService.getGasPrice();
const expectedValue = gasService.get('web3')._web3.utils.toWei(
(gasStationData['fast'] / 10).toString(),
'gwei'
);
const expectedValue = gasService
.get('web3')
._web3.utils.toWei((gasStationData['fast'] / 10).toString(), 'gwei');
expect(typeof gasPrice).toBe('string');
expect(gasPrice).toBe(expectedValue);
});
Expand Down

0 comments on commit 09a73fe

Please sign in to comment.