1use ergo_lib::ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
4
5use std::str::FromStr;
6
7use crate::{
8 address::{Address, ConstAddressPtr},
9 collections::ConstCollectionPtr,
10 ergo_box::ErgoBox,
11 ergo_state_ctx::ConstErgoStateContextPtr,
12 reduced::ConstReducedTransactionPtr,
13 secret_key::SecretKey,
14 transaction::{
15 ConstTransactionHintsBagPtr, ConstUnsignedTransactionPtr, Transaction, TransactionHintsBag,
16 TransactionHintsBagPtr, TransactionPtr,
17 },
18 util::{const_ptr_as_ref, mut_ptr_as_mut},
19 Error,
20};
21
22pub struct Wallet(ergo_lib::wallet::Wallet);
24pub type WalletPtr = *mut Wallet;
25pub type ConstWalletPtr = *const Wallet;
26
27pub struct MnemonicGenerator(ergo_lib::wallet::mnemonic_generator::MnemonicGenerator);
28pub type MnemonicGeneratorPtr = *mut MnemonicGenerator;
29
30pub unsafe fn mnemonic_generator(
32 language: &str,
33 strength: u32,
34 mnemonic_generator_out: *mut MnemonicGeneratorPtr,
35) -> Result<(), Error> {
36 let lang = match ergo_lib::wallet::mnemonic_generator::Language::from_str(language) {
37 Ok(lang) => lang,
38 _ => return Err(Error::Misc("Invalid language string".into())),
39 };
40 let mnemonic_generator_inner =
41 ergo_lib::wallet::mnemonic_generator::MnemonicGenerator::new(lang, strength);
42 *mnemonic_generator_out = Box::into_raw(Box::new(MnemonicGenerator(mnemonic_generator_inner)));
43 Ok(())
44}
45
46pub unsafe fn mnemonic_generator_generate(
48 mnemonic_generator_ptr: MnemonicGeneratorPtr,
49) -> Result<String, Error> {
50 let mnemonic_generator = mut_ptr_as_mut(mnemonic_generator_ptr, "mnemonic_generator_ptr")?;
51 let mnemonic = match mnemonic_generator.0.generate() {
52 Ok(mnemonic) => mnemonic,
53 Err(error) => return Err(Error::Misc(Box::new(error))),
54 };
55 Ok(mnemonic)
56}
57
58pub unsafe fn mnemonic_generator_generate_from_entropy(
60 mnemonic_generator_ptr: MnemonicGeneratorPtr,
61 entropy_bytes_ptr: *const u8,
62 len: usize,
63) -> Result<String, Error> {
64 let entrophy = std::slice::from_raw_parts(entropy_bytes_ptr, len);
65 let mnemonic_generator = mut_ptr_as_mut(mnemonic_generator_ptr, "mnemonic_generator_ptr")?;
66 let mnemonic = match mnemonic_generator.0.from_entrophy(entrophy.to_vec()) {
67 Ok(mnemonic) => mnemonic,
68 Err(error) => return Err(Error::Misc(Box::new(error))),
69 };
70 Ok(mnemonic)
71}
72
73pub unsafe fn wallet_from_mnemonic(
76 mnemonic_phrase: &str,
77 mnemonic_pass: &str,
78 wallet_out: *mut WalletPtr,
79) -> Result<(), Error> {
80 let wallet_out = mut_ptr_as_mut(wallet_out, "wallet_out")?;
81 if let Ok(wallet_inner) =
82 ergo_lib::wallet::Wallet::from_mnemonic(mnemonic_phrase, mnemonic_pass)
83 {
84 *wallet_out = Box::into_raw(Box::new(Wallet(wallet_inner)));
85 Ok(())
86 } else {
87 Err(Error::Misc(
88 "Wallet.from_mnemonic: DlogSecretKey can't be parsed from the provided phrase".into(),
89 ))
90 }
91}
92
93pub unsafe fn wallet_from_secrets(
95 secret_keys_ptr: ConstCollectionPtr<SecretKey>,
96 wallet_out: *mut WalletPtr,
97) -> Result<(), Error> {
98 let secret_keys = const_ptr_as_ref(secret_keys_ptr, "secret_keys_ptr")?;
99 let wallet_out = mut_ptr_as_mut(wallet_out, "wallet_out")?;
100 *wallet_out = Box::into_raw(Box::new(Wallet(ergo_lib::wallet::Wallet::from_secrets(
101 secret_keys.0.clone().into_iter().map(|s| s.0).collect(),
102 ))));
103 Ok(())
104}
105
106pub unsafe fn wallet_add_secret(
108 wallet_ptr: WalletPtr,
109 secret_key_ptr: *mut SecretKey,
110) -> Result<(), Error> {
111 let wallet = mut_ptr_as_mut(wallet_ptr, "wallet_ptr")?;
112 let sk = mut_ptr_as_mut(secret_key_ptr, "secret_key_ptr")?;
113 wallet.0.add_secret(sk.0.clone());
114 Ok(())
115}
116
117pub unsafe fn wallet_sign_transaction(
119 wallet_ptr: ConstWalletPtr,
120 state_context_ptr: ConstErgoStateContextPtr,
121 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
122 boxes_to_spend_ptr: ConstCollectionPtr<ErgoBox>,
123 data_boxes_ptr: ConstCollectionPtr<ErgoBox>,
124 transaction_out: *mut TransactionPtr,
125) -> Result<(), Error> {
126 let wallet = const_ptr_as_ref(wallet_ptr, "wallet_ptr")?;
127 let state_context = const_ptr_as_ref(state_context_ptr, "state_context_ptr")?;
128 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
129 let boxes_to_spend = const_ptr_as_ref(boxes_to_spend_ptr, "boxes_to_spend_ptr")?;
130 let data_boxes = const_ptr_as_ref(data_boxes_ptr, "data_boxes_ptr")?;
131 let transaction_out = mut_ptr_as_mut(transaction_out, "transaction_out")?;
132 let boxes_to_spend = boxes_to_spend.0.clone().into_iter().map(|b| b.0).collect();
133 let data_boxes = data_boxes.0.clone().into_iter().map(|b| b.0).collect();
134 let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
135 unsigned_tx.0.clone(),
136 boxes_to_spend,
137 data_boxes,
138 )?;
139 let tx = wallet
140 .0
141 .sign_transaction(tx_context, &state_context.0, None)?;
142 *transaction_out = Box::into_raw(Box::new(Transaction(tx)));
143 Ok(())
144}
145
146pub unsafe fn wallet_sign_transaction_multi(
148 wallet_ptr: ConstWalletPtr,
149 state_context_ptr: ConstErgoStateContextPtr,
150 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
151 boxes_to_spend_ptr: ConstCollectionPtr<ErgoBox>,
152 data_boxes_ptr: ConstCollectionPtr<ErgoBox>,
153 tx_hints_ptr: ConstTransactionHintsBagPtr,
154 transaction_out: *mut TransactionPtr,
155) -> Result<(), Error> {
156 let wallet = const_ptr_as_ref(wallet_ptr, "wallet_ptr")?;
157 let state_context = const_ptr_as_ref(state_context_ptr, "state_context_ptr")?;
158 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
159 let boxes_to_spend = const_ptr_as_ref(boxes_to_spend_ptr, "boxes_to_spend_ptr")?;
160 let data_boxes = const_ptr_as_ref(data_boxes_ptr, "data_boxes_ptr")?;
161 let tx_hints = const_ptr_as_ref(tx_hints_ptr, "tx_hints_ptr")?;
162 let transaction_out = mut_ptr_as_mut(transaction_out, "transaction_out")?;
163 let boxes_to_spend = boxes_to_spend.0.clone().into_iter().map(|b| b.0).collect();
164 let data_boxes = data_boxes.0.clone().into_iter().map(|b| b.0).collect();
165 let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
166 unsigned_tx.0.clone(),
167 boxes_to_spend,
168 data_boxes,
169 )?;
170 let tx = wallet
171 .0
172 .sign_transaction(tx_context, &state_context.0, Some(&tx_hints.0))?;
173 *transaction_out = Box::into_raw(Box::new(Transaction(tx)));
174 Ok(())
175}
176
177pub unsafe fn wallet_sign_reduced_transaction(
179 wallet_ptr: ConstWalletPtr,
180 reduced_tx_ptr: ConstReducedTransactionPtr,
181 transaction_out: *mut TransactionPtr,
182) -> Result<(), Error> {
183 let wallet = const_ptr_as_ref(wallet_ptr, "wallet_ptr")?;
184 let reduced_tx = const_ptr_as_ref(reduced_tx_ptr, "reduced_tx_ptr")?;
185 let transaction_out = mut_ptr_as_mut(transaction_out, "transaction_out")?;
186 let tx = wallet
187 .0
188 .sign_reduced_transaction(reduced_tx.0.clone(), None)
189 .map(Transaction)?;
190 *transaction_out = Box::into_raw(Box::new(tx));
191 Ok(())
192}
193
194pub unsafe fn wallet_sign_reduced_transaction_multi(
196 wallet_ptr: ConstWalletPtr,
197 reduced_tx_ptr: ConstReducedTransactionPtr,
198 tx_hints_ptr: ConstTransactionHintsBagPtr,
199 transaction_out: *mut TransactionPtr,
200) -> Result<(), Error> {
201 let wallet = const_ptr_as_ref(wallet_ptr, "wallet_ptr")?;
202 let reduced_tx = const_ptr_as_ref(reduced_tx_ptr, "reduced_tx_ptr")?;
203 let transaction_out = mut_ptr_as_mut(transaction_out, "transaction_out")?;
204 let tx_hints = const_ptr_as_ref(tx_hints_ptr, "tx_hints_ptr")?;
205 let tx = wallet
206 .0
207 .sign_reduced_transaction(reduced_tx.0.clone(), Some(&tx_hints.0))
208 .map(Transaction)?;
209 *transaction_out = Box::into_raw(Box::new(tx));
210 Ok(())
211}
212
213pub unsafe fn wallet_generate_commitments(
215 wallet_ptr: ConstWalletPtr,
216 state_context_ptr: ConstErgoStateContextPtr,
217 unsigned_tx_ptr: ConstUnsignedTransactionPtr,
218 boxes_to_spend_ptr: ConstCollectionPtr<ErgoBox>,
219 data_boxes_ptr: ConstCollectionPtr<ErgoBox>,
220 transaction_hints_bag_out: *mut TransactionHintsBagPtr,
221) -> Result<(), Error> {
222 let wallet = const_ptr_as_ref(wallet_ptr, "wallet_ptr")?;
223 let state_context = const_ptr_as_ref(state_context_ptr, "state_context_ptr")?;
224 let unsigned_tx = const_ptr_as_ref(unsigned_tx_ptr, "unsigned_tx_ptr")?;
225 let boxes_to_spend = const_ptr_as_ref(boxes_to_spend_ptr, "boxes_to_spend_ptr")?;
226 let data_boxes = const_ptr_as_ref(data_boxes_ptr, "data_boxes_ptr")?;
227 let transaction_hints_bag_out = mut_ptr_as_mut(transaction_hints_bag_out, "transaction_out")?;
228 let boxes_to_spend = boxes_to_spend.0.clone().into_iter().map(|b| b.0).collect();
229 let data_boxes = data_boxes.0.clone().into_iter().map(|b| b.0).collect();
230 let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
231 unsigned_tx.0.clone(),
232 boxes_to_spend,
233 data_boxes,
234 )?;
235 *transaction_hints_bag_out = Box::into_raw(Box::new(TransactionHintsBag(
236 wallet
237 .0
238 .generate_commitments(tx_context, &state_context.0)?,
239 )));
240 Ok(())
241}
242
243pub unsafe fn wallet_generate_commitments_for_reduced_transaction(
245 wallet_ptr: ConstWalletPtr,
246 reduced_tx_ptr: ConstReducedTransactionPtr,
247 transaction_hints_bag_out: *mut TransactionHintsBagPtr,
248) -> Result<(), Error> {
249 let wallet = const_ptr_as_ref(wallet_ptr, "wallet_ptr")?;
250 let reduced_tx = const_ptr_as_ref(reduced_tx_ptr, "reduced_tx_ptr")?;
251 let transaction_hints_bag_out = mut_ptr_as_mut(transaction_hints_bag_out, "transaction_out")?;
252 *transaction_hints_bag_out = Box::into_raw(Box::new(TransactionHintsBag(
253 wallet
254 .0
255 .generate_commitments_for_reduced_transaction(reduced_tx.0.clone())?,
256 )));
257 Ok(())
258}
259
260pub struct SignedMessage(Vec<u8>);
262pub type SignedMessagePtr = *mut SignedMessage;
263pub type ConstSignedMessagePtr = *const SignedMessage;
264
265pub unsafe fn wallet_sign_message_using_p2pk(
267 wallet_ptr: ConstWalletPtr,
268 address_ptr: ConstAddressPtr,
269 message_ptr: *const u8,
270 message_length: usize,
271 signed_message_out: *mut SignedMessagePtr,
272) -> Result<(), Error> {
273 let wallet = const_ptr_as_ref(wallet_ptr, "wallet_ptr")?;
274 let address = const_ptr_as_ref(address_ptr, "address_ptr")?;
275 let msg = std::slice::from_raw_parts(message_ptr, message_length);
276 let signed_message_out = mut_ptr_as_mut(signed_message_out, "signed_message_out")?;
277 if let Address(ergo_lib::ergotree_ir::chain::address::Address::P2Pk(d)) = address {
278 let sb = SigmaBoolean::from(d.clone());
279 let sig = wallet.0.sign_message(sb, msg)?;
280 *signed_message_out = Box::into_raw(Box::new(SignedMessage(sig)));
281 Ok(())
282 } else {
283 Err(Error::Misc(
284 "wallet::sign_message_using_p2pk: Address:P2Pk expected".into(),
285 ))
286 }
287}
288
289pub unsafe fn verify_signature(
291 address_ptr: ConstAddressPtr,
292 message_ptr: *const u8,
293 message_length: usize,
294 signed_message_ptr: ConstSignedMessagePtr,
295) -> Result<bool, Error> {
296 let address = const_ptr_as_ref(address_ptr, "address_ptr")?;
297 let msg = std::slice::from_raw_parts(message_ptr, message_length);
298 let signed_message = const_ptr_as_ref(signed_message_ptr, "signed_message_ptr")?;
299
300 if let Address(ergo_lib::ergotree_ir::chain::address::Address::P2Pk(d)) = address {
301 let sb = SigmaBoolean::from(d.clone());
302 let res = ergo_lib::ergotree_interpreter::sigma_protocol::verifier::verify_signature(
303 sb,
304 msg,
305 signed_message.0.as_slice(),
306 )?;
307 Ok(res)
308 } else {
309 Err(Error::Misc(
310 "wallet::verify_signature: Address:P2Pk expected".into(),
311 ))
312 }
313}