7.8 KiB
paths
| paths | |
|---|---|
|
XRPL Python Code Sample Conventions
Code samples come in two flavors with very different conventions. Identify which you're writing first.
| Flavor | Filename pattern | Audience | Priority |
|---|---|---|---|
| Tutorial | <verb>_<thing>.py (e.g., create_loan_broker.py) |
A dev reading & learning the protocol | Clarity over speed |
| Setup | <topic>_setup.py (e.g., lending_setup.py) |
A dev who never opens this file — runs to prep network data (accounts, tokens, etc.) for all tutorials in the subject folder | Speed over clarity |
If a file isn't clearly one or the other, prompt the user for clarity.
Style
Formatting
- 4-space indent
- Double quotes
- Trailing commas on multi-line collections and call args
Naming
- File names:
snake_case(e.g.,create_loan.py) - Variables:
snake_case—loan_broker,mpt_id,vault_id,loan_broker_id,credential_issuer - Transaction model fields:
snake_caseperxrpl-py(e.g.,account=,vault_id=,management_fee_rate=) —xrpl-pyhandles the PascalCase translation on the wire - Setup JSON keys:
snake_case(loan_broker,credential_issuer,mpt_id,vault_id,loan_broker_id)
Structure
Folder layout
Each code sample lives at _code-samples/<topic>/py/:
_code-samples/<topic>/py/
├── README.md
├── requirements.txt
├── <topic>_setup.py # Optional — runs once to prep network state
├── <topic>_setup.json # Auto-generated by the setup script and is gitignored
└── <verb>_<thing>.py # Tutorial scripts (one per user action)
README
README.md is the entry point for a reader running the samples.
- Title:
# <Topic> Examples (Python) - One-sentence description listing what the directory demonstrates
## Setupsection with a single fenced block showing venv creation +pip install -r requirements.txt:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
- One
##section per tutorial script, in the order a reader should run them:
- Heading describes the action (e.g.,
## Create a Loan Broker), not the filename - Fenced
shblock withpython3 <file>.py - One-sentence summary of what the script will output
- Fenced
shblock showing actual expected console output (real addresses, tx IDs, JSON dumps — captured from a successful sample code run)
---separator between tutorial sections
The expected-output blocks document the golden path. Update them when a script's output format changes.
requirements.txt
Minimal — pin only what's needed:
xrpl-py>=<latest-stable>
Add other deps only when a sample requires them.
Tutorial files
Sync API only — xrpl.clients.JsonRpcClient, xrpl.transaction.submit_and_wait, xrpl.wallet.Wallet, xrpl.wallet.generate_faucet_wallet. No asyncio, no main() wrapper, no if __name__ == "__main__": — scripts run top-to-bottom and exit.
Structure
- Multi-line
# IMPORTANT:header explaining what the script demonstrates and any preconditions (e.g., "uses an existing account that has a PRIVATE vault") - Imports — stdlib first, blank line, then
xrplimports - Set up the client:
# Set up client ----------------------
client = JsonRpcClient("https://s.devnet.rippletest.net:51234")
- (Optional) If the tutorial is using setup script data:
# This step checks for the necessary setup data to run the lending tutorials.
# If missing, lending_setup.py will generate the data.
if not os.path.exists("lending_setup.json"):
print("\n=== Lending tutorial data doesn't exist. Running setup script... ===\n")
subprocess.run([sys.executable, "lending_setup.py"], check=True)
# Load preconfigured accounts and vault_id.
with open("lending_setup.json") as f:
setup_data = json.load(f)
# You can replace these values with your own.
loan_broker = Wallet.from_seed(setup_data["loan_broker"]["seed"])
vault_id = setup_data["vault_id"]
print(f"\nLoan broker/vault owner address: {loan_broker.address}")
print(f"Vault ID: {vault_id}")
- (Optional) If no setup data is used, fund new wallets for the tutorial.
wallet = generate_faucet_wallet(client)
Funding multiple wallets requires sequential calls. 6. Tutorial code steps.
Tutorial code step guide
- Before each major step, add a comment and print a section banner.
- Build transactions as
xrpl-pymodel instances and print the wire form before submitting:# Prepare LoanBrokerSet transaction ---------------------- print("\n=== Preparing LoanBrokerSet transaction ===\n") loan_broker_set_tx = LoanBrokerSet( account=loan_broker.address, vault_id=vault_id, management_fee_rate=1000, ) print(json.dumps(loan_broker_set_tx.to_xrpl(), indent=2)) - Submit with
submit_and_waitand handle results by checking fortesSUCCESSand exiting on failure:# Submit, sign, and wait for validation ---------------------- print("\n=== Submitting LoanBrokerSet transaction ===\n") submit_response = submit_and_wait(loan_broker_set_tx, client, loan_broker) if submit_response.result["meta"]["TransactionResult"] != "tesSUCCESS": result_code = submit_response.result["meta"]["TransactionResult"] print(f"Error: Unable to create loan broker: {result_code}") sys.exit(1) print("Loan broker created successfully!") - Extract metadata relevant to the tutorial:
# Extract loan broker information from the transaction result print("\n=== Loan Broker Information ===\n") loan_broker_node = next( node for node in submit_response.result["meta"]["AffectedNodes"] if node.get("CreatedNode", {}).get("LedgerEntryType") == "LoanBroker" ) print(f"LoanBroker ID: {loan_broker_node['CreatedNode']['LedgerIndex']}") print(f"LoanBroker Psuedo-Account Address: {loan_broker_node['CreatedNode']['NewFields']['Account']}")
Setup files
Async API only — xrpl.asyncio.clients.AsyncWebsocketClient, xrpl.asyncio.wallet.generate_faucet_wallet, xrpl.asyncio.transaction (submit_and_wait, autofill, sign). Wrap in async def main(): + async with AsyncWebsocketClient(WSS_URL) as client:, and call asyncio.run(main()) at the bottom.
WebSocket endpoints: Devnet (wss://s.devnet.rippletest.net:51233) or Testnet (wss://s.altnet.rippletest.net:51233).
Speed-first patterns when possible
- Run independent transactions concurrently with
await asyncio.gather(...) - When fanning out parallel transactions from the same account, batch them first via
TicketCreate(ticket_count=N), then passsequence=0andticket_sequence=...on each parallel tx - Destructure gather results:
loan_broker, borrower = await asyncio.gather(generate_faucet_wallet(client), generate_faucet_wallet(client)) - Group
xrpl.modelsimports into a single alphabetized parenthesized block
Setup code guide
- Top comment: single line,
# Setup script for <topic> tutorials - Only output is a carriage-return progress indicator:
print("Setting up tutorial: N/D", end="\r")between phases, where N is the step number and D is the total steps - No
=== Section ===banners, no transaction dumps — the reader never sees this file's output beyond the progress counter - Section comments in code are short:
# Section description(no dash visual)
Output file
At the end, write all data the tutorials will need:
setup_data = {
"description": "This file is auto-generated by lending_setup.py. It stores XRPL account info for use in lending protocol tutorials.",
"loan_broker": {
"address": loan_broker.address,
"seed": loan_broker.seed,
},
"domain_id": domain_id,
"mpt_id": mpt_id,
}
with open("lending_setup.json", "w") as f:
json.dump(setup_data, f, indent=2)