UNPKG

@q-dev/q-js-sdk

Version:

Typescript Library to interact with Q System Contracts

164 lines 7.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidatorMetrics = void 0; const __1 = require(".."); const SystemContractInstance_1 = require("../contracts/SystemContractInstance"); const ethers_1 = require("ethers"); const c = new __1.UnitConverter(); const DUSTED_DELEGATED_STAKE = '100'; /** * Helps calculate delegation efficiency and saturation */ class ValidatorMetrics { /** * @internal * Takes snapshot using given data. * Used by unit tests. * @param validatorsInfo ValidatorInfo struct array * @param poolsInfo ValidatorPoolInfo struct array * @param stakeDelegationFactor current stake delegation factor */ setSnapShot(validatorsInfo, poolsInfo, stakeDelegationFactor) { if (validatorsInfo.length !== poolsInfo.length) { throw new RangeError('validatorsInfo length does not equal to poolsInfo length'); } this.validatorsInfo = validatorsInfo; this.poolsInfo = poolsInfo; this.stakeDelegationFactor = stakeDelegationFactor; } /** * Takes snapshot using registry * @param registry Contract registry instance */ async takeSnapshotFromNetwork(registry) { await this.takeSnapshot(await registry.validators(), await registry.validationRewardPools(), await registry.epqfiParameters()); } /** * @internal * Takes snapshot using Validators, ValidationRewardPools and EPQFIParameters instances. * Used by takeSnapshotFromNetwork method * @param validatorsInstance ValidatorsInstance * @param poolsInstance ValidationRewardPoolsInstance * @param parameters EPQFIParametersInstance */ async takeSnapshot(validatorsInstance, poolsInstance, parameters) { const longListAddress = await validatorsInstance.instance.longList(); const { instance: stakesInstance } = new SystemContractInstance_1.SystemContractInstance(validatorsInstance.instance.provider, 'AddressStorageStakes.json', longListAddress); this.validators = await validatorsInstance.getShortList(); const stakeDelegationFactorKey = 'governed.EPQFI.stakeDelegationFactor'; const stakePromises = Promise.all(this.validators.map((v) => this.getStakeInfo(validatorsInstance, stakesInstance, v.address))); const poolPromises = Promise.all(this.validators.map((v) => poolsInstance.getPoolInfo(v.address))); const [infos, pools, stakeDelegationFactor] = await Promise.all([ stakePromises, poolPromises, parameters.getUint(stakeDelegationFactorKey), ]); this.setSnapShot(infos, pools, stakeDelegationFactor); } /** * Returns stored snapshot * @returns ValidatorSnapshot struct array */ getSnapshot() { const validatorSnapshots = this.validatorsInfo.map((v, i) => { return { address: v.address, accountableStake: v.accountableStake, delegatedStake: v.delegatedStake, delegatorsShare: this.poolsInfo[i].delegatorsShare, selfStake: v.selfStake, totalStake: v.totalStake, stakeDelegationFactor: this.stakeDelegationFactor, }; }); return validatorSnapshots; } /** * Calculates delegation efficiency using snapshot * @returns Delegation efficiency */ getDelegationEfficiency() { var _a; const globalAccountableStake = (_a = this.validatorsInfo) === null || _a === void 0 ? void 0 : _a.reduce((acc, v) => acc.plus(v.accountableStake), c.toBigNumber(0)); const delegators = this.validatorsInfo.map((v, i) => { const poolInfo = this.poolsInfo[i]; const globalStakeShare = globalAccountableStake.isGreaterThan(0) ? c.toBigNumber(v.accountableStake).div(globalAccountableStake) : c.toBigNumber(0); const payoutToDelegator = globalStakeShare.multipliedBy(poolInfo.delegatorsShare); const delegatedStake = c.toBigNumber(v.delegatedStake); const payoutPerDelegatedQ = delegatedStake.isGreaterThan(DUSTED_DELEGATED_STAKE) ? payoutToDelegator.div(delegatedStake).toString() : '0'; return { address: v.address, payoutPerDelegatedQ, globalStakeShare: globalStakeShare.toString(), delegatorShare: poolInfo.delegatorsShare.toString(), payoutToDelegators: payoutToDelegator.toString(), }; }); const totalPayoutPerDelegatedQ = delegators.reduce((acc, v) => acc.plus(v.payoutPerDelegatedQ), c.toBigNumber(0)); const delegationEfficiency = delegators.map((v) => { const delegationEfficiency = globalAccountableStake.isGreaterThan(0) ? c .toBigNumber(v.payoutPerDelegatedQ) .multipliedBy(100) .div(totalPayoutPerDelegatedQ) .toString() : '0'; return { ...v, delegationEfficiency, }; }); return delegationEfficiency; } /** * Calculates delegation saturation using snapshot * @returns DelegationSaturation */ getDelegationSaturation() { const stakeDelegationFactor = c.fromSmallestUnit(this.stakeDelegationFactor, 29); return this.validatorsInfo.map((v) => { const saturation = c .toBigNumber(v.currentDelegationFactor) .div(stakeDelegationFactor); return saturation.toString(); }); } /** * Return short validator list using snapshot * @returns AddressWithBalance[] */ getValidatorsShortList() { return this.validators; } /** * Calculates stake information using snapshot * @returns StakeInfo */ async getStakeInfo(validatorsInstance, stakesInstance, address) { var _a; const [{ stake, delegatedStake }, withdrawalInfo] = await Promise.all([ stakesInstance.addrStake(address), validatorsInstance.getWithdrawalInfo(address), ]); const selfStake = ethers_1.utils.formatUnits(stake); const totalStake = ethers_1.utils.formatUnits(stake.add(delegatedStake).sub(withdrawalInfo.amount)); const accountableStake = ((_a = this.validators.find((v) => v.address === address)) === null || _a === void 0 ? void 0 : _a.balance) || '0'; return { address, selfStake, delegatedStake: ethers_1.utils.formatUnits(delegatedStake), totalStake, accountableStake: accountableStake.toString(), currentDelegationFactor: c .toBigNumber(totalStake) .div(selfStake) .toNumber(), }; } } exports.ValidatorMetrics = ValidatorMetrics; //# sourceMappingURL=validator-metrics.js.map