diff --git a/src/lender/adapters/mkr/assessor.sol b/src/lender/adapters/mkr/assessor.sol
deleted file mode 100644
index 9966ff3f..00000000
--- a/src/lender/adapters/mkr/assessor.sol
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (C) 2020 Centrifuge
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-pragma solidity >=0.5.15 <0.6.0;
-
-import "./../../assessor.sol";
-
-interface ClerkLike {
- function remainingCredit() external view returns (uint);
- function juniorStake() external view returns (uint);
- function calcOvercollAmount(uint amount) external view returns (uint);
- function stabilityFee() external view returns(uint);
- function debt() external view returns(uint);
-}
-
-contract MKRAssessor is Assessor {
- ClerkLike public clerk;
-
- uint public creditBufferTime = 1 days;
-
- function file(bytes32 name, uint value) public auth {
- if(name == "creditBufferTime") {
- creditBufferTime = value;
- return;
- }
- super.file(name, value);
- }
-
- function depend(bytes32 contractName, address addr) public auth {
- if (contractName == "clerk") {
- clerk = ClerkLike(addr);
- } else {
- super.depend(contractName, addr);
- }
- }
-
- function calcSeniorTokenPrice() external view returns(uint) {
- return calcSeniorTokenPrice(navFeed.approximatedNAV(), reserve.totalBalance());
- }
-
- function _calcSeniorTokenPrice(uint nav_, uint reserve_) internal view returns(uint) {
- // the coordinator interface will pass the reserveAvailable
-
- if ((nav_ == 0 && reserve_ == 0) || seniorTranche.tokenSupply() == 0) {
- // initial token price at start 1.00
- return ONE;
- }
-
- // reserve includes creditline from maker
- uint totalAssets = safeAdd(nav_, reserve_);
-
- // includes creditline
- uint seniorAssetValue = calcExpectedSeniorAsset(seniorDebt(), seniorBalance_);
-
- if(totalAssets < seniorAssetValue) {
- seniorAssetValue = totalAssets;
- }
- return rdiv(seniorAssetValue, seniorTranche.tokenSupply());
- }
-
- // calculates the tokenPrice based on the nav and the reserve
- function calcSeniorTokenPrice(uint nav_, uint) public view returns(uint) {
- return _calcSeniorTokenPrice(nav_, reserve.totalBalance());
- }
-
- function _calcJuniorTokenPrice(uint nav_, uint reserve_) internal view returns (uint) {
- if ((nav_ == 0 && reserve_ == 0) || juniorTranche.tokenSupply() == 0) {
- // initial token price at start 1.00
- return ONE;
- }
- // reserve includes creditline from maker
- uint totalAssets = safeAdd(nav_, reserve_);
-
- // includes creditline from mkr
- uint seniorAssetValue = calcExpectedSeniorAsset(seniorDebt(), seniorBalance_);
-
- if(totalAssets < seniorAssetValue) {
- return 0;
- }
-
- // the junior tranche only needs to pay for the mkr over-collateralization if
- // the mkr vault is liquidated, if that is true juniorStake=0
- return rdiv(safeAdd(safeSub(totalAssets, seniorAssetValue), clerk.juniorStake()),
- juniorTranche.tokenSupply());
- }
-
- function calcJuniorTokenPrice(uint nav_, uint) public view returns (uint) {
- return _calcJuniorTokenPrice(nav_, reserve.totalBalance());
- }
-
- function seniorBalance() public view returns(uint) {
- return safeAdd(seniorBalance_, remainingOvercollCredit());
- }
-
- function effectiveSeniorBalance() public view returns(uint) {
- return seniorBalance_;
- }
-
- function effectiveTotalBalance() public view returns(uint) {
- return reserve.totalBalance();
- }
-
- function totalBalance() public view returns(uint) {
- return safeAdd(reserve.totalBalance(), remainingCredit());
- }
-
- // returns the current NAV
- function currentNAV() public view returns(uint) {
- return navFeed.currentNAV();
- }
-
- // returns the approximated NAV for gas-performance reasons
- function getNAV() public view returns(uint) {
- return navFeed.approximatedNAV();
- }
-
- // changes the total amount available for borrowing loans
- function changeBorrowAmountEpoch(uint currencyAmount) public auth {
- reserve.file("currencyAvailable", currencyAmount);
- }
-
- // returns the remainingCredit plus a buffer for the interest increase
- function remainingCredit() public view returns(uint) {
- // over the time the remainingCredit will decrease because of the accumulated debt interest
- // therefore a buffer is reduced from the remainingCredit to prevent the usage of currency which is not available
- uint debt = clerk.debt();
- uint stabilityBuffer = safeSub(rmul(rpow(clerk.stabilityFee(),
- creditBufferTime, ONE), debt), debt);
- uint remainingCredit = clerk.remainingCredit();
- if(remainingCredit > stabilityBuffer) {
- return safeSub(remainingCredit, stabilityBuffer);
- }
- return 0;
- }
-
- function remainingOvercollCredit() public view returns(uint) {
- return clerk.calcOvercollAmount(remainingCredit());
- }
-}
diff --git a/src/lender/adapters/mkr/deployer.sol b/src/lender/adapters/mkr/deployer.sol
index 14075620..6e3dbf6f 100644
--- a/src/lender/adapters/mkr/deployer.sol
+++ b/src/lender/adapters/mkr/deployer.sol
@@ -84,7 +84,7 @@ contract MKRLenderDeployer is LenderDeployer {
MemberlistLike(seniorMemberlist).updateMember(clerk, uint(-1));
MemberlistLike(seniorMemberlist).updateMember(mkrMgr, uint(-1));
- DependLike(assessor).depend("clerk", clerk);
+ DependLike(assessor).depend("lending", clerk);
}
}
diff --git a/src/lender/adapters/mkr/fabs/assessor.sol b/src/lender/adapters/mkr/fabs/assessor.sol
deleted file mode 100644
index 6e621c3f..00000000
--- a/src/lender/adapters/mkr/fabs/assessor.sol
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) 2020 Centrifuge
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-pragma solidity >=0.5.15 <0.6.0;
-
-import { MKRAssessor } from "./../assessor.sol";
-
-contract MKRAssessorFab {
- function newAssessor() public returns (address) {
- MKRAssessor assessor = new MKRAssessor();
- assessor.rely(msg.sender);
- assessor.deny(address(this));
- return address(assessor);
- }
-}
diff --git a/src/lender/adapters/mkr/test/assessor.t.sol b/src/lender/adapters/mkr/test/assessor.t.sol
deleted file mode 100644
index d50a7044..00000000
--- a/src/lender/adapters/mkr/test/assessor.t.sol
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright (C) 2020 Centrifuge
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-pragma solidity >=0.5.15 <0.6.0;
-
-import "ds-test/test.sol";
-import "tinlake-math/math.sol";
-
-import "./../assessor.sol";
-import "./../../../test/mock/tranche.sol";
-import "./../../../test/mock/navFeed.sol";
-import "./../../../test/mock/reserve.sol";
-import "./../../../test/mock/clerk.sol";
-import "../../../../test/simple/token.sol";
-
-
-interface Hevm {
- function warp(uint256) external;
-}
-
-contract AssessorMKRTest is DSTest, Interest {
- Hevm hevm;
- MKRAssessor assessor;
- TrancheMock seniorTranche;
- TrancheMock juniorTranche;
- NAVFeedMock navFeed;
- ReserveMock reserveMock;
- SimpleToken currency;
-
- ClerkMock clerk;
-
- address seniorTranche_;
- address juniorTranche_;
- address navFeed_;
- address reserveMock_;
- address clerk_;
-
- function setUp() public {
- hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
- hevm.warp(1234567);
- currency = new SimpleToken("CUR", "Currency");
-
- seniorTranche = new TrancheMock();
- juniorTranche = new TrancheMock();
-
- seniorTranche_ = address(seniorTranche);
- juniorTranche_ = address(juniorTranche);
-
- navFeed = new NAVFeedMock();
- navFeed_ = address(navFeed);
-
- reserveMock = new ReserveMock(address(currency));
- reserveMock_ = address(reserveMock);
-
- clerk = new ClerkMock();
- clerk_ = address(clerk);
-
- assessor = new MKRAssessor();
- assessor.depend("juniorTranche", juniorTranche_);
- assessor.depend("seniorTranche", seniorTranche_);
- assessor.depend("navFeed", navFeed_);
- assessor.depend("reserve", reserveMock_);
- assessor.depend("clerk", clerk_);
- }
-
- function testSeniorBalance() public {
- uint remainingOvercollCredit = 90 ether;
- uint seniorSupply = 10 ether;
- assessor.changeSeniorAsset(seniorSupply, 0);
- clerk.setReturn("calcOvercollAmount", remainingOvercollCredit);
- // balance should not have an effect
- reserveMock.setReturn("balance", 1000 ether);
- assertEq(assessor.seniorBalance(), 100 ether);
- }
-
- function testTotalBalance() public {
- uint reserve = 10 ether;
- uint remainingCredit = 80 ether;
- reserveMock.setReturn("balance", reserve);
- clerk.setReturn("remainingCredit", remainingCredit);
- assertEq(assessor.totalBalance(), remainingCredit+reserve);
- }
-
- function testCalcSeniorTokenPrice() public {
- uint nav = 10 ether;
- navFeed.setReturn("approximatedNAV", nav);
- uint seniorSupply = 80 ether;
- reserveMock.setReturn("balance", 100 ether);
-
- assessor.changeSeniorAsset(seniorSupply, 0);
- seniorTranche.setReturn("tokenSupply", 40 ether);
-
- uint seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, 123123 ether);
- // seniorAsset: 80 ether, tokenSupply: 40 ether
- assertEq(seniorTokenPrice, 2 * 10**27);
-
- reserveMock.setReturn("balance", 30 ether);
- seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, 123123 ether);
- // seniorAsset: 40 ether, tokenSupply: 40 ether
- assertEq(seniorTokenPrice, 1 * 10**27);
- }
-
- function testCalcJuniorTokenPrice() public {
- uint nav = 10 ether;
- navFeed.setReturn("approximatedNAV", nav);
- uint seniorSupply = 80 ether;
- reserveMock.setReturn("balance", 90 ether);
-
- assessor.changeSeniorAsset(seniorSupply, 0);
- juniorTranche.setReturn("tokenSupply", 20 ether);
- uint juniorTokenPrice = assessor.calcJuniorTokenPrice(nav, 123123 ether);
-
- assertEq(juniorTokenPrice, 1 * 10**27);
-
- clerk.setReturn("juniorStake", 20 ether);
- juniorTokenPrice = assessor.calcJuniorTokenPrice(nav, 123123 ether);
-
- assertEq(juniorTokenPrice, 2 * 10**27);
- }
-
- function testTotalBalanceBuffer() public {
- uint nav = 20 ether;
- navFeed.setReturn("approximatedNAV", nav);
- uint reserve = 80 ether;
- reserveMock.setReturn("balance", reserve);
- assertEq(assessor.totalBalance(), 80 ether);
- // 5% per day)
- uint fee = 1000000593415115246806684338;
- clerk.setReturn("stabilityFee", fee);
-
- uint creditLine = 100 ether;
- uint debt = 20 ether;
- clerk.setReturn("remainingCredit", creditLine-debt);
- clerk.setReturn("debt", debt);
- uint expectedTotalBalance = safeAdd(reserve, creditLine-debt);
-
- uint interest = safeSub(rmul(rpow(clerk.stabilityFee(),
- safeSub(safeAdd(block.timestamp, assessor.creditBufferTime()), block.timestamp), ONE), debt), debt);
-
- expectedTotalBalance = expectedTotalBalance - interest;
- assertEq(assessor.totalBalance(), expectedTotalBalance);
- }
-
- function testSeniorBalanceBuffer() public {
- // add seniorBalance
- uint seniorSupply = 10 ether;
- assessor.changeSeniorAsset(seniorSupply, 0);
-
- uint effectiveSeniorBalance = assessor.effectiveSeniorBalance();
-
- // 5% per day)
- uint fee = 1000000593415115246806684338;
- clerk.setReturn("stabilityFee", fee);
-
- uint creditLine = 100 ether;
- uint debt = 20 ether;
- uint remainingCredit = creditLine-debt;
- clerk.setReturn("remainingCredit", remainingCredit);
- clerk.setReturn("debt", debt);
-
- uint interest = safeSub(rmul(rpow(clerk.stabilityFee(),
- safeSub(safeAdd(block.timestamp, assessor.creditBufferTime()), block.timestamp), ONE), debt), debt);
-
- uint overCollAmount = rmul(remainingCredit-interest, 1.1 * 10**27);
- clerk.setReturn("calcOvercollAmount", overCollAmount);
-
- uint expectedSeniorBalance = safeSub(overCollAmount, interest);
- assertEq(assessor.seniorBalance(), safeAdd(effectiveSeniorBalance, overCollAmount));
- }
-
- function testCalcJuniorRatio() public {
- uint nav = 20 ether;
- navFeed.setReturn("approximatedNAV", nav);
- uint reserve = 80 ether;
- reserveMock.setReturn("balance", reserve);
-
- // add seniorBalance
- uint seniorSupply = 80 ether;
- assessor.changeSeniorAsset(seniorSupply, 0);
-
- assertEq(assessor.calcJuniorRatio(), 0.2 * 10**27);
- }
-
- function testCalcJuniorRatioZero() public {
- assertEq(assessor.calcJuniorRatio(), 0);
- }
-
- function testCalcJuniorRatioNoSeniorAsset() public {
- uint nav = 20 ether;
- navFeed.setReturn("approximatedNAV", nav);
- uint reserve = 80 ether;
- reserveMock.setReturn("balance", reserve);
-
- assertEq(assessor.calcJuniorRatio(), ONE);
- }
-
- function testCalcJuniorRatioJuniorAllLost() public {
- uint nav = 20 ether;
- navFeed.setReturn("approximatedNAV", nav);
- uint reserve = 80 ether;
- reserveMock.setReturn("balance", reserve);
-
- // add seniorBalance
- uint seniorSupply = 110 ether;
- assessor.changeSeniorAsset(seniorSupply, 0);
-
- assertEq(assessor.calcJuniorRatio(), 0);
- }
-}
diff --git a/src/lender/admin/pool.sol b/src/lender/admin/pool.sol
index 2b0fca1d..7901fd04 100644
--- a/src/lender/admin/pool.sol
+++ b/src/lender/admin/pool.sol
@@ -20,7 +20,7 @@ interface AssessorLike {
function file(bytes32 name, uint256 value) external;
}
-interface LendingAdapter {
+interface LendingAdapterLike {
function raise(uint256 amount) external;
function sink(uint256 amount) external;
}
@@ -34,7 +34,7 @@ interface MemberlistLike {
contract PoolAdmin is Auth {
AssessorLike public assessor;
- LendingAdapter public lending;
+ LendingAdapterLike public lending;
MemberlistLike public seniorMemberlist;
MemberlistLike public juniorMemberlist;
@@ -63,7 +63,7 @@ contract PoolAdmin is Auth {
if (contractName == "assessor") {
assessor = AssessorLike(addr);
} else if (contractName == "lending") {
- lending = LendingAdapter(addr);
+ lending = LendingAdapterLike(addr);
} else if (contractName == "seniorMemberlist") {
seniorMemberlist = MemberlistLike(addr);
} else if (contractName == "juniorMemberlist") {
diff --git a/src/lender/assessor.sol b/src/lender/assessor.sol
index b35598a6..df263c4a 100644
--- a/src/lender/assessor.sol
+++ b/src/lender/assessor.sol
@@ -34,6 +34,14 @@ interface ReserveLike {
function currencyAvailable() external view returns(uint);
}
+interface LendingAdapter {
+ function remainingCredit() external view returns (uint);
+ function juniorStake() external view returns (uint);
+ function calcOvercollAmount(uint amount) external view returns (uint);
+ function stabilityFee() external view returns(uint);
+ function debt() external view returns(uint);
+}
+
contract Assessor is Definitions, Auth, Interest {
// senior ratio from the last epoch executed
Fixed27 public seniorRatio;
@@ -56,10 +64,13 @@ contract Assessor is Definitions, Auth, Interest {
uint public maxReserve;
+ uint public creditBufferTime = 1 days;
+
TrancheLike public seniorTranche;
TrancheLike public juniorTranche;
NAVFeedLike public navFeed;
ReserveLike public reserve;
+ LendingAdapter public lending;
constructor() public {
wards[msg.sender] = 1;
@@ -77,23 +88,28 @@ contract Assessor is Definitions, Auth, Interest {
juniorTranche = TrancheLike(addr);
} else if (contractName == "reserve") {
reserve = ReserveLike(addr);
+ } else if (contractName == "lending") {
+ lending = LendingAdapter(addr);
} else revert();
}
function file(bytes32 name, uint value) public auth {
- if(name == "seniorInterestRate") {
+ if (name == "seniorInterestRate") {
+ dripSeniorDebt();
seniorInterestRate = Fixed27(value);
- }
- else if (name == "maxReserve") {maxReserve = value;}
- else if (name == "maxSeniorRatio") {
+ } else if (name == "maxReserve") {
+ maxReserve = value;
+ } else if (name == "maxSeniorRatio") {
require(value > minSeniorRatio.value, "value-too-small");
maxSeniorRatio = Fixed27(value);
- }
- else if (name == "minSeniorRatio") {
+ } else if (name == "minSeniorRatio") {
require(value < maxSeniorRatio.value, "value-too-big");
minSeniorRatio = Fixed27(value);
+ } else if (name == "creditBufferTime") {
+ creditBufferTime = value;
+ } else {
+ revert("unknown-variable");
}
- else {revert("unknown-variable");}
}
function reBalance(uint seniorAsset_, uint seniorRatio_) internal {
@@ -133,11 +149,19 @@ contract Assessor is Definitions, Auth, Interest {
}
function calcSeniorTokenPrice() external view returns(uint) {
- return calcSeniorTokenPrice(navFeed.currentNAV(), reserve.totalBalance());
+ return calcSeniorTokenPrice(navFeed.approximatedNAV(), reserve.totalBalance());
+ }
+
+ function calcSeniorTokenPrice(uint nav_, uint) public view returns(uint) {
+ return _calcSeniorTokenPrice(nav_, reserve.totalBalance());
}
function calcJuniorTokenPrice() external view returns(uint) {
- return calcJuniorTokenPrice(navFeed.currentNAV(), reserve.totalBalance());
+ return _calcJuniorTokenPrice(navFeed.currentNAV(), reserve.totalBalance());
+ }
+
+ function calcJuniorTokenPrice(uint nav_, uint) public view returns (uint) {
+ return _calcJuniorTokenPrice(nav_, reserve.totalBalance());
}
function calcTokenPrices() external view returns (uint, uint) {
@@ -147,15 +171,21 @@ contract Assessor is Definitions, Auth, Interest {
}
function calcTokenPrices(uint epochNAV, uint epochReserve) public view returns (uint, uint) {
- return (calcJuniorTokenPrice(epochNAV, epochReserve), calcSeniorTokenPrice(epochNAV, epochReserve));
+ return (_calcJuniorTokenPrice(epochNAV, epochReserve), _calcSeniorTokenPrice(epochNAV, epochReserve));
}
- function calcSeniorTokenPrice(uint epochNAV, uint epochReserve) public view returns(uint) {
- if ((epochNAV == 0 && epochReserve == 0) || seniorTranche.tokenSupply() == 0) {
+ function _calcSeniorTokenPrice(uint nav_, uint reserve_) internal view returns(uint) {
+ // the coordinator interface will pass the reserveAvailable
+
+ if ((nav_ == 0 && reserve_ == 0) || seniorTranche.tokenSupply() == 0) {
// initial token price at start 1.00
return ONE;
}
- uint totalAssets = safeAdd(epochNAV, epochReserve);
+
+ // reserve includes creditline from maker
+ uint totalAssets = safeAdd(nav_, reserve_);
+
+ // includes creditline
uint seniorAssetValue = calcExpectedSeniorAsset(seniorDebt(), seniorBalance_);
if(totalAssets < seniorAssetValue) {
@@ -164,19 +194,30 @@ contract Assessor is Definitions, Auth, Interest {
return rdiv(seniorAssetValue, seniorTranche.tokenSupply());
}
- function calcJuniorTokenPrice(uint epochNAV, uint epochReserve) public view returns(uint) {
- if ((epochNAV == 0 && epochReserve == 0) || juniorTranche.tokenSupply() == 0) {
+ function _calcJuniorTokenPrice(uint nav_, uint reserve_) internal view returns (uint) {
+ if ((nav_ == 0 && reserve_ == 0) || juniorTranche.tokenSupply() == 0) {
// initial token price at start 1.00
return ONE;
}
- uint totalAssets = safeAdd(epochNAV, epochReserve);
+ // reserve includes creditline from maker
+ uint totalAssets = safeAdd(nav_, reserve_);
+
+ // includes creditline from mkr
uint seniorAssetValue = calcExpectedSeniorAsset(seniorDebt(), seniorBalance_);
if(totalAssets < seniorAssetValue) {
return 0;
}
- return rdiv(safeSub(totalAssets, seniorAssetValue), juniorTranche.tokenSupply());
+ // the junior tranche only needs to pay for the mkr over-collateralization if
+ // the mkr vault is liquidated, if that is true juniorStake=0
+ uint juniorStake = 0;
+ if (address(lending) != address(0)) {
+ juniorStake = lending.juniorStake();
+ }
+
+ return rdiv(safeAdd(safeSub(totalAssets, seniorAssetValue), juniorStake),
+ juniorTranche.tokenSupply());
}
/// repayment update keeps track of senior bookkeeping for repaid loans
@@ -239,14 +280,32 @@ contract Assessor is Definitions, Auth, Interest {
return seniorDebt_;
}
- function seniorBalance() public view returns (uint) {
+ function seniorBalance() public view returns(uint) {
+ return safeAdd(seniorBalance_, remainingOvercollCredit());
+ }
+
+ function effectiveSeniorBalance() public view returns(uint) {
return seniorBalance_;
}
- function totalBalance() public view returns (uint) {
+ function effectiveTotalBalance() public view returns(uint) {
return reserve.totalBalance();
}
+ function totalBalance() public view returns(uint) {
+ return safeAdd(reserve.totalBalance(), remainingCredit());
+ }
+
+ // returns the current NAV
+ function currentNAV() public view returns(uint) {
+ return navFeed.currentNAV();
+ }
+
+ // returns the approximated NAV for gas-performance reasons
+ function getNAV() public view returns(uint) {
+ return navFeed.approximatedNAV();
+ }
+
// changes the total amount available for borrowing loans
function changeBorrowAmountEpoch(uint currencyAmount) public auth {
reserve.file("currencyAvailable", currencyAmount);
@@ -276,4 +335,31 @@ contract Assessor is Definitions, Auth, Interest {
return safeSub(ONE, rdiv(seniorAsset, assets));
}
+
+ // returns the remainingCredit plus a buffer for the interest increase
+ function remainingCredit() public view returns(uint) {
+ if (address(lending) == address(0)) {
+ return 0;
+ }
+
+ // over the time the remainingCredit will decrease because of the accumulated debt interest
+ // therefore a buffer is reduced from the remainingCredit to prevent the usage of currency which is not available
+ uint debt = lending.debt();
+ uint stabilityBuffer = safeSub(rmul(rpow(lending.stabilityFee(),
+ creditBufferTime, ONE), debt), debt);
+ uint remainingCredit = lending.remainingCredit();
+ if(remainingCredit > stabilityBuffer) {
+ return safeSub(remainingCredit, stabilityBuffer);
+ }
+
+ return 0;
+ }
+
+ function remainingOvercollCredit() public view returns(uint) {
+ if (address(lending) == address(0)) {
+ return 0;
+ }
+
+ return lending.calcOvercollAmount(remainingCredit());
+ }
}
diff --git a/src/lender/test/assessor.t.sol b/src/lender/test/assessor.t.sol
index 36b86e4f..36ccbde2 100644
--- a/src/lender/test/assessor.t.sol
+++ b/src/lender/test/assessor.t.sol
@@ -22,6 +22,7 @@ import "./../assessor.sol";
import "./mock/tranche.sol";
import "./mock/navFeed.sol";
import "./mock/reserve.sol";
+import "./mock/clerk.sol";
import "../../test/simple/token.sol";
interface Hevm {
@@ -36,11 +37,13 @@ contract AssessorTest is DSTest, Math {
NAVFeedMock navFeed;
ReserveMock reserveMock;
SimpleToken currency;
+ ClerkMock clerk;
address seniorTranche_;
address juniorTranche_;
address navFeed_;
address reserveMock_;
+ address clerk_;
function setUp() public {
hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
@@ -56,15 +59,18 @@ contract AssessorTest is DSTest, Math {
navFeed = new NAVFeedMock();
navFeed_ = address(navFeed);
-
reserveMock = new ReserveMock(address(currency));
reserveMock_ = address(reserveMock);
+ clerk = new ClerkMock();
+ clerk_ = address(clerk);
+
assessor = new Assessor();
assessor.depend("juniorTranche", juniorTranche_);
assessor.depend("seniorTranche", seniorTranche_);
assessor.depend("navFeed", navFeed_);
assessor.depend("reserve", reserveMock_);
+ assessor.depend("lending", clerk_);
}
function testCurrentNAV() public {
@@ -259,101 +265,40 @@ contract AssessorTest is DSTest, Math {
}
function testCalcSeniorTokenPrice() public {
- assertEq(assessor.calcSeniorTokenPrice(0,0), ONE);
-
- uint reserve = 50 ether;
- uint nav = 50 ether;
+ uint nav = 10 ether;
+ navFeed.setReturn("approximatedNAV", nav);
+ uint seniorSupply = 80 ether;
+ reserveMock.setReturn("balance", 100 ether);
- seniorTranche.setReturn("tokenSupply", 0);
- uint seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, reserve);
- assertEq(seniorTokenPrice, ONE);
-
- navFeed.setReturn("approximatedNAV", 200 ether);
- reserveMock.setReturn("balance", 200 ether);
-
- uint seniorSupply = 200 ether;
-
- // seniorRatio 50%
assessor.changeSeniorAsset(seniorSupply, 0);
+ seniorTranche.setReturn("tokenSupply", 40 ether);
- assertEq(assessor.seniorDebt(), 100 ether);
- assertEq(assessor.seniorBalance(), 100 ether);
-
-
- seniorTranche.setReturn("tokenSupply", 100 ether);
- reserve = 100 ether;
- nav = 100 ether;
- seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, reserve);
- // token price 2.0
- assertEq(seniorTokenPrice, 2 * 10 ** 27);
-
-
- reserve = 1000 ether;
- nav = 100 ether;
- seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, reserve);
- assertEq(seniorTokenPrice, 2 * 10 ** 27);
+ uint seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, 123123 ether);
+ // seniorAsset: 80 ether, tokenSupply: 40 ether
+ assertEq(seniorTokenPrice, 2 * 10**27);
- reserve = 100 ether;
- nav = 1000 ether;
- seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, reserve);
- assertEq(seniorTokenPrice, 2 * 10 ** 27);
-
- reserve = 25 ether;
- nav = 25 ether;
- seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, reserve);
- // price: 0.5
- assertEq(seniorTokenPrice, 5 * 10 ** 26);
+ reserveMock.setReturn("balance", 30 ether);
+ seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, 123123 ether);
+ // seniorAsset: 40 ether, tokenSupply: 40 ether
+ assertEq(seniorTokenPrice, 1 * 10**27);
}
function testCalcJuniorTokenPrice() public {
- assertEq(assessor.calcJuniorTokenPrice(0,0), ONE);
-
- uint reserve = 50 ether;
- uint nav = 50 ether;
-
- juniorTranche.setReturn("tokenSupply", 0);
- uint juniorTokenPrice = assessor.calcJuniorTokenPrice(nav, reserve);
- assertEq(juniorTokenPrice, ONE);
-
- // set up senior asset
- navFeed.setReturn("approximatedNAV", 200 ether);
- reserveMock.setReturn("balance", 200 ether);
-
- uint seniorSupply = 200 ether;
+ uint nav = 10 ether;
+ navFeed.setReturn("approximatedNAV", nav);
+ uint seniorSupply = 80 ether;
+ reserveMock.setReturn("balance", 90 ether);
- // seniorRatio 50%
assessor.changeSeniorAsset(seniorSupply, 0);
+ juniorTranche.setReturn("tokenSupply", 20 ether);
+ uint juniorTokenPrice = assessor.calcJuniorTokenPrice(nav, 123123 ether);
- assertEq(assessor.seniorDebt(), 100 ether);
- assertEq(assessor.seniorBalance(), 100 ether);
-
- reserve = 300 ether;
- nav = 200 ether;
-
- juniorTranche.setReturn("tokenSupply", 100 ether);
- juniorTokenPrice = assessor.calcJuniorTokenPrice(nav, reserve);
- // NAV + Reserve = 500 ether
- // seniorAsset = 200 ether
- // juniorAsset = 300 ether
-
- // junior price: 3.0
- assertEq(juniorTokenPrice, 3 * 10 ** 27);
-
- reserve = 300 ether;
- nav = 0 ether;
-
- juniorTranche.setReturn("tokenSupply", 100 ether);
- juniorTokenPrice = assessor.calcJuniorTokenPrice(nav, reserve);
- assertEq(juniorTokenPrice, ONE);
+ assertEq(juniorTokenPrice, 1 * 10**27);
- reserve = 150 ether;
- nav = 0 ether;
- juniorTokenPrice = assessor.calcJuniorTokenPrice(nav, reserve);
- assertEq(juniorTokenPrice, 0);
+ clerk.setReturn("juniorStake", 20 ether);
+ juniorTokenPrice = assessor.calcJuniorTokenPrice(nav, 123123 ether);
- seniorTranche.setReturn("tokenSupply", 200 ether);
- uint seniorTokenPrice = assessor.calcSeniorTokenPrice(nav, reserve);
- assertEq(seniorTokenPrice, 75 * 10**25);
+ assertEq(juniorTokenPrice, 2 * 10**27);
}
function testCalcTokenPrices() public {
diff --git a/src/test/system/lender/mkr/mkr_basic.t.sol b/src/test/system/lender/mkr/mkr_basic.t.sol
index df9e2b85..3482c05a 100644
--- a/src/test/system/lender/mkr/mkr_basic.t.sol
+++ b/src/test/system/lender/mkr/mkr_basic.t.sol
@@ -19,11 +19,11 @@ pragma experimental ABIEncoderV2;
import "../../test_suite.sol";
import "tinlake-math/interest.sol";
import {BaseTypes} from "../../../../lender/test/coordinator-base.t.sol";
-import { MKRAssessor }from "../../../../lender/adapters/mkr/assessor.sol";
+import { Assessor }from "../../../../lender/assessor.sol";
contract MKRTestBasis is TestSuite, Interest {
- MKRAssessor mkrAssessor;
+ Assessor mkrAssessor;
function setUp() public {
// setup hevm
@@ -37,7 +37,7 @@ contract MKRTestBasis is TestSuite, Interest {
nftFeed_ = NFTFeedLike(address(nftFeed));
root.relyContract(address(clerk), address(this));
- mkrAssessor = MKRAssessor(address(assessor));
+ mkrAssessor = assessor;
mkr.depend("currency" ,currency_);
mkr.depend("drop", mkrLenderDeployer.seniorToken());
}
diff --git a/src/test/system/lender/mkr/mkr_scenarios.t.sol b/src/test/system/lender/mkr/mkr_scenarios.t.sol
index 9f9ab44b..831944ac 100644
--- a/src/test/system/lender/mkr/mkr_scenarios.t.sol
+++ b/src/test/system/lender/mkr/mkr_scenarios.t.sol
@@ -19,7 +19,6 @@ pragma experimental ABIEncoderV2;
import "../../test_suite.sol";
import "tinlake-math/interest.sol";
import {BaseTypes} from "../../../../lender/test/coordinator-base.t.sol";
-import { MKRAssessor }from "../../../../lender/adapters/mkr/assessor.sol";
import {MKRTestBasis} from "./mkr_basic.t.sol";
contract MKRLenderSystemTest is MKRTestBasis {
diff --git a/src/test/system/setup.sol b/src/test/system/setup.sol
index 2af4a161..54284bc8 100644
--- a/src/test/system/setup.sol
+++ b/src/test/system/setup.sol
@@ -49,7 +49,6 @@ import { LenderDeployer } from "../../lender/deployer.sol";
// MKR
import { MKRLenderDeployer } from "../../lender/adapters/mkr/deployer.sol";
import { ClerkFab } from "../../lender/adapters/mkr/fabs/clerk.sol";
-import { MKRAssessorFab }from "../../lender/adapters/mkr/fabs/assessor.sol";
import { Title } from "tinlake-title/title.sol";
import { Pile } from "../../borrower/pile.sol";
@@ -242,7 +241,7 @@ contract TestSetup is Config {
function prepareMKRLenderDeployer(address rootAddr, address trancheFab, address memberlistFab, address restrictedTokenFab,
address reserveFab, address coordinatorFab, address operatorFab, address assessorAdminFab) public {
- MKRAssessorFab assessorFab = new MKRAssessorFab();
+ AssessorFab assessorFab = new AssessorFab();
ClerkFab clerkFab = new ClerkFab();
mkrLenderDeployer = new MKRLenderDeployer(rootAddr, currency_, address(trancheFab), address(memberlistFab),