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());
    });
};
import axios from "axios";
import { BigNumber, constants, utils } from "ethers";
import ComptrollerABI from "../../abis/Comptroller";
import EIP20InterfaceABI from "../../abis/EIP20Interface";
import ICErc20ABI from "../../abis/ICErc20";
import { getContract } from "../IonicSdk/utils";
import { ChainSupportedAssets } from "./Pools";
export function withFundOperations(Base) {
    return class FundOperations extends Base {
        fetchGasForCall(amount, address) {
            return __awaiter(this, void 0, void 0, function* () {
                const estimatedGas = BigNumber.from(((yield this.provider.estimateGas({
                    from: address,
                    value: amount.div(BigNumber.from(2))
                })).toNumber() * 3.13).toFixed(0));
                const res = yield axios.get("/api/getGasPrice");
                const average = res.data.average;
                const gasPrice = utils.parseUnits(average.toString(), "gwei");
                const gasWEI = estimatedGas.mul(gasPrice);
                return { gasWEI, gasPrice, estimatedGas };
            });
        }
        approve(cTokenAddress, underlyingTokenAddress) {
            return __awaiter(this, void 0, void 0, function* () {
                const token = getContract(underlyingTokenAddress, EIP20InterfaceABI, this.signer);
                const max = BigNumber.from(2).pow(BigNumber.from(256)).sub(constants.One);
                const tx = yield token.approve(cTokenAddress, max);
                return tx;
            });
        }
        enterMarkets(cTokenAddress, comptrollerAddress) {
            return __awaiter(this, void 0, void 0, function* () {
                const comptrollerInstance = getContract(comptrollerAddress, ComptrollerABI, this.signer);
                const tx = yield comptrollerInstance.enterMarkets([cTokenAddress]);
                return tx;
            });
        }
        mint(cTokenAddress, amount) {
            return __awaiter(this, void 0, void 0, function* () {
                const cToken = getContract(cTokenAddress, ICErc20ABI, this.signer);
                const address = yield this.signer.getAddress();
                // add 10% to default estimated gas
                const gasLimit = (yield cToken.estimateGas.mint(amount, { from: address })).mul(11).div(10);
                const response = (yield cToken.callStatic.mint(amount, { gasLimit, from: address }));
                if (response.toString() !== "0") {
                    const errorCode = parseInt(response.toString());
                    return { errorCode };
                }
                const tx = yield cToken.mint(amount, { gasLimit, from: address });
                return { tx, errorCode: null };
            });
        }
        repay(cTokenAddress, isRepayingMax, amount) {
            return __awaiter(this, void 0, void 0, function* () {
                const max = BigNumber.from(2).pow(BigNumber.from(256)).sub(constants.One);
                const cToken = getContract(cTokenAddress, ICErc20ABI, this.signer);
                const response = (yield cToken.callStatic.repayBorrow(isRepayingMax ? max : amount));
                if (response.toString() !== "0") {
                    const errorCode = parseInt(response.toString());
                    return { errorCode };
                }
                const tx = yield cToken.repayBorrow(isRepayingMax ? max : amount);
                return { tx, errorCode: null };
            });
        }
        borrow(cTokenAddress, amount) {
            return __awaiter(this, void 0, void 0, function* () {
                const cToken = getContract(cTokenAddress, ICErc20ABI, this.signer);
                const address = yield this.signer.getAddress();
                // add 20% to default estimated gas
                const gasLimit = (yield cToken.estimateGas.borrow(amount, { from: address })).mul(12).div(10);
                const response = (yield cToken.callStatic.borrow(amount, { gasLimit, from: address }));
                if (response.toString() !== "0") {
                    const errorCode = parseInt(response.toString());
                    return { errorCode };
                }
                const tx = yield cToken.borrow(amount, { gasLimit, from: address });
                return { tx, errorCode: null };
            });
        }
        withdraw(cTokenAddress, amount) {
            return __awaiter(this, void 0, void 0, function* () {
                const cToken = getContract(cTokenAddress, ICErc20ABI, this.signer);
                const response = (yield cToken.callStatic.redeemUnderlying(amount));
                if (response.toString() !== "0") {
                    const errorCode = parseInt(response.toString());
                    return { errorCode };
                }
                const tx = yield cToken.redeemUnderlying(amount);
                return { tx, errorCode: null };
            });
        }
        swap(inputToken, amount, outputToken) {
            return __awaiter(this, void 0, void 0, function* () {
                const iLiquidatorsRegistry = this.createILiquidatorsRegistry(this.signer);
                return yield iLiquidatorsRegistry.amountOutAndSlippageOfSwap(inputToken, amount, outputToken);
            });
        }
        approveLiquidatorsRegistry(underlying) {
            return __awaiter(this, void 0, void 0, function* () {
                const token = getContract(underlying, EIP20InterfaceABI, this.signer);
                const tx = yield token.approve(this.chainDeployment.LiquidatorsRegistry.address, constants.MaxUint256);
                return tx;
            });
        }
        getSwapTokens(outputToken) {
            return __awaiter(this, void 0, void 0, function* () {
                const iLiquidatorsRegistry = this.createILiquidatorsRegistry();
                const tokens = yield iLiquidatorsRegistry.callStatic.getInputTokensByOutputToken(outputToken);
                return tokens.map((token) => {
                    var _a, _b, _c;
                    const _asset = ChainSupportedAssets[this.chainId].find((ass) => ass.underlying === token);
                    return {
                        underlyingToken: token,
                        underlyingSymbol: (_b = (_a = _asset === null || _asset === void 0 ? void 0 : _asset.originalSymbol) !== null && _a !== void 0 ? _a : _asset === null || _asset === void 0 ? void 0 : _asset.symbol) !== null && _b !== void 0 ? _b : token,
                        underlyingDecimals: (_c = _asset === null || _asset === void 0 ? void 0 : _asset.decimals) !== null && _c !== void 0 ? _c : 18
                    };
                });
            });
        }
        getAmountOutAndSlippageOfSwap(inputToken, amount, outputToken) {
            return __awaiter(this, void 0, void 0, function* () {
                const iLiquidatorsRegistry = this.createILiquidatorsRegistry();
                const account = yield this.signer.getAddress();
                return yield iLiquidatorsRegistry.callStatic.amountOutAndSlippageOfSwap(inputToken, amount, outputToken, {
                    from: account
                });
            });
        }
    };
}
