Skip to Content

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-sdk

Verify 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: raise

Submit 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:

SettingDefault
max_gas_amount500_000 gas units
gas_unit_priceNone, which uses min_configured_gas_price from GET /rpc/v3/transactions/estimate_gas_price
expiration_ttl600 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 URL
  • supra_client_config: Optional SupraClientConfig with 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 address
  • wait_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 transaction
  • transaction_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 name
  • ty_args: Type arguments
  • args: 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.u256
  • Serializer.bool
  • Serializer.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())

Last updated on