1pub mod arbitrated_pool;
2mod error;
3mod multisig;
4mod types;
5mod version;
6
7pub use arbitrated_pool::*;
8pub use error::{MultisigError, Result};
9pub use multisig::Multisig;
10pub use types::*;
11pub use version::{PROTOCOL, PROTOCOL_VERSION, RELEASE_VERSION, VERSION};
12
13use serde_wasm_bindgen as swbg;
14use wasm_bindgen::prelude::*;
15
16#[wasm_bindgen]
17pub fn build_arbitrated_pool_lock_v4(roles: JsValue) -> std::result::Result<JsValue, JsValue> {
18 let roles: ArbitratedPoolRoles = swbg::from_value(roles)?;
19 let script = arbitrated_pool::build_arbitrated_pool_lock(&roles)
20 .map_err(|error| JsValue::from_str(&error.to_string()))?;
21 Ok(swbg::to_value(&script)?)
22}
23
24#[wasm_bindgen]
25pub fn build_arbitrated_pool_state_v4(input: JsValue) -> std::result::Result<JsValue, JsValue> {
26 let input: ArbitratedPoolStateInput = swbg::from_value(input)?;
27 let state = arbitrated_pool::build_arbitrated_pool_state(input)
28 .map_err(|error| JsValue::from_str(&error.to_string()))?;
29 Ok(swbg::to_value(&state)?)
30}
31
32#[wasm_bindgen]
33pub fn build_arbitrated_pool_funding_v4(
34 utxos: JsValue,
35 pool_amount: u64,
36 buyer_private_key: JsValue,
37 roles: JsValue,
38 fee_rate: u64,
39) -> std::result::Result<JsValue, JsValue> {
40 let utxos: Vec<Utxo> = swbg::from_value(utxos)?;
41 let buyer_private_key: PrivateKey = swbg::from_value(buyer_private_key)?;
42 let roles: ArbitratedPoolRoles = swbg::from_value(roles)?;
43 let result = arbitrated_pool::build_arbitrated_pool_funding_tx(
44 &utxos,
45 pool_amount,
46 &buyer_private_key,
47 &roles,
48 fee_rate,
49 )
50 .map_err(|error| JsValue::from_str(&error.to_string()))?;
51 Ok(swbg::to_value(&result)?)
52}
53
54#[wasm_bindgen]
55pub fn build_arbitrated_pool_opening_state_v4(
56 funding_tx: JsValue,
57 pool_amount: u64,
58 roles: JsValue,
59 lock_time: u32,
60 fee_rate: u64,
61) -> std::result::Result<JsValue, JsValue> {
62 let funding_tx: Transaction = swbg::from_value(funding_tx)?;
63 let roles: ArbitratedPoolRoles = swbg::from_value(roles)?;
64 let state = arbitrated_pool::build_arbitrated_pool_opening_state(
65 &funding_tx,
66 pool_amount,
67 roles,
68 lock_time,
69 fee_rate,
70 )
71 .map_err(|error| JsValue::from_str(&error.to_string()))?;
72 Ok(swbg::to_value(&state)?)
73}
74
75#[wasm_bindgen]
76pub fn build_arbitrated_pool_final_state_v4(
77 input: JsValue,
78) -> std::result::Result<JsValue, JsValue> {
79 let input: ArbitratedPoolStateInput = swbg::from_value(input)?;
80 let state = arbitrated_pool::build_arbitrated_pool_final_state(input)
81 .map_err(|error| JsValue::from_str(&error.to_string()))?;
82 Ok(swbg::to_value(&state)?)
83}
84
85fn wasm_sign_role(
86 state: JsValue,
87 pool_amount: u64,
88 roles: JsValue,
89 key: JsValue,
90 sign: fn(&Transaction, u64, &ArbitratedPoolRoles, &PrivateKey) -> Result<Vec<u8>>,
91) -> std::result::Result<JsValue, JsValue> {
92 let state: Transaction = swbg::from_value(state)?;
93 let roles: ArbitratedPoolRoles = swbg::from_value(roles)?;
94 let key: PrivateKey = swbg::from_value(key)?;
95 let signature = sign(&state, pool_amount, &roles, &key)
96 .map_err(|error| JsValue::from_str(&error.to_string()))?;
97 Ok(swbg::to_value(&signature)?)
98}
99
100#[wasm_bindgen]
101pub fn sign_arbitrated_pool_as_buyer_v4(
102 state: JsValue,
103 pool_amount: u64,
104 roles: JsValue,
105 key: JsValue,
106) -> std::result::Result<JsValue, JsValue> {
107 wasm_sign_role(
108 state,
109 pool_amount,
110 roles,
111 key,
112 arbitrated_pool::sign_arbitrated_pool_as_buyer,
113 )
114}
115
116#[wasm_bindgen]
117pub fn sign_arbitrated_pool_as_seller_v4(
118 state: JsValue,
119 pool_amount: u64,
120 roles: JsValue,
121 key: JsValue,
122) -> std::result::Result<JsValue, JsValue> {
123 wasm_sign_role(
124 state,
125 pool_amount,
126 roles,
127 key,
128 arbitrated_pool::sign_arbitrated_pool_as_seller,
129 )
130}
131
132#[wasm_bindgen]
133pub fn sign_arbitrated_pool_as_arbiter_v4(
134 state: JsValue,
135 pool_amount: u64,
136 roles: JsValue,
137 key: JsValue,
138) -> std::result::Result<JsValue, JsValue> {
139 wasm_sign_role(
140 state,
141 pool_amount,
142 roles,
143 key,
144 arbitrated_pool::sign_arbitrated_pool_as_arbiter,
145 )
146}
147
148fn wasm_verify_role(
149 state: JsValue,
150 pool_amount: u64,
151 roles: JsValue,
152 signature: JsValue,
153 verify: fn(&Transaction, u64, &ArbitratedPoolRoles, &[u8]) -> Result<bool>,
154) -> std::result::Result<bool, JsValue> {
155 let state: Transaction = swbg::from_value(state)?;
156 let roles: ArbitratedPoolRoles = swbg::from_value(roles)?;
157 let signature: Vec<u8> = swbg::from_value(signature)?;
158 verify(&state, pool_amount, &roles, &signature)
159 .map_err(|error| JsValue::from_str(&error.to_string()))
160}
161
162#[wasm_bindgen]
163pub fn verify_arbitrated_pool_buyer_signature_v4(
164 state: JsValue,
165 pool_amount: u64,
166 roles: JsValue,
167 signature: JsValue,
168) -> std::result::Result<bool, JsValue> {
169 wasm_verify_role(
170 state,
171 pool_amount,
172 roles,
173 signature,
174 arbitrated_pool::verify_arbitrated_pool_buyer_signature,
175 )
176}
177
178#[wasm_bindgen]
179pub fn verify_arbitrated_pool_seller_signature_v4(
180 state: JsValue,
181 pool_amount: u64,
182 roles: JsValue,
183 signature: JsValue,
184) -> std::result::Result<bool, JsValue> {
185 wasm_verify_role(
186 state,
187 pool_amount,
188 roles,
189 signature,
190 arbitrated_pool::verify_arbitrated_pool_seller_signature,
191 )
192}
193
194#[wasm_bindgen]
195pub fn verify_arbitrated_pool_arbiter_signature_v4(
196 state: JsValue,
197 pool_amount: u64,
198 roles: JsValue,
199 signature: JsValue,
200) -> std::result::Result<bool, JsValue> {
201 wasm_verify_role(
202 state,
203 pool_amount,
204 roles,
205 signature,
206 arbitrated_pool::verify_arbitrated_pool_arbiter_signature,
207 )
208}
209
210type ArbitratedPoolMerge =
211 fn(&Transaction, u64, &ArbitratedPoolRoles, &[u8], &[u8]) -> Result<Transaction>;
212
213fn wasm_merge(
214 state: JsValue,
215 pool_amount: u64,
216 roles: JsValue,
217 first: JsValue,
218 second: JsValue,
219 merge: ArbitratedPoolMerge,
220) -> std::result::Result<JsValue, JsValue> {
221 let state: Transaction = swbg::from_value(state)?;
222 let roles: ArbitratedPoolRoles = swbg::from_value(roles)?;
223 let first: Vec<u8> = swbg::from_value(first)?;
224 let second: Vec<u8> = swbg::from_value(second)?;
225 let merged = merge(&state, pool_amount, &roles, &first, &second)
226 .map_err(|error| JsValue::from_str(&error.to_string()))?;
227 Ok(swbg::to_value(&merged)?)
228}
229
230#[wasm_bindgen]
231pub fn merge_arbitrated_pool_buyer_seller_signatures_v4(
232 state: JsValue,
233 pool_amount: u64,
234 roles: JsValue,
235 buyer: JsValue,
236 seller: JsValue,
237) -> std::result::Result<JsValue, JsValue> {
238 wasm_merge(
239 state,
240 pool_amount,
241 roles,
242 buyer,
243 seller,
244 arbitrated_pool::merge_arbitrated_pool_buyer_seller_signatures,
245 )
246}
247
248#[wasm_bindgen]
249pub fn merge_arbitrated_pool_buyer_arbiter_signatures_v4(
250 state: JsValue,
251 pool_amount: u64,
252 roles: JsValue,
253 buyer: JsValue,
254 arbiter: JsValue,
255) -> std::result::Result<JsValue, JsValue> {
256 wasm_merge(
257 state,
258 pool_amount,
259 roles,
260 buyer,
261 arbiter,
262 arbitrated_pool::merge_arbitrated_pool_buyer_arbiter_signatures,
263 )
264}
265
266#[wasm_bindgen]
267pub fn merge_arbitrated_pool_seller_arbiter_signatures_v4(
268 state: JsValue,
269 pool_amount: u64,
270 roles: JsValue,
271 seller: JsValue,
272 arbiter: JsValue,
273) -> std::result::Result<JsValue, JsValue> {
274 wasm_merge(
275 state,
276 pool_amount,
277 roles,
278 seller,
279 arbiter,
280 arbitrated_pool::merge_arbitrated_pool_seller_arbiter_signatures,
281 )
282}
283
284#[wasm_bindgen]
285pub fn create_multisig(
286 private_keys: JsValue,
287 public_keys: JsValue,
288 m: usize,
289) -> std::result::Result<MultisigWasm, JsValue> {
290 let pub_keys: Vec<PublicKey> = swbg::from_value(public_keys)?;
291 let priv_keys: Option<Vec<PrivateKey>> = swbg::from_value(private_keys).ok();
292
293 let multisig =
294 Multisig::new(priv_keys, pub_keys, m).map_err(|e| JsValue::from_str(&e.to_string()))?;
295
296 Ok(MultisigWasm { multisig })
297}
298
299#[wasm_bindgen]
300pub fn create_locking_script(
301 public_keys: JsValue,
302 m: usize,
303) -> std::result::Result<JsValue, JsValue> {
304 let pub_keys: Vec<PublicKey> = swbg::from_value(public_keys)?;
305
306 if m == 0 || m > pub_keys.len() {
307 return Err(JsValue::from_str("Invalid m value"));
308 }
309 if pub_keys.is_empty() || pub_keys.len() > 20 {
310 return Err(JsValue::from_str("Invalid public keys"));
311 }
312
313 let mut script = vec![0x01 + (m as u8) - 1];
314
315 for pub_key in &pub_keys {
316 script.push(pub_key.key.len() as u8);
317 script.extend(&pub_key.key);
318 }
319
320 script.push(0x01 + (pub_keys.len() as u8) - 1);
321 script.push(0xae);
322
323 Ok(swbg::to_value(&script)?)
324}
325
326#[wasm_bindgen]
327pub fn estimate_multisig_length(m: usize) -> usize {
328 1 + m * (71 + 1)
329}
330
331#[wasm_bindgen]
332pub struct MultisigWasm {
333 multisig: Multisig,
334}
335
336#[wasm_bindgen]
337impl MultisigWasm {
338 #[wasm_bindgen(constructor)]
339 pub fn new(
340 private_keys: JsValue,
341 public_keys: JsValue,
342 m: usize,
343 ) -> std::result::Result<MultisigWasm, JsValue> {
344 create_multisig(private_keys, public_keys, m)
345 }
346
347 pub fn lock(&self) -> std::result::Result<JsValue, JsValue> {
348 let script = self
349 .multisig
350 .lock()
351 .map_err(|e| JsValue::from_str(&e.to_string()))?;
352 Ok(swbg::to_value(&script)?)
353 }
354
355 pub fn sign(
356 &self,
357 transaction: JsValue,
358 input_index: usize,
359 ) -> std::result::Result<JsValue, JsValue> {
360 let tx: Transaction = swbg::from_value(transaction)?;
361 let signatures = self
362 .multisig
363 .sign(&tx, input_index)
364 .map_err(|e| JsValue::from_str(&e.to_string()))?;
365 Ok(swbg::to_value(&signatures)?)
366 }
367
368 pub fn sign_one(
369 &self,
370 transaction: JsValue,
371 input_index: usize,
372 private_key: JsValue,
373 ) -> std::result::Result<JsValue, JsValue> {
374 let tx: Transaction = swbg::from_value(transaction)?;
375 let priv_key: PrivateKey = swbg::from_value(private_key)?;
376
377 let signature = self
378 .multisig
379 .sign_one(&tx, input_index, &priv_key)
380 .map_err(|e| JsValue::from_str(&e.to_string()))?;
381 Ok(swbg::to_value(&signature)?)
382 }
383
384 pub fn estimate_length(&self) -> usize {
385 self.multisig.estimate_length()
386 }
387
388 pub fn create_fake_sign(&self) -> std::result::Result<JsValue, JsValue> {
389 let script = self
390 .multisig
391 .create_fake_sign()
392 .map_err(|e| JsValue::from_str(&e.to_string()))?;
393 Ok(swbg::to_value(&script)?)
394 }
395
396 pub fn build_sign_script(&self, signatures: JsValue) -> std::result::Result<JsValue, JsValue> {
397 let sigs: Vec<Vec<u8>> = swbg::from_value(signatures)?;
398 let script = self
399 .multisig
400 .build_sign_script(&sigs)
401 .map_err(|e| JsValue::from_str(&e.to_string()))?;
402 Ok(swbg::to_value(&script)?)
403 }
404
405 pub fn get_m(&self) -> usize {
406 self.multisig.get_m()
407 }
408
409 pub fn get_n(&self) -> usize {
410 self.multisig.get_n()
411 }
412
413 pub fn get_sig_hash_type(&self) -> u8 {
414 self.multisig.get_sig_hash_type()
415 }
416}
417
418#[cfg(not(feature = "wasm-test"))]
419#[wasm_bindgen(start)]
420pub fn main() {
421 console_error_panic_hook::set_once();
422}
423
424#[wasm_bindgen]
425extern "C" {
426 #[wasm_bindgen(js_namespace = console)]
427 fn error(s: &str);
428}