Documentation
Server
Usage examples
Within Ledger Live

Usage of the walletAPIServer in Ledger Live

The react hook useWalletAPIServer is used within Ledger Live (opens in a new tab) to create a walletAPIServer

It is used in ledger-live-common here ledger-live-common/src/wallet-api/react.ts
In this file, a walletAPIServer is created, and exposed through another hook (also called useWalletAPIServer)

This (LLC hook) is in turn used in both LLD (opens in a new tab) and LLM (opens in a new tab)

useWebview()

useWebView() gets called

Both LLD and LLM, when creating live apps, use the hook useWebView, with the main arguments being:

apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx
const WalletAPIWebview => {
  ({ manifest customHandlers} ) => {
    const { webviewRef } = useWebviewState();
 
    useWebView({ manifest, customHandlers}, webviewRef);
    return <webview />
  }
};

Prepares transport

Will allow communication with the webview.

simplified
const webviewHook =  {
  return {
    postMessage: (message) => {
        webviewRef.current.contentWindow?.postMessage(message);
    },
  };
};

Prepares uiHooks

They will allow walletHandlers to trigger ui actions

more on uiHooks

uiHooks are created in useWebView and sent to LLC useWalletAPIServer uiHook is an object that maps a method like "account.request" to an action in LLD / LLM here's a list of actions it triggers in LLD:

  • opening a drawer to select an account, start an exchange process
  • opening modals to sign transactions, messages, start an exchange process, connect a device
  • store data / update account data
  • display toaster

LLC useWalletAPIServer() gets called

The goal of LLC's useWalletAPIServer is simply to call the walletAPIServer hook (also called useWalletAPIServer)

Before doing so it:

  • Extracts permissions From the manifest

  • Converts accounts sent from useWebView (coming from redux store) to a format readable by walletAPIServer

  • Fetches and filters currencies (coming from libs/ledger-live-common/src/currencies/helpers.ts listCurrencies)

  • Converts filtered currencies to a format readable by wallet-api-server. More on that format here

  • Creates a transport

function useTransport(postMessage: (message: string) => void | undefined): Transport {
  return useMemo(() => {
    return {
      onMessage: undefined,
      send: postMessage, // will allow WALLETAPISERVER -> LIVEAPP communication (via postMessage)
    };
  }, [postMessage]);
}
 
  const transport = useTransport(webviewHook.postMessage);

walletAPIServer gets instantiated

via the react hook useWalletAPIServer

post-instantiation transport setup

walletAPIServer sends back its onMessage callback, the webview will use it to send message to it.

const { onMessage } = useWalletAPIServer({
  manifest,
  accounts,
  config,
  webviewHook,
  uiHook,
  customHandlers,
});
 
const handleMessage = useCallback(
  (event: Electron.IpcMessageEvent) => {
    if (event.channel === "webviewToParent") {
      onMessage(event.args[0]);
    }
  },
  [onMessage]
);
 
useEffect(() => {
  webviewRef.current.addEventListener("ipc-message", handleMessage);
}, [handleMessage, onLoad]);

post-instantiation setup of wallet handlers

server.setHandler is called to setup Ledger Live Wallet/UI/Store callbacks.

Simplified example of setHandler() call
libs/ledger-live-common/src/wallet-api/react.ts
    server.setHandler("account.request", async ({ accounts$, currencies$ }) => {
      const currencies = await firstValueFrom(currencies$);
      return new Promise((resolve, reject) => {
        let currencyList = currencyList = allCurrenciesAndTokens.filter(({ id }) => currencyIds.includes(id));
        uiAccountRequest({
          accounts$,
          currencies: currencyList,
          onSuccess: (account: AccountLike, parentAccount: Account | undefined) => {
            resolve(accountToWalletAPIAccount(account, parentAccount));
          },
          onCancel: () => {
            reject(new Error("Canceled by user"));
          },
        });
      });
    });
  }, [manifest, server, tracking, uiAccountRequest]);

those handlers are saved in the property WalletAPIServer.walletHandlers

To recap:

  • WalletAPIServer.walletHandlers -> callbacks defined in LLC, trigger modals / drawers / update redux store, etc.
  • WalletAPIServer.requestHandlers -> internalHandlers + customHandlers, can call walletHandlers inside of them