Documentation Index
Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Dynamic’s Python SDK exposes two transaction methods on DynamicSvmWalletClient:
send_transaction — signs a serialized message and broadcasts it via JSON-RPC. Returns the base58-encoded transaction signature. This is the path most apps want.
sign_transaction — signs only. Returns a hex-encoded Ed25519 signature you assemble into a transaction yourself. Note that this is asymmetric with sign_message, which returns a base58 signature — the SDK uses different encodings on purpose.
Both methods sign the transaction message (not the full transaction). Pass bytes(tx.message) or tx.serialize_message().
Prerequisites
Quick Start: Send a Transaction
send_transaction builds the wire transaction, signs the message, and broadcasts it for you:
import asyncio
import os
from solders.pubkey import Pubkey
from solders.system_program import transfer, TransferParams
from solders.message import Message
from solders.hash import Hash
import httpx
from dynamic_wallet_sdk import DynamicSvmWalletClient
async def get_recent_blockhash(rpc_url: str) -> str:
async with httpx.AsyncClient() as http:
resp = await http.post(rpc_url, json={
"jsonrpc": "2.0",
"id": 1,
"method": "getLatestBlockhash",
"params": [{"commitment": "finalized"}],
})
return resp.json()["result"]["value"]["blockhash"]
async def main():
rpc_url = "https://api.mainnet-beta.solana.com"
from_address = "YourBase58WalletAddress"
to_address = "RecipientBase58Address"
from_pubkey = Pubkey.from_string(from_address)
to_pubkey = Pubkey.from_string(to_address)
blockhash = await get_recent_blockhash(rpc_url)
instruction = transfer(TransferParams(
from_pubkey=from_pubkey,
to_pubkey=to_pubkey,
lamports=1_000_000,
))
message = Message.new_with_blockhash(
[instruction],
from_pubkey,
Hash.from_string(blockhash),
)
async with DynamicSvmWalletClient(os.environ["DYNAMIC_ENV_ID"]) as client:
await client.authenticate_api_token(os.environ["DYNAMIC_API_TOKEN"])
tx_signature = await client.send_transaction(
address=from_address,
message_bytes=bytes(message),
rpc_url=rpc_url,
)
print(f"Transaction: {tx_signature}") # base58 tx signature
asyncio.run(main())
rpc_url resolution: explicit argument → DynamicSvmWalletClient(default_rpc_url=...) → falls back to https://api.devnet.solana.com.
Signing with a Password-Protected Wallet
tx_signature = await client.send_transaction(
address=from_address,
message_bytes=bytes(message),
rpc_url=rpc_url,
password="your-wallet-password",
)
Pass sponsor=True to have Dynamic pay network fees for the transaction:
tx_signature = await client.send_transaction(
address=from_address,
message_bytes=bytes(message),
rpc_url=rpc_url,
sponsor=True,
)
Gas sponsorship requires the feature to be enabled for your environment in the Dynamic dashboard.
Manual Signing and Broadcasting
When you need to inspect, log, or relay the signed transaction yourself, use sign_transaction to get the raw signature and assemble the wire transaction by hand.
import asyncio
import os
from solders.pubkey import Pubkey
from solders.transaction import Transaction
from solders.system_program import transfer, TransferParams
from solders.message import Message
from solders.hash import Hash
import httpx
from dynamic_wallet_sdk import DynamicSvmWalletClient
async def send_sol(
from_address: str,
to_address: str,
lamports: int,
rpc_url: str,
password: str | None = None,
):
from_pubkey = Pubkey.from_string(from_address)
to_pubkey = Pubkey.from_string(to_address)
async with httpx.AsyncClient() as http:
resp = await http.post(rpc_url, json={
"jsonrpc": "2.0",
"id": 1,
"method": "getLatestBlockhash",
"params": [{"commitment": "finalized"}],
})
blockhash = resp.json()["result"]["value"]["blockhash"]
instruction = transfer(TransferParams(
from_pubkey=from_pubkey,
to_pubkey=to_pubkey,
lamports=lamports,
))
message = Message.new_with_blockhash(
[instruction],
from_pubkey,
Hash.from_string(blockhash),
)
async with DynamicSvmWalletClient(os.environ["DYNAMIC_ENV_ID"]) as client:
await client.authenticate_api_token(os.environ["DYNAMIC_API_TOKEN"])
sig_hex = await client.sign_transaction(
address=from_address,
message_bytes=bytes(message),
password=password,
)
sig_bytes = bytes.fromhex(sig_hex)
tx = Transaction.populate(message, [sig_bytes])
async with httpx.AsyncClient() as http:
resp = await http.post(rpc_url, json={
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
bytes(tx).hex(),
{"encoding": "base64", "skipPreflight": False},
],
})
return resp.json()["result"]
sign_transaction returns the signature as hex (64 bytes / 128 hex chars). Convert to bytes with bytes.fromhex(sig_hex) before inserting into the transaction. If a downstream consumer expects base58:
import base58
sig_b58 = base58.b58encode(bytes.fromhex(sig_hex)).decode()
Verifying a Signature
import nacl.signing
import base58
sig_bytes = bytes.fromhex(signature_hex)
pubkey_bytes = base58.b58decode(address)
verify_key = nacl.signing.VerifyKey(pubkey_bytes)
verify_key.verify(message_bytes, sig_bytes)
print("Signature verified")
Error Handling
from dynamic_wallet_sdk import DynamicSDKError
try:
sig_hex = await client.sign_transaction(
address=address,
message_bytes=bytes(message),
)
except DynamicSDKError as e:
print(f"Signing failed: {e}")
Next Steps