Quick Start

This guide walks you through the five steps needed to place your first trade on the O2 Exchange using the Python SDK.

See also

For background on how the O2 Exchange works, see the O2 Exchange documentation.

Step 1: Initialize the client

from o2_sdk import O2Client, Network

client = O2Client(network=Network.TESTNET)

The client connects to the O2 testnet by default. Pass Network.MAINNET for production trading. You can also provide a custom NetworkConfig for private deployments.

Step 2: Create a wallet

# Fuel-native wallet
owner = client.generate_wallet()
print(owner.b256_address)  # 0x-prefixed, 66-character hex

# — or load an existing private key —
owner = client.load_wallet("0xabcd...1234")

The SDK supports both Fuel-native wallets and EVM-compatible wallets:

# EVM wallet (Ethereum-style address, zero-padded for Fuel)
evm_owner = client.generate_evm_wallet()
print(evm_owner.evm_address)    # 0x-prefixed, 42-character hex
print(evm_owner.b256_address)   # zero-padded to 32 bytes

Use Fuel-native wallets for broad interop with other Fuel ecosystem apps. Use EVM wallets when you want to reuse existing EVM accounts and simplify bridging from EVM chains. O2 owner identity is always B256; for EVM wallets, that B256 value is the EVM address zero-left-padded to 32 bytes.

Warning

Never hard-code private keys in source code. Use environment variables or a secrets manager for production deployments.

Step 3: Set up a trading account

account = await client.setup_account(owner)
print(account.trade_account_id)

setup_account() is idempotent — it is safe to call on every bot startup. It performs the following steps automatically:

  1. Checks whether an account already exists for the wallet address.

  2. Creates a new trading account if needed.

  3. Mints test tokens via the faucet (testnet/devnet only).

  4. Whitelists the account for trading.

Step 4: Create a trading session

session = await client.create_session(
    owner=owner,
    markets=["fFUEL/fUSDC"],
    expiry_days=30,
)

A session delegates signing authority from your owner wallet to a temporary session key. This allows the SDK to sign trade actions without needing the owner key for every request. Sessions are scoped to specific markets and expire after the specified number of days.

The returned session is stored as the client’s active session. Trading methods use it automatically unless you pass session=... explicitly.

Note

Session creation uses personalSign (Fuel prefix + SHA-256 for Fuel-native wallets, or Ethereum prefix + keccak-256 for EVM wallets). Session actions use rawSign (plain SHA-256). The SDK handles this distinction automatically.

Step 5: Place an order

from o2_sdk import OrderSide, OrderType

result = await client.create_order(
    market="fFUEL/fUSDC",
    side=OrderSide.BUY,
    price=0.02,
    quantity=100.0,
    order_type=OrderType.SPOT,
)

if result.success:
    print(f"Order placed! tx_id={result.tx_id}")
    if result.orders:
        print(f"Order ID: {result.orders[0].order_id}")

Prices and quantities accept human-readable values ("0.02", 100.0) or explicit on-chain integers via ChainInt. The SDK scales and validates inputs against the market’s constraints automatically.

Cleanup

Always close the client when you are done:

await client.close()

Or use the async context manager:

async with O2Client(network=Network.TESTNET) as client:
    # ... your trading logic ...
    pass  # close() is called automatically

Complete example

import asyncio
from o2_sdk import O2Client, Network, OrderSide

async def main():
    async with O2Client(network=Network.TESTNET) as client:
        # Wallet + account
        owner = client.generate_wallet()
        account = await client.setup_account(owner)

        # Session
        session = await client.create_session(
            owner=owner,
            markets=["fFUEL/fUSDC"],
        )

        # Place order
        result = await client.create_order(
            "fFUEL/fUSDC", OrderSide.BUY,
            price=0.02, quantity=100.0,
        )
        print(f"tx_id={result.tx_id}")

        # Check balances
        balances = await client.get_balances(account)
        for symbol, bal in balances.items():
            print(f"{symbol}: {bal.trading_account_balance}")

asyncio.run(main())

Next steps