1use crate::{async_data::AsyncCallTxData, SendBalance, TxContext, TxOutput, TxPanic};
2use numbat_wasm::{
3 api::{BlockchainApi, SendApi, StorageReadApi, StorageWriteApi},
4 types::{
5 BigUint, BoxedBytes, CodeMetadata, DcdtTokenPayment, ManagedAddress, ManagedArgBuffer,
6 ManagedBuffer, ManagedInto, ManagedVec, TokenIdentifier,
7 },
8 HexCallDataSerializer,
9};
10use num_traits::Zero;
12
13impl TxContext {
14 fn get_available_rewa_balance(&self) -> num_bigint::BigUint {
15 let mut available_balance = self.blockchain_info_box.contract_balance.clone();
17
18 available_balance += &self.tx_input_box.call_value;
20
21 let tx_output = self.tx_output_cell.borrow();
23 for send_balance in &tx_output.send_balance_list {
24 available_balance -= &send_balance.amount;
25 }
26
27 available_balance
28 }
29
30 fn get_available_dcdt_balance(&self, token_identifier: &[u8]) -> num_bigint::BigUint {
31 let mut available_balance = self
33 .blockchain_info_box
34 .contract_dcdt
35 .get(token_identifier)
36 .unwrap_or(&num_bigint::BigUint::zero())
37 .clone();
38
39 if self.tx_input_box.dcdt_token_identifier == token_identifier {
41 available_balance += &self.tx_input_box.dcdt_value;
42 }
43 let tx_output = self.tx_output_cell.borrow();
44
45 for send_balance in &tx_output.send_balance_list {
47 if send_balance.token_identifier.as_slice() == token_identifier {
48 available_balance -= &send_balance.amount;
49 }
50 }
51
52 available_balance
53 }
54}
55
56impl SendApi for TxContext {
57 fn direct_rewa<D>(&self, to: &ManagedAddress<Self>, amount: &BigUint<Self>, _data: D)
58 where
59 D: ManagedInto<Self, ManagedBuffer<Self>>,
60 {
61 let amount_value = self.big_uint_value(amount);
62 if amount_value > self.get_available_rewa_balance() {
63 std::panic::panic_any(TxPanic {
64 status: 10,
65 message: b"failed transfer (insufficient funds)".to_vec(),
66 });
67 }
68
69 let recipient = to.to_address();
70 let mut tx_output = self.tx_output_cell.borrow_mut();
71 tx_output.send_balance_list.push(SendBalance {
72 recipient,
73 token_identifier: BoxedBytes::empty(),
74 amount: amount_value,
75 });
76 }
77
78 fn direct_rewa_execute(
79 &self,
80 _to: &ManagedAddress<Self>,
81 _amount: &BigUint<Self>,
82 _gas_limit: u64,
83 _endpoint_name: &ManagedBuffer<Self>,
84 _arg_buffer: &ManagedArgBuffer<Self>,
85 ) -> Result<(), &'static [u8]> {
86 panic!("direct_rewa_execute not yet implemented")
87 }
88
89 fn direct_dcdt_execute(
90 &self,
91 to: &ManagedAddress<Self>,
92 token: &TokenIdentifier<Self>,
93 amount: &BigUint<Self>,
94 _gas: u64,
95 _endpoint_name: &ManagedBuffer<Self>,
96 _arg_buffer: &ManagedArgBuffer<Self>,
97 ) -> Result<(), &'static [u8]> {
98 let amount_value = self.big_uint_value(amount);
99 if amount_value > self.get_available_dcdt_balance(token.to_dcdt_identifier().as_slice()) {
100 std::panic::panic_any(TxPanic {
101 status: 10,
102 message: b"insufficient funds".to_vec(),
103 });
104 }
105
106 let recipient = to.to_address();
107 let token_identifier = token.to_dcdt_identifier();
108 let mut tx_output = self.tx_output_cell.borrow_mut();
109 tx_output.send_balance_list.push(SendBalance {
110 recipient,
111 token_identifier,
112 amount: amount_value,
113 });
114 Ok(())
115 }
116
117 fn direct_dcdt_nft_execute(
118 &self,
119 _to: &ManagedAddress<Self>,
120 _token: &TokenIdentifier<Self>,
121 _nonce: u64,
122 _amount: &BigUint<Self>,
123 _gas_limit: u64,
124 _endpoint_name: &ManagedBuffer<Self>,
125 _arg_buffer: &ManagedArgBuffer<Self>,
126 ) -> Result<(), &'static [u8]> {
127 panic!("direct_dcdt_nft_execute not implemented yet");
128 }
129
130 fn direct_multi_dcdt_transfer_execute(
131 &self,
132 _to: &ManagedAddress<Self>,
133 _payments: &ManagedVec<Self, DcdtTokenPayment<Self>>,
134 _gas_limit: u64,
135 _endpoint_name: &ManagedBuffer<Self>,
136 _arg_buffer: &ManagedArgBuffer<Self>,
137 ) -> Result<(), &'static [u8]> {
138 panic!("direct_multi_dcdt_transfer_execute not implemented yet");
139 }
140
141 fn async_call_raw(
142 &self,
143 to: &ManagedAddress<Self>,
144 amount: &BigUint<Self>,
145 endpoint_name: &ManagedBuffer<Self>,
146 arg_buffer: &ManagedArgBuffer<Self>,
147 ) -> ! {
148 let amount_value = self.big_uint_value(amount);
149 let recipient = to.to_address();
150 let call_data =
151 HexCallDataSerializer::from_managed_arg_buffer(endpoint_name, arg_buffer).into_vec();
152 let tx_hash = self.get_tx_hash_legacy();
153 let mut tx_output = self.tx_output_cell.replace(TxOutput::default());
155 tx_output.async_call = Some(AsyncCallTxData {
156 to: recipient,
157 call_value: amount_value,
158 call_data,
159 tx_hash,
160 });
161 std::panic::panic_any(tx_output)
162 }
163
164 fn deploy_contract(
165 &self,
166 _gas: u64,
167 _amount: &BigUint<Self>,
168 _code: &ManagedBuffer<Self>,
169 _code_metadata: CodeMetadata,
170 _arg_buffer: &ManagedArgBuffer<Self>,
171 ) -> (ManagedAddress<Self>, ManagedVec<Self, ManagedBuffer<Self>>) {
172 panic!("deploy_contract not yet implemented")
173 }
174
175 fn deploy_from_source_contract(
176 &self,
177 _gas: u64,
178 _amount: &BigUint<Self>,
179 _source_contract_address: &ManagedAddress<Self>,
180 _code_metadata: CodeMetadata,
181 _arg_buffer: &ManagedArgBuffer<Self>,
182 ) -> (ManagedAddress<Self>, ManagedVec<Self, ManagedBuffer<Self>>) {
183 panic!("deploy_from_source_contract not yet implemented")
184 }
185
186 fn upgrade_contract(
187 &self,
188 _sc_address: &ManagedAddress<Self>,
189 _gas: u64,
190 _amount: &BigUint<Self>,
191 _code: &ManagedBuffer<Self>,
192 _code_metadata: CodeMetadata,
193 _arg_buffer: &ManagedArgBuffer<Self>,
194 ) {
195 panic!("upgrade_contract not yet implemented")
196 }
197
198 fn execute_on_dest_context_raw(
199 &self,
200 _gas: u64,
201 _to: &ManagedAddress<Self>,
202 _value: &BigUint<Self>,
203 _endpoint_name: &ManagedBuffer<Self>,
204 _arg_buffer: &ManagedArgBuffer<Self>,
205 ) -> ManagedVec<Self, ManagedBuffer<Self>> {
206 panic!("execute_on_dest_context_raw not implemented yet!");
207 }
208
209 fn execute_on_dest_context_raw_custom_result_range<F>(
210 &self,
211 _gas: u64,
212 _to: &ManagedAddress<Self>,
213 _value: &BigUint<Self>,
214 _endpoint_name: &ManagedBuffer<Self>,
215 _arg_buffer: &ManagedArgBuffer<Self>,
216 _range_closure: F,
217 ) -> ManagedVec<Self, ManagedBuffer<Self>>
218 where
219 F: FnOnce(usize, usize) -> (usize, usize),
220 {
221 panic!("execute_on_dest_context_raw_custom_result_range not implemented yet!");
222 }
223
224 fn execute_on_dest_context_by_caller_raw(
225 &self,
226 _gas: u64,
227 _to: &ManagedAddress<Self>,
228 _value: &BigUint<Self>,
229 _endpoint_name: &ManagedBuffer<Self>,
230 _arg_buffer: &ManagedArgBuffer<Self>,
231 ) -> ManagedVec<Self, ManagedBuffer<Self>> {
232 panic!("execute_on_dest_context_by_caller_raw not implemented yet!");
233 }
234
235 fn execute_on_same_context_raw(
236 &self,
237 _gas: u64,
238 _to: &ManagedAddress<Self>,
239 _value: &BigUint<Self>,
240 _endpoint_name: &ManagedBuffer<Self>,
241 _arg_buffer: &ManagedArgBuffer<Self>,
242 ) -> ManagedVec<Self, ManagedBuffer<Self>> {
243 panic!("execute_on_same_context_raw not implemented yet!");
244 }
245
246 fn execute_on_dest_context_readonly_raw(
247 &self,
248 _gas: u64,
249 _to: &ManagedAddress<Self>,
250 _endpoint_name: &ManagedBuffer<Self>,
251 _arg_buffer: &ManagedArgBuffer<Self>,
252 ) -> ManagedVec<Self, ManagedBuffer<Self>> {
253 panic!("execute_on_dest_context_readonly_raw not implemented yet!");
254 }
255
256 fn storage_store_tx_hash_key(&self, data: &ManagedBuffer<Self>) {
257 let tx_hash = self.get_tx_hash_legacy();
258 self.storage_store_slice_u8(tx_hash.as_bytes(), data.to_boxed_bytes().as_slice());
259 }
260
261 fn storage_load_tx_hash_key(&self) -> ManagedBuffer<Self> {
262 let tx_hash = self.get_tx_hash_legacy();
263 let bytes = self.storage_load_boxed_bytes(tx_hash.as_bytes());
264 ManagedBuffer::new_from_bytes(self.clone(), bytes.as_slice())
265 }
266
267 fn call_local_dcdt_built_in_function(
268 &self,
269 _gas: u64,
270 _function_name: &ManagedBuffer<Self>,
271 _arg_buffer: &ManagedArgBuffer<Self>,
272 ) -> ManagedVec<Self, ManagedBuffer<Self>> {
273 panic!("call_local_dcdt_built_in_function not implemented yet!");
274 }
275}