UNPKG

@volare.finance/volare.js

Version:
453 lines 21.2 kB
"use strict"; /** * @file Controller.ts * @author astra <astra@volare.finance> * @date 2022 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Controller = void 0; const tslib_1 = require("tslib"); const bytes_1 = require("@ethersproject/bytes"); const utils_js_1 = require("@volare.finance/utils.js"); const ethers_1 = require("ethers"); const Controller_json_1 = require("../artifacts/Controller.json"); const cache_1 = require("./cache"); const errors_1 = require("./errors"); const protocols_1 = require("./protocols"); const VTokenImpl_1 = require("./VTokenImpl"); const VIRTUAL_VAULT_ID_MIN = 202300000; class Controller extends utils_js_1.Provider { static ABI() { return Controller_json_1.abi; } constructor(address, endpoint) { super(endpoint); this.contract = new ethers_1.Contract(address, Controller.ABI(), this.provider); } /** * @notice returns the current controller configuration * @return whitelist, the address of the whitelist module * @return oracle, the address of the oracle module * @return calculator, the address of the calculator module * @return pool, the address of the pool module */ getConfiguration() { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { if (this.configuration === undefined) { const addresses = yield ((_a = this.contract) === null || _a === void 0 ? void 0 : _a.getConfiguration()); this.configuration = { whitelist: addresses[0], oracle: addresses[1], calculator: addresses[2], pool: addresses[3], }; } return this.configuration; }); } /** * @notice get cap amount for collateral asset * @param assetAddress collateral asset address * @return cap amount */ getNakedCap(assetAddress) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const assetAmount = yield ((_a = this.contract) === null || _a === void 0 ? void 0 : _a.getNakedCap(assetAddress)); const decimals = yield (0, cache_1.cDecimals)(assetAddress); return (0, utils_js_1.$float)(assetAmount, decimals); }); } /** * @notice get amount of collateral deposited in all naked margin vaults * @param assetAddress collateral asset address * @return naked pool balance */ getNakedPoolBalance(assetAddress) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const assetAmount = yield ((_a = this.contract) === null || _a === void 0 ? void 0 : _a.getNakedPoolBalance(assetAddress)); const decimals = yield (0, cache_1.cDecimals)(assetAddress); return (0, utils_js_1.$float)(assetAmount, decimals); }); } /** * @notice get an vToken's payout/cash value after expiry, in the collateral asset * @param vTokenAddress vToken address * @param vTokenAmount amount of the vToken to calculate the payout for, always represented in 1e8 * @return amount of collateral to pay out */ getPayout(vTokenAddress, vTokenAmount) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const scaledVTokenAmount = (0, utils_js_1.$)(vTokenAmount, protocols_1.VTOKEN_DECIMALS); const payout = yield ((_a = this.contract) === null || _a === void 0 ? void 0 : _a.getPayout(vTokenAddress, scaledVTokenAmount.toString(10))); const vTokenDetails = yield (0, cache_1.cVTokenDetails)(vTokenAddress); const decimals = yield (0, cache_1.cDecimals)(vTokenDetails.collateralAsset); return (0, utils_js_1.$float)(payout.toString(), decimals); }); } /** * @notice get the number of vaults for a specified account owner * @param ownerAddress account owner address * @return number of vaults */ getAccountVaultCounter(ownerAddress) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { return (yield ((_a = this.contract) === null || _a === void 0 ? void 0 : _a.getAccountVaultCounter(ownerAddress))).toNumber(); }); } /** * @notice return a specific vault * @param ownerAddress account owner * @param vaultId vault id of vault to return * @return INativeVault struct that corresponds to the _vaultId of _owner */ getVault(ownerAddress, vaultId) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const vault = yield ((_a = this.contract) === null || _a === void 0 ? void 0 : _a.getVault(ownerAddress, vaultId)); return this.v(vault); }); } /** * @notice return a specific vault * @param ownerAddress account owner * @param vaultId vault id of vault to return * @return INativeVault struct that corresponds to the vaultId of ownerAddress, vault type and the latest timestamp when the vault was updated */ getVaultWithDetails(ownerAddress, vaultId) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const [vault, vaultType, vaultLatestUpdate] = yield ((_a = this.contract) === null || _a === void 0 ? void 0 : _a.getVaultWithDetails(ownerAddress, vaultId)); return [yield this.v(vault), (0, bytes_1.hexlify)(vaultType), vaultLatestUpdate.toNumber()]; }); } /** * @notice mint short vTokens from a vault which creates an obligation that is recorded in the vault * @dev only the account owner or operator can mint an vToken, cannot be called when system is partiallyPaused or fullyPaused * @param wallet * @param vaultId * @param index * @param vToken * @param vTokenAmount * @param vaultType */ short(wallet, vaultId, index, vToken, vTokenAmount, vaultType = protocols_1.VaultType.FullyCollateralized) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const collateralContract = new utils_js_1.ERC20(vToken.collateralAsset, this.endpoint); const collateralAmount = vToken.isPut ? vToken.strikePrice.multipliedBy(vTokenAmount) : vTokenAmount; const scaledCollateralAmount = (0, utils_js_1.$)(collateralAmount, yield collateralContract.decimals()); const scaledVTokenAmount = (0, utils_js_1.$)(vTokenAmount, protocols_1.VTOKEN_DECIMALS); const configuration = yield this.getConfiguration(); const allowance = yield collateralContract.allowance(yield wallet.getAddress(), configuration.pool); if (allowance.lt(scaledCollateralAmount)) { const tx = yield collateralContract.approve(wallet, configuration.pool, new utils_js_1.BigNumber(utils_js_1.ONE_BYTES32)); yield tx.wait(); } return this.shortOptionOp(wallet, vaultId, index, vToken.address, collateralContract.address, scaledVTokenAmount, scaledCollateralAmount, vaultType); }); } /** * @notice redeem an vToken after expiry, receiving the payout of the vToken in the collateral asset * @dev cannot be called when system is fullyPaused * @param wallet * @param vToken * @param vTokenAmount */ redeem(wallet, vToken, vTokenAmount) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const scaledVTokenAmount = (0, utils_js_1.$)(vTokenAmount, protocols_1.VTOKEN_DECIMALS); return this.redeemOp(wallet, [vToken.address], [scaledVTokenAmount]); }); } /** * @notice settle a vault after expiry, removing the net proceeds/collateral after both long and short vToken payouts have settled * @dev deletes a vault of vaultId after net proceeds/collateral is removed, cannot be called when system is fullyPaused * @param wallet * @param vaultId * @param vault */ settle(wallet, vaultId, vault) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (vaultId > VIRTUAL_VAULT_ID_MIN) { const scaledVTokenAmounts = vault.longAmounts.map(longAmount => { return (0, utils_js_1.$)(longAmount, protocols_1.VTOKEN_DECIMALS); }); return this.redeemOp(wallet, vault.longVTokens, scaledVTokenAmounts); } return this.settleVaultOp(wallet, vaultId); }); } /** * @notice liquidate naked margin vault * @dev can liquidate different vaults id in the same operate() call * @param wallet * @param ownerAddress * @param vaultId * @param vTokenAmount */ liquidate(wallet, ownerAddress, vaultId, vTokenAmount) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const scaledVTokenAmount = (0, utils_js_1.$)(vTokenAmount, protocols_1.VTOKEN_DECIMALS); return this.liquidateOp(wallet, ownerAddress, vaultId, scaledVTokenAmount); }); } /** * @notice deposit a collateral asset into a vault * @dev only the account owner or operator can deposit collateral, cannot be called when system is partiallyPaused or fullyPaused * @param owner * @param vaultId * @param index * @param collateralAddress * @param collateralAmount */ depositCollateral(owner, vaultId, index, collateralAddress, collateralAmount) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const collateralContract = new utils_js_1.ERC20(collateralAddress, this.endpoint); const collateralDecimals = yield collateralContract.decimals(); const scaledCollateralAmount = (0, utils_js_1.$)(collateralAmount, collateralDecimals); const configuration = yield this.getConfiguration(); const allowance = new utils_js_1.BigNumber((yield collateralContract.allowance(yield owner.getAddress(), configuration.pool)).toString()); if (allowance.lt(scaledCollateralAmount)) { const tx = yield collateralContract.approve(owner, configuration.pool, new utils_js_1.BigNumber(utils_js_1.ONE_BYTES32)); yield tx.wait(); } return this.depositOp(protocols_1.ActionType.DepositCollateral, owner, vaultId, index, collateralAddress, scaledCollateralAmount); }); } /** * @notice withdraw a collateral asset from a vault * @dev only the account owner or operator can withdraw collateral, cannot be called when system is partiallyPaused or fullyPaused * @param owner * @param vaultId * @param index * @param collateralAddress * @param collateralAmount */ withdrawCollateral(owner, vaultId, index, collateralAddress, collateralAmount) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const collateralDecimals = yield utils_js_1.ERC20.Decimals(collateralAddress); const scaledCollateralAmount = (0, utils_js_1.$)(collateralAmount, collateralDecimals); return this.withdrawOp(protocols_1.ActionType.WithdrawCollateral, owner, vaultId, index, collateralAddress, scaledCollateralAmount); }); } /** * @notice deposit a long vToken into a vault * @dev only the account owner or operator can deposit a long vToken, cannot be called when system is partiallyPaused or fullyPaused * @param owner * @param vaultId * @param index * @param vToken * @param vTokenAmount */ depositLong(owner, vaultId, index, vToken, vTokenAmount) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const vTokenContract = new VTokenImpl_1.VTokenImpl(vToken.address, this.endpoint); const scaledVTokenAmount = (0, utils_js_1.$)(vTokenAmount, protocols_1.VTOKEN_DECIMALS); const configuration = yield this.getConfiguration(); const allowance = yield vTokenContract.allowance(yield owner.getAddress(), configuration.pool); if (allowance.lt(scaledVTokenAmount)) { const tx = yield vTokenContract.approve(owner, configuration.pool, new utils_js_1.BigNumber(utils_js_1.ONE_BYTES32)); yield tx.wait(); } return this.depositOp(protocols_1.ActionType.DepositLongOption, owner, vaultId, index, vToken.address, scaledVTokenAmount); }); } /** * @notice withdraw a long vToken from a vault * @dev only the account owner or operator can withdraw a long vToken, cannot be called when system is partiallyPaused or fullyPaused * @param owner * @param vaultId * @param index * @param vToken * @param vTokenAmount */ withdrawLong(owner, vaultId, index, vToken, vTokenAmount) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const scaledVTokenAmount = (0, utils_js_1.$)(vTokenAmount, protocols_1.VTOKEN_DECIMALS); return this.withdrawOp(protocols_1.ActionType.WithdrawLongOption, owner, vaultId, index, vToken.address, scaledVTokenAmount); }); } v(vault) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const [shortVTokens, longVTokens, collateralAssets, shortAmounts, longAmounts, collateralAmounts] = vault; const scaledCollateralAmounts = []; for (let i = 0; i < collateralAssets.length; i++) { if (collateralAssets[i] === utils_js_1.ZERO_ADDR) { scaledCollateralAmounts[i] = utils_js_1.ZERO; } else { const decimals = yield (0, cache_1.cDecimals)(collateralAssets[i]); scaledCollateralAmounts[i] = (0, utils_js_1.$float)(collateralAmounts[i].toString(), decimals); } } return { shortVTokens, longVTokens, collateralAssets, shortAmounts: shortAmounts.map((amount) => (0, utils_js_1.$float)(amount.toString(), protocols_1.VTOKEN_DECIMALS)), longAmounts: longAmounts.map((amount) => (0, utils_js_1.$float)(amount.toString(), protocols_1.VTOKEN_DECIMALS)), collateralAmounts: scaledCollateralAmounts, }; }); } shortOptionOp(owner, vaultId, index, vTokenAddress, collateralAddress, scaledVTokenAmount, scaledCollateralAmount, vaultType = protocols_1.VaultType.FullyCollateralized) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const ownerAddress = yield owner.getAddress(); const vaultCounter = yield this.getAccountVaultCounter(ownerAddress); const actionArgs = []; if (vaultId > vaultCounter) { throw errors_1.CONTROLLER.C35; } if (vaultId === 0) { vaultId = vaultCounter + 1; actionArgs.push({ actionType: protocols_1.ActionType.OpenVault, owner: ownerAddress, secondAddress: ownerAddress, asset: utils_js_1.ZERO_ADDR, vaultId: vaultId, amount: 0, index: 0, data: (0, bytes_1.hexZeroPad)(vaultType, 32), }); } actionArgs.push({ actionType: protocols_1.ActionType.MintShortOption, owner: ownerAddress, secondAddress: ownerAddress, asset: vTokenAddress, vaultId, amount: scaledVTokenAmount.toString(10), index, data: utils_js_1.ZERO_ADDR, }, { actionType: protocols_1.ActionType.DepositCollateral, owner: ownerAddress, secondAddress: ownerAddress, asset: collateralAddress, vaultId, amount: scaledCollateralAmount.toString(10), index, data: utils_js_1.ZERO_ADDR, }); try { return yield ((_a = this.contract) === null || _a === void 0 ? void 0 : _a.connect(owner).operate(actionArgs)); } catch (e) { const s = e.error.reason.split(': '); console.log(`${s[1]}: ${(0, errors_1.reason)(s[1])}`); throw e; } }); } settleVaultOp(owner, vaultId) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const ownerAddress = yield owner.getAddress(); const actionArgs = [ { actionType: protocols_1.ActionType.SettleVault, owner: ownerAddress, secondAddress: ownerAddress, asset: utils_js_1.ZERO_ADDR, vaultId, amount: 0, index: 0, data: utils_js_1.ZERO_ADDR, }, ]; return (_a = this.contract) === null || _a === void 0 ? void 0 : _a.connect(owner).operate(actionArgs); }); } redeemOp(owner, vTokenAddresses, scaledVTokenAmounts) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const ownerAddress = yield owner.getAddress(); const actionArgs = []; for (let i = 0; i < vTokenAddresses.length; i++) { actionArgs[i] = { actionType: protocols_1.ActionType.Redeem, owner: ownerAddress, secondAddress: ownerAddress, asset: vTokenAddresses[i], vaultId: 0, amount: scaledVTokenAmounts[i].toString(10), index: 0, data: utils_js_1.ZERO_ADDR, }; } return (_a = this.contract) === null || _a === void 0 ? void 0 : _a.connect(owner).operate(actionArgs); }); } liquidateOp(wallet, ownerAddress, vaultId, scaledVTokenAmount) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { const receiverAddress = yield wallet.getAddress(); const actionArgs = [ { actionType: protocols_1.ActionType.Liquidate, owner: ownerAddress, secondAddress: receiverAddress, asset: utils_js_1.ZERO_ADDR, vaultId, amount: scaledVTokenAmount.toString(10), index: 0, data: utils_js_1.ZERO_ADDR, }, ]; return (_a = this.contract) === null || _a === void 0 ? void 0 : _a.connect(wallet).operate(actionArgs); }); } depositOp(actionType, owner, vaultId, index, assetAddress, scaledAssetAmount) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { if (actionType !== protocols_1.ActionType.DepositCollateral && actionType !== protocols_1.ActionType.DepositLongOption) { throw errors_1.LIB_ACTIONS.A8; } const ownerAddress = yield owner.getAddress(); const actionArgs = [ { actionType, owner: ownerAddress, secondAddress: ownerAddress, asset: assetAddress, vaultId, amount: scaledAssetAmount.toString(10), index, data: utils_js_1.ZERO_ADDR, }, ]; return (_a = this.contract) === null || _a === void 0 ? void 0 : _a.connect(owner).operate(actionArgs); }); } withdrawOp(actionType, owner, vaultId, index, assetAddress, scaledAssetAmount) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function* () { if (actionType !== protocols_1.ActionType.WithdrawCollateral && actionType !== protocols_1.ActionType.WithdrawLongOption) { throw errors_1.LIB_ACTIONS.A10; } const ownerAddress = yield owner.getAddress(); const actionArgs = [ { actionType, owner: ownerAddress, secondAddress: ownerAddress, asset: assetAddress, vaultId, amount: scaledAssetAmount.toString(10), index, data: utils_js_1.ZERO_ADDR, }, ]; return (_a = this.contract) === null || _a === void 0 ? void 0 : _a.connect(owner).operate(actionArgs); }); } } exports.Controller = Controller; Controller.OwnershipTransferred_t0 = ethers_1.utils.id('OwnershipTransferred(address,address)'); //# sourceMappingURL=Controller.js.map