Usage of the walletAPIServer in Ledger Live

The react hook useWalletAPIServer is used within Ledger Live 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 and LLM

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
Ledger
Copyright © Ledger SAS. All rights reserved. Ledger, Ledger Nano S, Ledger Vault, Ledger OS are registered trademarks of Ledger SAS