PerformanceBlog
Tempo MCP serverGive agents search and read tools for Tempo docs
Skip to content
LogoLogo

Python SDK

Tempo distributes a Python SDK as a web3.py extension. The SDK adds native support for Tempo Transactions, including call batching, fee sponsorship, and access key management.

The Tempo Python SDK can be used to perform common operations with the chain, such as: sending Tempo Transactions, batching multiple calls, fee sponsorship, and more.

Install the Python SDK

To install the Tempo Python SDK:

pip
pip install pytempo

Create a Python client

To interact with Tempo, create a web3.py client connected to a Tempo node:

main.py
from web3 import Web3
 
w3 = Web3(Web3.HTTPProvider("https://rpc.tempo.xyz")) 
 
block_number = w3.eth.block_number
print(f"Connected to Tempo at block {block_number}")

Send a Tempo transaction with Python

Build and send a transaction using the TempoTransaction class:

main.py
import os
from web3 import Web3
from pytempo import Call, TempoTransaction 
 
w3 = Web3(Web3.HTTPProvider("https://rpc.tempo.xyz"))
private_key = os.environ["PRIVATE_KEY"]
account = w3.eth.account.from_key(private_key)
 
tx = TempoTransaction.create(
    chain_id=w3.eth.chain_id,
    gas_limit=100_000,
    max_fee_per_gas=w3.eth.gas_price * 2,
    max_priority_fee_per_gas=w3.eth.gas_price,
    nonce=w3.eth.get_transaction_count(account.address),
    calls=(
        Call.create(to="0x70997970C51812dc3A010C7d01b50e0d17dc79C8"),
    ),
)
 
signed_tx = tx.sign(private_key) 
tx_hash = w3.eth.send_raw_transaction(signed_tx.encode()) 
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"Transaction hash: {tx_hash.hex()}")

Python SDK examples

Send a token transfer with Python

Send a TIP-20 token transfer using pytempo's typed contract helpers:

transfer.py
from pytempo import TempoTransaction
from pytempo.contracts import TIP20, ALPHA_USD
 
tx = TempoTransaction.create(
    chain_id=4217,
    gas_limit=100_000,
    max_fee_per_gas=10_000_000_000,
    max_priority_fee_per_gas=1_000_000_000,
    nonce=w3.eth.get_transaction_count(account.address),
    calls=(
        TIP20(ALPHA_USD).transfer( 
            to="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", 
            amount=100_000_000, # 100 tokens (6 decimals) 
        ), 
    ),
)

Pay fees in a stablecoin with Python

Use a TIP-20 token to pay for transaction fees instead of the native token:

fee_token.py
from pytempo import TempoTransaction, Call
from pytempo.contracts import ALPHA_USD
 
tx = TempoTransaction.create(
    chain_id=4217,
    gas_limit=100_000,
    max_fee_per_gas=10_000_000_000,
    max_priority_fee_per_gas=1_000_000_000,
    nonce=w3.eth.get_transaction_count(account.address),
    fee_token=ALPHA_USD, 
    calls=(
        Call.create(to="0x70997970C51812dc3A010C7d01b50e0d17dc79C8"),
    ),
)

Batch multiple calls with Python

Execute multiple operations atomically in a single transaction:

batch.py
from pytempo import TempoTransaction
from pytempo.contracts import TIP20, ALPHA_USD
 
token = TIP20(ALPHA_USD)
 
tx = TempoTransaction.create(
    chain_id=4217,
    gas_limit=300_000,
    max_fee_per_gas=10_000_000_000,
    max_priority_fee_per_gas=1_000_000_000,
    nonce=w3.eth.get_transaction_count(account.address),
    calls=(
        token.transfer(to="0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb", amount=100_000_000), 
        token.transfer(to="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", amount=50_000_000), 
        token.transfer(to="0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", amount=25_000_000), 
    ),
)
 
signed_tx = tx.sign(private_key)
tx_hash = w3.eth.send_raw_transaction(signed_tx.encode())

Parallel Transactions (2D Nonces)

Send multiple transactions concurrently using different nonce keys:

parallel.py
tx1 = TempoTransaction.create(
    chain_id=4217,
    gas_limit=100_000,
    max_fee_per_gas=10_000_000_000,
    max_priority_fee_per_gas=1_000_000_000,
    nonce_key=1, # Sequence A
    nonce=0,
    calls=(Call.create(to=recipient1, data=data1),),
)
 
tx2 = TempoTransaction.create(
    chain_id=4217,
    gas_limit=100_000,
    max_fee_per_gas=10_000_000_000,
    max_priority_fee_per_gas=1_000_000_000,
    nonce_key=2, # Sequence B (parallel)
    nonce=0,
    calls=(Call.create(to=recipient2, data=data2),),
)
 
# Sign and send both in parallel
signed_tx1 = tx1.sign(private_key)
signed_tx2 = tx2.sign(private_key)
w3.eth.send_raw_transaction(signed_tx1.encode())
w3.eth.send_raw_transaction(signed_tx2.encode())

Fee sponsorship with Python

Have another account pay for transaction fees:

fee_payer.py
# User creates and signs a transaction marked for fee sponsorship
tx = TempoTransaction.create(
    chain_id=4217,
    gas_limit=100_000,
    max_fee_per_gas=10_000_000_000,
    max_priority_fee_per_gas=1_000_000_000,
    awaiting_fee_payer=True, 
    calls=(Call.create(to=recipient, data=data),),
)
 
