Skip to main content

hiero_sdk/token/
token_create_transaction.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use hiero_sdk_proto::services;
4use hiero_sdk_proto::services::token_service_client::TokenServiceClient;
5use time::{
6    Duration,
7    OffsetDateTime,
8};
9use tonic::transport::Channel;
10
11use crate::ledger_id::RefLedgerId;
12use crate::protobuf::{
13    FromProtobuf,
14    ToProtobuf,
15};
16use crate::token::custom_fees::AnyCustomFee;
17use crate::token::token_supply_type::TokenSupplyType;
18use crate::token::token_type::TokenType;
19use crate::transaction::{
20    AnyTransactionData,
21    ChunkInfo,
22    ToSchedulableTransactionDataProtobuf,
23    ToTransactionDataProtobuf,
24    TransactionData,
25    TransactionExecute,
26};
27use crate::{
28    AccountId,
29    BoxGrpcFuture,
30    Error,
31    Key,
32    Transaction,
33    ValidateChecksums,
34};
35
36/// Create a new token.
37///
38/// After the token is created, the [`TokenId`](crate::TokenId) for it is in the receipt.
39///
40/// The specified treasury account receives the initial supply of tokens, as well as the tokens
41/// from a [`TokenMintTransaction`](crate::TokenMintTransaction) once executed.
42/// The balance of the treasury account is decreased when a [`TokenBurnTransaction`](crate::TokenBurnTransaction) is executed.
43///
44/// The `initial_supply` is in the lowest denomination of the token (like a tinybar, not an hbar).
45///
46/// Note that a created token is __immutable__ if the `admin_key` is omitted. No property of
47/// an immutable token can ever change, with the sole exception of its expiry. Anyone can pay to
48/// extend the expiry time of an immutable token.
49///
50/// - If [`NonFungibleUnique`][TokenType::NonFungibleUnique] is used, the `initial_supply` should
51/// explicitly be set to 0 (which is the default). If not, the transaction will
52/// resolve to `InvalidTokenInitialSupply`.
53///
54/// - If [`Infinite`][TokenSupplyType::Infinite] is used, the `max_supply` should
55/// explicitly be set to 0 (which is the default). If it is not 0,
56/// the transaction will resolve to `InvalidTokenMaxSupply`.
57///
58pub type TokenCreateTransaction = Transaction<TokenCreateTransactionData>;
59
60#[derive(Debug, Clone)]
61pub struct TokenCreateTransactionData {
62    /// The publicly visible name of the token.
63    name: String,
64
65    /// The publicly visible token symbol.
66    symbol: String,
67
68    /// The number of decimal places a fungible token is divisible by.
69    decimals: u32,
70
71    /// The initial supply of fungible tokens to to mint to the treasury account.
72    initial_supply: u64,
73
74    /// The account which will act as a treasury for the token.
75    treasury_account_id: Option<AccountId>,
76
77    /// The key which can perform update/delete operations on the token.
78    admin_key: Option<Key>,
79
80    /// The key which can grant or revoke KYC of an account for the token's transactions.
81    kyc_key: Option<Key>,
82
83    /// The key which can sign to freeze or unfreeze an account for token transactions.
84    freeze_key: Option<Key>,
85
86    /// The key which can wipe the token balance of an account.
87    wipe_key: Option<Key>,
88
89    /// The key which can change the supply of a token.
90    supply_key: Option<Key>,
91
92    /// The default freeze status (frozen or unfrozen) of Hiero accounts relative to this token. If
93    /// true, an account must be unfrozen before it can receive the token
94    freeze_default: bool,
95
96    /// The time at which the token should expire.
97    expiration_time: Option<OffsetDateTime>,
98
99    /// An account which will be automatically charged to renew the token's expiration, at
100    /// `auto_renew_period` interval.
101    auto_renew_account_id: Option<AccountId>,
102
103    /// The interval at which the auto-renew account will be charged to extend the token's expiry
104    auto_renew_period: Option<Duration>,
105
106    /// The memo associated with the token.
107    token_memo: String,
108
109    /// The token type. Defaults to FungibleCommon.
110    token_type: TokenType,
111
112    /// The token supply type. Defaults to Infinite.
113    token_supply_type: TokenSupplyType,
114
115    /// Sets the maximum number of tokens that can be in circulation.
116    max_supply: u64,
117
118    /// The key which can change the token's custom fee schedule.
119    fee_schedule_key: Option<Key>,
120
121    /// The custom fees to be assessed during a transfer.
122    custom_fees: Vec<AnyCustomFee>,
123
124    /// The key which can pause and unpause the token.
125    pause_key: Option<Key>,
126
127    /// Metadata of the created token definition.
128    metadata: Vec<u8>,
129
130    /// The key which can change the metadata of a token
131    /// (token definition, partition definition, and individual NFTs).
132    metadata_key: Option<Key>,
133}
134
135impl Default for TokenCreateTransactionData {
136    fn default() -> Self {
137        Self {
138            name: String::new(),
139            symbol: String::new(),
140            decimals: 0,
141            initial_supply: 0,
142            treasury_account_id: None,
143            admin_key: None,
144            kyc_key: None,
145            freeze_key: None,
146            wipe_key: None,
147            supply_key: None,
148            freeze_default: false,
149            expiration_time: None,
150            auto_renew_account_id: None,
151            auto_renew_period: Some(Duration::days(90)),
152            token_memo: String::new(),
153            token_type: TokenType::FungibleCommon,
154            token_supply_type: TokenSupplyType::Infinite,
155            max_supply: 0,
156            fee_schedule_key: None,
157            custom_fees: vec![],
158            pause_key: None,
159            metadata: vec![],
160            metadata_key: None,
161        }
162    }
163}
164
165impl TokenCreateTransaction {
166    /// Returns the publicly visible name of the token.
167    #[must_use]
168    pub fn get_name(&self) -> &str {
169        &self.data().name
170    }
171
172    /// Sets the publicly visible name of the token.
173    ///
174    /// Maximum 100 characters.
175    pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
176        self.data_mut().name = name.into();
177        self
178    }
179
180    /// Returns the publicly visible token symbol.
181    #[must_use]
182    pub fn get_symbol(&self) -> &str {
183        &self.data().symbol
184    }
185
186    /// Sets the publicly visible token symbol.
187    ///
188    /// Maximum 100 characters.
189    pub fn symbol(&mut self, symbol: impl Into<String>) -> &mut Self {
190        self.data_mut().symbol = symbol.into();
191        self
192    }
193
194    /// Returns the number of decimal places the token is divisble by.
195    #[must_use]
196    pub fn get_decimals(&self) -> u32 {
197        self.data().decimals
198    }
199
200    /// Sets the number of decimal places a token is divisible by.
201    pub fn decimals(&mut self, decimals: u32) -> &mut Self {
202        self.data_mut().decimals = decimals;
203        self
204    }
205
206    /// Returns the initial supply of tokens to be put into circulation.
207    #[must_use]
208    pub fn get_initial_supply(&self) -> u64 {
209        self.data().initial_supply
210    }
211
212    /// Sets the initial supply of tokens to be put in circulation.
213    pub fn initial_supply(&mut self, initial_supply: u64) -> &mut Self {
214        self.data_mut().initial_supply = initial_supply;
215        self
216    }
217
218    /// Returns the account which will act as a treasury for the token.
219    #[must_use]
220    pub fn get_treasury_account_id(&self) -> Option<AccountId> {
221        self.data().treasury_account_id
222    }
223
224    /// Sets the account which will act as a treasury for the token.
225    pub fn treasury_account_id(&mut self, treasury_account_id: AccountId) -> &mut Self {
226        self.data_mut().treasury_account_id = Some(treasury_account_id);
227        self
228    }
229
230    /// Returns the key whcih can perform update/delete operations on the token.
231    #[must_use]
232    pub fn get_admin_key(&self) -> Option<&Key> {
233        self.data().admin_key.as_ref()
234    }
235
236    /// Sets the key which can perform update/delete operations on the token.
237    pub fn admin_key(&mut self, admin_key: impl Into<Key>) -> &mut Self {
238        self.data_mut().admin_key = Some(admin_key.into());
239        self
240    }
241
242    /// Returns the key which can grant or revoke KYC of an account for the token's transactions.
243    #[must_use]
244    pub fn get_kyc_key(&self) -> Option<&Key> {
245        self.data().kyc_key.as_ref()
246    }
247
248    /// Sets the key which can grant or revoke KYC of an account for the token's transactions.
249    pub fn kyc_key(&mut self, kyc_key: impl Into<Key>) -> &mut Self {
250        self.data_mut().kyc_key = Some(kyc_key.into());
251        self
252    }
253
254    /// Returns the key which can sign to freeze or unfreeze an account for token transactions.
255    #[must_use]
256    pub fn get_freeze_key(&self) -> Option<&Key> {
257        self.data().freeze_key.as_ref()
258    }
259
260    /// Sets the key which can sign to freeze or unfreeze an account for token transactions.
261    pub fn freeze_key(&mut self, freeze_key: impl Into<Key>) -> &mut Self {
262        self.data_mut().freeze_key = Some(freeze_key.into());
263        self
264    }
265
266    /// Returns the key which can wipe the token balance of an account.
267    #[must_use]
268    pub fn get_wipe_key(&self) -> Option<&Key> {
269        self.data().wipe_key.as_ref()
270    }
271
272    /// Sets the key which can wipe the token balance of an account.
273    pub fn wipe_key(&mut self, wipe_key: impl Into<Key>) -> &mut Self {
274        self.data_mut().wipe_key = Some(wipe_key.into());
275        self
276    }
277
278    /// Returns the key which can change the supply of the token.
279    #[must_use]
280    pub fn get_supply_key(&self) -> Option<&Key> {
281        self.data().supply_key.as_ref()
282    }
283
284    /// Sets the key which can change the supply of the token.
285    pub fn supply_key(&mut self, supply_key: impl Into<Key>) -> &mut Self {
286        self.data_mut().supply_key = Some(supply_key.into());
287        self
288    }
289
290    /// Returnsthe default freeze status (frozen or unfrozen) of hedera accounts
291    /// relative to this token. If true, an account must be unfrozen before it can receive the token.
292    #[must_use]
293    pub fn get_freeze_default(&self) -> bool {
294        self.data().freeze_default
295    }
296
297    /// Sets the default freeze status (frozen or unfrozen) of hedera accounts
298    /// relative to this token. If true, an account must be unfrozen before it can receive the token.
299    pub fn freeze_default(&mut self, freeze_default: bool) -> &mut Self {
300        self.data_mut().freeze_default = freeze_default;
301        self
302    }
303
304    /// Returns the time at which the token should expire.
305    #[must_use]
306    pub fn get_expiration_time(&self) -> Option<OffsetDateTime> {
307        self.data().expiration_time
308    }
309
310    /// Sets the time at which the token should expire.
311    pub fn expiration_time(&mut self, expiration_time: OffsetDateTime) -> &mut Self {
312        let data = self.data_mut();
313        data.expiration_time = Some(expiration_time);
314        data.auto_renew_period = None;
315
316        self
317    }
318
319    /// Returns the account which will be automatically charged to renew the token's expiration.
320    #[must_use]
321    pub fn get_auto_renew_account_id(&self) -> Option<AccountId> {
322        self.data().auto_renew_account_id
323    }
324
325    /// Sets the account which will be automatically charged to renew the token's expiration.
326    pub fn auto_renew_account_id(&mut self, auto_renew_account_id: AccountId) -> &mut Self {
327        self.data_mut().auto_renew_account_id = Some(auto_renew_account_id);
328        self
329    }
330
331    /// Returns the interval at which the auto renew account will be charged to extend the token's expiry.
332    #[must_use]
333    pub fn get_auto_renew_period(&self) -> Option<Duration> {
334        self.data().auto_renew_period
335    }
336
337    /// Sets the interval at which the auto renew account will be charged to extend
338    /// the token's expiry.
339    pub fn auto_renew_period(&mut self, auto_renew_period: Duration) -> &mut Self {
340        self.data_mut().auto_renew_period = Some(auto_renew_period);
341        self
342    }
343
344    /// Returns the memo associated with the token.
345    #[must_use]
346    pub fn get_token_memo(&self) -> &str {
347        &self.data().token_memo
348    }
349
350    // note(sr): I got rid of the comment stating UTF-8, since this is a Rust string, which implies UTF-8.
351    /// Sets the memo associated with the token.
352    ///
353    /// Maximum 100 bytes.
354    pub fn token_memo(&mut self, memo: impl Into<String>) -> &mut Self {
355        self.data_mut().token_memo = memo.into();
356        self
357    }
358
359    /// Returns the token type.
360    #[must_use]
361    pub fn get_token_type(&self) -> TokenType {
362        self.data().token_type
363    }
364
365    /// Sets the token type. Defaults to `FungibleCommon`.
366    pub fn token_type(&mut self, token_type: TokenType) -> &mut Self {
367        self.data_mut().token_type = token_type;
368        self
369    }
370
371    /// Returns the token supply type.
372    #[must_use]
373    pub fn get_token_supply_type(&self) -> TokenSupplyType {
374        self.data().token_supply_type
375    }
376
377    /// Sets the token supply type. Defaults to `Infinite`.
378    pub fn token_supply_type(&mut self, token_supply_type: TokenSupplyType) -> &mut Self {
379        self.data_mut().token_supply_type = token_supply_type;
380        self
381    }
382
383    /// Returns the maximum number of tokens that can be in circulation.
384    #[must_use]
385    pub fn get_max_supply(&self) -> u64 {
386        self.data().max_supply
387    }
388
389    /// Sets the maximum number of tokens that can be in circulation.
390    pub fn max_supply(&mut self, max_supply: u64) -> &mut Self {
391        self.data_mut().max_supply = max_supply;
392        self
393    }
394
395    /// Returns the key which can change the token's custom fee schedule.
396    #[must_use]
397    pub fn get_fee_schedule_key(&self) -> Option<&Key> {
398        self.data().fee_schedule_key.as_ref()
399    }
400
401    /// Sets the key which can change the token's custom fee schedule.
402    pub fn fee_schedule_key(&mut self, fee_schedule_key: impl Into<Key>) -> &mut Self {
403        self.data_mut().fee_schedule_key = Some(fee_schedule_key.into());
404        self
405    }
406
407    /// Returns the custom fees to be assessed during a transfer.
408    #[must_use]
409    pub fn get_custom_fees(&self) -> &[AnyCustomFee] {
410        &self.data().custom_fees
411    }
412
413    /// Sets the custom fees to be assessed during a transfer.
414    pub fn custom_fees(
415        &mut self,
416        custom_fees: impl IntoIterator<Item = AnyCustomFee>,
417    ) -> &mut Self {
418        self.data_mut().custom_fees = custom_fees.into_iter().collect();
419        self
420    }
421
422    /// Returns the key which can pause and unpause the token.
423    #[must_use]
424    pub fn get_pause_key(&self) -> Option<&Key> {
425        self.data().pause_key.as_ref()
426    }
427
428    /// Sets the key which can pause and unpause the token.
429    pub fn pause_key(&mut self, pause_key: impl Into<Key>) -> &mut Self {
430        self.data_mut().pause_key = Some(pause_key.into());
431        self
432    }
433
434    /// Returns the metadata of the created token definition.
435    #[must_use]
436    pub fn get_metadata(&self) -> Vec<u8> {
437        self.data().metadata.clone()
438    }
439
440    /// Sets metadata of the created token definition.
441    pub fn metadata(&mut self, metadata: Vec<u8>) -> &mut Self {
442        self.data_mut().metadata = metadata;
443        self
444    }
445
446    /// Returns the key which can change the metadata of a token.
447    #[must_use]
448    pub fn get_metadata_key(&self) -> Option<&Key> {
449        self.data().metadata_key.as_ref()
450    }
451
452    /// Sets the key which can change the metadata of a token.
453    pub fn metadata_key(&mut self, metadata_key: impl Into<Key>) -> &mut Self {
454        self.data_mut().metadata_key = Some(metadata_key.into());
455        self
456    }
457}
458
459impl TransactionData for TokenCreateTransactionData {
460    fn default_max_transaction_fee(&self) -> crate::Hbar {
461        crate::Hbar::from_unit(40, crate::HbarUnit::Hbar)
462    }
463}
464
465impl TransactionExecute for TokenCreateTransactionData {
466    fn execute(
467        &self,
468        channel: Channel,
469        request: services::Transaction,
470    ) -> BoxGrpcFuture<'_, services::TransactionResponse> {
471        Box::pin(async { TokenServiceClient::new(channel).create_token(request).await })
472    }
473}
474
475impl ValidateChecksums for TokenCreateTransactionData {
476    fn validate_checksums(&self, ledger_id: &RefLedgerId) -> Result<(), Error> {
477        // TODO: validate custom fees.
478        self.treasury_account_id.validate_checksums(ledger_id)?;
479        self.auto_renew_account_id.validate_checksums(ledger_id)
480    }
481}
482
483impl ToTransactionDataProtobuf for TokenCreateTransactionData {
484    fn to_transaction_data_protobuf(
485        &self,
486        chunk_info: &ChunkInfo,
487    ) -> services::transaction_body::Data {
488        let _ = chunk_info.assert_single_transaction();
489
490        // Generate the protobuf data
491        let mut protobuf_data = self.to_protobuf();
492
493        // Manually assign the auto_renew_account with operator_id if none is set
494        if protobuf_data.auto_renew_account.is_none() {
495            let operator_id = chunk_info.current_transaction_id.account_id;
496            protobuf_data.auto_renew_account = Some(operator_id.to_protobuf());
497        }
498        services::transaction_body::Data::TokenCreation(protobuf_data)
499    }
500}
501
502impl ToSchedulableTransactionDataProtobuf for TokenCreateTransactionData {
503    fn to_schedulable_transaction_data_protobuf(
504        &self,
505    ) -> services::schedulable_transaction_body::Data {
506        services::schedulable_transaction_body::Data::TokenCreation(self.to_protobuf())
507    }
508}
509
510impl From<TokenCreateTransactionData> for AnyTransactionData {
511    fn from(transaction: TokenCreateTransactionData) -> Self {
512        Self::TokenCreate(transaction)
513    }
514}
515
516impl FromProtobuf<services::TokenCreateTransactionBody> for TokenCreateTransactionData {
517    fn from_protobuf(pb: services::TokenCreateTransactionBody) -> crate::Result<Self> {
518        let services::TokenCreateTransactionBody {
519            name,
520            symbol,
521            decimals,
522            initial_supply,
523            treasury,
524            admin_key,
525            kyc_key,
526            freeze_key,
527            wipe_key,
528            supply_key,
529            freeze_default,
530            expiry,
531            auto_renew_account,
532            auto_renew_period,
533            memo,
534            token_type,
535            supply_type,
536            max_supply,
537            fee_schedule_key,
538            custom_fees,
539            pause_key,
540            metadata,
541            metadata_key,
542        } = pb;
543
544        let token_type = services::TokenType::try_from(token_type).unwrap_or_default();
545        let token_supply_type =
546            services::TokenSupplyType::try_from(supply_type).unwrap_or_default();
547
548        Ok(Self {
549            name,
550            symbol,
551            decimals,
552            initial_supply,
553            treasury_account_id: Option::from_protobuf(treasury)?,
554            admin_key: Option::from_protobuf(admin_key)?,
555            kyc_key: Option::from_protobuf(kyc_key)?,
556            freeze_key: Option::from_protobuf(freeze_key)?,
557            wipe_key: Option::from_protobuf(wipe_key)?,
558            supply_key: Option::from_protobuf(supply_key)?,
559            freeze_default,
560            expiration_time: expiry.map(Into::into),
561            auto_renew_account_id: Option::from_protobuf(auto_renew_account)?,
562            auto_renew_period: auto_renew_period.map(Into::into),
563            token_memo: memo,
564            token_type: TokenType::from_protobuf(token_type)?,
565            token_supply_type: TokenSupplyType::from_protobuf(token_supply_type)?,
566            max_supply: max_supply as u64,
567            fee_schedule_key: Option::from_protobuf(fee_schedule_key)?,
568            custom_fees: Vec::from_protobuf(custom_fees)?,
569            pause_key: Option::from_protobuf(pause_key)?,
570            metadata,
571            metadata_key: Option::from_protobuf(metadata_key)?,
572        })
573    }
574}
575
576impl ToProtobuf for TokenCreateTransactionData {
577    type Protobuf = services::TokenCreateTransactionBody;
578
579    fn to_protobuf(&self) -> Self::Protobuf {
580        services::TokenCreateTransactionBody {
581            name: self.name.clone(),
582            symbol: self.symbol.clone(),
583            decimals: self.decimals,
584            initial_supply: self.initial_supply,
585            treasury: self.treasury_account_id.to_protobuf(),
586            admin_key: self.admin_key.to_protobuf(),
587            kyc_key: self.kyc_key.to_protobuf(),
588            freeze_key: self.freeze_key.to_protobuf(),
589            wipe_key: self.wipe_key.to_protobuf(),
590            supply_key: self.supply_key.to_protobuf(),
591            freeze_default: self.freeze_default,
592            expiry: self.expiration_time.map(Into::into),
593            auto_renew_account: self.auto_renew_account_id.to_protobuf(),
594            auto_renew_period: self.auto_renew_period.map(Into::into),
595            memo: self.token_memo.clone(),
596            token_type: self.token_type.to_protobuf().into(),
597            supply_type: self.token_supply_type.to_protobuf().into(),
598            max_supply: self.max_supply as i64,
599            fee_schedule_key: self.fee_schedule_key.to_protobuf(),
600            custom_fees: self.custom_fees.to_protobuf(),
601            pause_key: self.pause_key.to_protobuf(),
602            metadata: self.metadata.clone(),
603            metadata_key: self.metadata_key.to_protobuf(),
604        }
605    }
606}
607
608#[cfg(test)]
609mod tests {
610    use std::str::FromStr;
611
612    use expect_test::expect_file;
613    use hiero_sdk_proto::services;
614    use time::OffsetDateTime;
615
616    use crate::protobuf::{
617        FromProtobuf,
618        ToProtobuf,
619    };
620    use crate::token::TokenCreateTransactionData;
621    use crate::transaction::test_helpers::{
622        check_body,
623        transaction_body,
624        unused_private_key,
625        VALID_START,
626    };
627    use crate::{
628        AccountId,
629        AnyCustomFee,
630        AnyTransaction,
631        FixedFee,
632        FixedFeeData,
633        Key,
634        PublicKey,
635        TokenCreateTransaction,
636        TokenId,
637        TokenSupplyType,
638        TokenType,
639    };
640
641    const INITIAL_SUPPLY: u64 = 30;
642
643    fn key() -> PublicKey {
644        unused_private_key().public_key()
645    }
646
647    const AUTO_RENEW_ACCOUNT_ID: AccountId = AccountId::new(0, 0, 123);
648    const MAX_SUPPLY: u64 = 500;
649    const AUTO_RENEW_PERIOD: time::Duration = time::Duration::seconds(100);
650    const DECIMALS: u32 = 3;
651    const FREEZE_DEFAULT: bool = true;
652    const SYMBOL: &str = "K";
653    const EXPIRATION_TIME: OffsetDateTime = VALID_START;
654    const TREASURY_ACCOUNT_ID: AccountId = AccountId::new(0, 0, 456);
655    const NAME: &str = "Flook";
656    const TOKEN_MEMO: &str = "Flook memo";
657    const METADATA: &str = "Token Metadata";
658
659    fn custom_fees() -> impl IntoIterator<Item = AnyCustomFee> {
660        let fee = FixedFee {
661            fee: FixedFeeData {
662                amount: 3,
663                denominating_token_id: Some(TokenId::from_str("0.0.543").unwrap()),
664            },
665            fee_collector_account_id: Some(AccountId::from_str("4.3.2").unwrap()),
666            all_collectors_are_exempt: false,
667        };
668
669        std::iter::once(fee.into())
670    }
671
672    fn make_transaction() -> TokenCreateTransaction {
673        let mut tx = TokenCreateTransaction::new_for_tests();
674
675        tx.initial_supply(INITIAL_SUPPLY)
676            .fee_schedule_key(key())
677            .supply_key(key())
678            .admin_key(key())
679            .auto_renew_account_id(AUTO_RENEW_ACCOUNT_ID)
680            .auto_renew_period(AUTO_RENEW_PERIOD)
681            .decimals(3)
682            .freeze_default(FREEZE_DEFAULT)
683            .freeze_key(key())
684            .wipe_key(key())
685            .symbol(SYMBOL)
686            .kyc_key(key())
687            .pause_key(key())
688            .expiration_time(EXPIRATION_TIME)
689            .treasury_account_id(TREASURY_ACCOUNT_ID)
690            .name(NAME)
691            .token_memo(TOKEN_MEMO)
692            .custom_fees(custom_fees())
693            .metadata(METADATA.as_bytes().to_vec())
694            .metadata_key(key())
695            .freeze()
696            .unwrap();
697
698        tx
699    }
700
701    fn make_transaction_nft() -> TokenCreateTransaction {
702        let mut tx = TokenCreateTransaction::new_for_tests();
703
704        tx.fee_schedule_key(key())
705            .supply_key(key())
706            .max_supply(MAX_SUPPLY)
707            .admin_key(key())
708            .auto_renew_account_id(AUTO_RENEW_ACCOUNT_ID)
709            .auto_renew_period(AUTO_RENEW_PERIOD)
710            .token_type(TokenType::NonFungibleUnique)
711            .token_supply_type(TokenSupplyType::Finite)
712            .freeze_key(key())
713            .wipe_key(key())
714            .symbol(SYMBOL)
715            .kyc_key(key())
716            .pause_key(key())
717            .expiration_time(EXPIRATION_TIME)
718            .treasury_account_id(TREASURY_ACCOUNT_ID)
719            .name(NAME)
720            .token_memo(TOKEN_MEMO)
721            .metadata(METADATA.as_bytes().to_vec())
722            .metadata_key(key())
723            .freeze()
724            .unwrap();
725        tx
726    }
727
728    #[test]
729    fn serialize_fungible() {
730        let tx = make_transaction();
731
732        let tx = transaction_body(tx);
733
734        let tx = check_body(tx);
735
736        expect_file!["./snapshots/token_create_transaction/serialize_fungible.txt"]
737            .assert_debug_eq(&tx);
738    }
739
740    #[test]
741    fn serialize_nft() {
742        let tx = make_transaction_nft();
743
744        let tx = transaction_body(tx);
745
746        let tx = check_body(tx);
747
748        expect_file!["./snapshots/token_create_transaction/serialize_nft.txt"].assert_debug_eq(&tx);
749    }
750
751    #[test]
752    fn to_from_bytes_nft() {
753        let tx = make_transaction_nft();
754        let tx2 = AnyTransaction::from_bytes(&tx.to_bytes().unwrap()).unwrap();
755        let tx = transaction_body(tx);
756        let tx2 = transaction_body(tx2);
757        assert_eq!(tx, tx2);
758    }
759
760    #[test]
761    fn from_proto_body() {
762        let tx = services::TokenCreateTransactionBody {
763            name: NAME.to_owned(),
764            symbol: SYMBOL.to_owned(),
765            decimals: DECIMALS as _,
766            initial_supply: INITIAL_SUPPLY as _,
767            treasury: Some(TREASURY_ACCOUNT_ID.to_protobuf()),
768            admin_key: Some(key().to_protobuf()),
769            kyc_key: Some(key().to_protobuf()),
770            freeze_key: Some(key().to_protobuf()),
771            wipe_key: Some(key().to_protobuf()),
772            supply_key: Some(key().to_protobuf()),
773            freeze_default: FREEZE_DEFAULT,
774            expiry: Some(EXPIRATION_TIME.to_protobuf()),
775            auto_renew_account: Some(AUTO_RENEW_ACCOUNT_ID.to_protobuf()),
776            auto_renew_period: Some(AUTO_RENEW_PERIOD.to_protobuf()),
777            memo: TOKEN_MEMO.to_owned(),
778            token_type: services::TokenType::FungibleCommon as _,
779            supply_type: services::TokenSupplyType::Infinite as _,
780            max_supply: 0,
781            fee_schedule_key: Some(key().to_protobuf()),
782            custom_fees: custom_fees().into_iter().map(|it| it.to_protobuf()).collect(),
783            pause_key: Some(key().to_protobuf()),
784            metadata: METADATA.to_owned().into(),
785            metadata_key: Some(key().to_protobuf()),
786        };
787
788        let data = TokenCreateTransactionData::from_protobuf(tx).unwrap();
789
790        assert_eq!(data.name, NAME);
791        assert_eq!(data.symbol, SYMBOL);
792        assert_eq!(data.decimals, DECIMALS);
793        assert_eq!(data.initial_supply, INITIAL_SUPPLY);
794        assert_eq!(data.treasury_account_id, Some(TREASURY_ACCOUNT_ID));
795        assert_eq!(data.admin_key, Some(key().into()));
796        assert_eq!(data.kyc_key, Some(key().into()));
797        assert_eq!(data.freeze_key, Some(key().into()));
798        assert_eq!(data.wipe_key, Some(key().into()));
799        assert_eq!(data.supply_key, Some(key().into()));
800        assert_eq!(data.freeze_default, FREEZE_DEFAULT);
801        assert_eq!(data.expiration_time, Some(EXPIRATION_TIME));
802        assert_eq!(data.auto_renew_account_id, Some(AUTO_RENEW_ACCOUNT_ID));
803        assert_eq!(data.auto_renew_period, Some(AUTO_RENEW_PERIOD));
804        assert_eq!(data.token_memo, TOKEN_MEMO);
805        assert_eq!(data.token_type, TokenType::FungibleCommon);
806        assert_eq!(data.token_supply_type, TokenSupplyType::Infinite);
807        assert_eq!(data.max_supply, 0);
808        assert_eq!(data.fee_schedule_key, Some(key().into()));
809        assert_eq!(data.custom_fees, Vec::from_iter(custom_fees()));
810        assert_eq!(data.pause_key, Some(key().into()));
811    }
812
813    #[test]
814    fn properties() {
815        let tx = make_transaction();
816        let key = &Key::Single(key());
817
818        assert_eq!(tx.get_name(), NAME);
819        assert_eq!(tx.get_symbol(), SYMBOL);
820        assert_eq!(tx.get_token_memo(), TOKEN_MEMO);
821        assert_eq!(tx.get_decimals(), DECIMALS);
822        assert_eq!(tx.get_initial_supply(), INITIAL_SUPPLY);
823        assert_eq!(tx.get_treasury_account_id(), Some(TREASURY_ACCOUNT_ID));
824        assert_eq!(tx.get_admin_key(), Some(key));
825        assert_eq!(tx.get_kyc_key(), Some(key));
826        assert_eq!(tx.get_freeze_key(), Some(key));
827        assert_eq!(tx.get_wipe_key(), Some(key));
828        assert_eq!(tx.get_supply_key(), Some(key));
829        assert_eq!(tx.get_fee_schedule_key(), Some(key));
830        assert_eq!(tx.get_pause_key(), Some(key));
831        assert_eq!(tx.get_freeze_default(), true);
832        assert_eq!(tx.get_expiration_time(), Some(EXPIRATION_TIME));
833        assert_eq!(tx.get_auto_renew_account_id(), Some(AUTO_RENEW_ACCOUNT_ID));
834        assert_eq!(tx.get_auto_renew_period(), None);
835        assert_eq!(tx.get_token_type(), TokenType::FungibleCommon);
836        assert_eq!(tx.get_token_supply_type(), TokenSupplyType::Infinite);
837        assert_eq!(tx.get_max_supply(), 0);
838    }
839
840    #[test]
841    fn get_set_name() {
842        let mut tx = TokenCreateTransaction::new();
843        tx.name(NAME);
844
845        assert_eq!(tx.get_name(), NAME);
846    }
847    #[test]
848    #[should_panic]
849    fn get_set_name_frozen_panics() {
850        let mut tx = make_transaction();
851        tx.name(NAME);
852    }
853
854    #[test]
855    fn get_set_symbol() {
856        let mut tx = TokenCreateTransaction::new();
857        tx.symbol(SYMBOL);
858
859        assert_eq!(tx.get_symbol(), SYMBOL);
860    }
861    #[test]
862    #[should_panic]
863    fn get_set_symbol_frozen_panics() {
864        let mut tx = make_transaction();
865        tx.symbol(SYMBOL);
866    }
867
868    #[test]
869    fn get_set_decimals() {
870        let mut tx = TokenCreateTransaction::new();
871        tx.decimals(DECIMALS);
872
873        assert_eq!(tx.get_decimals(), DECIMALS);
874    }
875    #[test]
876    #[should_panic]
877    fn get_set_decimals_frozen_panics() {
878        let mut tx = make_transaction();
879        tx.decimals(DECIMALS);
880    }
881
882    #[test]
883    fn get_set_initial_supply() {
884        let mut tx = TokenCreateTransaction::new();
885        tx.initial_supply(INITIAL_SUPPLY);
886
887        assert_eq!(tx.get_initial_supply(), INITIAL_SUPPLY);
888    }
889
890    #[test]
891    #[should_panic]
892    fn get_set_initial_supply_frozen_panics() {
893        let mut tx = make_transaction();
894        tx.initial_supply(INITIAL_SUPPLY);
895    }
896
897    #[test]
898    fn get_set_treasury_account_id() {
899        let mut tx = TokenCreateTransaction::new();
900        tx.treasury_account_id(TREASURY_ACCOUNT_ID);
901
902        assert_eq!(tx.get_treasury_account_id(), Some(TREASURY_ACCOUNT_ID));
903    }
904
905    #[test]
906    #[should_panic]
907    fn get_set_treasury_account_id_frozen_panics() {
908        let mut tx = make_transaction();
909        tx.treasury_account_id(TREASURY_ACCOUNT_ID);
910    }
911
912    #[test]
913    fn get_set_admin_key() {
914        let mut tx = TokenCreateTransaction::new();
915        tx.admin_key(key());
916
917        assert_eq!(tx.get_admin_key(), Some(&key().into()));
918    }
919
920    #[test]
921    #[should_panic]
922    fn get_set_admin_key_frozen_panics() {
923        let mut tx = make_transaction();
924        tx.admin_key(key());
925    }
926
927    #[test]
928    fn get_set_kyc_key() {
929        let mut tx = TokenCreateTransaction::new();
930        tx.kyc_key(key());
931
932        assert_eq!(tx.get_kyc_key(), Some(&key().into()));
933    }
934
935    #[test]
936    #[should_panic]
937    fn get_set_kyc_key_frozen_panics() {
938        let mut tx = make_transaction();
939        tx.kyc_key(key());
940    }
941
942    #[test]
943    fn get_set_freeze_key() {
944        let mut tx = TokenCreateTransaction::new();
945        tx.freeze_key(key());
946
947        assert_eq!(tx.get_freeze_key(), Some(&key().into()));
948    }
949
950    #[test]
951    #[should_panic]
952    fn get_set_freeze_key_frozen_panics() {
953        let mut tx = make_transaction();
954        tx.freeze_key(key());
955    }
956
957    #[test]
958    fn get_set_wipe_key() {
959        let mut tx = TokenCreateTransaction::new();
960        tx.wipe_key(key());
961
962        assert_eq!(tx.get_wipe_key(), Some(&key().into()));
963    }
964
965    #[test]
966    #[should_panic]
967    fn get_set_wipe_key_frozen_panics() {
968        let mut tx = make_transaction();
969        tx.wipe_key(key());
970    }
971
972    #[test]
973    fn get_set_supply_key() {
974        let mut tx = TokenCreateTransaction::new();
975        tx.supply_key(key());
976
977        assert_eq!(tx.get_supply_key(), Some(&key().into()));
978    }
979
980    #[test]
981    #[should_panic]
982    fn get_set_supply_key_frozen_panics() {
983        let mut tx = make_transaction();
984        tx.supply_key(key());
985    }
986
987    #[test]
988    fn get_set_freeze_default() {
989        let mut tx = TokenCreateTransaction::new();
990        tx.freeze_default(FREEZE_DEFAULT);
991
992        assert_eq!(tx.get_freeze_default(), FREEZE_DEFAULT);
993    }
994
995    #[test]
996    #[should_panic]
997    fn get_set_freeze_default_frozen_panics() {
998        let mut tx = make_transaction();
999        tx.freeze_default(FREEZE_DEFAULT);
1000    }
1001
1002    #[test]
1003    fn get_set_expiration_time() {
1004        let mut tx = TokenCreateTransaction::new();
1005        tx.expiration_time(EXPIRATION_TIME);
1006
1007        assert_eq!(tx.get_expiration_time(), Some(EXPIRATION_TIME));
1008    }
1009
1010    #[test]
1011    #[should_panic]
1012    fn get_set_expiration_time_frozen_panics() {
1013        let mut tx = make_transaction();
1014        tx.expiration_time(EXPIRATION_TIME);
1015    }
1016
1017    #[test]
1018    fn get_set_auto_renew_account_id() {
1019        let mut tx = TokenCreateTransaction::new();
1020        tx.auto_renew_account_id(AUTO_RENEW_ACCOUNT_ID);
1021
1022        assert_eq!(tx.get_auto_renew_account_id(), Some(AUTO_RENEW_ACCOUNT_ID));
1023    }
1024
1025    #[test]
1026    #[should_panic]
1027    fn get_set_auto_renew_account_id_frozen_panics() {
1028        let mut tx = make_transaction();
1029        tx.auto_renew_account_id(AUTO_RENEW_ACCOUNT_ID);
1030    }
1031
1032    #[test]
1033    fn get_set_auto_renew_period() {
1034        let mut tx = TokenCreateTransaction::new();
1035        tx.auto_renew_period(AUTO_RENEW_PERIOD);
1036
1037        assert_eq!(tx.get_auto_renew_period(), Some(AUTO_RENEW_PERIOD));
1038    }
1039
1040    #[test]
1041    #[should_panic]
1042    fn get_set_auto_renew_period_frozen_panics() {
1043        let mut tx = make_transaction();
1044        tx.auto_renew_period(AUTO_RENEW_PERIOD);
1045    }
1046
1047    #[test]
1048    fn get_set_token_memo() {
1049        let mut tx = TokenCreateTransaction::new();
1050        tx.token_memo(TOKEN_MEMO);
1051
1052        assert_eq!(tx.get_token_memo(), TOKEN_MEMO);
1053    }
1054
1055    #[test]
1056    #[should_panic]
1057    fn get_set_token_memo_frozen_panics() {
1058        let mut tx = make_transaction();
1059        tx.token_memo(TOKEN_MEMO);
1060    }
1061
1062    #[test]
1063    fn get_set_token_type() {
1064        let mut tx = TokenCreateTransaction::new();
1065        tx.token_type(TokenType::NonFungibleUnique);
1066
1067        assert_eq!(tx.get_token_type(), TokenType::NonFungibleUnique);
1068    }
1069    #[test]
1070    #[should_panic]
1071    fn get_set_token_type_frozen_panics() {
1072        let mut tx = make_transaction();
1073        tx.token_type(TokenType::NonFungibleUnique);
1074    }
1075
1076    #[test]
1077    fn get_set_token_supply_type() {
1078        let mut tx = TokenCreateTransaction::new();
1079        tx.token_supply_type(TokenSupplyType::Finite);
1080
1081        assert_eq!(tx.get_token_supply_type(), TokenSupplyType::Finite);
1082    }
1083
1084    #[test]
1085    #[should_panic]
1086    fn get_set_token_supply_type_frozen_panics() {
1087        let mut tx = make_transaction();
1088        tx.token_supply_type(TokenSupplyType::Finite);
1089    }
1090
1091    #[test]
1092    fn get_set_max_supply() {
1093        let mut tx = TokenCreateTransaction::new();
1094        tx.max_supply(MAX_SUPPLY);
1095
1096        assert_eq!(tx.get_max_supply(), MAX_SUPPLY);
1097    }
1098
1099    #[test]
1100    #[should_panic]
1101    fn get_set_max_supply_frozen_panics() {
1102        let mut tx = make_transaction();
1103        tx.max_supply(MAX_SUPPLY);
1104    }
1105
1106    #[test]
1107    fn get_set_fee_schedule_key() {
1108        let mut tx = TokenCreateTransaction::new();
1109        tx.fee_schedule_key(key());
1110
1111        assert_eq!(tx.get_fee_schedule_key(), Some(&key().into()));
1112    }
1113
1114    #[test]
1115    #[should_panic]
1116    fn get_set_fee_schedule_key_frozen_panics() {
1117        let mut tx = make_transaction();
1118        tx.fee_schedule_key(key());
1119    }
1120
1121    #[test]
1122    fn get_set_custom_fees() {
1123        let mut tx = TokenCreateTransaction::new();
1124        tx.custom_fees(custom_fees());
1125
1126        assert_eq!(tx.get_custom_fees(), Vec::from_iter(custom_fees()));
1127    }
1128
1129    #[test]
1130    #[should_panic]
1131    fn get_set_custom_fees_frozen_panics() {
1132        let mut tx = make_transaction();
1133        tx.custom_fees(custom_fees());
1134    }
1135
1136    #[test]
1137    fn get_set_pause_key() {
1138        let mut tx = TokenCreateTransaction::new();
1139        tx.pause_key(key());
1140
1141        assert_eq!(tx.get_pause_key(), Some(&key().into()));
1142    }
1143
1144    #[test]
1145    #[should_panic]
1146    fn get_set_pause_key_frozen_panics() {
1147        let mut tx = make_transaction();
1148        tx.pause_key(key());
1149    }
1150
1151    #[test]
1152    fn get_set_metadata() {
1153        let mut tx = TokenCreateTransaction::new();
1154        tx.metadata(METADATA.as_bytes().to_vec());
1155        assert_eq!(tx.get_metadata(), METADATA.as_bytes().to_vec());
1156    }
1157
1158    #[test]
1159    #[should_panic]
1160    fn get_set_metadata_frozen_panic() {
1161        let mut tx = make_transaction();
1162        tx.metadata(METADATA.as_bytes().to_vec());
1163    }
1164
1165    #[test]
1166    fn get_set_metadata_key() {
1167        let mut tx = TokenCreateTransaction::new();
1168        tx.metadata_key(key());
1169        assert_eq!(tx.get_metadata_key(), Some(&key().into()));
1170    }
1171
1172    #[test]
1173    #[should_panic]
1174    fn get_set_metadata_key_frozen_panic() {
1175        let mut tx = make_transaction();
1176        tx.metadata_key(key());
1177    }
1178}