// Copyright 2017-2021 @polkadot/api-derive authors & contributors // SPDX-License-Identifier: Apache-2.0 import type { ApiInterfaceRx } from '@polkadot/api/types'; import type { Data, Option } from '@polkadot/types'; import type { AccountId, IdentityInfoAdditional, Registration } from '@polkadot/types/interfaces'; import type { ITuple } from '@polkadot/types/types'; import type { Observable } from '@polkadot/x-rxjs'; import type { DeriveAccountRegistration, DeriveHasIdentity } from '../types'; import { isHex, u8aToString } from '@polkadot/util'; import { combineLatest, of } from '@polkadot/x-rxjs'; import { map, switchMap } from '@polkadot/x-rxjs/operators'; import { memo } from '../util'; const UNDEF_HEX = { toHex: () => undefined }; function dataAsString (data: Data): string | undefined { return data.isRaw ? u8aToString(data.asRaw.toU8a(true)) : data.isNone ? undefined : data.toHex(); } function extractOther (additional: IdentityInfoAdditional[]): Record { return additional.reduce((other: Record, [_key, _value]): Record => { const key = dataAsString(_key); const value = dataAsString(_value); if (key && value) { other[key] = value; } return other; }, {}); } function extractIdentity (identityOfOpt?: Option, superOf?: [AccountId, Data]): DeriveAccountRegistration { if (!identityOfOpt?.isSome) { return { judgements: [] }; } const { info, judgements } = identityOfOpt.unwrap(); const topDisplay = dataAsString(info.display); return { display: (superOf && dataAsString(superOf[1])) || topDisplay, displayParent: superOf && topDisplay, email: dataAsString(info.email), image: dataAsString(info.image), judgements, legal: dataAsString(info.legal), other: extractOther(info.additional), parent: superOf && superOf[0], pgp: info.pgpFingerprint.unwrapOr(UNDEF_HEX).toHex(), riot: dataAsString(info.riot), twitter: dataAsString(info.twitter), web: dataAsString(info.web) }; } function getParent (api: ApiInterfaceRx, identityOfOpt: Option | undefined, superOfOpt: Option> | undefined): Observable<[Option | undefined, [AccountId, Data] | undefined]> { if (identityOfOpt?.isSome) { // this identity has something set return of([identityOfOpt, undefined]); } else if (superOfOpt?.isSome) { const superOf = superOfOpt.unwrap(); // we have a super return combineLatest([ api.query.identity.identityOf>(superOf[0]), of(superOf) ]); } // nothing of value returned return of([undefined, undefined]); } function getBase (api: ApiInterfaceRx, accountId?: AccountId | Uint8Array | string): Observable<[Option | undefined, Option> | undefined]> { return accountId && api.query.identity?.identityOf ? api.queryMulti<[Option, Option>]>([ [api.query.identity.identityOf, accountId], [api.query.identity.superOf, accountId] ]) : of([undefined, undefined]); } /** * @name identity * @description Returns identity info for an account */ export function identity (instanceId: string, api: ApiInterfaceRx): (accountId?: AccountId | Uint8Array | string) => Observable { return memo(instanceId, (accountId?: AccountId | Uint8Array | string): Observable => getBase(api, accountId).pipe( switchMap(([identityOfOpt, superOfOpt]) => getParent(api, identityOfOpt, superOfOpt)), map(([identityOfOpt, superOf]) => extractIdentity(identityOfOpt, superOf)) ) ); } 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) ) ); } export function hasIdentityMulti (instanceId: string, api: ApiInterfaceRx): (accountIds: (AccountId | Uint8Array | string)[]) => Observable { return memo(instanceId, (accountIds: (AccountId | Uint8Array | string)[]): Observable => api.query.identity?.identityOf ? combineLatest([ api.query.identity.identityOf.multi>(accountIds), api.query.identity.superOf.multi>>(accountIds) ]).pipe( map(([identities, supers]) => identities.map((identityOfOpt, index): DeriveHasIdentity => { const superOfOpt = supers[index]; const parentId = superOfOpt && superOfOpt.isSome ? superOfOpt.unwrap()[0].toString() : undefined; let display: string | undefined; if (identityOfOpt && identityOfOpt.isSome) { const value = dataAsString(identityOfOpt.unwrap().info.display); if (value && !isHex(value)) { display = value; } } return { display, hasIdentity: !!(display || parentId), parentId }; }) ) ) : of(accountIds.map(() => ({ hasIdentity: false }))) ); }