1use elements::{hex::ToHex, pset::serialize::Deserialize};
4
5use crate::{types::Hex, LwkError};
6use std::{fmt::Display, sync::Arc};
7
8#[derive(uniffi::Object)]
10#[uniffi::export(Display)]
11pub struct Script {
12 inner: elements::Script,
13}
14
15impl From<elements::Script> for Script {
16 fn from(inner: elements::Script) -> Self {
17 Self { inner }
18 }
19}
20
21impl From<Script> for elements::Script {
22 fn from(script: Script) -> elements::Script {
23 script.inner
24 }
25}
26
27impl From<&Script> for elements::Script {
28 fn from(script: &Script) -> elements::Script {
29 script.inner.clone()
30 }
31}
32
33impl Display for Script {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 write!(f, "{}", self.inner.to_hex())
36 }
37}
38
39#[uniffi::export]
40impl Script {
41 #[uniffi::constructor]
44 pub fn new(hex: &Hex) -> Result<Arc<Self>, LwkError> {
45 let inner = elements::Script::deserialize(hex.as_ref())?;
46 Ok(Arc::new(Self { inner }))
47 }
48
49 pub fn bytes(&self) -> Vec<u8> {
51 self.inner.as_bytes().to_vec()
52 }
53
54 pub fn asm(&self) -> String {
57 self.inner.asm()
58 }
59
60 pub fn is_provably_unspendable(&self) -> bool {
62 self.inner.is_provably_unspendable()
63 }
64}
65
66#[uniffi::export]
68pub fn is_provably_segwit(script_pubkey: &Script, redeem_script: &Option<Arc<Script>>) -> bool {
69 lwk_common::is_provably_segwit(
70 &script_pubkey.into(),
71 &redeem_script.as_ref().map(|s| s.as_ref().into()),
72 )
73}
74
75#[cfg(test)]
76mod tests {
77 use elements::hashes::hex::FromHex;
78
79 use super::{is_provably_segwit, Script};
80
81 #[test]
82 fn script() {
83 let script_str = "0020d2e99f0c38089c08e5e1080ff6658c6075afaa7699d384333d956c470881afde";
84
85 let script = Script::new(&script_str.parse().unwrap()).unwrap();
86 assert_eq!(script.to_string(), script_str);
87
88 let script_bytes = Vec::<u8>::from_hex(script_str).unwrap();
89 assert_eq!(script.bytes(), script_bytes);
90
91 assert_eq!(
92 script.asm(),
93 "OP_0 OP_PUSHBYTES_32 d2e99f0c38089c08e5e1080ff6658c6075afaa7699d384333d956c470881afde"
94 );
95
96 assert!(is_provably_segwit(&script, &None));
97
98 let burn = Script::new(&"6a".parse().unwrap()).unwrap();
99 assert!(burn.is_provably_unspendable());
100 }
101}