Skip to content

Commit

Permalink
TokenAirdrop, TokenClaimAirdrop, and TokenCancelAirdrop
Browse files Browse the repository at this point in the history
  • Loading branch information
RickyLB authored Sep 17, 2024
1 parent 55abf78 commit d7f1667
Show file tree
Hide file tree
Showing 24 changed files with 4,100 additions and 14 deletions.
218 changes: 218 additions & 0 deletions examples/token_airdrop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* ‌
* Hedera Rust SDK
* ​
* Copyright (C) 2022 - 2023 Hedera Hashgraph, LLC
* ​
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ‍
*/

use std::iter::repeat;

use clap::Parser;
use hedera::{
AccountBalanceQuery, AccountCreateTransaction, AccountId, Client, Hbar, PrivateKey, TokenAirdropTransaction, TokenAssociateTransaction, TokenCreateTransaction, TokenDeleteTransaction, TokenGrantKycTransaction, TokenMintTransaction, TokenWipeTransaction, TransferTransaction
};
use time::{Duration, OffsetDateTime};

#[derive(Parser, Debug)]
struct Args {
#[clap(long, env)]
operator_account_id: AccountId,

#[clap(long, env)]
operator_key: PrivateKey,

#[clap(long, env, default_value = "testnet")]
hedera_network: String,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let _ = dotenvy::dotenv();
let Args {
operator_account_id,
operator_key,
hedera_network,
} = Args::parse();

let client = Client::for_name(&hedera_network)?;

client.set_operator(operator_account_id, operator_key.clone());
let private_key_1 = PrivateKey::generate_ed25519();
let alice = AccountCreateTransaction::new()
.key(private_key_1.public_key())
.initial_balance(Hbar::new(10))
.max_automatic_token_associations(-1)
.execute(&client)
.await?
.get_receipt(&client)
.await?
.account_id
.unwrap();

let private_key_2 = PrivateKey::generate_ed25519();
let bob = AccountCreateTransaction::new()
.key(private_key_2.public_key())
.max_automatic_token_associations(1)
.execute(&client)
.await?
.get_receipt(&client)
.await?
.account_id
.unwrap();

let private_key_3 = PrivateKey::generate_ed25519();
let carol = AccountCreateTransaction::new()
.key(private_key_3.public_key())
.max_automatic_token_associations(0)
.execute(&client)
.await?
.get_receipt(&client)
.await?
.account_id
.unwrap();

let treasury_key = PrivateKey::generate_ed25519();
let treasury_account_id = AccountCreateTransaction::new()
.key(treasury_key.public_key())
.initial_balance(Hbar::new(10))
.execute(&client)
.await?
.get_receipt(&client)
.await?
.account_id
.unwrap();

/*
* Step 2:
* Create FT and NFT and mint
*/
let token_id = TokenCreateTransaction::new()
.name("ffff")
.symbol("F")
.decimals(3)
.initial_supply(100)
.max_supply(100)
.treasury_account_id(treasury_account_id)
.token_supply_type(hedera::TokenSupplyType::Finite)
.admin_key(operator_key.clone().public_key())
.freeze_key(operator_key.clone().public_key())
.supply_key(operator_key.clone().public_key())
.pause_key(operator_key.clone().public_key())
.expiration_time(OffsetDateTime::now_utc() + Duration::hours(2))
.freeze_with(&client)?
.sign(treasury_key.clone())
.execute(&client)
.await?
.get_receipt(&client)
.await?
.token_id
.unwrap();

let nft_id = TokenCreateTransaction::new()
.name("example NFT")
.symbol("F")
.decimals(3)
.max_supply(10)
.treasury_account_id(treasury_account_id)
.token_supply_type(hedera::TokenSupplyType::Finite)
.token_type(hedera::TokenType::NonFungibleUnique)
.admin_key(operator_key.clone().public_key())
.freeze_key(operator_key.clone().public_key())
.supply_key(operator_key.clone().public_key())
.pause_key(operator_key.clone().public_key())
.expiration_time(OffsetDateTime::now_utc() + Duration::hours(2))
.freeze_with(&client)?
.sign(treasury_key)
.execute(&client)
.await?
.get_receipt(&client)
.await?
.token_id
.unwrap();

_ = TokenMintTransaction::new()
.token_id(nft_id)
.metadata(repeat(vec![9, 1, 6]).take(4).collect::<Vec<Vec<_>>>())
.execute(&client)
.await?
.get_receipt(&client)
.await?;

/*
* Step 3:
* Airdrop fungible tokens to all 3 accounts
*/
println!("Airdropping tokens to all accounts");

let airdrop_record = TokenAirdropTransaction::new()
.token_transfer(token_id, alice, 10)
.token_transfer(token_id, treasury_account_id, -10)
.token_transfer(token_id, bob, 10)
.token_transfer(token_id, treasury_account_id, -10)
.token_transfer(token_id, carol, 10)
.token_transfer(token_id, treasury_account_id, -10)
.execute(&client)
.await?
.get_record(&client)
.await?;

/*
* Step 4:
* Get the transaction record and see one pending airdrop (for carol)
*/
println!(
"Pending airdrop length: {}",
airdrop_record.pending_airdrop_records.len()
);
println!(
"Pending airdrops: {:?}",
airdrop_record.pending_airdrop_records.get(0)
);

/*
* Step 5:
* Query to verify alice and bob received the airdrops and carol did not
*/
let alice_balance = AccountBalanceQuery::new()
.account_id(alice)
.execute(&client)
.await?;

let bob_balance = AccountBalanceQuery::new()
.account_id(bob)
.execute(&client)
.await?;

let carol_balance = AccountBalanceQuery::new()
.account_id(carol)
.execute(&client)
.await?;

println!(
"Alice ft balance after airdrop: {}",
alice_balance.tokens.get(&token_id).unwrap()
);
println!(
"Bob ft balance after airdrop: {}",
bob_balance.tokens.get(&token_id).unwrap()
);
println!(
"Carol ft balance after airdrop: {}",
carol_balance.tokens.get(&token_id).unwrap()
);

Ok(())
}
2 changes: 1 addition & 1 deletion protobufs/protobufs
Submodule protobufs updated 62 files
+6 −6 .github/CODEOWNERS
+866 −0 block/block_service.proto
+71 −0 block/stream/block.proto
+247 −0 block/stream/block_item.proto
+212 −0 block/stream/block_proof.proto
+55 −0 block/stream/input/event_metadata.proto
+46 −0 block/stream/input/round_header.proto
+165 −0 block/stream/output/block_header.proto
+160 −0 block/stream/output/consensus_service.proto
+96 −0 block/stream/output/crypto_service.proto
+96 −0 block/stream/output/file_service.proto
+48 −0 block/stream/output/network_service.proto
+110 −0 block/stream/output/schedule_service.proto
+141 −0 block/stream/output/smart_contract_service.proto
+835 −0 block/stream/output/state_changes.proto
+163 −0 block/stream/output/token_service.proto
+153 −0 block/stream/output/transaction_output.proto
+169 −0 block/stream/output/transaction_result.proto
+67 −0 block/stream/output/util_service.proto
+104 −0 block/stream/record_file_item.proto
+537 −0 documents/api/block/block_service.md
+ documents/api/block/stream/Merkle-Hash-Diagram.png
+64 −0 documents/api/block/stream/block.md
+67 −0 documents/api/block/stream/block_header.md
+132 −0 documents/api/block/stream/block_item.md
+125 −0 documents/api/block/stream/block_proof.md
+49 −0 documents/api/block/stream/input/event_metadata.md
+48 −0 documents/api/block/stream/input/round_header.md
+68 −0 documents/api/block/stream/output/block_header.md
+126 −0 documents/api/block/stream/output/consensus_service.md
+125 −0 documents/api/block/stream/output/crypto_service.md
+129 −0 documents/api/block/stream/output/file_service.md
+57 −0 documents/api/block/stream/output/network_service.md
+105 −0 documents/api/block/stream/output/schedule_service.md
+154 −0 documents/api/block/stream/output/smart_contract_service.md
+396 −0 documents/api/block/stream/output/state_changes.md
+256 −0 documents/api/block/stream/output/token_service.md
+122 −0 documents/api/block/stream/output/transaction_output.md
+66 −0 documents/api/block/stream/output/transaction_result.md
+55 −0 documents/api/block/stream/output/util_service.md
+71 −0 documents/api/block/stream/record_file_item.md
+93 −0 documents/modified_md.tmpl
+1 −1 platform/event/event_descriptor.proto
+24 −21 platform/event/event_transaction.proto
+6 −5 platform/event/gossip_event.proto
+3 −3 platform/event/state_signature_transaction.proto
+341 −0 platform/state/platform_state.proto
+105 −1 services/basic_types.proto
+64 −0 services/response_code.proto
+18 −0 services/schedulable_transaction_body.proto
+88 −0 services/state/blockstream/block_stream_info.proto
+32 −0 services/state/recordcache/recordcache.proto
+107 −0 services/state/roster/roster.proto
+77 −0 services/state/roster/roster_state.proto
+17 −0 services/state/token/account.proto
+70 −0 services/state/token/account_pending_airdrop.proto
+100 −0 services/token_airdrop.proto
+60 −0 services/token_cancel_airdrop.proto
+64 −0 services/token_claim_airdrop.proto
+42 −0 services/token_service.proto
+18 −0 services/transaction_body.proto
+33 −0 services/transaction_record.proto
15 changes: 15 additions & 0 deletions src/fee_schedules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,15 @@ pub enum RequestType {

/// Reject tokens.
TokenReject,

/// Airdrop tokens.
TokenAirdrop,

/// Claim airdrop tokens.
TokenClaimAirdrop,

/// Cancel airdrop tokens.
TokenCancelAirdrop,
}

