github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/examples/custom_fees/main.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 7 "github.com/hashgraph/hedera-sdk-go/v2" 8 ) 9 10 func main() { 11 var client *hedera.Client 12 var err error 13 14 // Retrieving network type from environment variable HEDERA_NETWORK 15 client, err = hedera.ClientForName(os.Getenv("HEDERA_NETWORK")) 16 if err != nil { 17 panic(fmt.Sprintf("%v : error creating client", err)) 18 } 19 20 // Retrieving operator ID from environment variable OPERATOR_ID 21 operatorAccountID, err := hedera.AccountIDFromString(os.Getenv("OPERATOR_ID")) 22 if err != nil { 23 panic(fmt.Sprintf("%v : error converting string to AccountID", err)) 24 } 25 26 // Retrieving operator key from environment variable OPERATOR_KEY 27 operatorKey, err := hedera.PrivateKeyFromString(os.Getenv("OPERATOR_KEY")) 28 if err != nil { 29 panic(fmt.Sprintf("%v : error converting string to PrivateKey", err)) 30 } 31 32 // Setting the client operator ID and key 33 client.SetOperator(operatorAccountID, operatorKey) 34 35 // Generate new key to be used with new account 36 aliceKey, err := hedera.GeneratePrivateKey() 37 if err != nil { 38 panic(fmt.Sprintf("%v : error generating PrivateKey", err)) 39 } 40 41 // Create three accounts, Alice, Bob, and Charlie. Alice will be the treasury for our example token. 42 // Fees only apply in transactions not involving the treasury, so we need two other accounts. 43 44 aliceAccountCreate, err := hedera.NewAccountCreateTransaction(). 45 SetInitialBalance(hedera.NewHbar(10)). 46 SetKey(aliceKey). 47 FreezeWith(client) 48 if err != nil { 49 panic(fmt.Sprintf("%v : error freezing account create for alice", err)) 50 } 51 52 aliceAccountCreate.Sign(aliceKey) 53 resp, err := aliceAccountCreate.Execute(client) 54 if err != nil { 55 panic(fmt.Sprintf("%v : error executing account create for alice", err)) 56 } 57 58 receipt, err := resp.GetReceipt(client) 59 if err != nil { 60 panic(fmt.Sprintf("%v : error getting receipt for alice account create", err)) 61 } 62 63 var aliceId hedera.AccountID 64 if receipt.AccountID != nil { 65 aliceId = *receipt.AccountID 66 } else { 67 panic("Receipt didn't return alice's ID") 68 } 69 70 bobKey, err := hedera.GeneratePrivateKey() 71 if err != nil { 72 panic(fmt.Sprintf("%v : error generating PrivateKey", err)) 73 } 74 75 bobAccountCreate, err := hedera.NewAccountCreateTransaction(). 76 SetInitialBalance(hedera.NewHbar(10)). 77 SetKey(bobKey). 78 FreezeWith(client) 79 if err != nil { 80 panic(fmt.Sprintf("%v : error freezing account create for bob", err)) 81 } 82 83 bobAccountCreate.Sign(bobKey) 84 resp, err = bobAccountCreate.Execute(client) 85 if err != nil { 86 panic(fmt.Sprintf("%v : error executing account create for bob", err)) 87 } 88 89 receipt, err = resp.GetReceipt(client) 90 if err != nil { 91 panic(fmt.Sprintf("%v : error getting receipt for bob account create", err)) 92 } 93 94 var bobId hedera.AccountID 95 if receipt.AccountID != nil { 96 bobId = *receipt.AccountID 97 } else { 98 panic("Receipt didn't return bob's ID") 99 } 100 101 charlieKey, err := hedera.GeneratePrivateKey() 102 if err != nil { 103 panic(fmt.Sprintf("%v : error generating PrivateKey", err)) 104 } 105 106 charlieAccountCreate, err := hedera.NewAccountCreateTransaction(). 107 SetInitialBalance(hedera.NewHbar(10)). 108 SetKey(charlieKey). 109 FreezeWith(client) 110 if err != nil { 111 panic(fmt.Sprintf("%v : error freezing account create for charlie", err)) 112 } 113 114 charlieAccountCreate.Sign(aliceKey) 115 resp, err = charlieAccountCreate.Execute(client) 116 if err != nil { 117 panic(fmt.Sprintf("%v : error executing account create for charlie", err)) 118 } 119 120 receipt, err = resp.GetReceipt(client) 121 if err != nil { 122 panic(fmt.Sprintf("%v : error getting receipt for charlie account create", err)) 123 } 124 125 var charlieId hedera.AccountID 126 if receipt.AccountID != nil { 127 charlieId = *receipt.AccountID 128 } else { 129 panic("Receipt didn't return charlie's ID") 130 } 131 132 println("Alice:", aliceId.String()) 133 println("Bob:", bobId.String()) 134 println("Charlie:", charlieId.String()) 135 136 // Let's start with a custom fee list of 1 fixed fee. A custom fee list can be a list of up to 137 // 10 custom fees, where each fee is a fixed fee or a fractional fee. 138 // This fixed fee will mean that every time Bob transfers any number of tokens to Charlie, 139 // Alice will collect 1 Hbar from each account involved in the transaction who is SENDING 140 // the Token (in this case, Bob). 141 142 customHbarFee := hedera.NewCustomFixedFee(). 143 SetHbarAmount(hedera.NewHbar(1)). 144 SetFeeCollectorAccountID(aliceId) 145 146 // In this example the fee is in Hbar, but you can charge a fixed fee in a token if you'd like. 147 // EG, you can make it so that each time an account transfers Foo tokens, 148 // they must pay a fee in Bar tokens to the fee collecting account. 149 // To charge a fixed fee in tokens, instead of calling setHbarAmount(), call 150 // setDenominatingTokenId(tokenForFee) and setAmount(tokenFeeAmount). 151 152 // Setting the feeScheduleKey to Alice's key will enable Alice to change the custom 153 // fees list on this token later using the TokenFeeScheduleUpdateTransaction. 154 // We will create an initial supply of 100 of these tokens. 155 156 tokenCreate, err := hedera.NewTokenCreateTransaction(). 157 // Token name and symbol are only things required to create a token 158 SetTokenName("Example Token"). 159 SetTokenSymbol("EX"). 160 // The key which can perform update/delete operations on the token. If empty, the token can be 161 // perceived as immutable (not being able to be updated/deleted) 162 SetAdminKey(aliceKey). 163 // The key which can change the supply of a token. The key is used to sign Token Mint/Burn 164 // operations 165 SetSupplyKey(aliceKey). 166 // The key which can change the token's custom fee schedule; must sign a TokenFeeScheduleUpdate 167 // transaction 168 SetFeeScheduleKey(aliceKey). 169 // The account which will act as a treasury for the token. This account 170 // will receive the specified initial supply or the newly minted NFTs 171 SetTreasuryAccountID(aliceId). 172 // The custom fees to be assessed during a CryptoTransfer that transfers units of this token 173 SetCustomFees([]hedera.Fee{*customHbarFee}). 174 // Specifies the initial supply of tokens to be put in circulation. The 175 // initial supply is sent to the Treasury Account. 176 SetInitialSupply(100). 177 FreezeWith(client) 178 if err != nil { 179 panic(fmt.Sprintf("%v : error freezing token create transaction", err)) 180 } 181 182 // Sign with alice's key before executing 183 tokenCreate.Sign(aliceKey) 184 resp, err = tokenCreate.Execute(client) 185 if err != nil { 186 panic(fmt.Sprintf("%v : error executing token create transaction", err)) 187 } 188 189 // Get receipt to make sure the transaction passed through 190 receipt, err = resp.GetReceipt(client) 191 if err != nil { 192 panic(fmt.Sprintf("%v : error getting receipt for token create transaction", err)) 193 } 194 195 // Get the token out of the receipt 196 var tokenId hedera.TokenID 197 if receipt.TokenID != nil { 198 tokenId = *receipt.TokenID 199 } else { 200 println("Token ID missing in the receipt") 201 } 202 203 println("TokenID:", tokenId.String()) 204 205 tokenInfo1, err := hedera.NewTokenInfoQuery(). 206 SetTokenID(tokenId). 207 Execute(client) 208 209 println("Custom Fees according to TokenInfoQuery:") 210 for _, i := range tokenInfo1.CustomFees { 211 switch t := i.(type) { 212 case hedera.CustomFixedFee: 213 println(t.String()) 214 } 215 } 216 217 // We must associate the token with Bob and Charlie before they can trade in it. 218 219 tokenAssociate, err := hedera.NewTokenAssociateTransaction(). 220 // Account to associate token with 221 SetAccountID(bobId). 222 // The token to associate with 223 SetTokenIDs(tokenId). 224 FreezeWith(client) 225 if err != nil { 226 panic(fmt.Sprintf("%v : error freezing token associate transaction for bob", err)) 227 } 228 229 // Signing with bob's key 230 tokenAssociate.Sign(bobKey) 231 resp, err = tokenAssociate.Execute(client) 232 if err != nil { 233 panic(fmt.Sprintf("%v : error executing token associate transaction for bob", err)) 234 } 235 236 _, err = resp.GetReceipt(client) 237 if err != nil { 238 panic(fmt.Sprintf("%v : error getting receipt for token associate transaction for bob", err)) 239 } 240 241 // Associating charlie's account with the token 242 tokenAssociate, err = hedera.NewTokenAssociateTransaction(). 243 // Account to associate token with 244 SetAccountID(charlieId). 245 // The token to associate with 246 SetTokenIDs(tokenId). 247 FreezeWith(client) 248 if err != nil { 249 panic(fmt.Sprintf("%v : error freezing token associate transaction for charlie", err)) 250 } 251 252 // Signing with charlie's key 253 tokenAssociate.Sign(charlieKey) 254 resp, err = tokenAssociate.Execute(client) 255 if err != nil { 256 panic(fmt.Sprintf("%v : error executing token associate transaction for charlie", err)) 257 } 258 259 _, err = resp.GetReceipt(client) 260 if err != nil { 261 panic(fmt.Sprintf("%v : error getting receipt for token associate transaction for charlie", err)) 262 } 263 264 // Give all 100 tokens to Bob 265 transferTransaction, err := hedera.NewTransferTransaction(). 266 // The 100 tokens being given to bob 267 AddTokenTransfer(tokenId, bobId, 100). 268 // Have to take the 100 tokens from alice by negating the 100 269 AddTokenTransfer(tokenId, aliceId, -100). 270 FreezeWith(client) 271 if err != nil { 272 panic(fmt.Sprintf("%v : error freezing token transfer transaction for alice", err)) 273 } 274 275 // Have to sign with alice's key as we are taking alice's tokens 276 transferTransaction.Sign(aliceKey) 277 resp, err = transferTransaction.Execute(client) 278 if err != nil { 279 panic(fmt.Sprintf("%v : error executing token transfer transaction for alice", err)) 280 } 281 282 // Make sure the transaction passed through 283 _, err = resp.GetReceipt(client) 284 if err != nil { 285 panic(fmt.Sprintf("%v : error getting receipt for token transfer transaction for alice", err)) 286 } 287 288 // Check alice's balance before Bob transfers 20 tokens to Charlie 289 // This is a free query 290 aliceBalance1, err := hedera.NewAccountBalanceQuery(). 291 SetAccountID(aliceId). 292 Execute(client) 293 if err != nil { 294 panic(fmt.Sprintf("%v : error getting account balance 1 for alice", err)) 295 } 296 297 println("Alice's Hbar balance before Bob transfers 20 tokens to Charlie:", aliceBalance1.Hbars.String()) 298 299 // Transfer 20 tokens from bob to charlie 300 transferTransaction, err = hedera.NewTransferTransaction(). 301 // Taking away 20 tokens from bob 302 AddTokenTransfer(tokenId, bobId, -20). 303 // Giving 20 to charlie 304 AddTokenTransfer(tokenId, charlieId, 20). 305 FreezeWith(client) 306 if err != nil { 307 panic(fmt.Sprintf("%v : error freezing token transfer transaction for bob", err)) 308 } 309 310 // As we are taking from bob, bob has to sign this. 311 transferTransaction.Sign(bobKey) 312 resp, err = transferTransaction.Execute(client) 313 if err != nil { 314 panic(fmt.Sprintf("%v : error executing token transfer transaction for bob", err)) 315 } 316 317 // Getting the record to show the assessed custom fees 318 record1, err := resp.GetRecord(client) 319 if err != nil { 320 panic(fmt.Sprintf("%v : error getting record for token transfer transaction for bob", err)) 321 } 322 323 // Query to check alice's balance 324 aliceBalance2, err := hedera.NewAccountBalanceQuery(). 325 SetAccountID(aliceId). 326 Execute(client) 327 if err != nil { 328 panic(fmt.Sprintf("%v : error getting account balance 2 for alice", err)) 329 } 330 331 println("Alice's Hbar balance after Bob transfers 20 tokens to Charlie:", aliceBalance2.Hbars.String()) 332 println("Assessed fees according to transaction record:") 333 for _, k := range record1.AssessedCustomFees { 334 println(k.String()) 335 } 336 337 // Let's use the TokenUpdateFeeScheduleTransaction with Alice's key to change the custom fees on our token. 338 // TokenUpdateFeeScheduleTransaction will replace the list of fees that apply to the token with 339 // an entirely new list. Let's charge a 10% fractional fee. This means that when Bob attempts to transfer 340 // 20 tokens to Charlie, 10% of the tokens he attempts to transfer (2 in this case) will be transferred to 341 // Alice instead. 342 343 // Fractional fees default to FeeAssessmentMethod.INCLUSIVE, which is the behavior described above. 344 // If you set the assessment method to EXCLUSIVE, then when Bob attempts to transfer 20 tokens to Charlie, 345 // Charlie will receive all 20 tokens, and Bob will be charged an _additional_ 10% fee which 346 // will be transferred to Alice. 347 348 customFractionalFee := hedera.NewCustomFractionalFee(). 349 SetNumerator(1). 350 SetDenominator(10). 351 // The minimum amount to assess 352 SetMin(1). 353 // The maximum amount to assess (zero implies no maximum) 354 SetMax(10). 355 // The account to receive the custom fee 356 SetFeeCollectorAccountID(aliceId) 357 358 tokenFeeUpdate, err := hedera.NewTokenFeeScheduleUpdateTransaction(). 359 // The token for which the custom fee will be updated 360 SetTokenID(tokenId). 361 // The updated custom fee 362 SetCustomFees([]hedera.Fee{*customFractionalFee}). 363 FreezeWith(client) 364 if err != nil { 365 panic(fmt.Sprintf("%v : error freezing token fee update", err)) 366 } 367 368 // As the token is owned by alice and all keys are set to alice's key we have to sign with that 369 tokenFeeUpdate.Sign(aliceKey) 370 resp, err = tokenFeeUpdate.Execute(client) 371 if err != nil { 372 panic(fmt.Sprintf("%v : error executing token fee update", err)) 373 } 374 375 _, err = resp.GetReceipt(client) 376 if err != nil { 377 panic(fmt.Sprintf("%v : error getting receipt for token fee update", err)) 378 } 379 380 // Get token info, we can check if the custom fee is updated 381 tokenInfo2, err := hedera.NewTokenInfoQuery(). 382 SetTokenID(tokenId). 383 Execute(client) 384 if err != nil { 385 panic(fmt.Sprintf("%v : error getting token info 2", err)) 386 } 387 388 println("Custom Fees according to TokenInfoQuery:") 389 for _, i := range tokenInfo2.CustomFees { 390 switch t := i.(type) { 391 case hedera.CustomFractionalFee: 392 println(t.String()) 393 } 394 } 395 396 // Another account balance query to check alice's token balance before Bob transfers 20 tokens to Charlie 397 aliceBalance3, err := hedera.NewAccountBalanceQuery(). 398 SetAccountID(aliceId). 399 Execute(client) 400 if err != nil { 401 panic(fmt.Sprintf("%v : error getting account balance 3 for alice", err)) 402 } 403 404 println("Alice's token balance before Bob transfers 20 tokens to Charlie:", aliceBalance3.Tokens.Get(tokenId)) 405 406 // Once again transfer 20 tokens from bob to charlie 407 transferTransaction, err = hedera.NewTransferTransaction(). 408 AddTokenTransfer(tokenId, bobId, -20). 409 AddTokenTransfer(tokenId, charlieId, 20). 410 FreezeWith(client) 411 if err != nil { 412 panic(fmt.Sprintf("%v : error freezing token transfer transaction for bob", err)) 413 } 414 415 // Bob's is losing 20 tokens again. so he has to sign this transfer 416 transferTransaction.Sign(bobKey) 417 resp, err = transferTransaction.Execute(client) 418 if err != nil { 419 panic(fmt.Sprintf("%v : error executing token transfer transaction for bob", err)) 420 } 421 422 record2, err := resp.GetRecord(client) 423 if err != nil { 424 panic(fmt.Sprintf("%v : error getting record for token transfer transaction for bob", err)) 425 } 426 427 // Checking alice's token balance again 428 aliceBalance4, err := hedera.NewAccountBalanceQuery(). 429 SetAccountID(aliceId). 430 Execute(client) 431 if err != nil { 432 panic(fmt.Sprintf("%v : error getting account balance 2 for alice", err)) 433 } 434 435 println("Alice's token balance after Bob transfers 20 tokens to Charlie:", aliceBalance4.Tokens.Get(tokenId)) 436 println("Token transfers according to transaction record:") 437 for token, transfer := range record2.TokenTransfers { 438 tokenT := "" 439 for _, t := range transfer { 440 tokenT = tokenT + " " + t.String() 441 } 442 println("for token", token.String()+":", tokenT) 443 } 444 println("Assessed fees according to transaction record:") 445 for _, k := range record2.AssessedCustomFees { 446 println(k.String()) 447 } 448 449 //Clean up 450 451 tokenDelete, _ := hedera.NewTokenDeleteTransaction(). 452 SetTokenID(tokenId). 453 FreezeWith(client) 454 455 tokenDelete.Sign(aliceKey) 456 resp, _ = tokenDelete.Execute(client) 457 _, _ = resp.GetReceipt(client) 458 459 accDelete, _ := hedera.NewAccountDeleteTransaction(). 460 SetTransactionID(hedera.TransactionIDGenerate(charlieId)). 461 SetTransferAccountID(client.GetOperatorAccountID()). 462 SetAccountID(charlieId). 463 FreezeWith(client) 464 465 accDelete.Sign(charlieKey) 466 resp, err = accDelete.Execute(client) 467 _, _ = resp.GetReceipt(client) 468 469 accDelete, _ = hedera.NewAccountDeleteTransaction(). 470 SetTransactionID(hedera.TransactionIDGenerate(bobId)). 471 SetTransferAccountID(client.GetOperatorAccountID()). 472 SetAccountID(bobId). 473 FreezeWith(client) 474 475 accDelete.Sign(bobKey) 476 resp, _ = accDelete.Execute(client) 477 _, _ = resp.GetReceipt(client) 478 479 accDelete, _ = hedera.NewAccountDeleteTransaction(). 480 SetTransactionID(hedera.TransactionIDGenerate(aliceId)). 481 SetTransferAccountID(client.GetOperatorAccountID()). 482 SetAccountID(aliceId). 483 FreezeWith(client) 484 485 accDelete.Sign(aliceKey) 486 resp, _ = accDelete.Execute(client) 487 _, _ = resp.GetReceipt(client) 488 489 _ = client.Close() 490 }