numbat_wasm_module_dcdt/
lib.rs

1#![no_std]
2
3numbat_wasm::imports!();
4
5/// Standard module for managing a single DCDT.
6#[numbat_wasm::module]
7pub trait DcdtModule {
8    #[storage_mapper("token_id")]
9    fn token_id(&self) -> SingleValueMapper<TokenIdentifier>;
10
11    #[payable("REWA")]
12    #[endpoint(issueToken)]
13    fn issue_token(
14        &self,
15        token_display_name: ManagedBuffer,
16        token_ticker: ManagedBuffer,
17        num_decimals: usize,
18        #[payment] issue_cost: BigUint,
19    ) -> SCResult<AsyncCall> {
20        only_owner!(self, "only owner can issue token");
21        require!(self.token_id().is_empty(), "Token already issued");
22
23        let initial_supply = self.types().big_uint_from(1u32);
24
25        Ok(self
26            .send()
27            .dcdt_system_sc_proxy()
28            .issue_fungible(
29                issue_cost,
30                &token_display_name,
31                &token_ticker,
32                &initial_supply,
33                FungibleTokenProperties {
34                    can_burn: false,
35                    can_mint: false,
36                    num_decimals,
37                    can_freeze: true,
38                    can_wipe: true,
39                    can_pause: true,
40                    can_change_owner: false,
41                    can_upgrade: false,
42                    can_add_special_roles: true,
43                },
44            )
45            .async_call()
46            .with_callback(self.callbacks().issue_callback()))
47    }
48
49    /// optional address to set roles for. Defaults to SC's address.
50    #[endpoint(setLocalRoles)]
51    fn set_local_roles(
52        &self,
53        #[var_args] opt_dest_address: OptionalArg<ManagedAddress>,
54    ) -> SCResult<AsyncCall> {
55        only_owner!(self, "only owner can set roles");
56
57        let dest_address = match opt_dest_address {
58            OptionalArg::Some(addr) => addr,
59            OptionalArg::None => self.blockchain().get_sc_address(),
60        };
61        let token_id = self.token_id().get();
62        let roles = [DcdtLocalRole::Mint, DcdtLocalRole::Burn];
63
64        Ok(self
65            .send()
66            .dcdt_system_sc_proxy()
67            .set_special_roles(&dest_address, &token_id, (&roles[..]).into_iter().cloned())
68            .async_call())
69    }
70
71    #[callback]
72    fn issue_callback(&self, #[call_result] result: ManagedAsyncCallResult<TokenIdentifier>) {
73        match result {
74            ManagedAsyncCallResult::Ok(token_id) => {
75                self.token_id().set(&token_id);
76            },
77            ManagedAsyncCallResult::Err(_) => {
78                // return payment to initial caller
79                let initial_caller = self.blockchain().get_owner_address();
80                let rewa_returned = self.call_value().rewa_value();
81                if rewa_returned > 0u32 {
82                    self.send()
83                        .direct_rewa(&initial_caller, &rewa_returned, &[]);
84                }
85            },
86        }
87    }
88
89    fn mint(&self, amount: &BigUint) -> SCResult<()> {
90        let token_id = self.token_id().get();
91
92        self.require_local_roles_set(&token_id)?;
93        self.send().dcdt_local_mint(&token_id, 0, amount);
94
95        Ok(())
96    }
97
98    fn burn(&self, amount: &BigUint) -> SCResult<()> {
99        let token_id = self.token_id().get();
100
101        self.require_local_roles_set(&token_id)?;
102        self.send().dcdt_local_burn(&token_id, 0, amount);
103
104        Ok(())
105    }
106
107    fn require_token_issued(&self) -> SCResult<()> {
108        require!(!self.token_id().is_empty(), "Token must be issued first");
109        Ok(())
110    }
111
112    fn require_local_roles_set(&self, token_id: &TokenIdentifier) -> SCResult<()> {
113        let roles = self.blockchain().get_dcdt_local_roles(token_id);
114        require!(
115            roles.contains(&DcdtLocalRole::Mint) && roles.contains(&DcdtLocalRole::Burn),
116            "Must set local roles first"
117        );
118        Ok(())
119    }
120}