From 9657995f89c6ba00b2928a322c613f93d472e0be Mon Sep 17 00:00:00 2001 From: okjodom Date: Wed, 12 Jul 2023 12:30:04 -0700 Subject: [PATCH 1/3] feat: type modules and client configs --- .../src/components/ConnectGuardians.tsx | 10 +++--- .../src/components/SetConfiguration.tsx | 7 ++-- apps/guardian-ui/src/setup/types.tsx | 34 ++++++++----------- apps/guardian-ui/src/types.tsx | 31 +++++++++++++++++ apps/guardian-ui/src/utils/api.ts | 6 ++-- 5 files changed, 58 insertions(+), 30 deletions(-) diff --git a/apps/guardian-ui/src/components/ConnectGuardians.tsx b/apps/guardian-ui/src/components/ConnectGuardians.tsx index 9be7427cf..81a09f5ba 100644 --- a/apps/guardian-ui/src/components/ConnectGuardians.tsx +++ b/apps/guardian-ui/src/components/ConnectGuardians.tsx @@ -16,7 +16,7 @@ import { } from '@chakra-ui/react'; import { CopyInput, Table, TableRow } from '@fedimint/ui'; import { useConsensusPolling, useSetupContext } from '../hooks'; -import { ServerStatus } from '../types'; +import { ModuleKind, ServerStatus } from '../types'; import { GuardianRole } from '../setup/types'; import { getModuleParamsFromConfig } from '../utils/api'; import { ReactComponent as CopyIcon } from '../assets/svgs/copy.svg'; @@ -79,13 +79,13 @@ export const ConnectGuardians: React.FC = ({ next }) => { }, { label: 'Network', - value: getModuleParamsFromConfig(configGenParams, 'wallet')?.consensus - ?.network, + value: getModuleParamsFromConfig(configGenParams, ModuleKind.Wallet) + ?.consensus?.network, }, { label: 'Block confirmations', - value: getModuleParamsFromConfig(configGenParams, 'wallet')?.consensus - ?.finality_delay, + value: getModuleParamsFromConfig(configGenParams, ModuleKind.Wallet) + ?.consensus?.finality_delay, }, ]; diff --git a/apps/guardian-ui/src/components/SetConfiguration.tsx b/apps/guardian-ui/src/components/SetConfiguration.tsx index db8f84e0b..a42918173 100644 --- a/apps/guardian-ui/src/components/SetConfiguration.tsx +++ b/apps/guardian-ui/src/components/SetConfiguration.tsx @@ -29,6 +29,7 @@ import { ReactComponent as FedimintLogo } from '../assets/svgs/fedimint.svg'; import { ReactComponent as BitcoinLogo } from '../assets/svgs/bitcoin.svg'; import { ReactComponent as ArrowRightIcon } from '../assets/svgs/arrow-right.svg'; import { formatApiErrorMessage, getModuleParamsFromConfig } from '../utils/api'; +import { ModuleKind } from '../types'; interface Props { next: () => void; @@ -69,11 +70,11 @@ export const SetConfiguration: React.FC = ({ next }: Props) => { setFederationName(params.meta?.federation_name || ''); setMintAmounts( - getModuleParamsFromConfig(params, 'mint')?.consensus?.mint_amounts || - mintAmounts + getModuleParamsFromConfig(params, ModuleKind.Mint)?.consensus + ?.mint_amounts || mintAmounts ); - const walletModule = getModuleParamsFromConfig(params, 'wallet'); + const walletModule = getModuleParamsFromConfig(params, ModuleKind.Wallet); if (walletModule) { setBlockConfirmations( diff --git a/apps/guardian-ui/src/setup/types.tsx b/apps/guardian-ui/src/setup/types.tsx index 50717c43f..f6a70c362 100644 --- a/apps/guardian-ui/src/setup/types.tsx +++ b/apps/guardian-ui/src/setup/types.tsx @@ -1,4 +1,4 @@ -import { ServerStatus } from '../types'; +import { MetaConfig, ModuleKind, ServerStatus } from '../types'; export enum GuardianRole { Host = 'Host', @@ -42,22 +42,22 @@ export interface BitcoinRpc { export type PeerHashMap = Record; -export type LnFedimintModule = [ - 'ln', +export type LnModuleParams = [ + ModuleKind.Ln, { consensus?: object; local?: object; } ]; -export type MintFedimintModule = [ - 'mint', +export type MintModuleParams = [ + ModuleKind.Mint, { consensus?: { mint_amounts: number[] }; local?: object; } ]; -export type WalletFedimintModule = [ - 'wallet', +export type WalletModuleParams = [ + ModuleKind.Wallet, { consensus?: { finality_delay: number; network: Network }; local?: { @@ -65,20 +65,16 @@ export type WalletFedimintModule = [ }; } ]; -export type OtherFedimintModule = [string, object]; -export type AnyFedimintModule = - | LnFedimintModule - | MintFedimintModule - | WalletFedimintModule - | OtherFedimintModule; - -type Meta = { federation_name?: string }; - -type Modules = Record; +export type OtherModuleParams = [string, object]; +export type AnyModuleParams = + | LnModuleParams + | MintModuleParams + | WalletModuleParams + | OtherModuleParams; export type ConfigGenParams = { - meta: Meta; - modules: Modules; + meta: MetaConfig; + modules: Record; }; type ConsensusParams = ConfigGenParams & { diff --git a/apps/guardian-ui/src/types.tsx b/apps/guardian-ui/src/types.tsx index 8bf54f515..075719fae 100644 --- a/apps/guardian-ui/src/types.tsx +++ b/apps/guardian-ui/src/types.tsx @@ -47,3 +47,34 @@ export interface Versions { } >; } + +export enum ModuleKind { + Ln = 'ln', + Mint = 'mint', + Wallet = 'wallet', +} + +interface FedimintModule { + config: string; + kind: ModuleKind; + version: number; +} + +interface ApiEndpoint { + name: string; + url: string; +} + +export type MetaConfig = { federation_name?: string }; + +export interface ClientConfig { + consenus_version: number; + epoch_pk: string; + federation_id: string; + api_endpoint: Record; + modules: Record; + meta: MetaConfig; +} +export interface ConfigResponse { + client_config: ClientConfig; +} diff --git a/apps/guardian-ui/src/utils/api.ts b/apps/guardian-ui/src/utils/api.ts index 2af283f3c..a50c21bf1 100644 --- a/apps/guardian-ui/src/utils/api.ts +++ b/apps/guardian-ui/src/utils/api.ts @@ -1,15 +1,15 @@ import { JsonRpcError } from 'jsonrpc-client-websocket'; -import { AnyFedimintModule, ConfigGenParams } from '../setup/types'; +import { AnyModuleParams, ConfigGenParams } from '../setup/types'; /** * Given a config and the name of the module, return the module */ -export function getModuleParamsFromConfig( +export function getModuleParamsFromConfig( config: ConfigGenParams | null, moduleName: T // Ignore any type below, it will be properly typed at call time via moduleName. // eslint-disable-next-line @typescript-eslint/no-explicit-any -): Extract[1] | null { +): Extract[1] | null { if (!config) return null; const module = Object.values(config.modules).find((m) => m[0] === moduleName); return module ? module[1] : null; From 20bf3cfdbbef354f11fffba6ffb083329c9fb203 Mon Sep 17 00:00:00 2001 From: okjodom Date: Wed, 12 Jul 2023 12:34:21 -0700 Subject: [PATCH 2/3] feat: add admin api for fetching client config --- apps/guardian-ui/src/GuardianApi.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/guardian-ui/src/GuardianApi.ts b/apps/guardian-ui/src/GuardianApi.ts index 690e91505..f13e8afbc 100644 --- a/apps/guardian-ui/src/GuardianApi.ts +++ b/apps/guardian-ui/src/GuardianApi.ts @@ -1,6 +1,7 @@ import { JsonRpcError, JsonRpcWebsocket } from 'jsonrpc-client-websocket'; import { ConfigGenParams, ConsensusState, PeerHashMap } from './setup/types'; import { + ConfigResponse, ConsensusStatus, ServerStatus, StatusResponse, @@ -20,7 +21,7 @@ export interface SocketAndAuthInterface { interface RpcInterface { call: ( method: SetupRpc | AdminRpc | SharedRpc, - params?: object | null + params?: unknown ) => Promise; // TODO: Consider moving this to `SocketAndAuthInterface` as part of the authentication methods. clearPassword: () => void; @@ -130,7 +131,7 @@ class BaseGuardianApi call = async ( method: SetupRpc | AdminRpc | SharedRpc, - params: object | null = null + params: unknown = null ): Promise => { try { const websocket = await this.connect(); @@ -191,12 +192,14 @@ enum AdminRpc { fetchEpochCount = 'fetch_epoch_count', consensusStatus = 'consensus_status', connectionCode = 'connection_code', + config = 'config', } export interface AdminApiInterface extends SharedApiInterface { version: () => Promise; fetchEpochCount: () => Promise; connectionCode: () => Promise; + config: (connection: string) => Promise; } export class GuardianApi @@ -332,4 +335,8 @@ export class GuardianApi connectionCode = (): Promise => { return this.base.call(AdminRpc.connectionCode); }; + + config = (connection: string): Promise => { + return this.base.call(AdminRpc.config, connection); + }; } From ec505fe0dcba90b40d755d2fb97982d73f85c7ce Mon Sep 17 00:00:00 2001 From: okjodom Date: Wed, 12 Jul 2023 13:45:59 -0700 Subject: [PATCH 3/3] feat: module api rpc to list gateways --- apps/gateway-ui/src/types.tsx | 7 +++++-- apps/guardian-ui/src/GuardianApi.ts | 21 +++++++++++++++++++++ apps/guardian-ui/src/types.tsx | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/apps/gateway-ui/src/types.tsx b/apps/gateway-ui/src/types.tsx index 51f56b410..dddc764a9 100644 --- a/apps/gateway-ui/src/types.tsx +++ b/apps/gateway-ui/src/types.tsx @@ -8,8 +8,11 @@ export interface Registration { fees: Fees; mint_channel_id: number; node_pub_key: string; - route_hints: object[]; // FIXME - valid_until: object; // FIXME + route_hints: object[]; // FIXME : https://github.com/fedimint/ui/issues/80 + valid_until: { + nanos_since_epoch: number; + secs_since_epoch: number; + }; } export interface Federation { diff --git a/apps/guardian-ui/src/GuardianApi.ts b/apps/guardian-ui/src/GuardianApi.ts index f13e8afbc..8ac65238b 100644 --- a/apps/guardian-ui/src/GuardianApi.ts +++ b/apps/guardian-ui/src/GuardianApi.ts @@ -3,6 +3,7 @@ import { ConfigGenParams, ConsensusState, PeerHashMap } from './setup/types'; import { ConfigResponse, ConsensusStatus, + Gateway, ServerStatus, StatusResponse, Versions, @@ -132,6 +133,13 @@ class BaseGuardianApi call = async ( method: SetupRpc | AdminRpc | SharedRpc, params: unknown = null + ): Promise => { + return this.call_any_method(method, params); + }; + + call_any_method = async ( + method: string, + params: unknown = null ): Promise => { try { const websocket = await this.connect(); @@ -193,13 +201,21 @@ enum AdminRpc { consensusStatus = 'consensus_status', connectionCode = 'connection_code', config = 'config', + module = 'module', } +export enum LightningModuleRpc { + listGateways = 'list_gateways', +} + +type ModuleRpc = LightningModuleRpc; + export interface AdminApiInterface extends SharedApiInterface { version: () => Promise; fetchEpochCount: () => Promise; connectionCode: () => Promise; config: (connection: string) => Promise; + moduleApiCall: (moduleId: number, rpc: ModuleRpc) => Promise; } export class GuardianApi @@ -339,4 +355,9 @@ export class GuardianApi config = (connection: string): Promise => { return this.base.call(AdminRpc.config, connection); }; + + moduleApiCall = (moduleId: number, rpc: ModuleRpc): Promise => { + const method = `${AdminRpc.module}_${moduleId}_${rpc}`; + return this.base.call_any_method(method); + }; } diff --git a/apps/guardian-ui/src/types.tsx b/apps/guardian-ui/src/types.tsx index 075719fae..a3653aaf1 100644 --- a/apps/guardian-ui/src/types.tsx +++ b/apps/guardian-ui/src/types.tsx @@ -78,3 +78,22 @@ export interface ClientConfig { export interface ConfigResponse { client_config: ClientConfig; } + +// These types are shared with the gateway-ui +export interface Fees { + base_msat: number; + proportional_millionths: number; +} + +export interface Gateway { + gateway_pub_key: string; + api: string; + fees: Fees; + mint_channel_id: number; + node_pub_key: string; + route_hints: object[]; // FIXME: https://github.com/fedimint/ui/issues/80 + valid_until: { + nanos_since_epoch: number; + secs_since_epoch: number; + }; +}