Skip to content

Commit 7744971

Browse files
authored
Merge branch 'hiero-ledger:main' into main
2 parents 177248e + e1ffa96 commit 7744971

File tree

110 files changed

+4172
-838
lines changed

Some content is hidden

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

110 files changed

+4172
-838
lines changed

.github/workflows/examples.yml

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
2323
with:
2424
fetch-depth: 0
25-
25+
2626
- name: Install uv
2727
uses: astral-sh/setup-uv@1781c6eb42f98d67097986d30130a8ff6879fda2
2828

@@ -37,17 +37,32 @@ jobs:
3737
uses: hiero-ledger/hiero-solo-action@6a1a77601cf3e69661fb6880530a4edf656b40d5 #v0.14.0
3838
with:
3939
installMirrorNode: true
40-
4140
- name: Run Examples
4241
env:
4342
OPERATOR_ID: ${{ steps.solo.outputs.accountId }}
4443
OPERATOR_KEY: ${{ steps.solo.outputs.privateKey }}
4544
CHAIN_ID: 012A
4645
NETWORK: solo
46+
shell: bash
4747
run: |
48+
set -euo pipefail
4849
files=$(ls examples/*.py)
50+
4951
for file in $files;
5052
do
5153
echo -e "\n************ ${file} ************"
52-
uv run -m examples.$(basename "$file" .py)
53-
done
54+
55+
module="examples.$(basename "$file" .py)"
56+
57+
# Run the example and capture both stdout and stderr
58+
if ! output=$(uv run -m "$module" 2>&1); then
59+
echo -e "\n❌ Example failed: ${file}"
60+
echo "************ Error Output ************"
61+
echo "$output"
62+
echo "**************************************"
63+
exit 1
64+
fi
65+
66+
echo "$output"
67+
echo "✅ Completed ${file} successfully."
68+
done

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
77
## [Unreleased]
88

99
### Added
10+
- Add `TokenFeeScheduleUpdateTransaction` class to support updating custom fee schedules on tokens (#471).
11+
- Add `examples/token_update_fee_schedule_fungible.py` and `examples/token_update_fee_schedule_nft.py` demonstrating the use of `TokenFeeScheduleUpdateTransaction`.
12+
- Update `docs/sdk_users/running_examples.md` to include `TokenFeeScheduleUpdateTransaction`.
13+
- added FreezeTransaction class
14+
- added FreezeType class
1015
- Added `docs/sdk_developers/pylance.md`, a new guide explaining how to set up and use **Pylance** in VS Code for validating imports, file references, and methods before review. (#713)
16+
- feat: TokenAirdropClaim Transaction, examples (with signing required and not), unit and integration tests (#201)
1117
- docs: Add Google-style docstrings to `TokenId` class and its methods in `token_id.py`.
1218
- added Google-style docstrings to the `TransactionRecord` class including all dataclass fields, `__repr__`, `_from_proto()` & `_to_proto()` methods.
1319
- Standardized docstrings, improved error handling, and updated type hinting (`str | None` to `Optional[str]`) for the `FileId` class (#652).
@@ -23,6 +29,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
2329
- docs: Add `docs/sdk_developers/project_structure.md` to explain repository layout and import paths.
2430

2531
### Changed
32+
- chore: replaced hardcoded 'testnet' messages with environment network name
2633
- chore: validate that token airdrop transactions require an available token service on the channel (#632)
2734
- chore: update local environment configuration in env.example (#649)
2835
- chore: Update env.example NETWORK to encourage testnet or local usage (#659)
@@ -36,6 +43,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
3643
- Expanded docs/sdk_developers/signing.md to clarify GPG and DCO requirements and add a Table of Contents (#455).
3744
- chore: Standardized client initialization across all examples/ files to promote consistency (#658).
3845
- chore: changed the file names of airdrop examples, classes, unit and integration tests so they are grouped together. (#631)
46+
- Refactor `AbstractTokenTransferTransaction` to unify Token/NFT transfer logic.
3947

4048
### Fixed
4149
- Added explicit read permissions to examples.yml (#623)
@@ -44,13 +52,18 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
4452
- fix: Resolve `__eq__` type conflict in `CustomFee` class (#627)
4553
- Fixes a type conflict in `token_id.py` where `from_string` could receive `None`, preventing a runtime error by raising a `ValueError` if the input is missing. #630
4654
- Dependabot alerts (version bumps)
55+
- Fixed incorrect `TokenType` import (protobuf vs. SDK enum) in 18 example files.
56+
- Update `schedule_sign_transaction_e2e_test` to check for key presence instead of relying on index.
4757

4858
### Breaking Changes
4959
- chore: changed the file names airdrop classes (#631)
5060
{pending_airdrop_id.py -> token_airdrop_pending_id.py}
5161
{pending_airdrop_record.py -> token_airdrop_pending_record.py}
5262
{token_cancel_airdrop_transaction.py -> token_airdrop_transaction_cancel.py}
5363

64+
- In `TokenAirdropTransaction` the parameters of the following methods have been renamed:
65+
- add_nft_transfer(sender → sender_id, receiver → receiver_id)
66+
- add_approved_nft_transfer(sender → sender_id, receiver → receiver_id)
5467

5568
## [0.1.7] - 2025-10-28
5669

@@ -162,6 +175,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
162175
- Add strict type hints to `TransactionGetReceiptQuery` (#420)
163176
- Fixed broken documentation links in CONTRIBUTING.md by converting absolute GitHub URLs to relative paths
164177
- Updated all documentation references to use local paths instead of pointing to hiero-sdk project hub
178+
- chore: fix the examples workflow to log error messages and run on import failure (#738)
165179

166180
## [0.1.5] - 2025-09-25
167181

docs/sdk_users/running_examples.md

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ transaction = (
955955
TokenAirdropTransaction()
956956
.add_token_transfer(token_id=token_id, account_id=operator_id, amount=-1)
957957
.add_token_transfer(token_id=token_id, account_id=recipient_id, amount=1)
958-
.add_nft_transfer(nft_id=nft_id, serial_number=serial_number, sender=operator_id, receiver=recipient_id)
958+
.add_nft_transfer(nft_id=nft_id, serial_number=serial_number, sender_id=operator_id, receiver_id=recipient_id)
959959
.freeze_with(client)
960960
.sign(operator_key)
961961
)
@@ -1034,22 +1034,61 @@ print(nft_info)
10341034
### Querying Fungible Token Info
10351035

10361036
#### Pythonic Syntax:
1037-
```
1037+
```python
10381038
info_query = TokenInfoQuery(token_id=token_id)
10391039
info = info_query.execute(client)
10401040
print(info)
10411041
```
1042+
10421043
#### Method Chaining:
1043-
```
1044+
```python
10441045
info_query = (
1045-
TokenInfoQuery()
1046-
.set_token_id(token_id)
1047-
)
1046+
TokenInfoQuery()
1047+
.set_token_id(token_id)
1048+
)
10481049

10491050
info = info_query.execute(client)
10501051
print(info)
10511052
```
10521053

1054+
### Updating a Token Fee Schedule
1055+
1056+
#### Pythonic Syntax:
1057+
1058+
```python
1059+
# Note: Royalty fees are only for NON_FUNGIBLE_UNIQUE tokens.
1060+
new_fees = [
1061+
CustomFixedFee(amount=100, fee_collector_account_id=collector_account_id),
1062+
CustomRoyaltyFee(numerator=5, denominator=10, fee_collector_account_id=collector_account_id)
1063+
]
1064+
1065+
transaction = TokenFeeScheduleUpdateTransaction(
1066+
token_id=token_id, # assumed NFT in this example
1067+
custom_fees=new_fees
1068+
).freeze_with(client)
1069+
1070+
transaction.sign(fee_schedule_key) # The fee_schedule_key MUST sign
1071+
transaction.execute(client)
1072+
```
1073+
1074+
#### Method Chaining:
1075+
1076+
```python
1077+
# Note: Fractional fees are only for FUNGIBLE_COMMON tokens.
1078+
new_fees = [
1079+
CustomFixedFee(amount=100, fee_collector_account_id=collector_account_id)
1080+
]
1081+
1082+
transaction = (
1083+
TokenFeeScheduleUpdateTransaction()
1084+
.set_token_id(token_id) # assumed FUNGIBLE in this example
1085+
.set_custom_fees(new_fees)
1086+
.freeze_with(client)
1087+
)
1088+
1089+
transaction.sign(fee_schedule_key) # The fee_schedule_key MUST sign
1090+
transaction.execute(client)
1091+
```
10531092
## HBAR Transactions
10541093

10551094
### Transferring HBAR

examples/account_allowance_hbar.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,18 @@
1616
from hiero_sdk_python.transaction.transfer_transaction import TransferTransaction
1717

1818
load_dotenv()
19-
19+
network_name = os.getenv('NETWORK', 'testnet').lower()
2020

2121
def setup_client():
2222
"""Initialize and set up the client with operator account"""
23-
network = Network(os.getenv('NETWORK'))
23+
network = Network(network_name)
24+
print(f"Connecting to Hedera {network_name} network!")
2425
client = Client(network)
2526

26-
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID"))
27-
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY"))
27+
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID",""))
28+
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY",""))
2829
client.set_operator(operator_id, operator_key)
30+
print(f"Client set up with operator id {client.operator_account_id}")
2931

3032
return client
3133

examples/account_allowance_nft.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,18 @@
2727

2828
load_dotenv()
2929

30+
network_name = os.getenv('NETWORK', 'testnet').lower()
3031

3132
def setup_client():
3233
"""Initialize and set up the client with operator account"""
33-
network = Network(os.getenv('NETWORK'))
34+
network = Network(network_name)
35+
print(f"Connecting to Hedera {network_name} network!")
3436
client = Client(network)
3537

36-
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID"))
37-
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY"))
38+
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID",""))
39+
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY",""))
3840
client.set_operator(operator_id, operator_key)
41+
print(f"Client set up with operator id {client.operator_account_id}")
3942

4043
return client
4144

examples/account_create.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
)
3838

3939
load_dotenv()
40+
network_name = os.getenv('NETWORK', 'testnet').lower()
4041

4142
def setup_client() -> Tuple[Client, PrivateKey]:
4243
"""
@@ -59,11 +60,13 @@ def setup_client() -> Tuple[Client, PrivateKey]:
5960
OPERATOR_ID (str): The account ID of the operator (format: "0.0.xxxxx")
6061
OPERATOR_KEY (str): The private key of the operator account
6162
"""
62-
network = Network(os.getenv('NETWORK'))
63+
64+
network = Network(network_name)
65+
print(f"Connecting to Hedera {network_name} network!")
6366
client = Client(network)
6467

65-
operator_id = AccountId.from_string(os.getenv('OPERATOR_ID'))
66-
operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY'))
68+
operator_id = AccountId.from_string(os.getenv('OPERATOR_ID',''))
69+
operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY',''))
6770
client.set_operator(operator_id, operator_key)
6871

6972
return client, operator_key

examples/account_delete.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,21 @@
1717

1818
load_dotenv()
1919

20+
network_name = os.getenv('NETWORK', 'testnet').lower()
2021

2122
def setup_client():
2223
"""Initialize and set up the client with operator account"""
23-
network = Network(os.getenv('NETWORK'))
24+
network = Network(network_name)
25+
print(f"Connecting to Hedera {network_name} network!")
2426
client = Client(network)
2527

26-
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID"))
27-
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY"))
28+
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID", ""))
29+
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY", ""))
2830
client.set_operator(operator_id, operator_key)
31+
print(f"Client set up with operator id {client.operator_account_id}")
2932

3033
return client
3134

32-
3335
def create_account(client):
3436
"""Create a test account"""
3537
account_private_key = PrivateKey.generate_ed25519()

examples/account_update.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,18 @@
2020

2121
load_dotenv()
2222

23+
network_name = os.getenv('NETWORK', 'testnet').lower()
2324

2425
def setup_client():
2526
"""Initialize and set up the client with operator account"""
26-
network = Network(os.getenv('NETWORK'))
27+
network = Network(network_name)
28+
print(f"Connecting to Hedera {network_name} network!")
2729
client = Client(network)
2830

29-
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID"))
30-
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY"))
31+
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID", ""))
32+
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY", ""))
3133
client.set_operator(operator_id, operator_key)
34+
print(f"Client set up with operator id {client.operator_account_id}")
3235

3336
return client
3437

examples/contract_create.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,18 @@
3333

3434
load_dotenv()
3535

36+
network_name = os.getenv('NETWORK', 'testnet').lower()
3637

3738
def setup_client():
3839
"""Initialize and set up the client with operator account"""
39-
network = Network(os.getenv('NETWORK'))
40+
network = Network(network_name)
41+
print(f"Connecting to Hedera {network_name} network!")
4042
client = Client(network)
4143

42-
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID"))
43-
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY"))
44+
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID", ""))
45+
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY", ""))
4446
client.set_operator(operator_id, operator_key)
47+
print(f"Client set up with operator id {client.operator_account_id}")
4548

4649
return client
4750

examples/contract_create_constructor.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,18 @@
3737

3838
load_dotenv()
3939

40+
network_name = os.getenv('NETWORK', 'testnet').lower()
4041

4142
def setup_client():
4243
"""Initialize and set up the client with operator account"""
43-
network = Network(os.getenv('NETWORK'))
44+
network = Network(network_name)
45+
print(f"Connecting to Hedera {network_name} network!")
4446
client = Client(network)
4547

46-
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID"))
47-
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY"))
48+
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID", ""))
49+
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY", ""))
4850
client.set_operator(operator_id, operator_key)
51+
print(f"Client set up with operator id {client.operator_account_id}")
4952

5053
return client
5154

0 commit comments

Comments
 (0)