-
Notifications
You must be signed in to change notification settings - Fork 92
Description
π Problem
SDK users often understand what a transaction does, but not how the transaction lifecycle works in the Python SDK.
Right now, we lack a beginner-friendly explanation of the typical transaction flow:
create β populate β freeze β sign β execute β check response
Users may wonder:
Why do I need to call .freeze_with(client)?
When do I sign? Who needs to sign?
Why does execution return a receipt?
What happens if I skip one of the steps?
def demonstrate_mint_success(client, token_id, supply_key):
"""
Mint a token using the valid supply key.
For NFTs, minting involve setting metadata for each unique serial number been created.
"""
print(f"Attempting to mint NFT to {token_id} using Supply Key...")
transaction = (
TokenMintTransaction()
.set_token_id(token_id)
.set_metadata([b"NFT Serial 1", b"NFT Serial 2"])
.freeze_with(client)
)
## #### =>: Must sign with the supply key!
transaction.sign(supply_key)
receipt = transaction.execute(client)
if receipt.status != ResponseCode.SUCCESS:
print(f" β Mint failed with status: {ResponseCode(receipt.status).name}")
return
print(f"β
Mint Successful! New Serials: {receipt.serial_numbers}")π― Solution
Create a user-focused documentation page explaining the lifecycle of executing a (token) transaction using the Python SDK.
This document should describe:
What each step in the chain does
Why the order matters
It refer to an example of setting up a transaction e.g.
examples/token_grant_kyc.py
with correct vs incorrect
π οΈ Implementation Guide
The documentation should walk through the six steps of a typical transaction.
- Construct the transaction
Explain:
The transaction object is created empty or partially populated, typically if you are doing pythonic vs method chaining.
Example:
(see docs/sdk_users/running_examples.md)
Deleting an Account
Pythonic Syntax:
transaction = AccountDeleteTransaction(
account_id=account_id,
transfer_account_id=transfer_account_id # Account to receive remaining balance
).freeze_with(client)
transaction.sign(account_private_key) # Account being deleted must sign
transaction.execute(client)
Method Chaining:
transaction = (
AccountDeleteTransaction()
.set_account_id(account_id)
.set_transfer_account_id(transfer_account_id) # Account to receive remaining balance
.freeze_with(client)
)
transaction.sign(account_private_key) # Account being deleted must sign
transaction.execute(client)
if you are using setters:
Example:
.set_account_id(account_id)
.add_token_id(token_id)
This step collects all the information that will end up in the transaction body.
3. Freeze the transaction
Freezing finalizes the transaction payload
After freezing, fields cannot be changed
Example:
.freeze_with(client)
Freezing is required before signing.
4. Sign the transaction
Hedera requires cryptographic signatures for authorization
The operator often signs automatically, but additional signers may be required depending on the requirements for that specific transaction
You may need multiple .sign() calls for a given transaction
Example:
.sign(admin_key)
5. Execute the transaction
Sending the transaction to Hedera
If the network accepts the transaction β returns a TransactionResponse
IMPORTANT: This step does NOT guarantee success β only that the network received it
Example:
.execute(client)
6. Fetch and check the receipt
Hedera will process the transaction, and will generate a receipt for you to see how it was processed.
Must check receipt.status for ResponseCode.SUCCESS
(or your expected ResponseCode message)
Example:
if receipt.status != ResponseCode.SUCCESS:
...
show some kind of clean, minimal example that demonstrates the workflow well (you can pick):
eg
def associate_token_with_account(client, account_id, account_private_key, token_id):
"""Associate a token with an account."""
receipt = (
TokenAssociateTransaction()
.set_account_id(account_id)
.add_token_id(token_id)
.freeze_with(client) # lock transaction fields
.sign(account_private_key) # authorize
.execute(client) # submit to Hedera
)
if receipt.status != ResponseCode.SUCCESS:
print(f"Token association failed with status: {ResponseCode(receipt.status).name}")
sys.exit(1)
Optionally, include a small diagram showing the flow:
[build] β [freeze] β [sign] β [execute] β [receipt]