multiversx_chain_vm/system_sc/
system_sc_issue.rs1use num_bigint::BigUint;
2
3use crate::{
4 crypto_functions::keccak256,
5 host::context::{BlockchainUpdate, TxCache, TxInput, TxResult},
6 types::{top_decode_u64, VMTokenType},
7};
8
9#[allow(unused_variables)]
11pub fn issue(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) {
12 if tx_input.args.len() < 4 {
13 let tx_result = TxResult::from_vm_error("not enough arguments");
14 return (tx_result, BlockchainUpdate::empty());
15 }
16 let name = tx_input.args[0].clone();
17 let ticker = tx_input.args[1].clone();
18 let total_supply = BigUint::from_bytes_be(tx_input.args[2].clone().as_ref());
19 let decimals = top_decode_u64(tx_input.args[3].clone().as_ref()) as u32;
20
21 register_and_set_roles(tx_input, tx_cache, ticker, VMTokenType::Fungible)
22}
23
24#[allow(unused_variables)]
26pub fn issue_semi_fungible(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) {
27 if tx_input.args.len() < 2 {
28 let tx_result = TxResult::from_vm_error("not enough arguments");
29 return (tx_result, BlockchainUpdate::empty());
30 }
31 let name = tx_input.args[0].clone();
32 let ticker = tx_input.args[1].clone();
33
34 register_and_set_roles(tx_input, tx_cache, ticker, VMTokenType::SemiFungible)
35}
36
37#[allow(unused_variables)]
39pub fn issue_non_fungible(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) {
40 if tx_input.args.len() < 2 {
41 let tx_result = TxResult::from_vm_error("not enough arguments");
42 return (tx_result, BlockchainUpdate::empty());
43 }
44 let name = tx_input.args[0].clone();
45 let ticker = tx_input.args[1].clone();
46
47 register_and_set_roles(tx_input, tx_cache, ticker, VMTokenType::NonFungible)
48}
49
50#[allow(unused_variables)]
52pub fn register_and_set_all_roles(
53 tx_input: TxInput,
54 tx_cache: TxCache,
55) -> (TxResult, BlockchainUpdate) {
56 if tx_input.args.len() < 4 {
57 let tx_result = TxResult::from_vm_error("not enough arguments");
58 return (tx_result, BlockchainUpdate::empty());
59 }
60
61 let name = tx_input.args[0].clone();
62 let ticker = tx_input.args[1].clone();
63 let token_type = VMTokenType::from_system_sc_arg(&tx_input.args[2]);
64 let decimals = top_decode_u64(tx_input.args[3].clone().as_ref()) as u32;
65
66 register_and_set_roles(tx_input, tx_cache, ticker, token_type)
67}
68
69fn register_and_set_roles(
70 tx_input: TxInput,
71 tx_cache: TxCache,
72 ticker: Vec<u8>,
73 token_type: VMTokenType,
74) -> (TxResult, BlockchainUpdate) {
75 let mut new_token_identifiers = tx_cache.get_new_token_identifiers();
76
77 let token_identifier = if let Some((i, ti)) =
78 first_token_identifier_with_ticker(&new_token_identifiers, &ticker)
79 {
80 new_token_identifiers.remove(i);
81 ti.into_bytes()
82 } else {
83 generate_token_identifier_from_ticker(&tx_input, &tx_cache, &ticker)
84 };
85
86 tx_cache.with_account_mut(&tx_input.from, |account| {
87 account
88 .esdt
89 .register_and_set_roles(&token_identifier, token_type);
90 });
91 tx_cache.set_new_token_identifiers(new_token_identifiers);
92
93 let tx_result = TxResult {
94 result_values: vec![token_identifier],
95 ..Default::default()
96 };
97
98 (tx_result, tx_cache.into_blockchain_updates())
99}
100
101fn first_token_identifier_with_ticker(
102 token_identifiers: &[String],
103 ticker: &[u8],
104) -> Option<(usize, String)> {
105 let extract_ticker =
106 |ti: &String| -> String { ti.split('-').map(|x| x.to_string()).next().unwrap() };
107
108 token_identifiers
109 .iter()
110 .position(|x| extract_ticker(x).as_bytes() == ticker)
111 .map(|i| (i, token_identifiers[i].clone()))
112}
113
114fn generate_token_identifier_from_ticker(
115 tx_input: &TxInput,
116 tx_cache: &TxCache,
117 ticker: &[u8],
118) -> Vec<u8> {
119 let new_random_base = [
120 tx_input.from.as_bytes(),
121 tx_cache
122 .blockchain_ref()
123 .block_config
124 .current_block_info
125 .block_random_seed
126 .as_slice(),
127 ]
128 .concat();
129 let new_random = keccak256(&new_random_base);
130 let new_random_for_ticker = &new_random[..3];
131
132 let token_identifier = [
133 ticker,
134 "-".as_bytes(),
135 hex::encode(new_random_for_ticker).as_bytes(),
136 ]
137 .concat();
138
139 token_identifier
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_first_token_identifier_with_ticker_ok() {
148 let ticker = String::from("BBBB").into_bytes();
149 let new_token_indetifiers = vec![
150 "AAAA-0123".to_string(),
151 "BBBB-4567".to_string(),
152 "BBBB-0123".to_string(),
153 "CCCC-4567".to_string(),
154 ];
155
156 let ti = first_token_identifier_with_ticker(&new_token_indetifiers, &ticker);
157 let expected = b"BBBB-4567".as_slice();
158 assert_eq!(expected, ti.unwrap().1.into_bytes());
159 }
160
161 #[test]
162 fn test_first_token_identifier_with_ticker_is_none() {
163 let ticker = String::from("BBBB").into_bytes();
164 let new_token_indetifiers = vec!["AAAA-0123".to_string()];
165
166 let i = first_token_identifier_with_ticker(&new_token_indetifiers, &ticker);
167 let expected = None;
168 assert_eq!(expected, i);
169 }
170}