From 8f22058a592496ed937bc274b40ec246c62e2bcc Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Sat, 20 Jan 2024 11:34:04 -0500 Subject: [PATCH 1/5] Experimental Ordinals Support --- cli/src/contracts/request.rs | 4 + cli/src/main.rs | 2 + examples/dcf_mining_pool/src/miner_payout.rs | 3 +- plugin-example/Cargo.toml | 3 +- .../clause-module-trampoline/src/plugin.rs | 3 +- plugin-example/nft-auction/src/plugin.rs | 4 +- plugin-example/nft-sale/src/plugin.rs | 5 +- plugin-example/nft-trait/Cargo.toml | 2 +- plugin-example/nft/src/plugin.rs | 3 +- plugin-example/ordinal-example/Cargo.toml | 66 ++++++++++ plugin-example/ordinal-example/README.md | 6 + plugin-example/ordinal-example/src/logo.png | Bin 0 -> 114777 bytes plugin-example/ordinal-example/src/plugin.rs | 116 ++++++++++++++++++ plugin-example/trampolinepay/src/plugin.rs | 3 +- plugin-example/treepay/src/plugin.rs | 3 +- plugins/src/client/plugin.rs | 2 + sapio-base/src/plugin_args.rs | 4 + sapio-contrib/src/contracts/channel.rs | 1 + .../src/contracts/derivatives/dlc.rs | 1 + sapio-contrib/src/contracts/hanukkah.rs | 8 +- .../src/contracts/op_return_chain.rs | 6 +- sapio-contrib/src/contracts/vault.rs | 1 + sapio/src/contract/context.rs | 41 +++++++ sapio/src/contract/error.rs | 2 + sapio/src/contract/macros.rs | 4 +- sapio/src/template/builder.rs | 67 ++++++---- 26 files changed, 318 insertions(+), 42 deletions(-) create mode 100644 plugin-example/ordinal-example/Cargo.toml create mode 100644 plugin-example/ordinal-example/README.md create mode 100644 plugin-example/ordinal-example/src/logo.png create mode 100644 plugin-example/ordinal-example/src/plugin.rs diff --git a/cli/src/contracts/request.rs b/cli/src/contracts/request.rs index 43ced0b1..46fb6954 100644 --- a/cli/src/contracts/request.rs +++ b/cli/src/contracts/request.rs @@ -73,6 +73,8 @@ pub struct Bind { pub outpoint: Option, pub use_txn: Option, pub compiled: Compiled, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub ordinals_info: Option> } pub type BindReturn = Program; #[derive(Serialize, Deserialize, JsonSchema)] @@ -271,6 +273,7 @@ impl Bind { use_txn, compiled, outpoint, + ordinals_info } = self; let use_txn = use_txn .map(|buf| base64::decode(buf.as_bytes())) @@ -285,6 +288,7 @@ impl Bind { emulator.clone(), "mock".try_into()?, Arc::new(MapEffectDB::default()), + ordinals_info ); let mut tx = ctx .template() diff --git a/cli/src/main.rs b/cli/src/main.rs index 9287734c..bb46eda0 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -499,6 +499,7 @@ async fn bind_command( client_auth: bitcoincore_rpc_async::Auth, ) -> Result> { let use_mock = args.is_present("mock"); + let ordinals_info = None; let use_base64 = args.is_present("base64_psbt"); let outpoint: Option = args .value_of("outpoint") @@ -520,5 +521,6 @@ async fn bind_command( outpoint, use_txn, compiled, + ordinals_info })) } diff --git a/examples/dcf_mining_pool/src/miner_payout.rs b/examples/dcf_mining_pool/src/miner_payout.rs index d4d93d34..0f380499 100644 --- a/examples/dcf_mining_pool/src/miner_payout.rs +++ b/examples/dcf_mining_pool/src/miner_payout.rs @@ -152,8 +152,7 @@ impl MiningPayout { for pay in v.iter() { builder = builder.add_output(pay.0, pay.1.as_compilable(), None)?; } - builder = builder.add_fees(self.fee_sats_per_tx)?; - return builder.into(); + return builder.add_fees(self.fee_sats_per_tx)?.into(); } else { let pay = Box::new(PayoutBundle { contracts: v, diff --git a/plugin-example/Cargo.toml b/plugin-example/Cargo.toml index 560354ad..7812c5c4 100644 --- a/plugin-example/Cargo.toml +++ b/plugin-example/Cargo.toml @@ -16,4 +16,5 @@ members = ["treepay" , "nft-sale" , "nft-auction" , "clause-module" - , "clause-module-trampoline"] + , "clause-module-trampoline" + , "ordinal-example"] diff --git a/plugin-example/clause-module-trampoline/src/plugin.rs b/plugin-example/clause-module-trampoline/src/plugin.rs index d909564c..1cba6120 100644 --- a/plugin-example/clause-module-trampoline/src/plugin.rs +++ b/plugin-example/clause-module-trampoline/src/plugin.rs @@ -63,10 +63,11 @@ impl Callable for Wrapper { amount: ctx.funds(), network: ctx.network, effects: unsafe { ctx.get_effects_internal() }.as_ref().clone(), + ordinals_info: ctx.get_ordinals().clone() }, arguments: self.g.clone(), }; - self.v.call(ctx.path(), &create_args) + self.v.clone().call(ctx.path(), &create_args) } } diff --git a/plugin-example/nft-auction/src/plugin.rs b/plugin-example/nft-auction/src/plugin.rs index 04b9cb12..4cd85b14 100644 --- a/plugin-example/nft-auction/src/plugin.rs +++ b/plugin-example/nft-auction/src/plugin.rs @@ -22,7 +22,6 @@ use schemars::*; use serde::*; use std::convert::TryFrom; - use std::sync::Arc; /// # Dutch Auction Data @@ -145,7 +144,7 @@ impl NFTDutchAuction { let amt = ctx.funds(); // first, let's get the module that should be used to 're-mint' this NFT // to the new owner - let minting_module = self + let mut minting_module = self .main .data .minting_module @@ -162,6 +161,7 @@ impl NFTDutchAuction { amount: ctx.funds(), network: ctx.network, effects: unsafe { ctx.get_effects_internal() }.as_ref().clone(), + ordinals_info: ctx.get_ordinals().clone(), }, arguments: mint_impl::Versions::Mint_NFT_Trait_Version_0_1_0(mint_data), }; diff --git a/plugin-example/nft-sale/src/plugin.rs b/plugin-example/nft-sale/src/plugin.rs index 2b4ef4fe..96782a7e 100644 --- a/plugin-example/nft-sale/src/plugin.rs +++ b/plugin-example/nft-sale/src/plugin.rs @@ -53,10 +53,10 @@ impl SimpleNFTSale { let amt = ctx.funds(); // first, let's get the module that should be used to 're-mint' this NFT // to the new owner - let minting_module = + let mut minting_module = self.0.data.minting_module.as_ref().ok_or_else(|| { CompilationError::TerminateWith("Must Provide Module Hash".into()) - })?; + })?.clone(); // let's make a copy of the old nft metadata.. let mut mint_data = self.0.data.clone(); // and change the owner to the buyer @@ -68,6 +68,7 @@ impl SimpleNFTSale { amount: ctx.funds(), network: ctx.network, effects: unsafe { ctx.get_effects_internal() }.as_ref().clone(), + ordinals_info: ctx.get_ordinals().clone(), }, arguments: mint_impl::Versions::Mint_NFT_Trait_Version_0_1_0(mint_data), }; diff --git a/plugin-example/nft-trait/Cargo.toml b/plugin-example/nft-trait/Cargo.toml index 7bb68080..d0190e6e 100644 --- a/plugin-example/nft-trait/Cargo.toml +++ b/plugin-example/nft-trait/Cargo.toml @@ -15,7 +15,7 @@ serde_derive = "1.0" [dependencies.simp-pack] path = "../../simp-pack" -version = "0.1.0" +version = "0.2.4" [dependencies.schemars] version = "0.8.0" features = ['impl_json_schema'] diff --git a/plugin-example/nft/src/plugin.rs b/plugin-example/nft/src/plugin.rs index 93127198..9e9aa4ad 100644 --- a/plugin-example/nft/src/plugin.rs +++ b/plugin-example/nft/src/plugin.rs @@ -72,7 +72,7 @@ impl SellableNFT for SimpleNFT { fn sell(self, mut ctx: Context, sale: Sell) { if let Sell::MakeSale { sale_info_partial, - which_sale, + mut which_sale, } = sale { let sale_info = sale_info_partial.fill(self.data.clone()); @@ -83,6 +83,7 @@ impl SellableNFT for SimpleNFT { amount: ctx.funds(), network: ctx.network, effects: unsafe { ctx.get_effects_internal() }.as_ref().clone(), + ordinals_info: ctx.get_ordinals().clone(), }, arguments: sale_impl::Versions::NFT_Sale_Trait_Version_0_1_0(sale_info.clone()), }; diff --git a/plugin-example/ordinal-example/Cargo.toml b/plugin-example/ordinal-example/Cargo.toml new file mode 100644 index 00000000..943c8b3a --- /dev/null +++ b/plugin-example/ordinal-example/Cargo.toml @@ -0,0 +1,66 @@ +[package] +name = "sapio-wasm-ordinal-example" +version = "0.1.0" +license = "MPL-2.0" +authors = ["Jeremy Rubin "] +edition = "2021" +repository = "https://github.com/sapio-lang/sapio" +homepage = "https://sapio-lang.org" +description = "An Example Sapio Application" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] +path = "src/plugin.rs" +[package.metadata.wasm-pack.profile.release] +wasm-opt = false + +[dependencies] +serde_json = "1.0" +serde = "1.0" +serde_derive = "1.0" + + +[dependencies.schemars] +version = "0.8.0" +features = ['impl_json_schema'] +[dependencies.bitcoin] +package = "sapio-bitcoin" +version = "0.28.0" +features = ['use-serde'] +[dependencies.sapio] +path = "../../sapio" +version = "0.2.0" + +[dependencies.batching-trait] +path = "../batching-trait" +version = "0.1.0" + +[dependencies.sapio-base] +path = "../../sapio-base" +version = "0.2.0" +[dependencies.sapio-contrib] +path = "../../sapio-contrib" +version = "0.2.0" + + +[dependencies.sapio-ctv-emulator-trait] +path = "../../emulator-trait" +version = "0.2.0" + +[dependencies.miniscript] +package = "sapio-miniscript" +version = "^7.0.0" +features = ['compiler', 'use-serde', 'use-schemars', 'serde'] +optional = true + + +[dependencies.sapio-wasm-plugin] +path = "../../plugins" +version = "0.2.0" +features = ["client"] + +[dependencies.sapio-wasm-nft-trait] +path = "../nft-trait" +version = "0.1.0" diff --git a/plugin-example/ordinal-example/README.md b/plugin-example/ordinal-example/README.md new file mode 100644 index 00000000..acabbf6d --- /dev/null +++ b/plugin-example/ordinal-example/README.md @@ -0,0 +1,6 @@ +# Sapio Vault Example + +This crate can be compiled with `wasm-pack build`. The `*.wasm` artifact will +be created in the `pkg` directory, not in `target`. + +Feel free to modify this code to experiment with creating your own Sapio plugins. diff --git a/plugin-example/ordinal-example/src/logo.png b/plugin-example/ordinal-example/src/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ff1bcc1cb1341823b1ec78cec3e3babe95942653 GIT binary patch literal 114777 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 z zdyrZ7UrN|@I!49gl;Z5hqV^Vpj=sJ-uKk6q|+;C$@3ti6P+YY3YL*>~?7 z6WqtLFY;<1(GTc$8)M}vUBl#hwn50LxG(#>Zs980p0SV^)37kobtYyTnwh3%J(9GP z;EjTyjA!%Ken$@}4{8Z(Rkfk5o+-FE>GRxFz=SrGawdfUcDFVARx@fj=ep;)?$ppW zKC`}XSU!LE@)3_#g4h?-rrv!e`q9+z-#@d${#UzBxJwM~`{4&%G^`gnec7S|;I0?L z_6q0$FkvhUCB=6?IKd~HYfP=B!ElS z4)}`(k#piVXjl{x)P>)_T}7cAu}%k)waI`T6NaA(B(u#7WgM#A%fUZA!H1sKa{tnl zP6Ae1cbT<3=c2TpUy94VpnZ!D(2oPjk8|N4aHEA^0wxzyq&6<7Z@D>gp^viQ^8SEk zNp6~`SOIa)5b&^E2l=d_)a|SeDC*7pDB{>L$6ZD|F?Au2jcvD&uSmoi-~4EB6Fk*&Fmf|86Kb z)YY8zFB?52V;4j*Z?e;O5c3<%`59p>OXdh5?b|`-1%S(KI#^XPJWRkDf{hPYE z*7MetZ$-blwm3g?C*Qcaz)Al?5|Aj#Qc3bg#p9)L`;~f$5RQUWQ_jgrh+%Nq2zp!? z*NP4raQKxDhYI&(dr~pKHyogkl^}>DR%oV63U0vrKkiG8?=Qpt^4LHB2NyfM=S&A9 z9epiqnSrMCIM8TO8#?FPH%gLkR=wNif*I;2+3{6)9Lc_W;Ce-IZpzQ;VuD0E!6XZG zJi*lh2+jiMJjpk9hE!(4jV`HJK5{i?*J`$*^}l01bAZMXyG~y)lmPV97kkt>2iT*} zlmb-wi8h=2Nt9UOm`2rzA{fIb>gdJ=yk9BHl~}3`OU2JXLGX|v{LrmAnuk)u z{mqQ&Tqr{rhZY{kM+bKa8JVN8b62=lAXtbL%iB~A_LL|1e-D=VY{lbmuB{NRk11Wv z@H6Yl@kWcouwuVsS=<%$1Nv5a)HiEQ#D-lL5=v{v=`Ywp`%!F?%nIW;yg|#L63a)P zY4FJFZ7$6PtX8%@zDB}@n#Xshf+1Pd8?g-V>|{WCRB-Q7!c@bV3H5{KNPrinM+0*b zxi&|ampX=eQ}^G$R)S_(a%wu@Kko=Om|4XFPHb|?E8tPj=?F;UIPfA*eqEc~ZgA0( zqR`>WF9ea#+>=n!EK7pa_7iD=1(Pe%^zAC3y+5Vjny;Jn7EQL@p?L-wQV*}--d@U@dQnz zs{m3HCxq1$f)ful*F1)`MpjNZRkv zut@{|YEJ}vA{6jTi!n!+QcAHQh%G8(yyUDYJ_9%FM+m&sQeW3Y3Uj@`Qyj7M6zwuk z^m*x83aW|WiK{U)lRi(@eBM=S+?n*;9+&Az+!q_q!QFKW1NwO-cz!nE*wK)OzS2Og z_AKi*&(y5SFF6V6lwk2~wiS(X@_}h6hXe}-8%hudg86BmM_*`Bdm(k8ylVjCbPb;S zjXF;qtI+ZU&s97Cpg>>0+P5GcBm&w>uvAk0OQ@7tYF*=`Ev*xB@bqAQo+@`K${b8r zP7Hfmu){MXN?csHukz1o4#O z(!C*_lFTJW1Q3oNXTfXQk-#(y{c<*0_YSKd;MwX3wV7PYu;BL&7s3fP=B;xJDRbZKAm4(;D}bI5oY@`ni zIkJ{g$sLh;7mHUA&hYfWAxTRxzNG7mLgz$mYcJ=S%<$fmZFavI)ePuf<{IT8 zz2FFIyF4!M3Yf2X%vTgGPqO9-&fH?$z$<~|m3ym@bJ*YN`eZZX*T1*Q?vpV>=k|}; z=9Ei`3;Z&JBd>HQbqxN)RnG4SZccXvSSTqLCq1g+AYhg|hEh-LW#sW0<$`Ql=oqb6 z6ff@yd8+QeCBdKGQo!H4)ZxHlI)p6=b34@_aat9{>fBZ08`a}_41;b-_63WI&U!|= zgv%uXg&?0J`mKO6`1*aR;eY(b5(l5ogM2T+Ygr!rlO_++ zboSMzzk!{>i#I-2tRM3^{>6Y-B1L>RhTr&rUP>&YYd5q%$EwA#(V#_OiB4#uQ<}*a z6V#V1uTS|K0{XlX{O3u3Q_}!|&#tF@xT%?JWKQ3FHG6A-y!^F$tCpYp$_k$-t$~2m zT^|4BQ`2uth~$Q~IrGm}4Vg@cKG-PBIkCl$yBSC>mKCXltNtBy(~K|_Vo$JGQoK_2 zHl49}}0-Vt^Xz|84 zuN8~d-mh8;x}M;2S#4XC^r9zu@o1TIb0PI+#=}oLOGb;xM>ckBix~k)U1B_e@dTZU zL|WL}%$RFtB%UD6kHHn}b8xc6oIv-3zo>M5?)Jr>7|Lq4>c@`xumRd&n_d%dqH`xXig z>sr1GRfSiUlq-YRS?y|SO+5hq*QzU0(Qz+X=XH*G9( zGnWS16@@MdH-6p3O1n5pvJ&t|j=O;FKE(?ku5!MtNbbh(n-kFge1D1N|FDaLi%EYb zR$tFJ^n3@^aSm&$V^Iz3+U(;l>HMyhF+BLEO@3X2{9v7Ls_)5)(n$Jhun%!MZH8s?_hH7kF+kMR6 z3sZwK4wRF4kV(0%)T=5M-rvsn=*2GK$i-)*pfl~Ek_@383fe{z;}6ukdV8faB{}tA znM@5j6v|jCajw{gBn!mto7m^)!S)d18LmY+BC2DhgK4YSQoEc{UC>;-FXTu2Bfff* zL0BS3uS;Xcp2uFhJM37h>zdhxlq3|Sg(S-gH}77od$e~6UJ2z}a$45F@6DAU*A?Go zEW1)ml>eJMW5dT!w%Dc4uaGYCeEf<=gNS_*a7E$^StL> zv#xlOryrzs zvEjaE#zaAPJ<42g^0Xz;xi)q|bxTVzBn_&CL$_-Q?Le{?Nt(XojjG4X+o&o%ni#(L zYLok)ZQ(cFyj&)>pIiyM#XTr+!ZHf7Nc8o>ZT^>h?M4on2VHObAO3%GtP015XY2d5 z<>Si<`&ZMx3fk;S%8{2ll&Yg3{TL8e}h+7lV8c;qK>OFRIKLDWLSu_v_Kj@QH)G%KrMH8vv-kB<%|yc) zyVRQ+-&npi6L8AA^IGtkfUJ~*4brXgO9Jo~-TwW9hbMR?xC?W?r2&1b^`5roOV6$I zz+W`+R?SA+$Z;*Y6v7LdU|xd+Jt0~9gvaImArlSl+Ugdnt4`LnPa(-?kU_&$@m`)d zptvTw-IN7u6CO`Z1)RHu*`OHHuI%$)p)YvRyI=$sDO|hHRTG9(2?A|+G)sApbZ@=o zNluj&uLbg!6${g;;mFHvq6Ixb!S)g|yY=VMQ&7_-!IgUgQqM_<_Gm9!I{D4@Nb$-J zpJ&S+o!cm>|Ll6oPoHkH`${^5>@PJ9!TOl4RL?WK_$46-TCN3tBbNm3X=WU`nz*?+ zmU72Y!{ita`dE6QfHaWAIYq6@)WUZN5uYazMu7cs%#<2_97qCV!B^HO!@ifvNK;fA@uTmTQXNzqfj~D&I~4{o%y$ z(S?}%F2?LS7b8;Z>@U5Z5@ap{lWk1@t=bsbv=W@z6_D<6%1u#bdF1sL_1OIYp)J*m z8Q!V`6AcN>s4Z@$yt3);R($oo$}I`z0;qSj0~cB+h|#m0lxEm^(&o`m=in!qdpc|B zDsQ&MRCCi?? zt%CXAT1oig(`)Q`x$CO!w~%pJ30YN=mI`lF3Ys&Dt2OV2ULc=dOWD7YGSSj~`BOhn zB5d)Q^ejvTq`o8x9ca%AXq6@BW*uXtw^He7P~WL|Z>iP3c?(yJm6Pq$A+l z#`!Hc22O2V(L?Fv{gdF&KUiLNg=lNT7pVBSk;hCsr7Ilw!2g%%!;HM6nd)wz)9 zgNB1sU4ph@@|6^CWwgySkk_rhkn(|7S6O*9;7<M8q{laRN7uDubjFi>ZEwWH?r`k6kBsGDOLNas!v0G!rIw@F z_L9kQ+eI3S%5-0a@l@S++7Li3HXIU(Q@_icVT&*Wr?ws-t{2pkK(aLDabbr~Bap0w zk_G?H3R<(q^2HM^p7`Tcq7!-;ggDAgmxGZRB2U^AsGUgp!s#|w@2zmwSvxav!ik@t`Y!K%8oK(XV#Tm6($G6=`oVU z*6Co+J=`T}J4=5`he?K+syPUXsSrihHP1GZ$6+|7wy%)OFJDMNN zMLb#anKG8$vmxaIj^};LDfeIMB28}6Q!s;xI)($yn1g5I{?CqcV4xMSR#PqaO_lBj^tZ9z)7E_P zg>{ZS-9mNqj6HRTb?b?1R~`Ao4Hpf+`Y*5Yg=xi`kCv$~XVkBz?qcH_9Cx6-+r#Vy z;|tPAQd-s2-b@jxV9Rb-eyHDfp~H{r9w%=yNW}unB}FMUlw*sh*$~)A%dm26*xk@D z0gIvHcu8@_yM40R$Uv>B@z-sC&un-sW)RSX6<7`9dh=F5^=d{rHdr9>ZZCJM|1=fw z)lbgwz{fPZW5Z-(c<6G>!#`@d{o6Y~dYC&+0q@xdh!(cM#Mz8TUTpICY;fH~X0(8l zlRi@|&CE)!2A5i*u65^ZOE;u#(F8#i+T+65t*w=!^Ho(|b#00+Y|=!`M)*n7(n1FmO*O2}kbFrV?EA1k2l~diAYkdNF1Cl>~3a zATnozZS!Ot*m{&yNJz7)M87)>>b7S<-*A5O)~OBh3b^RH)}!Qz%@4h>aPYOxKsBt_ zmDxnMyZ?uP4kc-HbHp{SSA{;;HO#a%rPzscc-jtWMQ@Df7B3U{+7hLP%7kUf7o7Ff zZNrYa90*ow9$8tS+G7GiuLatZ231>QA&l=Z1ep?aJV7jOuU1`0;3~0D@jGYRyzl7- z)i<*t;|jLe`o+q;{}C!D=5jq(2K-sw=g;as5~m9G!R3Vao$WHYk`3{&dx-L)6m0K& zS6i9~7h`5S1F?!!3NDoue_i#iTh%_cl2=ZlE>r`4{FX_;R`<>|n~!#=pc(x!Qro`j zoEK|KErZVGf9q=*a|;Ps;Tak!xIFFi)Lg_fCABRtH0!zlL~dZy_dBoU-v550q)s7l8JqCd+(>$9mibnNbd}as1O$e;-L{$)Op4^#K z%-4NR)I5$yic7aSphgG6b+a=E=fay@dcOnhc`@QCbIDPvmK6{ z@AjotjT+vse##K?-6%&x^)k!h^D&1DVxE~NxU@6i)R78jyc;(jS|}-!Z~(?KTLq4s zZ@xV3@wEr4JXzcNJYBAN)Mk8?aU-Hi%TQ`*m(19W_m**XZ%!UJ7qsbABxxY}$oktN zLH8v8=3`S#e5k%5X(?xxPd~fP{_l41*38DlUFTzu1WIQ$kNulf-tVsspNFd8%ty-n zub-Uely^7K-_U^mR9W%VBQkSDenLXTsA3FplR`% zrtfZ*OiF48LwtKpx8Y!3#GbXh~T&I98fZv+$a%eH>bNfB*WLvFtYL?Ot8{qVkj^1f9o-<#0 z{6d#q)0#in6%D<%C)%2iUFtHolnhtn)+GZ*2~_63U=e8F0pxngk2E+@9&JejNwcbG zY+@>81vDbL?MzBq0=~Y9BISoWnw=+NM_b-R<#LG8X!6SbZrr{#0lm1^l;Dlo0RK~U zJZ-6T3DGqfF4=*KDyBlAdv`#Hg=>i`eL81h$P~29#-#5-R zP8v(AB#{PYJ1H~YkGE_w_fr-L-9w7T9?xl)d$6*@N8bS#!2Y&VQJc7!p*qf#<(d&| zvwrT4xIio%UQ0PL9}^~)`f5hdHhl`%xS&4zg0&~;mgU%B)sC*ePC_*?Og099)1Kf> z8i;}LjTm$hg&h7!rM670Yf5cHloen$u6$QqU?%8q*%N3t2y&+H179OeoNibD8STV3=qukT1Dp)<_b9FADT~eIb6Ea^`T#O_aZxC4SvJza*-^XK#q2AP6 z&d>)JfF%wDKbQ&merfy9&toBI`4Rz?6NeRe{G034Ur1d7XSNPp))zfL5=xge(Yz*} zRXq2p37$Dr=3*pi+(8$Bm0$vpQf&Ne?4T8yOi8jxkcEQwl;Y^6nBQGXhXTdby2rCS zL%w@G=dQUcnbZy#H*V0}^HIor(N|_$o${F9;j>)XxMx>G$&zey?QBZ0Y@Oux=*O!H=iC#dJ0ut17jbc4fXR!iRwUVx8P0i% z^lmJ_@d15zYO5aE!N~9k|oO{&$lSW zhOZy3jBWMI8q24a6F&7qgK|UDol!(f+RY?2*fMtfTE+P;wQ);tz| zLV(5&V|lP^m`u&4g;c05VL@@qZUOB2Nq{=HYP}jrUY!m&ni?JnGj_K1JHC)9v~jf* zyju0{h}qitvf}ys%Uqlb`YqydtG=GG|BWv76DiT<0kCY6lsURX-)lm_xeu4PRP}!1 zfSw6>v+mRJ1%ZayM#h25F_Vj#lV#rQ;wiXpRaY}+uBLqdkqZC!{xaPg_}DD)mwO_9 zIJ=RXUNV*^&Ue^1pWr8!AU1gE@ZK7iWU0*d{R04=DJz~iT7jdL4d1^{TmJUx7Wbd* zAPd`F^?c%c_gqi(Mq8?@n)3QElJ0X0DWAzX>skrU?+y8jd&=7r7&o#`dXj(eiD{00 zbc%oUSIZpvW(zUuv|)qlIlFMERajN+evex`30^S0Z577n&DcDD59zSh>_>t0vF z&B!z5=67O@W_?ep@>nBdrl-^;V9k@f7D-mN8A|kUX8Fw%O(&fRgozkDs@e_g;yqbPb)7q^5+Mqi-hRD|%xhZu)d+Gj96l)>3vZ zr&QN8syEKM23Ele2s}d?D4LOE^%@<*3rg_qy(JbZ9;)!OXPOy%7Sq1{YNe?uuMZ@V zM`^1;7yQ^&IGHC1Q*+zx?R6n^TQ=;Puj&?L@S=~|{{u{9lv^9^u+Ty^|9oOYDJ)h}9(o;}7V>D zvj0Ah=4T|--+5LfaLDC)OH*rTXKG@u-6VHiB{vt8`ArnM`>*N`Coh>ATB#BRT@eTucnmhK5cO~(%NrCm8!NIw`0YBQTVzxLST(3OnZ4zsT zzQzbowD+2f2Rag4&->rTY6>`8@mLGwhKu5!wUmi=MvxZJfkF_Z88hona6;)}@QjxS z^bN0DI)3_XcPZo@njz5?Grr~73;dq899+xDl;bd84dfjc(8n$_B9m)|@dsj)AO@DH z@2C92>N1m`H~hzYD?hPEys%JN(*#|+5p>FM(?#T$b{Yv9HIKvd3BNm^46!z@);<1W zZ;4lLpox&cf&0S5&Hh#9=H^3m$uY`t0)aFZYXmB@R9c!KF~p%{qVB!ry#LwK^e{VcU%T7FItu&x0 zUG)Vo+*f9De~7dYC5C%Wb(uby4Cdw5DUOZy0<8q&Loy*To*;_^FF#u0506!^oBimr z6g*W{jGC?s;I}%OeVHW~YNNT&M2%66v%<~W%$O`SQ-Ve)iMJs*Y|)ea;Ad(~d{FmW zjlwzv|Ir_`n0PgVmfiYdRFF*zvZ`SAYSK3cLBM?%yZl-pIlepOndyMn?f@Icb7jTz z4^_ChFF@o$X#c4$yPoMfj|9uxyV$j*bVl>gi!Ex+jAX>d){?^t$Ui2E23?LoJ!h$BHakodMgTE3yH6H2-z z>1MXE8OGIYr5u;**1uEns-3Cjz*5T0)znq{c7)>FfJE<`0HLu1P(YrgkXFl;Gs#pl$euFL|Soxjo*|{Fm#R>61wzm~V1e zMNejQn6h%c*QXm9hu2cV5mA+TTjOUN)!~d}NT{QKCo4g-tY}3em$88Pn#W&Fhg{l* z0I@ec!9Tyh$_E-52O1eWTAImbhM!uZD+bZE4pXsJX=TA*uz1TE)mJm_DgL>H)kl5i zKjRVHA#Ka=mK5JDaLUUT9)3i#_cIy+OvZ*MUTJdwA2o-46N-8dqm^c2nfr2wIni<7 z8szgz1=*w^{8F9gr-Drbx&_WF!Fi>qTKL71q!x(&{_TOkdK&3tI|gPDt)y}O_Fe|1 z*lh3sF?c>k*{Dyw>=oiP4&tIX1#kUaTl zjjNGFBUtgoJ93Bkb&@KL2W}iP~l$iqm5p7N>TCF>=t2MH}=v4As6OCF4a9+cd2Z*CZHGB@!cUi z-v z_nOX@vnqM=jOZ0QPMS4XpNIo;q_t+d6@#-;%BA4;AN119S}_nq%jYB*4ueG7+KdxG<2#Sfyl z@7sRW7rd}HVxi`-Zz*N(xp-)#R(w7xwS5Ym_612Kh?)i!TY}E;w^x82m(xD`#Y$*S zc`QF(+ZF-+fVTW^UtM7KWP;x?xi(1Q%-it+-D?@9FQ!B-!%+cGywv2}{*eFc!3nOu z%jIEjSwR2&UC~bzpx@4VAT|8L`40D-i~C;3{a{gS28?c?ToXKt#7(7yjWvf5u0rny zlDO!oCgAFX;(IgUPdxv;6>CpwDCfYRAs}4O%68;=^tJ!h;A^@fNGBziABk9=_J*W8 zn`Oz(N=ttZH41?QhAabbVR@!cWI z?=W%AfUneizLE>BNZ`}!Deu1=vu80O>KOdk^nt6rztpF-<@-L%4VJp4>-+inz-L!e z9=+UUqUE|A!a{Au313OGkqP6JDhDDbRybw1dm9Ug%y_HRrHtP*5ZiAllo^^O zN#cv4A0Ndo$SFNQ@%Kcf%3VWPtmtzO^!r1_OVhz^_iS`7>albzU@}T6oz0N(AgFI> zYcRsMH=r68nHZWi#if}5oy!NWM~bIr0!LH2LszY9sGmy-FPQ>3ZgZ}f^#wNC!q^5! z16+PE;5$Dx!SC%YUH8{q)(#OrwU`mM@?gG2S*t{DUdhPISl;G^akhA4mckNFZ%ilTQ;eD^SDYZ0{=Tp2w$H?Ru z0MWPLrB7crg#=${@Y)uu!1(rVBkxWR=$~Cr`NDJS?6{ITgP7Hvm)!%}ZMFj>G*?*WLpn8Iw@m`a+(^rsz7Orw2;YRr#Pi8!U_`KAzOPZFt=BF z`kut_Uz}`l>_msKWf0bqMNSc_&qgqy8s;rIjNM(sfqT={^Geuay9fmVi|sfd%W(HhSc{ik9~zecYO!W&HKV$&@w;XS zxYr9PLxtjq$avBHG0?E@%`ShtFdi5RzydDs4){;^SNYKbf5eksGaeSsuu9J!!#+2}!>NX%R@Ig-#&o24ZYgu$|XbYM5+fOrJ`K zuIPaQ!)QUI1SZJs7c&Nc8L=@?J^1AYM`qic{7{*dy2r%{kLDeI$iF@pvG7|vnQm)m z)>HVi`_6PZ_7_c5+YY$tTO~(|zPZi%ZjZI-?RPegEu|bg-J!asou)g3%UEhQbyu_u zIx-f}0i=-}w6&!evJJg1=dPDGN=Qn>?^PO0&^D+PEV(%l!^Tmfc#l|1&;^xc7$rzU zvEgUFrGRJP$Xdo@ue1nT1IcG$z>5tk+1Smn(hlgfIlwq<8ET%UlGFj5 zk}12{lgmdRe%o^FwKj8?V!l*XJb$#rf7l(d`YsLb-n-_VzMU?e1+P1Rz5hJ9#sz1u40O=Xdd{>ChPZjys+=iKiDq^l9y-4 zYkL1riRDP8jmRx(ox|ZZBAjpzgLBVx`K3!4pPe1_=8Y0uI27{rV->zy^WXAW5_ys; z3i{>6;L}q9)4mJb+7~SC_BlNl()EX*pAmwK)t}s_AQAAFb0yByeLi-)#mtp-h*e^R zAPXeI7*sZJd+d1@_ob+d38--;VwYd-=zcfP2)I1q@x!{$iCZv= zY6>{9FQWV&LzF8-3ImfDQoN2C>=`4lcA#=toU0p8^!JYSAzCv8EkmbnnAjhpc=xV5 zHlTmC=JVB0Oat)WoNM!$udLv8EL)^~*L^7qJ6jq1781%`Glb|Dn{^O!^(?J&)0$B) zL2J>;XHc;sk_KRQz3m3O%J4e)X(39RA+q0^hNd5c?W zh?*KN9(d1-{On=H26+sIkEe_I3er$)AnApv!P|mw-J7HDJW}GY>{4p#4ee;rt6=lH zA`1nLx}v(ShxFksu=_&7u1f=$p7sQ99*#I$@i=h{B$Jn=;Qu^WhJu{&4rBSv^Brm( zjj!RM7h9ByXq>=K|1+>X?QgVl_S$#vg?CYferdvE@nFErnWS%b zvY=B}bSsK>MbdtoZ9iqfGr0nlwwnrn3^6rwp%`tUU6M2l6cZ!hYTf6>>3~&FTvI!G z+ddN|`SFCu2NT22m5ln;%!zUN#kSiR6N>Yt zw~si!lh!{wQ0AZIS`7d2LWjTcXUndw&M?2ZKT{vwm)eQ^7;%ltzVOKYcq)LY0P=tL ziz^8qJK1LEm5tuuDpzF#P>IEhU6rZxsyyfpUR3Yv`Z~AWQz2NdC`!{_|Mhv9#g7es z#}2sj1v}?)1wn7`^{t(K!8?I!ElI(XHJ^nelE^j9w zYpGvIuX&esrWBot?RQ`FgFJ8~v;5EJyOfvpfW}6lxGBCb1&!SvfAygn=c^ux6kG}= z>+j-O`nw~bM~d_RKYQ;PV`+AucmB>fZ@Q^+b$4}j?w-WS9F9m1MN*`wKuWaNtA*rU z0fJU57&Z*}!veclf7xglu=k6B{k8$J9As;?mewmul&BFiMGhx$a^g%+=iC)o=bxVEU`%aQQ(4wXy-|^F!xJ!6CkwikdRCCE z8D9I$M1TC|Mz}vW+|$-flwGr(Sdw&2U*&D=c*(Hcx&?_qTgXDm($IXl0j^afr((Hn z8eM)GOjyekOF2)x*<$a>jK=8#k=-P9QW~;kRZ)()S-MrpwfT^xi2x&<@W{EzfFDdn zychUwJHX#R-{DJNS)z7My8u&eAn=V%qCG>G(&_N}M%I^_CK5EU0v(5y(p z*$}BMN!Jjj7HKSTW(kKz7JCtyDh7r`{V_2GnUEhSp&Q`kSW-Vw;laA1QEIYRGDBmv zD4R9MmkP$+n?)>WPb#h~gq&Q6d2J>dm9`MDUUs_QtOEFaqIiDD1O1S;{OZLnkG`@- z+;*Fduw`yI9neozm!*Qrvg>Pj^jeFDUuX@@rwf+$h5X6KZf$+LoyY~OOb1Lg3Su+r z39zZ}NkG^!9J!h?+tU5x$&}!&*@$mUgfw^A60j=>{reTg_aB;ohbH($NAoN1wz%i* z4wY3y*#6*MiuPoNdzNx$nnk}ZXL=5Dx4PI!Xx5$o`v0+z+;!JP;2Hs^FBMcTyR_oQ zQL0U1Kjp(YdAjI7yy>)LeKMesg0)0)rV;RFHTbCof9_WF%|^<`G<&mA%ra`1nPv8k zjOllCOeCm1Ug7mU(NFZg^^RfovJ;Vt+J>-OW~$7%2CrT;=030v1v-*siQw{L#KpM* z;r!~EHeV8gYc<7>rXzk7%b)5#Jk&0DGK-m^@si(b61S>D>I`=@D|^c78X* z&vZ2ptmMo#3ug;DMB+xehLw#T@I@dR^LFj-Z1Ko|W+eN@H&n#P z!zwezW>G|L-F$HG25wnCa&4Xa5=nPf^4wDmUbv@D$MgB<`L0PSu}1bg(d0$1Dzklam>VrRIue||x55kaH;+snUe3AaVoGIbRutT>*hqm8L!GJuvPiNz z;dI!0ov2noE0#=UhWoLIT5#8iqpV25*XAPl!ZZ(DOsRD=wU%b@dl~VnA;7uu^+NHj z7FRn?QO=`}zqOJxzh3a_M{6|h(@ZTFRGOyWJuS5*><$+Cq9Q3Gfl)5fS({We>xw)O z7y*|jLe3|*zR5hFNM1ddaDFZ%)RyU{rc$QagTj(@3_)&7;sG5xYs{GoIbmy~?&|ml zHD1eTTrD^%Vdlg#>b-Pf+0>PVl0}hoeIj5bly@DW8{o1OJUbl{8q0|* z8A;c;W+J&c^}BHvzxT&Pg0+JIX-(3tD%Q48>e?-MqN{oGddA+h0%2kCV#cADJIHc= zS>|@sYITF>w5}LTBrxUZ*w-Fv@E@ms`iS@WMDhH-@f(0IujYL2?G_7X)4}GqTRQJ) zx7i+XJi7t6hiyZUS{{F<$wM!#0N<@DzFV!JfWLb+W&T=D61!$I zRc!qkdVC>_rJ8BNu4T{O0%f_a_u#vM7f zZt*i>bQdTGsjdFY#*Lwbg{9Kg#9gyxBq@e6VZGT~VV(79n1a$~uufGaS-3l{#mP|e zGg46PxLR3rMv*6iiSq?P%ewQuarU;S=U%4kP2jqp+cnAmyIA4cF79$&>>3_@x5J@V zJI>cTwdHx-BFNo_qkt;21Z9W0FhD7o(~Fk{c8h1Vw~_wo56A*}D996clS%EwT(F~d;6`bE2(JeROR>1j*fPXh1V{X@)CS4{mY#XPCK4#++v>;h>3PVR! zhkF(~9Q{OtlanEZ5WHShocj<6u>h`22ZV(ShNiCO)C+Y4>lIEkYwD{IS z!bP>4r_gr^p&#pLCR%#Plto}m)rYZ3H9H`TVe+o7>P;;Dkrho5icyh_jdjPN+Hg5O z={C{QS)b;SB#T8~iR#L1$m!|G>5)f*%hBDdMLumT_gqOi^iH=g&nt}6Y2K9O7@k}y zmCsbyGI6e;77L_?-#FDK3j~+yisvUo-VS%Sx1v=7T^&SiBbJ;3(kV%6R*@&NKSman zjiP%`XZ+@sC4M~?uHHHv*-ALK81s!|Ri6GS{kD7Q_zSb)h*a#s%Nd8>>YxizlKaqg zx0@eTt6Wo>Rf5)xVtp#WNLXzsIzItH8Q^cGBhEY#P|=ppoNjZ^TOI1x^_V6!I~We= z*~I3Sux+Vcccr5ucBKoW1QYjFP#+MXPZ`U{Tbd^>cBy2B(?=5oQ0-_AzS*VP(StR| zZpbJMX$Z{xIOEIbmM{v^3B~{Yt26w;TztpxQ7s@1BoiwIamP4Mc!nZ$yJ4(X(ih#z ztCFlDY1b8PFa5eZ2z@3qSYUNNK;@RWV+gX*qZdOdNF#?HhK*K!Vl&YPxy6VRvmwx;+-?e4ua2ejpZwq`cfM8+A;Y)qwEHM$`6HcK1# zUsecbg;Mn{teg7sM5H6G|cDM`L`yuzjVa7(R)g{v6{U+EI98=^HsxNiCxqrT(a z&<$?`D5|1woMCY$8qJ2HqJR36{6egFVM988zqb6B+OqgwiY$7@EnB?)U7HwKHhC_F0k+~oc1{26l8=(&ZbqmK< zb3XRNb>gNOU5nbbZ_sly&3hq0wA|;Gh32WZS{zx*d43_`nVS00R2Hoi=)fY4=Y>Fu$xnEz3rpwlf9*g z1i5tGx<)z~SEF1sJ|H5l8ocDWfS(^=LO}ez@)Ww{T zA+e5|q#6P8s$g|S-BFv{?TF_S#q*05ScG3)&H3fmnjCzyGtw;_q?T~V^hRuCwGEv} z!ic_>`R&FN&4R_t87gx%an&6|Om`QtKO3jYFJUKJsRpFmwF^8`p-(rJ{ex;iTP_ z8~R;A=x3^mmycGc=9WfBvv@gUV%bRx3P2W4%%VSYI#h2IVhgYI4J%BCjpO0X{BaT_h}18S-_$fAstR`L&dfzuRW!T0zp%eZ6Ekq+Z1qmXpJ2_1;2g z#b|BbNI|zIY1S359Io(xE+o79rdv{ilZ}vCYN(gp$-R>+HYk|gOaR3yC@O-yD(Qxj zld;_OovybMN^WVPI;70jYvYdB3_tUYH9nfGqeH=qPuBUP<27Et4ZR(`_qL@6Hb%Hb z{YEL|p)8un+-4wTaPJ)dew)AdQitD31n2Hg_{&EcPNH^PWDfl1m6XrE(qzx6v@GYi zkv%MfXx$ELijUpngMiux@toI7ihGOEuD)N00`id0%Wh3A(8}*Ubf3~gpwZgKm zo-%zdCuk0xvkeNBwww?tYLZirRJb}Dprs&Jf|HZsmY(e&Bo?&gSFWTyaK1}8q%9HV zmd5p>G|1XKjxpS@Y!qDEAMy0VbykM%$5g`UUD!Y4Q|>@Bl&m%a;&K*O^yYI@iz+3O zh1{@y^lIkAb@Cx!#oqUf6l94LoY;*!$V1xl_SaCM)KpuVAhVkSiEBp& z3vOJ_EqCgY^ZR4Ev0(91#=^<8?}}Gh(R}8wR(L929q|KC>yqa_TIb&!sd8bL5&c&t zL%#CVG(0uU?_TWkxo6jyC^hp{X5G0PCZ}=Mv|=1n-9A|5>h=9MG_Fn>w97kV+!Tpr ztm0hnHjt?$uuiOK?n2J}`!fzrgd9mVk6z1|?3j_mon6V9yq5O`jE0|cG3LFt3%*-b zeD`Ojc;qp|=Pq`cEGI{#h3U0|!*6t{pD&!NA+FvYG&T1>-Q@nE>-+Pe;OYYrXO1SM zk^4p(O8(+-h3AqFu8TYX>ZxIRxgZ?c)T_Q3%LWboaT_o#m{=~jm?*wi-Q6ATp3qDD z>14>CPKN$O+y=}PmgCDgM=qr#-O-g$X=hp!cMOx~@=;Z&;l;X)gr)@Sdo!g-1TuG| zG-BQrxX~R-krMB~)DpA}(aN9)0K=whb; zsx*F?=@x3NVJ0WM$k{W-_AY3%aP>eAvd!{ZTT-wwYl$mEo3@eRi5dcu-Fb^Jg=nbyL+e0CiI)(s|PB)@^>O6@YLxJAN}?^mC^%1h%N4$zA}{Sv9N&~ZJWBD^E)rB zGIK3w>Ow)-F=Z4kTpx`d9qsEy>FK26@{x$u3Ab!o0c$nI3kxw{od|c1`lxkww&R)& z`_F9KqS|f~WGaG08NTpFlP4RBm8#-v2P*H|w)v_Q{MG)1H)bQ|x*Ao!e`qYnFK3*{ zJH#ymJsVZyvPxn@FF=r4e&P8wo}3CWJqN}>@YX`iU+jrFzl$<+p3psRE0zL59teWm zmJ**Eqi@J6lGOttm7zI*VR|Deb`wGOHvwuWdQyVUjO5vmH~532HBNgu*wLsWrKRw#QUG=vLL(kM)GvkHHBGa zk%j9NAIHwMO9jU+7bEv!I;D`GZSWV{kkCKY)%@Mp)_M3_O*hq$4^>cZ)NHyTW)_7d zS}{EMwRKD^xN?8Y%k%O3CiJd=bD`v(w&pXhH%UtE_Aqk>K0#_WW$iX)-pVXe(lSih zfoW47NgA^u;V$cR_k`|oTX9AS&Nl*%ROOb|v8u3Si6oER(`clN6zj{H>hYtk6@#mY=u9Tg_w-8X90G1C$oIV<}UQuJu`_+2Dh2+jQAN}h+ zG5`7(oB+yiT+jI8v#T6@zUzp*u!ziA>u!olhsi)X0=F7;B1&C*_xs~I*~fXt3*jVZ z_g~KW^udB}ZD;KW0X8ZtC zJfVBsesq+eRaK}l#4N0((lG?ZAO|eV2CcLz5k|SDsMPjTZzHQzspniI(%Ei$Y{Ki2 z679qGE2u_8P_FcME zh{f-m@y2r=9~us5%dem5@W6W=g50Hrm2s)hq-FY%meUKceaY7zffSM8{PBeI^I>1O zCsTrF_QbrLsJr&TeZP1-H9WSQG27N0zLas`-R>4mi58W)MzNkrPF|N}6)`qqx|4+d zw^wpLak|5ilO6WGm=azY@=~xjBXlq|fk}F`bw)NcFeb{s0kTQS_kU@U|M`K&wo1Jp z(3b!7e1~884@<;(!0$z5LNk^nrcWC%c;8dSQ({ z7c!(7WJ+Ywn>N}|JQrgwvv7V8-HP1QTv3FAHxDO#Wq-mucj-u*kI+3nRI~)VHx&>a zikVw2*mF5Y<kP#04S5OKvY?=tlN1es4Fo21 zjdP-~E~8{N{L)q=x0Cq63`z@IhRs`*xynd5S~mRrt4&TUM11XFh37wj?)QtKh4ws_3=znQ;ZK^;cfd`U2;F_7JD;~F)xTi>(MKlYSneYi zBo~a@0{ssaWBtX$wI^E?A4B|t_{)vfNx$i+!A&?<8$1q+4#;*o%xfQmJPJDfJDWS* z$*KE#jp*D)6ShW;;3mi(EEIz_!P@}alMnMT;PnNR=piQHNHZY}L`@T9No5yJ(_|!- zkNsLKiLhEy8=!=3NkbS-b`ek76Up%kl%UPWpHsISUMJ$@k9$D4KF_{6$1S0w+X?NV)R400Osu(BR?8NH1;!=Vew zYd-SZQhC7fTtK-EHt{F)bt5jDmh}n|V$7@^*R-98Qp_m4-&}AI@h_#WNm`)CR`+6_ zni#9*X+?f$db z9}8M$fym#9LrI;zgtm}`IM3B8m{UX#$q6oSl zo)`Qxt`Is>%S8G^^cQ%qJa*aF*B995L{OUohNMlp_8e{Za{gcOz*8z-Yh4(>!iZBk z0uu*>4e9HMsH+CFk2TTJTs~HP$&0|r+h>@G_<}8gFplnYyg)z2wO|YC2n#Rft+2iA z&D-2;>-*gcyZ%MuQ2H!JdpzeV{SY%?`rk|V`9<-stk~blIUGcKoNk|zDc@>(rSs8Y zIhe)wmFCbuw*As{e5^*Ll)!7@frK`G+(x->oLklXEw_5dCY+ z_pxJN--;~3SejVFzVo79tuHw@`t>^}%V+28sruH9^3{UE+OgpHr?J8*!3KWf`rT?9 z{mAwiA*>81?Uf}*(S|pT-3+p=h$)vl)yY^o{Yi|v=RoO}gkzD`?I{m_h1`}v&-^M~ zw0P)DTU||!uGYflw|SUB6=W8dVt&T}yIkq{k6K=J5zRC&3X!A=#|8^F?I@zhOz?6q zi)};&H#PWo*3WWjkhJfG5u4;HEhwJ$}^ZSm>BS-v968#Pm4V9>lT->Vn9cKQ^0 zYrw>~OAw>k0QF+Y1=4Eauh`5sXEGh2J-XkU_#3Ql{xwu)>KKQ`WOPc6h|XsySIL1_kwr|px5P%vAE2TqwJ)30ZPjfbO_F2_+_V=iI?7WZO6TD>7OT$t^{8UsZeIf5C z`t7CT3-89;57;cgn|2p~f!3l8=Pv$cddTit#Asi~Ep#!W6{CFF?o!Li32!|w{4Mw5 z#kYI$_&4_bn{bz;769FG9D34@x#UirFnT$8KZ|n9fe!we;V^o0B?IvW=m0wb{&0b9 z!*ijo@XBO26N7odEFAM0bJ^}h5}vO3o;hVX2WoK8y#_K}H|F*wSh_pK+i_Xol>%jx zy-+E2JVt?1pAG8&V*z4_Wbw<>1Pwuy+JozhTceWY7r3sm2-@SAH|BhN9e^g2fuKEj zk8}A%JPVc4%EOVK0~GZA35(xUO~b8Vwm*R4iQ*UJ{+j6DOTNPN5Cs?3T)rK%f@-OW z6AF2FsSP9mozMi59?Ph%;Sjv4Md%-WFQZ?;qv;@(Rt(zNNWJxbN6ERg?takEJh*W! zXJsS)$!e!%U&pu_IQ^dANaZZURXZh`GwXo-tS6hUNv#Y2s*Yh`0@=;f9o20 z>!4=1d-8Vom0qRtw|G^VOa?1vuHuX;;wu+ zmWsuWR3sNTg)Cd=k_w-ve>IVPP@b(LF2!AaNRtVJwqiP2bLdf9oCT)O=Ldxl0c;Wm zhrkKQvIVH$i(&Li$v}LxnhwnLyWC>T2qJaFPg^9%*XRrEdrap7w%?S3!G!mL+n?fT zb+SXSe>C8pc~_24<0B|s{yj<>da;BR3{-1x2&(5b^FHYIvVPA32|FGneq@tX|1|HS zJRJ?6i*6i+_mG2>zjrx*Xpu-?>0DZ1TQ{LzzHAT0yxows19#uLkqRNS8e7fMJQyU7 zGjnB7+ul4Gyv>sY!rWOIwLhk@4LPg(0`Lg916 z5BYx_l77#~9x9ZCjo1yIWPs;#Z4kAB(*+4bcl*vtoC1v#H#P+83DgU4*eMX#L>^Vx zR!u~YZe+*h_k3>;k4xnjyTp;^K`k;)9`t_IR+dt)~8VB{lNNQ3@2zi zvN4CaA1#71(9@v_GJcH*dwW2MIdJflXTRrR4nzZ9I-p+NyQ^M- zcoo?+uu}Hr#i5FbaH>@S@}yP{incUGhUEnw)yTIMm}`IkyV!a@Ag`DTom`TR!~l+fZ~XscKY{ zY?5HXN=b&!dO0RMJzk*xJ@e*0*r_1YO0Hj0yTAC6GS8+;5V^Dv8g7dR%oH_&#O?_x z_SPum8yO;jj==;p6^%rt6vF-uz{C0Xx;LpTp|uDh*h`nAo8cu+jqH`o4a0Dbk>EZB zvz}~~^9it1Xi(gM84lcu{7q)Hv`l$0O+&J{ENJivKhv23)b_Bj5x0OQ!{9tr8SaBo z8P28F@Ma>Zsa*hW(!{->t#b0lb(zj;uJv(;xhaexUKEll>Vz^<-K7H&BJkr75d6f* zse$yRSp~*#7Nw_!8wnRv%IZ{AN~tl?FpBkx_;pn{=Ed&21jGnOL4`P+Tp!g*+cej{ zwo?$zL&H{_N|XmwB~+y70)J(H8Ox>!(*z>h4=}4JU0zu_QJq2r0R-<3BKDJRaQ}O8 ze~m=2%S=P1t?|-vkwiqdZ6XqfQ%vb+$JaF7NX8!9_iagvu%YBBct)z$U0+4Y^t6Q1 z{@%4pcaR5BVh*O8wbP9z=b=I`qYNoia-w@A+W&78AlfL?>gd&ijLFzfR1%klNNr@4 zg-d(pZSi590h9}iIvM4zQ?e?~zo?7K!EUY@of->l|GB)Pq3FiU%{LNcv4?5fbLprKy@Z8xLaf@#H}0mcz+ zTf~f(HBY2hmhtq*(yh+@%7vmTOJOyfD3c7!YdATO9r@JxkFNJfTo8d?*G~ieDXwl_ zEHltlzgQ;?iB#XcbRkxn%VEl;Puop^Y_-*s8tfgBaL+Q7CEZ{rl0)t2XFHm%0$M5Y zSZVNtB57OO+0Bu(V>$Ber0Sq|&M4o1o{=rbLm3q;*ae#y9t@6Lmz1qJOa6jGUgEGZ zX|TxFwYc?@`&2U_5J$k3fL#*N#{|C2oQOkg2R%U$w2juiR?z5QVdGJ!MriZn#!LD6 zKLVjXd-lMR4*UuWhfXGqCt>@A<$!V$W>$K>LOOy-_(pUi?3O(GNKk@hXHJr*JzcAU znmRvkn+=LaP!I=dy}oFb(cK=5wuw!Hr0u{9g7-hqeKX``VGM~JQkW6tMInU+BQvCu z0+(l=lH49?TZgEXAOCjzD_9l2J07;RZmMI4PTo>N1~YkL&jc`_lYYmmC6q^(7;==e z>8J;t(zzNH26SW*W3Pg>?X6s*A}1XJ3%v?$uPP41AZb3%R7c&eBJ`4joYBQtl1w_5 zD%Y8n)L6%{T>~U_EM!^8bAR1P5AO-yovV&M)A0ZQrsa^d{s71pQ;3n!0xxIGo~_St zZB8-j=9SN|{PrHn4Upucig97*6`jn8cLgpLT07y1S1Xkr0h1U$Rh6C|WEM5m>DJc$ zL`?WrSX6AS(UHB9qrx2iwPchuOnxy_|NF2(|6l-Y5H5Ztp$8z17NF^`G3Lg+v#Y}v z)l*&-Xp?|TQB&%MVWWD}X%w{<#=l3^^UlxV*`LWB;^CxOVahha85u!MkhewaeHfDx zv_R3sbvgfI`6F8}&I?lOzdvFldfAzZGRZNabbM(R{UJOmnq?gWteMsQ7aC>Mkn{@g zlaak5id}hWrt7*0X!0V;QOOPT4v7mE2>}U&_LCK*X0>#xZyBY229yWSL)7(u)Qd@G zF9?pMSP&p$Fd~4mg|rP=J4=sWO@~q+zF3U}x)16?cuJZ8{KeWNhT1x!qs$Zb!qVce&l6|f_a3}vAxnob2kdqA)kyvZDg~5%BoS8bG zT#8P~IxYjg@l2%94n!2;(N(VaU~`>*5uJe)#u+l!ObkZ946;*0$u=q%6c)C8Z;poQ zJ;ga_|5yjU)Qq7OjYdD(NA&+!F3@S9Kh4>x-rCO0*rKg?hI10Rz2LT!=E`7mr5TwF zLO0O^Dm`Fo?a^5YiOd)$)u%?*T4k?brw6K0v^%Z{rq{w)N~dOHMJ0q2G4F9q{+;HS znQ~^{CtTsl^aNC(|EgaTT#%`MK`5Lo5vTMoww?RB-b=< zrDUem)v-G5Ed6hu4uMXL>YOL z#C0_)H7A4Q@Y6iN<^5M#h!gEThzb^>Dqp0@@zPdZKq<6`QnEl@m``tA#2i&$x(+;x zT4af6VMs?Pdk=wxpe@2q{4U> zHcz8kxDP?Gq#8}e;)y9O-W^#WnqdX0d7E}e{Q0j+^(jNaVn;Rg^#ulMr#R#e72bgS7pgw z^Bc}j!F^(bEzxdgpk|Ss)DA=jwtv~5Gz6MFLdfBABzFI^Gu*&P9f?^!KF-)Bri(@O zcoK35qU!9_P0m))SD?G2=3 zx1y%m7FoKEr{Z5`!Fh2mBvLF1CUj~5B$wpY!a~pgP2@*yNk%D*#0S%aQ7*l8pFgXX zRAmklNN@++!r8EBhC`rB@oGA98%cxh&yOGPE13J(H|bbVZFLyhHB~@M#CeB-k%aB0 z>U{j<&_@G?4 zout&dwjX`pdqf73tMab~t5=EB1P(Xc_ZTE?p6wX|09zNM@};QAA%v`nFGJ;#k)i_+ zaVeDE63mNYd4dACo-H#oFMu$UjV57*gJtFyp+f=r8-_$*k@M`La(1PW;n*UzFtaz5 zarNM)JfFMq>J90_yCu%I4u2~d>4cL`xP~A{WtVCUCnPa9@A5k*q|?EfNiSeuKzjVE z`z{G74V!I%wspcJ5;{gPetl$o`@!jrT+_oSu|p9dte8I+n%gbkc#;K1M4%UzBBkYU zggR*}0ge9O;BGr2Y2~D0<0P!2+4?ej2lK6`i?cuTzH$!*ciXL*EY4@@q^ag2UvG}d zOM;!XEY|70<{}QHM9Of1pEv8qGQF!m2rT@ikDrz)~z>;3{aSMjY0o z1H(hl9jG=okl&k*1ntYLyj6^7V1Xp(x|D52*EJB>KPYX&VMNGW^?K)Rt8tpoHb;d@ zZ|Z8BBJCky4`QkYdPZBTX!7d>O?wWkqw#f%Y1$R`&DJ zCsVz@=U>4NQ=(Za-AdB~sBg`EK-@>H?o3%pi#n-JC8a*F)u8G|n-ug9Aa_Ah^8^|;v1meb%!@kv;FR&gG>)G~_aK+^jbRyM5ReDC%I z_PxOL8yJBL95eW2ny3Abxd_5G?HpvPGCE8jE;OHRVkTin0P^iSB=t`y>~4qtSTJ?z zh}kESUyh9@R~g2h!tn9MEK+UyD!LWrh*cB5G@>D9)?In?OquNR1+x3G)E%V*rOp8wtZQ zsNR%sC3v!rqaTjmz=M}iRvZ0M^x=GDMW|MVV$fs8{)6mjamBuEf#t+sBac8svHl9Q z%g_o_%i{g09vW_)U-1H3`%&OQw9P zYq)x>T`xip8~XiyQOA1=@z%vB;J6pjJeg{zP43^%D?BAr*dP7T*l#&4Hb#! zrK9XpSaJq{w(E}P7m3z z4<|CH+dFG$=~;(O3@04kl)jZ0{dV4VFu8YS4!B|m8W&-yG)`h%iW^EgGn2F{)Hl{{Yy=I3+Q2m_}IhG%aQ&~-Bd62G7X6&pz@C^H8a}sSlnA+`4Z%5$) z93{dze@*$_?p-K3RCyqhwfa+pqMS(^AC6Qwx~45lo3Ywwf?dE^o%v64zlYdT%t7g= zL$Y$AUK3wEbc%LcP;=zaW(aEg{^C3zhf=6JBUEF^)?xz5SSa{e7T=N0Q_8C-IhxEG zEmUJ#q5Fg-8fWJ$sXPj=GY^6CXva-AhO~fSlkupVVHRvySw=63K2$^H6j%PCz((+R6$?FPgd8A#09@ycr6^wU$M%4XR5kJ}VpM^`I@SnIfiMlGf)L~}^#*8Tp}yG- zXXbYrMZW``?(lgOrKI@Q^*H-$HaBP+CS}6$wez}vurE6!SvQtU0}YD_;!KCv%(NF; zx;N1%Vcai&L5OQB_c%uL)#ln^@Vf97rXXCGhS*>WS-<07u_I*${mRF_a%?FMwzfz1 zYkUaYleB+%NKQIPRVLSnRN8s2c02A;k^vW^lr)i|i2tmYMf_K8!qtFoK$|{Tj~?VW z>SV}ko)z5NlY07+AL8G!k8e7vRD@pwiC5 zXZ@KM>lu5z4gT8OkDqkBk)GCVJY9+N_L?>ZZG0TA$v_{n7BdQ55^ZQ0$S`*L0gUKR z)En1SrW?>hNy}YSFZ)>88vK}qvV=r|oy49<)|;>PW0Bkp?p-X-@-TCumEOf!m8Hbf z%48zgZ2pk2_ta3gXL=+|XbSuXw9j?m15ug$37xmtsHFJyJRXK&<4CgU0tkb5srW5RS6&D=Xa5$UtGBi^*QKvN1YzglcQ+TyB64F1KOju4E04g;@- zyD?mFgTHaRyEWe?WC&O1qLSX_nT0uBo-% zQ$tF-{_v_iu4g@;=Wev0VjcXs23^&8AZID49MDf?p8Pdq0@|;fKS}vUVnc8Q0qN0N z_^QKD_3L(tUdSRUr7vz{b(r;!+V3V$i=LoQdgT=}Rs&TqEj4CeW|H>Z#Y0hfs*dKN zFccAg5H~)eDVzzFN-l+*YsNP1RumNmVh(x5694mYhUj406w`PtY&E-Ov}~uS>bRg9 z4ukuD9}Y1+oD!9dSE0|Z+IDryK5MyO^~jE{VTk$6d|<@=?$ib?}?9+Bea~N zq{olq6u@L!Tjp&pfv!!7a9ZEi70?JMhiMN(-)i5-+_t=1Q+(LzNS4&s|MPmT`p^wn zXyHKtUFtW>E9yI=J(`>t&xG>$r7+18Zfpf9S_Z?Jg6ntfG;S&pTlJp2=nA0F6N%Gl$$MmH z5RQs(Yofe@qsc%YTX;v+-x->6gn4nP-0dsQdVLH!py-g*or31UNRM_9JEwb^bW;4skjLAC#oC6*bQJo|74-;57WEPsr+%SEeBRlz{7(_ zdkJ3BsRA{W|BEK7qZ~AMV5EH1VT!3fz(ucGVg)9q2AzZSTb|IPl;Bp@?EQFeUh-+- z7`-xHB*9(0-4c)eA{>_r7#<$dB)~58%!O^O0ZUEZwb#E-3L%*alGw3gapt1X=O}C1 zL<28asbnV%ccK;^0ZG?U)vp-DUisuFjE65;4;D*r@Q4-PKJ{zJl-O>LSe5u{kNi_k z0zRQ8W+$CLj^8Qk3p}Q>504I?c9L@c7mrNz&akiLIW;|9tSRpFG48ayBdhCAXndm`aj8iOCagmtO#*@Y=ht_4H57$)A)%h4t_R~@ z_Szp8Ot^Lnl#F`Q>Iw*ySyaUftmE1f66TTlR+kS)b20Rk2zFU&xhx#7{eMD&J_JJ& z<4vcYQ-GoGp2pTPFn?bBzNYtgk@UUrqb%PG;1(5!UA>w9JlH~k3T+5#flwO@X=65> zCouTtvbsqVPEhInS!^{0{==n3gd&}73*>$S~zJDO*q@1-tl(+ zE|O4Hj^t$8+=U5C5e4|;e&e4$4J_;W)d9R{VA@f%mPSm9Y#XAyDSi?@{`oYI)%S|? zT@wpeT~qTMHa~VYg=H=K`vtlZl(ZJgY$>T*=+B!?-pZ?jJIT*vC8JQX_)+c^2+~dG zHNVz0YNJbpLwg9mI%vmqomBXYmzo#1Y0~)PP%o8{1BWIZ_x~k+@lkQU)MNmql0+To zcsEHwUF&(CQAM{qliCKF8!?1@bP%z?=5hA4nw8Y^iVX>p`Z+M3_L+$uP7{)>^^RYkfBG;an@w@dp} zPO(p32m|;OwwUWu>#yETF`t3wCCd8PTntJu+8GE^L~)Xy+$u}!6Sj)A4JzABPrL5e z_u6Eo5_tC$&W)mw!t}kI$DlgLAc3?w=Vq&OMJN|aO&g$J6WP2u3Cynuedl_uc8_PD>k&+uxsT^*kPZL7T#wNQ4D9XDt7~qViGF!#uxM!>s|@56XSGduruR8U zI|#9t4V+8n$&@P<=CPsIaaWJW3-$qJuM_(|;`5-X$jt&ukpIJ&)yv^7fXn2y)RMBtZH|qMpaF?ouEaFUbfKS6OIAFHH~XLm z%FjGMKrEy~4mxn@w4Kww-(*S6yO34b$`Ni*xC1+eTTyoU61Dn9SCB-UvFw^{9 z=TdGTZRl=q#x*4Z1OftgvV4Jg>Q;9$ifOv&nv!+=Q+t}Xf4N1!=r+qM* zltLtH+o)?qw~iI*H6aFk3qTg@!%B(jD=uj_Uf<3?e_P-Y+<9?-nWw#%|dq`SPaeyYWwXI{Z@oOx>a ze=GpqR!}jzB%L@IJJ|2Cp?!=-#^3ErK8M1opfp^y*U_()V~#6tdANpv0?iEgIEV^6 zIUr(@X>^mj`Y8uwZI)I5mt962IyDB-uL0ExbmfR1W(CV3xrVRy2P_c&CIb#AxmF;Sq^-bW^?^C)cdOh&$25=2UVuTUMaQdw$U^wIUIxm6 zu+SKkDv1PHtqj2gor?7Qb+*Aasv{!El!#^S{)-SUzRD$Hq_p`^7qimE<=_cwH0hMB zbBI-0h_3ehr$&Iu9Qtj~f1EXx7gL@4UFqROhvsyiTqEbmI{8T72^LN9iHpV`7pM_S z?FHzYLC$*V`tH)^AjOwubx{Gf$_-A8MSq4QzlKue+L+FPhMHP=kO{QFnuSxiX= zF8O+>_=0OQWC+=$T~D92X}A7EftOGz@fmr-W5oWDFOxqPc1%(DjX33QWF;452Dp({ zLb`!7d{Vz~lFn1sjO6m;pW-ue=IhemU{}y%90L4(H+1Ua8GH8VEW>xP2D%5`KLKU> zOY&aJ+q}Xn;duawzt^DX>&57|>Z8fKn=Ye2r$%__N$x$YUp_(*!ssnN=O**&7FSq} ztQ}smVr}g~g`9=w%B5HS*6dDhr#aA)eo#KOUlZ^P_Z+Q_qE*xkni@I2_1ND5tvZe=RD8q4>T2m1A&-+W{m9jGYe zC1#WqTTNyrEC-9z^=kWkWrETd;g+`Zv0?NrgR?p!kLQy^P-(cHv#+@UjIc|tazGNZ zu;vTbp{BdC1cU?x3B83y{{L zz8H2I#A$^B`{mwy=yv$VxK6H3U!-9!(%r$Zw#*N|0o~J?;#^lA@5Vv{`SfjZGX(@m z)Ufmzm~UUvsnsrDpLfkg4~qxDLfNBeDD5lGE5ZU~Scn|hNQ*Vn=cW@N(+# z_n>AtJA;d%HyRG(!|-GZD3uDzh{&8I1HhmIzyvQ(#cP+A)bt*oI!sHxN42o=*h4eb6T@{2>E&%UV8~!qj+=Kr4k44Ifen`>CQi@`c`j#e|cv$4pDf#2jfIg6j&a zB6E2&vr88Jn;<*+&<#B&@{QUVS`I}zqcP$O5oxmwyp#20;W_I`kgR_5-8yzXMO^dN z`1d$i+L;RIwK<|x^1A!ESBsOD;5(tuNQ1j?EETfvrZs>y)gIg>g-^e&MYx5S!mmAG z^ZmVwTOf}PNYqKeKvBa@{ZsYT>!*V5W18i>;h9d_l_kGN@yx&mFAIqw;P|iU*1;vB zr2&wMfp>Gd)qMcK_2n_qldiwo*FCYE)B1<%r^Du9qpzMk1%G#%wZSV}n#rI=7@ z6RrKR#K1Fw;nI|m!8Qr9NUOsHp7C$HEZn31*ebLpcj_&Fa-yAcO&Iuo`(Zj{#mCo{ ztA5*R+Dr>PyH!NKnJ1P3>J15 zN0F$hi1mU<);?xusnF}911SW`(EPaj_`@o93)R0PO=j#XmuaDjQ`I*p8|S1jm7+va!_(HTDOAZLs+?wL1dq}a)dmI^Z?xoduNGP>A>5S( zd&&l(z&4eFL}AX;jq)8hHz(7sOoM;*x#UjnZcVu~l%-Rgibbf){q0xo{qAUej+Qe1 zk(+t{x|yY5xyQlq-1aS;JFG5_l=;JyrexI%^HYpQ7X;}M-j5vOa;GS1)?=M{VafAo zU;O>LC}Ri&SNitz_m6SSV-A*fmIzuT(9#;A6n)#%PLN9tbX;eGF2%c9@gRW{XJ)Dd zh`tgE5B9jtMS_{7Q%1K#>=?X%R0slQF=}DMdVbzlT1S=&H1saV zEG`&Pmdctp#lr3M3CgoPKr5_?qHA+PV$j8#uu)w%7IhqDP)Z+CU@HmO2oVwXiZ?B( zJxc|7r3hF>?OeTm_1fyVGS*;&jdj6ixLDNgkC$Oej=^3f=^)iNl&Nc<4i3ikWj_JJI%qX zUwJ)~Z5POiWIGN2GkZP-$U{ky$Uz7XmYq?szEtxaW77RhlQ8(*cSfhZn?=#ufYq?L zG})AGqOr(SW{P%(WI`SE7##&#J7ga`o66g82;XqVnbhgXdN^dVlu6#AsfBUGpqP9| zo+~>Y#V}eC#F{|bmu*(%EC$Wrh;*AC5};sL?6cXNZgtj2r=0GsAEI3_Yn+s&Dy&W$ z#F}Kv#SN%Gbv9Zn)q$Y|KkUA~nqg1+$L~nHzy5eOF)s(!A^8=upIMjyqgmBRn@88i zQ#aAT9Kc4Zg|IA2l?KCumV+bJbacuO5QeL&bk!#-+B%~VyADJDct$|AFc0Nqc;8U$D)~>GdG3C=6;w$+T0sir{ z2ZewraZNg{{8Xxc;k4`3Ooz5uO)W}hz}vn1;nZ6QY+~|5NKht%N8Wf5)UP1jX(l8s z#0JRnQ8p;=^^dJZmT_3v-c(vql~mu(_biCds2X&SU-66+jY)H*6)OOjrzxcvmTIqr zAeog8AzBw=S#kwf`V<-hhys?RLek~oO6TZ7y=1mOw-28^ZEB|mEhbvBnabS1V``fc*3?+QPGJWvekbG)(Y(u31=> zK&slmQTyvoy%q{9FJE*`Bu{dJ0wr{%?-?R|Q++YVtJ=bRxkEYJUnHTh(kBH3*|X7A zdab|HHo=oV`i*;++Qa@i?#KYusX=FQlDRWPBTYHbKt-_UK54e6^fY7IwVhJSS>|s3 zOJvtp1m>P#XfCFsY%p6ZT?D}}R(BA!{8!qOcQrUjUX80EpTRQJY2^ohLrP1}`oUl$ zUr=*8sh3@%A$%)Rah0z*-NC2-7TAx^_QUH$q8lB@2q#Q)K41o|sAVR#optww8?}G` zEz3;cH?N^-x9EF~SOMRNr{xrNw~s;e%nYP^=P`(25;y18;jDX73-MN0gNenD0soc( zX=fi(C#1Nc)AaGAr{mrDq`8uh6V>xSoy{+y9~MFMc(EoJD=f#cp+0ug7WZzK-ZotG zbF_LhWz7!(Hb-d0rM5y$aQmMXhslY^CnrAL^;owF3{>X9>P<%$>hEpNg}A@f$`8EZ z;<~Mxm&FQ-`#AEHr^cE_1axJjgaeg=szdkPxA`ZWIgodsf9_#6cS`5SMKA)wO(Cu!X>Pj6b_jW!%HOX-|55v(yo_X4@xa63g2gTw;OCu=M|TxM?jv=B+? z#G&XJUhvv;8XWmDfhdVl34`BCnqQaFqu(wK?I%xx;9rJR0mc77fAov@pG5~t+d`v` zaQ|$g7?-spM^(4cOTzT5yPBlrZnP#GHv`9OjcfID{<;S>wpRiuh_sC_eGpQON-$no zg8RSE!E!9q4sY)?b8zgqCpYhHV|r~~J$m}9p`@aCDDeEMI1d#!k2xSl<%ww6`h%RS zt-7<{0-x+E$4fCL9L}23yZMo`b-&{MmVv56#lqEjP0>8)w{u!J+$0AY%jTo+Er@JoQTVop z$xT~ReC?RgP#*G2-jCY(+1d@&Z@(PlC-h(vsq$>ObPlKbo-=IU;(03r*bWc25jdVN z8M*CwI6Q-+IlUS7IxfDK7!vC6V}_0IfC%3JN5#1-BypfKSyge0`UKlkv=mSBceJ2V509>Idt-O z90J(LHG(8@cq#&X4h#x@>u$2Bn+FDLUw(9wKgTJ2w|+Gxzrab4*#|iE$9_BPwh?z{ zAD}yb`&Z%*(C0BK(!F?fgtqc%7samW;;2Ny*$QeDg<06mmvm%cY&W>xqr7;1(Zd&W z&<*@RYH!&(QM4u1M$#b~SH#24**h99G>O4&3m_skQyP9f2Q<1^zY#nvO z606O_xU-V1B$lEdS@zo7=D&d{+ zTPGd2a#RXJoLe{wA9nw@t!(&@#qCN-Znco^-}}voAKsYWo6bz+vY}x>tV=)@t^>s~mv&H}1s6DxY_Ob|)2efNBfgWD_1BnT@Q>=lq)v z>~pk@xg-axOd5wsGyCzS^2pH?!RuObP@$Rv&)Nb{PljvxI`$UJzV-W(QHt7odB)DP zv#{K=Bj9JclF!)}_jmhVPkvt)&8~wr!OTg+7-Hvg=`#HbjS98%!Sb%-)$wNXAn{}w zg0wQSX`sY0EH(brhs@dO=!qy82pMM8n}q`ZzY>4cB_ zOwliCCxPzdzd0HEJTycGS&uhR;s7vt)0Afiay)A*96mlGW94mKKusc6is#K%C-es_ zY!O>HwD>C#b-l=xr<1T;oXDhdp0CjHNi~S)g`znG?@#HPmmh%uJfIK4Cuc~Tytt2T zk)V3fv0Xh*Bb;1_Q-E}i#j_NKB+$k(;iI@1Ns{%L8T|42o5FmL~GRPLz>&+t-=#^ipfaDeO@3ku=OKhqa48V6$l zbRg09&$&&Y^+q(K7e^3LzX+W?AnGrRbwhZ=E|FZRCPy8!q7< z)42sa^GD(VVE&iBG-JE8`h6>`%&yTD>J6281d^ruuoA94z0NJae?9Z@} zCk>D%?GC=fw@af9FL%O!ok7PA!jq%%B_OP*yq(EZfcz6Om z%T1~*RXeDr&mkk6zX&1n{b0FC4FnY`N?>v9XOs^5J|W0Hmz1)r&H7=4nR*O4#&2K` z+625q-I}`#7@^p+Km ze>tEZYyQACe%Yy&sbZ+341`ZGvB>ddtudSdChU$qSqx@pq<)dNG|ML&RuY#N4Qpw> z6Y>Tkw0t8GgVs7YD};64*b_-kBG^F762@7LhvnMb?`A3N02$}eZj-rkZImyk0{ogv zwYDemehkF08I_oE^~ZD0Gc^P}fptkXB*$U_gr#V2bU`*<6>c{J;{ezk-OZchoShlU zXVwzb(vxM_l752lh)sCp$w(UDwK-6)k*I3)+XdKT`t7oQxy|Ni6GMFh1Pm=SG0uT8 z)+>2@eeuyz1}eTy0o@cHZP$OVBG%d7w?GNbtoR>w!;1rd#I=&gS1kxOJPW z#9`dmNh7b)0%gjUx-)53=Rb1IZPe!?N%eM4UXPHrK_wU{XbmJcan_E>D+l*o;i=vF zd^sdTX7jwJ%m3!ox-$_y9HZZLvG{l|pJZ%O#CiW3h$Q&sIb4rLV?E_%JI%>keVY92 z+joD@@83Oww`ea@EGqw^jg{EgHPhGL^JpCwmV1o^n5uc>78l}4@;M;~S@eTGJ>eUJ zg%n9yQK8mjDWg=inzYDpDMYVnQQs_-mS}8^M+r+X*NewP=S8Pdu74jGnrOTub*eB= zHm4V}x(xnjw5g&wK%n~Hx_C9U(~STV`NoH>YZy8opo3kOs3b?LWUkoOu9*af-yx0? z$~*d2ZUdzDH+JF=`0E5{%rW@~GjoSpe3o1zJMxEdoF~VO=PA^Sd>J7vG4IFTMW#Nf*Z{L z0pdU%zZ+LM!`_G7FH{td-Bl&jmQY)cT~ArwNF5v26Hdmkw3wuJMhuP345Oe|QEbg9 zd@XtB)tGu_`Rqc#59(!rSLS?X?yhifJ*Bac5%kTDkf9%2-uY~o|8_m)(Nk6azlGqI zdc}L`>I?W@!{_8mzdN1jV77M;WJAAPLJM?{M>6#T^_v;05H z;l5a}!Z@N~rC;)_m~xc~enkbTwB>D8!}&b~jpUskRN$WNwTO@NW~~Wb=9S_KX^|Z$-{UP?;N1E!(Hs z9PZYh7?G|u%JCSwk>YYi5sO{+VT#N^4ACm^Ne{YlHh0i^nG+4MI6~ZSraSZ|grFHnp0BA} zlHJ>@mj?c5KHyL013tZx@cvi2% z_S&Uz9D|>Ht;<47y8y9~xqw{GoVT0Z9gQ7>4{j8!E%|(ZCFFcXk=;Zv^{wUTx=U2k z5uS%z;9hKoBUuF`RrGz$@Oy=IbJ}nFewTl|nene4oZ+$R{zFzCj}(ues==w+#A^%2 z@-u5OAAPdL+?5QkZwJ+25zNQg>RxOS){upw(NlB1e?(J!oe8EeBWJ|t2RN>0~F>nR`o z^G*C*+(=j;u{X>CtOQXU6UHJ_fl4f~F9#fqJrB9toSA8qV_#dleTF)madbj5Vc!l! z7G}F<$N%HntjDGw-jM-)5Y#NZ{ZgN!XJdk%xnWfxwWTHnm6qmsw7r{{m2iE*r*&HL z*d7h&yE#F{ZX{U8tavkD@Zw6qXO~}}%&N_$iLG#i&!C(4CJTf>7I56?FCRI0gm8q$ zrshx<^Bb|@m;K=Z*sdy`JR0%&`C#8l!EQ*wGYy{ucUL*%_nBXH{am44;8s)ml|nn> zk%Q^oEz~(IU(NRRD%HU69SHf!Q1YQyyKb~{;2|Ie!dW}2WXd;2g-w(Y4|dXkFW|uP z4~ns`Wxm-gpaj~7EOcV(Vb2isoyLflW>eO}1tfUpQ0av8wlm5#_SH_g%Ds!lW4Y z8|o=cn{<#P{1%I}0xK7y1zue>R#fD~8?frnBNkO;j>=gZhlqpk2djzR3 zxHj*xHsj$L%Ym(o*^VPHcsp!hE1cLxa3@(;ja8@r(b+B!zSyO)p5YgZX{Q4v5Tw4u zD9CQs8gzdEnGU*E!$VORF=^CN4(2fE(H6by^(CJ_d!50&Cj`$NiMTTFBdz7YX2zk* z31Oam3JYFrhNc+XCL(sAnpVjSK|dadcVvOUKj2e4X!iZ+;Zva^JQNXof`x+t!dfb^ zrL6)BfbuS;Nppp7iYcwvP?13DYzAg&|rqY@P{u~G`mfnYzqjUJgcz222te&ZXP9DA~lmy^7O2HCxVAkUO37m+7H zrqs*uo0g-G_BrD9X`b})F8cIe=ZIKW!0#S# zecY;rU%DDo>uP4iP;OFY0_l}hP4yJFH!)e63S7@p-a)d)$F$`=S7YAuWE(FjU}x)W zKFf-TC5TdoPKSSx#O32^`vr&VD#2>QqZ`T{9VH7`xD`phyA<%(HSd-uQ!XmOfBudJ zr!&Jp(i^NiA5Z0V3`Z>84slLv4mFa~#uSx%E=f(222TF9oQi1=IyFVRCTUg`iG2Me zzEvsspN~}tj#W678mc+jG&1nM)tIGbhOdWehSE5aYM~%k-e;L7Xw{vnp3Z~070?SL z=Ndj;;fkk2+VWs0BQ!7{YoeZUVn}+l+Mdv49^cdBvhFn9j@^7EgJm*G>qk=S7TPTGJ@QRF3J@S%WFg$XXGVIy>iP? zQn%jGBZ56fLbsx5h7u3o{XZKCzx4TaX3u6WxlWus@kA0-+!F~Vgskr5UUejBuXuQ| zA=+>Vot2QxO4>`_RB{?U5t`9WT^DMJ8PSHu2QDW5~Hk2wHVTOmG6?tZO2i+nq;BqKQ{Nd-ip?KA9 zVaJh(abQFEmft{)v&O&Ft;L_2MFP^E9I_Yzoo_s?N z#5e1DTVi<6^@M{hJyPA(dxm2dViqo>!=88v#+4;Gx+t7zs(F_AML z8dPj0EVRoJc)k=_rk{~gh*+_Y% zqWJzBD83WKhNzP>nzzw|76!--c#H>eRkF3_!pOxz=Vcs(jVh6MDIytu%?Mb>7IWjJpdVq5dO9;ouQla-+Woe*q!f~O;O+w2hEh(mQnTMnm& z*mDyUQd7##rx2_Fft&3OV?#HR&WOa`nk025;9SikI#HpP7!Gb`9KMn`d&*?8MN%e3 zfon6V%nGTRjH_w5p1B#j(s6$q0L9 zN8zS2_agHJ7Y+t|`B;UXD$WCe7O<`aSCnwcvJiZBA>gxrYia85eK^+q)>p1`?Aty3 zO*fW$Qx%bQQQK4m@d3#z@2j%e@CIT^`!=9wl3_2yGI3YL6ez_@oxr}AjZ$KaglhH9 z9anoz30|uV(>Mv#jznzK6+uZCe|an8_}M-)SM#jdmc@I90i^hTCBW-uJiON89p7k= zzcOzLrqwIWC4YCHc~A>`IG`BaEAz z2s6v!SmWoy867Ej(Z9KBJq5m2ReY_gs95-gN=&`0ofDNeoRKZBW!E+t&Kzrxfs>xr zj@`UH_PKYjD}m&hqaoKC9@1J4T}wInY!8{a&#Ypm&pwyj&5S4T`-an(V*cTnHg+Zj zPaFvO%bC4@^i9>;utST}%op@3&IWdCM)CO33ZI|z-!c@&iW|r$?^7zZQ&+w(Wp-IcW4d@r@9w!d^90bC?nK-$e z&El}GB7aDk@BWOya1vG<9#2;lKM0orJ~!vXoIe89{QcLu96Q%{?9_2Mz7*_65D)<( zb`^a2TI?k>u4Dsg$9s+i96nX$dy76_t$J@cOz&BU(jlAG)gpN z^90qt;YVNV4Kxr|8y@G6ROr6W^QR}^_m)F`Z#g8i@bl|2?>Xyw>t&;&sOwa%rgrbp?ylXi?8OzFg%Bk;m3ECyp!seBG0kM{p z{O-Tn=AOv0sEcoi>ypk#=HAkPZh;L?@Z561>Wt#hR>piYqp_)px*Dm)q<{;f#6PJm zUg}WCG;kxkZ)Wb+7V!Mh2>(5nO2@ExF(F#lqlC?Ah-t3HZscLom06?X3ho zCwT5db$>N;>2AhcOXDXNX|3Z1OnLrFyQ;woNCV0BInQP8Z{f4jO3;~6Q!Aj>jN)4- zEBxVNNPGt@=P%B9d@&EcXHvt@tOUIKsSfpx%%MbyQ!r!tAcoU_@7n=1qdkFV-kPT; zfMc2E16wI`{b3h>b=KqRtjAI#pUHY;5 z7VeETAGzG;$hDNHgwDww`~SD*_gcv;;f6-`>`nE}MX43+U3X)3+r5i@70_q3G@;KehmL}+$3G*0$g)1q?U+(ki zJUOufdNYczzN60X9gOyMkU!JYyzRvvi?1XD&30kg`EazOBSK-z@bNEga@T_~e|~@c zO*L-vfe&sbeE69*Gh2EBU6Hv*g~}!&;K@ZLum-$*QM@|u^TeBs!h{w+*va_xQ%#o6 zCQhc^Q4@)Oq*?puwSZE5a#v_o)Z%x=(5 zCOg|!>UrUG`Ws#T!A8a(e|U~BE(C0p3Xwe@(BIe7eEfWmN7Pzg1jfTg?n#T|FWr4GGkJ)>x%$zU-AM3kb>oa#Xn;;`;e-fGo z$2!g`(^tFA6|COM%eQc9E91yUO1-0p3Q^NGy(t-9SVOhv9Iv+9aH;2d*PmXC`OI>7 z({tYnIM&s??P8zVR)&`i*L!&^Ye3wycHn?90HgB$zO{Cc%ao97n=H)iK%J~?Vj?s{J#jO=S}m_NBc0|zzbd)3 z67Zeb+tWL*SorZ~$^&Z&)x=CBA@#22=nFAn)3|4`8;|&Mf->I18<@BZUn_dr{cQrN z6;O)}4ebc3JB_%77EY&z`P5B46-BqTAAUFYZDjyrC@*T<-JU z&uvk8Q4eR)Zx%)o!vaZkEY;^S4kng`_fA&odp?T2Z7b!}`9AecJu3TZr`#I>aYb_V zP(U0w=JIA;aeas0xCJ&N#g*U(yFypMhc5KF>$Uy}?6hzxp>oYkRjD$8I~;{!;7{FO zP^=&JrJEL=+QVy7kU^;~~*TS&LWw3arX@fD*tC}_i}XL@{6 z2$Bct{OkIga|~Jmu@ZD@YC^s`$W<*TP-Efxwq{J!B@HFlR(vik`D|7c$79XWxO5H* z!DU}^{uZrLBkNGnN50)+=1Mj(+A1`7?O}^<+vRMfw+Nz%}rk#qH~6y{g>-}vf;#N`ZJ0r-dWp!q&Q)QYH-sMnM&Jm z?3MnYGCxpL#L?s(v{JCT=<~JX6~0ve!LH7WfYoScEM7|SJ7&s)_oKkC40%FnKD@v}uzAmP=M5&z`=8Is%d*(w%(^HPt~R}w0H zLy$N^nY_WgdD+~;X*LVG6}fHS&*bBex3Et+UsY6(MATBlQY+)=m1N*F=xiM)adw-F zau^9oB*AIYJbNf2{7K8(zu2Pk+Sttb6n48P%e@-A{r$@< zGf$?>0CO<_l)que!jfE#p~wwlxF+n z$;pulbOdQd&|LB9Rweho&|~4%WK{NXyC4<{HWqzuk#BNS@YMj)6FbPfilKX-RuG4h zYx5poJ67SkFW5;2q$7DLV^-)On1iQ+&tImE6lUNWrEt#oToS&IwCCs)o!Z;YdXzvJPw;jzJs5zP(qVE}`5d-vS zkf0klb1mV$6~#BI>UG2M3I}InA&VqI+u*gv~LN^qs&@u$n-t_jVVfKDLrjHDJD+7(4b8fsm=V}f54CsyPw6D<(dIkgoZ zebzI4$iRb<JqMMWWN-k<>UexB|r*9YHtd4+tUI4$J-h2 zJ>TQl`FKE1lG*kZx>0%0JkRW`WP$9#+Gc2B|@iR{}IsQx^)prbGp|{t5 z7sk!3`#q>`X-;qTn0+mCq$RseFdaFh- z5*?{sBH*b}Zh%TNjs${Zi$341sMjqj6IwXDmaz2w1l6@A7qFe5*C23<>F0)%iG%K8 zj|&e(gQ=wQy7p6xmpOBjBp=N)Qjqw9&AQ@z!)Gm0bZ>$ua#afc;6TKKvF812F}2uL z=8?)(Lrc5{Tatk-p!edB6Y`P7CD~{r1Yv5ZD+o%;qgQ>ww>~t>?8BOB*YS30EyJPj z_MNzlaoN0>hG>W(xz$t!$-H#Rkh6-_lL2YqNZsE#QQ^h9xA!abqR**H0b(lTnd>xn zXA~C?1*|sw8)nNJ75M|-J1^gl$0`c1qBwMKjY|gu>Rm&lndN%^FrNK?t7)}eq9N^e=sEdpghNUJxbUfoUv#BxI2o$i<3jD7^q>EkWY+7mO5So?^42_~K%~+Up!O4lFc!hPk%J z%Pd~5I9QN@2T!E5(F$^&maeCtW{E#a3grv%q? zwK%=AWUc^YZ1JwU8TbI&IjU$A+P&mZ1D!?&V+;D;Wj#u0-wH-sL9vDCEYu3n#G zLA>*(Qi97X0oOvs(?1OALr4nv=PMDcL_2<8WZ}Pm^g3_5+(O27*FMQvRr2C{Ypl;X zxxx!`K95!3yz0>k=!8yVIY`ZpbEn{#>#ba6FEDRi=rc;7{o%nV#zq6TJy$IRea9KF z!s)~ZiKQA_+P>t;NbMPY_e)Cf2a5qLIwy-yUr#u8HXgQacEg~Skj+S*d8E$2xUbIl z_Tb*uz|)c9r(WuCxT!Uq3ApYF*6JS8Sc1$_>ANwuLRdzW4vayd&YA9o&wSzwI-%sk ztjCLWZ(#G93ApIV+m7Uk%n?7U*EGNIbc>&k_PE>Hm+BrX$16m!t5C{|$IGnKx{mFL z4=)xf+oU)~I^zZ_AgM^A`5!jhUw7aa@brm@6UX{AUP>Xm@o8I(8$EL(;-4R>kiG>6 z>36G&%O|Vc-_Cg7t39H=-gd6MxMo|L6PIH)XFbxpt9-rc-S!};1-!5ruvt+EYdLi_ zVQwpP4ui2RnPAv$&1CEt48I>QC-{>;ywa$X*k(jZ7zoxiANcGh@Ao#bO0ad(=imIu z4F5w(Eo{#tW>O3+b8lG46eOx#A~g*qNhE036`RqmnFei0!GCja9ZD7E5pDVJ{%nn- zU+~QgKib11e~9Sshm;9uCmLJ~Vw zE5?1djs(pGkMqj`mwzZI^SUef|MO6V#)k~=4_nNhOGh9hnObDuP7vd&mok3&ch>l& zQoqkCSid{q%O9A%t%1H!1KbD%M|@|j;$^#cTxzs3?%zy#IaFM}%`S5p@JG2kuLt}G znZ?h2oV`>}RHb&Tk}C{5j3;Q%D$cEhY}AJEddC-B3gw>etABIW=i1*|WcJ5g#WWWi z8nNNvR?54+-e%^NbSPp}t`s$p=42&dS^Qqi$FFPNyV54}1&_U}&ObZ8_e@*7#3gGo zE489aWHWIinA?IBmat>+W2bU>awFx#d8^0*i4m;3xW%eR7gVUkcpChg58cGFNUpGFS8`RiwQT&qODoDdn@HYE2GiY z19GV--{0}EyyBno7!(IXyX7FW)P>>nR?6Y7rsoNsZ1}w3OOjo@wZ|jHzxByw-u^Me zzyJ6q4}PJYw~%)DY-LnLf(^t7Pi)Tz^m8?j%83fmSOqxO)tq^y$84H`7KnUD+wB%R zfD{-ncPR=4^}gZbm-~D?Uv%pg#djP2o`mW4;*|>ccI2cmREN@$jdH1*5EPg*h zH6595T3<-DhE|Ct5@d}x|9)E>WabP_cK0(%!;#I5`)4&*>)x9-4rYLt=6qVA9#Q}0b1gpfr(1X}gX-C#P{&S{D_{*& zRy9G>peuse``-FH(G>8H9-4)R+}ELnU%VFc-j}<~ZfS&d7N1eujgV3ZX=SD4Wl*UN zlTu{`QoGL=bS>{_x4HlM?jW!>=R6+0x5lNL6h4Y9{PgvNPd?G)#J75ct7gIla1gx9 z!M#95Rc}hd z)8%%-Jp)hYmfOZb@ScX6anlC=>u_E?+0&f)W*3pzUA@oZPrM{K`<^QONbaA2Ubs+= zUmxyfWJ+*wF{Rpd zZwPZA`lpu>_g>hD?cD8ndlhxG&MH#D?X*rnjI_Jtv+dN_;Vq+Ue_Eg4ed({gsYG z=#)#G_VhCU`RfUfobOZXP0pQ%v1N8MBkZ`vXMr>lq|s3L!%Hnv3xu&`fgrBQ38%Fm zUblAnz;CSf`OtUUocd}PZ^H~-l}rh`GB8eeF8}}_07*naRBSu+?HHVJ;`3dOhh5em z4rqORjxWvnZ&=Wjz`?|Ds+m$v48DdiGmg2c#8l&j;x&`^`Lq&rB1!rt1V{nAJvN-_ zWJBdS3-!Lq-|r+V*b2wKEv!?mfU9#p8@}YAwp>yBckQ1n#Es-=lDLzfbvh?$9q}-p z;M|#r@0_f#8A#4Yd(Txd74UE7173NDM_8(SeFL9*y2Zf@N$yP{9P(wSppf~fl+ED@ zVJ&1(Ni2~xSP65NGmgB}=jZb=w=@(OCAfOXr&(7#@|6~i@1}?}|3zijx1CMFroNmk zOCEi=&KC|x{QS8d3$1Jba~FawJ9?7KT!J~jCq}|r&7<==mhz?)PP>2Bha)g&E$?q- zoZiZ4^tID=*TYdYX(!*Ck%De0X+@IFiefX6Z2E#k3a)#C3*PSF_9L0$XJ78}?yt6} zu4c%d-8oSmKc1{>YZh*7TDfo7(*eDnTIRPh>Mfny1rBG>rM3e($ibqr0;zK-SLLE0 zo?Eb;hT`h7PrD+wg>_bEy&v|}Z#M8)m`Mx^S5mx9GmwK689UnoPLvjJ;(Nwfr_OXW zL29RN-16rW)($rE+Kk85NZ$7GH31xsHTSJ0%(aJ-o7J8n>gAIkW^&ID)$QCHoL|p4 zb)nA-$0PpPUA29q8h0YI{P?w)Q)`X|KDVVg^4%V?V<&r^+hlP5rlAq1=tyAiiFjt# z=ZQVKzYTEK6P)!%lZ}RjPlOWV2{H*X6ZnA0l@2L0vJ00<%E|Mj6q#Q_Fm&K%_PaBZ zR&6ZNDJs`&7x!D|0zlFtJO*CA!8OAt{_HwGR#NMxiekKVJe)Xtdg8p6STvV;G(NGeAB$Z=zKzIIb1 z_1JJ&!g{25Y2K%Oljnjk)+J9;V6ofFJB!J`TM5<^By*D1Vb3`U?w7zJ4fuVVv)bJU zccW}2J!B1jU%P6`chHaDcZ)LU8LCaaZH2CV!RABtAHwao0>OL25#jnb?r)Y4UQ-ja z@Ar85kt*%FqFGhEH0QseLDK-Mfh3&usc6gn*J2uZMy#cnRBb9ji8hyXeR(k>n(xDdsov7ucec+z?r2^(5c2y6!ad(lU(|+&&h>fdi%q`Og#qk7AK%%lS1RByS0Y~gIiKp^wmfpa&%3|WWac~R zuB2bFAi9>BCsN+=Oq1r@JzjZtl}1PN5dmurk1rgp@N95vjBEou=S!aRC3OqOS}DuI zY1j*Ecm6?~#O<-ol=syXU#s1ILYxIIg^Jp8Kz+^|>FeFKo^q^b27*6!7r!is4YO@c zxMy+GfVW1%rx*8Xbdq?vhc8BhlGX5YPR!t*fe4-@)>#r3o+UDS^3A zh7q@coQra@xb_lJ=|FO~1+y7nxGabpXS)XSjMSquQn9XPZ z3NlE0?|h=o+}RWryW+=6w&f8F z5{vR17O?P2!rb{3E8s`+m-ci(uW2~d%2@1bDyb#$CF{!$Fp6Ts>_$dthrZBOIwc>Q zOTS8ET?PciRY_~!o3KwEROkv?!4D(;>j^wXpbRZ6^bJSu59!ZKgofH>P4t>ZcBdZ- zWvfIHTN;n2yz2=!Q)w!2;o}vaTn>3Ic;iN_GGHrI#DT<5bsp4jj1bMWHE&-}@D02c zNnZ4C-`JN0o(d&Tg~2$W!B5mY-W>>zTurF8^pK@*cSaff)KX6j5BD`%z?PD{;_Xes z+`5unT?sgFICfQJJUIe6GSXExE@@e2o=cf|KASiMvsr=tg*n(K0e!mwr1F-dN*PX* zjHBzBbpgCQP8yd2eqlMg!ve5DzDdn47HsJa>W1LkztZ3vr>psh+32@6eaS14B9Rc~ zwx@HkA_{MQ|Lr_Qc3~l7hcp3I;56-@ut}#wnT7=<2+8 zKKgt7Qh&b)^qF$*Zd+AFQc{N-d0)GN+MT(TDCsNgSa6mS*5Yf~x1}++Js!~i?JIpg z@??v-)vP2QQ+$}wD#HqA9ME3yxO&j1QyD(-OhMwwkq2x9oNM@ez2V<5oBH8(6Y!vb z-#HZVJBOU>&rffr{Q8$RIC8m%RqQ^?H@U}kBA8jtIMqz~YWUwV*-NC z@7>|`lu!Tv?7eA>rPq1q_j}HHm%G&7-PJprO|nUfq!xq3#~

9%q8U zLB3=e%!go*2CH`)wSI1 zUCufAaNfJtt?DM(-K=V!KR{OXy>)Nhdf#)-|5^XfT0s^oUOkZT`hj%UD8-H9jYv4V zKjxk#O}ybydLoqUJUK}=g~$v(FDVm}u<1^*%)NmUc)q6i_CvG$V&+&noBLE`XJjhk zwvmjj<3~wk$H+&&2U~K-buE-WImOUwDE@jeW^IR<`sultIR`(#UT}Q1pwS!Oi-NC+ zANH*K+JU~%OsB3X_3#%vpqmO8Q$41RmkGQUjWg~~(u4!^F^^s?IJQx+(Duf$Fsk7` z9*R$_BPpQSwUk=uCB6vT3DgV4%#wp^aLT1v_}PaWJiNY1{i4~Tqp;I;9T@1_{Eodh zKGk_kT_(o&snW8qm9y`Se9Y1@iBQy)_uTbxBwy|R1~1G;fzWRP87*7KfALa_`(NyE z;Q0*IWvmrr+KUEy&oUnFj$4kUj^RdDHW=XPx@Kl6AuSyHH%ea|ca0)Gt7MC}aWkNR zJK817YX!~r4pX39rGBXVFqSNpK?VHO&oA%Hi@25e?MoTI{DU=){ap{~?R+0xO?dmW zHM+BkJO8fZbq&nU7c@VpIQK}Mw~nX0a5&x5du&|^KbebIdZ5YDoiz?$DL8VvNBycD ztAJN|MM%}Pk;3n(>z+obe7m1%3c54y-48gQ^hw9)wu8uwB0qZWE_hY7VU&E@3Qs;rHbiBuAmqe@m@gW6A`8dZ++N{c>BSd1LLd8BB?yDZ#Z&43;Y ztyk@jGV(ktSRo@wZ~( zn@b5-Cdgg`b?XNiMP}IT(kJts+Ub;q$oQ7PSUa*vA+_t@O_w6Y%g1Y^nIrAlYZJOa zR#QB8Pn|zKTIY>uk9p|-@=%R`Ib}e||M21_k36{zL3M{}aEOnNjNX&6Gev=`!KKfnZ0?KLoYQpc zUZ!-jp?GESz4xQn9Q?zTjC~z5IMZr{qnY`CmlKwCUrFxjh+JwXR=hMH^TUR|X+?3V zgF8!0I~HC%QX`t8S-#M-9J`oP>)Ek-rKE7g#a36fNQAX!!k^z!=kzTY8u6};!4g!5 zZR;&Y?@scTyXFDtB5lrj=2tE7Zo zBoy~jBuZNmaa>f6 zU*y|Lx8&=^|51|;Z35hvTRydtv9INO(5(no_j}N%hrtJtfx3@CFl^b1|#e zd5zwPg#Z0S15Pw<`1!mmal|<8$St$wc)naY#ys}xTGWxy*{6BoM4f+ryiUN4g|N-x z5bYrRG5WoN)~Sg9`nL}8W+d^w#t^&!CrZm#E@m9uD7Ovy)pAFgSs$r#Lyu{@ zJ&|T`r^)zABA7!pUbzVokN1i{SWbEQ>-+iL#jD)^hpmA@_?|uf(F*tv7)%0AsV$LA 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 +// ASSUMES 500 sats after Ord are "dust" +impl SimpleOrdinal { + #[continuation(guarded_by = "[Self::signed]", web_api, coerce_args = "default_coerce")] + fn sell(self, ctx: Context, opt_sale: Sale) { + if let Sale(Some(sale)) = opt_sale { + let o = ctx + .get_ordinals() + .as_ref() + .ok_or_else(|| CompilationError::OrdinalsError("Missing Ordinals Info".into()))?; + let mut index = 0; + for (a, b) in o.iter() { + if (*a..*b).contains(&self.ordinal) { + index += (self.ordinal) - a; + break; + } else { + index += b - a + } + } + let mut t = ctx.template(); + // TODO: Check Index calculation + if index != 0 { + t = t.add_output(Amount::from_sat(index - 1), &self.owner, None)?; + } + let buyer = Compiled::from_address(sale.purchaser, None); + t = t.add_output(Amount::from_sat(501), &buyer, None)?; + let remaining = t.ctx().funds(); + t = t.add_amount(sale.amount.into()); + t = t.add_output(remaining + sale.amount.into(), &self.owner, None)?; + t = t.add_sequence(); + t = t.add_amount(sale.change.into()); + t = t.add_output(sale.change.into(), &buyer, None)?; + t = t.add_amount(sale.fee.into()); + t.add_fees(sale.fee.into())?.into() + } else { + empty() + } + } +} +impl StatefulArgumentsTrait for Sale {} + +/// # The SimpleNFT Contract +impl Contract for SimpleOrdinal { + // Ordinals... only good for selling? + declare! {updatable, Self::sell} + + fn ensure_amount(&self, ctx: Context) -> Result { + let ords = ctx + .get_ordinals() + .as_ref() + .ok_or_else(|| CompilationError::OrdinalsError("Missing Ordinals Info".into()))?; + if ords.iter().any(|(a, b)| (*a..*b).contains(&self.ordinal)) { + Ok(Amount::from_sat(1 + 500)) + } else { + Err(CompilationError::OrdinalsError( + "Missing Intended Ordinal".into(), + )) + } + } +} + +impl SimpleOrdinal { + /// # signed + /// Get the current owners signature. + #[guard] + fn signed(self, _ctx: Context) { + Clause::Key(self.owner.clone()) + } +} +fn default_coerce( + k: ::StatefulArguments, +) -> Result { + Ok(k) +} + +REGISTER![SimpleOrdinal, "logo.png"]; diff --git a/plugin-example/trampolinepay/src/plugin.rs b/plugin-example/trampolinepay/src/plugin.rs index b9b776a9..6fa86260 100644 --- a/plugin-example/trampolinepay/src/plugin.rs +++ b/plugin-example/trampolinepay/src/plugin.rs @@ -34,13 +34,14 @@ pub struct TrampolinePay { impl TrampolinePay { #[then] fn expand(self, mut ctx: Context) { - let contract = self.handle.call( + let contract = self.handle.clone().call( &ctx.derive_str(Arc::new("plugin_trampoline".into()))?.path(), &CreateArgs { context: ContextualArguments { amount: ctx.funds(), network: ctx.network, effects: unsafe { ctx.get_effects_internal() }.as_ref().clone(), + ordinals_info: ctx.get_ordinals().clone(), }, arguments: batching_trait::Versions::BatchingTraitVersion0_1_1(self.data.clone()), }, diff --git a/plugin-example/treepay/src/plugin.rs b/plugin-example/treepay/src/plugin.rs index 696f5096..af199f4e 100644 --- a/plugin-example/treepay/src/plugin.rs +++ b/plugin-example/treepay/src/plugin.rs @@ -100,8 +100,7 @@ impl TreePay { builder = builder.set_sequence(0, timelock)?; } } - builder = builder.add_fees(self.fee_sats_per_tx)?; - return builder.into(); + return builder.add_fees(self.fee_sats_per_tx)?.into(); } else { let pay = Box::new(PayThese { contracts: v, diff --git a/plugins/src/client/plugin.rs b/plugins/src/client/plugin.rs index ebca721f..63915f47 100644 --- a/plugins/src/client/plugin.rs +++ b/plugins/src/client/plugin.rs @@ -73,6 +73,7 @@ where network, amount, effects, + ordinals_info }, } = serde_json::from_slice(s.to_bytes()).map_err(CompilationError::DeserializationError)?; // TODO: In theory, these trampoline bounds are robust/serialization safe... @@ -105,6 +106,7 @@ where path, // TODO: load database? Arc::new(effects), + ordinals_info ); let converted = Self::try_from(arguments)?; converted.call(ctx) diff --git a/sapio-base/src/plugin_args.rs b/sapio-base/src/plugin_args.rs index 92b4e21e..7069798f 100644 --- a/sapio-base/src/plugin_args.rs +++ b/sapio-base/src/plugin_args.rs @@ -48,4 +48,8 @@ pub struct ContextualArguments { /// # Effects to augment compilations with #[serde(skip_serializing_if = "MapEffectDB::skip_serializing", default)] pub effects: MapEffectDB, + + /// # the ranges of ordinals held in the input + #[serde(skip_serializing_if = "Option::is_none", default)] + pub ordinals_info: Option> } diff --git a/sapio-contrib/src/contracts/channel.rs b/sapio-contrib/src/contracts/channel.rs index 4af2d939..709af1f3 100644 --- a/sapio-contrib/src/contracts/channel.rs +++ b/sapio-contrib/src/contracts/channel.rs @@ -75,6 +75,7 @@ mod tests { std::sync::Arc::new(CTVAvailable), "root".try_into().unwrap(), Default::default(), + None ); Compilable::compile(&x, ctx.derive_str(Arc::new("X".into())).unwrap()).ok(); Compilable::compile(&y, ctx.derive_str(Arc::new("Y".into())).unwrap()).ok(); diff --git a/sapio-contrib/src/contracts/derivatives/dlc.rs b/sapio-contrib/src/contracts/derivatives/dlc.rs index 3ce77b84..8a7c6a20 100644 --- a/sapio-contrib/src/contracts/derivatives/dlc.rs +++ b/sapio-contrib/src/contracts/derivatives/dlc.rs @@ -252,6 +252,7 @@ mod tests { Arc::new(CTVAvailable), EffectPath::try_from("dlc").unwrap(), Arc::new(Default::default()), + None ); let _r = d.compile(ctx).unwrap(); } diff --git a/sapio-contrib/src/contracts/hanukkah.rs b/sapio-contrib/src/contracts/hanukkah.rs index cc895510..b71727a9 100644 --- a/sapio-contrib/src/contracts/hanukkah.rs +++ b/sapio-contrib/src/contracts/hanukkah.rs @@ -151,11 +151,11 @@ impl Hanukkiah2Night { let size = txn.estimate_tx_size(); let fees = self.feerate_per_byte * size; txn = txn.add_amount(fees); - txn = txn.add_fees(fees)?; let candle_time = AbsTime::try_from(self.night_time.get() + 24 * 60 * 60 * (self.night as u32 - 1))? .into(); - txn.set_lock_time(candle_time)?.into() + txn = txn.set_lock_time(candle_time)?.into(); + txn.add_fees(fees)?.into() } } impl Hanukkiah2 { @@ -181,8 +181,8 @@ impl Hanukkiah2 { let size = txn.estimate_tx_size(); let fees = self.feerate_per_byte * size; txn = txn.add_amount(fees); - txn = txn.add_fees(fees)?; - txn.into() + let fee_paying_txn = txn.add_fees(fees)?; + fee_paying_txn.into() } } impl Contract for Hanukkiah2 { diff --git a/sapio-contrib/src/contracts/op_return_chain.rs b/sapio-contrib/src/contracts/op_return_chain.rs index 181f76d1..17f72843 100644 --- a/sapio-contrib/src/contracts/op_return_chain.rs +++ b/sapio-contrib/src/contracts/op_return_chain.rs @@ -43,8 +43,9 @@ impl ChainReturn { )] fn next_chain(self, ctx: sapio::Context, o: UpdateTypes) { let mut tmpl = ctx.template(); + let mut pay_fees = (Amount::ZERO); if let UpdateTypes::AddData { data, fees } = o { - tmpl = tmpl.spend_amount(fees.into())?; + pay_fees += fees.into(); tmpl = tmpl.add_output( Amount::from_sat(0), &Compiled::from_op_return(data.as_str().as_bytes())?, @@ -58,7 +59,8 @@ impl ChainReturn { let funds = tmpl.ctx().funds(); tmpl = tmpl.add_output(funds, &self.pk, None)?; } - tmpl.into() + + tmpl.add_fees(pay_fees.into())?.into() } } diff --git a/sapio-contrib/src/contracts/vault.rs b/sapio-contrib/src/contracts/vault.rs index 5a5ee867..1dae5002 100644 --- a/sapio-contrib/src/contracts/vault.rs +++ b/sapio-contrib/src/contracts/vault.rs @@ -217,6 +217,7 @@ mod test { Arc::new(CTVAvailable), EffectPath::try_from("dlc").unwrap(), Arc::new(v.context.effects), + None ); Vault::try_from(v.arguments)?.compile(ctx)?; Ok(()) diff --git a/sapio/src/contract/context.rs b/sapio/src/contract/context.rs index 49089b14..137c9254 100644 --- a/sapio/src/contract/context.rs +++ b/sapio/src/contract/context.rs @@ -19,6 +19,7 @@ use std::convert::TryInto; use std::collections::HashSet; +use std::mem; use std::sync::Arc; /// Context is used to track statet during compilation such as remaining value. @@ -32,9 +33,32 @@ pub struct Context { path: Arc, already_derived: HashSet, effects: Arc, + ordinals_info: Option>, +} + +fn allocate_ordinals(a: Amount, ords: &Vec<(u64, u64)>) -> [Vec<(u64, u64)>; 2] { + let mut amt = a.as_sat(); + let mut ret = [vec![], vec![]]; + for (start, end) in ords.iter().copied() { + let sats = end - start; + if sats <= amt { + amt -= sats; + ret[0].push((start, end)) + } else { + if sats != 0 { + ret[0].push((start, start + sats)); + } + ret[1].push((start + sats, end)) + } + } + ret } impl Context { + /// Borrow the Ordinals Info + pub fn get_ordinals(&self) -> &Option> { + &self.ordinals_info + } /// create a context instance. Should only happen *once* at the very top /// level. pub fn new( @@ -43,6 +67,7 @@ impl Context { emulator: Arc, path: EffectPath, effects: Arc, + ordinals_info: Option>, ) -> Self { Context { available_funds, @@ -52,6 +77,7 @@ impl Context { path: Arc::new(path), already_derived: Default::default(), effects, + ordinals_info, } } /// Get this Context's effect database, for clients @@ -94,6 +120,7 @@ impl Context { network: self.network, already_derived: Default::default(), effects: self.effects.clone(), + ordinals_info: self.ordinals_info.clone(), }) } } @@ -107,6 +134,7 @@ impl Context { network: self.network, already_derived: self.already_derived.clone(), effects: self.effects.clone(), + ordinals_info: self.ordinals_info.clone(), } } @@ -141,6 +169,12 @@ impl Context { network: self.network, already_derived: self.already_derived.clone(), effects: self.effects.clone(), + ordinals_info: self.ordinals_info.as_ref().map(|o| { + let mut a = allocate_ordinals(amount, o); + let mut v = vec![]; + mem::swap(&mut a[0], &mut v); + v + }), }) } } @@ -150,6 +184,13 @@ impl Context { Err(CompilationError::OutOfFunds) } else { self.available_funds -= amount; + + self.ordinals_info = self.ordinals_info.as_ref().map(|o| { + let mut a = allocate_ordinals(amount, o); + let mut v = vec![]; + mem::swap(&mut a[1], &mut v); + v + }); Ok(self) } } diff --git a/sapio/src/contract/error.rs b/sapio/src/contract/error.rs index 08350ca2..fc3da554 100644 --- a/sapio/src/contract/error.rs +++ b/sapio/src/contract/error.rs @@ -100,6 +100,8 @@ pub enum CompilationError { ModuleFailedAPICheck(String), /// CompError ModuleCompilationErrorUnsendable(String), + /// Issue in the Ordinals System + OrdinalsError(String), /// Error while serializing SerializationError(serde_json::Error), /// Error while deserializing diff --git a/sapio/src/contract/macros.rs b/sapio/src/contract/macros.rs index b60f33ae..37ee9812 100644 --- a/sapio/src/contract/macros.rs +++ b/sapio/src/contract/macros.rs @@ -127,12 +127,12 @@ pub fn get_schema_for() -> Arc macro_rules! web_api { {$name:ident,$type:ty,{}} => { $crate::contract::macros::paste!{ - const [] : Option<&'static dyn Fn() -> std::sync::Arc<$crate::schemars::schema::RootSchema>> = Some(&|| $crate::contract::macros::get_schema_for::<$type>()); + const [] : Option<&'static dyn Fn() -> std::sync::Arc> = Some(&|| $crate::contract::macros::get_schema_for::<$type>()); } }; {$name:ident,$type:ty} => { $crate::contract::macros::paste!{ - const [] : Option<&'static dyn Fn() -> std::sync::Arc<$crate::schemars::schema::RootSchema>> = None; + const [] : Option<&'static dyn Fn() -> std::sync::Arc> = None; } } } diff --git a/sapio/src/template/builder.rs b/sapio/src/template/builder.rs index 3ea29f92..48d582c8 100644 --- a/sapio/src/template/builder.rs +++ b/sapio/src/template/builder.rs @@ -21,10 +21,15 @@ use sapio_base::timelocks::*; use sapio_base::CTVHash; use sapio_base::Clause; use std::convert::TryFrom; +use std::marker::PhantomData; +/// State Type Tag for NotAddingFees +pub struct NotAddingFees; +/// State Type Tag for AddingFees (forces fees to be added last) +pub struct AddingFees; /// Builder can be used to interactively put together a transaction template before /// finalizing into a Template. -pub struct Builder { +pub struct BuilderState { guards: Vec, // TODO: Should be Comitted/Uncomitted if not CTV sequences: Vec>, @@ -37,12 +42,16 @@ pub struct Builder { min_feerate: Option, // Metadata Fields: metadata: TemplateMetadata, + _pd: PhantomData, } -impl Builder { +/// Start state of a Builder +pub type Builder = BuilderState; + +impl BuilderState { /// Creates a new transaction template with 1 input and no outputs. - pub fn new(ctx: Context) -> Builder { - Builder { + pub fn new(ctx: Context) -> BuilderState { + Self { guards: Vec::new(), sequences: vec![None], inputs: vec![InputMetadata::default()], @@ -53,6 +62,7 @@ impl Builder { fees: Amount::from_sat(0), min_feerate: None, ctx, + _pd: Default::default(), } } @@ -61,19 +71,6 @@ impl Builder { &self.ctx } - /// reduce the amount availble in the builder's context - pub fn spend_amount(mut self, amount: Amount) -> Result { - self.ctx = self.ctx.spend_amount(amount)?; - Ok(self) - } - - /// reduce the amount availble in the builder's context, and add to the fees - pub fn add_fees(self, amount: Amount) -> Result { - let mut c = self.spend_amount(amount)?; - c.fees += amount; - Ok(c) - } - /// Creates a new Output, forcing the compilation of the compilable object and defaulting /// metadata if not provided to blank. pub fn add_output( @@ -223,6 +220,33 @@ impl Builder { self.guards.push(guard); self } +} + +impl BuilderState { + /// reduce the amount availble in the builder's context + pub fn spend_amount(mut self, amount: Amount) -> Result { + self.ctx = self.ctx.spend_amount(amount)?; + Ok(self) + } + /// reduce the amount availble in the builder's context, and add to the fees + pub fn add_fees(self, amount: Amount) -> Result, CompilationError> { + let mut s = BuilderState { + _pd: Default::default(), + guards: self.guards, + sequences: self.sequences, + outputs: self.outputs, + inputs: self.inputs, + version: self.version, + lock_time: self.lock_time, + ctx: self.ctx, + fees: self.fees, + min_feerate: self.min_feerate, + metadata: self.metadata, + }; + let mut c = s.spend_amount(amount)?; + c.fees += amount; + Ok(c) + } /// Creates a transaction from a Builder. /// Generally, should not be called directly. @@ -320,8 +344,9 @@ impl Builder { } } } -impl From for Template { - fn from(t: Builder) -> Template { + +impl From> for Template { + fn from(t: BuilderState) -> Template { let tx = t.get_tx(); Template { guards: t.guards, @@ -337,8 +362,8 @@ impl From for Template { } } -impl From for crate::contract::TxTmplIt { - fn from(t: Builder) -> Self { +impl From> for crate::contract::TxTmplIt { + fn from(t: BuilderState) -> Self { // t.into() // works too, but prefer the explicit form so we know what we get concretely Ok(Box::new(std::iter::once(Ok(t.into())))) } From 1de7a1e437bb2a4c607f6b7b32b9d98396d53555 Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Sun, 21 Jan 2024 01:42:54 -0500 Subject: [PATCH 2/5] Add Ordinal TX Planner Module --- plugin-example/ordinal-example/src/plugin.rs | 64 +++-- sapio-base/src/plugin_args.rs | 20 +- sapio/src/contract/context.rs | 26 +- sapio/src/lib.rs | 1 + sapio/src/ordinals/mod.rs | 288 +++++++++++++++++++ 5 files changed, 369 insertions(+), 30 deletions(-) create mode 100644 sapio/src/ordinals/mod.rs diff --git a/plugin-example/ordinal-example/src/plugin.rs b/plugin-example/ordinal-example/src/plugin.rs index 550570bb..0c605a5a 100644 --- a/plugin-example/ordinal-example/src/plugin.rs +++ b/plugin-example/ordinal-example/src/plugin.rs @@ -1,26 +1,21 @@ -use bitcoin::hashes::hex::ToHex; -use bitcoin::hashes::sha256::Hash as Sha256; -use bitcoin::hashes::Hash; +use std::collections::BTreeMap; + use bitcoin::util::amount::Amount; use bitcoin::XOnlyPublicKey; use sapio::contract::empty; -use sapio::contract::object::ObjectMetadata; +use sapio::contract::Compilable; use sapio::contract::CompilationError; use sapio::contract::Compiled; use sapio::contract::Contract; use sapio::contract::StatefulArgumentsTrait; +use sapio::ordinals::OrdinalPlanner; +use sapio::ordinals::OrdinalSpec; use sapio::util::amountrange::AmountF64; use sapio::*; use sapio_base::Clause; -use sapio_wasm_nft_trait::*; -use sapio_wasm_plugin::client::*; -use sapio_wasm_plugin::plugin_handle::PluginHandle; use sapio_wasm_plugin::*; use schemars::*; use serde::*; -use std::convert::TryFrom; -use std::convert::TryInto; -use std::sync::Arc; /// # SimpleOrdinal /// A really Ordinal Bearing Contract #[derive(JsonSchema, Serialize, Deserialize)] @@ -39,22 +34,57 @@ pub struct Sell { #[derive(JsonSchema, Serialize, Deserialize, Default)] pub struct Sale(Option); +fn multimap( + v: [(T, U); N], +) -> BTreeMap> { + let mut ret = BTreeMap::new(); + for (t, u) in v.into_iter() { + ret.entry(t.clone()).or_insert(vec![]).push(u) + } + ret +} // ASSUMES 500 sats after Ord are "dust" impl SimpleOrdinal { + #[continuation(guarded_by = "[Self::signed]", web_api, coerce_args = "default_coerce")] + fn sell_with_planner(self, ctx: Context, opt_sale: Sale) { + if let Sale(Some(sale)) = opt_sale { + if let Some(ords) = ctx.get_ordinals().clone() { + let plan = ords.output_plan(&OrdinalSpec { + payouts: vec![sale.amount.into()], + payins: vec![Amount::from(sale.amount) + sale.fee.into() + sale.change.into()], + fees: sale.fee.into(), + ordinals: [Ordinal(self.ordinal)].into(), + })?; + let buyer: &dyn Compilable = &Compiled::from_address(sale.purchaser, None); + return plan + .build_plan( + ctx, + multimap([ + (sale.amount.into(), (&self.owner, None)), + (sale.change.into(), (buyer, None)), + ]), + [(Ordinal(self.ordinal), (buyer, None))].into(), + (&self.owner, None), + )? + .into(); + } + } + empty() + } #[continuation(guarded_by = "[Self::signed]", web_api, coerce_args = "default_coerce")] fn sell(self, ctx: Context, opt_sale: Sale) { if let Sale(Some(sale)) = opt_sale { - let o = ctx + let ords = ctx .get_ordinals() .as_ref() .ok_or_else(|| CompilationError::OrdinalsError("Missing Ordinals Info".into()))?; let mut index = 0; - for (a, b) in o.iter() { - if (*a..*b).contains(&self.ordinal) { - index += (self.ordinal) - a; + for (a, b) in ords.0.iter() { + if (*a..*b).contains(&Ordinal(self.ordinal)) { + index += self.ordinal - a.0; break; } else { - index += b - a + index += b.0 - a.0 } } let mut t = ctx.template(); @@ -82,14 +112,14 @@ impl StatefulArgumentsTrait for Sale {} /// # The SimpleNFT Contract impl Contract for SimpleOrdinal { // Ordinals... only good for selling? - declare! {updatable, Self::sell} + declare! {updatable, Self::sell, Self::sell_with_planner} fn ensure_amount(&self, ctx: Context) -> Result { let ords = ctx .get_ordinals() .as_ref() .ok_or_else(|| CompilationError::OrdinalsError("Missing Ordinals Info".into()))?; - if ords.iter().any(|(a, b)| (*a..*b).contains(&self.ordinal)) { + if ords.0.iter().any(|(a, b)| (*a..*b).contains(&Ordinal(self.ordinal))) { Ok(Amount::from_sat(1 + 500)) } else { Err(CompilationError::OrdinalsError( diff --git a/sapio-base/src/plugin_args.rs b/sapio-base/src/plugin_args.rs index 7069798f..b4850f04 100644 --- a/sapio-base/src/plugin_args.rs +++ b/sapio-base/src/plugin_args.rs @@ -6,6 +6,7 @@ //! arguments for passing into a sapio module use crate::effects::MapEffectDB; +use bitcoin::Amount; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -51,5 +52,22 @@ pub struct ContextualArguments { /// # the ranges of ordinals held in the input #[serde(skip_serializing_if = "Option::is_none", default)] - pub ordinals_info: Option> + pub ordinals_info: Option, } + +/// Struct to contain Ordinal ID +#[derive( + Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd, Clone, Copy, Debug, JsonSchema, +)] +pub struct Ordinal(pub u64); + +impl Ordinal { + /// How much padding in sats to require + /// TODO: Flexible padding + pub fn padding(&self) -> Amount { + Amount::from_sat(500) + } +} +/// Struct to contain Ordinal Spans +#[derive(Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd, Clone, Debug, JsonSchema)] +pub struct OrdinalsInfo(pub Vec<(Ordinal, Ordinal)>); diff --git a/sapio/src/contract/context.rs b/sapio/src/contract/context.rs index 137c9254..4261f2d7 100644 --- a/sapio/src/contract/context.rs +++ b/sapio/src/contract/context.rs @@ -7,6 +7,8 @@ //! general non-parameter compilation state required by all contracts use super::{Amount, Compilable, CompilationError, Compiled}; use crate::contract::compiler::InternalCompilerTag; +use crate::ordinals::Ordinal; +use crate::ordinals::OrdinalsInfo; use bitcoin::Network; @@ -33,22 +35,22 @@ pub struct Context { path: Arc, already_derived: HashSet, effects: Arc, - ordinals_info: Option>, + ordinals_info: Option, } -fn allocate_ordinals(a: Amount, ords: &Vec<(u64, u64)>) -> [Vec<(u64, u64)>; 2] { +fn allocate_ordinals(a: Amount, ords: &OrdinalsInfo) -> [OrdinalsInfo; 2] { let mut amt = a.as_sat(); - let mut ret = [vec![], vec![]]; - for (start, end) in ords.iter().copied() { - let sats = end - start; + let mut ret = [OrdinalsInfo(vec![]), OrdinalsInfo(vec![])]; + for (start, end) in ords.0.iter().copied() { + let sats = end.0 - start.0; if sats <= amt { amt -= sats; - ret[0].push((start, end)) + ret[0].0.push((start, end)) } else { if sats != 0 { - ret[0].push((start, start + sats)); + ret[0].0.push((start, Ordinal(start.0 + sats))); } - ret[1].push((start + sats, end)) + ret[1].0.push((Ordinal(start.0 + sats), end)) } } ret @@ -56,7 +58,7 @@ fn allocate_ordinals(a: Amount, ords: &Vec<(u64, u64)>) -> [Vec<(u64, u64)>; 2] impl Context { /// Borrow the Ordinals Info - pub fn get_ordinals(&self) -> &Option> { + pub fn get_ordinals(&self) -> &Option { &self.ordinals_info } /// create a context instance. Should only happen *once* at the very top @@ -67,7 +69,7 @@ impl Context { emulator: Arc, path: EffectPath, effects: Arc, - ordinals_info: Option>, + ordinals_info: Option, ) -> Self { Context { available_funds, @@ -171,7 +173,7 @@ impl Context { effects: self.effects.clone(), ordinals_info: self.ordinals_info.as_ref().map(|o| { let mut a = allocate_ordinals(amount, o); - let mut v = vec![]; + let mut v = OrdinalsInfo(vec![]); mem::swap(&mut a[0], &mut v); v }), @@ -187,7 +189,7 @@ impl Context { self.ordinals_info = self.ordinals_info.as_ref().map(|o| { let mut a = allocate_ordinals(amount, o); - let mut v = vec![]; + let mut v = OrdinalsInfo(vec![]); mem::swap(&mut a[1], &mut v); v }); diff --git a/sapio/src/lib.rs b/sapio/src/lib.rs index 78845392..187c4fb4 100644 --- a/sapio/src/lib.rs +++ b/sapio/src/lib.rs @@ -17,3 +17,4 @@ pub use sapio_base; pub use sapio_macros; pub use sapio_macros::*; pub use schemars; +pub mod ordinals; diff --git a/sapio/src/ordinals/mod.rs b/sapio/src/ordinals/mod.rs new file mode 100644 index 00000000..db70f5ed --- /dev/null +++ b/sapio/src/ordinals/mod.rs @@ -0,0 +1,288 @@ +// Copyright Judica, Inc 2021 +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Functionality for Ordinals + +use crate::{ + contract::{Compilable, CompilationError, TxTmplIt}, + template::{ + builder::{AddingFees, BuilderState}, + Builder, OutputMeta, + }, + util::amountrange::{AmountF64, AmountU64}, + Context, +}; +use bitcoin::Amount; +pub use sapio_base::plugin_args::Ordinal; +pub use sapio_base::plugin_args::OrdinalsInfo; +use serde_derive::{Deserialize, Serialize}; +use std::collections::{BTreeMap, BTreeSet, VecDeque}; + +/// Struct for a payout plan +pub struct OrdinalSpec { + /// List of payout amounts + pub payouts: Vec, + /// Incoming Payments + // TODO: Optional Ordinal info? + pub payins: Vec, + /// Fees available + pub fees: Amount, + /// List of Ordinals + pub ordinals: BTreeSet, +} + +impl OrdinalSpec { + fn total(&self) -> Amount { + self.payin_sum() + + self.fees + + self.payouts.iter().fold(Amount::ZERO, |a, b| a + *b) + + self + .ordinals + .iter() + .map(|m| m.padding() + Amount::ONE_SAT) + .sum() + } + + fn payin_sum(&self) -> Amount { + self.payins.iter().fold(Amount::ZERO, |a, b| a + *b) + } +} + +/// Plan Step represents one step in a Builder Plan +#[derive(Eq, Ord, PartialEq, PartialOrd)] +pub enum PlanStep { + /// Must be Last, the amount of fees + Fee(Amount), + /// Change to send to a change addr + Change(Amount), + /// Payout to some value carrying contract + Payout(Amount), + /// Payout to an ordinal contract + Ordinal(Ordinal), + /// PayIn via a separate input + PayIn(Amount), +} +/// The steps to follow to construct a transaction +pub struct Plan(Vec); + +impl Plan { + /// Turn a plan into a txn... + pub fn build_plan( + self, + ctx: Context, + mut bs: BTreeMap)>>, + mut os: BTreeMap)>, + (change, change_meta): (&dyn Compilable, Option), + ) -> Result, CompilationError> { + let mut tmpl = ctx.template(); + for step in self.0 { + match step { + PlanStep::Fee(f) => { + return tmpl.add_fees(f.into()); + } + PlanStep::Change(amt) => { + tmpl = tmpl.add_output(amt.into(), change, change_meta.clone())?; + } + PlanStep::Payout(amt) => { + let vs = bs + .get_mut(&amt.into()) + .ok_or(CompilationError::OrdinalsError( + "No Place for payout".into(), + ))?; + let (contract, metadata) = vs.pop().ok_or(CompilationError::OrdinalsError( + "No Place for payout".into(), + ))?; + tmpl = tmpl.add_output(amt.into(), contract, metadata)?; + } + PlanStep::Ordinal(o) => { + tmpl = { + let (contract, metadata) = os + .remove(&o) + .ok_or(CompilationError::OrdinalsError("No Place for Ord".into()))?; + tmpl.add_output( + o.padding() + Amount::from_sat(1), + contract, + metadata.clone(), + )? + } + } + PlanStep::PayIn(a) => { + tmpl = tmpl.add_sequence().add_amount(a); + } + } + } + Err(CompilationError::OrdinalsError("Poorly Formed Plan".into())) + } +} + +/// Generates an Output Plan +pub trait OrdinalPlanner { + /// Computes the total sats in an OrdinalsInfo + fn total(&self) -> Amount; + /// Generates an Output Plan which details how Change/Payouts/Fees/Ordinals + fn output_plan(&self, spec: &OrdinalSpec) -> Result; +} +impl OrdinalPlanner for OrdinalsInfo { + /// Computes the total sats in an OrdinalsInfo + fn total(&self) -> Amount { + Amount::from_sat(self.0.iter().map(|(a, b)| b.0 - a.0).sum()) + } + /// Generates an Output Plan which details how Change/Payouts/Fees/Ordinals + fn output_plan(&self, spec: &OrdinalSpec) -> Result { + if self.total() < spec.total() { + return Err(CompilationError::OutOfFunds); + } else { + let mut payouts: VecDeque<_> = spec.payouts.iter().cloned().collect(); + { + let v = payouts.make_contiguous(); + v.sort(); + } + let info_master = { + let mut info = self + .0 + .iter() + .cloned() + .enumerate() + .map(|(a, b)| (b, a)) + .collect::>(); + info[..].sort(); + info + }; + let order = { + let mut order = vec![]; + let mut info = info_master.clone(); + let mut it = info.iter_mut().peekable(); + let mut info_idx = 0; + 'ordscan: for ord in spec.ordinals.iter() { + while info_idx < info.len() { + if *ord >= info[info_idx].0 .0 && *ord < info[info_idx].0 .1 { + order.push((info[info_idx].1, (*ord))); + // Add the padding here to prevent bugs + + let mut unfilled = ord.padding().as_sat() + 1; + while unfilled != 0 { + let ((lower, upper), _) = &mut info[info_idx]; + let available = upper.0 - lower.0; + lower.0 += std::cmp::min(available, unfilled); + unfilled = unfilled.saturating_sub(available); + if unfilled > 0 { + info_idx += 1; // advance the global index whenever exhausted + } + } + + continue 'ordscan; + } + info_idx += 1 + } + return Err(CompilationError::OrdinalsError("Ordinal Not Found".into())); + } + order[..].sort(); + order + }; + let mut info = info_master.clone(); + let mut info_idx = 0; + let mut base_instructions = vec![]; + for payin in &spec.payins { + base_instructions.push(PlanStep::PayIn(*payin)); + } + for (idx, ord) in order { + let mut total = 0; + + // Fast Forward to the required IDX and count how many sats + while info_idx < idx { + let ((lower, upper), _) = &mut info[info_idx]; + total += upper.0 - lower.0; + info_idx += 1; + } + + // if ord != lower, pull out those sats + let ((lower, upper), _) = &mut info[info_idx]; + total += ord.0 - lower.0; + + // Add a Payout covering the total... this is NP Hard? + // Greedily pick the largest and loop + // TODO: Solver? + greedy_assign_outs(total, &mut payouts, &mut base_instructions); + + // Advance lower bound past the end + + let mut unfilled = ord.padding().as_sat() + 1; + while unfilled != 0 { + let ((lower, upper), _) = &mut info[info_idx]; + let available = upper.0 - lower.0; + lower.0 += std::cmp::min(available, unfilled); + unfilled = unfilled.saturating_sub(available); + if unfilled > 0 { + info_idx += 1; // advance the global index whenever exhausted + } + } + + base_instructions.push(PlanStep::Ordinal(ord)); + } + let mut total = 0; + + // Fast Forward to the required IDX and count how many sats remain + while info_idx < info.len() { + let ((lower, upper), _) = &mut info[info_idx]; + total += upper.0 - lower.0; + info_idx += 1; + } + + total += spec.payin_sum().as_sat(); + + // Add a Payout covering the total + if total < spec.fees.as_sat() { + return Err(CompilationError::OrdinalsError( + "Failed to save enough for Fees".into(), + )); + } + + greedy_assign_outs(total, &mut payouts, &mut base_instructions); + if payouts.len() > 0 { + return Err(CompilationError::OrdinalsError( + "Failed to assign all payouts".into(), + )); + } + + // Reserve fees now! + total -= spec.fees.as_sat(); + // Whatever is left can become Change... + base_instructions.push(PlanStep::Change(Amount::from_sat(total))); + + base_instructions.push(PlanStep::Fee(spec.fees.into())); + + Ok(Plan(base_instructions)) + } + } +} + +fn greedy_assign_outs( + mut total: u64, + payouts: &mut VecDeque, + base_instructions: &mut Vec, +) { + while total > 0 { + match payouts.binary_search(&Amount::from_sat(total)) { + Ok(i) => { + base_instructions.push(PlanStep::Payout(Amount::from_sat(total))); + payouts.remove(i); + total = 0; + } + Err(i) => { + if i == 0 { + // Best we can do is make this change, total smaller than any payout + // Must be change and not fee because we still have ordinals + base_instructions.push(PlanStep::Change(Amount::from_sat(total))); + total = 0; + } + + let v = payouts.remove(i - 1).expect("Valid given not 0"); + base_instructions.push(PlanStep::Payout(v.into())); + total -= v.as_sat(); + } + } + } +} From 2ec5af0a7290f25ec4a8de5457e6d04288ec427e Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Sun, 21 Jan 2024 22:16:55 -0500 Subject: [PATCH 3/5] Remove redundant miniscript imports --- cli/Cargo.toml | 4 ---- ctv_emulators/Cargo.toml | 5 ----- ctv_emulators/src/msgs.rs | 1 + emulator-trait/Cargo.toml | 4 ---- examples/dcf_mining_pool/Cargo.toml | 6 ------ plugin-example/batching-trait/Cargo.toml | 5 ----- .../clause-module-trampoline/Cargo.toml | 5 ----- plugin-example/clause-module/Cargo.toml | 5 ----- plugin-example/coin_pool/Cargo.toml | 5 ----- plugin-example/fedpeg/Cargo.toml | 6 ------ plugin-example/hanukkiah/Cargo.toml | 6 ------ plugin-example/helloworld/Cargo.toml | 6 ------ plugin-example/jamesob-vault/Cargo.toml | 7 ------- plugin-example/nft-auction/Cargo.toml | 6 ------ plugin-example/nft-sale/Cargo.toml | 6 ------ plugin-example/nft-trait/Cargo.toml | 6 ------ plugin-example/nft/Cargo.toml | 6 ------ plugin-example/op_return_chain/Cargo.toml | 6 ------ plugin-example/ordinal-example/Cargo.toml | 6 ------ plugin-example/payment_pool/Cargo.toml | 6 ------ plugin-example/staker/Cargo.toml | 6 ------ plugin-example/trampolinepay/Cargo.toml | 6 ------ plugin-example/treepay/Cargo.toml | 6 ------ plugin-example/vault/Cargo.toml | 7 ------- plugins/Cargo.toml | 8 +------- plugins/src/client/api/emulator.rs | 1 + sapio-base/Cargo.toml | 2 +- sapio-base/src/lib.rs | 1 + sapio-contrib/Cargo.toml | 6 ------ sapio-psbt/Cargo.toml | 5 +++-- sapio/Cargo.toml | 4 ---- sapio/src/contract/abi/object/bind.rs | 11 +++-------- sapio/src/contract/abi/object/descriptors.rs | 6 ++---- sapio/src/contract/abi/object/error.rs | 7 ++----- sapio/src/contract/abi/object/mod.rs | 19 +++++++------------ sapio/src/contract/abi/studio/mod.rs | 4 ++-- sapio/src/contract/compiler/mod.rs | 6 ++---- sapio/src/contract/compiler/util.rs | 5 +++-- sapio/src/contract/error.rs | 1 + sapio/src/lib.rs | 1 + sapio/src/util/extended_address.rs | 3 ++- tools/Cargo.toml | 5 ----- 42 files changed, 33 insertions(+), 194 deletions(-) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index fb9ea842..fe99b048 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -39,10 +39,6 @@ package = "sapio-bitcoin" version = "0.28.0" features = ['use-serde', 'rand', 'base64'] -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'rand', 'use-schemars', 'serde'] [dependencies.sapio] path = "../sapio" diff --git a/ctv_emulators/Cargo.toml b/ctv_emulators/Cargo.toml index f4aa3079..9bc6fb04 100644 --- a/ctv_emulators/Cargo.toml +++ b/ctv_emulators/Cargo.toml @@ -27,11 +27,6 @@ package = "sapio-bitcoin" version = "0.28.0-rc.3" features = ['use-serde', 'rand'] -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'rand', 'use-schemars', 'serde'] - [dependencies.sapio-base] path = "../sapio-base" version = "0.2.0" diff --git a/ctv_emulators/src/msgs.rs b/ctv_emulators/src/msgs.rs index 7330a065..d0ad784b 100644 --- a/ctv_emulators/src/msgs.rs +++ b/ctv_emulators/src/msgs.rs @@ -7,6 +7,7 @@ use super::*; use bitcoin::consensus::encode::{Decodable, Encodable}; use miniscript::serde; +use sapio_base::miniscript; use serde::de::Visitor; use serde::de::*; use serde::*; diff --git a/emulator-trait/Cargo.toml b/emulator-trait/Cargo.toml index 2b09670a..9d8f1fae 100644 --- a/emulator-trait/Cargo.toml +++ b/emulator-trait/Cargo.toml @@ -22,10 +22,6 @@ package = "sapio-bitcoin" version = "0.28.0" features = ['use-serde'] -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] [dependencies.sapio-base] path = "../sapio-base" diff --git a/examples/dcf_mining_pool/Cargo.toml b/examples/dcf_mining_pool/Cargo.toml index 063d793e..154c60bf 100644 --- a/examples/dcf_mining_pool/Cargo.toml +++ b/examples/dcf_mining_pool/Cargo.toml @@ -33,9 +33,3 @@ version = "0.2.0" [dependencies.sapio-ctv-emulator-trait] path = "../../emulator-trait" version = "0.2.0" - -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'rand', 'use-schemars', 'serde'] -optional = true diff --git a/plugin-example/batching-trait/Cargo.toml b/plugin-example/batching-trait/Cargo.toml index 0c00a911..664397d1 100644 --- a/plugin-example/batching-trait/Cargo.toml +++ b/plugin-example/batching-trait/Cargo.toml @@ -35,11 +35,6 @@ version = "0.2.0" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true [dependencies.sapio-wasm-plugin] diff --git a/plugin-example/clause-module-trampoline/Cargo.toml b/plugin-example/clause-module-trampoline/Cargo.toml index 25c73d4e..fbea3609 100644 --- a/plugin-example/clause-module-trampoline/Cargo.toml +++ b/plugin-example/clause-module-trampoline/Cargo.toml @@ -47,11 +47,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/clause-module/Cargo.toml b/plugin-example/clause-module/Cargo.toml index e3b40be7..16ad4901 100644 --- a/plugin-example/clause-module/Cargo.toml +++ b/plugin-example/clause-module/Cargo.toml @@ -47,11 +47,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/coin_pool/Cargo.toml b/plugin-example/coin_pool/Cargo.toml index cac0ecd4..c70bd844 100644 --- a/plugin-example/coin_pool/Cargo.toml +++ b/plugin-example/coin_pool/Cargo.toml @@ -47,11 +47,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/fedpeg/Cargo.toml b/plugin-example/fedpeg/Cargo.toml index 2bd3e001..6c5acf5e 100644 --- a/plugin-example/fedpeg/Cargo.toml +++ b/plugin-example/fedpeg/Cargo.toml @@ -47,12 +47,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/hanukkiah/Cargo.toml b/plugin-example/hanukkiah/Cargo.toml index c002c96b..fc51c708 100644 --- a/plugin-example/hanukkiah/Cargo.toml +++ b/plugin-example/hanukkiah/Cargo.toml @@ -46,12 +46,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/helloworld/Cargo.toml b/plugin-example/helloworld/Cargo.toml index bfc86668..bb0bd33b 100644 --- a/plugin-example/helloworld/Cargo.toml +++ b/plugin-example/helloworld/Cargo.toml @@ -47,12 +47,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/jamesob-vault/Cargo.toml b/plugin-example/jamesob-vault/Cargo.toml index f0183c2e..927944ca 100644 --- a/plugin-example/jamesob-vault/Cargo.toml +++ b/plugin-example/jamesob-vault/Cargo.toml @@ -49,13 +49,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" - -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/nft-auction/Cargo.toml b/plugin-example/nft-auction/Cargo.toml index c653983c..7faf4096 100644 --- a/plugin-example/nft-auction/Cargo.toml +++ b/plugin-example/nft-auction/Cargo.toml @@ -48,12 +48,6 @@ version = "0.2.0" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/nft-sale/Cargo.toml b/plugin-example/nft-sale/Cargo.toml index 17ec3b78..c197d541 100644 --- a/plugin-example/nft-sale/Cargo.toml +++ b/plugin-example/nft-sale/Cargo.toml @@ -51,12 +51,6 @@ version = "0.2.0" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [dependencies.sapio-wasm-plugin] path = "../../plugins" diff --git a/plugin-example/nft-trait/Cargo.toml b/plugin-example/nft-trait/Cargo.toml index d0190e6e..399633c4 100644 --- a/plugin-example/nft-trait/Cargo.toml +++ b/plugin-example/nft-trait/Cargo.toml @@ -45,9 +45,3 @@ version = "0.2.0" [dependencies.sapio-ctv-emulator-trait] path = "../../emulator-trait" version = "0.2.0" - -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true diff --git a/plugin-example/nft/Cargo.toml b/plugin-example/nft/Cargo.toml index 952a1c88..994148a2 100644 --- a/plugin-example/nft/Cargo.toml +++ b/plugin-example/nft/Cargo.toml @@ -49,12 +49,6 @@ version = "0.2.0" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [dependencies.sapio-wasm-plugin] path = "../../plugins" diff --git a/plugin-example/op_return_chain/Cargo.toml b/plugin-example/op_return_chain/Cargo.toml index 0000adb4..34f5e278 100644 --- a/plugin-example/op_return_chain/Cargo.toml +++ b/plugin-example/op_return_chain/Cargo.toml @@ -47,12 +47,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/ordinal-example/Cargo.toml b/plugin-example/ordinal-example/Cargo.toml index 943c8b3a..6c5d501a 100644 --- a/plugin-example/ordinal-example/Cargo.toml +++ b/plugin-example/ordinal-example/Cargo.toml @@ -49,12 +49,6 @@ version = "0.2.0" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [dependencies.sapio-wasm-plugin] path = "../../plugins" diff --git a/plugin-example/payment_pool/Cargo.toml b/plugin-example/payment_pool/Cargo.toml index 6abcf5d0..af025f4d 100644 --- a/plugin-example/payment_pool/Cargo.toml +++ b/plugin-example/payment_pool/Cargo.toml @@ -47,12 +47,6 @@ path = "src/payment_pool.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/staker/Cargo.toml b/plugin-example/staker/Cargo.toml index 5491eb1d..41a16c51 100644 --- a/plugin-example/staker/Cargo.toml +++ b/plugin-example/staker/Cargo.toml @@ -47,12 +47,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/trampolinepay/Cargo.toml b/plugin-example/trampolinepay/Cargo.toml index 1f977025..97db8c29 100644 --- a/plugin-example/trampolinepay/Cargo.toml +++ b/plugin-example/trampolinepay/Cargo.toml @@ -43,12 +43,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/treepay/Cargo.toml b/plugin-example/treepay/Cargo.toml index 23cac13b..5b4f9024 100644 --- a/plugin-example/treepay/Cargo.toml +++ b/plugin-example/treepay/Cargo.toml @@ -44,12 +44,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugin-example/vault/Cargo.toml b/plugin-example/vault/Cargo.toml index eff2d323..b2f2d19a 100644 --- a/plugin-example/vault/Cargo.toml +++ b/plugin-example/vault/Cargo.toml @@ -46,13 +46,6 @@ path = "src/plugin.rs" path = "../../emulator-trait" version = "0.2.0" - -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugins/Cargo.toml b/plugins/Cargo.toml index 27a41132..5ddeed4b 100644 --- a/plugins/Cargo.toml +++ b/plugins/Cargo.toml @@ -13,7 +13,7 @@ description = "Libarary for building client/host sapio plugin bindings" [features] default = ["client"] host = ["wasmer", "wasmer-cache", "tokio"] -client = ["miniscript"] +client = [] [dependencies] schemars = "0.8.0" @@ -60,11 +60,5 @@ path = "src/lib.rs" path = "../emulator-trait" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] -optional = true - [package.metadata.wasm-pack.profile.release] wasm-opt = false diff --git a/plugins/src/client/api/emulator.rs b/plugins/src/client/api/emulator.rs index 232394d2..826d87ab 100644 --- a/plugins/src/client/api/emulator.rs +++ b/plugins/src/client/api/emulator.rs @@ -7,6 +7,7 @@ //! Host based Emulator use crate::client::ext::*; use bitcoin::hashes::Hash; +use sapio_base::miniscript; use sapio_ctv_emulator_trait::CTVEmulator; use std::ffi::CString; use std::os::raw::c_char; diff --git a/sapio-base/Cargo.toml b/sapio-base/Cargo.toml index e8f75726..9480568e 100644 --- a/sapio-base/Cargo.toml +++ b/sapio-base/Cargo.toml @@ -19,7 +19,7 @@ serde_derive = "1.0" [dependencies.miniscript] package = "sapio-miniscript" -version = "^7.0.1" +version = "7.0.2-alpha.0" features = ['compiler', 'use-serde', 'use-schemars', 'serde'] [dependencies.bitcoin] diff --git a/sapio-base/src/lib.rs b/sapio-base/src/lib.rs index c1325baa..4563ba76 100644 --- a/sapio-base/src/lib.rs +++ b/sapio-base/src/lib.rs @@ -10,6 +10,7 @@ pub mod util; use bitcoin::XOnlyPublicKey; pub use util::CTVHash; +pub use miniscript; pub mod plugin_args; pub mod simp; diff --git a/sapio-contrib/Cargo.toml b/sapio-contrib/Cargo.toml index 4ebe0c94..4749cfc3 100644 --- a/sapio-contrib/Cargo.toml +++ b/sapio-contrib/Cargo.toml @@ -33,12 +33,6 @@ path = "../sapio-base" version = "0.2.0" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] - - [dependencies.sapio-ctv-emulator-trait] path = "../emulator-trait" version = "0.2.0" diff --git a/sapio-psbt/Cargo.toml b/sapio-psbt/Cargo.toml index c44ca98b..8510d40b 100644 --- a/sapio-psbt/Cargo.toml +++ b/sapio-psbt/Cargo.toml @@ -21,7 +21,8 @@ package = "sapio-bitcoin" version = "0.28.0" features = ['use-serde', 'rand', 'base64'] + [dependencies.miniscript] package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'rand', 'use-schemars', 'serde'] +version = "7.0.2-alpha.0" +features = ['compiler', 'use-serde', 'use-schemars', 'serde'] \ No newline at end of file diff --git a/sapio/Cargo.toml b/sapio/Cargo.toml index 9fa30d20..756a1fd3 100644 --- a/sapio/Cargo.toml +++ b/sapio/Cargo.toml @@ -11,10 +11,6 @@ description = "A programming framework for bitcoin smart contracts." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.1" -features = ['compiler', 'use-serde', 'use-schemars', 'serde'] [features] # used to enable some niceties if compiling on a nightly compiler diff --git a/sapio/src/contract/abi/object/bind.rs b/sapio/src/contract/abi/object/bind.rs index 8a345c8e..66644ca6 100644 --- a/sapio/src/contract/abi/object/bind.rs +++ b/sapio/src/contract/abi/object/bind.rs @@ -6,30 +6,25 @@ //! binding Object to a specific UTXO use super::descriptors::*; - pub use crate::contract::abi::studio::*; use crate::contract::object::Object; use crate::contract::object::ObjectError; use crate::template::Template; - -use ::miniscript::*; - use bitcoin::hashes::sha256::Hash as Sha256; - use bitcoin::util::psbt::PartiallySignedTransaction; use bitcoin::util::taproot::TaprootBuilder; use bitcoin::util::taproot::TaprootSpendInfo; use bitcoin::OutPoint; - +use miniscript::*; use sapio_base::effects::EffectPath; - +use sapio_base::miniscript; use sapio_base::serialization_helpers::SArc; use sapio_base::txindex::TxIndex; use sapio_ctv_emulator_trait::CTVEmulator; - use std::collections::BTreeMap; use std::rc::Rc; use std::sync::Arc; + impl Object { /// bind_psbt attaches and `Object` to a specific UTXO, returning a /// Vector of PSBTs and transaction metadata. diff --git a/sapio/src/contract/abi/object/descriptors.rs b/sapio/src/contract/abi/object/descriptors.rs index c245daae..5898b479 100644 --- a/sapio/src/contract/abi/object/descriptors.rs +++ b/sapio/src/contract/abi/object/descriptors.rs @@ -7,13 +7,11 @@ //! Wrapper for supported descriptor types pub use crate::contract::abi::studio::*; - -use ::miniscript::*; - use bitcoin::PublicKey; use bitcoin::Script; use bitcoin::XOnlyPublicKey; - +use miniscript::*; +use sapio_base::miniscript; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/sapio/src/contract/abi/object/error.rs b/sapio/src/contract/abi/object/error.rs index cfce5d63..92b4058c 100644 --- a/sapio/src/contract/abi/object/error.rs +++ b/sapio/src/contract/abi/object/error.rs @@ -7,12 +7,9 @@ //! Errors during object construction pub use crate::contract::abi::studio::*; - -use ::miniscript::{self, *}; - use bitcoin::util::taproot::TaprootBuilderError; - -use sapio_base::txindex::TxIndexError; +use miniscript::*; +use sapio_base::{miniscript, txindex::TxIndexError}; use sapio_ctv_emulator_trait::EmulatorError; /// Error types that can arise when constructing an Object diff --git a/sapio/src/contract/abi/object/mod.rs b/sapio/src/contract/abi/object/mod.rs index be482877..8787fcb2 100644 --- a/sapio/src/contract/abi/object/mod.rs +++ b/sapio/src/contract/abi/object/mod.rs @@ -10,33 +10,28 @@ pub mod error; pub use error::*; pub mod bind; pub mod descriptors; -pub use descriptors::*; -use sapio_base::simp::CompiledObjectLT; -use sapio_base::simp::SIMPAttachableAt; -use sapio_base::Clause; -use serde_json::Value; - use crate::contract::abi::continuation::ContinuationPoint; - use crate::contract::CompilationError; use crate::template::Template; use crate::util::amountrange::AmountRange; use crate::util::extended_address::ExtendedAddress; -use ::miniscript::*; use bitcoin::hashes::sha256; - use bitcoin::util::amount::Amount; - +pub use descriptors::*; use sapio_base::effects::EffectPath; use sapio_base::effects::PathFragment; +use sapio_base::miniscript::*; use sapio_base::serialization_helpers::SArc; - +use sapio_base::simp::CompiledObjectLT; +use sapio_base::simp::SIMPAttachableAt; use sapio_base::simp::SIMPError; +use sapio_base::Clause; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use serde_json::Value; use std::collections::BTreeMap; - use std::sync::Arc; + /// Metadata for Object, arbitrary KV set. #[derive(Serialize, Deserialize, Clone, JsonSchema, Debug, PartialEq, Eq, Default)] pub struct ObjectMetadata { diff --git a/sapio/src/contract/abi/studio/mod.rs b/sapio/src/contract/abi/studio/mod.rs index 5095bc87..807601ce 100644 --- a/sapio/src/contract/abi/studio/mod.rs +++ b/sapio/src/contract/abi/studio/mod.rs @@ -9,12 +9,12 @@ use crate::contract::abi::continuation::ContinuationPoint; use crate::contract::object::ObjectMetadata; use crate::template::output::OutputMeta; use crate::template::TemplateMetadata; -use ::miniscript::*; use bitcoin::consensus::serialize; use bitcoin::util::psbt::PartiallySignedTransaction; use bitcoin::OutPoint; -use sapio_base::effects::EffectPath; +use miniscript::*; use sapio_base::serialization_helpers::SArc; +use sapio_base::{effects::EffectPath, miniscript}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; diff --git a/sapio/src/contract/compiler/mod.rs b/sapio/src/contract/compiler/mod.rs index 49d8ea95..96f463b5 100644 --- a/sapio/src/contract/compiler/mod.rs +++ b/sapio/src/contract/compiler/mod.rs @@ -15,18 +15,16 @@ use crate::contract::actions::conditional_compile::CCILWrapper; use crate::contract::actions::CallableAsFoF; use crate::contract::TxTmplIt; use crate::util::amountrange::AmountRange; - -use ::miniscript::*; use bitcoin::schnorr::TweakedPublicKey; use bitcoin::XOnlyPublicKey; +use miniscript::*; use sapio_base::effects::EffectDB; use sapio_base::effects::EffectPath; use sapio_base::effects::PathFragment; - +use sapio_base::miniscript; use sapio_base::serialization_helpers::SArc; use sapio_base::Clause; use std::collections::{BTreeMap, BTreeSet}; - use std::sync::Arc; mod cache; mod util; diff --git a/sapio/src/contract/compiler/util.rs b/sapio/src/contract/compiler/util.rs index 41a96719..fd8c9f83 100644 --- a/sapio/src/contract/compiler/util.rs +++ b/sapio/src/contract/compiler/util.rs @@ -6,11 +6,12 @@ //! utility functions for compiler -use ::miniscript::descriptor::TapTree; -use ::miniscript::*; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; use bitcoin::XOnlyPublicKey; +use miniscript::descriptor::TapTree; +use miniscript::*; +use sapio_base::miniscript; use std::cmp::Reverse; use std::collections::BinaryHeap; use std::sync::Arc; diff --git a/sapio/src/contract/error.rs b/sapio/src/contract/error.rs index fc3da554..63b99117 100644 --- a/sapio/src/contract/error.rs +++ b/sapio/src/contract/error.rs @@ -11,6 +11,7 @@ use crate::contract::object::ObjectError; use sapio_base::effects::EffectDBError; use sapio_base::effects::EffectPath; use sapio_base::effects::ValidFragmentError; +use sapio_base::miniscript; use sapio_base::plugin_args::CreateArgs; use sapio_base::simp::SIMPError; use sapio_ctv_emulator_trait::EmulatorError; diff --git a/sapio/src/lib.rs b/sapio/src/lib.rs index 187c4fb4..c32a54fe 100644 --- a/sapio/src/lib.rs +++ b/sapio/src/lib.rs @@ -8,6 +8,7 @@ #![cfg_attr(feature = "nightly", feature(associated_type_defaults))] #![deny(missing_docs)] +pub use sapio_base::miniscript; #[macro_use] pub mod contract; pub mod template; diff --git a/sapio/src/util/extended_address.rs b/sapio/src/util/extended_address.rs index ea69aa05..8808e4d9 100644 --- a/sapio/src/util/extended_address.rs +++ b/sapio/src/util/extended_address.rs @@ -10,7 +10,8 @@ use crate::contract::object::ObjectError; use bitcoin::{Address, Script, XOnlyPublicKey}; -use miniscript::{Descriptor, DescriptorTrait}; +use crate::miniscript::{Descriptor, DescriptorTrait}; +use sapio_base::miniscript; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::convert::TryFrom; diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 00f1f13f..81373e37 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -16,11 +16,6 @@ serde_derive = "1.0" tokio = { version = "1", features = ["full"] } bitcoincore-rpc-async = "4.0.1-alpha.2" -[dependencies.miniscript] -package = "sapio-miniscript" -version = "^7.0.0" -features = ['compiler', 'use-serde', 'rand', 'use-schemars', 'serde'] - [dependencies.bitcoin] package = "sapio-bitcoin" version = "0.28.0" From 8b6c571e4f42a3c5607c976d863421c3bed4c294 Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Sun, 21 Jan 2024 22:19:29 -0500 Subject: [PATCH 4/5] Fix Type in CLI --- cli/src/contracts/request.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/contracts/request.rs b/cli/src/contracts/request.rs index 46fb6954..da41ac4d 100644 --- a/cli/src/contracts/request.rs +++ b/cli/src/contracts/request.rs @@ -23,7 +23,7 @@ use sapio_base::{ }; use sapio_wasm_plugin::{ host::{plugin_handle::ModuleLocator, PluginHandle, WasmPluginHandle}, - CreateArgs, API, + CreateArgs, API, OrdinalsInfo, }; use schemars::JsonSchema; use serde::*; @@ -74,7 +74,7 @@ pub struct Bind { pub use_txn: Option, pub compiled: Compiled, #[serde(skip_serializing_if = "Option::is_none", default)] - pub ordinals_info: Option> + pub ordinals_info: Option } pub type BindReturn = Program; #[derive(Serialize, Deserialize, JsonSchema)] From 387e990543314a48b3698a84ac0982ec5c060114 Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Sun, 21 Jan 2024 23:15:52 -0500 Subject: [PATCH 5/5] Inscription Example --- plugin-example/Cargo.toml | 3 +- plugin-example/ordinal-inscription/Cargo.toml | 60 ++++++++++ plugin-example/ordinal-inscription/README.md | 6 + .../ordinal-inscription/src/logo.png | Bin 0 -> 32878 bytes .../ordinal-inscription/src/plugin.rs | 109 ++++++++++++++++++ 5 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 plugin-example/ordinal-inscription/Cargo.toml create mode 100644 plugin-example/ordinal-inscription/README.md create mode 100644 plugin-example/ordinal-inscription/src/logo.png create mode 100644 plugin-example/ordinal-inscription/src/plugin.rs diff --git a/plugin-example/Cargo.toml b/plugin-example/Cargo.toml index 7812c5c4..c671bce9 100644 --- a/plugin-example/Cargo.toml +++ b/plugin-example/Cargo.toml @@ -17,4 +17,5 @@ members = ["treepay" , "nft-auction" , "clause-module" , "clause-module-trampoline" - , "ordinal-example"] + , "ordinal-example" + , "ordinal-inscription"] diff --git a/plugin-example/ordinal-inscription/Cargo.toml b/plugin-example/ordinal-inscription/Cargo.toml new file mode 100644 index 00000000..5b1e4e82 --- /dev/null +++ b/plugin-example/ordinal-inscription/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "sapio-wasm-ordinal-inscription" +version = "0.1.0" +license = "MPL-2.0" +authors = ["Jeremy Rubin "] +edition = "2021" +repository = "https://github.com/sapio-lang/sapio" +homepage = "https://sapio-lang.org" +description = "An Example Sapio Application" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] +path = "src/plugin.rs" +[package.metadata.wasm-pack.profile.release] +wasm-opt = false + +[dependencies] +serde_json = "1.0" +serde = "1.0" +serde_derive = "1.0" + + +[dependencies.schemars] +version = "0.8.0" +features = ['impl_json_schema'] +[dependencies.bitcoin] +package = "sapio-bitcoin" +version = "0.28.0" +features = ['use-serde'] +[dependencies.sapio] +path = "../../sapio" +version = "0.2.0" + +[dependencies.batching-trait] +path = "../batching-trait" +version = "0.1.0" + +[dependencies.sapio-base] +path = "../../sapio-base" +version = "0.2.0" +[dependencies.sapio-contrib] +path = "../../sapio-contrib" +version = "0.2.0" + + +[dependencies.sapio-ctv-emulator-trait] +path = "../../emulator-trait" +version = "0.2.0" + + +[dependencies.sapio-wasm-plugin] +path = "../../plugins" +version = "0.2.0" +features = ["client"] + +[dependencies.sapio-wasm-nft-trait] +path = "../nft-trait" +version = "0.1.0" diff --git a/plugin-example/ordinal-inscription/README.md b/plugin-example/ordinal-inscription/README.md new file mode 100644 index 00000000..acabbf6d --- /dev/null +++ b/plugin-example/ordinal-inscription/README.md @@ -0,0 +1,6 @@ +# Sapio Vault Example + +This crate can be compiled with `wasm-pack build`. The `*.wasm` artifact will +be created in the `pkg` directory, not in `target`. + +Feel free to modify this code to experiment with creating your own Sapio plugins. diff --git a/plugin-example/ordinal-inscription/src/logo.png b/plugin-example/ordinal-inscription/src/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d3bd711deed5707b1dec9cfa6b5c7e53a3fc7553 GIT binary patch literal 32878 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 N3NlL4WpBR({11nOgpB|I literal 0 HcmV?d00001 diff --git a/plugin-example/ordinal-inscription/src/plugin.rs b/plugin-example/ordinal-inscription/src/plugin.rs new file mode 100644 index 00000000..bdd80c1d --- /dev/null +++ b/plugin-example/ordinal-inscription/src/plugin.rs @@ -0,0 +1,109 @@ +use bitcoin::util::amount::Amount; +use bitcoin::Address; +use bitcoin::XOnlyPublicKey; +use sapio::contract::CompilationError; +use sapio::contract::Compiled; +use sapio::contract::Contract; +use sapio::contract::StatefulArgumentsTrait; +use sapio::ordinals::OrdinalPlanner; +use sapio::util::amountrange::AmountU64; +use sapio::*; +use sapio_base::Clause; +use sapio_wasm_plugin::*; +use schemars::*; +use serde::*; +/// # SimpleInscription +/// A really Ordinal Bearing Contract +#[derive(JsonSchema, Serialize, Deserialize)] +pub struct InscribingStep { + #[schemars(with = "bitcoin::hashes::sha256::Hash")] + owner: XOnlyPublicKey, + data: Vec, + content_type: String, +} +impl InscribingStep { + /// # signed + /// Get the current owners signature. + #[guard] + fn signed(self, _ctx: Context) { + Clause::Key(self.owner) + } + + #[guard] + fn inscription(self, _ctx: Context) { + let insc = sapio_base::miniscript::ord::Inscription::new( + Some(self.content_type.as_bytes().into()), + Some(self.data.clone()), + ); + Clause::Inscribe(Box::new(insc), Box::new(Clause::Trivial)) + } +} + +#[derive(JsonSchema, Serialize, Deserialize)] +pub struct Reveal { + fee: AmountU64, + alternative: Option

