>AgentChain

Sending Transactions

For LLM-based agents: If your agent runs through an LLM provider (OpenAI, Anthropic, etc.), use the Agent API instead of the methods on this page. The agent API handles all signing internally so private keys never appear in RPC calls. See Security Architecture for why this matters.

This guide walks through the full lifecycle of an AgentChain transaction using standard Ethereum libraries: creating an account, building a transaction object, signing, sending, and confirming. This approach is suitable for developers and non-LLM agents that manage keys locally.

AgentChain transaction details:

  • Native token: Credits / CRD (18 decimals, identical to ETH wei conversion)
  • EVM fork: Berlin (no EIP-1559 -- use legacy gasPrice transactions only)
  • Block time: 6 seconds
  • Gas limit: 10M – 60M per block (dynamic)
  • Min gas price: 1 Gwei
  • Tx ordering: First-come-first-served (FCFS)
  • Chain ID: 7331

Important: AgentChain uses the Berlin EVM fork. EIP-1559 fields (maxFeePerGas, maxPriorityFeePerGas) are not supported. Always use legacy transaction type with gasPrice.


Creating / Importing an Account

Python (web3.py)

from web3 import Web3
from eth_account import Account
 
# Generate a brand-new account
acct = Account.create()
print(f"Address:     {acct.address}")
print(f"Private key: {acct.key.hex()}")
 
# Or import from an existing private key
private_key = "0xYOUR_PRIVATE_KEY_HEX"
acct = Account.from_key(private_key)
print(f"Imported address: {acct.address}")

JavaScript (ethers.js v6)

import { ethers } from "ethers";
 
// Generate a brand-new account
const wallet = ethers.Wallet.createRandom();
console.log(`Address:     ${wallet.address}`);
console.log(`Private key: ${wallet.privateKey}`);
 
// Or import from an existing private key
const privateKey = "0xYOUR_PRIVATE_KEY_HEX";
const imported = new ethers.Wallet(privateKey);
console.log(`Imported address: ${imported.address}`);

Gas Estimation

Always estimate gas before sending. This avoids wasted fees from failed transactions.

Python (web3.py)

from web3 import Web3
 
w3 = Web3(Web3.HTTPProvider("http://localhost:8545"))
 
tx_params = {
    "from": acct.address,
    "to": "0xRecipientAddress",
    "value": w3.to_wei(1, "ether"),  # 1 CRD
}
 
# Estimate gas units required
gas_estimate = w3.eth.estimate_gas(tx_params)
print(f"Estimated gas: {gas_estimate}")
 
# Get the current gas price
gas_price = w3.eth.gas_price
print(f"Gas price: {gas_price} wei")
 
# Calculate the maximum transaction cost
max_cost_wei = gas_estimate * gas_price
print(f"Max cost: {w3.from_wei(max_cost_wei, 'ether')} CRD")

JavaScript (ethers.js v6)

import { ethers } from "ethers";
 
const provider = new ethers.JsonRpcProvider("http://localhost:8545");
 
const txParams = {
  from: wallet.address,
  to: "0xRecipientAddress",
  value: ethers.parseEther("1.0"), // 1 CRD
};
 
// Estimate gas units required
const gasEstimate = await provider.estimateGas(txParams);
console.log(`Estimated gas: ${gasEstimate}`);
 
// Get the current gas price (legacy)
const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;
console.log(`Gas price: ${gasPrice} wei`);
 
// Calculate the maximum transaction cost
const maxCost = gasEstimate * gasPrice;
console.log(`Max cost: ${ethers.formatEther(maxCost)} CRD`);

Nonce Management

Every transaction from an account must have a unique, sequential nonce. Using the wrong nonce causes transactions to fail or get stuck.

Python (web3.py)

from web3 import Web3
 
w3 = Web3(Web3.HTTPProvider("http://localhost:8545"))
 
# Get the next nonce for the account (includes pending transactions)
nonce = w3.eth.get_transaction_count(acct.address, "pending")
print(f"Next nonce: {nonce}")

JavaScript (ethers.js v6)

import { ethers } from "ethers";
 
const provider = new ethers.JsonRpcProvider("http://localhost:8545");
 
// Get the next nonce (includes pending transactions)
const nonce = await provider.getTransactionCount(wallet.address, "pending");
console.log(`Next nonce: ${nonce}`);

Building, Signing, and Sending a Transaction

Python (web3.py)

from web3 import Web3
from eth_account import Account
 
# Connect
w3 = Web3(Web3.HTTPProvider("http://localhost:8545"))
assert w3.is_connected() and w3.eth.chain_id == 7331
 
# Import account
private_key = "0xYOUR_PRIVATE_KEY_HEX"
acct = Account.from_key(private_key)
 
# Build the transaction (legacy -- no EIP-1559 fields)
tx = {
    "chainId": 7331,
    "from": acct.address,
    "to": "0xRecipientAddressHere",
    "value": w3.to_wei(0.5, "ether"),       # 0.5 CRD
    "gas": 21000,                            # standard transfer gas
    "gasPrice": w3.eth.gas_price,
    "nonce": w3.eth.get_transaction_count(acct.address, "pending"),
}
 
# Sign the transaction
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
 
# Send the signed transaction
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
print(f"Transaction sent: {tx_hash.hex()}")
 
# Wait for the receipt (blocks until mined)
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
print(f"Mined in block: {receipt['blockNumber']}")
print(f"Status: {'success' if receipt['status'] == 1 else 'reverted'}")
print(f"Gas used: {receipt['gasUsed']}")

JavaScript (ethers.js v6)

import { ethers } from "ethers";
 
// Connect
const provider = new ethers.JsonRpcProvider("http://localhost:8545");
const network = await provider.getNetwork();
if (network.chainId !== 7331n) throw new Error("Wrong network");
 
// Import account and connect to provider
const privateKey = "0xYOUR_PRIVATE_KEY_HEX";
const wallet = new ethers.Wallet(privateKey, provider);
 
// Build and send the transaction (legacy -- no EIP-1559 fields)
const tx = {
  to: "0xRecipientAddressHere",
  value: ethers.parseEther("0.5"),       // 0.5 CRD
  gasLimit: 21000n,                      // standard transfer gas
  gasPrice: (await provider.getFeeData()).gasPrice,
  nonce: await provider.getTransactionCount(wallet.address, "pending"),
  chainId: 7331,
  type: 0,                               // legacy transaction type
};
 
// Sign and send
const txResponse = await wallet.sendTransaction(tx);
console.log(`Transaction sent: ${txResponse.hash}`);
 
// Wait for confirmation
const receipt = await txResponse.wait();
console.log(`Mined in block: ${receipt.blockNumber}`);
console.log(`Status: ${receipt.status === 1 ? "success" : "reverted"}`);
console.log(`Gas used: ${receipt.gasUsed}`);

Checking Transaction Status

After sending, you may want to inspect a transaction by its hash without blocking.

Python (web3.py)

from web3 import Web3
 
w3 = Web3(Web3.HTTPProvider("http://localhost:8545"))
 
tx_hash = "0xYOUR_TX_HASH"
 
# Get transaction details (returns None if not found)
tx = w3.eth.get_transaction(tx_hash)
if tx is None:
    print("Transaction not found (may have been dropped)")
else:
    print(f"From: {tx['from']}")
    print(f"To: {tx['to']}")
    print(f"Value: {w3.from_wei(tx['value'], 'ether')} CRD")
    print(f"Block: {tx['blockNumber']}")  # None if still pending
 
# Get the receipt (only available after mining)
try:
    receipt = w3.eth.get_transaction_receipt(tx_hash)
    print(f"Status: {'success' if receipt['status'] == 1 else 'reverted'}")
    print(f"Gas used: {receipt['gasUsed']}")
except Exception:
    print("Receipt not available yet -- transaction is pending")

JavaScript (ethers.js v6)

import { ethers } from "ethers";
 
const provider = new ethers.JsonRpcProvider("http://localhost:8545");
 
const txHash = "0xYOUR_TX_HASH";
 
// Get transaction details (returns null if not found)
const tx = await provider.getTransaction(txHash);
if (tx === null) {
  console.log("Transaction not found (may have been dropped)");
} else {
  console.log(`From: ${tx.from}`);
  console.log(`To: ${tx.to}`);
  console.log(`Value: ${ethers.formatEther(tx.value)} CRD`);
  console.log(`Block: ${tx.blockNumber}`); // null if still pending
}
 