impl FromProtobuf<services::HederaFunctionality> for RequestType {
Expand Down Expand Up @@ -506,6 +515,9 @@ impl FromProtobuf<services::HederaFunctionality> for RequestType {
HederaFunctionality::NodeUpdate => Self::NodeUpdate,
HederaFunctionality::NodeDelete => Self::NodeDelete,
HederaFunctionality::TokenReject => Self::TokenReject,
HederaFunctionality::TokenAirdrop => Self::TokenAirdrop,
HederaFunctionality::TokenClaimAirdrop => Self::TokenClaimAirdrop,
HederaFunctionality::TokenCancelAirdrop => Self::TokenCancelAirdrop,
};

Ok(value)
Expand Down Expand Up @@ -597,6 +609,9 @@ impl ToProtobuf for RequestType {
Self::NodeUpdate => HederaFunctionality::NodeUpdate,
Self::NodeDelete => HederaFunctionality::NodeDelete,
Self::TokenReject => HederaFunctionality::TokenReject,
Self::TokenAirdrop => HederaFunctionality::TokenAirdrop,
Self::TokenClaimAirdrop => HederaFunctionality::TokenClaimAirdrop,
Self::TokenCancelAirdrop => HederaFunctionality::TokenCancelAirdrop,
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ mod network_version_info_query;
mod node_address;
mod node_address_book;
mod node_address_book_query;
mod pending_airdrop_id;
mod pending_airdrop_record;
mod ping_query;
mod prng_transaction;
mod query;
Expand Down Expand Up @@ -270,6 +272,7 @@ pub use node_address::NodeAddress;
pub use node_address_book::NodeAddressBook;
pub use node_address_book_query::NodeAddressBookQuery;
pub(crate) use node_address_book_query::NodeAddressBookQueryData;
pub use pending_airdrop_record::PendingAirdropRecord;
pub use prng_transaction::PrngTransaction;
pub(crate) use protobuf::{
FromProtobuf,
Expand Down Expand Up @@ -310,9 +313,12 @@ pub use token::{
NftId,
RoyaltyFee,
RoyaltyFeeData,
TokenAirdropTransaction,
TokenAssociateTransaction,
TokenAssociation,
TokenBurnTransaction,
TokenCancelAirdropTransaction,
TokenClaimAirdropTransaction,
TokenCreateTransaction,
TokenDeleteTransaction,
TokenDissociateTransaction,
Expand Down
Loading

0 comments on commit d7f1667

Please sign in to comment.