AlphaPortfolioValuesFeed.sol
This feed is responsible for passing in the pool's greek exposure (most importantly delta) and the portfolio's liabilities (or value of options contracts held) to the liquidity pool.
This function is responsible for doing the calculation for determining the portfolio delta and portfolio valuation. It achieves this by storing all the addresses of series held by the liquidityPool in an addressSet where each address is a key to a mapping that contains details on the option position [option series (with strike in e18) and amount in e18], then looping over all of these and computing the delta and value of each one, then finally summing those to form the portfolio delta and value. The amount incremented is the netExposure (shortExposure - longExposure)
It works by looping through the
addressSet
then searching the storesForAddress
mapping using the address of the loop. It first checks that the series being calculated has expired, if it has expired the fulfill will revert (the revert will also provide the address and index that it reverted at), what this indicates is that the oToken vault needs to be settled or redeemed and then removed from the loop via syncLooper
or cleanLooperManually
. This is done to prevent any miscalculated values of the pool due to expired options, since valuations are done manually and infrequently, this is reasonable to do. After that the volatility is determined from the VolatilityFeed
and the black scholes delta and value of the option of the loop is determined. These values then increment the portfolioValues. Once the loop is complete, the delta and portfolioValues
are pushed to storage.Update stores is the function that tells the Portfolio values feed any new positions that the liquidity pool has taken on. Then the
addressSet
is checked for _seriesAddress
, if it already exists then just increment the stores of that series by the signedAmount, otherwise add it to the addressSet
and store the option details in storesForAddress[_seriesAddress]
.An EnumerableSet.AddressSet by OpenZeppelin is used as it is easier to clean and much easier to search through.
Update stores can theoretically be pushed to by any set of contracts, meaning that a buyside products could also be used and could share the same liquidityPool liquidity and be represented by the same portfolio. Long exposure and short exposure are updated seperately and they are ints so that reducing positions is easily done via
updateStores
.This function is used to clean out the addressSet of expired options, the purpose being to keep the addressSet at the optimal size and to remove any expired options that might disrupt the valuation calculations.
It loops through the addressSet, if it finds any options that have expired then it adds it to another list, after looping through the addressSet. This new list is then looped through and each option is deleted from the addressSet and has its stores cleaned.
WARNING: A current danger of this function is that options that have not been settled but are settlable could be removed from the loop, this could result in incorrect counting of the option values. Thinking through ideas of how to fix this and open to ideas
This function is used to clean out the addressSet of expired options, the purpose being to keep the addressSet at the optimal size and to remove any expired options that might disrupt the valuation calculations.
This is a more manual process, it takes an address and an index. It checks the addressSet at that index. It compares it to the address given, if they are the same then it checks if the option has expired, if it has then it removes the option.
WARNING: A current danger of this function is that options that have not been settled but are settlable could be removed from the loop, this could result in incorrect counting of the option values. Thinking through ideas of how to fix this and open to ideas
This function is used to fix accounting in the stores if a series gets liquidated. This is mostly here to deal with the edge case that a vault does get liquidated. It first checks that the series exists in the stores then it checks that the stores have short exposure, if it does then it will check for the vault id in the option registry, if it exists then we know the liquidity pool had this position. Then in order to match the records of that vault we set the stores to the e18 version of the short amount in that opyn vault, the reason we do not set it to 0 is because partial liquidations are possible. This function would NEED to be called when a liquidation has occured so should be managed by a bot, however it is likely that guardian protocols would have kicked in if a liquidation has occured (protocol has paused).
This function is used to migrate all stored options data in one PortfolioValuesFeed to a new contract that has the IPortfolioValuesFeed interface. This is done if an update needs to be made to the PortfolioValuesFeed. (We as a team are not comfortable with using proxy solutions that achieve the same outcome)
Clear migration instructions are provided here:
////////////////////////////////////////////////////////////////////////////////////////////
/** MIGRATION PROCESS - FOR ALPHA
* 1/ On the migrate contract set this contract as a handler via Governance
* 2/ Make sure the storage of options in this contract is up to date and clean/synced
* 3/ Call migrate here via Governance
* 3i/ If the migration gas gets too big then
* 4/ Make sure the storage was correctly transferred to the new contract
* 5/ Properly configure the handlers on the new contract via Governance
* 6/ Properly configure the keepers on the new contract via Governance
* 7/ Set the liquidity pool on the new contract via Governance
* 8/ Change the PortfolioValuesFeed in the Protocol contract via Governance
*/
////////////////////////////////////////////////////////////////////////////////////////////
Options portfolio storage and calculations
struct OptionStores {
struct Types.OptionSeries optionSeries;
int256 shortExposure;
int256 longExposure;
}
uint256 oTokenDecimals
immutable variables ///
mapping(address => struct AlphaPortfolioValuesFeed.OptionStores) storesForAddress
dynamic variables ///
struct EnumerableSet.AddressSet addressSet
mapping(address => mapping(address => struct Types.PortfolioValues)) portfolioValues
contract Protocol protocol
govern settable variables ///
contract ILiquidityPool liquidityPool
mapping(address => bool) handler
mapping(bytes32 => int256) netDhvExposure
mapping(address => bool) keeper
uint256 rfr
event DataFullfilled(address underlying, address strike, int256 delta, int256 gamma, int256 vega, int256 theta, int256 callPutsValue)
events ///
event RequestedUpdate(address _underlying, address _strike)
event StoresUpdated(address seriesAddress, int256 shortExposure, int256 longExposure, struct Types.OptionSeries optionSeries)
error OptionHasExpiredInStores(uint256 index, address seriesAddress)
error NoVaultForShortPositions()
error IncorrectSeriesToRemove()
error SeriesNotExpired()
error NoShortPositions()
constructor(address _authority) public
Executes once when a contract is created to initialize state variables Make sure the protocol is configured after deployment
function setLiquidityPool(address _liquidityPool) external
setters ///
function setProtocol(address _protocol) external
function setRFR(uint256 _rfr) external
function setKeeper(address _keeper, bool _auth) external
change the status of a keeper
function setHandler(address _handler, bool _auth) external
change the status of a handler
function fulfill(address _underlying, address _strikeAsset) external
Fulfills the portfolio delta and portfolio value by doing a for loop over the stores. This is then used to update the portfolio values for external contracts to know what the liquidity pool's value is 1/ Make sure any expired options are settled, otherwise this fulfillment will fail 2/ Once the addressSet is cleared of any
Name | Type | Description |
---|---|---|
_underlying | address | - response; underlying address |
_strikeAsset | address | - response; strike address |
function updateStores(struct Types.OptionSeries _optionSeries, int256 shortExposure, int256 longExposure, address _seriesAddress) external
Updates the option series stores to be used for portfolio value calculation
callable by the handler and also during migration
Name | Type | Description |
---|---|---|
_optionSeries | struct Types.OptionSeries | the option series that was created, strike in e18 |
shortExposure | int256 | the amount of short to increment the short exposure by |
longExposure | int256 | the amount of long to increment the long exposure by |
_seriesAddress | address | the address of the series represented by the oToken |
address[] addyList
LOOP CLEANING - FOR ALPHA This is necessary to reduce the size of the foor loop when its not necessary to.
- Make sure the option has been settled!
function syncLooper() external
function to clean all expired series from the options storage to remove them from the looped array.
FOLLOW THE LOOP CLEANING INSTRUCTIONS ABOVE WHEN CALLING THIS FUNCTION
function cleanLooperManually(address _series) external
function to clean an expired series from the portfolio values feed, this function will make sure the series and index match and will also check if the series has expired before any cleaning happens.
FOLLOW THE LOOP CLEANING INSTRUCTIONS ABOVE WHEN CALLING THIS FUNCTION
Name | Type | Description |
---|---|---|
_series | address | the series at the index input above |
function _cleanLooper(address _series) internal
internal function for removing an address from the address set and clearing all option stores for that series
Name | Type | Description |
---|---|---|
_series | address | the option series address to be cleared |
function accountLiquidatedSeries(address _series) external
if a vault has been liquidated we need to account for it, so adjust our short positions to reality
Name | Type | Description |
---|---|---|
_series | address | the option series address to be cleared |
function migrate(contract IPortfolioValuesFeed _migrateContract) external
migrate all stored options data to a new contract that has the IPortfolioValuesFeed interface
FOLLOW THE MIGRATION PROCESS INSTRUCTIONS WHEN CALLING THIS FUNCTION
Name | Type | Description |
---|---|---|
_migrateContract | contract IPortfolioValuesFeed | the new portfolio values feed contract to migrate option values too |
function requestPortfolioData(address _underlying, address _strike) external returns (bytes32 id)
requests a portfolio data update
function getPortfolioValues(address underlying, address strike) external view returns (struct Types.PortfolioValues)
non-complex getters ///
function _isKeeper() internal view
keepers, managers or governors can access
function _isHandler() internal view
handlers can access
function isAddressInSet(address _a) external view returns (bool)
get the address set details
function addressAtIndexInSet(uint256 _i) external view returns (address)
function addressSetLength() external view returns (uint256)
function getAddressSet() external view returns (address[])
function _getVolatilityFeed() internal view returns (contract VolatilityFeed)
get the volatility feed used by the liquidity pool
Name | Type | Description |
---|---|---|
[0] | contract VolatilityFeed | the volatility feed contract interface |
function _getOptionRegistry() internal view returns (contract IOptionRegistry)
get the option registry used for storing and managing the options
Name | Type | Description |
---|---|---|
[0] | contract IOptionRegistry | the option registry contract |
function _getUnderlyingPrice(address underlying, address _strikeAsset) internal view returns (uint256)
get the underlying price with just the underlying asset and strike asset
Name | Type | Description |
---|---|---|
underlying | address | the asset that is used as the reference asset |
_strikeAsset | address | the asset that the underlying value is denominated in |
Name | Type | Description |
---|---|---|
[0] | uint256 | the underlying price |
Last modified 4mo ago