Skip to content

Commit

Permalink
Merge pull request #78 from euler-xyz/fix-convert-fees
Browse files Browse the repository at this point in the history
fix convert fees total shares
  • Loading branch information
dglowinski authored Mar 28, 2024
2 parents d7ad9db + 050032e commit b49869c
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 47 deletions.
17 changes: 9 additions & 8 deletions src/EVault/EVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,20 @@ contract EVault is Dispatch {

function governorAdmin() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function feeReceiver() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function interestFee() public view virtual override useView(MODULE_GOVERNANCE) returns (uint16) {}

function interestRateModel() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function protocolConfigAddress() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function protocolFeeShare() public view virtual override useView(MODULE_GOVERNANCE) returns (uint256) {}

function protocolFeeReceiver() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function caps() public view virtual override useView(MODULE_GOVERNANCE) returns (uint16 supplyCap, uint16 borrowCap) {}

function borrowingLTV(address collateral) public view virtual override useView(MODULE_GOVERNANCE) returns (uint16) {}

function liquidationLTV(address collateral) public view virtual override useView(MODULE_GOVERNANCE) returns (uint16) {}
Expand All @@ -177,24 +183,19 @@ contract EVault is Dispatch {

function LTVList() public view virtual override useView(MODULE_GOVERNANCE) returns (address[] memory) {}

function interestRateModel() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function hookConfig() public view virtual override useView(MODULE_GOVERNANCE) returns (address, uint32) {}

function configFlags() public view virtual override useView(MODULE_GOVERNANCE) returns (uint32) {}

function caps() public view virtual override useView(MODULE_GOVERNANCE) returns (uint16 supplyCap, uint16 borrowCap) {}

function feeReceiver() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function EVC() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function permit2Address() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function unitOfAccount() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function oracle() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}

function permit2Address() public view virtual override useView(MODULE_GOVERNANCE) returns (address) {}


function convertFees() public virtual override callThroughEVC use(MODULE_GOVERNANCE) {}

function setName(string calldata newName) public virtual override use(MODULE_GOVERNANCE) {}
Expand Down
26 changes: 13 additions & 13 deletions src/EVault/IEVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,17 @@ interface IGovernance {
/// @notice Retrieves the address of the governor
function governorAdmin() external view returns (address);

/// @notice Retrieves address of the governance fee receiver
function feeReceiver() external view returns (address);

/// @notice Retrieves the interest fee in effect for the vault
/// @return Amount of interest that is redirected as a fee, as a fraction scaled by 1e4
function interestFee() external view returns (uint16);

/// @notice Looks up an asset's currently configured interest rate model
/// @return Address of the interest rate contract or address zero to indicate 0% interest
function interestRateModel() external view returns (address);

/// @notice Retrieves the ProtocolConfig address
function protocolConfigAddress() external view returns (address);

Expand All @@ -314,6 +321,9 @@ interface IGovernance {
/// @notice Retrieves the address which will receive protocol's fees
function protocolFeeReceiver() external view returns (address);

/// @notice Retrieves supply and borrow caps in AmountCap format
function caps() external view returns (uint16 supplyCap, uint16 borrowCap);

/// @notice Retrieves regular LTV, set for the collateral, which is used to determine the health of the account
function borrowingLTV(address collateral) external view returns (uint16);

Expand All @@ -336,34 +346,24 @@ interface IGovernance {
/// @dev The list can have duplicates. Returned assets could have the ltv disabled (set to zero)
function LTVList() external view returns (address[] memory);

/// @notice Looks up an asset's currently configured interest rate model
/// @return Address of the interest rate contract or address zero to indicate 0% interest
function interestRateModel() external view returns (address);

/// @notice Retrieves a hook target and a bitmask indicating which operations call the hook target.
function hookConfig() external view returns (address, uint32);

/// @notice Retrieves a bitmask indicating enabled config flags.
function configFlags() external view returns (uint32);

/// @notice Retrieves supply and borrow caps in AmountCap format
function caps() external view returns (uint16 supplyCap, uint16 borrowCap);

/// @notice Retrieves address of the governance fee receiver
function feeReceiver() external view returns (address);

/// @notice Address of EthereumVaultConnector contract
function EVC() external view returns (address);

/// @notice Retrieves the Permit2 contract address
function permit2Address() external view returns (address);

/// @notice Retrieves a reference asset used for liquidity calculations
function unitOfAccount() external view returns (address);

/// @notice Retrieves the address of the oracle contract
function oracle() external view returns (address);

/// @notice Retrieves the Permit2 contract address
function permit2Address() external view returns (address);

/// @notice Splits accrued fees balance according to protocol fee share and transfers shares to the governor fee receiver and protocol fee receiver
function convertFees() external;

Expand Down
48 changes: 24 additions & 24 deletions src/EVault/modules/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,26 @@ abstract contract GovernanceModule is IGovernance, Base, BalanceUtils, BorrowUti
return vaultStorage.governorAdmin;
}

/// @inheritdoc IGovernance
function feeReceiver() public view virtual reentrantOK returns (address) {
return vaultStorage.feeReceiver;
}

/// @inheritdoc IGovernance
function interestFee() public view virtual reentrantOK returns (uint16) {
return vaultStorage.interestFee.toUint16();
}

/// @inheritdoc IGovernance
function interestRateModel() public view virtual reentrantOK returns (address) {
return vaultStorage.interestRateModel;
}

/// @inheritdoc IGovernance
function protocolConfigAddress() public view virtual reentrantOK returns (address) {
return address(protocolConfig);
}

/// @inheritdoc IGovernance
function protocolFeeShare() public view virtual reentrantOK returns (uint256) {
(, uint256 protocolShare) = protocolConfig.protocolFeeConfig(address(this));
Expand All @@ -61,8 +76,8 @@ abstract contract GovernanceModule is IGovernance, Base, BalanceUtils, BorrowUti
}

/// @inheritdoc IGovernance
function protocolConfigAddress() public view virtual reentrantOK returns (address) {
return address(protocolConfig);
function caps() public view virtual reentrantOK returns (uint16, uint16) {
return (vaultStorage.supplyCap.toRawUint16(), vaultStorage.borrowCap.toRawUint16());
}

/// @inheritdoc IGovernance
Expand All @@ -86,11 +101,6 @@ abstract contract GovernanceModule is IGovernance, Base, BalanceUtils, BorrowUti
return vaultStorage.ltvList;
}

/// @inheritdoc IGovernance
function interestRateModel() public view virtual reentrantOK returns (address) {
return vaultStorage.interestRateModel;
}

/// @inheritdoc IGovernance
function hookConfig() public view virtual reentrantOK returns (address, uint32) {
return (vaultStorage.hookTarget, vaultStorage.hookedOps.toUint32());
Expand All @@ -101,26 +111,11 @@ abstract contract GovernanceModule is IGovernance, Base, BalanceUtils, BorrowUti
return (vaultStorage.configFlags.toUint32());
}

/// @inheritdoc IGovernance
function caps() public view virtual reentrantOK returns (uint16, uint16) {
return (vaultStorage.supplyCap.toRawUint16(), vaultStorage.borrowCap.toRawUint16());
}

/// @inheritdoc IGovernance
function feeReceiver() public view virtual reentrantOK returns (address) {
return vaultStorage.feeReceiver;
}

/// @inheritdoc IGovernance
function EVC() public view virtual reentrantOK returns (address) {
return address(evc);
}

/// @inheritdoc IGovernance
function permit2Address() public view virtual reentrantOK returns (address) {
return permit2;
}

/// @inheritdoc IGovernance
function unitOfAccount() public view virtual reentrantOK returns (address) {
(,, address _unitOfAccount) = ProxyUtils.metadata();
Expand All @@ -133,6 +128,11 @@ abstract contract GovernanceModule is IGovernance, Base, BalanceUtils, BorrowUti
return address(_oracle);
}

/// @inheritdoc IGovernance
function permit2Address() public view virtual reentrantOK returns (address) {
return permit2;
}

/// @inheritdoc IGovernance
function convertFees() public virtual nonReentrant {
(VaultCache memory vaultCache, address account) = initOperation(OP_CONVERT_FEES, CHECKACCOUNT_NONE);
Expand All @@ -151,11 +151,11 @@ abstract contract GovernanceModule is IGovernance, Base, BalanceUtils, BorrowUti
Shares governorShares = vaultCache.accumulatedFees.mulDiv(1e4 - protocolFee, 1e4);
Shares protocolShares = vaultCache.accumulatedFees - governorShares;

vaultStorage.accumulatedFees = vaultCache.accumulatedFees = Shares.wrap(0);

// Decrease totalShares because increaseBalance will increase it by that total amount
vaultStorage.totalShares = vaultCache.totalShares = vaultCache.totalShares - vaultCache.accumulatedFees;

vaultStorage.accumulatedFees = vaultCache.accumulatedFees = Shares.wrap(0);

// For the Deposit events in increaseBalance the assets amount is zero - the shares are covered with the accrued interest
if (!governorShares.isZero()) {
increaseBalance(vaultCache, governorReceiver, address(0), governorShares, Assets.wrap(0));
Expand Down
4 changes: 3 additions & 1 deletion test/unit/evault/EVaultTestBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ contract EVaultTestBase is AssertionsCustomTypes, Test, DeployPermit2 {
EthereumVaultConnector public evc;
address admin;
address feeReceiver;
address protocolFeeReceiver;
ProtocolConfig protocolConfig;
address balanceTracker;
MockPriceOracle oracle;
Expand Down Expand Up @@ -73,10 +74,11 @@ contract EVaultTestBase is AssertionsCustomTypes, Test, DeployPermit2 {
function setUp() public virtual {
admin = vm.addr(1000);
feeReceiver = makeAddr("feeReceiver");
protocolFeeReceiver = makeAddr("protocolFeeReceiver");
factory = new GenericFactory(admin);

evc = new EthereumVaultConnector();
protocolConfig = new ProtocolConfig(admin, feeReceiver);
protocolConfig = new ProtocolConfig(admin, protocolFeeReceiver);
balanceTracker = address(new MockBalanceTracker());
oracle = new MockPriceOracle();
unitOfAccount = address(1);
Expand Down
61 changes: 61 additions & 0 deletions test/unit/evault/modules/Governance/convertFees.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "../../EVaultTestBase.t.sol";

contract Governance_ConvertFees is EVaultTestBase {
using TypesLib for uint256;

address depositor;
address borrower;

function setUp() public override {
super.setUp();

depositor = makeAddr("depositor");
borrower = makeAddr("borrower");

// Setup

oracle.setPrice(address(assetTST), unitOfAccount, 1e18);
oracle.setPrice(address(eTST2), unitOfAccount, 1e18);

eTST.setLTV(address(eTST2), 0.9e4, 0);

// Depositor

startHoax(depositor);

assetTST.mint(depositor, type(uint256).max);
assetTST.approve(address(eTST), type(uint256).max);
eTST.deposit(100e18, depositor);

// Borrower

startHoax(borrower);

assetTST2.mint(borrower, type(uint256).max);
assetTST2.approve(address(eTST2), type(uint256).max);
eTST2.deposit(10e18, borrower);

evc.enableCollateral(borrower, address(eTST2));
evc.enableController(borrower, address(eTST));

eTST.borrow(5e18, borrower);
}

function test_Governance_convertFees() public {
skip(1000 days);

uint256 fees = eTST.accumulatedFees();
assertApproxEqAbs(fees, 0.03e18, 0.001e18);

uint256 totalSupplyBefore = eTST.totalSupply();

eTST.convertFees();

assertEq(eTST.totalSupply(), totalSupplyBefore);
assertEq(eTST.balanceOf(feeReceiver) + eTST.balanceOf(protocolFeeReceiver), fees);
}
}
2 changes: 1 addition & 1 deletion test/unit/evault/modules/Governance/interestRates.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.0;

import "../../EVaultTestBase.t.sol";

contract GovernanceTest is EVaultTestBase {
contract Governance_InterestRates is EVaultTestBase {
using TypesLib for uint256;

address depositor;
Expand Down

0 comments on commit b49869c

Please sign in to comment.