Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Send guaranteed transactions

Route transactions through reserved Enterprise-lane blockspace with @stablechain/enterprise. The guaranteedBlock module relays a GuaranteedTx (a type 0x3F CustomTx) through the Enterprise RPC gateway so it lands in capacity reserved for enterprise workloads. Unlike gas waiver, the signer pays its own gas, so it must be funded.

You can combine this with gas waiver to get guaranteed relayed transactions: gas-waived transactions that still land in the Enterprise lane.

Prerequisites

  • Node.js 20 or later, and @stablechain/enterprise plus viem installed. See the Enterprise SDK reference.
  • An Enterprise RPC gateway API key. The Enterprise SDK runs on Stable Mainnet and Stable Testnet, and access is gated: contact Stable to get a gateway endpoint.
  • A funded signer, since a GuaranteedTx pays its own gas.

1. Create a client with the guaranteed blockspace module

Pass guaranteedBlock and enterpriseRpcEndpoints to createStableEnterprise. The gateway is the only endpoint that admits 0x3F GuaranteedTxs, and it holds your API key. An invalid laneId is rejected up front.

import { createStableEnterprise, stable } from "@stablechain/enterprise";
import { privateKeyToAccount } from "viem/accounts";
 
const enterprise = createStableEnterprise({
  chain: stable,
  enterpriseRpcEndpoints: [process.env.ENTERPRISE_RPC_URL], // the gateway URL Stable provisions
  guaranteedBlock: {
    account: privateKeyToAccount(process.env.SIGNER_PRIVATE_KEY as `0x${string}`), // must be funded
    laneId: 0n, // Enterprise lane
  },
});
 
const gb = enterprise.guaranteedBlock;
StableEnterpriseClient { gasWaiver: undefined, guaranteedBlock, guaranteedWaiver: undefined }

2. Send a single transaction

Call send with the signer and the varying fields. The 1559 fee fields are required because the signer pays gas. The chainId, the Enterprise nonceKey, and the 2D nonce (discovered from the gateway) are handled for you.

import { createPublicClient, http } from "viem";
 
const publicClient = createPublicClient({ chain: stable, transport: http() });
const gasPrice = await publicClient.getGasPrice();
 
const { txHash } = await gb.send(signer, {
  to: recipient,
  gas: 21_000n,
  gasFeeCap: gasPrice * 2n,
  gasTipCap: gasPrice,
});
console.log("Guaranteed tx:", txHash);
Guaranteed tx: 0xabcd...7890

gasFeeCap is the maximum total fee per gas (the EIP-1559 maxFeePerGas) and gasTipCap is the maximum priority fee per gas (maxPriorityFeePerGas). Setting gasTipCap to the current gas price and gasFeeCap to twice it, as above, is a safe default.

The signer pays gas, so confirm it holds a balance before relaying. A GuaranteedTx from a zero-balance account fails.

3. Send a batch

Call sendBatch to send several transactions. Nonces are auto-sequenced from a discovered base, and you get one result per input, in input order. A failure strands its successors.

const results = await gb.sendBatch(signer, [
  { to: a, gas: 21_000n, gasFeeCap: gasPrice * 2n, gasTipCap: gasPrice },
  { to: b, gas: 21_000n, gasFeeCap: gasPrice * 2n, gasTipCap: gasPrice },
]);
 
for (const r of results) {
  console.log(r.success ? `[${r.index}] ✔ ${r.txHash}` : `[${r.index}] ✖ ${r.error?.code}`);
}
[0] ✔ 0xabcd...7890
[1] ✔ 0x1f2e...66a1

4. Send a pre-signed transaction

For a non-custodial flow, build and sign the GuaranteedTx elsewhere with buildGuaranteedTx, then hand the operator only the signed hex. The Enterprise nonce key comes from nonceKeyForLane.

import { buildGuaranteedTx, nonceKeyForLane, toSigner } from "@stablechain/enterprise";
 
const signed = await buildGuaranteedTx(toSigner(signer), stable.id, {
  to: recipient,
  gas: 21_000n,
  gasFeeCap,
  gasTipCap,
  nonce, // the account's current 2D-lane nonce
  nonceKey: nonceKeyForLane(0n), // Enterprise lane 0
});
 
const { txHash } = await gb.relay(signed);
console.log("Guaranteed tx:", txHash);
Guaranteed tx: 0xabcd...7890

For several pre-signed transactions, use relayBatch.

Combine with gas waiver

To waive the user's gas and still land in the Enterprise lane, compose both rails with the guaranteedWaiver module. The user needs no balance and no fee fields, and the transaction routes through the same gateway. See Guaranteed relayed transactions.

Handle rejections

send and relay throw StableEnterpriseRelayError on rejection. Gateway-specific codes include GATEWAY_UNAUTHORIZED (a missing or invalid API key) and QUOTA_EXCEEDED (the gateway gas quota is exhausted).

import { StableEnterpriseRelayError } from "@stablechain/enterprise";
 
try {
  await gb.send(signer, { to: recipient, gas: 21_000n, gasFeeCap, gasTipCap });
} catch (err) {
  if (err instanceof StableEnterpriseRelayError && err.code === "GATEWAY_UNAUTHORIZED") {
    // the Enterprise RPC gateway rejected the API key
  }
  throw err;
}
StableEnterpriseRelayError: relay failed [GATEWAY_UNAUTHORIZED]: invalid api key

Where to go next