Python SDK
Introduction
The supra-sdk package is a Python SDK for Supra L1. It builds, signs and submits MoveVM transactions and reads
accounts, resources and transactions over the RPC API. The source is in the supra-python-sdk repository.
Key Features
- Complete Move VM Support - Full compatibility with Move VM operations
- On-chain Data Queries - Efficient methods to query blockchain state
- Transaction Management - Submit and manage transactions seamlessly
- Cryptographic Operations - Built-in support for ED25519 and multi-signature operations
- Token Operations - Native support for token creation and management
- BCS Serialization - Efficient Binary Canonical Serialization support
For detailed API documentation of all modules, see the Official Python SDK Reference and for some more reference examples, you can check official examples repo here.
Installation
supra-sdk requires Python 3.12 or later. Install it with pip in a virtual environment:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install supra-sdkVerify the installation by printing the installed version:
from importlib.metadata import version
print(version("supra-sdk"))Quick Start
Initialize the Client
import asyncio
from supra_sdk.account import Account
from supra_sdk.clients.rest import SupraClient
async def main():
# Initialize client with RPC endpoint
client = SupraClient("https://rpc-testnet.supra.com")
# Create a new account
account = Account.generate()
print(f"Address: {account.address()}")
# Close client when done
await client.close()
if __name__ == "__main__":
asyncio.run(main())Request Testnet Tokens
async def get_testnet_tokens():
client = SupraClient("https://rpc-testnet.supra.com")
account = Account.generate()
# Request tokens from faucet
tx_hash = await client.faucet(account.address())
if tx_hash:
print(f"Faucet successful! Tx: {tx_hash}")
# Optionally wait for confirmation
await client.wait_for_faucet(tx_hash)
await client.close()The faucet limits requests per IP address and account; see Faucet. A request over the limit makes
faucet raise ApiError (from supra_sdk.clients.api_client) with status_code 429. Its message holds the response
body, which includes retry_after_seconds.
from supra_sdk.clients.api_client import ApiError
try:
tx_hash = await client.faucet(account.address())
except ApiError as error:
if error.status_code == 429:
print(f"Faucet limit reached: {error}")
else:
raiseSubmit Your First Transaction
from supra_sdk.transactions import EntryFunction, TransactionArgument, TransactionPayload
from supra_sdk.bcs import Serializer
from supra_sdk.account import Account
from supra_sdk.clients.rest import SupraClient
async def transfer_coins():
client = SupraClient("https://rpc-testnet.supra.com")
sender = Account.generate()
recipient = Account.generate()
# Fund sender account
await client.faucet(sender.address())
# Create transfer payload. supra_account::transfer also creates the recipient's account if it does not exist.
payload = EntryFunction.natural(
"0x1::supra_account",
"transfer",
[],
[
TransactionArgument(recipient.address(), Serializer.struct),
TransactionArgument(100_000, Serializer.u64),
],
)
# Create and submit signed transaction
signed_txn = await client.create_signed_transaction(
sender,
TransactionPayload(payload)
)
result = await client.submit_transaction(signed_txn)
print(f"Transaction Hash: {result}")
await client.close()0x1::coin::transfer aborts with ECOIN_STORE_NOT_PUBLISHED when the recipient has no account yet, and the
transaction commits as failed. 0x1::supra_account::transfer creates the recipient’s account first. It takes no type
arguments. See Sending Tokens to New Accounts.
Gas Settings
SupraClient sets max_gas_amount and gas_unit_price on every transaction it builds. They come from
SupraClientConfig, whose defaults in supra-sdk 0.1.1 are:
| Setting | Default |
|---|---|
max_gas_amount | 500_000 gas units |
gas_unit_price | None, which uses min_configured_gas_price from GET /rpc/v3/transactions/estimate_gas_price |
expiration_ttl | 600 seconds |
The node rejects a transaction whose sender cannot pay max_gas_amount * gas_unit_price in advance, however little gas
the transaction uses. submit_transaction then raises ApiError with status_code 400 and the message
INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE. At a price of 100,000 quants per gas unit, the default max_gas_amount
needs 50,000,000,000 quants (500 SUPRA); read the current price from the endpoint above. An account with less sets a
lower limit:
from supra_sdk.clients.rest import SupraClient, SupraClientConfig
client = SupraClient(
"https://rpc-testnet.supra.com",
supra_client_config=SupraClientConfig(max_gas_amount=1_000),
)API Reference - SupraClient
SupraClient is the main interface for interacting with the Supra blockchain.
Constructor
SupraClient(base_url: str, supra_client_config: SupraClientConfig | None = None)Parameters:
base_url: RPC endpoint URLsupra_client_config: OptionalSupraClientConfigwith transaction and HTTP settings for the client
Example:
from supra_sdk.clients.rest import SupraClient, SupraClientConfig
client = SupraClient("https://rpc-testnet.supra.com")
# With a configuration object
client = SupraClient(
"https://rpc-testnet.supra.com",
supra_client_config=SupraClientConfig(),
)Core Methods
faucet(address: AccountAddress, wait_for_faucet: bool = True) -> str | None
Request testnet tokens from the faucet.
Parameters:
address: Recipient addresswait_for_faucet: Whether to wait for transaction confirmation (default: True)
Returns: Faucet transaction hash, or None if the faucet answered without accepting the request. With
wait_for_faucet=True the method raises FaucetRequestNotAcceptedError instead of returning None. A response with an
HTTP status other than 200, such as 429 when the limit is reached, raises ApiError.
Example:
tx_hash = await client.faucet(account.address())
# Or without waiting
tx_hash = await client.faucet(account.address(), wait_for_faucet=False)
if tx_hash:
await client.wait_for_faucet(tx_hash)wait_for_faucet(faucet_tx_hash: str) -> dict[str, Any]
Wait for faucet transaction to complete.
Parameters:
faucet_tx_hash: Faucet transaction hash
Returns: Transaction data once the faucet transaction is no longer pending
create_signed_transaction(sender: Account, transaction_payload: TransactionPayload, sequence_number: int | None = None) -> SignedTransaction
Create a signed transaction ready for submission.
Parameters:
sender: Account signing the transactiontransaction_payload: Transaction payload (EntryFunction, Script, etc.)sequence_number: Sequence number to use (default: the account’s current sequence number)
Returns: Signed transaction object
Example:
payload = EntryFunction.natural(...)
signed_txn = await client.create_signed_transaction(account, TransactionPayload(payload))submit_transaction(signed_transaction: SignedTransaction) -> str
Submit a signed transaction to the blockchain.
Parameters:
signed_transaction: Signed transaction object
Returns: Transaction hash
API Reference - Account
Account class manages cryptographic keys and signing operations.
Creating Accounts
from supra_sdk.account import Account
# Generate new random account
account = Account.generate()
# Load from private key hex string
account = Account.load_key("0x1234...private_key_hex")
# Save account to file
account.store("./my_account.json")
# Load account from file
account = Account.load("./my_account.json")store writes the account’s private key to the file as unencrypted hex, with your default file permissions. Restrict
the file to your user (chmod 600 ./my_account.json) and keep it out of version control. Anyone who can read the
file controls the account.
API Reference - Token Clients
SupraTokenClient
High-level client for the legacy 0x3::token NFT standard (collections and tokens), not for fungible tokens.
Constructor
from supra_sdk.clients import SupraTokenClient
token_client = SupraTokenClient(supra_client)Key Methods
create_collection(account: Account, name: str, description: str, uri: str) -> str
Create a new token collection.
Example:
await token_client.create_collection(
account,
"My Collection",
"Collection description",
"https://example.com/collection"
)create_token(account: Account, collection_name: str, name: str, description: str, supply: int, uri: str, royalty_points_per_million: int) -> str
Mint a new token in a collection. royalty_points_per_million is the royalty in millionths of the sale price:
50000 is 5%.
Example:
await token_client.create_token(
account,
"My Collection",
"Token #1",
"First token",
supply=1,
uri="https://example.com/token/1",
royalty_points_per_million=50000 # 5% royalty
)offer_token(account: Account, receiver: AccountAddress, creator: AccountAddress, collection_name: str, token_name: str, property_version: int, amount: int) -> str
Offer a token to another account.
claim_token(account: Account, sender: AccountAddress, creator: AccountAddress, collection_name: str, token_name: str, property_version: int) -> str
Claim an offered token.
get_token_balance(owner: AccountAddress, creator: AccountAddress, collection_name: str, token_name: str, property_version: int) -> str
Get token balance for an account.
get_collection(creator: AccountAddress, collection_name: str) -> Any
Get collection data.
get_token_data(creator: AccountAddress, collection_name: str, token_name: str) -> Any
Get token metadata.
API Reference - Transactions
Creating Transaction Payloads
from supra_sdk.transactions import (
EntryFunction,
TransactionArgument,
TransactionPayload
)
from supra_sdk.bcs import Serializer
# Create an entry function payload
payload = EntryFunction.natural(
"0x1::supra_account", # Module
"transfer", # Function
[], # Type args
[
TransactionArgument(recipient_address, Serializer.struct),
TransactionArgument(amount, Serializer.u64),
] # Arguments
)
# Wrap in TransactionPayload
tx_payload = TransactionPayload(payload)EntryFunction
natural(module: str, function: str, ty_args: list[TypeTag], args: list[TransactionArgument]) -> EntryFunction (static)
Create an entry function with natural argument encoding.
Parameters:
module: Module identifier (e.g., “0x1::coin”)function: Function namety_args: Type argumentsargs: Function arguments as TransactionArgument objects
TransactionArgument
TransactionArgument(value: Any, serializer: Callable)Wraps an argument with its serializer function.
Common serializers from Serializer:
Serializer.u8,Serializer.u64,Serializer.u128,Serializer.u256Serializer.boolSerializer.struct(for addresses and complex types)Serializer.str(for strings)
API Reference - Type System
TypeTag & StructTag
from supra_sdk.type_tag import TypeTag, StructTag
# Parse struct type from string
coin_type = StructTag.from_str("0x1::supra_coin::SupraCoin")
# Use in type arguments
type_arg = TypeTag(coin_type)
# Generic types
coin_store_type = StructTag.from_str(
"0x1::coin::CoinStore<0x1::supra_coin::SupraCoin>"
)StructTag
from_str(type_tag: str) -> StructTag (static)
Parse a struct type from string representation.
Example:
# Simple type
simple = StructTag.from_str("0x1::coin::Coin")
# Generic type with type parameters
generic = StructTag.from_str("0x1::coin::Coin<0x1::supra_coin::SupraCoin>")API Reference - BCS Serialization
Binary Canonical Serialization (BCS) is the format used by Move VM.
Serializer
from supra_sdk.bcs import Serializer
serializer = Serializer()
serializer.u64(12345)
serializer.str("Hello")
serializer.bool(True)
# Get serialized bytes
data = serializer.output()Deserializer
from supra_sdk.bcs import Deserializer
deserializer = Deserializer(data)
number = deserializer.u64()
text = deserializer.str()
flag = deserializer.bool()Common Serialization Methods
u8(value: int),u16(value: int),u32(value: int),u64(value: int)u128(value: int),u256(value: int)bool(value: bool)str(value: str)struct(value: Serializable)sequence(values: list, encoder: Callable)
NFT Collection Example:
This example demonstrates how to create and manage an NFT collection using the Supra Python SDK.
import asyncio
import json
from supra_sdk.account import Account
from supra_sdk.clients import SupraTokenClient
from supra_sdk.clients.rest import SupraClient
RPC_NODE_URL = "https://rpc-testnet.supra.com"
async def main():
supra_client = SupraClient(RPC_NODE_URL)
token_client = SupraTokenClient(supra_client)
alice = Account.generate()
bob = Account.generate()
collection_name = "Alice's"
token_name = "Alice's first token"
property_version = 0
print(f"Alice account address: {alice.address()}")
print(f"Bob account address: {bob.address()}")
await supra_client.faucet(alice.address())
await supra_client.faucet(bob.address())
print("\n=== Creating Collection and Token ===")
await token_client.create_collection(
alice, collection_name, "Alice's simple collection", "https://supra.com"
)
await token_client.create_token(
alice,
collection_name,
token_name,
"Alice's simple token",
1,
"https://supra.dev/img/temp.jpeg",
0,
)
collection_data = await token_client.get_collection(
alice.address(), collection_name
)
print(
f"Alice's collection: {json.dumps(collection_data, indent=4, sort_keys=True)}"
)
balance = await token_client.get_token_balance(
alice.address(), alice.address(), collection_name, token_name, property_version
)
print(f"Alice's token balance: {balance}")
token_data = await token_client.get_token_data(
alice.address(), collection_name, token_name
)
print(f"Alice's token data: {json.dumps(token_data, indent=4, sort_keys=True)}")
print("\n=== Transferring the token to Bob ===")
await token_client.offer_token(
alice,
bob.address(),
alice.address(),
collection_name,
token_name,
property_version,
1,
)
await token_client.claim_token(
bob,
alice.address(),
alice.address(),
collection_name,
token_name,
property_version,
)
alice_balance = token_client.get_token_balance(
alice.address(), alice.address(), collection_name, token_name, property_version
)
bob_balance = token_client.get_token_balance(
bob.address(), alice.address(), collection_name, token_name, property_version
)
[alice_balance, bob_balance] = await asyncio.gather(*[alice_balance, bob_balance])
print(f"Alice's token balance: {alice_balance}")
print(f"Bob's token balance: {bob_balance}")
print("\n=== Transferring the token back to Alice using MultiAgent ===")
await token_client.direct_transfer_token(
bob, alice, alice.address(), collection_name, token_name, 0, 1
)
alice_balance = token_client.get_token_balance(
alice.address(), alice.address(), collection_name, token_name, property_version
)
bob_balance = token_client.get_token_balance(
bob.address(), alice.address(), collection_name, token_name, property_version
)
[alice_balance, bob_balance] = await asyncio.gather(*[alice_balance, bob_balance])
print(f"Alice's token balance: {alice_balance}")
print(f"Bob's token balance: {bob_balance}")
await supra_client.close()
if __name__ == "__main__":
asyncio.run(main())