1use std::convert::{TryFrom, TryInto};
4
5use ergo_lib::{
6 chain,
7 ergo_chain_types::{Base16DecodedBytes, Base16EncodedBytes},
8};
9
10use crate::{
11 collections::{Collection, CollectionPtr, ConstCollectionPtr},
12 data_input::DataInput,
13 ergo_box::{ErgoBox, ErgoBoxCandidate},
14 ergo_state_ctx::ConstErgoStateContextPtr,
15 input::{Input, UnsignedInput},
16 json::{TransactionJsonEip12, UnsignedTransactionJsonEip12},
17 reduced::ConstPropositionsPtr,
18 util::{const_ptr_as_ref, mut_ptr_as_mut, ByteArray},
19 Error,
20};
21
22pub struct CommitmentHint(
24 pub(crate) ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::CommitmentHint,
25);
26pub type CommitmentHintPtr = *mut CommitmentHint;
27pub type ConstCommitmentHintPtr = *const CommitmentHint;
28
29pub struct HintsBag(
31 pub(crate) ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::HintsBag,
32);
33pub type HintsBagPtr = *mut HintsBag;
34pub type ConstHintsBagPtr = *const HintsBag;
35
36pub unsafe fn hints_bag_empty(hints_bag_out: *mut HintsBagPtr) -> Result<(), Error> {
38 let hints_bag_out = mut_ptr_as_mut(hints_bag_out, "hints_bag_out")?;
39 *hints_bag_out = Box::into_raw(Box::new(HintsBag(
40 ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::HintsBag::empty(),
41 )));
42 Ok(())
43}
44
45pub unsafe fn hints_bag_add_commitment(
47 hints_bag_mut: HintsBagPtr,
48 hint_ptr: ConstCommitmentHintPtr,
49) -> Result<(), Error> {
50 let hints_bag_mut = mut_ptr_as_mut(hints_bag_mut, "hints_bag_mut")?;
51 let hint = const_ptr_as_ref(hint_ptr, "hint_ptr")?;
52 hints_bag_mut.0.add_hint(
53 ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::Hint::CommitmentHint(
54 hint.0.clone(),
55 ),
56 );
57 Ok(())
58}
59
60pub unsafe fn hints_bag_len(hints_bag_ptr: ConstHintsBagPtr) -> Result<usize, Error> {
62 let hints_bag = const_ptr_as_ref(hints_bag_ptr, "hints_bag_ptr")?;
63 Ok(hints_bag.0.hints.len())
64}
65
66pub unsafe fn hints_bag_get(
68 hints_bag_ptr: ConstHintsBagPtr,
69 index: usize,
70 hint_out: *mut CommitmentHintPtr,
71) -> Result<bool, Error> {
72 let hints_bag = const_ptr_as_ref(hints_bag_ptr, "hints_bag_ptr")?;
73 let hint_out = mut_ptr_as_mut(hint_out, "hint_out")?;
74 if let Some(commitment) = hints_bag.0.commitments().get(index) {
75 *hint_out = Box::into_raw(Box::new(CommitmentHint(commitment.clone())));
76 return Ok(true);
77 }
78 Ok(false)
79}
80
81pub struct TransactionHintsBag(pub(crate) ergo_lib::wallet::multi_sig::TransactionHintsBag);
83pub type TransactionHintsBagPtr = *mut TransactionHintsBag;
84pub type ConstTransactionHintsBagPtr = *const TransactionHintsBag;
85
86pub unsafe fn transaction_hints_bag_empty(
88 transaction_hints_bag_out: *mut TransactionHintsBagPtr,
89) -> Result<(), Error> {
90 let transaction_hints_bag_out =
91 mut_ptr_as_mut(transaction_hints_bag_out, "transaction_hints_bag_out")?;
92 *transaction_hints_bag_out = Box::into_raw(Box::new(TransactionHintsBag(
93 ergo_lib::wallet::multi_sig::TransactionHintsBag::empty(),
94 )));
95 Ok(())
96}
97
98pub unsafe fn transaction_hints_bag_add_hints_for_input(
100 transaction_hints_bag_mut: TransactionHintsBagPtr,
101 index: usize,
102 hints_bag_ptr: ConstHintsBagPtr,
103) -> Result<(), Error> {
104 let transaction_hints_bag_mut =
105 mut_ptr_as_mut(transaction_hints_bag_mut, "transaction_hints_bag_mut")?;
106 let hints_bag = const_ptr_as_ref(hints_bag_ptr, "hints_bag_ptr")?;
107 transaction_hints_bag_mut
108 .0
109 .add_hints_for_input(index, hints_bag.0.clone());
110 Ok(())
111}
112
113pub unsafe fn transaction_hints_bag_all_hints_for_input(
115 transaction_hints_bag_ptr: ConstTransactionHintsBagPtr,
116 index: usize,
117 hints_bag_out: *mut HintsBagPtr,
118) -> Result<(), Error> {
119 let transaction_hints_bag =
120 const_ptr_as_ref(transaction_hints_bag_ptr, "transaction_hints_bag_ptr")?;
121 let hints_bag_out = mut_ptr_as_mut(hints_bag_out, "hints_bag_out")?;
122 *hints_bag_out = Box::into_raw(Box::new(HintsBag(
123 transaction_hints_bag.0.all_hints_for_input(index),
124 )));
125 Ok(())
126}
127
128pub unsafe fn transaction_extract_hints(
130 signed_transaction_ptr: ConstTransactionPtr,
131 state_context_ptr: ConstErgoStateContextPtr,
132 boxes_to_spend_ptr: ConstCollectionPtr<ErgoBox>,
133 data_boxes_ptr: ConstCollectionPtr<ErgoBox>,
134 real_propositions_ptr: ConstPropositionsPtr,
135 simulated_propositions_ptr: ConstPropositionsPtr,
136 transaction_hints_bag_out: *mut TransactionHintsBagPtr,
137) -> Result<(), Error> {
138 let signed_transaction = const_ptr_as_ref(signed_transaction_ptr, "signed_transaction_ptr")?;
139 let state_context = const_ptr_as_ref(state_context_ptr, "state_context_ptr")?;
140 let boxes_to_spend = const_ptr_as_ref(boxes_to_spend_ptr, "boxes_to_spend_ptr")?;
141 let data_boxes = const_ptr_as_ref(data_boxes_ptr, "data_boxes_ptr")?;
142 let real_propositions = const_ptr_as_ref(real_propositions_ptr, "real_propositions_ptr")?;
143 let simulated_propositions =
144 const_ptr_as_ref(simulated_propositions_ptr, "simulated_propositions_ptr")?;
145 let transaction_hints_bag_out =
146 mut_ptr_as_mut(transaction_hints_bag_out, "transaction_hints_bag_out")?;
147
148 let boxes_to_spend = boxes_to_spend.0.clone().into_iter().map(|x| x.0).collect();
149 let data_boxes = data_boxes.0.clone().into_iter().map(|x| x.0).collect();
150 let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
151 signed_transaction.0.clone(),
152 boxes_to_spend,
153 data_boxes,
154 )?;
155
156 *transaction_hints_bag_out = Box::into_raw(Box::new(TransactionHintsBag(
157 ergo_lib::wallet::multi_sig::extract_hints(
158 &tx_context,
159 &state_context.0.clone(),
160 real_propositions.0.clone(),
161 simulated_propositions.0.clone(),
162 )?,
163 )));
164 Ok(())
165}
166
167#[derive(PartialEq, Eq, Debug, Clone)]
169pub struct UnsignedTransaction(pub(crate) chain::transaction::unsigned::UnsignedTransaction);
170pub type UnsignedTransactionPtr = *mut UnsignedTransaction;
171pub type ConstUnsignedTransactionPtr = *const UnsignedTransaction;
172
173pub unsafe fn unsigned_tx_id(
175 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
176 tx_id_out: *mut TxIdPtr,
177) -> Result<(), Error> {
178 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
179 let tx_id_out = mut_ptr_as_mut(tx_id_out, "tx_id_out")?;
180 *tx_id_out = Box::into_raw(Box::new(TxId(unsigned_tx.0.id())));
181 Ok(())
182}
183
184pub unsafe fn unsigned_tx_inputs(
186 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
187 unsigned_inputs_out: *mut CollectionPtr<UnsignedInput>,
188) -> Result<(), Error> {
189 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
190 let unsigned_inputs_out = mut_ptr_as_mut(unsigned_inputs_out, "unsigned_inputs_out")?;
191 *unsigned_inputs_out = Box::into_raw(Box::new(Collection(
192 unsigned_tx
193 .0
194 .inputs
195 .as_vec()
196 .clone()
197 .into_iter()
198 .map(UnsignedInput)
199 .collect(),
200 )));
201 Ok(())
202}
203
204pub unsafe fn unsigned_tx_data_inputs(
206 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
207 data_inputs_out: *mut CollectionPtr<DataInput>,
208) -> Result<(), Error> {
209 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
210 let data_inputs_out = mut_ptr_as_mut(data_inputs_out, "data_inputs_out")?;
211 *data_inputs_out = Box::into_raw(Box::new(Collection(
212 unsigned_tx
213 .0
214 .data_inputs
215 .as_ref()
216 .map(|v| v.as_vec().clone())
217 .unwrap_or_else(Vec::new)
218 .into_iter()
219 .map(DataInput)
220 .collect(),
221 )));
222 Ok(())
223}
224
225pub unsafe fn unsigned_tx_output_candidates(
227 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
228 ergo_box_candidates_out: *mut CollectionPtr<ErgoBoxCandidate>,
229) -> Result<(), Error> {
230 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
231 let ergo_box_candidates_out =
232 mut_ptr_as_mut(ergo_box_candidates_out, "ergo_box_candidates_out")?;
233 *ergo_box_candidates_out = Box::into_raw(Box::new(Collection(
234 unsigned_tx
235 .0
236 .output_candidates
237 .iter()
238 .map(|ebc| ErgoBoxCandidate(ebc.clone()))
239 .collect(),
240 )));
241 Ok(())
242}
243
244pub unsafe fn unsigned_tx_from_json(
247 json: &str,
248 unsigned_tx_out: *mut UnsignedTransactionPtr,
249) -> Result<(), Error> {
250 let unsigned_tx_out = mut_ptr_as_mut(unsigned_tx_out, "unsigned_tx_out")?;
251 let unsigned_tx = serde_json::from_str(json).map(UnsignedTransaction)?;
252 *unsigned_tx_out = Box::into_raw(Box::new(unsigned_tx));
253 Ok(())
254}
255
256pub unsafe fn unsigned_tx_to_json(
258 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
259) -> Result<String, Error> {
260 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
261 let s = serde_json::to_string(&unsigned_tx.0)?;
262 Ok(s)
263}
264
265pub unsafe fn unsigned_tx_to_json_eip12(
267 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
268) -> Result<String, Error> {
269 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
270 let tx_dapp: UnsignedTransactionJsonEip12 = unsigned_tx.0.clone().into();
271 let s = serde_json::to_string(&tx_dapp)?;
272 Ok(s)
273}
274
275#[derive(PartialEq, Eq, Debug, Clone)]
277pub struct TxId(pub(crate) chain::transaction::TxId);
278pub type TxIdPtr = *mut TxId;
279pub type ConstTxIdPtr = *const TxId;
280
281pub unsafe fn tx_id_from_str(str: &str, tx_id_out: *mut TxIdPtr) -> Result<(), Error> {
283 let tx_id_out = mut_ptr_as_mut(tx_id_out, "tx_id_out")?;
284 let bytes = Base16DecodedBytes::try_from(str.to_string())?;
285 let tx_id = bytes
286 .try_into()
287 .map(|digest| TxId(chain::transaction::TxId(digest)))?;
288 *tx_id_out = Box::into_raw(Box::new(tx_id));
289 Ok(())
290}
291
292pub unsafe fn tx_id_to_str(tx_id_ptr: ConstTxIdPtr) -> Result<String, Error> {
294 let tx_id = const_ptr_as_ref(tx_id_ptr, "tx_id_ptr")?;
295 let base16_bytes = Base16EncodedBytes::new(tx_id.0 .0 .0.as_ref());
296 Ok(base16_bytes.into())
297}
298
299pub struct Transaction(pub(crate) chain::transaction::Transaction);
310pub type TransactionPtr = *mut Transaction;
311pub type ConstTransactionPtr = *const Transaction;
312
313pub unsafe fn tx_from_unsigned_tx(
316 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
317 proofs_ptr: ConstCollectionPtr<ByteArray>,
318 tx_out: *mut TransactionPtr,
319) -> Result<(), Error> {
320 let proofs = const_ptr_as_ref(proofs_ptr, "proofs_ptr")?;
321 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
322 let tx_out = mut_ptr_as_mut(tx_out, "tx_out")?;
323 let tx = chain::transaction::Transaction::from_unsigned_tx(
324 unsigned_tx.0.clone(),
325 proofs
326 .0
327 .iter()
328 .cloned()
329 .map(|bytes| bytes.0.into())
330 .collect(),
331 )
332 .map(Transaction)?;
333 *tx_out = Box::into_raw(Box::new(tx));
334 Ok(())
335}
336
337pub unsafe fn tx_id(tx_ptr: ConstTransactionPtr, tx_id_out: *mut TxIdPtr) -> Result<(), Error> {
339 let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
340 let tx_id_out = mut_ptr_as_mut(tx_id_out, "tx_id_out")?;
341 *tx_id_out = Box::into_raw(Box::new(TxId(tx.0.id())));
342 Ok(())
343}
344
345pub unsafe fn tx_from_json(json: &str, tx_out: *mut TransactionPtr) -> Result<(), Error> {
348 let tx_out = mut_ptr_as_mut(tx_out, "tx_out")?;
349 let tx = serde_json::from_str(json).map(Transaction)?;
350 *tx_out = Box::into_raw(Box::new(tx));
351 Ok(())
352}
353
354pub unsafe fn tx_to_json(tx_ptr: ConstTransactionPtr) -> Result<String, Error> {
356 let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
357 let s = serde_json::to_string(&tx.0)?;
358 Ok(s)
359}
360
361pub unsafe fn tx_to_json_eip12(tx_ptr: ConstTransactionPtr) -> Result<String, Error> {
363 let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
364 let tx_dapp: TransactionJsonEip12 = tx.0.clone().into();
365 let s = serde_json::to_string(&tx_dapp)?;
366 Ok(s)
367}
368
369pub unsafe fn tx_inputs(
371 tx_ptr: ConstTransactionPtr,
372 inputs_out: *mut CollectionPtr<Input>,
373) -> Result<(), Error> {
374 let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
375 let inputs_out = mut_ptr_as_mut(inputs_out, "inputs_out")?;
376 *inputs_out = Box::into_raw(Box::new(Collection(
377 tx.0.inputs
378 .as_vec()
379 .clone()
380 .into_iter()
381 .map(Input)
382 .collect(),
383 )));
384 Ok(())
385}
386
387pub unsafe fn tx_data_inputs(
389 tx_ptr: ConstTransactionPtr,
390 data_inputs_out: *mut CollectionPtr<DataInput>,
391) -> Result<(), Error> {
392 let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
393 let data_inputs_out = mut_ptr_as_mut(data_inputs_out, "data_inputs_out")?;
394 *data_inputs_out = Box::into_raw(Box::new(Collection(
395 tx.0.data_inputs
396 .as_ref()
397 .map(|v| v.as_vec().clone())
398 .unwrap_or_else(Vec::new)
399 .into_iter()
400 .map(DataInput)
401 .collect(),
402 )));
403 Ok(())
404}
405
406pub unsafe fn tx_output_candidates(
408 tx_ptr: ConstTransactionPtr,
409 ergo_box_candidates_out: *mut CollectionPtr<ErgoBoxCandidate>,
410) -> Result<(), Error> {
411 let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
412 let ergo_box_candidates_out =
413 mut_ptr_as_mut(ergo_box_candidates_out, "ergo_box_candidates_out")?;
414 *ergo_box_candidates_out = Box::into_raw(Box::new(Collection(
415 tx.0.output_candidates
416 .iter()
417 .map(|ebc| ErgoBoxCandidate(ebc.clone()))
418 .collect(),
419 )));
420 Ok(())
421}
422
423pub unsafe fn tx_outputs(
425 tx_ptr: ConstTransactionPtr,
426 ergo_box_out: *mut CollectionPtr<ErgoBox>,
427) -> Result<(), Error> {
428 let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
429 let ergo_box_out = mut_ptr_as_mut(ergo_box_out, "ergo_box_candidates_out")?;
430 *ergo_box_out = Box::into_raw(Box::new(Collection(
431 tx.0.outputs
432 .iter()
433 .map(|ebc| ErgoBox(ebc.clone()))
434 .collect(),
435 )));
436 Ok(())
437}
438
439pub unsafe fn tx_validate(
441 tx_ptr: ConstTransactionPtr,
442 state_context_ptr: ConstErgoStateContextPtr,
443 boxes_to_spend_ptr: ConstCollectionPtr<ErgoBox>,
444 data_boxes_ptr: ConstCollectionPtr<ErgoBox>,
445) -> Result<(), Error> {
446 let state_context = const_ptr_as_ref(state_context_ptr, "state_context_ptr")?;
447 let tx = const_ptr_as_ref(tx_ptr, "tx_ptr")?;
448 let boxes_to_spend = const_ptr_as_ref(boxes_to_spend_ptr, "boxes_to_spend_ptr")?;
449 let data_boxes = const_ptr_as_ref(data_boxes_ptr, "data_boxes_ptr")?;
450 let boxes_to_spend = boxes_to_spend.0.clone().into_iter().map(|b| b.0).collect();
451 let data_boxes = data_boxes.0.clone().into_iter().map(|b| b.0).collect();
452 let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
453 tx.0.clone(),
454 boxes_to_spend,
455 data_boxes,
456 )?;
457 tx_context.validate(&state_context.0)?;
458 Ok(())
459}