// Get the receipt (only available after mining)
const receipt = await provider.getTransactionReceipt(txHash);
if (receipt === null) {
  console.log("Receipt not available yet -- transaction is pending");
} else {
  console.log(`Status: ${receipt.status === 1 ? "success" : "reverted"}`);
  console.log(`Gas used: ${receipt.gasUsed}`);
}

Complete Example: End-to-End Transfer

Here is a self-contained script that connects, checks the balance, sends CRD, and confirms the result.

Python (web3.py)

from web3 import Web3
from eth_account import Account
 
# --- Configuration ---
RPC_URL = "http://localhost:8545"
PRIVATE_KEY = "0xYOUR_PRIVATE_KEY_HEX"
RECIPIENT = "0xRecipientAddressHere"
AMOUNT_CRD = 1.0
 
# --- Connect ---
w3 = Web3(Web3.HTTPProvider(RPC_URL))
assert w3.is_connected(), "Cannot reach node"
assert w3.eth.chain_id == 7331, "Wrong chain"
 
acct = Account.from_key(PRIVATE_KEY)
print(f"Sender: {acct.address}")
 
# --- Check balance ---
balance = w3.eth.get_balance(acct.address)
print(f"Balance: {w3.from_wei(balance, 'ether')} CRD")
 
amount_wei = w3.to_wei(AMOUNT_CRD, "ether")
if balance < amount_wei:
    raise ValueError("Insufficient balance")
 
# --- Build transaction ---
tx = {
    "chainId": 7331,
    "from": acct.address,
    "to": RECIPIENT,
    "value": amount_wei,
    "gas": 21000,
    "gasPrice": w3.eth.gas_price,
    "nonce": w3.eth.get_transaction_count(acct.address, "pending"),
}
 
# --- Sign and send ---
signed = w3.eth.account.sign_transaction(tx, PRIVATE_KEY)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f"Sent: {tx_hash.hex()}")
 
# --- Wait for confirmation ---
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
if receipt["status"] == 1:
    print(f"Success! Mined in block {receipt['blockNumber']}, gas used: {receipt['gasUsed']}")
else:
    print("Transaction reverted")
 
# --- Verify new balance ---
new_balance = w3.eth.get_balance(acct.address)
print(f"New balance: {w3.from_wei(new_balance, 'ether')} CRD")

JavaScript (ethers.js v6)

import { ethers } from "ethers";
 
// --- Configuration ---
const RPC_URL = "http://localhost:8545";
const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY_HEX";
const RECIPIENT = "0xRecipientAddressHere";
const AMOUNT_CRD = "1.0";
 
// --- Connect ---
const provider = new ethers.JsonRpcProvider(RPC_URL);
const network = await provider.getNetwork();
if (network.chainId !== 7331n) throw new Error("Wrong chain");
 
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
console.log(`Sender: ${wallet.address}`);
 
// --- Check balance ---
const balance = await provider.getBalance(wallet.address);
console.log(`Balance: ${ethers.formatEther(balance)} CRD`);
 
const amountWei = ethers.parseEther(AMOUNT_CRD);
if (balance < amountWei) throw new Error("Insufficient balance");
 
// --- Build and send transaction ---
const tx = {
  to: RECIPIENT,
  value: amountWei,
  gasLimit: 21000n,
  gasPrice: (await provider.getFeeData()).gasPrice,
  nonce: await provider.getTransactionCount(wallet.address, "pending"),
  chainId: 7331,
  type: 0, // legacy transaction
};
 
const txResponse = await wallet.sendTransaction(tx);
console.log(`Sent: ${txResponse.hash}`);
 
// --- Wait for confirmation ---
const receipt = await txResponse.wait();
if (receipt.status === 1) {
  console.log(`Success! Mined in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
} else {
  console.log("Transaction reverted");
}
 
// --- Verify new balance ---
const newBalance = await provider.getBalance(wallet.address);
console.log(`New balance: ${ethers.formatEther(newBalance)} CRD`);

Next Steps