numbat_wasm_debug/api/
send_api_mock.rs

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};
10// use num_bigint::BigUint;
11use num_traits::Zero;
12
13impl TxContext {
14    fn get_available_rewa_balance(&self) -> num_bigint::BigUint {
15        // start with the pre-existing balance
16        let mut available_balance = self.blockchain_info_box.contract_balance.clone();
17
18        // add amount received
19        available_balance += &self.tx_input_box.call_value;
20
21        // already sent
22        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        // start with the pre-existing balance
32        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        // add amount received (if the same token)
40        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        // already sent
46        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        // the cell is no longer needed, since we end in a panic
154        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}