Skip to content

Commit 35b90bb

Browse files
authored
chore: structure examples to have subfiles and names to match src (#770)
Signed-off-by: exploreriii <133720349+exploreriii@users.noreply.github.com>
1 parent 7a51eac commit 35b90bb

File tree

137 files changed

+558
-192
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+558
-192
lines changed

.github/workflows/examples.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,16 @@ jobs:
4646
shell: bash
4747
run: |
4848
set -euo pipefail
49-
files=$(ls examples/*.py)
49+
export PYTHONPATH="$PWD"
5050
51-
for file in $files;
52-
do
51+
files=$(find examples -name "*.py" -type f ! -name "__init__.py")
52+
53+
for file in $files; do
5354
echo -e "\n************ ${file} ************"
5455
55-
module="examples.$(basename "$file" .py)"
56+
# Convert path to module name
57+
module=$(realpath --relative-to="$PWD" "$file" | sed 's|/|.|g' | sed 's|.py$||')
5658
57-
# Run the example and capture both stdout and stderr
5859
if ! output=$(uv run -m "$module" 2>&1); then
5960
echo -e "\n❌ Example failed: ${file}"
6061
echo "************ Error Output ************"

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
8282
- docs: Add `docs/sdk_developers/project_structure.md` to explain repository layout and import paths.
8383

8484
### Changed
85-
85+
- chore: renamed examples to match src where possible
86+
- Moved examples/ to be inside subfiles to match src structure
87+
- changed example script workflow to run on new subdirectory structure
8688
- chore: bumped solo action from 14.0 to 15.0 (#764)
8789
- chore: replaced hardcoded 'testnet' messages with environment network name
8890
- chore: validate that token airdrop transactions require an available token service on the channel (#632)
@@ -148,7 +150,6 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
148150
- Added `docs/discord.md` explaining how to join and navigate the Hiero community Discord (#614).
149151

150152
### Changed
151-
152153
- Added direct links to Python SDK channel in Linux Foundation Decentralized Trust Discord back in
153154
- Updated all occurrences of non-functional Discord invite links throughout the documentation with the new, stable Hyperledger and Hedera invite links (#603).
154155
- Refactored TopicId class to use @dataclass decorator for reducing boilerplate code

examples/account/__init__.py

Whitespace-only changes.
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
"""
2+
Example demonstrating hbar allowance approval and usage.
3+
Run:
4+
uv run examples/account/account_allowance_approve_transaction_hbar.py
5+
"""
6+
7+
import os
8+
import sys
9+
10+
from dotenv import load_dotenv
11+
12+
from hiero_sdk_python import AccountId, Client, Hbar, Network, PrivateKey, TransactionId
13+
from hiero_sdk_python.account.account_allowance_approve_transaction import (
14+
AccountAllowanceApproveTransaction,
15+
)
16+
from hiero_sdk_python.account.account_create_transaction import AccountCreateTransaction
17+
from hiero_sdk_python.response_code import ResponseCode
18+
from hiero_sdk_python.transaction.transfer_transaction import TransferTransaction
19+
20+
load_dotenv()
21+
network_name = os.getenv('NETWORK', 'testnet').lower()
22+
23+
def setup_client():
24+
"""Initialize and set up the client with operator account"""
25+
network = Network(network_name)
26+
print(f"Connecting to Hedera {network_name} network!")
27+
client = Client(network)
28+
29+
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID",""))
30+
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY",""))
31+
client.set_operator(operator_id, operator_key)
32+
print(f"Client set up with operator id {client.operator_account_id}")
33+
34+
return client
35+
36+
37+
def create_account(client):
38+
"""Create an account"""
39+
account_private_key = PrivateKey.generate_ed25519()
40+
account_public_key = account_private_key.public_key()
41+
42+
account_receipt = (
43+
AccountCreateTransaction()
44+
.set_key(account_public_key)
45+
.set_initial_balance(Hbar(1))
46+
.set_account_memo("Account for hbar allowance")
47+
.execute(client)
48+
)
49+
50+
if account_receipt.status != ResponseCode.SUCCESS:
51+
print(f"Account creation failed with status: {ResponseCode(account_receipt.status).name}")
52+
sys.exit(1)
53+
54+
account_account_id = account_receipt.account_id
55+
56+
return account_account_id, account_private_key
57+
58+
59+
def approve_hbar_allowance(client, owner_account_id, spender_account_id, amount):
60+
"""Approve Hbar allowance for spender"""
61+
receipt = (
62+
AccountAllowanceApproveTransaction()
63+
.approve_hbar_allowance(owner_account_id, spender_account_id, amount)
64+
.execute(client)
65+
)
66+
67+
if receipt.status != ResponseCode.SUCCESS:
68+
print(f"Hbar allowance approval failed with status: {ResponseCode(receipt.status).name}")
69+
sys.exit(1)
70+
71+
print(f"Hbar allowance of {amount} approved for spender {spender_account_id}")
72+
return receipt
73+
74+
75+
def delete_hbar_allowance(client, owner_account_id, spender_account_id):
76+
"""Delete hbar allowance by setting amount to 0"""
77+
receipt = (
78+
AccountAllowanceApproveTransaction()
79+
.approve_hbar_allowance(owner_account_id, spender_account_id, Hbar(0))
80+
.execute(client)
81+
)
82+
83+
if receipt.status != ResponseCode.SUCCESS:
84+
print(f"Hbar allowance deletion failed with status: {ResponseCode(receipt.status).name}")
85+
sys.exit(1)
86+
87+
print(f"Hbar allowance deleted for spender {spender_account_id}")
88+
return receipt
89+
90+
91+
def transfer_hbar_without_allowance(client, spender_account_id, spender_private_key, amount):
92+
"""Transfer hbars without allowance"""
93+
print("Trying to transfer hbars without allowance...")
94+
owner_account_id = client.operator_account_id
95+
client.set_operator(spender_account_id, spender_private_key) # Set operator to spender
96+
97+
receipt = (
98+
TransferTransaction()
99+
.add_approved_hbar_transfer(owner_account_id, -amount.to_tinybars())
100+
.add_approved_hbar_transfer(spender_account_id, amount.to_tinybars())
101+
.execute(client)
102+
)
103+
104+
if receipt.status != ResponseCode.SPENDER_DOES_NOT_HAVE_ALLOWANCE:
105+
print(
106+
f"Hbar transfer should have failed with SPENDER_DOES_NOT_HAVE_ALLOWANCE "
107+
f"status but got: {ResponseCode(receipt.status).name}"
108+
)
109+
110+
print(f"Hbar transfer successfully failed with {ResponseCode(receipt.status).name} status")
111+
112+
113+
def hbar_allowance():
114+
"""
115+
Demonstrates hbar allowance functionality by:
116+
1. Setting up client with operator account
117+
2. Creating spender and receiver accounts
118+
3. Approving hbar allowance for spender
119+
4. Transferring hbars using the allowance
120+
5. Deleting the allowance
121+
6. Attempting to transfer hbars without allowance (should fail)
122+
"""
123+
client = setup_client()
124+
125+
# Create spender and receiver accounts
126+
spender_id, spender_private_key = create_account(client)
127+
print(f"Spender account created with ID: {spender_id}")
128+
129+
receiver_id, _ = create_account(client)
130+
print(f"Receiver account created with ID: {receiver_id}")
131+
132+
# Approve hbar allowance for spender
133+
allowance_amount = Hbar(2)
134+
135+
approve_hbar_allowance(client, client.operator_account_id, spender_id, allowance_amount)
136+
137+
# Transfer hbars using the allowance
138+
receipt = (
139+
TransferTransaction()
140+
.set_transaction_id(TransactionId.generate(spender_id))
141+
.add_approved_hbar_transfer(client.operator_account_id, -allowance_amount.to_tinybars())
142+
.add_approved_hbar_transfer(receiver_id, allowance_amount.to_tinybars())
143+
.freeze_with(client)
144+
.sign(spender_private_key)
145+
.execute(client)
146+
)
147+
148+
if receipt.status != ResponseCode.SUCCESS:
149+
print(f"Hbar transfer failed with status: {ResponseCode(receipt.status).name}")
150+
sys.exit(1)
151+
152+
print(f"Successfully transferred {allowance_amount} from", end=" ")
153+
print(f"{client.operator_account_id} to {receiver_id} using allowance")
154+
155+
# Delete allowance
156+
delete_hbar_allowance(client, client.operator_account_id, spender_id)
157+
158+
# Try to transfer hbars without allowance
159+
transfer_hbar_without_allowance(client, spender_id, spender_private_key, allowance_amount)
160+
161+
162+
if __name__ == "__main__":
163+
hbar_allowance()

examples/account_allowance_approve_transaction_nft.py renamed to examples/account/account_allowance_approve_transaction_nft.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
- Spender (as payer) transfers the NFT from the owner to the receiver.
1010
1111
Usage:
12-
uv run examples/account_allowance_approve_transaction_nft.py
12+
uv run examples/account/account_allowance_approve_transaction_nft.py
1313
"""
1414

1515
import os

examples/account_allowance_delete_transaction_nft.py renamed to examples/account/account_allowance_delete_transaction_nft.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
- Verifies the spender can NO LONGER transfer the NFT.
99
1010
Usage:
11-
uv run examples/account_allowance_delete_transaction_nft.py
11+
uv run examples/account/account_allowance_delete_transaction_nft.py
1212
"""
1313

1414
import os

examples/account_create.py renamed to examples/account/account_create_transaction.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
1313
Usage:
1414
Run this script directly:
15-
python examples/account_create.py
15+
python examples/account/account_create_transaction.py
1616
1717
Or using uv:
18-
uv run examples/account_create.py
18+
uv run examples/account/account_create_transaction.py
1919
2020
Requirements:
2121
- Environment variables OPERATOR_ID and OPERATOR_KEY must be set

examples/account_delete.py renamed to examples/account/account_delete_transaction.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""
22
Example demonstrating account delete functionality.
33
Run:
4-
uv run examples/account_delete.py
5-
python examples/account_delete.py
4+
uv run examples/account/account_delete_transaction.py
5+
python examples/account/account_delete_transaction.py
66
77
"""
88
import os

examples/account_id.py renamed to examples/account/account_id.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
2-
uv run examples/account_id.py
3-
python examples/account_id.py
2+
uv run examples/account/account_id.py
3+
python examples/account/account_id.py
44
55
This example demonstrates various ways to use the AccountId class:
66
1. Creating a standard AccountId

examples/account_info.py renamed to examples/account/account_info.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
"""
2+
uv run examples/account/account_info.py
3+
"""
4+
15
from hiero_sdk_python.account.account_id import AccountId
26
from hiero_sdk_python.crypto.private_key import PrivateKey
37
from hiero_sdk_python.crypto.public_key import PublicKey

0 commit comments

Comments
 (0)