OZRelayerClient

public class OZRelayerClient : @unchecked Sendable

Client for submitting transactions to an OpenZeppelin Smart Account relayer.

The relayer wraps user transactions with fee bumps and submits them to Stellar, supplying the transaction fee on behalf of the user. Two submission modes are supported:

  1. Host function + auth entries via send(hostFunction:authEntries:): the relayer assembles the full transaction from the supplied components.
  2. Signed transaction envelope via sendXdr(transactionEnvelope:): the relayer fee-bumps the supplied envelope, preserving the inner signatures (required for source-account auth such as contract deployments).

Example:

let relayer = try OZRelayerClient(relayerUrl: "https://relayer.example.com")
let response = await relayer.send(hostFunction: hf, authEntries: entries)
if response.success {
    print("Transaction hash: \(response.hash ?? "unknown")")
} else {
    print("Error: \(response.error ?? "unknown") (\(response.errorCode ?? ""))")
}
relayer.close()

The client validates its relayerUrl argument at construction. HTTPS is required, with http://localhost allowed for development. Both submission methods capture all failure modes in the returned OZRelayerResponse; they do not throw network or HTTP errors directly. Only XDR encoding failures surface in the response via the error field — exceptions are not propagated.

Subclassing contract: OZRelayerClient is open-able for test doubles. Any subclass that overrides close() MUST either call super.close() or invoke the internal teardown helper, otherwise the owned URLSession will leak. The SDK recording mocks (MockOZRelayerClient) follow this pattern; consumer code is generally expected to inject a custom urlSession rather than subclass.

  • Creates a new OZRelayerClient.

    Throws

    SmartAccountConfigurationException.InvalidConfig when the URL is blank or does not satisfy the HTTPS / localhost constraint.

    Declaration

    Swift

    public init(
        relayerUrl: String,
        timeoutMs: Int64 = OZConstants.defaultRelayerTimeoutMs,
        urlSession: URLSession? = nil
    ) throws

    Parameters

    relayerUrl

    The relayer endpoint URL. Must start with https:// or http://localhost (with optional port and path).

    timeoutMs

    Default request timeout in milliseconds. Defaults to OZConstants.defaultRelayerTimeoutMs (6 minutes) to accommodate testnet submission retries.

    urlSession

    Optional pre-configured URLSession. Use this to inject a test mock OR to apply production transport configuration such as certificate pinning, proxy settings, or request inspection. When nil, the client builds an ephemeral session whose redirect handler denies all 3xx redirects to protect signed SorobanAuthorizationEntryXDR / TransactionEnvelopeXDR payloads and pinned identification headers; the owned session is invalidated on close(). When an injected session is supplied, the redirect-handling policy of that session is the caller’s responsibility.

  • Submits a transaction using a host function and authorization entries.

    The relayer constructs the full transaction from the supplied components, wraps it with a fee bump, and submits it to the Stellar network. As with all submission methods on this client, every failure mode (including pre-request XDR encoding errors) surfaces in the returned OZRelayerResponse rather than being thrown — see the class documentation.

    Declaration

    Swift

    public func send(
        hostFunction: HostFunctionXDR,
        authEntries: [SorobanAuthorizationEntryXDR],
        perRequestTimeoutMs: Int64? = nil
    ) async -> OZRelayerResponse

    Parameters

    hostFunction

    The host function to execute.

    authEntries

    Authorization entries for the transaction.

    perRequestTimeoutMs

    Optional per-request timeout override in milliseconds. When supplied, overrides the timeout supplied to the constructor for this single request.

    Return Value

    The relayer response with transaction hash or error details.

  • Submits a signed transaction envelope.

    Use this when the transaction requires source-account authentication (for example, smart account contract deployments). The relayer fee-bumps the signed envelope, preserving the inner signatures. Every failure mode surfaces in the returned OZRelayerResponse rather than being thrown — see the class documentation.

    Declaration

    Swift

    public func sendXdr(
        transactionEnvelope: TransactionEnvelopeXDR,
        perRequestTimeoutMs: Int64? = nil
    ) async -> OZRelayerResponse

    Parameters

    transactionEnvelope

    The signed TransactionEnvelopeXDR to submit.

    perRequestTimeoutMs

    Optional per-request timeout override in milliseconds.

    Return Value

    The relayer response with transaction hash or error details.

  • Releases the owned URLSession and marks the client as closed.

    When the client was constructed with a caller-supplied urlSession, the caller retains ownership and the session is NOT invalidated. After close() completes the client must not be used again; subsequent calls to close() are safe no-ops.

    Subclasses overriding this method MUST call super.close() (or performCloseInternal() directly) to invalidate the owned URLSession; otherwise the underlying transport leaks.

    Declaration

    Swift

    public func close()
  • Performs the canonical close sequence: idempotent state flip plus URLSession invalidation when the session is owned.

    Subclasses that override close() should call this helper from their override so the resource teardown remains correct even if the override is reordered or augmented with additional bookkeeping.

    Declaration

    Swift

    public final func performCloseInternal()