glyphdocs
Protocol / Relay

Understand Glyph Connect and Relay v2

See how a released Glyph Connect v2 request moves between a dApp, Relay, and Glyph Wallet.

Understand Glyph Connect and Relay v2

Glyph Connect is the handoff between a dApp and Glyph Wallet. The dApp describes an action, the wallet asks the user to approve or reject it, and the wallet delivers a result back through the route in the request.

These guides describe the released contract in @glyph-oss/connect 4.0.1, Relay v2, and Glyph Wallet 0.16.5.

The three roles

  • The dApp creates a typed request, keeps the original request record, and verifies the returned result.
  • Glyph Wallet validates the request, shows it to the user, and returns either an approved result or an explicit rejection.
  • Relay is an optional delivery bridge. It receives the wallet callback and gives the dApp a read-only SSE or polling path for that result.

Relay does not approve requests and does not replace callback verification. It only separates wallet delivery from dApp result reading.

How a v2 request works

The SDK wraps a typed request in a glyph-connect-request/2 envelope. The envelope includes the request, delivery fields, a network binding, and a request_hash. The dApp then opens a glyph://v2/request?d=... URL for Glyph Wallet.

The hash is calculated over the canonical request, delivery fields, and network. Changing one of those values produces a different request binding. Keep the original request and envelope so the eventual result can be checked against what the dApp actually opened.

Mermaid diagram
sequenceDiagram
  participant D as dApp
  participant W as Glyph Wallet
  D->>D: Create typed request
  D->>D: Create v2 envelope and request_hash
  D->>W: Open glyph://v2/request?d=...
  W->>W: Validate request and ask the user
  alt User approves
      W-->>D: Deliver signed result
  else User rejects
      W-->>D: Deliver signed rejected result
  end

See launch a request for delivery-specific steps and protocol v2 fields and bindings for the envelope details.

What Relay v2 unlocks

Relay is useful when the dApp should not receive a wallet POST directly. The dApp registers a short-lived session, puts the session's callback URL in the envelope, and reads the result from the session's stream or result URL.

The wallet sends its callback to Relay. The dApp reads the accepted result over SSE or by polling. This means the Relay path does not require a callback page or a public callback route in the dApp.

Mermaid diagram
sequenceDiagram
  participant D as dApp
  participant R as Relay v2
  participant W as Glyph Wallet
  D->>R: Register a fresh session
  R-->>D: Return callback and read URLs
  D->>R: Subscribe to the read URL
  D->>W: Open v2 envelope with Relay callback URL
  alt User approves
      W->>R: POST signed approved result
  else User rejects
      W->>R: POST signed rejected result
  end
  R-->>D: Stream or return the accepted result

A direct callback or browser redirect flow is different: it needs the dApp route that receives that delivery. Choose Relay when the dApp wants the official relay route and a read channel instead. See Use Relay v2 and Launch a request.

Short sessions, separate capabilities

Relay v2 sessions are short-lived and single-use for delivery. Prepare and register a fresh session for each request. The relay accepts the first callback result for a session, keeps it briefly for reading, and rejects a later callback for that session.

The session has separate authorities:

  • The callback capability authorizes the wallet's POST delivery. Give it to the wallet through callbackUrl.
  • The read capability authorizes the dApp's GET access. Keep it in the dApp process through streamUrl or resultUrl.

The two capabilities are not interchangeable. Do not put a stream or result URL in callback, and do not send read URLs to the wallet, analytics, or other third parties. The dApp can listen for a result without giving the wallet permission to read it.

Mermaid diagram
flowchart LR
  A[Create fresh session] --> B[Register once]
  B --> C[Give callback URL to wallet]
  B --> D[Keep read URLs in dApp]
  C --> E[First callback accepted]
  E --> F[Result available to dApp]
  E --> G[Later callback rejected]

Approval and rejection use the same delivery

An approval and a user rejection both travel through the selected delivery route. A rejection is a normal result with status: "rejected" and reason: "user_rejected"; it is not the same as a malformed callback, a timeout, or a failed signature check.

Transport completion only means that a result was delivered and accepted by the transport. It does not mean that the user approved the action. After verification, branch on the result status. See handle results and troubleshoot rejections.

Signed bindings connect the result to the request

For a signed v2 callback, the result is not trusted just because it arrived at the expected URL. The signed envelope connects:

  • request_hash to the exact request, delivery fields, and network that the dApp opened.
  • The network, dApp origin, nonce, request type, and expiry to the original request.
  • result_hash to the exact canonical JSON result.
  • signed_payload to the canonical callback binding, including the Relay route when Relay is used.

Verify the complete signed envelope, the expected bindings, the trusted wallet key, and the Qubic SchnorrQ signature before using an identity, transaction hash, message signature, permission list, or verification result. Use k12 and verify from @qubic.org/crypto@1.0.0 for the dApp-side signature check. Glyph Wallet signs the callback after the user action. See verify signed callbacks.

Mermaid diagram
flowchart LR
  A[Typed request] --> B[Canonical v2 envelope]
  B --> C[request_hash]
  C --> D[Wallet callback envelope]
  D --> E[Signed payload and result_hash]
  E --> F[Verify expected bindings and signature]
  F --> G[Use approved or rejected result]

On this page