Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[main][fix] LibShareUtil rounding #422

Merged
merged 3 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions solidity/contracts/money-market/libraries/LibShareUtil.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ library LibShareUtil {
) internal pure returns (uint256) {
uint256 _shares = valueToShare(_tokenAmount, _totalShare, _totalValue);
uint256 _shareValues = shareToValue(_shares, _totalValue, _totalShare);
if (_shareValues + 1 == _tokenAmount) {

if (_shareValues + 1 <= _tokenAmount) {
_shares += 1;
}
return _shares;
Expand All @@ -46,7 +47,7 @@ library LibShareUtil {
) internal pure returns (uint256) {
uint256 _values = shareToValue(_shareAmount, _totalValue, _totalShare);
uint256 _valueShares = valueToShare(_values, _totalShare, _totalValue);
if (_valueShares + 1 == _shareAmount) {
if (_valueShares + 1 <= _shareAmount) {
_values += 1;
}
return _values;
Expand Down
27 changes: 27 additions & 0 deletions solidity/tests/money-market/MoneyMarket_BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { IMMOwnershipFacet } from "../../contracts/money-market/interfaces/IMMOw
import { IMoneyMarketAccountManager } from "../../contracts/interfaces/IMoneyMarketAccountManager.sol";
import { IFlashloanFacet } from "../../contracts/money-market/interfaces/IFlashloanFacet.sol";
import { IERC20 } from "../../contracts/money-market/interfaces/IERC20.sol";
import { TestHelperFacet } from "solidity/tests/money-market/utils/TestHelperFacet.sol";
import { IMMDiamondCut } from "solidity/contracts/money-market/interfaces/IMMDiamondCut.sol";

// mocks
import { MockERC20 } from "../mocks/MockERC20.sol";
Expand Down Expand Up @@ -46,6 +48,8 @@ abstract contract MoneyMarket_BaseTest is BaseTest {
ILiquidationFacet internal liquidationFacet;
IMMOwnershipFacet internal MMOwnershipFacet;
IFlashloanFacet internal flashloanFacet;
// helper facet for test only
TestHelperFacet internal testHelperFacet;

MockAlpacaV2Oracle internal mockOracle;

Expand All @@ -64,6 +68,10 @@ abstract contract MoneyMarket_BaseTest is BaseTest {
MMOwnershipFacet = IMMOwnershipFacet(moneyMarketDiamond);
flashloanFacet = IFlashloanFacet(moneyMarketDiamond);

//
setUpTestHelperFacet();
testHelperFacet = TestHelperFacet(moneyMarketDiamond);

address[] memory _whitelistedCallers = new address[](1);
_whitelistedCallers[0] = moneyMarketDiamond;
miniFL.setWhitelistedCallers(_whitelistedCallers, true);
Expand Down Expand Up @@ -237,4 +245,23 @@ abstract contract MoneyMarket_BaseTest is BaseTest {
// set minimum debt required to borrow
adminFacet.setMinDebtSize(normalizeEther(0.1 ether, usdDecimal));
}

function setUpTestHelperFacet() internal {
TestHelperFacet _testHelperFacet = new TestHelperFacet();
//
bytes4[] memory _selectors = new bytes4[](2);
_selectors[0] = TestHelperFacet.writeGlobalDebts.selector;
_selectors[1] = TestHelperFacet.writeoverCollatDebtValues.selector;

//
IMMDiamondCut.FacetCut[] memory _facetCuts = new IMMDiamondCut.FacetCut[](1);

_facetCuts[0] = IMMDiamondCut.FacetCut({
action: IMMDiamondCut.FacetCutAction.Add,
facetAddress: address(_testHelperFacet),
functionSelectors: _selectors
});

IMMDiamondCut(moneyMarketDiamond).diamondCut(_facetCuts, address(0), "");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.19;

import { MoneyMarket_BaseTest, MockERC20, console } from "../MoneyMarket_BaseTest.t.sol";
import { FixedInterestRateModel, IInterestRateModel } from "../../../contracts/money-market/interest-models/FixedInterestRateModel.sol";

// libraries
import { LibMoneyMarket01 } from "../../../contracts/money-market/libraries/LibMoneyMarket01.sol";
Expand Down Expand Up @@ -416,7 +417,7 @@ contract MoneyMarket_OverCollatBorrow_BorrowTest is MoneyMarket_BaseTest {
assertEq(_miniFL.getUserTotalAmountOf(_poolId, BOB), _borrowAmount);
}

function testRevert_WhenDemoteMarket_UserHasMoreThanOneIsolate_ShouldNotBeAbleToBorrow() public {
function testRevert_WhenDemoteMarket_UserHasMoreThanOneIsolate_ShouldNotBeAbleToBorrow() external {
// prepare
usdc.mint(ALICE, 1e10);
vm.prank(ALICE);
Expand Down Expand Up @@ -472,4 +473,60 @@ contract MoneyMarket_OverCollatBorrow_BorrowTest is MoneyMarket_BaseTest {
vm.expectRevert(abi.encodeWithSelector(IBorrowFacet.BorrowFacet_InvalidAssetTier.selector));
accountManager.borrow(subAccount0, address(btc), 0.01 ether);
}

function testCorrectness_WhenUerBorrowTokenFromMM_WithShareValueMoreThanTwo_MMShouldCalculateShareToAddCorrectly()
external
{
FixedInterestRateModel model = new FixedInterestRateModel(wethDecimal);
adminFacet.setInterestModel(address(weth), address(model));

deal(address(weth), ALICE, 20 ether);
vm.startPrank(ALICE);
// just add collateral for borrowing power
accountManager.addCollateralFor(ALICE, subAccount0, address(weth), normalizeEther(10 ether, wethDecimal));
accountManager.addCollateralFor(BOB, subAccount0, address(weth), normalizeEther(10 ether, wethDecimal));

uint256 _borrowAmount = 1.000000000000000001 ether;

accountManager.borrow(subAccount0, address(weth), normalizeEther(_borrowAmount, wethDecimal));

vm.startPrank(moneyMarketDiamond);

// fabricate contract state for assertion
vm.warp(block.timestamp + 1000);
borrowFacet.accrueInterest(address(weth));
testHelperFacet.writeGlobalDebts(address(weth), 2 ether);
testHelperFacet.writeoverCollatDebtValues(address(weth), 2 ether);

uint256 wethGlobalDebt = viewFacet.getGlobalDebtValue(address(weth));

assertEq(wethGlobalDebt, 2 ether);

(uint256 _aliceDebtShare, uint256 _aliceDebtAmount) = viewFacet.getOverCollatDebtShareAndAmountOf(
ALICE,
subAccount0,
address(weth)
);

vm.stopPrank();

vm.startPrank(BOB);

accountManager.borrow(subAccount0, address(weth), normalizeEther(1.000000000000000002 ether, wethDecimal));

// shares = amount * share / totalDebtValue = 1.000000000000000002 * 1.000000000000000001 / 2.000000000000000000 = 0.500000000000000001
// sharesValue = _shares * _totalValue / _totalShare = 0.500000000000000001 * 2.000000000000000000 / 1.000000000000000001 = 1.000000000000000000
// sharesValue + 1 <= _tokenAmount = 1.000000000000000000 + 1 <= 1.000000000000000002
// _shares = _shares+1 = 0.500000000000000001 + 1 = 0.500000000000000002
(uint256 _bobDebtShare, uint256 _bobDebtAmount) = viewFacet.getOverCollatDebtShareAndAmountOf(
BOB,
subAccount0,
address(weth)
);

assertEq(_bobDebtShare, 0.500000000000000002 ether);
assertEq(_bobDebtAmount, 1.000000000000000002 ether);

vm.stopPrank();
}
}
19 changes: 19 additions & 0 deletions solidity/tests/money-market/utils/TestHelperFacet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import { LibMoneyMarket01 } from "solidity/contracts/money-market/libraries/LibMoneyMarket01.sol";

/// @title A HelperFacet for faciliating test
contract TestHelperFacet {
function writeGlobalDebts(address _token, uint256 _newAmount) public {
LibMoneyMarket01.MoneyMarketDiamondStorage storage moneyMarketDs = LibMoneyMarket01.moneyMarketDiamondStorage();

moneyMarketDs.globalDebts[_token] = _newAmount;
}

function writeoverCollatDebtValues(address _token, uint256 _newAmount) public {
LibMoneyMarket01.MoneyMarketDiamondStorage storage moneyMarketDs = LibMoneyMarket01.moneyMarketDiamondStorage();

moneyMarketDs.overCollatDebtValues[_token] = _newAmount;
}
}
Loading