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 134x 134x 146x 152x 134x 146x 147x 178x 147x 167x 134x 146x 146x 147x 163x 162x 164x 163x 152x 194x 194x 195x 195x 64x 178x | 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])))
);
};
|