Continuing from the previous post, this article examines the rewards earned by Lenders. In Part 1, it was mentioned that LoopFi features positions not only for borrowers, but also for Lenders who supply WETH or ETH, as well as for dLP Lockers who hold the governance token dLP.
Since no contract appears to have been deployed to handle rewards for the dLP Locker position, it is presumed that rewards for them are not yet active. Therefore, this article will focus solely on the rewards earned by Lenders.
Lenders provide WETH or ETH to the pool and receive lpETH as a reward. Although it’s called a “pool”, it is not a typical swap pool but rather more akin to a vault that holds WETH. Pool V3 is a Vault that follows ERC4626 standard, with WETH as its asset and lpETH as its share. However, when examining the function that calculates the asset-to-share value, unlike typical ERC4626 vaults where the asset value can fluctuate, the ratio between asset and share is fixed at 1:1.
What is an ERC4626 Vault?
It is a vault standard in which depositing an
assetyields ashareas a reward. Previous implementations of supply-reward vaults were inconsistent, so this unified standard was proposed.Asset values can change over time, and when withdrawing assets, users receive an amount that corresponds to both the current asset value and their share. In other words, users may end up receiving either less or more than their original deposit, depending on asset value fluctuations.
In ERC4626, the functions _convertToShares and _convertToAssets are used to calculate asset and share values. PoolV3 also includes functions with the same names, but since they do not override those in ERC4626, using ERC4626's convertToShares would invoke the parent’s internal function, potentially leading to asset values being displayed differently than expected. Therefore, in PoolV3, instead of using convertToShares during share issuance and redemption, the two functions below are called directly.
function _convertToShares(uint256 assets) internal pure returns (uint256 shares) {
// uint256 supply = totalSupply();
return assets; //(assets == 0 || supply == 0) ? assets : assets.mulDiv(supply, totalAssets(), rounding);
}
function _convertToAssets(uint256 shares) internal pure returns (uint256 assets) {
//uint256 supply = totalSupply();
return shares; //(supply == 0) ? shares : shares.mulDiv(totalAssets(), supply, rounding);
}
Lenders can either receive a share corresponding to the amount of WETH they supply to the pool or specify the exact number of shares they wish to obtain, thereby providing the necessary liquidity. However, since the asset-to-share ratio is fixed at 1:1, the amount of WETH required to obtain a given share remains the same regardless of the approach.
The most common method—issuing shares in proportion to the amount supplied—is executed through the deposit, depositWithReferral, or depositETH functions. The first two functions are used when a Lender directly supplies WETH, while depositETH is employed when a Lender supplies ETH that must be converted to WETH by the pool.
function depositETH(address receiver)
public
payable
whenNotPaused // U:[LP-2A]
nonReentrant // U:[LP-2B]
nonZeroAddress(receiver) // U:[LP-5]
returns (uint256 shares)
{
//...
// Convert ETH to WETH
WETH.deposit{value: msg.value}();
// Calculate the amount of underlying received after the fee
uint256 assetsReceived = _amountMinusFee(msg.value); // U:[LP-6]
shares = _convertToShares(assetsReceived); // U:[LP-6]
// The weth is already in the contract, so we can directly register the deposit
_registerDeposit(receiver, msg.value, assetsReceived, shares); // U:[LP-6]
}
When a user supplies WETH or ETH, the _deposit function is called to issue shares, and _mint mints lpETH to the provider in an amount equal to the shares. In the case of supplying ETH, as shown in the code above, _registerDeposit is called instead of _deposit because ETH has already been sent via msg.value, so the safeTransferFrom for obtaining WETH is omitted; otherwise, it functions identically to _deposit.
Lenders can generate additional yields with lpETH. LoopFi offers two options:
lpETH into the StakingLPEth contract for a set period to receive a portion of pool earnings.lpETH in the Locking contract for a designated lock-up period to earn points.Since merely holding lpETH can’t create