# author_submitExtrinsic - Bifrost RPC Method

Submits a fully signed extrinsic to Bifrost 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 Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`author_submitExtrinsic` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Token Transfers** -- Send native tokens or assets between accounts on Bifrost
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **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

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## 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;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bifrost/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/bifrost/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/bifrost/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/bifrost/chain_getBlock) -- Verify extrinsic inclusion in a block
