forked from hiero-ledger/hiero-sdk-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtoken_allowance.py
More file actions
219 lines (169 loc) · 7.48 KB
/
token_allowance.py
File metadata and controls
219 lines (169 loc) · 7.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
"""
Example demonstrating fungible token allowance approval and usage.
"""
import os
import sys
from dotenv import load_dotenv
from hiero_sdk_python import AccountId, Client, Hbar, Network, PrivateKey, TransactionId
from hiero_sdk_python.account.account_allowance_approve_transaction import (
AccountAllowanceApproveTransaction,
)
from hiero_sdk_python.account.account_create_transaction import AccountCreateTransaction
from hiero_sdk_python.response_code import ResponseCode
from hiero_sdk_python.tokens.supply_type import SupplyType
from hiero_sdk_python.tokens.token_associate_transaction import TokenAssociateTransaction
from hiero_sdk_python.tokens.token_create_transaction import TokenCreateTransaction
from hiero_sdk_python.tokens.token_type import TokenType
from hiero_sdk_python.transaction.transfer_transaction import TransferTransaction
load_dotenv()
def setup_client():
"""Initialize and set up the client with operator account"""
network = Network(os.getenv('NETWORK'))
client = Client(network)
operator_id = AccountId.from_string(os.getenv("OPERATOR_ID"))
operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY"))
client.set_operator(operator_id, operator_key)
return client
def create_account(client):
"""Create an account"""
account_private_key = PrivateKey.generate_ed25519()
account_public_key = account_private_key.public_key()
account_receipt = (
AccountCreateTransaction()
.set_key(account_public_key)
.set_initial_balance(Hbar(1))
.set_account_memo("Account for token allowance")
.execute(client)
)
if account_receipt.status != ResponseCode.SUCCESS:
print(f"Account creation failed with status: {ResponseCode(account_receipt.status).name}")
sys.exit(1)
account_account_id = account_receipt.account_id
return account_account_id, account_private_key
def create_fungible_token(client):
"""Create a fungible token"""
receipt = (
TokenCreateTransaction()
.set_token_name("Test Token")
.set_token_symbol("TT")
.set_token_type(TokenType.FUNGIBLE_COMMON)
.set_supply_type(SupplyType.INFINITE)
.set_decimals(2)
.set_initial_supply(1000)
.set_treasury_account_id(client.operator_account_id)
.set_admin_key(client.operator_private_key)
.set_supply_key(client.operator_private_key)
.execute(client)
)
if receipt.status != ResponseCode.SUCCESS:
print(f"Token creation failed with status: {ResponseCode(receipt.status).name}")
sys.exit(1)
token_id = receipt.token_id
print(f"Fungible token created with ID: {token_id}")
return token_id
def associate_token_with_account(client, account_id, account_private_key, token_id):
"""Associate token with account"""
receipt = (
TokenAssociateTransaction()
.set_account_id(account_id)
.add_token_id(token_id)
.freeze_with(client)
.sign(account_private_key)
.execute(client)
)
if receipt.status != ResponseCode.SUCCESS:
print(f"Token association failed with status: {ResponseCode(receipt.status).name}")
sys.exit(1)
print(f"Token {token_id} associated with account {account_id}")
def approve_token_allowance(client, token_id, owner_account_id, spender_account_id, amount):
"""Approve token allowance for spender"""
receipt = (
AccountAllowanceApproveTransaction()
.approve_token_allowance(token_id, owner_account_id, spender_account_id, amount)
.execute(client)
)
if receipt.status != ResponseCode.SUCCESS:
print(f"Token allowance approval failed with status: {ResponseCode(receipt.status).name}")
sys.exit(1)
print(f"Token allowance of {amount} approved for spender {spender_account_id}")
return receipt
def delete_token_allowance(client, token_id, owner_account_id, spender_account_id):
"""Delete token allowance by setting amount to 0"""
receipt = (
AccountAllowanceApproveTransaction()
.approve_token_allowance(token_id, owner_account_id, spender_account_id, 0)
.execute(client)
)
if receipt.status != ResponseCode.SUCCESS:
print(f"Token allowance deletion failed with status: {ResponseCode(receipt.status).name}")
sys.exit(1)
print(f"Token allowance deleted for spender {spender_account_id}")
return receipt
def transfer_token_without_allowance(
client, spender_account_id, spender_private_key, amount, receiver_account_id, token_id
):
"""Transfer tokens without allowance"""
print("Trying to transfer tokens without allowance...")
owner_account_id = client.operator_account_id
client.set_operator(spender_account_id, spender_private_key) # Set operator to spender
receipt = (
TransferTransaction()
.add_approved_token_transfer(token_id, owner_account_id, -amount)
.add_approved_token_transfer(token_id, receiver_account_id, amount)
.execute(client)
)
if receipt.status != ResponseCode.SPENDER_DOES_NOT_HAVE_ALLOWANCE:
print(
f"Token transfer should have failed with SPENDER_DOES_NOT_HAVE_ALLOWANCE "
f"status but got: {ResponseCode(receipt.status).name}"
)
print(f"Token transfer successfully failed with {ResponseCode(receipt.status).name} status")
def token_allowance():
"""
Demonstrates fungible token allowance functionality by:
1. Setting up client with operator account
2. Creating spender and receiver accounts
3. Creating a fungible token and associating it with the receiver account
4. Approving token allowance for spender
5. Transferring tokens using the allowance
6. Deleting the allowance
7. Attempting to transfer tokens without allowance (should fail)
"""
client = setup_client()
# Create spender and receiver accounts
spender_id, spender_private_key = create_account(client)
print(f"Spender account created with ID: {spender_id}")
receiver_id, receiver_private_key = create_account(client)
print(f"Receiver account created with ID: {receiver_id}")
# Create fungible token
token_id = create_fungible_token(client)
# Associate token with receiver account
associate_token_with_account(client, receiver_id, receiver_private_key, token_id)
# Approve token allowance for spender
allowance_amount = 20
approve_token_allowance(
client, token_id, client.operator_account_id, spender_id, allowance_amount
)
# Transfer tokens using the allowance
receipt = (
TransferTransaction()
.set_transaction_id(TransactionId.generate(spender_id))
.add_approved_token_transfer(token_id, client.operator_account_id, -allowance_amount)
.add_approved_token_transfer(token_id, receiver_id, allowance_amount)
.freeze_with(client)
.sign(spender_private_key)
.execute(client)
)
if receipt.status != ResponseCode.SUCCESS:
print(f"Token transfer failed with status: {ResponseCode(receipt.status).name}")
sys.exit(1)
print(f"Successfully transferred {allowance_amount} from", end=" ")
print(f"{client.operator_account_id} to {receiver_id} using allowance")
# Delete allowance
delete_token_allowance(client, token_id, client.operator_account_id, spender_id)
# Try to transfer tokens without allowance
transfer_token_without_allowance(
client, spender_id, spender_private_key, allowance_amount, receiver_id, token_id
)
if __name__ == "__main__":
token_allowance()