Skip to content

Commit

Permalink
Merge pull request #35 from exploreriii/TokenMintTransaction
Browse files Browse the repository at this point in the history
Token mint transaction
  • Loading branch information
nadineloepfe authored Jan 31, 2025
2 parents 09959b4 + c719b08 commit fb371c6
Show file tree
Hide file tree
Showing 13 changed files with 681 additions and 11 deletions.
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is a Python SDK for interacting with the Hedera Hashgraph platform. It allows developers to:

- Manage Token Transactions like Create, Associate, Dissociate, Transfer & Delete
- Manage Token Transactions like Create, Mint Fungible, Mint Non-Fungible, Associate, Dissociate, Transfer & Delete
- Manage Consensus Transactions like Topic Create, Update, Delete
- Submit Topic Messages
- Query Account Balance, Transaction Receipts, Topic Infos and Messages
Expand All @@ -19,6 +19,8 @@ This is a Python SDK for interacting with the Hedera Hashgraph platform. It allo
- [Creating an Account](#creating-an-account)
- [Querying Account Balance](#querying-account-balance)
- [Creating a Token](#creating-a-token)
- [Minting a Fungible Token](#minting-a-fungible-token)
- [Minting a Non-Fungible Token](#minting-a-non-fungible-token)
- [Associating a Token](#associating-a-token)
- [Dissociating a Token](#dissociating-a-token)
- [Transferring Tokens](#transferring-tokens)
Expand Down Expand Up @@ -112,6 +114,7 @@ Create a .env file in the root of your project with the following (replace with
OPERATOR_ID=0.0.1234xx
OPERATOR_KEY=302e020100300506032b657004220420...
ADMIN_KEY=302a300506032b65700321009308ecfdf...
SUPPLY_KEY =302a300506032b6570032100c5e4af5..."
RECIPIENT_ID=0.0.789xx
TOKEN_ID=0.0.100xx
TOPIC_ID=0.0.200xx
Expand Down Expand Up @@ -143,6 +146,7 @@ New Account Public Key: 8f444e36e8926def492adxxx...
Token creation successful. Token ID: 0.0.5025xxx
Token association successful.
Token dissociation successful.
Token minting successful.
Token transfer successful.
Token deletion successful.
Topic creation successful.
Expand Down Expand Up @@ -215,6 +219,7 @@ transaction = TokenCreateTransaction(
initial_supply=1000,
treasury_account_id=operator_id,
admin_key=admin_key
supply_key=supply_key
).freeze_with(client)
transaction.sign(admin_key)
Expand All @@ -232,6 +237,7 @@ transaction = (
.set_initial_supply(1000)
.set_treasury_account_id(operator_id)
.set_admin_key(admin_key) # Optional to create a token. Necessary for Token Delete or Update.
.set_supply_key(supply_key) # Optional to change token supply. Necessary for Token Mint or Burn.
.freeze_with(client)
)
Expand All @@ -240,6 +246,59 @@ transaction = (
transaction.execute(client)
```


### Minting a Fungible Token

#### Pythonic Syntax:
```
transaction = TokenMintTransaction(
token_id=token_id,
amount=amount, # lowest denomination, must be positive and not zero
).freeze_with(client)
transaction.sign(operator_key)
transaction.sign(supply_key)
transaction.execute(client)
```
#### Method Chaining:
```
transaction = (
TokenMintTransaction()
.set_token_id(token_id)
.set_amount(amount) # lowest denomination, must be positive and not zero
.freeze_with(client)
)
transaction.sign(operator_key)
transaction.sign(admin_key)
transaction.execute(client)
```

### Minting a Non-Fungible Token

#### Pythonic Syntax:
```
transaction = TokenMintTransaction(
token_id=token_id,
metadata=metadata # Bytes for non-fungible tokens (NFTs)
).freeze_with(client)
transaction.sign(operator_key)
transaction.sign(supply_key)
transaction.execute(client)
```
#### Method Chaining:
```
transaction = (
TokenMintTransaction()
.set_token_id(token_id)
.set_metadata(metadata) # Bytes for non-fungible tokens (NFTs)
.freeze_with(client)
)
transaction.sign(operator_key)
transaction.sign(admin_key)
transaction.execute(client)
```

### Associating a Token

#### Pythonic Syntax:
Expand Down
3 changes: 3 additions & 0 deletions examples/token_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ def create_token():
operator_id = AccountId.from_string(os.getenv('OPERATOR_ID'))
operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY'))
admin_key = PrivateKey.from_string(os.getenv('ADMIN_KEY'))
supply_key = PrivateKey.from_string(os.getenv('ADMIN_KEY')) #Optional


client.set_operator(operator_id, operator_key)

transaction = (
Expand All @@ -30,6 +32,7 @@ def create_token():
.set_initial_supply(10)
.set_treasury_account_id(operator_id)
.set_admin_key(admin_key)
.set_supply_key(supply_key)
.freeze_with(client)
.sign(operator_key)
.sign(admin_key)
Expand Down
59 changes: 59 additions & 0 deletions examples/token_mint_fungible.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import os
import sys
from dotenv import load_dotenv

from hedera_sdk_python import (
Client,
AccountId,
PrivateKey,
TokenMintTransaction,
Network,
TokenId,
)

load_dotenv()

def fungible_token_mint():
"""
Mint fungible tokens to increase the total supply of the token.
The new supply must be lower than 2^63-1 (within the range that can be safely stored in a signed 64-bit integer).
Loads environment variables for OPERATOR_ID, OPERATOR_KEY, SUPPLY_KEY, TOKEN_ID.
Creates and signs a TokenMintTransaction for a fungible token.
Submits the transaction and prints the result.
"""

network = Network(network='testnet')
client = Client(network)

payer_id = AccountId.from_string(os.getenv('OPERATOR_ID'))
payer_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY'))
supply_key = PrivateKey.from_string(os.getenv('SUPPLY_KEY'))
token_id = TokenId.from_string(os.getenv('TOKEN_ID'))

client.set_operator(payer_id, payer_key)

# Example: If the token has 2 decimals, "20000" here means 200.00 tokens minted.
transaction = (
TokenMintTransaction()
.set_token_id(token_id)
.set_amount(20000) # Positive, non-zero amount to mint in lowest denomination
.freeze_with(client)
.sign(payer_key)
.sign(supply_key)
)

try:
receipt = transaction.execute(client)
if receipt and receipt.tokenId:
print(f"Fungible token minting successful")
else:
print(f"Fungible token minting failed")
sys.exit(1)
except Exception as e:
print(f"Fungible token minting failed: {str(e)}")
sys.exit(1)


if __name__ == "__main__":
fungible_token_mint()
78 changes: 78 additions & 0 deletions examples/token_mint_non_fungible.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import os
import sys
import json
from dotenv import load_dotenv

from hedera_sdk_python import (
Client,
AccountId,
PrivateKey,
TokenMintTransaction,
Network,
TokenId,
)

load_dotenv()

def nft_token_mint(metadata):
"""
Minting a non-fungible token creates new NFTs for the token ID by providing metadata as a list of byte arrays.
Loads environment variables for OPERATOR_ID, OPERATOR_KEY, SUPPLY_KEY, TOKEN_ID.
Creates and signs a TokenMintTransaction for a NON_FUNGIBLE_UNIQUE token.
Submits the transaction and prints the result.
"""

network = Network(network='testnet')
client = Client(network)

payer_id = AccountId.from_string(os.getenv('OPERATOR_ID'))
payer_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY'))
supply_key = PrivateKey.from_string(os.getenv('SUPPLY_KEY'))
token_id = TokenId.from_string(os.getenv('TOKEN_ID'))

client.set_operator(payer_id, payer_key)

transaction = (
TokenMintTransaction()
.set_token_id(token_id)
.set_metadata(metadata) # Mandatory single or list of byte array metadata for NFTs each up to 100 bytes e.g. b"A"
.freeze_with(client)
.sign(payer_key)
.sign(supply_key)

)

try:
receipt = transaction.execute(client)
if receipt and receipt.tokenId:
print(f"NFT minting successful")
else:
print(f"NFT minting failed")
sys.exit(1)
except Exception as e:
print(f"NFT minting failed: {str(e)}")
sys.exit(1)


def load_metadata_from_json(file_path):
"""
Loads NFT metadata from a JSON file to use in the transaction.
:param file_path: Path to the JSON file containing metadata.
:return: List of byte arrays representing NFT metadata.
"""
try:
with open(file_path, 'r') as file:
metadata = json.load(file)
if not isinstance(metadata, list):
raise ValueError("Metadata JSON must be a list of strings.")
# Convert each metadata string to bytes
return [m.encode('utf-8') for m in metadata]
except Exception as e:
print(f"Failed to load metadata from JSON: {str(e)}")
sys.exit(1)

if __name__ == "__main__":
metadata = load_metadata_from_json("nft_metadata.json")
nft_token_mint(metadata)

2 changes: 2 additions & 0 deletions src/hedera_sdk_python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .tokens.token_associate_transaction import TokenAssociateTransaction
from .tokens.token_dissociate_transaction import TokenDissociateTransaction
from .tokens.token_delete_transaction import TokenDeleteTransaction
from .tokens.token_mint_transaction import TokenMintTransaction
from .tokens.token_id import TokenId

# Transaction
Expand Down Expand Up @@ -62,6 +63,7 @@
"TokenAssociateTransaction",
"TokenDissociateTransaction",
"TokenDeleteTransaction",
"TokenMintTransaction",
"TokenId",

# Transaction
Expand Down
2 changes: 1 addition & 1 deletion src/hedera_sdk_python/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(self, network=None):
if network is None:
network = Network()
self.network = network

self.channel = None
self.token_stub = None
self.crypto_stub = None
Expand Down
18 changes: 16 additions & 2 deletions src/hedera_sdk_python/tokens/token_create_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class TokenCreateTransaction(Transaction):
"""

def __init__(self, token_name=None, token_symbol=None, decimals=None, initial_supply=None,
treasury_account_id=None, admin_key=None):
treasury_account_id=None, admin_key=None, supply_key=None):
"""
Initializes a new TokenCreateTransaction instance with optional keyword arguments.
Expand All @@ -26,6 +26,8 @@ def __init__(self, token_name=None, token_symbol=None, decimals=None, initial_su
initial_supply (int, optional): The initial supply of the token.
treasury_account_id (AccountId, optional): The treasury account ID.
admin_key (PrivateKey, optional): The admin key for the token.
supply_key (PrivateKey, optional): The supply key for the token.
"""
super().__init__()
self.token_name = token_name
Expand All @@ -34,6 +36,7 @@ def __init__(self, token_name=None, token_symbol=None, decimals=None, initial_su
self.initial_supply = initial_supply
self.treasury_account_id = treasury_account_id
self.admin_key = admin_key
self.supply_key = supply_key

self._default_transaction_fee = 3_000_000_000

Expand Down Expand Up @@ -67,6 +70,11 @@ def set_admin_key(self, admin_key):
self.admin_key = admin_key
return self

def set_supply_key(self, supply_key):
self._require_not_frozen()
self.supply_key = supply_key
return self

def build_transaction_body(self):
"""
Builds and returns the protobuf transaction body for token creation.
Expand All @@ -91,13 +99,19 @@ def build_transaction_body(self):
admin_public_key_bytes = self.admin_key.public_key().to_bytes_raw()
admin_key_proto = basic_types_pb2.Key(ed25519=admin_public_key_bytes)

supply_key_proto = None
if self.supply_key:
supply_public_key_bytes = self.supply_key.public_key().to_bytes_raw()
supply_key_proto = basic_types_pb2.Key(ed25519=supply_public_key_bytes)

token_create_body = token_create_pb2.TokenCreateTransactionBody(
name=self.token_name,
symbol=self.token_symbol,
decimals=self.decimals,
initialSupply=self.initial_supply,
treasury=self.treasury_account_id.to_proto(),
adminKey=admin_key_proto
adminKey=admin_key_proto,
supplyKey=supply_key_proto
)

transaction_body = self.build_base_transaction_body()
Expand Down
Loading

0 comments on commit fb371c6

Please sign in to comment.