@volare.finance/volare.js
Version:
The SDK for Volare Protocol
209 lines • 10.1 kB
JavaScript
"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