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 129x 129x 141x 147x 129x 141x 142x 168x 142x 157x 129x 141x 141x 142x 158x 157x 159x 158x 147x 189x 189x 190x 190x 64x 173x | 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])))
);
};
|