Skip to content

Commit

Permalink
feat: add origination fee to LToken (#236)
Browse files Browse the repository at this point in the history
* feat: add origination fee to LToken

* fix: remove redundant call to riskEngine

* fix: tests
  • Loading branch information
r0ohafza authored Oct 18, 2022
1 parent c0af90e commit c93c7ea
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 111 deletions.
4 changes: 2 additions & 2 deletions src/core/AccountManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,12 @@ contract AccountManager is ReentrancyGuard, Pausable, IAccountManager {
{
if (registry.LTokenFor(token) == address(0))
revert Errors.LTokenUnavailable();
if (!riskEngine.isBorrowAllowed(account, token, amt))
revert Errors.RiskThresholdBreached();
if (IAccount(account).hasAsset(token) == false)
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,
uint _maxSupply
Expand Down
63 changes: 63 additions & 0 deletions src/test/account/OriginationFee.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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, type(uint).max);

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

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, type(uint).max);
lEth.init(weth, "LEther", "LEth", registry, 0, treasury, 0, type(uint).max);

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

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,
uint _maxSupply
Expand All @@ -108,7 +105,7 @@ contract LToken is Pausable, ERC4626, ILToken {
initPausable(msg.sender);
initERC4626(_asset, _name, _symbol, _reserveShares, _maxSupply);
registry = _registry;
reserveFactor = _reserveFactor;
originationFee = _originationFee;
treasury = _treasury;
}

Expand Down Expand Up @@ -143,7 +140,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 @@ -176,11 +177,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 @@ -192,7 +188,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 @@ -205,7 +201,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 @@ -246,11 +241,8 @@ 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;
}

function updateMaxSupply(uint _maxSupply) external adminOnly {
Expand Down

0 comments on commit c93c7ea

Please sign in to comment.