diff --git a/packages/api-derive/src/accounts/identity.ts b/packages/api-derive/src/accounts/identity.ts index 9ee2ed7d4f..dff561d450 100644 --- a/packages/api-derive/src/accounts/identity.ts +++ b/packages/api-derive/src/accounts/identity.ts @@ -13,7 +13,7 @@ import { combineLatest, map, of, switchMap } from 'rxjs'; import { isHex, u8aToString } from '@polkadot/util'; -import { memo } from '../util'; +import { firstObservable, memo } from '../util'; type IdentityInfoAdditional = PalletIdentityIdentityInfo['additional'][0]; @@ -106,9 +106,7 @@ export function identity (instanceId: string, api: ApiInterfaceRx): (accountId?: export function hasIdentity (instanceId: string, api: ApiInterfaceRx): (accountId: AccountId | Uint8Array | string) => Observable { return memo(instanceId, (accountId: AccountId | Uint8Array | string): Observable => - api.derive.accounts.hasIdentityMulti([accountId]).pipe( - map(([first]) => first) - ) + firstObservable(api.derive.accounts.hasIdentityMulti([accountId])) ); } diff --git a/packages/api-derive/src/collective/getInstance.ts b/packages/api-derive/src/collective/helpers.ts similarity index 56% rename from packages/api-derive/src/collective/getInstance.ts rename to packages/api-derive/src/collective/helpers.ts index 99049b0822..7d56347eae 100644 --- a/packages/api-derive/src/collective/getInstance.ts +++ b/packages/api-derive/src/collective/helpers.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import type { ApiInterfaceRx } from '@polkadot/api/types'; +import type { Collective } from './types'; export function getInstance (api: ApiInterfaceRx, section: string): string { const instances = api.registry.getModuleInstances(api.runtimeVersion.specName.toString(), section); @@ -10,3 +11,8 @@ export function getInstance (api: ApiInterfaceRx, section: string): string { ? instances[0] : section; } + +export function withSection (_section: Collective, fn: (section: string, instanceId: string, api: ApiInterfaceRx) => T): (instanceId: string, api: ApiInterfaceRx) => T { + return (instanceId: string, api: ApiInterfaceRx) => + fn(getInstance(api, _section), instanceId, api); +} diff --git a/packages/api-derive/src/collective/members.ts b/packages/api-derive/src/collective/members.ts index c036f1b526..148442359e 100644 --- a/packages/api-derive/src/collective/members.ts +++ b/packages/api-derive/src/collective/members.ts @@ -11,16 +11,14 @@ import { of } from 'rxjs'; import { isFunction } from '@polkadot/util'; import { memo } from '../util'; -import { getInstance } from './getInstance'; +import { withSection } from './helpers'; export function members (_section: Collective): (instanceId: string, api: ApiInterfaceRx) => () => Observable { - return (instanceId: string, api: ApiInterfaceRx) => { - const section = getInstance(api, _section); - - return memo(instanceId, (): Observable => + return withSection(_section, (section, instanceId, api) => + memo(instanceId, (): Observable => isFunction(api.query[section]?.members) ? api.query[section as 'council'].members() : of([]) - ); - }; + ) + ); } diff --git a/packages/api-derive/src/collective/prime.ts b/packages/api-derive/src/collective/prime.ts index edf83ebc56..7ddec4f01d 100644 --- a/packages/api-derive/src/collective/prime.ts +++ b/packages/api-derive/src/collective/prime.ts @@ -5,19 +5,18 @@ import type { Observable } from 'rxjs'; import type { ApiInterfaceRx } from '@polkadot/api/types'; import type { Option } from '@polkadot/types'; import type { AccountId } from '@polkadot/types/interfaces'; +import type { Collective } from './types'; import { map, of } from 'rxjs'; import { isFunction } from '@polkadot/util'; import { memo } from '../util'; -import { getInstance } from './getInstance'; +import { withSection } from './helpers'; -export function prime (_section: string): (instanceId: string, api: ApiInterfaceRx) => () => Observable { - return (instanceId: string, api: ApiInterfaceRx) => { - const section = getInstance(api, _section); - - return memo(instanceId, (): Observable => +export function prime (_section: Collective): (instanceId: string, api: ApiInterfaceRx) => () => Observable { + return withSection(_section, (section, instanceId, api) => + memo(instanceId, (): Observable => isFunction(api.query[section as 'council']?.prime) ? api.query[section as 'council'].prime>().pipe( map((optPrime): AccountId | null => @@ -25,6 +24,6 @@ export function prime (_section: string): (instanceId: string, api: ApiInterface ) ) : of(null) - ); - }; + ) + ); } diff --git a/packages/api-derive/src/collective/proposals.ts b/packages/api-derive/src/collective/proposals.ts index 69b4e3ff35..a2c6bc8942 100644 --- a/packages/api-derive/src/collective/proposals.ts +++ b/packages/api-derive/src/collective/proposals.ts @@ -13,17 +13,17 @@ import { catchError, combineLatest, map, of, switchMap } from 'rxjs'; import { isFunction } from '@polkadot/util'; import { memo } from '../util'; -import { getInstance } from './getInstance'; +import { withSection } from './helpers'; type Result = [(Hash | Uint8Array | string)[], (Option | null)[], Option[]]; function parse (api: ApiInterfaceRx, [hashes, proposals, votes]: Result): DeriveCollectiveProposal[] { return proposals - .map((proposalOpt, index): DeriveCollectiveProposal | null => - proposalOpt && proposalOpt.isSome + .map((o, index): DeriveCollectiveProposal | null => + o && o.isSome ? { hash: api.registry.createType('Hash', hashes[index]), - proposal: proposalOpt.unwrap(), + proposal: o.unwrap(), votes: votes[index].unwrapOr(null) } : null @@ -31,7 +31,7 @@ function parse (api: ApiInterfaceRx, [hashes, proposals, votes]: Result): Derive .filter((proposal): proposal is DeriveCollectiveProposal => !!proposal); } -function _proposalsFrom (instanceId: string, api: ApiInterfaceRx, section: string): (hashes: (Hash | Uint8Array | string)[]) => Observable { +function _proposalsFrom (section: string, instanceId: string, api: ApiInterfaceRx): (hashes: (Hash | Uint8Array | string)[]) => Observable { return memo(instanceId, (hashes: (Hash | Uint8Array | string)[]): Observable => (isFunction(api.query[section]?.proposals) && hashes.length ? combineLatest([ @@ -39,8 +39,8 @@ function _proposalsFrom (instanceId: string, api: ApiInterfaceRx, section: strin // this should simply be api.query[section].proposalOf.multi>(hashes), // however we have had cases on Edgeware where the indices have moved around after an // upgrade, which results in invalid on-chain data - combineLatest(hashes.map((hash) => - api.query[section].proposalOf>(hash).pipe( + combineLatest(hashes.map((h) => + api.query[section].proposalOf>(h).pipe( catchError(() => of(null)) ) )), @@ -48,69 +48,63 @@ function _proposalsFrom (instanceId: string, api: ApiInterfaceRx, section: strin ]) : of([[], [], []]) ).pipe( - map((result) => parse(api, result)) + map((r) => parse(api, r)) ) ); } -export function hasProposals (_section: Collective): (instanceId: string, api: ApiInterfaceRx) => () => Observable { - return (instanceId: string, api: ApiInterfaceRx) => { - const section = getInstance(api, _section); +function withProposals (_section: Collective, fn: (section: string, instanceId: string, api: ApiInterfaceRx, proposalsFrom: (hashes: (string | Hash | Uint8Array)[]) => Observable) => T): (instanceId: string, api: ApiInterfaceRx) => T { + return withSection(_section, (section, instanceId, api) => + fn(section, instanceId, api, _proposalsFrom(section, instanceId, api)) + ); +} - return memo(instanceId, (): Observable => +export function hasProposals (_section: Collective): (instanceId: string, api: ApiInterfaceRx) => () => Observable { + return withSection(_section, (section, instanceId, api) => + memo(instanceId, (): Observable => of(isFunction(api.query[section]?.proposals)) - ); - }; + ) + ); } export function proposalCount (_section: Collective): (instanceId: string, api: ApiInterfaceRx) => () => Observable { - return (instanceId: string, api: ApiInterfaceRx) => { - const section = getInstance(api, _section); - - return memo(instanceId, (): Observable => + return withSection(_section, (section, instanceId, api) => + memo(instanceId, (): Observable => isFunction(api.query[section].proposalCount) ? api.query[section as 'council'].proposalCount() : of(null) - ); - }; + ) + ); } export function proposalHashes (_section: Collective): (instanceId: string, api: ApiInterfaceRx) => () => Observable { - return (instanceId: string, api: ApiInterfaceRx) => { - const section = getInstance(api, _section); - - return memo(instanceId, (): Observable => + return withSection(_section, (section, instanceId, api) => + memo(instanceId, (): Observable => isFunction(api.query[section]?.proposals) ? api.query[section as 'council'].proposals() : of([]) - ); - }; + ) + ); } export function proposals (_section: Collective): (instanceId: string, api: ApiInterfaceRx) => () => Observable { - return (instanceId: string, api: ApiInterfaceRx) => { - const section = getInstance(api, _section); - const proposalsFrom = _proposalsFrom(instanceId, api, section); - - return memo(instanceId, (): Observable => + return withProposals(_section, (section, instanceId, api, proposalsFrom) => + memo(instanceId, (): Observable => api.derive[section as 'council'].proposalHashes().pipe( switchMap(proposalsFrom) ) - ); - }; + ) + ); } export function proposal (_section: Collective): (instanceId: string, api: ApiInterfaceRx) => (hash: Hash | Uint8Array | string) => Observable { - return (instanceId: string, api: ApiInterfaceRx) => { - const section = getInstance(api, _section); - const proposalsFrom = _proposalsFrom(instanceId, api, section); - - return memo(instanceId, (hash: Hash | Uint8Array | string): Observable => + return withProposals(_section, (section, instanceId, api, proposalsFrom) => + memo(instanceId, (hash: Hash | Uint8Array | string): Observable => isFunction(api.query[section]?.proposals) ? proposalsFrom([hash]).pipe( map(([proposal]) => proposal) ) : of(null) - ); - }; + ) + ); } diff --git a/packages/api-derive/src/staking/account.ts b/packages/api-derive/src/staking/account.ts index 85e7892fd0..c2297b44ef 100644 --- a/packages/api-derive/src/staking/account.ts +++ b/packages/api-derive/src/staking/account.ts @@ -11,7 +11,7 @@ import { combineLatest, map, switchMap } from 'rxjs'; import { BN, BN_ZERO } from '@polkadot/util'; -import { memo } from '../util'; +import { firstObservable, memo } from '../util'; const QUERY_OPTS = { withDestination: true, @@ -85,8 +85,6 @@ export function accounts (instanceId: string, api: ApiInterfaceRx): (accountIds: */ export function account (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string) => Observable { return memo(instanceId, (accountId: Uint8Array | string): Observable => - api.derive.staking.accounts([accountId]).pipe( - map(([first]) => first) - ) + firstObservable(api.derive.staking.accounts([accountId])) ); } diff --git a/packages/api-derive/src/staking/cache.ts b/packages/api-derive/src/staking/cache.ts index fb3afc2045..b4340a3b1d 100644 --- a/packages/api-derive/src/staking/cache.ts +++ b/packages/api-derive/src/staking/cache.ts @@ -25,3 +25,16 @@ export function getEraMultiCache (CACHE_KEY: string, eras: EraIndex[], withA return cached; } + +export function setEraMultiCache (CACHE_KEY: string, withActive: boolean, values: T[]): T[] { + !withActive && values.forEach((v) => deriveCache.set(`${CACHE_KEY}-${v.era.toString()}`, v)); + + return values; +} + +export function filterCachedEras (eras: EraIndex[], cached: T[], query: T[]): T[] { + return eras.map((e) => + cached.find(({ era }) => e.eq(era)) || + query.find(({ era }) => e.eq(era)) as T + ); +} diff --git a/packages/api-derive/src/staking/erasExposure.ts b/packages/api-derive/src/staking/erasExposure.ts index fcd71d2705..62dddcc556 100644 --- a/packages/api-derive/src/staking/erasExposure.ts +++ b/packages/api-derive/src/staking/erasExposure.ts @@ -8,11 +8,11 @@ import type { AccountId, EraIndex } from '@polkadot/types/interfaces'; import type { PalletStakingExposure } from '@polkadot/types/lookup'; import type { DeriveEraExposure, DeriveEraNominatorExposure, DeriveEraValidatorExposure } from '../types'; -import { combineLatest, map, of } from 'rxjs'; +import { map, of } from 'rxjs'; import { deriveCache, memo } from '../util'; import { getEraCache } from './cache'; -import { erasHistoricApply } from './util'; +import { combineEras, erasHistoricApply } from './util'; type KeysAndExposures = [StorageKey<[EraIndex, AccountId]>, PalletStakingExposure][]; @@ -62,12 +62,5 @@ export function eraExposure (instanceId: string, api: ApiInterfaceRx): (era: Era ); } -export function _erasExposure (instanceId: string, api: ApiInterfaceRx): (eras: EraIndex[], withActive: boolean) => Observable { - return memo(instanceId, (eras: EraIndex[], withActive: boolean): Observable => - eras.length - ? combineLatest(eras.map((era) => api.derive.staking._eraExposure(era, withActive))) - : of([]) - ); -} - +export const _erasExposure = combineEras('_eraExposure'); export const erasExposure = erasHistoricApply('_erasExposure'); diff --git a/packages/api-derive/src/staking/erasPoints.ts b/packages/api-derive/src/staking/erasPoints.ts index 5d09c457e3..7e662ea12b 100644 --- a/packages/api-derive/src/staking/erasPoints.ts +++ b/packages/api-derive/src/staking/erasPoints.ts @@ -11,8 +11,8 @@ import { map, of } from 'rxjs'; import { BN_ZERO } from '@polkadot/util'; -import { deriveCache, memo } from '../util'; -import { getEraMultiCache } from './cache'; +import { memo } from '../util'; +import { filterCachedEras, getEraMultiCache, setEraMultiCache } from './cache'; import { erasHistoricApply, filterEras } from './util'; const CACHE_KEY = 'eraPoints'; @@ -47,16 +47,7 @@ export function _erasPoints (instanceId: string, api: ApiInterfaceRx): (eras: Er return !remaining.length ? of(cached) : api.query.staking.erasRewardPoints.multi(remaining).pipe( - map((points): DeriveEraPoints[] => { - const query = mapPoints(remaining, points); - - !withActive && query.forEach((q) => deriveCache.set(`${CACHE_KEY}-${q.era.toString()}`, q)); - - return eras.map((era): DeriveEraPoints => - cached.find((cached) => era.eq(cached.era)) || - query.find((query) => era.eq(query.era)) as DeriveEraPoints - ); - }) + map((p) => filterCachedEras(eras, cached, setEraMultiCache(CACHE_KEY, withActive, mapPoints(remaining, p)))) ); }); } diff --git a/packages/api-derive/src/staking/erasPrefs.ts b/packages/api-derive/src/staking/erasPrefs.ts index a329de47b7..383dc10aa3 100644 --- a/packages/api-derive/src/staking/erasPrefs.ts +++ b/packages/api-derive/src/staking/erasPrefs.ts @@ -8,11 +8,11 @@ import type { EraIndex } from '@polkadot/types/interfaces'; import type { PalletStakingValidatorPrefs } from '@polkadot/types/lookup'; import type { DeriveEraPrefs, DeriveEraValPrefs } from '../types'; -import { combineLatest, map, of } from 'rxjs'; +import { map, of } from 'rxjs'; import { deriveCache, memo } from '../util'; import { getEraCache } from './cache'; -import { erasHistoricApply } from './util'; +import { combineEras, erasHistoricApply } from './util'; const CACHE_KEY = 'eraPrefs'; @@ -50,12 +50,5 @@ export function eraPrefs (instanceId: string, api: ApiInterfaceRx): (era: EraInd ); } -export function _erasPrefs (instanceId: string, api: ApiInterfaceRx): (eras: EraIndex[], withActive: boolean) => Observable { - return memo(instanceId, (eras: EraIndex[], withActive: boolean): Observable => - eras.length - ? combineLatest(eras.map((era) => api.derive.staking._eraPrefs(era, withActive))) - : of([]) - ); -} - +export const _erasPrefs = combineEras('_eraPrefs'); export const erasPrefs = erasHistoricApply('_erasPrefs'); diff --git a/packages/api-derive/src/staking/erasRewards.ts b/packages/api-derive/src/staking/erasRewards.ts index 7eaabf35b1..6daaad4cdf 100644 --- a/packages/api-derive/src/staking/erasRewards.ts +++ b/packages/api-derive/src/staking/erasRewards.ts @@ -9,8 +9,8 @@ import type { DeriveEraRewards } from '../types'; import { map, of } from 'rxjs'; -import { deriveCache, memo } from '../util'; -import { getEraMultiCache } from './cache'; +import { memo } from '../util'; +import { filterCachedEras, getEraMultiCache, setEraMultiCache } from './cache'; import { erasHistoricApply, filterEras } from './util'; const CACHE_KEY = 'eraRewards'; @@ -36,16 +36,7 @@ export function _erasRewards (instanceId: string, api: ApiInterfaceRx): (eras: E } return api.query.staking.erasValidatorReward.multi(remaining).pipe( - map((optRewards) => { - const query = mapRewards(remaining, optRewards); - - !withActive && query.forEach((q) => deriveCache.set(`${CACHE_KEY}-${q.era.toString()}`, q)); - - return eras.map((era): DeriveEraRewards => - cached.find((cached) => era.eq(cached.era)) || - query.find((query) => era.eq(query.era)) as DeriveEraRewards - ); - }) + map((r) => filterCachedEras(eras, cached, setEraMultiCache(CACHE_KEY, withActive, mapRewards(remaining, r)))) ); }); } diff --git a/packages/api-derive/src/staking/erasSlashes.ts b/packages/api-derive/src/staking/erasSlashes.ts index 2de58f9ece..646542fc91 100644 --- a/packages/api-derive/src/staking/erasSlashes.ts +++ b/packages/api-derive/src/staking/erasSlashes.ts @@ -12,7 +12,7 @@ import { combineLatest, map, of } from 'rxjs'; import { deriveCache, memo } from '../util'; import { getEraCache } from './cache'; -import { erasHistoricApply } from './util'; +import { combineEras, erasHistoricApply } from './util'; const CACHE_KEY = 'eraSlashes'; @@ -58,14 +58,5 @@ export function eraSlashes (instanceId: string, api: ApiInterfaceRx): (era: EraI ); } -export function _erasSlashes (instanceId: string, api: ApiInterfaceRx): (eras: EraIndex[], withActive: boolean) => Observable { - return memo(instanceId, (eras: EraIndex[], withActive: boolean): Observable => - eras.length - ? combineLatest( - eras.map((era) => api.derive.staking._eraSlashes(era, withActive)) - ) - : of([]) - ); -} - +export const _erasSlashes = combineEras('_eraSlashes'); export const erasSlashes = erasHistoricApply('_erasSlashes'); diff --git a/packages/api-derive/src/staking/keys.ts b/packages/api-derive/src/staking/keys.ts index a6f2b27cc3..d61ff08d46 100644 --- a/packages/api-derive/src/staking/keys.ts +++ b/packages/api-derive/src/staking/keys.ts @@ -11,7 +11,7 @@ import type { DeriveStakingKeys } from './types'; import { combineLatest, map, of, switchMap } from 'rxjs'; -import { memo } from '../util'; +import { firstObservable, memo } from '../util'; function extractsIds (stashId: Uint8Array | string, queuedKeys: [AccountId, NodeRuntimeSessionKeys | AccountId[]][], nextKeys: Option): DeriveStakingKeys { const sessionIds = (queuedKeys.find(([currentId]) => currentId.eq(stashId)) || [undefined, [] as AccountId[]])[1]; @@ -29,9 +29,7 @@ function extractsIds (stashId: Uint8Array | string, queuedKeys: [AccountId, Node export function keys (instanceId: string, api: ApiInterfaceRx): (stashId: Uint8Array | string) => Observable { return memo(instanceId, (stashId: Uint8Array | string): Observable => - api.derive.staking.keysMulti([stashId]).pipe( - map(([first]) => first) - ) + firstObservable(api.derive.staking.keysMulti([stashId])) ); } diff --git a/packages/api-derive/src/staking/ownExposure.ts b/packages/api-derive/src/staking/ownExposure.ts index 6c54fbd63f..de6382caf1 100644 --- a/packages/api-derive/src/staking/ownExposure.ts +++ b/packages/api-derive/src/staking/ownExposure.ts @@ -9,7 +9,7 @@ import type { DeriveOwnExposure } from '../types'; import { map, of } from 'rxjs'; -import { memo } from '../util'; +import { firstObservable, memo } from '../util'; import { erasHistoricApplyAccount } from './util'; export function _ownExposures (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, eras: EraIndex[], withActive: boolean) => Observable { @@ -17,8 +17,8 @@ export function _ownExposures (instanceId: string, api: ApiInterfaceRx): (accoun return memo(instanceId, (accountId: Uint8Array | string, eras: EraIndex[], _withActive: boolean): Observable => eras.length ? api.queryMulti([ - ...eras.map((era): QueryableStorageMultiArg<'rxjs'> => [api.query.staking.erasStakersClipped, [era, accountId]]), - ...eras.map((era): QueryableStorageMultiArg<'rxjs'> => [api.query.staking.erasStakers, [era, accountId]]) + ...eras.map((e): QueryableStorageMultiArg<'rxjs'> => [api.query.staking.erasStakersClipped, [e, accountId]]), + ...eras.map((e): QueryableStorageMultiArg<'rxjs'> => [api.query.staking.erasStakers, [e, accountId]]) ]).pipe( map((all): DeriveOwnExposure[] => eras.map((era, index) => ({ clipped: all[index], era, exposure: all[eras.length + index] })) @@ -30,9 +30,7 @@ export function _ownExposures (instanceId: string, api: ApiInterfaceRx): (accoun export function ownExposure (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, era: EraIndex) => Observable { return memo(instanceId, (accountId: Uint8Array | string, era: EraIndex): Observable => - api.derive.staking._ownExposures(accountId, [era], true).pipe( - map(([first]) => first) - ) + firstObservable(api.derive.staking._ownExposures(accountId, [era], true)) ); } diff --git a/packages/api-derive/src/staking/ownSlashes.ts b/packages/api-derive/src/staking/ownSlashes.ts index c2b894ae5b..d76c6b1169 100644 --- a/packages/api-derive/src/staking/ownSlashes.ts +++ b/packages/api-derive/src/staking/ownSlashes.ts @@ -10,7 +10,7 @@ import type { DeriveStakerSlashes } from '../types'; import { map, of } from 'rxjs'; -import { memo } from '../util'; +import { firstObservable, memo } from '../util'; import { erasHistoricApplyAccount } from './util'; export function _ownSlashes (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, eras: EraIndex[], withActive: boolean) => Observable { @@ -18,8 +18,8 @@ export function _ownSlashes (instanceId: string, api: ApiInterfaceRx): (accountI return memo(instanceId, (accountId: Uint8Array | string, eras: EraIndex[], _withActive: boolean): Observable => eras.length ? api.queryMulti<(Option> | Option)[]>([ - ...eras.map((era): QueryableStorageMultiArg<'rxjs'> => [api.query.staking.validatorSlashInEra, [era, accountId]]), - ...eras.map((era): QueryableStorageMultiArg<'rxjs'> => [api.query.staking.nominatorSlashInEra, [era, accountId]]) + ...eras.map((e): QueryableStorageMultiArg<'rxjs'> => [api.query.staking.validatorSlashInEra, [e, accountId]]), + ...eras.map((e): QueryableStorageMultiArg<'rxjs'> => [api.query.staking.nominatorSlashInEra, [e, accountId]]) ]).pipe( map((values): DeriveStakerSlashes[] => eras.map((era, index) => ({ @@ -36,9 +36,7 @@ export function _ownSlashes (instanceId: string, api: ApiInterfaceRx): (accountI export function ownSlash (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, era: EraIndex) => Observable { return memo(instanceId, (accountId: Uint8Array | string, era: EraIndex): Observable => - api.derive.staking._ownSlashes(accountId, [era], true).pipe( - map(([first]) => first) - ) + firstObservable(api.derive.staking._ownSlashes(accountId, [era], true)) ); } diff --git a/packages/api-derive/src/staking/query.ts b/packages/api-derive/src/staking/query.ts index 520c491dda..0cda50bda1 100644 --- a/packages/api-derive/src/staking/query.ts +++ b/packages/api-derive/src/staking/query.ts @@ -10,7 +10,7 @@ import type { DeriveStakingQuery, StakingQueryFlags } from '../types'; import { combineLatest, map, of, switchMap } from 'rxjs'; -import { memo } from '../util'; +import { firstObservable, memo } from '../util'; function parseDetails (stashId: AccountId, controllerIdOpt: Option | null, nominatorsOpt: Option, rewardDestination: PalletStakingRewardDestination, validatorPrefs: PalletStakingValidatorPrefs, exposure: PalletStakingExposure, stakingLedgerOpt: Option): DeriveStakingQuery { return { @@ -95,9 +95,7 @@ function getBatch (api: ApiInterfaceRx, activeEra: EraIndex, stashIds: AccountId */ export function query (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, flags: StakingQueryFlags) => Observable { return memo(instanceId, (accountId: Uint8Array | string, flags: StakingQueryFlags): Observable => - api.derive.staking.queryMulti([accountId], flags).pipe( - map(([first]) => first) - ) + firstObservable(api.derive.staking.queryMulti([accountId], flags)) ); } diff --git a/packages/api-derive/src/staking/stakerExposure.ts b/packages/api-derive/src/staking/stakerExposure.ts index 7010991352..8fa09f1fd9 100644 --- a/packages/api-derive/src/staking/stakerExposure.ts +++ b/packages/api-derive/src/staking/stakerExposure.ts @@ -8,7 +8,7 @@ import type { DeriveEraValidatorExposure, DeriveStakerExposure } from '../types' import { map, switchMap } from 'rxjs'; -import { memo } from '../util'; +import { firstObservable, memo } from '../util'; export function _stakerExposures (instanceId: string, api: ApiInterfaceRx): (accountIds: (Uint8Array | string)[], eras: EraIndex[], withActive: boolean) => Observable { return memo(instanceId, (accountIds: (Uint8Array | string)[], eras: EraIndex[], withActive: boolean): Observable => { @@ -48,8 +48,6 @@ export function stakerExposures (instanceId: string, api: ApiInterfaceRx): (acco export function stakerExposure (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, withActive?: boolean) => Observable { return memo(instanceId, (accountId: Uint8Array | string, withActive = false): Observable => - api.derive.staking.stakerExposures([accountId], withActive).pipe( - map(([first]) => first) - ) + firstObservable(api.derive.staking.stakerExposures([accountId], withActive)) ); } diff --git a/packages/api-derive/src/staking/stakerPrefs.ts b/packages/api-derive/src/staking/stakerPrefs.ts index 19e94a7022..778293a1ad 100644 --- a/packages/api-derive/src/staking/stakerPrefs.ts +++ b/packages/api-derive/src/staking/stakerPrefs.ts @@ -14,7 +14,7 @@ import { erasHistoricApplyAccount } from './util'; export function _stakerPrefs (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, eras: EraIndex[], withActive: boolean) => Observable { // eslint-disable-next-line @typescript-eslint/no-unused-vars return memo(instanceId, (accountId: Uint8Array | string, eras: EraIndex[], _withActive: boolean): Observable => - api.query.staking.erasValidatorPrefs.multi(eras.map((era) => [era, accountId])).pipe( + api.query.staking.erasValidatorPrefs.multi(eras.map((e) => [e, accountId])).pipe( map((all): DeriveStakerPrefs[] => all.map((validatorPrefs, index): DeriveStakerPrefs => ({ era: eras[index], diff --git a/packages/api-derive/src/staking/stakerRewards.ts b/packages/api-derive/src/staking/stakerRewards.ts index 0864adc2fe..0f94559020 100644 --- a/packages/api-derive/src/staking/stakerRewards.ts +++ b/packages/api-derive/src/staking/stakerRewards.ts @@ -13,7 +13,7 @@ import { combineLatest, map, of, switchMap } from 'rxjs'; import { BN_BILLION, BN_ZERO } from '@polkadot/util'; -import { memo } from '../util'; +import { firstObservable, memo } from '../util'; type ErasResult = [DeriveEraPoints[], DeriveEraPrefs[], DeriveEraRewards[]]; @@ -98,7 +98,7 @@ function removeClaimed (validators: string[], queryValidators: DeriveStakingQuer if (index !== -1) { const valLedger = queryValidators[index].stakingLedger; - if (valLedger?.claimedRewards.some((era) => reward.era.eq(era))) { + if (valLedger?.claimedRewards.some((e) => reward.era.eq(e))) { rm.push(validatorId); } } @@ -110,14 +110,14 @@ function removeClaimed (validators: string[], queryValidators: DeriveStakingQuer } function filterRewards (eras: EraIndex[], valInfo: [string, DeriveStakingQuery][], { rewards, stakingLedger }: { rewards: DeriveStakerReward[]; stakingLedger: PalletStakingStakingLedger }): DeriveStakerReward[] { - const filter = eras.filter((era) => !stakingLedger.claimedRewards.some((e) => e.eq(era))); + const filter = eras.filter((e) => !stakingLedger.claimedRewards.some((s) => s.eq(e))); const validators = valInfo.map(([v]) => v); const queryValidators = valInfo.map(([, q]) => q); return rewards .filter(({ isEmpty }) => !isEmpty) .filter((reward): boolean => { - if (!filter.some((filter) => reward.era.eq(filter))) { + if (!filter.some((e) => reward.era.eq(e))) { return false; } @@ -186,10 +186,9 @@ export function _stakerRewards (instanceId: string, api: ApiInterfaceRx): (accou export function stakerRewards (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, withActive?: boolean) => Observable { return memo(instanceId, (accountId: Uint8Array | string, withActive = false): Observable => - api.derive.staking.erasHistoric(withActive).pipe( - switchMap((eras) => api.derive.staking._stakerRewards([accountId], eras, withActive)), - map(([first]) => first) - ) + firstObservable(api.derive.staking.erasHistoric(withActive).pipe( + switchMap((eras) => api.derive.staking._stakerRewards([accountId], eras, withActive)) + )) ); } diff --git a/packages/api-derive/src/staking/util.ts b/packages/api-derive/src/staking/util.ts index 9dcd69fccd..1b18119d60 100644 --- a/packages/api-derive/src/staking/util.ts +++ b/packages/api-derive/src/staking/util.ts @@ -1,18 +1,19 @@ // Copyright 2017-2021 @polkadot/api-derive authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { ApiInterfaceRx } from '@polkadot/api/types'; +import type { Observable } from 'rxjs'; +import type { ApiInterfaceRx, ObsInnerType } from '@polkadot/api/types'; import type { EraIndex } from '@polkadot/types/interfaces'; import type { ExactDerive } from '../bundle'; -import { switchMap } from 'rxjs'; +import { combineLatest, of, switchMap } from 'rxjs'; import { memo } from '../util'; type ApplyReturn = ReturnType; export function filterEras (eras: EraIndex[], list: T[]): EraIndex[] { - return eras.filter((era) => !list.some((entry) => era.eq(entry.era))); + return eras.filter((e) => !list.some(({ era }) => e.eq(era))); } export function erasHistoricApply (fn: F): (instanceId: string, api: ApiInterfaceRx) => (withActive?: boolean) => ApplyReturn { @@ -36,3 +37,15 @@ export function erasHistoricApplyAccount (fn: F): (instanceId: string, api: ApiInterfaceRx) => (eras: EraIndex[], withActive: boolean) => Observable>[]> { + return (instanceId: string, api: ApiInterfaceRx) => + // Cannot quite get the typing right, but it is right in the code + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + memo(instanceId, (eras: EraIndex[], withActive: boolean) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + eras.length + ? combineLatest(eras.map((e) => api.derive.staking[fn](e, withActive))) + : of([]) + ) as any; +} diff --git a/packages/api-derive/src/util/index.ts b/packages/api-derive/src/util/index.ts index 21ffe00155..fad368e057 100644 --- a/packages/api-derive/src/util/index.ts +++ b/packages/api-derive/src/util/index.ts @@ -1,8 +1,16 @@ // Copyright 2017-2021 @polkadot/api-derive authors & contributors // SPDX-License-Identifier: Apache-2.0 +import type { Observable } from 'rxjs'; + +import { map } from 'rxjs'; + export { drr, memo } from '@polkadot/rpc-core'; export * from './approvalFlagsToBools'; export * from './cache'; export * from './cacheImpl'; + +export function firstObservable (obs: Observable): Observable { + return obs.pipe(map(([a]) => a)); +}