Skip to content

Commit

Permalink
Add helper functions for target USDP repayment
Browse files Browse the repository at this point in the history
Signed-off-by: 34x4p08 <[email protected]>
  • Loading branch information
chainpioneer committed Apr 3, 2021
1 parent c3bcde5 commit 9650300
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 14 deletions.
39 changes: 35 additions & 4 deletions contracts/vault-managers/CDPManager01.sol
Original file line number Diff line number Diff line change
Expand Up @@ -211,16 +211,42 @@ contract CDPManager01 is ReentrancyGuard {
}

/**
* @notice Exists with ETH
* @notice Repayment is the sum of the principal and interest
* @dev Withdraws collateral and repays specified amount of debt
* @param asset The address of the collateral
* @param assetAmount The amount of the collateral to withdraw
* @param repayment The target repayment amount
**/
function exit_targetRepayment(address asset, uint assetAmount, uint repayment) external returns (uint) {

uint usdpAmount = _calcPrincipal(asset, msg.sender, repayment);

return exit(asset, assetAmount, usdpAmount);
}

/**
* @notice Withdraws WETH and converts to ETH
* @param ethAmount ETH amount to withdraw
* @param usdpAmount The amount of USDP token to repay
**/
function exit_Eth(uint ethAmount, uint usdpAmount) external {
exit(WETH, ethAmount, usdpAmount);
function exit_Eth(uint ethAmount, uint usdpAmount) external returns (uint) {
usdpAmount = exit(WETH, ethAmount, usdpAmount);
IWETH(WETH).transferFrom(msg.sender, address(this), ethAmount);
IWETH(WETH).withdraw(ethAmount);
(bool success, ) = msg.sender.call{value:ethAmount}("");
require(success, "Unit Protocol: ETH_TRANSFER_FAILED");
return usdpAmount;
}

/**
* @notice Repayment is the sum of the principal and interest
* @notice Withdraws WETH and converts to ETH
* @param ethAmount ETH amount to withdraw
* @param repayment The target repayment amount
**/
function exit_Eth_targetRepayment(uint ethAmount, uint repayment) external returns (uint) {
uint usdpAmount = _calcPrincipal(WETH, msg.sender, repayment);
return exit_Eth(ethAmount, usdpAmount);
}

// decreases debt
Expand Down Expand Up @@ -447,11 +473,16 @@ contract CDPManager01 is ReentrancyGuard {
}
}

function isCurveLP(address asset) public view returns(bool) {
function isCurveLP(address asset) public view returns (bool) {
address underlying = IWrappedToUnderlyingOracle(oracleRegistry.oracleByType(WRAPPED_TO_UNDERLYING_ORACLE_TYPE)).assetToUnderlying(asset);

if (underlying == address(0)) { return false; }

return ICurveRegistry(curveProvider.get_registry()).get_pool_from_lp_token(underlying) != address(0);
}

function _calcPrincipal(address asset, address owner, uint repayment) public view returns (uint) {
uint fee = vault.stabilityFee(asset, owner) * (block.timestamp - vault.lastUpdate(asset, owner)) / 365 days;
return repayment * DENOMINATOR_1E5 / (DENOMINATOR_1E5 + fee);
}
}
48 changes: 40 additions & 8 deletions test/CDPManager_Keep3r_Chainlink.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const balance = require('./helpers/balances');
const BN = web3.utils.BN;
const { expect } = require('chai');
const utils = require('./helpers/utils');
const increaseTime = require('./helpers/timeTravel');

[
'chainlinkMainAsset',
Expand Down Expand Up @@ -101,22 +102,53 @@ const utils = require('./helpers/utils');
await this.utils.join(this.mainCollateral, mainAmount, usdpAmount);

const mainToWithdraw = ether('50');
const usdpToWithdraw = ether('2.5');
const usdpToRepay = ether('2.5');

const { logs } = await this.utils.exit(this.mainCollateral, mainToWithdraw, usdpToWithdraw);
const { logs } = await this.utils.exit(this.mainCollateral, mainToWithdraw, usdpToRepay);

expectEvent.inLogs(logs, 'Exit', {
asset: this.mainCollateral.address,
user: deployer,
main: mainToWithdraw,
usdp: usdpToWithdraw,
usdp: usdpToRepay,
});

const mainAmountInPosition = await this.vault.collaterals(this.mainCollateral.address, deployer);
const usdpInPosition = await this.vault.debts(this.mainCollateral.address, deployer);

expect(mainAmountInPosition).to.be.bignumber.equal(mainAmount.sub(mainToWithdraw));
expect(usdpInPosition).to.be.bignumber.equal(usdpAmount.sub(usdpToWithdraw));
expect(usdpInPosition).to.be.bignumber.equal(usdpAmount.sub(usdpToRepay));
})

