Skip to content

Wallet Gateway

Alex Matson edited this page Aug 6, 2026 · 5 revisions

Wallet Gateway Remote

The remote wallet gateway has a backend (nodejs+express) and a user management frontend (web components). The frontend, aka User UI, is opened as a separate browser popup window when used with a 3rd-party dApp.

Window Communication

The User UI and dApp UI, once connected, send window message events to each other to share session state, provide user interaction updates, and so on.

Origin Handshake

The origin handshake is used for the initial interaction between the dApp UI and the WG UI. This establishes each others' origins to each other and enables more secure .postMessage communication, since events are now explicitly addressed by origin, rather than open to any listening origin (*).

The stateManager referenced in the diagram is a client-side component that wraps around localStorage/sessionStorage utilities for persistence.

sequenceDiagram
    autonumber

    participant D as Dapp UI<br/>(Browser)
    participant WG as WG UI<br/>(Browser)
    participant SM as WG UI<br/>(stateManager)

    Note over D,WG: (note: Dapp UI and WG UI run on separate origins)

    D->>WG: Opens WG UI popup

    par
        loop broadcast dapp origin
            D-->>WG: postMessage sends: `SPLICE_WALLET_BROADCAST_ORIGIN`
        end
        and
            WG->>WG: addEventListener('message')
    end

    WG->>SM: store `event.data.origin` as `currentOrigin` in sessionStorage
    Note over WG: send back an acknowledgement
    WG-->>D: postMessage sends: `SPLICE_WALLET_BROADCAST_ORIGIN_ACK`
    D->>D: clearInterval on broadcast loop
Loading

Login

This diagram demonstrates the login flow through the Wallet Gateway UI. The WG UI is accessed in one of two ways: directly in a browser window, or as a popup triggered by a dApp. In the case of the latter, a successful authentication results in a message emitted to the parent dApp. For illustrative purposes, this diagram only shows the case of a login using an OAuth 2.0 IdP.

sequenceDiagram
    autonumber

    actor U as User
    participant D as Dapp UI<br/>(Browser)
    participant WG as WG UI<br/>(Browser)
    participant SM as WG UI<br/>(stateManager)
    participant WGB as WG Backend
    participant A as OAuth IdP

    Note over D,SM: Establish origin handshake (see above)
    WG->>SM: Check auth status (get accessToken)
    alt new session (accessToken is undefined)
        WG->>SM: persist intended page for post-auth
        WG->>WG: redirect to /login
        WG->>WGB: call listNetworks
        U->>WG: selects a network
        U->>WG: clicks "connect" on login page
        WG->>A: redirect to authorization endpoint
        A->>WG: redirect to /callback
        WG->>A: call token endpoint
        WG->>SM: store token and expiry
        WG->>WGB: call addSession
        WGB-->>D: SSE send: 'statusChanged'
        WGB-->>D: SSE send: 'connected'
        WG->>SM: store sessionId by origin
        WG-->>D: postMessage send: SPLICE_WALLET_IDP_AUTH_SUCCESS
        WG->>SM: get original intended page and redirect to it
    else existing session
        WG->>WGB: call listSessions
        opt no server session
            WG->>SM: call clearAuthState, redirect to /login
        end
        WG->>SM: reset token expiry date
        WG-->>D: postMessage send: SPLICE_WALLET_IDP_AUTH_SUCCESS
    else token expired
        WG->>SM: clearAuthState for origin
        Note over WG: (SPLICE_WALLET_LOGOUT event is _NOT_ emitted here: we should consider doing so)
    end

    WG-->>D: postMessage sends: `SPLICE_WALLET_IDP_AUTH_SUCCESS`
Loading

dApp Connect

From the dApp side, this flow shows what happens when a user clicks "connect" (aka calling .connect() on the dApp SDK)

sequenceDiagram
    autonumber

    actor U as User
    participant D as Dapp UI<br/>(Browser)
    participant P as Wallet Picker
    participant WG as WG UI<br/>(Browser)
    participant WGB as WG Backend

    U->>D: Clicks "connect"
    D->>P: Opens wallet discovery/picker
    U->>P: Select wallet
    P-->>D: postMessage send: SPLICE_WALLET_PICKER_RESULT
    D->>WGB: calls `connect` (dapp API)

    alt unauthenticated
        WGB->>D: sends `/login` userUrl
    else existing session
        WGB-->>D: SSE send: 'statusChanged'
        WGB-->>D: SSE send: 'connected'
    end

    D->>WG: open WG in popup
    Note over D,WG: Executes login flow (see above)
Loading

dApp Disconnect

If a user clicks "disconnect" (aka dapp-sdk .disconnect()), then...

sequenceDiagram
    autonumber

    actor U as User
    participant D as Dapp UI<br/>(Browser)
    participant P as Wallet Picker
    participant WG as WG UI<br/>(Browser)
    participant WGB as WG Backend

    U->>D: Click disconnect
    D->>WGB: dapp API: call 'disconnect'
    WGB->>WGB: remove session
    WGB-->>D: SSE send: 'statusChanged'
Loading

Logout

If a user clicks "Logout" from inside the WG popup, then...

sequenceDiagram
    autonumber

    actor U as User
    participant D as Dapp UI<br/>(Browser)
    participant WG as WG UI<br/>(Browser)
    participant SM as WG UI<br/>(stateManager)
    participant WGB as WG Backend

    U->>WG: Click Logout button in popup
    WG->>WGB: call 'removeSession'

    par
        WGB-->>D: SSE send: 'statusChanged'
        WGB-->>D: SSE send: 'logout'
        WG->>SM: clearAuthState
        WG-->>D: postMessage send: SPLICE_WALLET_LOGOUT
    end
Loading

Clone this wiki locally