diff --git a/src/renderer/services/cosmos/common.ts b/src/renderer/services/cosmos/common.ts new file mode 100644 index 000000000..291aed132 --- /dev/null +++ b/src/renderer/services/cosmos/common.ts @@ -0,0 +1,67 @@ +import * as RD from '@devexperts/remote-data-ts' +import { Client } from '@xchainjs/xchain-cosmos' +import { CosmosChain } from '@xchainjs/xchain-util' +import * as FP from 'fp-ts/lib/function' +import * as O from 'fp-ts/lib/Option' +import * as Rx from 'rxjs' +import * as RxOp from 'rxjs/operators' + +import { isError } from '../../../shared/utils/guard' +import { clientNetwork$ } from '../app/service' +import * as C from '../clients' +import { keystoreService } from '../wallet/keystore' +import { getPhrase } from '../wallet/util' +import type { Client$, ClientState, ClientState$ } from './types' + +/** + * Stream to create an observable `CosmosClient` depending on existing phrase in keystore + * + * Whenever a phrase has been added to keystore, a new `CosmosClient` will be created. + * By the other hand: Whenever a phrase has been removed, `ClientState` is set to `initial` + * A `CosmosClient` will never be created as long as no phrase is available + */ +const clientState$: ClientState$ = FP.pipe( + Rx.combineLatest([keystoreService.keystore$, clientNetwork$]), + RxOp.switchMap( + ([keystore, network]): ClientState$ => + Rx.of( + FP.pipe( + getPhrase(keystore), + O.map((phrase) => { + try { + const client = new Client({ + network, + phrase + }) + return RD.success(client) + } catch (error) { + return RD.failure(isError(error) ? error : new Error('Failed to create Cosmos client')) + } + }), + // Set back to `initial` if no phrase is available (locked wallet) + O.getOrElse(() => RD.initial) + ) + ) + ), + RxOp.startWith(RD.initial), + RxOp.shareReplay(1) +) + +const client$: Client$ = clientState$.pipe(RxOp.map(RD.toOption), RxOp.shareReplay(1)) + +/** + * `Address` + */ +const address$: C.WalletAddress$ = C.address$(client$, CosmosChain) + +/** + * `Address` + */ +const addressUI$: C.WalletAddress$ = C.addressUI$(client$, CosmosChain) + +/** + * Explorer url depending on selected network + */ +const explorerUrl$: C.ExplorerUrl$ = C.explorerUrl$(client$) + +export { client$, clientState$, address$, addressUI$, explorerUrl$ } diff --git a/src/renderer/services/cosmos/index.ts b/src/renderer/services/cosmos/index.ts new file mode 100644 index 000000000..c6419cb35 --- /dev/null +++ b/src/renderer/services/cosmos/index.ts @@ -0,0 +1,3 @@ +import { client$, clientState$, address$, addressUI$, explorerUrl$ } from './common' + +export { client$, clientState$, address$, addressUI$, explorerUrl$ } diff --git a/src/renderer/services/cosmos/types.ts b/src/renderer/services/cosmos/types.ts new file mode 100644 index 000000000..659c73d21 --- /dev/null +++ b/src/renderer/services/cosmos/types.ts @@ -0,0 +1,8 @@ +import { Client } from '@xchainjs/xchain-cosmos' + +import * as C from '../clients' + +export type Client$ = C.Client$ + +export type ClientState = C.ClientState +export type ClientState$ = C.ClientState$