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 | 42x 42x 42x 42x 244x 244x 124x 124x 124x 122x 122x 120x 2x 122x 122x 5x 8x 5x 5x 124x 5x 5x 13x | import { GroupedAddress } from '@cardano-sdk/key-management';
import { Logger } from 'ts-log';
import {
Observable,
Subject,
defaultIfEmpty,
distinctUntilChanged,
filter,
map,
merge,
mergeMap,
of,
shareReplay,
switchMap,
take,
tap
} from 'rxjs';
import { WalletStores } from '../persistence';
import { groupedAddressesEquals } from './util';
import { sortAddresses } from './util/sortAddresses';
export type AddressTrackerDependencies = {
store: WalletStores['addresses'];
addressDiscovery$: Observable<GroupedAddress[]>;
logger: Logger;
};
export const createAddressTracker = ({ addressDiscovery$, store, logger }: AddressTrackerDependencies) => {
// eslint-disable-next-line unicorn/consistent-function-scoping
const storeAddresses = () => (addresses$: Observable<GroupedAddress[]>) =>
addresses$.pipe(switchMap((addresses) => store.set(addresses).pipe(map(() => addresses))));
const newAddresses$ = new Subject<GroupedAddress[]>();
const addresses$ = store
.get()
.pipe(
defaultIfEmpty([]),
mergeMap(
// derive addresses if none available
(addresses) => {
if (addresses.length === 0) {
logger.debug('No addresses available; initiating address discovery process');
return addressDiscovery$.pipe(
tap((derivedAddresses) => {
Iif (derivedAddresses.length === 0) {
throw new Error('Address discovery derived 0 addresses');
}
}),
storeAddresses()
);
}
return of(addresses);
}
),
switchMap((addresses) => {
const addressCache = [...addresses];
return merge(
of(addresses),
newAddresses$.pipe(
map((newAddresses) => {
for (const newAddress of newAddresses) {
Iif (addressCache.some((addr) => addr.address === newAddress.address)) {
logger.warn('Address already exists', newAddress.address);
continue;
}
addressCache.push(newAddress);
}
return [...addressCache];
}),
storeAddresses()
)
).pipe(distinctUntilChanged(groupedAddressesEquals));
})
)
.pipe(shareReplay(1));
return {
addAddresses: (newAddresses: GroupedAddress[]) => {
newAddresses$.next(newAddresses);
return addresses$.pipe(
filter((addresses) =>
newAddresses.every(({ address: newAddress }) => addresses.some(({ address }) => address === newAddress))
),
take(1)
);
},
addresses$: addresses$.pipe(map(sortAddresses)),
shutdown: newAddresses$.complete.bind(newAddresses$)
};
};
export type AddressTracker = ReturnType<typeof createAddressTracker>;
|