"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.withVaults = void 0;
const types_1 = require("@ionicprotocol/types");
const ethers_1 = require("ethers");
const EIP20Interface_1 = __importDefault(require("../../abis/EIP20Interface"));
const utils_1 = require("../IonicSdk/utils");
const Pools_1 = require("./Pools");
function withVaults(Base) {
    return class Vaults extends Base {
        getAllVaults() {
            return __awaiter(this, void 0, void 0, function* () {
                if (this.chainId === types_1.SupportedChains.chapel) {
                    try {
                        const optimizedVaultsRegistry = this.createOptimizedVaultsRegistry();
                        const vaultsData = yield optimizedVaultsRegistry.callStatic.getVaultsData();
                        const mpo = this.createMasterPriceOracle();
                        return yield Promise.all(vaultsData.map((data) => __awaiter(this, void 0, void 0, function* () {
                            let symbol = data.assetSymbol;
                            let extraDocs;
                            const asset = Pools_1.ChainSupportedAssets[this.chainId].find((ass) => ass.underlying === data.asset);
                            if (asset) {
                                symbol = asset.symbol;
                                extraDocs = asset.extraDocs;
                            }
                            const underlyingPrice = yield mpo.callStatic.price(data.asset);
                            const totalSupplyNative = Number(ethers_1.utils.formatUnits(data.estimatedTotalAssets, data.assetDecimals)) *
                                Number(ethers_1.utils.formatUnits(underlyingPrice, 18));
                            return {
                                vault: data.vault,
                                chainId: this.chainId,
                                totalSupply: data.estimatedTotalAssets,
                                totalSupplyNative,
                                asset: data.asset,
                                symbol,
                                supplyApy: data.apr,
                                adaptersCount: Number(data.adaptersCount),
                                isEmergencyStopped: data.isEmergencyStopped,
                                adapters: data.adaptersData,
                                decimals: data.assetDecimals,
                                underlyingPrice,
                                extraDocs,
                                performanceFee: data.performanceFee,
                                depositFee: data.depositFee,
                                withdrawalFee: data.withdrawalFee,
                                managementFee: data.managementFee
                            };
                        })));
                    }
                    catch (error) {
                        this.logger.error(`get vaults error in chain ${this.chainId}:  ${error}`);
                        throw Error(`Getting vaults failed in chain ${this.chainId}: ` + (error instanceof Error ? error.message : error));
                    }
                }
                else {
                    return [];
                }
            });
        }
        getClaimableRewardsForVaults(account) {
            return __awaiter(this, void 0, void 0, function* () {
                if (this.chainId === types_1.SupportedChains.chapel) {
                    try {
                        const rewardsInfoForVaults = [];
                        const optimizedVaultsRegistry = this.createOptimizedVaultsRegistry();
                        const claimableRewards = yield optimizedVaultsRegistry.callStatic.getClaimableRewards(account);
                        claimableRewards.map((reward) => {
                            if (reward.rewards.gt(0)) {
                                const vault = reward.vault;
                                const chainId = Number(this.chainId);
                                // trying to get reward token symbol from defined assets list in sdk
                                const asset = Pools_1.ChainSupportedAssets[this.chainId].find((ass) => ass.underlying === reward.rewardToken);
                                const rewardTokenSymbol = asset ? asset.symbol : reward.rewardTokenSymbol;
                                const rewardsInfo = {
                                    rewardToken: reward.rewardToken,
                                    flywheel: reward.flywheel,
                                    rewards: reward.rewards,
                                    rewardTokenDecimals: reward.rewardTokenDecimals,
                                    rewardTokenSymbol
                                };
                                const rewardsAdded = rewardsInfoForVaults.find((info) => info.vault === vault);
                                if (rewardsAdded) {
                                    rewardsAdded.rewardsInfo.push(rewardsInfo);
                                }
                                else {
                                    rewardsInfoForVaults.push({ vault, chainId, rewardsInfo: [rewardsInfo] });
                                }
                            }
                        });
                        return rewardsInfoForVaults;
                    }
                    catch (error) {
                        this.logger.error(`get claimable rewards of vaults error for account ${account} in chain ${this.chainId}:  ${error}`);
                        throw Error(`get claimable rewards of vaults error for account ${account} in chain ${this.chainId}: ` +
                            (error instanceof Error ? error.message : error));
                    }
                }
                else {
                    return [];
                }
            });
        }
        vaultApprove(vault, asset) {
            return __awaiter(this, void 0, void 0, function* () {
                const token = (0, utils_1.getContract)(asset, EIP20Interface_1.default, this.signer);
                const tx = yield token.approve(vault, ethers_1.constants.MaxUint256);
                return tx;
            });
        }
        vaultDeposit(vault, amount) {
            return __awaiter(this, void 0, void 0, function* () {
                const optimizedAPRVault = this.createOptimizedAPRVault(vault, this.signer);
                const tx = yield optimizedAPRVault["deposit(uint256)"](amount);
                return { tx };
            });
        }
        vaultWithdraw(vault, amount) {
            return __awaiter(this, void 0, void 0, function* () {
                const optimizedAPRVault = this.createOptimizedAPRVault(vault, this.signer);
                const tx = yield optimizedAPRVault["withdraw(uint256)"](amount);
                return { tx };
            });
        }
        getUpdatedVault(mode, vault, amount) {
            return __awaiter(this, void 0, void 0, function* () {
                let updatedVault = vault;
                const optimizedAPRVault = this.createOptimizedAPRVault(vault.vault);
                if (mode === types_1.FundOperationMode.SUPPLY) {
                    const totalSupply = vault.totalSupply.add(amount);
                    const totalSupplyNative = Number(ethers_1.utils.formatUnits(totalSupply, vault.decimals)) * Number(ethers_1.utils.formatUnits(vault.underlyingPrice, 18));
                    const supplyApy = yield optimizedAPRVault.callStatic.supplyAPY(amount);
                    updatedVault = Object.assign(Object.assign({}, vault), { totalSupply,
                        totalSupplyNative,
                        supplyApy });
                }
                else if (mode === types_1.FundOperationMode.WITHDRAW) {
                    const totalSupply = vault.totalSupply.sub(amount);
                    const totalSupplyNative = Number(ethers_1.utils.formatUnits(totalSupply, vault.decimals)) * Number(ethers_1.utils.formatUnits(vault.underlyingPrice, 18));
                    const supplyApy = yield optimizedAPRVault.callStatic.supplyAPY(amount);
                    updatedVault = Object.assign(Object.assign({}, vault), { totalSupply,
                        totalSupplyNative,
                        supplyApy });
                }
                return updatedVault;
            });
        }
        getMaxWithdrawVault(vault) {
            return __awaiter(this, void 0, void 0, function* () {
                const optimizedAPRVault = this.createOptimizedAPRVault(vault, this.signer);
                return yield optimizedAPRVault.callStatic.maxWithdraw(yield this.signer.getAddress());
            });
        }
        getMaxDepositVault(vault) {
            return __awaiter(this, void 0, void 0, function* () {
                const optimizedAPRVault = this.createOptimizedAPRVault(vault, this.signer);
                return yield optimizedAPRVault.callStatic.maxDeposit(yield this.signer.getAddress());
            });
        }
        claimRewardsForVault(vault) {
            return __awaiter(this, void 0, void 0, function* () {
                const optimizedAPRVault = this.createOptimizedAPRVault(vault, this.signer);
                const tx = yield optimizedAPRVault.claimRewards();
                return { tx };
            });
        }
    };
}
exports.withVaults = withVaults;
