SDK Interface Guide

The SDK provides a TypeScript interface for Storail mutations. It is not intended to hide the protocol model. It constructs AEH calls, signs ERC-2771 requests, submits them to the relay, tracks receipts, and waits for subgraph visibility when requested.

Client Setup

import { createStorailMutationClient } from "@storail/sdk";

const client = createStorailMutationClient({
  chainId,
  aehAddress,
  forwarderAddress,
  relayUrl,
  subgraphUrl,
  wallet,
  publicClient,
});

Required fields:

Optional fields:

Wallet Adapter

The wallet adapter must provide:

Optional wallet methods:

Relay mode does not require sendTransaction. Direct mode does not use signTypedData.

Public-Domain Methods

await client.publish({
  path,
  providerId,
  pointer,
  contentHash,
  metadata,
});

await client.update({
  path,
  providerId,
  pointer,
  contentHash,
  metadata,
});

await client.remove({ path });

await client.grantWriter({ domain, writer });

await client.revokeWriter({ domain, writer });

The SDK validates paths, addresses, and bytes32 content hashes before signing.

Application Methods

Generic application action:

await client.submitToApp({
  appId,
  actionType,
  payload,
});

Payment demo helpers:

await client.paymentDemoTransfer({
  to,
  amount,
});

await client.paymentDemoInitializeSupply({
  amount,
});

These helpers only encode the demo instructions. The payment balances are still derived by the payment subgraph.

Operation States

SDK calls return a StorailOperation.

Important successful states:

Other states include:

The SDK type also reserves mined and expired, but the current implementation does not emit them.

Use onStatus to update UI state:

const operation = await client.publish(record, {
  onStatus(next) {
    setOperation(next);
  },
});

Relay Mode

Relay mode is the default.

The internal flow is:

1. Build AEH calldata. 2. Read the user's forwarder nonce. 3. Ask the wallet to sign the EIP-712 ForwardRequest. 4. Call forwarder.verify(request). 5. Simulate forwarder.execute(request). 6. Submit the signed request to POST /v1/relay. 7. Wait for the transaction receipt. 8. If subgraphUrl is configured, wait until _meta.block.number >= receipt.blockNumber. 9. Query the expected derived state.

By default, public-domain methods wait for indexing. If the application only needs the chain confirmation boundary, pass:

await client.publish(record, { waitForIndex: false });

This flow is why applications should not manually sign and submit relay requests unless they need lower-level control.

Direct Mode

Use direct mode when the user should pay gas or when the relay is unavailable:

await client.update(record, { mode: "direct" });

Direct mode sends a transaction directly to AuthorizedEventHub. It can still wait for receipt confirmation and subgraph indexing.

Direct mode does not emit signing or signed. Its normal successful state sequence is:

draft -> submitting -> submitted -> confirmed -> indexed

If publicClient.call is available and preflight is not disabled, the SDK performs an eth_call against AuthorizedEventHub before asking the wallet to send the transaction. If publicClient.call is not available, direct mode skips that preflight step.

Indexed Verification

The SDK does not treat any query result as sufficient by itself. It first checks subgraph progress:

{
  _meta {
    block {
      number
    }
  }
}

Only after the subgraph has reached the receipt block does the SDK check the expected derived state.

Built-in verifiers cover:

For application-specific calls, pass indexedVerifier.

Operation Persistence

Provide operationStore when the frontend needs retry or recovery across reloads.

The SDK stores:

If a request was signed but not submitted, resumeOperation can resubmit the same signed request. This avoids consuming a new forwarder nonce.

const recovered = await client.resumeOperation(operationId);

Current resume behavior:

Error Handling

Errors are exposed as StorailError with stable codes.

Common codes:

Applications should branch on error.code, not on RPC or relay text.