Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 43x 43x 43x 43x 43x 43x 43x 43x 132x 132x 144x 150x 132x 144x 145x 171x 145x 160x 132x 144x 144x 145x 161x 160x 162x 161x 150x 192x 192x 193x 193x 64x 176x | import { BigIntMath, Percent, calcPercentages, sameArrayItems } from '@cardano-sdk/util';
import { Cardano } from '@cardano-sdk/core';
import { DelegatedStake } from '../types';
import { DelegationTrackerProps } from './DelegationTracker';
import {
Observable,
combineLatest,
combineLatestWith,
distinctUntilChanged,
iif,
map,
of,
switchMap,
withLatestFrom
} from 'rxjs';
import { createUtxoBalanceByAddressTracker } from '../BalanceTracker';
import { delegatedStakeEquals } from '../util';
import _groupBy from 'lodash/groupBy.js';
import _map from 'lodash/map.js';
type DelegationDistributionTrackerProps = Pick<DelegationTrackerProps, 'knownAddresses$' | 'utxoTracker'> & {
rewardAccounts$: Observable<Cardano.RewardAccountInfo[]>;
};
export const createDelegationDistributionTracker = ({
rewardAccounts$,
knownAddresses$,
utxoTracker
}: DelegationDistributionTrackerProps): Observable<Map<Cardano.PoolId, DelegatedStake>> => {
const balanceAllUtxosTracker = createUtxoBalanceByAddressTracker(utxoTracker);
const delegatedAccounts$ = rewardAccounts$.pipe(
map((rewardsAccounts) =>
rewardsAccounts.filter(
(account) =>
account.credentialStatus === Cardano.StakeCredentialStatus.Registered && account.delegatee?.nextNextEpoch
)
)
);
const hydratedDelegatedAccounts$ = delegatedAccounts$.pipe(
withLatestFrom(knownAddresses$),
map(([delegatedAccounts, knownAddresses]) =>
delegatedAccounts.map((delegatedAccount) => {
const groupedAddresses = knownAddresses.filter(
(knownAddr) => knownAddr.rewardAccount === delegatedAccount.address
);
return {
balance: createUtxoBalanceByAddressTracker(
utxoTracker,
groupedAddresses.map(({ address }) => address)
),
delegatedAccount,
groupedAddresses
};
})
)
);
return hydratedDelegatedAccounts$.pipe(
switchMap((accts) =>
iif(
() => accts.length === 0,
of([]),
combineLatest(
accts.map((acct) =>
acct.balance.utxo.total$.pipe(
map(
(perAccountTotal): DelegatedStake => ({
// Percentage will be calculated in the next step
percentage: Percent(0),
pool: acct.delegatedAccount.delegatee!.nextNextEpoch!,
rewardAccounts: [acct.delegatedAccount.address],
stake: perAccountTotal.coins + acct.delegatedAccount.rewardBalance
})
)
)
)
)
)
),
// Merge rewardAccounts delegating to the same pool
map((delegatedStakes) =>
_map(
_groupBy(delegatedStakes, ({ pool: { id } }) => id),
(pools): DelegatedStake =>
pools.reduce((mergedPool, pool) => ({
...pool,
rewardAccounts: [...new Set([...mergedPool.rewardAccounts, ...pool.rewardAccounts])],
stake: pool.stake + mergedPool.stake || 0n
}))
)
),
// calculate percentages
combineLatestWith(
balanceAllUtxosTracker.utxo.total$,
rewardAccounts$.pipe(map((accts) => BigIntMath.sum(accts.map(({ rewardBalance }) => rewardBalance))))
),
map(([delegatedStakes, utxoBalance, totalRewards]) => {
const totalBalance = utxoBalance.coins + totalRewards;
const percentages = calcPercentages(
delegatedStakes.map(({ stake: value }) => Number(value)),
Number(totalBalance)
);
return delegatedStakes.map((pool, idx) => ({ ...pool, percentage: percentages[idx] }));
}),
distinctUntilChanged((a, b) => sameArrayItems(a, b, delegatedStakeEquals)),
map((delegatedStakes) => new Map(delegatedStakes.map((delegation) => [delegation.pool.id, delegation])))
);
};
|