|
| 1 | +"""Example: Update Custom Fees for an NFT""" |
| 2 | +import os |
| 3 | +import sys |
| 4 | +from dotenv import load_dotenv |
| 5 | + |
| 6 | +from hiero_sdk_python import Client, AccountId, PrivateKey, Network |
| 7 | +from hiero_sdk_python.tokens.token_create_transaction import TokenCreateTransaction, TokenParams, TokenKeys |
| 8 | +from hiero_sdk_python.tokens.token_type import TokenType |
| 9 | +from hiero_sdk_python.tokens.supply_type import SupplyType |
| 10 | +from hiero_sdk_python.tokens.token_fee_schedule_update_transaction import TokenFeeScheduleUpdateTransaction |
| 11 | +from hiero_sdk_python.tokens.custom_royalty_fee import CustomRoyaltyFee |
| 12 | +from hiero_sdk_python.response_code import ResponseCode |
| 13 | +from hiero_sdk_python.query.token_info_query import TokenInfoQuery |
| 14 | + |
| 15 | + |
| 16 | +def setup_client(): |
| 17 | + """Initialize client and operator credentials from .env.""" |
| 18 | + load_dotenv() |
| 19 | + try: |
| 20 | + client = Client(Network(os.getenv("NETWORK", "testnet"))) |
| 21 | + operator_id = AccountId.from_string(os.getenv("OPERATOR_ID")) |
| 22 | + operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY")) |
| 23 | + client.set_operator(operator_id, operator_key) |
| 24 | + print(f" Operator set: {operator_id}\n") |
| 25 | + return client, operator_id, operator_key |
| 26 | + except Exception as e: |
| 27 | + print(f" Error setting up client: {e}") |
| 28 | + sys.exit(1) |
| 29 | + |
| 30 | + |
| 31 | +def create_nft(client, operator_id, supply_key, fee_schedule_key): |
| 32 | + """Create an NFT with supply and fee schedule keys.""" |
| 33 | + print(" Creating NFT...") |
| 34 | + token_params = TokenParams( |
| 35 | + token_name="NFT Fee Example", |
| 36 | + token_symbol="NFE", |
| 37 | + treasury_account_id=operator_id, |
| 38 | + initial_supply=0, |
| 39 | + decimals=0, |
| 40 | + token_type=TokenType.NON_FUNGIBLE_UNIQUE, |
| 41 | + supply_type=SupplyType.FINITE, |
| 42 | + max_supply=1000, |
| 43 | + custom_fees=[], |
| 44 | + ) |
| 45 | + |
| 46 | + # A supply_key is REQUIRED for NFTs (to mint) |
| 47 | + # A fee_schedule_key is required to update fees |
| 48 | + keys = TokenKeys( |
| 49 | + supply_key=supply_key, |
| 50 | + fee_schedule_key=fee_schedule_key |
| 51 | + ) |
| 52 | + |
| 53 | + tx = TokenCreateTransaction(token_params=token_params, keys=keys) |
| 54 | + # tx.set_fee_schedule_key(fee_schedule_key) |
| 55 | + |
| 56 | + # Sign with the supply key as well |
| 57 | + tx.freeze_with(client).sign(supply_key) |
| 58 | + receipt = tx.execute(client) |
| 59 | + |
| 60 | + if receipt.status != ResponseCode.SUCCESS: |
| 61 | + print(f" Token creation failed: {ResponseCode(receipt.status).name}\n") |
| 62 | + client.close() |
| 63 | + sys.exit(1) |
| 64 | + |
| 65 | + token_id = receipt.token_id |
| 66 | + print(f" Token created successfully: {token_id}\n") |
| 67 | + return token_id |
| 68 | + |
| 69 | + |
| 70 | +def update_custom_royalty_fee(client, token_id, fee_schedule_key, collector_account_id): |
| 71 | + """Updates the token's fee schedule with a new royalty fee.""" |
| 72 | + print(f" Updating custom royalty fee for token {token_id}...") |
| 73 | + new_fees = [ |
| 74 | + CustomRoyaltyFee( |
| 75 | + numerator=5, |
| 76 | + denominator=100, # 5% royalty |
| 77 | + fee_collector_account_id=collector_account_id |
| 78 | + ) |
| 79 | + ] |
| 80 | + print(f" Defined {len(new_fees)} new custom fees.\n") |
| 81 | + tx = ( |
| 82 | + TokenFeeScheduleUpdateTransaction() |
| 83 | + .set_token_id(token_id) |
| 84 | + .set_custom_fees(new_fees) |
| 85 | + ) |
| 86 | + |
| 87 | + tx.freeze_with(client).sign(fee_schedule_key) |
| 88 | + |
| 89 | + try: |
| 90 | + receipt = tx.execute(client) |
| 91 | + if receipt.status != ResponseCode.SUCCESS: |
| 92 | + print(f" Fee schedule update failed: {ResponseCode(receipt.status).name}\n") |
| 93 | + sys.exit(1) |
| 94 | + else: |
| 95 | + print(" Fee schedule updated successfully.\n") |
| 96 | + except Exception as e: |
| 97 | + print(f" Error during fee schedule update execution: {e}\n") |
| 98 | + sys.exit(1) |
| 99 | + |
| 100 | + |
| 101 | +def query_token_info(client, token_id): |
| 102 | + """Query token info and verify updated custom fees.""" |
| 103 | + print(f"\nQuerying token info for {token_id}...\n") |
| 104 | + try: |
| 105 | + token_info = TokenInfoQuery(token_id=token_id).execute(client) |
| 106 | + print("Token Info Retrieved Successfully!\n") |
| 107 | + |
| 108 | + print(f"Name: {getattr(token_info, 'name', 'N/A')}") |
| 109 | + print(f"Symbol: {getattr(token_info, 'symbol', 'N/A')}") |
| 110 | + print(f"Total Supply: {getattr(token_info, 'total_supply', 'N/A')}") |
| 111 | + print(f"Treasury: {getattr(token_info, 'treasury_account_id', 'N/A')}") |
| 112 | + print(f"Decimals: {getattr(token_info, 'decimals', 'N/A')}") |
| 113 | + print(f"Max Supply: {getattr(token_info, 'max_supply', 'N/A')}") |
| 114 | + print() |
| 115 | + |
| 116 | + custom_fees = getattr(token_info, "custom_fees", []) |
| 117 | + if custom_fees: |
| 118 | + print(f"Found {len(custom_fees)} custom fee(s):") |
| 119 | + for i, fee in enumerate(custom_fees, 1): |
| 120 | + print(f" Fee #{i}: {type(fee).__name__}") |
| 121 | + print(f" Collector: {getattr(fee, 'fee_collector_account_id', 'N/A')}") |
| 122 | + if isinstance(fee, CustomRoyaltyFee): |
| 123 | + print(f" Royalty: {fee.numerator}/{fee.denominator}") |
| 124 | + else: |
| 125 | + print(f" Amount: {getattr(fee, 'amount', 'N/A')}") |
| 126 | + else: |
| 127 | + print("No custom fees defined for this token.\n") |
| 128 | + |
| 129 | + except Exception as e: |
| 130 | + print(f"Error querying token info: {e}") |
| 131 | + sys.exit(1) |
| 132 | + |
| 133 | +def main(): |
| 134 | + client, operator_id, operator_key = setup_client() |
| 135 | + token_id = None |
| 136 | + try: |
| 137 | + # Use operator key as both supply and fee key |
| 138 | + supply_key = operator_key |
| 139 | + fee_key = operator_key |
| 140 | + |
| 141 | + token_id = create_nft(client, operator_id, supply_key, fee_key) |
| 142 | + |
| 143 | + if token_id: |
| 144 | + query_token_info(client, token_id) |
| 145 | + update_custom_royalty_fee(client, token_id, fee_key, operator_id) |
| 146 | + query_token_info(client, token_id) |
| 147 | + |
| 148 | + except Exception as e: |
| 149 | + print(f" Error during token operations: {e}") |
| 150 | + finally: |
| 151 | + client.close() |
| 152 | + print("\n Client closed. Example complete.") |
| 153 | + |
| 154 | + |
| 155 | +if __name__ == "__main__": |
| 156 | + main() |
| 157 | + |
0 commit comments