"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
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.CurveChildLiquidityGaugeContractPositionFetcher = void 0;
const common_1 = require("@nestjs/common");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const lodash_1 = require("lodash");
const moment_1 = __importDefault(require("moment"));
const app_toolkit_interface_1 = require("../../../app-toolkit/app-toolkit.interface");
const address_1 = require("../../../app-toolkit/constants/address");
const image_present_1 = require("../../../app-toolkit/helpers/presentation/image.present");
const position_interface_1 = require("../../../position/position.interface");
const position_utils_1 = require("../../../position/position.utils");
const contract_position_template_position_fetcher_1 = require("../../../position/template/contract-position.template.position-fetcher");
const contracts_1 = require("../contracts");
const curve_pool_gauge_contract_position_fetcher_1 = require("./curve.pool-gauge.contract-position-fetcher");
let CurveChildLiquidityGaugeContractPositionFetcher = class CurveChildLiquidityGaugeContractPositionFetcher extends contract_position_template_position_fetcher_1.ContractPositionTemplatePositionFetcher {
    constructor(appToolkit, contractFactory) {
        super(appToolkit);
        this.appToolkit = appToolkit;
        this.contractFactory = contractFactory;
    }
    getContract(address) {
        return this.contractFactory.curveChildLiquidityGauge({ address, network: this.network });
    }
    getDefinitions({ multicall }) {
        return __awaiter(this, void 0, void 0, function* () {
            const factory = this.contractFactory.curveChildLiquidityGaugeFactory({
                address: this.factoryAddress,
                network: this.network,
            });
            const gaugeCount = yield multicall.wrap(factory).get_gauge_count();
            const gaugeRange = (0, lodash_1.range)(0, Number(gaugeCount));
            const gaugeDefinitions = yield Promise.all(gaugeRange.map((index) => __awaiter(this, void 0, void 0, function* () {
                const gaugeAddress = yield multicall.wrap(factory).get_gauge(index);
                return { address: gaugeAddress.toLowerCase(), gaugeType: curve_pool_gauge_contract_position_fetcher_1.GaugeType.CHILD };
            })));
            return gaugeDefinitions.flat();
        });
    }
    getTokenDefinitions({ contract }) {
        return __awaiter(this, void 0, void 0, function* () {
            const lpTokenAddress = yield contract.lp_token();
            const definitions = [{ metaType: position_interface_1.MetaType.SUPPLIED, address: lpTokenAddress, network: this.network }];
            definitions.push({ metaType: position_interface_1.MetaType.CLAIMABLE, address: this.crvTokenAddress, network: this.network });
            const rewardTokenAddresses = yield Promise.all((0, lodash_1.range)(0, 4).map(i => contract.reward_tokens(i)));
            const filtered = rewardTokenAddresses.filter(v => v !== address_1.ZERO_ADDRESS);
            filtered.forEach(v => definitions.push({ metaType: position_interface_1.MetaType.CLAIMABLE, address: v, network: this.network }));
            return definitions;
        });
    }
    getDataProps({ address, contract, multicall, contractPosition, definition, }) {
        return __awaiter(this, void 0, void 0, function* () {
            const stakedToken = contractPosition.tokens.find(position_utils_1.isSupplied);
            const rewardTokens = contractPosition.tokens.filter(position_utils_1.isClaimable);
            const stakedTokenContract = this.contractFactory.erc20(stakedToken);
            const reserveRaw = yield multicall.wrap(stakedTokenContract).balanceOf(address);
            const reserve = Number(reserveRaw) / Math.pow(10, stakedToken.decimals);
            const liquidity = reserve * stakedToken.price;
            const gaugeType = definition.gaugeType;
            const period = yield contract.period();
            const periodTimestamp = yield contract.period_timestamp(period);
            const periodWeek = Math.floor(periodTimestamp.toNumber() / moment_1.default.duration(7, 'days').asSeconds());
            const crvToken = rewardTokens.find(v => v.address === this.crvTokenAddress);
            const crvInflationRateRaw = yield contract.inflation_rate(periodWeek);
            const crvInflationRate = Number(crvInflationRateRaw) / Math.pow(10, crvToken.decimals);
            const crvYearlyReward = crvInflationRate * moment_1.default.duration(1, 'year').asSeconds();
            const crvYearlyRewardInUSD = crvYearlyReward * crvToken.price;
            const rewardTokenCount = yield contract.reward_count();
            const individualRewardsInUSD = yield Promise.all((0, lodash_1.range)(0, Number(rewardTokenCount)).map((index) => __awaiter(this, void 0, void 0, function* () {
                const rewardTokenAddressRaw = yield contract.reward_tokens(index);
                const rewardTokenAddress = rewardTokenAddressRaw.toLowerCase();
                const rewardToken = rewardTokens.find(p => p.address === rewardTokenAddress);
                if (!rewardToken)
                    return 0;
                const rewardData = yield contract.reward_data(rewardTokenAddress);
                if (Number(rewardData.period_finish) < Date.now() / 1000)
                    return 0;
                return new bignumber_js_1.default(rewardData.rate.toString())
                    .times(365 * 24 * 60 * 60)
                    .times(rewardToken.price)
                    .dividedBy(Math.pow(10, rewardToken.decimals))
                    .toNumber();
            })));
            const apy = liquidity > 0 ? (((0, lodash_1.sum)(individualRewardsInUSD) + crvYearlyRewardInUSD) / liquidity) * 100 : 0;
            const isActive = crvInflationRate > 0;
            return { gaugeType, liquidity, apy, isActive };
        });
    }
    getLabel({ contractPosition, }) {
        return __awaiter(this, void 0, void 0, function* () {
            return `Staked ${(0, image_present_1.getLabelFromToken)(contractPosition.tokens[0])}`;
        });
    }
    getTokenBalancesPerPosition({ address, contractPosition, contract, }) {
        return __awaiter(this, void 0, void 0, function* () {
            const rewardTokens = contractPosition.tokens.filter(position_utils_1.isClaimable);
            const balances = [
                yield contract.balanceOf(address),
                yield contract.callStatic.claimable_tokens(address),
                ...(yield Promise.all(rewardTokens.slice(1).map(t => contract.claimable_reward(address, t.address)))),
            ];
            return balances;
        });
    }
};
CurveChildLiquidityGaugeContractPositionFetcher = __decorate([
    __param(0, (0, common_1.Inject)(app_toolkit_interface_1.APP_TOOLKIT)),
    __param(1, (0, common_1.Inject)(contracts_1.CurveContractFactory)),
    __metadata("design:paramtypes", [Object, contracts_1.CurveContractFactory])
], CurveChildLiquidityGaugeContractPositionFetcher);
exports.CurveChildLiquidityGaugeContractPositionFetcher = CurveChildLiquidityGaugeContractPositionFetcher;
//# sourceMappingURL=curve.child-liquidity-gauge.contract-position-fetcher.js.map