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),