it('Should partially repay the debt of a position using `exit_targetRepayment`', async function() {
await this.vaultParameters.setStabilityFee(this.mainCollateral.address, 10_001);
const mainAmount = ether('100');
const usdpAmount = ether('20');

await this.utils.join(this.mainCollateral, mainAmount, usdpAmount);

await increaseTime(3600 * 24 * 365);

await this.utils.updatePrice();

const mainToWithdraw = ether('1');
const repayment = ether('11');

const receipt = await this.utils.exitTarget(this.mainCollateral, mainToWithdraw, repayment);

expectEvent(receipt, 'Exit', {
asset: this.mainCollateral.address,
user: deployer,
main: mainToWithdraw,
});

// the principal is about 10 USDP
expect(ether('10').sub(receipt.logs[0].args.usdp)).to.be.bignumber.lt(ether('0.001'));

const usdpInPosition = await this.vault.debts(this.mainCollateral.address, deployer);

// accumulated debt is about 1 USDP
expect(usdpInPosition.sub(ether('11'))).to.be.bignumber.lt(ether('0.001'));
})

it('Should partially repay the debt of a position and withdraw collaterals partially using ETH', async function() {
Expand All @@ -126,25 +158,25 @@ const utils = require('./helpers/utils');
await this.utils.joinEth(mainAmount, usdpAmount);

const mainToWithdraw = ether('1');
const usdpToWithdraw = ether('0.5');
const usdpToRepay = ether('0.5');

const wethBalanceBefore = await balance.current(this.weth.address);

const { logs } = await this.utils.exitEth(mainToWithdraw, usdpToWithdraw);
const { logs } = await this.utils.exitEth(mainToWithdraw, usdpToRepay);

expectEvent.inLogs(logs, 'Exit', {
asset: this.weth.address,
user: deployer,
main: mainToWithdraw,
usdp: usdpToWithdraw,
usdp: usdpToRepay,
});

const mainAmountInPosition = await this.vault.collaterals(this.weth.address, deployer);
const usdpInPosition = await this.vault.debts(this.weth.address, deployer);
const wethBalanceAfter = await balance.current(this.weth.address);

expect(mainAmountInPosition).to.be.bignumber.equal(mainAmount.sub(mainToWithdraw));
expect(usdpInPosition).to.be.bignumber.equal(usdpAmount.sub(usdpToWithdraw));
expect(usdpInPosition).to.be.bignumber.equal(usdpAmount.sub(usdpToRepay));
expect(wethBalanceBefore.sub(wethBalanceAfter)).to.be.bignumber.equal(mainToWithdraw);
})

Expand Down
1 change: 1 addition & 0 deletions test/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ module.exports = (context, mode) => {
buyout,
triggerLiquidation: w.triggerLiquidation,
exit: w.exit,
exitTarget: w.exitTarget,
exitEth: w.exitEth,
repayAllAndWithdraw,
repayAllAndWithdrawEth,
Expand Down
13 changes: 11 additions & 2 deletions test/helpers/wrappers.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,24 @@ module.exports = function(context, mode) {
},
exit: async (asset, mainAmount, usdpAmount) => {
if (+usdpAmount > 0) {
const debt = await context.vault.debts(asset.address, context.deployer)
await context.usdp.approve(context.vault.address, debt)
await context.usdp.approve(context.vault.address, usdpAmount)
}
return context.vaultManager.exit(
asset.address,
mainAmount, // main
usdpAmount, // USDP
);
},
exitTarget: async (asset, mainAmount, repayment) => {
if (+repayment > 0) {
await context.usdp.approve(context.vault.address, repayment)
}
return context.vaultManager.exit_targetRepayment(
asset.address,
mainAmount, // main
repayment, // USDP
);
},
exitEth: async (mainAmount, usdpAmount) => {
const debt = await context.vault.debts(context.weth.address, context.deployer)
await context.usdp.approve(context.vault.address, debt)
Expand Down

0 comments on commit 9650300

Please sign in to comment.