author_submitAndWatchExtrinsic - Astar RPC Method
Submit an extrinsic and subscribe to lifecycle status updates on Astar. Track transactions from pool admission through finalization with real-time WebSocket events for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos.
Submits a signed extrinsic to Astar 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 Astar? Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.
When to Use This Method
author_submitAndWatchExtrinsic is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:
- Transaction Lifecycle Tracking -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Astar
- 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-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- User-Facing Feedback -- Power progress indicators and toast notifications in dApp interfaces with granular status updates
Code Examples
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 Astar. Monitor mempool activity, verify transaction submission, and analyze network congestion.
author_rotateKeys
Generate new session keys for validator operations on Astar. Essential for validator setup, key rotation, and security best practices on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments.