author_submitAndWatchExtrinsic - Moonbeam RPC Method
Submit an extrinsic and subscribe to lifecycle status updates on Moonbeam. Track transactions from pool admission through finalization with real-time WebSocket events for cross-chain DeFi, multi-chain dApps, and Ethereum-to-Polkadot bridging via XCM, Axelar, LayerZero, and Wormhole.
Submits a signed extrinsic to Moonbeam and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.
Why Moonbeam? Build on the cross-chain connected EVM platform on Polkadot with $65M+ TVL and 100+ projects with full EVM compatibility on Polkadot, native XCM cross-chain messaging, 10K+ TPS, 24% staking APR, and $0.015 transaction costs.
When to Use This Method
author_submitAndWatchExtrinsic is essential for cross-chain dApp developers, Polkadot builders, and teams requiring multi-chain interoperability:
- Transaction Lifecycle Tracking -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Moonbeam
- Confirmation Waiting -- Block until a transaction reaches a specific finality level (e.g.,
inBlockorfinalized) before proceeding with dependent logic - Error Detection -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for cross-chain DeFi, multi-chain dApps, and Ethereum-to-Polkadot bridging via XCM, Axelar, LayerZero, and Wormhole
- User-Facing Feedback -- Power progress indicators and toast notifications in dApp interfaces with granular status updates
Code Examples
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
"jsonrpc": "2.0",
"method": "author_submitAndWatchExtrinsic",
"params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
"id": 1
}' | websocat wss://api-moonbeam.n.dwellir.com/YOUR_API_KEY
# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-moonbeam.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "author_submitExtrinsic",
"params": ["0x2d028400..."],
"id": 1
}'Common Use Cases
1. Transaction Confirmation with Timeout
Wait for finalization with a configurable timeout to avoid hanging indefinitely:
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';
async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error('Transaction confirmation timed out'));
}, timeoutMs);
tx.signAndSend(sender, ({ status, dispatchError, events }) => {
if (dispatchError) {
clearTimeout(timer);
if (dispatchError.isModule) {
const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
} else {
reject(new Error(dispatchError.toString()));
}
}
if (status.isFinalized) {
clearTimeout(timer);
resolve({
blockHash: status.asFinalized.toHex(),
events: events.map((e) => `${e.event.section}.${e.event.method}`)
});
}
}).catch((err) => {
clearTimeout(timer);
reject(err);
});
});
}2. Batch Transaction Pipeline
Submit multiple extrinsics sequentially and track each one through finalization:
async function submitBatch(api, sender, calls) {
const results = [];
let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();
for (const call of calls) {
const result = await new Promise((resolve, reject) => {
call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
if (dispatchError) {
const decoded = dispatchError.isModule
? api.registry.findMetaError(dispatchError.asModule)
: { name: dispatchError.toString() };
reject(new Error(`Dispatch error: ${decoded.name}`));
}
if (status.isFinalized) {
resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
}
});
});
results.push(result);
console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
}
return results;
}3. Reorg-Aware Event Handling
Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:
async function sendWithReorgHandling(api, sender, tx) {
let includedBlock = null;
return new Promise((resolve, reject) => {
tx.signAndSend(sender, ({ status, events }) => {
if (status.isReady) {
console.log('Transaction in ready queue');
}
if (status.isInBlock) {
includedBlock = status.asInBlock.toHex();
console.log(`Included in block: ${includedBlock}`);
}
if (status.isRetracted) {
console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
includedBlock = null;
}
if (status.isFinalized) {
console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
resolve({ finalized: status.asFinalized.toHex(), events });
}
if (status.isDropped || status.isInvalid) {
reject(new Error(`Transaction ${status.type}`));
}
if (status.isUsurped) {
reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
}
});
});
}Status Flow
┌─────────────────────────────────────┐
│ future (nonce gap) │
└──────────────┬──────────────────────┘
│ nonce becomes current
▼
submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
│ │
├──► dropped ✗ ├──► retracted (reorg) ──► inBlock (re-included)
├──► invalid ✗ └──► finalityTimeout ✗
└──► usurped ✗Error Handling
Common errors and solutions:
| Error Code | Description | Solution |
|---|---|---|
| 1002 | Verification error | The extrinsic has an invalid signature, wrong format, or failed validation -- re-sign and resubmit |
| 1010 | Invalid transaction | Bad nonce, insufficient balance, or the call is not permitted -- check account state with system_accountNextIndex |
| 1014 | Priority too low | Transaction pool rejected the extrinsic because a higher-priority transaction exists for the same nonce -- increase tip or wait |
| -32603 | Internal error | Node encountered an unexpected error -- retry after delay |
| Connection closed | WebSocket dropped | The subscription is lost -- reconnect and check author_pendingExtrinsics or re-query chain state to determine transaction outcome |
Related Methods
author_submitExtrinsic-- Submit an extrinsic without subscribing to status updates (fire-and-forget)system_accountNextIndex-- Get the next valid nonce for an account, including pending pool transactionsauthor_pendingExtrinsics-- List all extrinsics currently in the transaction poolpayment_queryInfo-- Estimate the fee for an extrinsic before submissionchain_getFinalizedHead-- Get the hash of the latest finalized block
author_pendingExtrinsics
Get pending extrinsics in the transaction pool on Moonbeam. Monitor mempool activity, verify transaction submission, and analyze network congestion.
author_rotateKeys
Generate new session keys for validator operations on Moonbeam. Essential for validator setup, key rotation, and security best practices on the cross-chain connected EVM platform on Polkadot with $65M+ TVL and 100+ projects.