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
The Python SDK exposes two methods for transactions on EVM chains:
send_transaction — signs a legacy transaction and broadcasts it via JSON-RPC in a single call. Returns the transaction hash.
sign_transaction — signs a legacy transaction and returns the raw ECDSA signature (0x + r + s + v, 132 chars). Broadcasting is your responsibility.
send_transaction is the recommended path for most apps. Reach for sign_transaction only if you need the signature out-of-band — co-signing, custom relayers, or assembling the raw tx yourself.
Prerequisites
Quick Start: Send a Transaction
send_transaction signs and broadcasts in one call. Pass a JSON-RPC endpoint either per-call via rpc_url=, or once at construction via rpc_urls={chainId: url}.
import asyncio
import os
from dynamic_wallet_sdk import DynamicEvmWalletClient
async def main():
async with DynamicEvmWalletClient(
os.environ["DYNAMIC_ENV_ID"],
rpc_urls={1: "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"},
) as client:
await client.authenticate_api_token(os.environ["DYNAMIC_API_TOKEN"])
tx = {
"to": "0xRecipientAddress",
"value": 100_000_000_000_000_000, # 0.1 ETH
"nonce": 0,
"gas": 21000,
"gasPrice": 20_000_000_000,
"chainId": 1,
"data": "0x",
}
tx_hash = await client.send_transaction(
address="0xYourWalletAddress",
tx=tx,
)
print(f"Transaction hash: {tx_hash}")
print(f"Explorer: https://etherscan.io/tx/{tx_hash}")
asyncio.run(main())
You can also pass rpc_url= per call, which overrides the constructor mapping:
tx_hash = await client.send_transaction(
address="0xYourWalletAddress",
tx=tx,
rpc_url="https://mainnet.infura.io/v3/YOUR_PROJECT_ID",
)
The SDK adds EIP-155 replay protection automatically based on chainId.
Signing with a Password-Protected Wallet
If the wallet was created with a password, pass it via password=. The same kwarg also auto-recovers key shares in stateless or fresh processes — see Step 3 of Create an EVM Wallet.
tx_hash = await client.send_transaction(
address="0xYourWalletAddress",
tx=tx,
password="your-wallet-password",
)
Common Transaction Types
ETH Transfer
tx = {
"to": "0xRecipientAddress",
"value": 100_000_000_000_000_000, # 0.1 ETH in wei
"nonce": nonce,
"gas": 21000,
"gasPrice": gas_price,
"chainId": 1,
"data": "0x",
}
Contract Interaction
tx = {
"to": "0xContractAddress",
"value": 0,
"nonce": nonce,
"gas": 100000,
"gasPrice": gas_price,
"chainId": 1,
"data": "0xFunctionSelector...", # ABI-encoded call data
}
EIP-1559 Support
EIP-1559 (Type 2) transactions are not yet supported — the SDK currently signs legacy transactions only. Use gasPrice rather than maxFeePerGas / maxPriorityFeePerGas. Passing EIP-1559 fields raises DynamicSDKError.
Manual Signing and Broadcasting
If you need the raw signature — for offline workflows, custom broadcast logic, or co-signing — call sign_transaction directly. It returns just the 65-byte ECDSA signature as a 0x-prefixed hex string (r + s + v, 132 chars). It does not return an RLP-encoded transaction.
import asyncio
import os
from dynamic_wallet_sdk import DynamicEvmWalletClient
async def main():
async with DynamicEvmWalletClient(os.environ["DYNAMIC_ENV_ID"]) as client:
await client.authenticate_api_token(os.environ["DYNAMIC_API_TOKEN"])
tx = {
"to": "0xRecipientAddress",
"value": 0,
"nonce": 0,
"gas": 21000,
"gasPrice": 20_000_000_000,
"chainId": 1,
"data": "0x",
}
sig_hex = await client.sign_transaction(
address="0xYourWalletAddress",
tx=tx,
)
print(f"Signature: {sig_hex}")
asyncio.run(main())
To broadcast yourself, combine the signature with the unsigned tx and apply EIP-155 v adjustment:
import rlp
from eth_account._utils.legacy_transactions import (
encode_transaction,
serializable_unsigned_transaction_from_dict,
)
from web3 import Web3
r = int(sig_hex[2:66], 16)
s = int(sig_hex[66:130], 16)
v = int(sig_hex[130:132], 16)
# EIP-155: v + chainId * 2 + 8
v = v + tx["chainId"] * 2 + 8
unsigned = serializable_unsigned_transaction_from_dict(tx)
raw_signed = encode_transaction(unsigned, vrs=(v, r, s))
w3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/v3/YOUR_PROJECT_ID"))
tx_hash = w3.eth.send_raw_transaction(raw_signed)
print(f"Transaction hash: {tx_hash.hex()}")
Error Handling
from dynamic_wallet_sdk import (
DynamicSDKError,
WalletNotFoundError,
)
try:
tx_hash = await client.send_transaction(address=address, tx=tx)
except WalletNotFoundError:
# Address not loaded into the client — rehydrate first.
await client.load_wallet(address)
tx_hash = await client.send_transaction(
address=address,
tx=tx,
password=password,
)
except DynamicSDKError as e:
print(f"Send failed: {e}")
Next Steps