@q-dev/q-js-sdk
Version:
Typescript Library to interact with Q System Contracts
164 lines • 7.06 kB
JavaScript
;
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