PriceAndFeeCalculator
Last updated
Last updated
Inherits: IPriceAndFeeCalculator, BaseFeeCalculator, HasNumeraire
Calculates and manages unit price and fees for multiple vaults that share the same numeraire token. Acts as a price oracle and fee accrual engine. Vault registration workflow is:
Register a new vault with registerVault()
Set the thresholds for the vault with setThresholds()
Set the initial price state with setInitialPrice() Once registered, a vault can have its price updated by an authorized entity. Vault owners set thresholds for price changes, update intervals, and price age. If a price update violates thresholds (too large change, too soon, or too old), the vault is paused. Paused vaults dont accrue fees and cannot have their price updated until they are unpaused by the vault owner. Accrues fees on each price update, based on TVL and performance since last update Supports conversion between vault units, tokens, and numeraire for deposits/withdrawals. All logic and state is per-vault, supporting many vaults in parallel. Only vault owners can set thresholds pause/unpause their vaults, whereas accountants can also pause their vaults Integrates with an external oracle registry for token price conversions
Oracle registry contract for price feeds
IOracleRegistry public immutable ORACLE_REGISTRY;
Mapping of vault addresses to their state information
mapping(address vault => VaultPriceState vaultPriceState) internal _vaultPriceStates;
modifier requiresVaultAuthOrAccountant(address vault);
constructor(IERC20 numeraire, IOracleRegistry oracleRegistry, address owner_, Authority authority_)
BaseFeeCalculator(owner_, authority_)
HasNumeraire(address(numeraire));
Register a new vault with the fee calculator
function registerVault() external override;
Set the initial price state for the vault
function setInitialPrice(address vault, uint128 price, uint32 timestamp) external requiresVaultAuth(vault);
Parameters
vault
address
Address of the vault
price
uint128
New unit price
timestamp
uint32
Timestamp when the price was measured
Set vault thresholds
function setThresholds(
address vault,
uint16 minPriceToleranceRatio,
uint16 maxPriceToleranceRatio,
uint16 minUpdateIntervalMinutes,
uint8 maxPriceAge,
uint8 maxUpdateDelayDays
) external requiresVaultAuth(vault);
Parameters
vault
address
Address of the vault
minPriceToleranceRatio
uint16
Minimum ratio (of a price decrease) in basis points
maxPriceToleranceRatio
uint16
Maximum ratio (of a price increase) in basis points
minUpdateIntervalMinutes
uint16
The minimum interval between updates in minutes
maxPriceAge
uint8
Max delay between when a vault was priced and when the price is acceptable
maxUpdateDelayDays
uint8
Max delay between two price updates
Set the unit price for the vault in numeraire terms
function setUnitPrice(address vault, uint128 price, uint32 timestamp) external onlyVaultAccountant(vault);
Parameters
vault
address
Address of the vault
price
uint128
New unit price
timestamp
uint32
Timestamp when the price was measured
Pause the vault
function pauseVault(address vault) external requiresVaultAuthOrAccountant(vault);
Parameters
vault
address
Address of the vault
Unpause the vault
MUST revert if price or timestamp don't exactly match last update
function unpauseVault(address vault, uint128 price, uint32 timestamp) external requiresVaultAuth(vault);
Parameters
vault
address
Address of the vault
price
uint128
Expected price of the last update
timestamp
uint32
Expected timestamp of the last update
Resets the highest price for a vault to the current price
function resetHighestPrice(address vault) external requiresVaultAuth(vault);
Parameters
vault
address
Address of the vault
Convert units to token amount
function convertUnitsToToken(address vault, IERC20 token, uint256 unitsAmount)
external
view
returns (uint256 tokenAmount);
Parameters
vault
address
Address of the vault
token
IERC20
Address of the token
unitsAmount
uint256
Amount of units
Returns
tokenAmount
uint256
Amount of tokens
Convert units to token amount if vault is not paused
MUST revert if vault is paused
function convertUnitsToTokenIfActive(address vault, IERC20 token, uint256 unitsAmount, Math.Rounding rounding)
external
view
returns (uint256 tokenAmount);
Parameters
vault
address
Address of the vault
token
IERC20
Address of the token
unitsAmount
uint256
Amount of units
rounding
Math.Rounding
The rounding mode
Returns
tokenAmount
uint256
Amount of tokens
Convert units to numeraire token amount
function convertUnitsToNumeraire(address vault, uint256 unitsAmount) external view returns (uint256);
Parameters
vault
address
Address of the vault
unitsAmount
uint256
Amount of units
Returns
<none>
uint256
numeraireAmount Amount of numeraire
Convert token amount to units
function convertTokenToUnits(address vault, IERC20 token, uint256 tokenAmount)
external
view
returns (uint256 unitsAmount);
Parameters
vault
address
Address of the vault
token
IERC20
Address of the token
tokenAmount
uint256
Amount of tokens
Returns
unitsAmount
uint256
Amount of units
Convert token amount to units if vault is not paused
MUST revert if vault is paused
function convertTokenToUnitsIfActive(address vault, IERC20 token, uint256 tokenAmount, Math.Rounding rounding)
external
view
returns (uint256 unitsAmount);
Parameters
vault
address
Address of the vault
token
IERC20
Address of the token
tokenAmount
uint256
Amount of tokens
rounding
Math.Rounding
The rounding mode
Returns
unitsAmount
uint256
Amount of units
Return the state of the vault
function getVaultState(address vault) external view returns (VaultPriceState memory, VaultAccruals memory);
Parameters
vault
address
Address of the vault
Returns
<none>
VaultPriceState
vaultPriceState The price state of the vault
<none>
VaultAccruals
vaultAccruals The accruals state of the vault
Returns the age of the last submitted price for a vault
function getVaultsPriceAge(address vault) external view returns (uint256);
Parameters
vault
address
Address of the vault
Returns
<none>
uint256
priceAge The difference between block.timestamp and vault's unit price timestamp
Check if a vault is paused
function isVaultPaused(address vault) external view returns (bool);
Parameters
vault
address
The address of the vault
Returns
<none>
bool
True if the vault is paused, false otherwise
function previewFees(address vault, uint256 feeTokenBalance) external view override returns (uint256, uint256);
Accrues fees for a vault
It is assumed that validation has already been done Tvl is calculated as the product of the minimum of the current and last price and the minimum of the current and last total supply. This is to minimize potential issues with price spikes
function _accrueFees(address vault, uint256 price, uint256 timestamp) internal;
Parameters
vault
address
The address of the vault
price
uint256
The price of a single vault unit
timestamp
uint256
The timestamp of the price update
Sets the paused state for a vault
function _setVaultPaused(VaultPriceState storage vaultPriceState, address vault, bool paused) internal;
Parameters
vaultPriceState
VaultPriceState
The storage pointer to the vault's price state
vault
address
The address of the vault
paused
bool
The new paused state
Converts a token amount to units
function _convertTokenToUnits(
address vault,
IERC20 token,
uint256 tokenAmount,
uint256 unitPrice,
Math.Rounding rounding
) internal view returns (uint256 unitsAmount);
Parameters
vault
address
The address of the vault
token
IERC20
The token to convert
tokenAmount
uint256
The amount of tokens to convert
unitPrice
uint256
The price of a single vault unit
rounding
Math.Rounding
The rounding direction
Returns
unitsAmount
uint256
The amount of units
Converts a units amount to tokens
function _convertUnitsToToken(
address vault,
IERC20 token,
uint256 unitsAmount,
uint256 unitPrice,
Math.Rounding rounding
) internal view returns (uint256 tokenAmount);
Parameters
vault
address
The address of the vault
token
IERC20
The token to convert
unitsAmount
uint256
The amount of units to convert
unitPrice
uint256
The price of a single vault unit
rounding
Math.Rounding
The rounding direction
Returns
tokenAmount
uint256
The amount of tokens
Validates a price update
Price is invalid if it is 0, before the last update, in the future, or if the price age is stale
function _validatePriceUpdate(VaultPriceState storage vaultPriceState, uint256 price, uint256 timestamp)
internal
view;
Parameters
vaultPriceState
VaultPriceState
The storage pointer to the vault's price state
price
uint256
The price of a single vault unit
timestamp
uint256
The timestamp of the price update
Determines if a price update should pause the vault
Vault should pause if the price increase or decrease is too large, or if the min update interval has not passed
function _shouldPause(VaultPriceState storage state, uint256 price, uint32 timestamp) internal view returns (bool);
Parameters
state
VaultPriceState
The storage pointer to the vault's price state
price
uint256
The price of a single vault unit
timestamp
uint32
The timestamp of the price update
Returns
<none>
bool
shouldPause True if the price update should pause the vault, false otherwise