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

feat: replace reserves with origination fee #233

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/core/AccountManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ contract AccountManager is Pausable, IAccountManager {
IAccount(account).addAsset(token);
if (ILToken(registry.LTokenFor(token)).lendTo(account, amt))
IAccount(account).addBorrow(token);
if (!riskEngine.isAccountHealthy(account))
revert Errors.RiskThresholdBreached();
emit Borrow(account, msg.sender, token, amt);
}

Expand Down
2 changes: 1 addition & 1 deletion src/interface/tokens/ILToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface ILToken {
string calldata _name,
string calldata _symbol,
IRegistry _registry,
uint _reserveFactor,
uint _originationFee,
address treasury,
uint _min_mint
) external;
Expand Down
64 changes: 64 additions & 0 deletions src/test/account/OriginationFee.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "forge-std/Test.sol";
import {TestBase} from "../utils/TestBase.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {IAccount} from "../../interface/core/IAccount.sol";

import {LEther} from "../../tokens/LEther.sol";
import {LToken} from "../../tokens/LToken.sol";
import {Proxy} from "../../proxy/Proxy.sol";

contract OriginationFeeTests is TestBase {
using FixedPointMathLib for uint96;
using FixedPointMathLib for uint;

address public account;
address lp = cheats.addr(100);
address borrower = cheats.addr(101);

uint fee = 1e3;

function setUp() public {
setupContracts();
lEth = LEther(payable(address(new Proxy(address(lEthImplementation)))));
lEth.init(weth, "LEther", "LEth", registry, fee, treasury, 0);

lErc20 = LToken(address(new Proxy(address(lErc20Implementation))));
lErc20.init(erc20, "LTestERC20", "LERC20", registry, fee, treasury, 0);

registry.setLToken(address(weth), address(lEth));
registry.setLToken(address(erc20), address(lErc20));

lEth.initDep('RATE_MODEL');
lErc20.initDep('RATE_MODEL');
account = openAccount(borrower);
}

function testOriginationFee(uint96 depositAmt, uint96 borrowAmt) public {
cheats.assume(borrowAmt > 10 ** (18 - 2));
// Test
cheats.assume(
(uint(depositAmt) + borrowAmt).divWadDown(borrowAmt) >
riskEngine.balanceToBorrowThreshold()
);
deposit(borrower, account, address(erc20), depositAmt);
borrow(borrower, account, address(erc20), borrowAmt);

// Assert
assertTrue(!IAccount(account).hasNoDebt());
assertEq(erc20.balanceOf(address(lErc20)), 0);
assertEq(lErc20.getBorrowBalance(address(account)), borrowAmt);
assertEq(
erc20.balanceOf(address(account)),
uint(depositAmt) + borrowAmt - borrowAmt.mulDivDown(fee, 10 ** erc20.decimals())
);
assertEq(
erc20.balanceOf(treasury),
borrowAmt.mulDivDown(fee, 10 ** erc20.decimals())
);
}

}

85 changes: 0 additions & 85 deletions src/test/account/Reserves.t.sol

This file was deleted.

4 changes: 2 additions & 2 deletions src/test/utils/TestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ contract TestBase is Test {

lEthImplementation = new LEther();
lEth = LEther(payable(address(new Proxy(address(lEthImplementation)))));
lEth.init(weth, "LEther", "LEth", registry, 1e17, treasury, 0);
lEth.init(weth, "LEther", "LEth", registry, 0, treasury, 0);

lErc20Implementation = new LToken();
lErc20 = LToken(address(new Proxy(address(lErc20Implementation))));
lErc20.init(erc20, "LTestERC20", "LERC20", registry, 1e17, treasury, 0);
lErc20.init(erc20, "LTestERC20", "LERC20", registry, 0, treasury, 0);
}

function register() private {
Expand Down
34 changes: 13 additions & 21 deletions src/tokens/LToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,8 @@ contract LToken is Pausable, ERC4626, ILToken {
/// @notice Timestamp of when the state of the LToken was last updated
uint public lastUpdated;

/// @notice Protocol reserves
uint public reserves;

/// @notice Reserve factor
uint public reserveFactor;
/// @notice Origination Fee
uint public originationFee;

/// @notice Total borrow shares minted
uint public totalBorrowShares;
Expand Down Expand Up @@ -82,7 +79,7 @@ contract LToken is Pausable, ERC4626, ILToken {
@param _name Name of LToken
@param _symbol Symbol of LToken
@param _registry Address of Registry
@param _reserveFactor Borrow Fee
@param _originationFee origination fee
@param _treasury Protocol treasury
@param _reserveShares Minimum amount of shares minted to zero address
*/
Expand All @@ -91,7 +88,7 @@ contract LToken is Pausable, ERC4626, ILToken {
string calldata _name,
string calldata _symbol,
IRegistry _registry,
uint _reserveFactor,
uint _originationFee,
address _treasury,
uint _reserveShares
) external {
Expand All @@ -107,7 +104,7 @@ contract LToken is Pausable, ERC4626, ILToken {
initPausable(msg.sender);
initERC4626(_asset, _name, _symbol, _reserveShares);
registry = _registry;
reserveFactor = _reserveFactor;
originationFee = _originationFee;
treasury = _treasury;
}

Expand Down Expand Up @@ -142,7 +139,11 @@ contract LToken is Pausable, ERC4626, ILToken {
borrowsOf[account] += borrowShares;

borrows += amt;
asset.safeTransfer(account, amt);

uint fee = amt.mulDivDown(originationFee, 10 ** decimals);
asset.safeTransfer(treasury, fee);
asset.safeTransfer(account, amt - fee);

return isFirstBorrow;
}

Expand Down Expand Up @@ -175,11 +176,6 @@ contract LToken is Pausable, ERC4626, ILToken {
return convertBorrowSharesToAsset(borrowsOf[account]);
}

function getReserves() public view returns (uint) {
return reserves + borrows.mulWadUp(getRateFactor())
.mulWadUp(reserveFactor);
}

/* -------------------------------------------------------------------------- */
/* PUBLIC FUNCTIONS */
/* -------------------------------------------------------------------------- */
Expand All @@ -191,7 +187,7 @@ contract LToken is Pausable, ERC4626, ILToken {
@return totalAssets Total amount of underlying assets
*/
function totalAssets() public view override returns (uint) {
return asset.balanceOf(address(this)) + getBorrows() - getReserves();
return asset.balanceOf(address(this)) + getBorrows();
}

function getBorrows() public view returns (uint) {
Expand All @@ -204,7 +200,6 @@ contract LToken is Pausable, ERC4626, ILToken {
uint rateFactor = getRateFactor();
uint interestAccrued = borrows.mulWadUp(rateFactor);
borrows += interestAccrued;
reserves += interestAccrued.mulWadUp(reserveFactor);
lastUpdated = block.timestamp;
}

Expand Down Expand Up @@ -245,10 +240,7 @@ contract LToken is Pausable, ERC4626, ILToken {
/* ADMIN FUNCTIONS */
/* -------------------------------------------------------------------------- */

function redeemReserves(uint amt) external adminOnly {
updateState();
reserves -= amt;
emit ReservesRedeemed(treasury, amt);
asset.safeTransfer(treasury, amt);
function updateOriginationFee(uint _originationFee) external adminOnly {
originationFee = _originationFee;
}
}