Skip to content

Configurable Radix Connect Relay server URL #325

@xstelea

Description

@xstelea

Problem Statement

Developers using the Radix dApp Toolkit cannot configure a custom Radix Connect Relay server URL. The relay base URL (https://radix-connect-relay.radixdlt.com) and wallet deep link URL (radixWallet://connect) are hardcoded. This prevents developers from running self-hosted relay infrastructure or pointing to alternative relay environments during development and testing.

The wallet also has no way to know which relay server the dApp is using, because the relay URL is not included in the request metadata. If a developer were to hack around the hardcoded URL on the dApp side, the wallet would still post responses to the default relay server, breaking the round trip.

Solution

Allow developers to configure the Radix Connect Relay server URL (and wallet deep link URL) via a new optional radixConnectRelay config object on RadixDappToolkitOptions. The configured relay base URL is:

  1. Used by the dApp's relay transport to poll for wallet responses (replacing the hardcoded value)
  2. Included in the wallet request metadata as a relayUrl field, so the wallet knows where to post its encrypted responses

When the config is not provided, the current default URLs are used, making this a fully backward-compatible change.

User Stories

  1. As a dApp developer, I want to configure a custom relay server URL, so that I can use self-hosted relay infrastructure
  2. As a dApp developer, I want the wallet to know which relay server my dApp uses, so that the wallet posts responses to the correct server
  3. As a dApp developer, I want sensible defaults when I don't configure a relay URL, so that existing integrations continue to work without changes
  4. As a dApp developer, I want to configure the wallet deep link URL, so that I can target alternative wallet builds during development
  5. As a dApp developer, I want to provide relay configuration at the top-level toolkit options, so that I don't have to understand the internal module structure
  6. As a dApp developer, I want the relay URL to appear in every wallet interaction's metadata, so that the wallet can always determine the correct relay server regardless of transport
  7. As a wallet implementor, I want to read the relay URL from the request metadata, so that I can post encrypted responses to the correct relay server
  8. As a wallet implementor, I want the metadata version to remain at 2, so that the new field is treated as an additive backward-compatible change and older wallets are not broken

Implementation Decisions

Config API

A new optional field radixConnectRelay is added to OptionalRadixDappToolkitOptions:

radixConnectRelay?: {
  baseUrl: string   // Relay server URL (default: 'https://radix-connect-relay.radixdlt.com')
  walletUrl: string // Wallet deep link URL (default: 'radixWallet://connect')
}

Metadata Schema

A new required field relayUrl: string is added to the Metadata valibot schema. It is always populated — either with the developer-provided value or the default. The metadata version stays at 2 (additive, backward-compatible change).

API Contract: dApp Toolkit ↔ Wallet

The WalletInteraction is the wire format exchanged between the dApp and the wallet. The metadata object within it is changing.

Before:

{
  "interactionId": "abc-123",
  "metadata": {
    "version": 2,
    "networkId": 1,
    "dAppDefinitionAddress": "account_rdx...",
    "origin": "https://my-dapp.com"
  },
  "items": { ... }
}

After:

{
  "interactionId": "abc-123",
  "metadata": {
    "version": 2,
    "networkId": 1,
    "dAppDefinitionAddress": "account_rdx...",
    "origin": "https://my-dapp.com",
    "relayUrl": "https://radix-connect-relay.radixdlt.com"
  },
  "items": { ... }
}

Contract details:

  • relayUrl is always present in the metadata (never omitted)
  • Contains the base URL only (e.g., https://radix-connect-relay.radixdlt.com), not the versioned API path (/api/v1)
  • The wallet should use this URL to determine where to post its encrypted response
  • If the wallet does not recognize the relayUrl field (older wallet versions), it falls back to its own hardcoded default — this is the backward-compatible path
  • The version field remains 2 — this is an additive change, not a breaking one

Plumbing Path

The config flows through existing module boundaries with no new modules:

  1. RadixDappToolkit reads options.radixConnectRelay, resolves defaults
  2. Passes the resolved baseUrl and walletUrl to WalletRequestModule
  3. WalletRequestModule fans out:
    • baseUrl and walletUrl to RadixConnectRelayModule (transport-side, replacing hardcoded values)
    • relayUrl (the baseUrl) to WalletRequestSdk (metadata-side)
  4. WalletRequestSdk bakes relayUrl into the Metadata object attached to every WalletInteraction

No New Modules

RadixConnectRelayModule already accepts baseUrl and walletUrl as constructor params. The change is purely about threading configurable values instead of hardcoded ones.

Testing Decisions

Tests should focus on config plumbing — verifying that a relay URL configured at the top flows correctly to both the metadata and the transport layer. Tests should verify external behavior (the metadata object contents, the URLs reaching the relay module) rather than internal wiring details.

Modules to test

  • Metadata schema: Validate that the Metadata schema accepts and requires relayUrl
  • Config-to-metadata plumbing: Given radixConnectRelay.baseUrl at the toolkit level, verify the correct relayUrl appears in the WalletInteraction metadata
  • Default behavior: When no radixConnectRelay config is provided, verify the default relay URL appears in metadata
  • Transport plumbing: Verify the configured URLs reach the RadixConnectRelayModule

Prior art

  • schemas.spec.ts — valibot schema validation tests using parse()
  • wallet-request.spec.ts — integration tests using WalletRequestModule with TestingTransportModule and mock WalletRequestSdk
  • radix-dapp-toolkit.spec.ts — top-level bootstrap test

A new dedicated test file should be added for relay URL configuration tests, following the patterns in wallet-request.spec.ts.

Out of Scope

  • Wallet-side implementation of reading and using the relayUrl from metadata
  • Configurability of other transport parameters (polling interval, encryption settings)
  • Making the connector extension transport configurable
  • Migration tooling or version negotiation for the metadata change

Further Notes

  • The requestInterceptor hook already allows developers to modify the entire WalletInteraction before sending, which could theoretically be used to inject a relayUrl. However, this is fragile (bypasses schema validation, requires knowledge of internals) and doesn't affect the relay transport's polling URL. A first-class config option is the correct approach.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions