mirror of
https://github.com/Instadapp/fluid-contracts-public.git
synced 2024-07-29 21:57:37 +00:00
d7a58e88ff
ARB: deploy protocols
187 lines
8.7 KiB
Solidity
187 lines
8.7 KiB
Solidity
// SPDX-License-Identifier: BUSL-1.1
|
|
pragma solidity 0.8.21;
|
|
|
|
import { FluidVaultT1Admin } from "../vaultT1/adminModule/main.sol";
|
|
import { IFluidVaultT1 } from "../interfaces/iVaultT1.sol";
|
|
import { IFluidReserveContract } from "../../../reserve/interfaces/iReserveContract.sol";
|
|
import { LiquiditySlotsLink } from "../../../libraries/liquiditySlotsLink.sol";
|
|
import { Events } from "./events.sol";
|
|
import { Variables } from "./variables.sol";
|
|
import { ErrorTypes } from "../errorTypes.sol";
|
|
import { Error } from "../error.sol";
|
|
import { IFluidLiquidity } from "../../../liquidity/interfaces/iLiquidity.sol";
|
|
|
|
/// @title VaultRewards
|
|
/// @notice This contract is designed to adjust the supply rate magnifier for a vault based on the current collateral supply & supply rate.
|
|
/// The adjustment aims to dynamically scale the rewards given to lenders as the TVL in the vault changes.
|
|
///
|
|
/// The magnifier is adjusted based on a regular most used reward type where rewardRate = totalRewardsAnnually / totalSupply.
|
|
/// Reward rate is applied by adjusting the supply magnifier on vault.
|
|
/// Adjustments are made via the rebalance function, which is restricted to be called by designated rebalancers only.
|
|
contract FluidVaultRewards is Variables, Events, Error {
|
|
/// @dev Validates that an address is not the zero address
|
|
modifier validAddress(address value_) {
|
|
if (value_ == address(0)) {
|
|
revert FluidVaultError(ErrorTypes.VaultRewards__AddressZero);
|
|
}
|
|
_;
|
|
}
|
|
|
|
/// @dev Validates that an address is a rebalancer (taken from reserve contract)
|
|
modifier onlyRebalancer() {
|
|
if (!RESERVE_CONTRACT.isRebalancer(msg.sender)) {
|
|
revert FluidVaultError(ErrorTypes.VaultRewards__Unauthorized);
|
|
}
|
|
_;
|
|
}
|
|
|
|
/// @notice Constructs the FluidVaultRewards contract.
|
|
/// @param reserveContract_ The address of the reserve contract where rebalancers are defined.
|
|
/// @param vault_ The vault to which this contract will apply new magnifier parameter.
|
|
/// @param liquidity_ Fluid liquidity address
|
|
/// @param rewardsAmt_ Amounts of rewards to distribute
|
|
/// @param duration_ rewards duration
|
|
/// @param initiator_ address that can start rewards with `start()`
|
|
/// @param collateralToken_ vault collateral token address
|
|
constructor(
|
|
IFluidReserveContract reserveContract_,
|
|
IFluidVaultT1 vault_,
|
|
IFluidLiquidity liquidity_,
|
|
uint256 rewardsAmt_,
|
|
uint256 duration_,
|
|
address initiator_,
|
|
address collateralToken_
|
|
) validAddress(address(reserveContract_)) validAddress(address(liquidity_)) validAddress(address(vault_)) validAddress(initiator_) validAddress(address(collateralToken_)){
|
|
if (rewardsAmt_ == 0 || duration_ == 0) {
|
|
revert FluidVaultError(ErrorTypes.VaultRewards__InvalidParams);
|
|
}
|
|
RESERVE_CONTRACT = reserveContract_;
|
|
VAULT = vault_;
|
|
REWARDS_AMOUNT = rewardsAmt_;
|
|
REWARDS_AMOUNT_PER_YEAR = rewardsAmt_ * SECONDS_PER_YEAR / duration_;
|
|
DURATION = duration_;
|
|
INITIATOR = initiator_;
|
|
LIQUIDITY = liquidity_;
|
|
VAULT_COLLATERAL_TOKEN = collateralToken_;
|
|
|
|
LIQUIDITY_TOTAL_AMOUNTS_COLLATERAL_TOKEN_SLOT = LiquiditySlotsLink.calculateMappingStorageSlot(
|
|
LiquiditySlotsLink.LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT,
|
|
collateralToken_
|
|
);
|
|
LIQUIDITY_EXCHANGE_PRICE_COLLATERAL_TOKEN_SLOT = LiquiditySlotsLink.calculateMappingStorageSlot(
|
|
LiquiditySlotsLink.LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT,
|
|
collateralToken_
|
|
);
|
|
}
|
|
|
|
/// @notice Rebalances the supply rate magnifier based on the current collateral supply.
|
|
/// Can only be called by an authorized rebalancer.
|
|
function rebalance() external onlyRebalancer {
|
|
(uint256 newMagnifier_, bool ended_) = calculateMagnifier();
|
|
if (ended_) {
|
|
ended = true;
|
|
}
|
|
if (newMagnifier_ == currentMagnifier()) {
|
|
revert FluidVaultError(ErrorTypes.VaultRewards__NewMagnifierSameAsOldMagnifier);
|
|
}
|
|
|
|
FluidVaultT1Admin(address(VAULT)).updateSupplyRateMagnifier(newMagnifier_);
|
|
emit LogUpdateMagnifier(address(VAULT), newMagnifier_);
|
|
}
|
|
|
|
/// @notice Calculates the new supply rate magnifier based on the current collateral supply (`vaultTVL()`).
|
|
/// @return magnifier_ The calculated magnifier value.
|
|
function calculateMagnifier() public view returns (uint256 magnifier_, bool ended_) {
|
|
uint256 currentTVL_ = vaultTVL();
|
|
uint256 startTime_ = uint256(startTime);
|
|
uint256 endTime_ = uint256(endTime);
|
|
|
|
if (startTime_ == 0 || endTime_ == 0 || ended) {
|
|
revert FluidVaultError(ErrorTypes.VaultRewards__RewardsNotStartedOrEnded);
|
|
}
|
|
|
|
if (block.timestamp > endTime_) {
|
|
return (FOUR_DECIMALS, true);
|
|
}
|
|
|
|
uint supplyRate_ = getSupplyRate();
|
|
uint rewardsRate_ = (REWARDS_AMOUNT_PER_YEAR * FOUR_DECIMALS) / currentTVL_;
|
|
|
|
magnifier_ = FOUR_DECIMALS + (supplyRate_ == 0 ? rewardsRate_ : ((rewardsRate_ * FOUR_DECIMALS) / supplyRate_));
|
|
if (magnifier_ > X16) {
|
|
magnifier_ = X16;
|
|
}
|
|
}
|
|
|
|
/// @notice returns the currently configured supply magnifier at the `VAULT`.
|
|
function currentMagnifier() public view returns (uint256) {
|
|
// read supply rate magnifier from Vault `vaultVariables2` located in storage slot 1, first 16 bits
|
|
return VAULT.readFromStorage(bytes32(uint256(1))) & X16;
|
|
}
|
|
|
|
/// @notice returns the current total value locked as collateral (TVL) in the `VAULT`.
|
|
function vaultTVL() public view returns (uint256 tvl_) {
|
|
// read total supply raw in vault from storage slot 0 `vaultVariables`, 64 bits 82-145
|
|
tvl_ = (VAULT.readFromStorage(bytes32(0)) >> 82) & 0xFFFFFFFFFFFFFFFF;
|
|
|
|
// Converting bignumber into normal number
|
|
tvl_ = (tvl_ >> 8) << (tvl_ & 0xFF);
|
|
|
|
// get updated supply exchange price, which takes slot 1 `vaultVariables2` as input param
|
|
(, , uint256 vaultSupplyExPrice_, ) = VAULT.updateExchangePrices(VAULT.readFromStorage(bytes32(uint256(1))));
|
|
|
|
// converting raw total supply into normal amount
|
|
tvl_ = (tvl_ * vaultSupplyExPrice_) / 1e12;
|
|
}
|
|
|
|
function getSupplyRate() public view returns (uint supplyRate_) {
|
|
uint256 exchangePriceAndConfig_ = LIQUIDITY.readFromStorage(LIQUIDITY_EXCHANGE_PRICE_COLLATERAL_TOKEN_SLOT);
|
|
uint256 totalAmounts_ = LIQUIDITY.readFromStorage(LIQUIDITY_TOTAL_AMOUNTS_COLLATERAL_TOKEN_SLOT);
|
|
|
|
uint borrowRate_ = exchangePriceAndConfig_ & X16;
|
|
uint fee_ = (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14;
|
|
uint supplyExchangePrice_ = ((exchangePriceAndConfig_ >>
|
|
LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) & X64);
|
|
uint borrowExchangePrice_ = ((exchangePriceAndConfig_ >>
|
|
LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) & X64);
|
|
|
|
// Extract supply raw interest
|
|
uint256 supplyWithInterest_ = totalAmounts_ & X64;
|
|
supplyWithInterest_ =
|
|
(supplyWithInterest_ >> DEFAULT_EXPONENT_SIZE) <<
|
|
(supplyWithInterest_ & DEFAULT_EXPONENT_MASK);
|
|
|
|
// Extract borrow raw interest
|
|
uint256 borrowWithInterest_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) &
|
|
X64;
|
|
borrowWithInterest_ =
|
|
(borrowWithInterest_ >> DEFAULT_EXPONENT_SIZE) <<
|
|
(borrowWithInterest_ & DEFAULT_EXPONENT_MASK);
|
|
|
|
if (supplyWithInterest_ > 0) {
|
|
// use old exchange prices for supply rate to be at same level as borrow rate from storage.
|
|
// Note the rate here can be a tiny bit with higher precision because we use borrowWithInterest_ / supplyWithInterest_
|
|
// which has higher precision than the utilization used from storage in LiquidityCalcs
|
|
supplyWithInterest_ = (supplyWithInterest_ * supplyExchangePrice_) / EXCHANGE_PRICES_PRECISION; // normalized from raw
|
|
borrowWithInterest_ = (borrowWithInterest_ * borrowExchangePrice_) / EXCHANGE_PRICES_PRECISION; // normalized from raw
|
|
|
|
supplyRate_ =
|
|
(borrowRate_ * (FOUR_DECIMALS - fee_) * borrowWithInterest_) /
|
|
(supplyWithInterest_ * FOUR_DECIMALS);
|
|
}
|
|
}
|
|
|
|
function start() external {
|
|
if (msg.sender != INITIATOR) {
|
|
revert FluidVaultError(ErrorTypes.VaultRewards__NotTheInitiator);
|
|
}
|
|
if (startTime > 0 || endTime > 0) {
|
|
revert FluidVaultError(ErrorTypes.VaultRewards__AlreadyStarted);
|
|
}
|
|
startTime = uint96(block.timestamp);
|
|
endTime = uint96(block.timestamp + DURATION);
|
|
|
|
emit LogRewardsStarted(startTime, endTime);
|
|
}
|
|
}
|