Home Reference Source

packages/oo7-substrate/src/srml/staking.js

const { Bond, TransformBond } = require('oo7')
const { ss58Encode } = require('../ss58')
const { Balance } = require('../types')
const balancesModule = require('./balances')
const sessionModule = require('./session')

function compareAccountId(a, b) {
	return a.length === b.length && a.every((v, i) => b[i] === v)
}

function accountIdMemberOf(member, set) {
	return set.find(item => compareAccountId(member, item)) !== undefined
}

function augment (runtime, chain) {
	sessionModule.augment(runtime, chain)
	balancesModule.augment(runtime, chain)
	let session = runtime.session
	let staking = runtime.staking
	let balances = runtime.balances
	if (staking._extras) {
		return
	} else {
		staking._extras = true
	}

	staking.thisSessionReward = new TransformBond(
		(r, l) => Math.round(r / l),
		[
			staking.sessionReward,
			session.lateness
		]
	)

	staking.currentNominatedBalance = who => staking.currentNominatorsFor(who)
		.map(ns => ns.map(n => balances.totalBalance(n)), 2)
		.map(bs => new Balance(bs.reduce((a, b) => a + b, 0)))
	staking.nominatedBalance = who => staking.nominatorsFor(who)
		.map(ns => ns.map(n => balances.totalBalance(n)), 2)
		.map(bs => new Balance(bs.reduce((a, b) => a + b, 0)))
	staking.stakingBalance = who => Bond
		.all([balances.totalBalance(who), staking.nominatedBalance(who)])
		.map(([f, r]) => new Balance(f + r));
	staking.currentStakingBalance = who => Bond
		.all([balances.totalBalance(who), staking.currentNominatedBalance(who)])
		.map(([f, r]) => new Balance(f + r));
		
	staking.eraLength = new TransformBond(
		(a, b) => a * b,
		[
			staking.sessionsPerEra,
			session.sessionLength
		])
	
	staking.validators = Bond.all([staking.invulerables, session.validators])
		.map(([inv, v]) => v.map(who => ({
			who,
			ownBalance: balances.totalBalance(who),
			otherBalance: staking.currentNominatedBalance(who),
			nominators: staking.currentNominatorsFor(who),
			invulnerable: accountIdMemberOf(who, inv)
		})), 2)
		.map(v => v
			.map(i => Object.assign({balance: i.ownBalance.add(i.otherBalance)}, i))
			.sort((a, b) => b.balance - a.balance)
		)

	staking.nextThreeUp = staking.intentions.map(
			l => ([session.validators, l.map(who => ({
				who, ownBalance: balances.totalBalance(who), otherBalance: staking.nominatedBalance(who)
			}) ) ]), 3
		).map(([c, l]) => l
			.map(i => Object.assign({balance: i.ownBalance.add(i.otherBalance)}, i))
			.sort((a, b) => b.balance - a.balance)
			.filter(i => !c.some(x => x+'' == i.who+''))
			.slice(0, 3)
		)

	staking.nextValidators = Bond
		.all([
			staking.intentions.map(v => v.map(who => ({
				who,
				ownBalance: balances.totalBalance(who),
				otherBalance: staking.nominatedBalance(who),
				nominators: staking.nominatorsFor(who)
			})), 2),
			staking.validatorCount
		]).map(([as, vc]) => as
			.map(i => Object.assign({balance: i.ownBalance.add(i.otherBalance)}, i))
			.sort((a, b) => b.balance - a.balance)
			.slice(0, vc)
		)

	staking.eraSessionsRemaining = new TransformBond(
		(spe, si, lec) => (spe - 1 - (si - lec) % spe),
		[
			staking.sessionsPerEra,
			session.currentIndex,
			staking.lastEraLengthChange
		])

	staking.eraBlocksRemaining = new TransformBond(
		(sl, sr, br) => br + sl * sr, 
		[
			session.sessionLength,
			staking.eraSessionsRemaining,
			session.blocksRemaining
		])

	staking.intentionIndexOf = id =>
		new TransformBond((i, id) => {
			let ss58 = ss58Encode(id);
			return i.findIndex(a => ss58Encode(a) === ss58);
		}, [runtime.staking.intentions, id])
	
	staking.bondageOf = id =>
		new TransformBond(
			(b, h) => h >= b ? null : (b - h),
			[runtime.staking.bondage(id), chain.height]
		)
	
	staking.nominationIndex = (val) =>
		new TransformBond((i, id) => {
			let ss58 = ss58Encode(id);
			return i.findIndex(a => ss58Encode(a) === ss58);
		}, [runtime.staking.nominatorsFor(staking.nominating(val)), val])
}

module.exports = { augment }