Docs

author_submitExtrinsic - Mythos RPC Method

Submit a signed extrinsic to Mythos for inclusion in a block. Broadcast transactions for token transfers, staking operations, governance votes, and smart contract calls.

Submits a fully signed extrinsic to Mythos for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

Why Mythos? Build on the gaming blockchain powering FIFA Rivals and NFL Rivals with World ID verification with World ID proof-of-humanity, Polkadot security, Snowbridge cross-chain bridge, and 1M+ downloads per title.

When to Use This Method

author_submitExtrinsic is essential for game studios, player-driven economy builders, and teams requiring verified human-only gameplay:

  • Token Transfers -- Send native tokens or assets between accounts on Mythos
  • Staking and Governance -- Submit staking nominations, validator operations, and governance votes for AAA gaming (FIFA Rivals, NFL Rivals, Pudgy Party), player-owned economies, and bot-resistant matchmaking
  • Smart Contract Interaction -- Call ink! or EVM smart contracts deployed on the chain
  • Automated Systems -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

Code Examples

Common Use Cases

1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

JavaScript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}

2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

JavaScript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);

3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

JavaScript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
1010Invalid TransactionCheck signature, nonce, era, and that the extrinsic is properly SCALE-encoded
1010 (bad signature)Signature verification failedEnsure the signing key matches the sender account and the correct genesis hash was used
1010 (outdated)Nonce too lowThe nonce has already been used -- query the current nonce and rebuild the extrinsic
1010 (stale)Mortality period expiredThe extrinsic era has passed -- rebuild with a current era or use an immortal era
1012Transaction pool fullThe node's pool is at capacity -- retry later or increase tip
-32603Internal errorNode may be syncing or experiencing issues -- check node health
  • author_pendingExtrinsics -- Check the transaction pool for pending extrinsics
  • payment_queryInfo -- Estimate fees before submitting
  • system_accountNextIndex -- Get the next valid nonce for an account
  • state_call -- Call runtime APIs (e.g., for nonce via AccountNonceApi)
  • chain_getBlock -- Verify extrinsic inclusion in a block