signed_by_user = tx.sign(user_private_key)
final_tx = signed_by_user.sign(fee_payer_private_key, for_fee_payer=True) 
w3.eth.send_raw_transaction(final_tx.encode())

Transaction validity windows in Python

Set a time window during which the transaction is valid:

validity.py
import time
 
now = int(time.time())
 
tx = TempoTransaction.create(
    chain_id=4217,
    gas_limit=100_000,
    max_fee_per_gas=10_000_000_000,
    max_priority_fee_per_gas=1_000_000_000,
    nonce=nonce,
    valid_after=now, 
    valid_before=now + 3600, # 1 hour from now
    calls=(Call.create(to=recipient, data=data),),
)

Account Keychain in the Python SDK

The AccountKeychain class provides typed helpers for Tempo's Account Keychain precompile, enabling access key management directly from Python.

keychain.py
from pytempo import (
    TempoTransaction, Call,
    KeyRestrictions, SignatureType, TokenLimit, CallScope,
)
from pytempo.contracts import AccountKeychain, ALPHA_USD
from web3 import Web3
 
w3 = Web3(Web3.HTTPProvider("https://rpc.tempo.xyz"))
 
# Authorize a new access key (secp256k1, no expiry):
call = AccountKeychain.authorize_key(
    key_id="<ACCESS_KEY_ADDRESS>",
    signature_type=SignatureType.SECP256K1,
    restrictions=KeyRestrictions(expiry=0),
)
tx = TempoTransaction.create(
    chain_id=w3.eth.chain_id,
    gas_limit=200_000,
    max_fee_per_gas=w3.eth.gas_price * 2,
    max_priority_fee_per_gas=w3.eth.gas_price,
    nonce=w3.eth.get_transaction_count(account.address),
    calls=(call,),
)
 
# Authorize with a spending limit:
call = AccountKeychain.authorize_key(
    key_id="<ACCESS_KEY_ADDRESS>",
    signature_type=SignatureType.SECP256K1,
    restrictions=KeyRestrictions(
        expiry=0,
        limits=[TokenLimit(token=ALPHA_USD, limit=1_000_000)],
    ),
)
 
# Authorize with call scopes (restrict to specific contracts/functions):
call = AccountKeychain.authorize_key(
    key_id="<ACCESS_KEY_ADDRESS>",
    signature_type=SignatureType.SECP256K1,
    restrictions=KeyRestrictions(
        expiry=0,
        allowed_calls=[
            CallScope.transfer(target=ALPHA_USD),
            CallScope.approve(target=ALPHA_USD),
        ],
    ),
)
 
# Full example: 24h expiry + spending limit + call scope:
import time
expiry = int(time.time()) + 86400
call = AccountKeychain.authorize_key(
    key_id="<ACCESS_KEY_ADDRESS>",
    signature_type=SignatureType.SECP256K1,
    restrictions=KeyRestrictions(
        expiry=expiry,
        limits=[TokenLimit(token=ALPHA_USD, limit=1_000_000)],
        allowed_calls=[CallScope.transfer(target=ALPHA_USD)],
    ),
)
 
# Revoke an access key (permanent, cannot be re-authorized):
call = AccountKeychain.revoke_key(key_id="<ACCESS_KEY_ADDRESS>")
 
# Update spending limit for a key-token pair:
call = AccountKeychain.update_spending_limit(
    key_id="<ACCESS_KEY_ADDRESS>",
    token=str(ALPHA_USD),
    new_limit=2_000_000,
)
 
# Replace all call scopes for a key:
call = AccountKeychain.set_allowed_calls(
    key_id="<ACCESS_KEY_ADDRESS>",
    scopes=[
        CallScope.transfer(target=ALPHA_USD),
        CallScope.unrestricted(target="<CONTRACT_ADDRESS>"),
    ],
)
 
# Remove a target contract from allowed call list:
call = AccountKeychain.remove_allowed_calls(
    key_id="<ACCESS_KEY_ADDRESS>",
    target="<TARGET_ADDRESS>",
)
 
# Query key info (read-only):
key_info = AccountKeychain.get_key(
    w3,
    account_address="<ACCOUNT_ADDRESS>",
    key_id="<ACCESS_KEY_ADDRESS>",
)
print(key_info)
# {'signature_type': 0, 'key_id': '0x...', 'expiry': 1893456000, ...}
 
# Query remaining spending limit:
remaining = AccountKeychain.get_remaining_limit(
    w3,
    account_address="<ACCOUNT_ADDRESS>",
    key_id="<ACCESS_KEY_ADDRESS>",
    token_address=str(ALPHA_USD),
)
print(f"Remaining: {remaining}")

Sign with an access key in Python

Use sign_access_key to sign a transaction as an access key holder:

access_key_sign.py
from pytempo import TempoTransaction, Call
 
tx = TempoTransaction.create(
    chain_id=w3.eth.chain_id,
    gas_limit=100_000,
    max_fee_per_gas=w3.eth.gas_price * 2,
    max_priority_fee_per_gas=w3.eth.gas_price,
    nonce=w3.eth.get_transaction_count(root_account_address),
    calls=(Call.create(to="<CONTRACT_ADDRESS>"),),
)
 
signed_tx = tx.sign_access_key( 
    access_key_private_key="<ACCESS_KEY_PRIVATE_KEY>", 
    root_account="<ROOT_ACCOUNT_ADDRESS>", 
) 
tx_hash = w3.eth.send_raw_transaction(signed_tx.encode())

Next steps for the Python SDK

After setting up the Python SDK, you can: