ergo_lib_wasm/
wallet.rs

1//! Wallet-like features
2use derive_more::{From, Into};
3use ergo_lib::ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
4use js_sys::Uint8Array;
5use wasm_bindgen::prelude::*;
6
7pub mod derivation_path;
8pub mod ext_pub_key;
9pub mod ext_secret_key;
10pub mod mnemonic;
11
12use crate::address::Address;
13use crate::input::Input;
14use crate::transaction::TransactionHintsBag;
15use crate::{
16    box_coll::ErgoBoxes,
17    ergo_state_ctx::ErgoStateContext,
18    error_conversion::to_js,
19    secret_key::{SecretKey, SecretKeys},
20    transaction::reduced::ReducedTransaction,
21    transaction::Transaction,
22    transaction::UnsignedTransaction,
23};
24
25/// A collection of secret keys. This simplified signing by matching the secret keys to the correct inputs automatically.
26#[wasm_bindgen]
27#[derive(From, Into)]
28pub struct Wallet(ergo_lib::wallet::Wallet);
29
30#[wasm_bindgen]
31impl Wallet {
32    /// Create wallet instance loading secret key from mnemonic
33    /// Returns None if a DlogSecretKey cannot be parsed from the provided phrase
34    #[wasm_bindgen]
35    pub fn from_mnemonic(mnemonic_phrase: &str, mnemonic_pass: &str) -> Result<Wallet, JsValue> {
36        ergo_lib::wallet::Wallet::from_mnemonic(mnemonic_phrase, mnemonic_pass)
37            .map(Wallet)
38            .map_err(to_js)
39    }
40
41    /// Create wallet using provided secret key
42    #[wasm_bindgen]
43    pub fn from_secrets(secret: &SecretKeys) -> Wallet {
44        Wallet(ergo_lib::wallet::Wallet::from_secrets(secret.into()))
45    }
46
47    /// Add a secret to the wallets prover
48    #[wasm_bindgen]
49    pub fn add_secret(&mut self, secret: &SecretKey) {
50        self.0.add_secret(secret.clone().into());
51    }
52
53    /// Sign a transaction:
54    /// `tx` - transaction to sign
55    /// `boxes_to_spend` - boxes corresponding to [`UnsignedTransaction::inputs`]
56    /// `data_boxes` - boxes corresponding to [`UnsignedTransaction::data_inputs`]
57    #[wasm_bindgen]
58    pub fn sign_transaction(
59        &self,
60        _state_context: &ErgoStateContext,
61        tx: &UnsignedTransaction,
62        boxes_to_spend: &ErgoBoxes,
63        data_boxes: &ErgoBoxes,
64    ) -> Result<Transaction, JsValue> {
65        crate::utils::set_panic_hook();
66        let boxes_to_spend = boxes_to_spend.clone().into();
67        let data_boxes = data_boxes.clone().into();
68        let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
69            tx.0.clone(),
70            boxes_to_spend,
71            data_boxes,
72        )
73        .map_err(to_js)?;
74        self.0
75            .sign_transaction(tx_context, &_state_context.clone().into(), None)
76            .map_err(to_js)
77            .map(Transaction::from)
78    }
79
80    /// Sign a multi signature transaction:
81    /// `tx` - transaction to sign
82    /// `boxes_to_spend` - boxes corresponding to [`UnsignedTransaction::inputs`]
83    /// `data_boxes` - boxes corresponding to [`UnsignedTransaction::data_inputs`]
84    /// `tx_hints` - transaction hints bag corresponding to [`TransactionHintsBag`]
85    #[wasm_bindgen]
86    pub fn sign_transaction_multi(
87        &self,
88        _state_context: &ErgoStateContext,
89        tx: &UnsignedTransaction,
90        boxes_to_spend: &ErgoBoxes,
91        data_boxes: &ErgoBoxes,
92        tx_hints: &TransactionHintsBag,
93    ) -> Result<Transaction, JsValue> {
94        let boxes_to_spend = boxes_to_spend.clone().into();
95        let data_boxes = data_boxes.clone().into();
96        let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
97            tx.0.clone(),
98            boxes_to_spend,
99            data_boxes,
100        )
101        .map_err(to_js)?;
102        self.0
103            .sign_transaction(
104                tx_context,
105                &_state_context.clone().into(),
106                Some(&tx_hints.0),
107            )
108            .map_err(to_js)
109            .map(Transaction::from)
110    }
111
112    /// Sign a transaction:
113    /// `reduced_tx` - reduced transaction, i.e. unsigned transaction where for each unsigned input
114    /// added a script reduction result.
115    #[wasm_bindgen]
116    pub fn sign_reduced_transaction(
117        &self,
118        reduced_tx: &ReducedTransaction,
119    ) -> Result<Transaction, JsValue> {
120        self.0
121            .sign_reduced_transaction(reduced_tx.clone().into(), None)
122            .map_err(to_js)
123            .map(Transaction::from)
124    }
125
126    /// Sign a multi signature reduced transaction:
127    /// `reduced_tx` - reduced transaction, i.e. unsigned transaction where for each unsigned input
128    /// added a script reduction result.
129    /// `tx_hints` - transaction hints bag corresponding to [`TransactionHintsBag`]
130    #[wasm_bindgen]
131    pub fn sign_reduced_transaction_multi(
132        &self,
133        reduced_tx: &ReducedTransaction,
134        tx_hints: &TransactionHintsBag,
135    ) -> Result<Transaction, JsValue> {
136        self.0
137            .sign_reduced_transaction(reduced_tx.clone().into(), Some(&tx_hints.0))
138            .map_err(to_js)
139            .map(Transaction::from)
140    }
141
142    /// Generate Commitments for unsigned tx
143    #[wasm_bindgen]
144    pub fn generate_commitments(
145        &self,
146        _state_context: &ErgoStateContext,
147        tx: &UnsignedTransaction,
148        boxes_to_spend: &ErgoBoxes,
149        data_boxes: &ErgoBoxes,
150    ) -> Result<TransactionHintsBag, JsValue> {
151        let boxes_to_spend = boxes_to_spend.clone().into();
152        let data_boxes = data_boxes.clone().into();
153        let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
154            tx.0.clone(),
155            boxes_to_spend,
156            data_boxes,
157        )
158        .map_err(to_js)?;
159        self.0
160            .generate_commitments(tx_context, &_state_context.clone().into())
161            .map_err(to_js)
162            .map(TransactionHintsBag::from)
163    }
164
165    /// Generate Commitments for reduced Transaction
166    #[wasm_bindgen]
167    pub fn generate_commitments_for_reduced_transaction(
168        &self,
169        reduced_tx: &ReducedTransaction,
170    ) -> Result<TransactionHintsBag, JsValue> {
171        self.0
172            .generate_commitments_for_reduced_transaction(reduced_tx.clone().into())
173            .map_err(to_js)
174            .map(TransactionHintsBag::from)
175    }
176
177    /// Sign an arbitrary message using a P2PK address
178    #[wasm_bindgen]
179    pub fn sign_message_using_p2pk(
180        &self,
181        address: &Address,
182        message: &[u8],
183    ) -> Result<Uint8Array, JsValue> {
184        if let Address(ergo_lib::ergotree_ir::chain::address::Address::P2Pk(d)) = address.clone() {
185            let sb = SigmaBoolean::from(d);
186            self.0
187                .sign_message(sb, message)
188                .map_err(to_js)
189                .map(|v| Uint8Array::from(v.as_slice()))
190        } else {
191            Err(JsValue::from_str(
192                "wallet::sign_message_using_p2pk: Address:P2Pk expected",
193            ))
194        }
195    }
196
197    /// Sign a given tx input
198    #[wasm_bindgen]
199    pub fn sign_tx_input(
200        &self,
201        input_idx: usize,
202        state_context: &ErgoStateContext,
203        tx: &UnsignedTransaction,
204        boxes_to_spend: &ErgoBoxes,
205        data_boxes: &ErgoBoxes,
206    ) -> Result<Input, JsValue> {
207        let boxes_to_spend = boxes_to_spend.clone().into();
208        let data_boxes = data_boxes.clone().into();
209        let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
210            tx.0.clone(),
211            boxes_to_spend,
212            data_boxes,
213        )
214        .map_err(to_js)?;
215        let state_context_inner = state_context.clone().into();
216        self.0
217            .sign_tx_input(input_idx, tx_context, &state_context_inner, None)
218            .map_err(to_js)
219            .map(Input::from)
220    }
221
222    /// Sign a given multi-signature tx input
223    #[wasm_bindgen]
224    pub fn sign_tx_input_multi(
225        &self,
226        input_idx: usize,
227        state_context: &ErgoStateContext,
228        tx: &UnsignedTransaction,
229        boxes_to_spend: &ErgoBoxes,
230        data_boxes: &ErgoBoxes,
231        tx_hints: &TransactionHintsBag,
232    ) -> Result<Input, JsValue> {
233        let boxes_to_spend = boxes_to_spend.clone().into();
234        let data_boxes = data_boxes.clone().into();
235        let tx_context = ergo_lib::wallet::signing::TransactionContext::new(
236            tx.0.clone(),
237            boxes_to_spend,
238            data_boxes,
239        )
240        .map_err(to_js)?;
241        let state_context_inner = state_context.clone().into();
242        self.0
243            .sign_tx_input(
244                input_idx,
245                tx_context,
246                &state_context_inner,
247                Some(&tx_hints.0),
248            )
249            .map_err(to_js)
250            .map(Input::from)
251    }
252}