Broadcasting Messages
This document provides a reference for broadcasting transactions with messages in Telescope-generated clients.
Transaction Broadcasting Methods
Method | Description | Best For |
---|---|---|
signAndBroadcast | Signs and broadcasts transactions in one step | Most use cases |
sign + broadcastTx | Separates signing and broadcasting steps | Multi-signature or offline signing |
signAndBroadcastWithoutBalanceCheck | Skips balance check for speedier execution | When balance is known to be sufficient |
Using SigningStargateClient
The standard way to broadcast transactions:
import { SigningStargateClient } from "@cosmjs/stargate";
// Create a SigningStargateClient (see Creating Signers documentation)
const client = await SigningStargateClient.connectWithSigner(rpcEndpoint, signer, options);
// Broadcast a transaction
const result = await client.signAndBroadcast(
signerAddress,
messages,
fee,
memo
);
Telescope Convenience Methods
import { getSigningClient } from "./my-chain-client";
// Create a chain-specific client
const client = await getSigningClient({
rpcEndpoint,
signer
});
// Broadcast a transaction using convenience method
const result = await client.sendMessages(
signerAddress,
messages,
fee,
memo
);
Broadcasting Options
Option | Description | Default |
---|---|---|
broadcastTimeoutMs | Maximum time to wait for confirmation | 60000 |
broadcastPollIntervalMs | Time between broadcast status checks | 3000 |
gasAdjustment | Multiplier for simulated gas | 1.5 |
gasPrice | Price per unit of gas | Chain-specific |
Transaction Result Structure
interface BroadcastTxResult {
readonly height: number; // Block height at which tx was committed
readonly transactionHash: string; // The hash of the transaction
readonly rawLog: string; // Raw log information
readonly code?: number; // 0 for success, error code otherwise
readonly data?: Uint8Array; // Return value from transaction
readonly gasUsed: number; // Amount of gas used
readonly gasWanted: number; // Amount of gas requested
readonly events: readonly Event[]; // Events emitted by the transaction
}
Broadcasting Workflow
- Preparation: Create messages and fee
- Simulation (optional): Estimate gas
- Signing: Create signature using signer
- Broadcasting: Send to network
- Confirmation: Wait for inclusion in a block
- Result Processing: Handle success/failure
Transaction Simulation
// Simulate to estimate gas requirements
const gasEstimated = await client.simulate(
signerAddress,
messages,
memo
);
// Apply safety factor
const gasLimit = Math.round(gasEstimated * 1.3);
// Create fee with estimated gas
const fee = {
amount: [{ denom: "uatom", amount: "5000" }],
gas: gasLimit.toString()
};
Broadcast Modes
Mode | Description | Use Case |
---|---|---|
block | Wait for block inclusion | Standard usage, ensures transaction success |
sync | Return after mempool validation | Faster response, when block confirmation not needed |
async | Return immediately | Maximum speed, no validation |
// Set broadcast mode (applicable for direct ABCI clients)
const result = await client.broadcastTx(
signedTx,
timeoutMs,
broadcastMode
);
Error Handling
try {
const result = await client.signAndBroadcast(
signerAddress,
messages,
fee,
memo
);
if (result.code === 0) {
console.log("Transaction successful");
} else {
console.error(`Transaction failed with code ${result.code}: ${result.rawLog}`);
}
} catch (error) {
if (error.message.includes("insufficient funds")) {
console.error("Account has insufficient funds to pay for fees");
} else if (error.message.includes("out of gas")) {
console.error("Transaction ran out of gas");
} else if (error.message.includes("account sequence mismatch")) {
console.error("Account sequence mismatch, retry with updated sequence");
} else {
console.error("Broadcasting error:", error);
}
}
Monitoring Transaction Status
// Get transaction status after broadcasting
const txStatus = await client.getTx(txHash);
// Check if transaction was included in a block
if (txStatus) {
console.log("Transaction included at height:", txStatus.height);
console.log("Transaction success:", txStatus.code === 0);
} else {
console.log("Transaction not yet included in a block");
}
Sequence Number Management
// Get account data to check sequence
const account = await client.getAccount(signerAddress);
if (!account) {
throw new Error("Account not found");
}
console.log("Current sequence:", account.sequence);
// For manual sequence management in advanced cases
const signDoc = {
chainId,
accountNumber: account.accountNumber,
sequence: account.sequence,
fee,
msgs: messages,
memo
};
Multi-Signature Transactions
// Collect signatures offline
const signatures = await Promise.all(
signers.map(signer => signer.sign(signerAddress, signDoc))
);
// Combine signatures
const combinedSignature = combineSignatures(signatures);
// Broadcast with combined signature
const signedTx = createSignedTx(signDoc, combinedSignature);
const result = await client.broadcastTx(signedTx);
Best Practices
- Always simulate transactions first to estimate gas
- Apply a safety margin to estimated gas (1.3-1.5x)
- Handle account sequence mismatches with retries
- Verify transaction success by checking result code
- Store transaction hashes for later queries
- Use appropriate broadcast modes for your use case
- Implement retry logic for transient failures
- Monitor network congestion and adjust gas prices