UNPKG

@volare.finance/volare.js

Version:
209 lines 10.1 kB
"use strict"; /** * @file mirror.ts * @author astra <astra@volare.com> * @date 2022 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getCollateralDetails = exports.getMarginRequired = exports.getLiquidatablePrice = exports.getNakedMarginRequired = exports.getPayout = exports.getExpiredPayoutRate = exports.getExpiredCashValue = exports._convertAmountOnExpiryPrice = exports.getProductHash = void 0; const tslib_1 = require("tslib"); const solidity_1 = require("@ethersproject/solidity"); const utils_js_1 = require("@volare.finance/utils.js"); const cache_1 = require("./cache"); const OptionUpperBoundValue = new utils_js_1.BigNumber(0.2); const SpotShockValue = new utils_js_1.BigNumber(1); function getProductHash(vToken) { return (0, solidity_1.keccak256)(['address', 'address', 'address', 'bool'], [vToken.underlyingAsset, vToken.strikeAsset, vToken.collateralAsset, vToken.isPut]); } exports.getProductHash = getProductHash; /** * @notice convert an amount in asset A to equivalent amount of asset B, based on an expiry price * @dev function includes the amount and apply .mul() first to increase the accuracy * @param _amount amount in asset A * @param _assetA asset A * @param _assetB asset B * @param _expiry * @param _prices * @return _amount in asset B */ function _convertAmountOnExpiryPrice(_amount, _assetA, _assetB, _expiry, _prices) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (!_prices) { _prices = {}; _prices[_assetA] = yield (0, cache_1.cExpiryPrice)(_assetA, _expiry); _prices[_assetB] = yield (0, cache_1.cExpiryPrice)(_assetB, _expiry); } return utils_js_1.ZERO; }); } exports._convertAmountOnExpiryPrice = _convertAmountOnExpiryPrice; /** * @description return the cash value of an expired vToken, denominated in strike asset * @param vToken * @param underlyingPrice denominated in usd * @param strikePrice denominated in usd * @return cash value of an expired vToken, denominated in the strike asset */ function getExpiredCashValue(vToken, underlyingPrice, strikePrice) { // amount A * price A in USD = amount B * price B in USD // amount B = amount A * price A / price B const underlyingPriceInStrike = underlyingPrice.multipliedBy(1).dividedBy(strikePrice); const strikePriceInStrike = new utils_js_1.BigNumber(vToken.strikePrice); if (vToken.isPut) { return underlyingPriceInStrike.lt(strikePriceInStrike) ? strikePriceInStrike.minus(underlyingPriceInStrike) : utils_js_1.ZERO; } else { return underlyingPriceInStrike.gt(strikePriceInStrike) ? underlyingPriceInStrike.minus(strikePriceInStrike) : utils_js_1.ZERO; } } exports.getExpiredCashValue = getExpiredCashValue; /** * @description return the cash value of an expired vToken, denominated in collateral * @param vToken * @param collateralPrice denominated in usd * @param underlyingPrice denominated in usd * @param strikePrice denominated in usd */ function getExpiredPayoutRate(vToken, collateralPrice, underlyingPrice, strikePrice) { const cashValueInStrike = getExpiredCashValue(vToken, underlyingPrice, strikePrice); return cashValueInStrike.multipliedBy(strikePrice).dividedBy(collateralPrice); } exports.getExpiredPayoutRate = getExpiredPayoutRate; /** * @description get an vToken's payout/cash value after expiry, in the collateral asset * @param vToken * @param collateralPrice denominated in usd * @param underlyingPrice denominated in usd * @param strikePrice denominated in usd * @param amount */ function getPayout(vToken, collateralPrice, underlyingPrice, strikePrice, amount) { const rate = getExpiredPayoutRate(vToken, collateralPrice, underlyingPrice, strikePrice); return amount.multipliedBy(rate); } exports.getPayout = getPayout; /** * @notice get required collateral for naked margin position * if put: * a = min(strike price, spot shock * underlying price) * b = max(strike price - spot shock * underlying price, 0) * marginRequired = ( option upper bound value * a + b) * short amount * if call: * a = min(1, strike price / (underlying price / spot shock value)) * b = max(1- (strike price / (underlying price / spot shock value)), 0) * marginRequired = (option upper bound value * a + b) * short amount * @param vToken * @param shortAmount short amount in vault, in FixedPointInt type * @param underlyingPrice underlying price of short vToken underlying asset, in FixedPointInt type * @return required margin for this naked vault, in FixedPointInt type (scaled by 1e27) */ function getNakedMarginRequired(vToken, shortAmount, underlyingPrice) { const strikePrice = vToken.strikePrice; const underlyingShockPrice = SpotShockValue.multipliedBy(underlyingPrice); if (vToken.isPut) { const payout = new utils_js_1.BigNumber(strikePrice).minus(underlyingShockPrice); if (payout.isNegative()) { return OptionUpperBoundValue.multipliedBy(strikePrice).multipliedBy(shortAmount); } else { return OptionUpperBoundValue.multipliedBy(underlyingShockPrice).plus(payout).multipliedBy(shortAmount); } } throw 'Not Support'; } exports.getNakedMarginRequired = getNakedMarginRequired; function getLiquidatablePrice(vToken, shortAmount, collateralAmount) { if (vToken.isPut) { const marginRequired = collateralAmount.dividedBy(shortAmount); if (marginRequired.gte(vToken.strikePrice)) { return utils_js_1.ZERO; } else { return vToken.strikePrice.minus(marginRequired).div(new utils_js_1.BigNumber(1).minus(OptionUpperBoundValue)); } } throw 'Not Support'; } exports.getLiquidatablePrice = getLiquidatablePrice; /** * @description returns the amount of collateral that can be removed from an actual or a theoretical vault * @param vault * @param prices denominated in usd */ function getMarginRequired(vault, prices) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const shortPayouts = []; const longPayouts = []; const marginRequired = []; const marginRequired2 = {}; for (let i = 0; i < vault.collateralAssets.length; i++) { marginRequired2[vault.collateralAssets[i].toLowerCase()] = utils_js_1.ZERO; } for (let i = 0; i < vault.shortVTokens.length; i++) { const short = vault.shortVTokens[i].toLowerCase(); if (short === utils_js_1.ZERO_ADDR) continue; const vToken = yield (0, cache_1.cVTokenDetails)(short); const collateral = vToken.collateralAsset.toLowerCase(); const underlying = vToken.underlyingAsset.toLowerCase(); const strike = vToken.strikeAsset.toLowerCase(); const collateralSymbol = yield (0, cache_1.cSymbol)(collateral); const underlyingSymbol = yield (0, cache_1.cSymbol)(underlying); const strikeSymbol = yield (0, cache_1.cSymbol)(strike); const payout = getExpiredPayoutRate(vToken, prices[collateralSymbol], prices[underlyingSymbol], prices[strikeSymbol]); shortPayouts[i] = new utils_js_1.BigNumber(payout).multipliedBy(vault.shortAmounts[i]); marginRequired2[collateral] = marginRequired2[collateral].plus(shortPayouts[i]); } for (let i = 0; i < vault.longVTokens.length; i++) { const long = vault.longVTokens[i].toLowerCase(); if (long === utils_js_1.ZERO_ADDR) continue; const vToken = yield (0, cache_1.cVTokenDetails)(long); const collateral = vToken.collateralAsset.toLowerCase(); const underlying = vToken.underlyingAsset.toLowerCase(); const strike = vToken.strikeAsset.toLowerCase(); const collateralSymbol = yield (0, cache_1.cSymbol)(collateral); const underlyingSymbol = yield (0, cache_1.cSymbol)(underlying); const strikeSymbol = yield (0, cache_1.cSymbol)(strike); const payout = getExpiredPayoutRate(vToken, prices[collateralSymbol], prices[underlyingSymbol], prices[strikeSymbol]); longPayouts[i] = new utils_js_1.BigNumber(payout).multipliedBy(vault.longAmounts[i]); marginRequired2[collateral] = marginRequired2[collateral].minus(longPayouts[i]); } for (let i = 0; i < vault.collateralAssets.length; i++) { const collateral = vault.collateralAssets[i].toLowerCase(); if (collateral === utils_js_1.ZERO_ADDR) continue; marginRequired[i] = marginRequired2[collateral]; } return { shortPayouts, longPayouts, marginRequired, }; }); } exports.getMarginRequired = getMarginRequired; function getCollateralDetails(vault, prices) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const { marginRequired } = yield getMarginRequired(vault, prices); const fullCollateralAmounts = []; const collateralRates = []; const liquidationRates = []; for (let i = 0; i < vault.collateralAssets.length; i++) { const short = yield (0, cache_1.cVTokenDetails)(vault.shortVTokens[i]); fullCollateralAmounts[i] = short.isPut ? new utils_js_1.BigNumber(short.strikePrice).multipliedBy(vault.shortAmounts[i]) : vault.shortAmounts[i]; collateralRates[i] = new utils_js_1.BigNumber(vault.collateralAmounts[i]).div(fullCollateralAmounts[i]).multipliedBy(100).toFixed(2) + '%'; liquidationRates[i] = new utils_js_1.BigNumber(marginRequired[i]).div(fullCollateralAmounts[i]).multipliedBy(100).toFixed(2) + '%'; } return { collateralAssets: vault.collateralAssets, collateralAmounts: vault.collateralAmounts, fullCollateralAmounts, collateralRates, marginRequired, liquidationRates, }; }); } exports.getCollateralDetails = getCollateralDetails; //# sourceMappingURL=mirror.js.map