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 133x 133x 143x 149x 133x 143x 121x 134x 121x 123x 133x 143x 143x 121x 125x 147x 126x 125x 149x 179x 179x 148x 179x 52x 147x | 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])))
);
};
|