drt_sc_modules/
dcdt.rs

1drt_sc::imports!();
2
3/// Standard smart contract module for managing a single DCDT.
4///
5/// When added to a smart contract offers basic DCDT usage.
6/// A lot of contracts use an owned DCDT for various purposes.
7/// This module is used to offer a standard way of performing the basic operations.  
8///
9/// It provides endpoints for:
10/// * issuing of an DCDT
11/// * setting local roles
12/// * minting/burning
13///
14#[drt_sc::module]
15pub trait DcdtModule {
16    /*
17        DcdtTokenType is an enum (u8):
18        0 - Fungible,
19        1 - NonFungible,
20        2 - SemiFungible,
21        3 - Meta,
22
23        Note: Only Fungible and Meta tokens have decimals
24    */
25    #[payable("REWA")]
26    #[only_owner]
27    #[endpoint(issueToken)]
28    fn issue_token(
29        &self,
30        token_display_name: ManagedBuffer,
31        token_ticker: ManagedBuffer,
32        token_type: DcdtTokenType,
33        opt_num_decimals: OptionalValue<usize>,
34    ) {
35        require!(self.token_id().is_empty(), "Token already issued");
36
37        let issue_cost = self.call_value().rewa_value().clone_value();
38        let num_decimals = match opt_num_decimals {
39            OptionalValue::Some(d) => d,
40            OptionalValue::None => 0,
41        };
42
43        self.send()
44            .dcdt_system_sc_proxy()
45            .issue_and_set_all_roles(
46                issue_cost,
47                token_display_name,
48                token_ticker,
49                token_type,
50                num_decimals,
51            )
52            .with_callback(self.callbacks().issue_callback())
53            .async_call_and_exit()
54    }
55
56    #[callback]
57    fn issue_callback(&self, #[call_result] result: ManagedAsyncCallResult<TokenIdentifier>) {
58        match result {
59            ManagedAsyncCallResult::Ok(token_id) => {
60                self.token_id().set(&token_id);
61            },
62            ManagedAsyncCallResult::Err(_) => {
63                // return payment to initial caller
64                let initial_caller = self.blockchain().get_owner_address();
65                let rewa_returned = self.call_value().rewa_value();
66                self.tx()
67                    .to(&initial_caller)
68                    .rewa(rewa_returned)
69                    .transfer_if_not_empty();
70            },
71        }
72    }
73
74    fn mint(&self, token_nonce: u64, amount: &BigUint) {
75        let token_id = self.token_id().get();
76        self.send().dcdt_local_mint(&token_id, token_nonce, amount);
77    }
78
79    fn burn(&self, token_nonce: u64, amount: &BigUint) {
80        let token_id = self.token_id().get();
81        self.send().dcdt_local_burn(&token_id, token_nonce, amount);
82    }
83
84    fn nft_create<T: TopEncode>(&self, amount: &BigUint, attributes: &T) -> u64 {
85        let token_id = self.token_id().get();
86        let empty_buffer = ManagedBuffer::new();
87        let empty_vec = ManagedVec::from_handle(empty_buffer.get_handle());
88
89        self.send().dcdt_nft_create(
90            &token_id,
91            amount,
92            &empty_buffer,
93            &BigUint::zero(),
94            &empty_buffer,
95            &attributes,
96            &empty_vec,
97        )
98    }
99
100    fn get_token_attributes<T: TopDecode>(&self, token_nonce: u64) -> T {
101        let own_sc_address = self.blockchain().get_sc_address();
102        let token_id = self.token_id().get();
103        let token_data =
104            self.blockchain()
105                .get_dcdt_token_data(&own_sc_address, &token_id, token_nonce);
106
107        token_data.decode_attributes()
108    }
109
110    fn require_token_issued(&self) {
111        require!(!self.token_id().is_empty(), "Token must be issued first");
112    }
113
114    // Note: to issue another token, you have to clear this storage
115    #[storage_mapper("token_id")]
116    fn token_id(&self) -> SingleValueMapper<TokenIdentifier>;
117}