, +} +impl Reveal { + fn parse( + k: ::StatefulArguments, + ) -> Result { + Ok(k) + } +} +impl Default for Reveal { + fn default() -> Self { + Self { + fee: Amount::from_sat(500).into(), + alternative: None, + } + } +} +// ASSUMES 500 sats after Ord are "dust" +impl InscribingStep { + #[continuation( + guarded_by = "[Self::signed, Self::inscription]", + web_api, + coerce_args = "Reveal::parse" + )] + fn reveal(self, ctx: Context, reveal: Reveal) { + let ord = ctx + .get_ordinals() + .as_ref() + .ok_or_else(|| CompilationError::OrdinalsError("Missing Ordinals Info".into()))? + .0[0] + .0; + let funds = ctx.funds(); + if funds < Amount::from(reveal.fee) + ord.padding() + Amount::ONE_SAT { + return Err(CompilationError::OutOfFunds); + } + let send_with = funds - reveal.fee.into(); + let tmpl = ctx.template(); + if let Some(address) = reveal.alternative { + tmpl.add_output(send_with, &Compiled::from_address(address, None), None) + } else { + tmpl.add_output(send_with, &self.owner, None) + }? + .add_fees(reveal.fee.into())? + .into() + } +} +impl StatefulArgumentsTrait for Reveal {} + +/// # The SimpleInscription Contract +impl Contract for InscribingStep { + declare! {updatable, Self::reveal} + + fn ensure_amount(&self, ctx: Context) -> Result { + // Optional if we want to require ordinal info provided -- we can + // happily track ordinals abstractly with some future patches. + let ords = ctx + .get_ordinals() + .as_ref() + .ok_or_else(|| CompilationError::OrdinalsError("Missing Ordinals Info".into()))?; + Ok(ords.total()) + } +} + + +REGISTER![InscribingStep, "logo.png"];