From 276d2277c48fd5610a1adbb812c78af756ea75ee Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 14 Jan 2025 14:45:10 +0100 Subject: [PATCH] unify single-use seals --- Cargo.lock | 36 +-- Cargo.toml | 32 +- cli/src/cmd.rs | 154 ++++------ examples/DemoToken.yaml | 2 +- examples/Transfer.yaml | 4 +- examples/data/bcor/NonInflatableAsset.issuer | Bin 2945 -> 0 bytes .../alice.wallet}/cache.yaml | 0 .../alice.wallet}/data.toml | 2 +- .../alice.wallet}/descriptor.toml | 2 +- examples/data2/bcor/NonInflatableAsset.issuer | Bin 2945 -> 0 bytes examples/data2/bcor/alice | 1 - .../bob.wallet}/cache.yaml | 0 .../bob.wallet}/data.toml | 2 +- .../bob.wallet}/descriptor.toml | 2 +- examples/script.sh | 22 +- psbt/src/common.rs | 8 - psbt/src/lib.rs | 2 +- src/descriptor.rs | 280 +++++++++++------- src/wallet.rs | 124 ++------ 19 files changed, 301 insertions(+), 372 deletions(-) delete mode 100644 examples/data/bcor/NonInflatableAsset.issuer rename examples/data/{bcor/alice => bitcoin.testnet/alice.wallet}/cache.yaml (100%) rename examples/data/{bcor/alice => bitcoin.testnet/alice.wallet}/data.toml (94%) rename examples/data/{bcor/alice => bitcoin.testnet/alice.wallet}/descriptor.toml (90%) delete mode 100644 examples/data2/bcor/NonInflatableAsset.issuer delete mode 120000 examples/data2/bcor/alice rename examples/data2/{bcor/bob => bitcoin.testnet/bob.wallet}/cache.yaml (100%) rename examples/data2/{bcor/bob => bitcoin.testnet/bob.wallet}/data.toml (93%) rename examples/data2/{bcor/bob => bitcoin.testnet/bob.wallet}/descriptor.toml (93%) diff --git a/Cargo.lock b/Cargo.lock index 16842425..e444c90f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,7 +294,7 @@ checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" [[package]] name = "bp-consensus" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#4ee5fc2af03e5eee82ff7e10d8c49f8c49451878" +source = "git+https://github.com/BP-WG/bp-core?branch=refactor/consensus#1645008e3aa31c762747a159877a2cd4550de933" dependencies = [ "amplify", "chrono", @@ -307,7 +307,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#4ee5fc2af03e5eee82ff7e10d8c49f8c49451878" +source = "git+https://github.com/BP-WG/bp-core?branch=refactor/consensus#1645008e3aa31c762747a159877a2cd4550de933" dependencies = [ "amplify", "bp-consensus", @@ -324,7 +324,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#4ee5fc2af03e5eee82ff7e10d8c49f8c49451878" +source = "git+https://github.com/BP-WG/bp-core?branch=refactor/consensus#1645008e3aa31c762747a159877a2cd4550de933" dependencies = [ "amplify", "base85", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "bp-derive" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.12#219ad166628c257b178d9c8658c778ceb50ae970" +source = "git+https://github.com/BP-WG/bp-std?branch=refactor/consensus#33198e0ba9fb6c2110da317990b161742202814d" dependencies = [ "amplify", "bp-consensus", @@ -387,7 +387,7 @@ dependencies = [ [[package]] name = "bp-invoice" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.12#219ad166628c257b178d9c8658c778ceb50ae970" +source = "git+https://github.com/BP-WG/bp-std?branch=refactor/consensus#33198e0ba9fb6c2110da317990b161742202814d" dependencies = [ "amplify", "bech32", @@ -400,7 +400,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#4ee5fc2af03e5eee82ff7e10d8c49f8c49451878" +source = "git+https://github.com/BP-WG/bp-core?branch=refactor/consensus#1645008e3aa31c762747a159877a2cd4550de933" dependencies = [ "amplify", "baid64", @@ -416,7 +416,7 @@ dependencies = [ [[package]] name = "bp-std" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.12#219ad166628c257b178d9c8658c778ceb50ae970" +source = "git+https://github.com/BP-WG/bp-std?branch=refactor/consensus#33198e0ba9fb6c2110da317990b161742202814d" dependencies = [ "amplify", "bp-consensus", @@ -698,7 +698,7 @@ dependencies = [ [[package]] name = "descriptors" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.12#219ad166628c257b178d9c8658c778ceb50ae970" +source = "git+https://github.com/BP-WG/bp-std?branch=refactor/consensus#33198e0ba9fb6c2110da317990b161742202814d" dependencies = [ "amplify", "bp-derive", @@ -930,7 +930,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hypersonic" version = "0.12.0-beta.4" -source = "git+https://github.com/AluVM/sonic#5e32310db8c3b23e9f55c048c78d6ac0548a3d86" +source = "git+https://github.com/AluVM/sonic?branch=refactor/consensus#cff215e4e3f33ab3c4b0fe027aff826a1c1ff644" dependencies = [ "aluvm", "amplify", @@ -1229,9 +1229,9 @@ checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" @@ -1365,7 +1365,7 @@ dependencies = [ [[package]] name = "psbt" version = "0.12.0-beta.4" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.12#219ad166628c257b178d9c8658c778ceb50ae970" +source = "git+https://github.com/BP-WG/bp-std?branch=refactor/consensus#33198e0ba9fb6c2110da317990b161742202814d" dependencies = [ "amplify", "base64", @@ -1480,7 +1480,7 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rgb-core" version = "0.12.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#e7748f424e7ab82606461a17ee89a0c91fcf56a2" +source = "git+https://github.com/RGB-WG/rgb-core?branch=refactor/consensus#7ba2b70f94bf7ceb8ca476051ba2d06e76f5c6bd" dependencies = [ "amplify", "bp-core", @@ -1496,7 +1496,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.12.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.12#9cc2dc2c0e1b370dad050a010008dc850b8df8be" +source = "git+https://github.com/RGB-WG/rgb-std?branch=refactor/consensus#74ce5ce1cc9a6379b566268c4e165998775ac319" dependencies = [ "amplify", "baid64", @@ -1543,7 +1543,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.12.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.12#9cc2dc2c0e1b370dad050a010008dc850b8df8be" +source = "git+https://github.com/RGB-WG/rgb-std?branch=refactor/consensus#74ce5ce1cc9a6379b566268c4e165998775ac319" dependencies = [ "amplify", "bp-core", @@ -1848,7 +1848,7 @@ dependencies = [ [[package]] name = "sonic-api" version = "0.12.0-beta.4" -source = "git+https://github.com/AluVM/sonic#5e32310db8c3b23e9f55c048c78d6ac0548a3d86" +source = "git+https://github.com/AluVM/sonic?branch=refactor/consensus#cff215e4e3f33ab3c4b0fe027aff826a1c1ff644" dependencies = [ "aluvm", "amplify", @@ -1867,7 +1867,7 @@ dependencies = [ [[package]] name = "sonic-callreq" version = "0.12.0-beta.4" -source = "git+https://github.com/AluVM/sonic#5e32310db8c3b23e9f55c048c78d6ac0548a3d86" +source = "git+https://github.com/AluVM/sonic?branch=refactor/consensus#cff215e4e3f33ab3c4b0fe027aff826a1c1ff644" dependencies = [ "amplify", "baid64", @@ -2096,7 +2096,7 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ultrasonic" version = "0.12.0-beta.4" -source = "git+https://github.com/AluVM/ultrasonic#32950ebd8c9ec32c8ef469107aab7744a7d37fab" +source = "git+https://github.com/AluVM/ultrasonic?branch=refactor/consensus#5e16d6b45e673156f807020c01e253636fe77405" dependencies = [ "amplify", "baid64", diff --git a/Cargo.toml b/Cargo.toml index d343b300..fa97792a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,20 +90,20 @@ serde = [ features = ["all"] [patch.crates-io] -ultrasonic = { git = "https://github.com/AluVM/ultrasonic" } -hypersonic = { git = "https://github.com/AluVM/sonic" } -sonic-api = { git = "https://github.com/AluVM/sonic" } -sonic-callreq = { git = "https://github.com/AluVM/sonic" } -bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "v0.12" } -bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "v0.12" } -bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "v0.12" } -bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.12" } -bp-invoice = { git = "https://github.com/BP-WG/bp-std", branch = "v0.12" } -bp-derive = { git = "https://github.com/BP-WG/bp-std", branch = "v0.12" } -descriptors = { git = "https://github.com/BP-WG/bp-std", branch = "v0.12" } -psbt = { git = "https://github.com/BP-WG/bp-std", branch = "v0.12" } -bp-std = { git = "https://github.com/BP-WG/bp-std", branch = "v0.12" } +ultrasonic = { git = "https://github.com/AluVM/ultrasonic", branch = "refactor/consensus" } +hypersonic = { git = "https://github.com/AluVM/sonic", branch = "refactor/consensus" } +sonic-api = { git = "https://github.com/AluVM/sonic", branch = "refactor/consensus" } +sonic-callreq = { git = "https://github.com/AluVM/sonic", branch = "refactor/consensus" } +bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "refactor/consensus" } +bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "refactor/consensus" } +bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "refactor/consensus" } +bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "refactor/consensus" } +bp-invoice = { git = "https://github.com/BP-WG/bp-std", branch = "refactor/consensus" } +bp-derive = { git = "https://github.com/BP-WG/bp-std", branch = "refactor/consensus" } +descriptors = { git = "https://github.com/BP-WG/bp-std", branch = "refactor/consensus" } +psbt = { git = "https://github.com/BP-WG/bp-std", branch = "refactor/consensus" } +bp-std = { git = "https://github.com/BP-WG/bp-std", branch = "refactor/consensus" } bp-wallet = { git = "https://github.com/BP-WG/bp-wallet", branch = "v0.12" } -rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.12" } -rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "v0.12" } -rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "v0.12" } +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "refactor/consensus" } +rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "refactor/consensus" } +rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "refactor/consensus" } diff --git a/cli/src/cmd.rs b/cli/src/cmd.rs index 8210f80f..db75f916 100644 --- a/cli/src/cmd.rs +++ b/cli/src/cmd.rs @@ -30,8 +30,6 @@ use std::str::FromStr; use amplify::ByteArray; use bpwallet::cli::ResolverOpt; -use bpwallet::dbc::opret::OpretProof; -use bpwallet::dbc::tapret::TapretProof; use bpwallet::fs::FsTextStore; use bpwallet::indexers::esplora; use bpwallet::psbt::TxParams; @@ -40,20 +38,20 @@ use clap::ValueHint; use rgb::invoice::RgbInvoice; use rgb::popls::bp::file::{DirBarrow, DirMound}; use rgb::popls::bp::{PrefabBundle, PrefabParamsSet, WoutAssignment}; -use rgb::{AuthToken, ContractId, CreateParams, Outpoint, SealType}; -use rgbp::descriptor::{Opret, Tapret}; +use rgb::{AuthToken, Consensus, ContractId, CreateParams, Outpoint}; +use rgbp::descriptor::RgbDescr; use rgbp::wallet::file::DirRuntime; -use rgbp::wallet::{OpretWallet, TapretWallet}; +use rgbp::wallet::RgbWallet; use rgbp::CoinselectStrategy; use rgpsbt::{RgbPsbt, ScriptResolver}; use strict_encoding::{StrictDeserialize, StrictSerialize}; use crate::opts::WalletOpts; -pub const RGB_COINSELECT_STRATEGY_ENV: &str = "RGB_COINSELECT_STRATEGY"; -pub const RGB_SEAL_ENV: &str = "RGB_SEAL"; pub const RGB_NETWORK_ENV: &str = "RGB_NETWORK"; +pub const RGB_NO_NETWORK_PREFIX_ENV: &str = "RGB_NO_NETWORK_PREFIX"; pub const RGB_WALLET_ENV: &str = "RGB_WALLET"; +pub const RGB_COINSELECT_STRATEGY_ENV: &str = "RGB_COINSELECT_STRATEGY"; pub const RGB_DATA_DIR_ENV: &str = "RGB_DATA_DIR"; #[cfg(target_os = "linux")] @@ -86,14 +84,14 @@ pub struct Args { #[clap(long, global = true)] pub init: bool, - /// Type of single-use seals to use - #[clap(short, long, global = true, default_value = "bctr", env = RGB_SEAL_ENV)] - pub seal: SealType, - - /// Network to use + /// Bitcoin network #[arg(short, long, global = true, default_value = "testnet4", env = RGB_NETWORK_ENV)] pub network: Network, + /// Do not add network name as a prefix to the data directory + #[arg(long, global = true, env = RGB_NO_NETWORK_PREFIX_ENV)] + pub no_network_prefix: bool, + /// Command to execute #[clap(subcommand)] pub command: Cmd, @@ -289,47 +287,45 @@ pub enum Cmd { } impl Args { + pub fn data_dir(&self) -> PathBuf { + if self.no_network_prefix { + self.data_dir.clone() + } else { + let mut dir = self.data_dir.join("bitcoin"); + if self.network.is_testnet() { + dir.set_extension("testnet"); + } + dir + } + } + pub fn mound(&self) -> DirMound { if self.init { - let _ = fs::create_dir_all(self.data_dir.join(SealType::BitcoinOpret.to_string())); - let _ = fs::create_dir_all(self.data_dir.join(SealType::BitcoinTapret.to_string())); + let _ = fs::create_dir_all(&self.data_dir()); + } + if !self.network.is_testnet() { + panic!("Non-testnet networks are not yet supported"); } - DirMound::load(&self.data_dir) + DirMound::load_testnet(Consensus::Bitcoin, &self.data_dir, self.no_network_prefix) } - fn wallet_file(&self, name: Option<&str>) -> PathBuf { - let path = self.data_dir.join(self.seal.to_string()); - path.join(name.unwrap_or("default")) + fn wallet_dir(&self, name: Option<&str>) -> PathBuf { + self.data_dir() + .join(name.unwrap_or("default")) + .with_extension("wallet") } pub fn wallet_provider(&self, name: Option<&str>) -> FsTextStore { - FsTextStore::new(self.wallet_file(name)).expect("Broken directory structure") + FsTextStore::new(self.wallet_dir(name)).expect("Broken directory structure") } pub fn runtime(&self, name: Option<&str>) -> DirRuntime { let provider = self.wallet_provider(name); - let wallet = match self.seal { - SealType::BitcoinOpret => { - let wallet = OpretWallet::load(provider, true).unwrap_or_else(|_| { - panic!( - "Error: unable to load opret wallet from path `{}`", - self.wallet_file(name).display() - ) - }); - DirBarrow::with_opret(self.seal, self.mound(), wallet) - } - SealType::BitcoinTapret => { - let wallet = TapretWallet::load(provider, true).unwrap_or_else(|_| { - panic!( - "Error: unable to load tapret wallet from path `{}`", - self.wallet_file(name).display() - ) - }); - DirBarrow::with_tapret(self.seal, self.mound(), wallet) - } - }; + let wallet = RgbWallet::load(provider, true).unwrap_or_else(|_| { + panic!("Error: unable to load wallet from path `{}`", self.wallet_dir(name).display()) + }); + DirRuntime::from(DirBarrow::with(wallet, self.mound())) // TODO: Sync wallet if needed - wallet.into() } pub fn indexer(&self, resolver: &ResolverOpt) -> AnyIndexer { @@ -373,7 +369,7 @@ impl Args { let mut runtime = self.runtime(wallet.as_deref()); let file = File::open(params).expect("Unable to open parameters file"); let params = serde_yaml::from_reader::<_, CreateParams>(file)?; - let contract_id = runtime.issue_to_file(params); + let contract_id = runtime.issue_to_file(params)?; println!("A new contract issued with ID {contract_id}"); } @@ -383,26 +379,13 @@ impl Args { let provider = self.wallet_provider(Some(name)); let xpub = XpubDerivable::from_str(descriptor).expect("Invalid extended pubkey"); let noise = xpub.xpub().chain_code().to_byte_array(); - match self.seal { - SealType::BitcoinOpret => { - OpretWallet::create( - provider, - Opret::new_unfunded(Wpkh::from(xpub), noise), - self.network, - true, - ) - .expect("Unable to create wallet"); - } - SealType::BitcoinTapret => { - TapretWallet::create( - provider, - Tapret::key_only_unfunded(xpub, noise), - self.network, - true, - ) - .expect("Unable to create wallet"); - } - } + RgbWallet::create( + provider, + RgbDescr::new_unfunded(Wpkh::from(xpub), noise), + self.network, + true, + ) + .expect("Unable to create wallet"); } Cmd::Contracts => { @@ -415,14 +398,7 @@ impl Args { Cmd::Fund { wallet } => { let mut runtime = self.runtime(wallet.as_deref()); - let addr = match self.seal { - SealType::BitcoinOpret => { - runtime.wallet_opret().next_address(Keychain::OUTER, true) - } - SealType::BitcoinTapret => { - runtime.wallet_tapret().next_address(Keychain::OUTER, true) - } - }; + let addr = runtime.wallet.next_address(Keychain::OUTER, true); println!("{addr}"); } @@ -446,14 +422,14 @@ impl Args { let mut runtime = self.runtime(wallet.wallet.as_deref()); if wallet.sync { let indexer = self.indexer(&wallet.resolver); - match self.seal { - SealType::BitcoinOpret => runtime.wallet_opret().update(&indexer), - SealType::BitcoinTapret => runtime.wallet_tapret().update(&indexer), - }; + runtime.wallet.update(&indexer); println!(); } - let state = - if *all { runtime.state_all(*contract) } else { runtime.state(*contract) }; + let state = if *all { + runtime.state_all(*contract).collect::>() + } else { + runtime.state(*contract).collect() + }; for (contract_id, state) in state { println!("{contract_id}"); if *global { @@ -573,19 +549,9 @@ impl Args { .collect::>(); let mut runtime = self.runtime(wallet.as_deref()); - // TODO: Attest possible oprets for tapret wallet - match &mut runtime.0 { - DirBarrow::BcOpret(barrow) => { - let (mpc, dbc) = psbt.dbc_commit::()?; - let tx = psbt.to_unsigned_tx(); - barrow.attest(&bundle, &tx.into(), mpc, dbc, &prevouts); - } - DirBarrow::BcTapret(barrow) => { - let (mpc, dbc) = psbt.dbc_commit::()?; - let tx = psbt.to_unsigned_tx(); - barrow.attest(&bundle, &tx.into(), mpc, dbc, &prevouts); - } - }; + let (mpc, dbc) = psbt.dbc_commit()?; + let tx = psbt.to_unsigned_tx(); + runtime.attest(&bundle, &tx.into(), mpc, dbc, &prevouts); psbt.encode( psbt.version, @@ -595,15 +561,9 @@ impl Args { Cmd::Consign { contract, terminals, output } => { let mut mound = self.mound(); - match self.seal { - SealType::BitcoinOpret => { - mound.bc_opret.consign_to_file(*contract, terminals, output) - } - SealType::BitcoinTapret => mound - .bc_tapret - .consign_to_file(*contract, terminals, output), - } - .expect("Unable to consign contract"); + mound + .consign_to_file(*contract, terminals, output) + .expect("Unable to consign contract"); } Cmd::Accept { wallet, input } => { diff --git a/examples/DemoToken.yaml b/examples/DemoToken.yaml index 832503da..0a3582c4 100644 --- a/examples/DemoToken.yaml +++ b/examples/DemoToken.yaml @@ -1,4 +1,4 @@ -sealType: bcor +consensus: bitcoin testnet: true codexId: znwQGVhW-rfRa8el-pNaAsUW-UWxXsB_-4UlC~Tf-TERhBm4#mirage-queen-delphi name: DemoToken diff --git a/examples/Transfer.yaml b/examples/Transfer.yaml index 5307e704..2052bd8b 100644 --- a/examples/Transfer.yaml +++ b/examples/Transfer.yaml @@ -1,9 +1,9 @@ -- contractId: gDmGtRAO-gp3AQ78-jqEzM8S-_u8FVot-g2WaGXD-xLdIWXQ +- contractId: qKpMlzOe-Imn6ysZ-a8JjG2p-WHWvaFm-BWMiPi3-_LvnfRw method: transfer reading: [ ] global: [ ] using: - - addr: 71dJZXJbPfkGBe5tL0cJ4YGu_MOYcE22LGYC~7ppXYM:0 + - addr: L28_t0y5~n3eYz4hR40Vt3rRaH9PptXJragTHTvZTCU:0 outpoint: b7116550736fbe5d3e234d0141c6bc8d1825f94da78514a3cede5674e9a5eae9:1 val: 10000 owned: diff --git a/examples/data/bcor/NonInflatableAsset.issuer b/examples/data/bcor/NonInflatableAsset.issuer deleted file mode 100644 index 58c9fe00a03ff0679abb6f3ba8598c75a1ec2abc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2945 zcmdT`c}x^%6rbTT*ukjZ`qOAncX=!yrb5G z7KPS|;ziZiYNXnr@d(9wm6&2}t+kaZ3YJ){x7b#p&{>4~Ps=oE)1)ui*FLA6FautX=V4 zMAh{X-5L+Fzk1d8`{lO>RCQsADX9F`y&aVkHwABFfs&&x1?MO`3jA_a0e<{WN}p3P z8AH2&ytjPD)?Uc-?sj`r%#wR6YpC%Nl>Ky{28Ij>RljgKv;hwdNBSIfX-Pp89 zGW7Ln3K(_1YR7@;Ya6<=D3p|g>-V=gnXe(@|_>5)w`nfd?<60~C*RMIYaojhxd7W2l>i}x)Lx9tv zi?$uDfcfItb*4-8`|u~9e;qmT)2d2$uOqr1*!qiV)gr)2%BOLALusz3_HNZ~zjfiu z3$E(6?CkzS?17}8GmDSqPOTc~H}uC9F{L+`hm>g}^v^tl7TkVoVA#!NJ6Fp$HyqKB zgy^7XWWZ4#&H8JdGA|)<0B)m1+d!>_XIV;k)y;tf8gbGfJ!My*sEnq;?v#TUC4qO? zP=L-XP)c)2aj$iv`@ zAF1Iv6r_=I`B8*q6A%iTb6(*Q{QHWrf8ra^N0bV$a zE!Rt(3n&Vh&48wX#R3olRx8NL0yZ097%*=h$j$~V3+#5lae(K6!vUO5AP7Jdfg}N0 z201w(Hy7mPf&6?hf4-jXyvPFF!8p*uKMs-?5fZ~%(Bk+o(}|jAqn|FhRJI|vZ`{`oKCm)#O-ey20n{GI?Du2SOpPJ;iYsoEjXZq+;<>}6ReN3@;oW~s`oU^{ z&;FQBZOUo7doY}Z$x%k4vJElZqD)6XxLS{aO6RaFqtUz0;$0ATZztL@p|G^TYdcs4 zx^=P&)+y7RMO9Nm!9x;=S5!PIf`>=Qi81 z4^BxE?@P`Z+<1lvdnG2?nE6>5nou^>t++YJ$L`$q>~hcgl$o0Ff70InRipm9&9-dd z(kA)A-Ghg&81swk#G>*Y-&e?iaax;kFQDOulbVqKXIyGKjR0ydKy6wRP%U>)ThS-G zTkTT*ukjZ`qOAncX=!yrb5G z7KPS|;ziZiYNXnr@d(9wm6&2}t+kaZ3YJ){x7b#p&{>4~Ps=oE)1)ui*FLA6FautX=V4 zMAh{X-5L+Fzk1d8`{lO>RCQsADX9F`y&aVkHwABFfs&&x1?MO`3jA_a0e<{WN}p3P z8AH2&ytjPD)?Uc-?sj`r%#wR6YpC%Nl>Ky{28Ij>RljgKv;hwdNBSIfX-Pp89 zGW7Ln3K(_1YR7@;Ya6<=D3p|g>-V=gnXe(@|_>5)w`nfd?<60~C*RMIYaojhxd7W2l>i}x)Lx9tv zi?$uDfcfItb*4-8`|u~9e;qmT)2d2$uOqr1*!qiV)gr)2%BOLALusz3_HNZ~zjfiu z3$E(6?CkzS?17}8GmDSqPOTc~H}uC9F{L+`hm>g}^v^tl7TkVoVA#!NJ6Fp$HyqKB zgy^7XWWZ4#&H8JdGA|)<0B)m1+d!>_XIV;k)y;tf8gbGfJ!My*sEnq;?v#TUC4qO? zP=L-XP)c)2aj$iv`@ zAF1Iv6r_=I`B8*q6A%iTb6(*Q{QHWrf8ra^N0bV$a zE!Rt(3n&Vh&48wX#R3olRx8NL0yZ097%*=h$j$~V3+#5lae(K6!vUO5AP7Jdfg}N0 z201w(Hy7mPf&6?hf4-jXyvPFF!8p*uKMs-?5fZ~%(Bk+o(}|jAqn|FhRJI|vZ`{`oKCm)#O-ey20n{GI?Du2SOpPJ;iYsoEjXZq+;<>}6ReN3@;oW~s`oU^{ z&;FQBZOUo7doY}Z$x%k4vJElZqD)6XxLS{aO6RaFqtUz0;$0ATZztL@p|G^TYdcs4 zx^=P&)+y7RMO9Nm!9x;=S5!PIf`>=Qi81 z4^BxE?@P`Z+<1lvdnG2?nE6>5nou^>t++YJ$L`$q>~hcgl$o0Ff70InRipm9&9-dd z(kA)A-Ghg&81swk#G>*Y-&e?iaax;kFQDOulbVqKXIyGKjR0ydKy6wRP%U>)ThS-G zTk, - pub tapret: Anchor, -} - pub trait RgbPsbt { // TODO: Add rgb_embed to embed operations for hardware signers fn rgb_fill_csv(&mut self, bundle: PrefabBundle) -> Result<(), RgbPsbtError>; diff --git a/psbt/src/lib.rs b/psbt/src/lib.rs index ff031885..a868aa3d 100644 --- a/psbt/src/lib.rs +++ b/psbt/src/lib.rs @@ -29,4 +29,4 @@ mod common; #[cfg(feature = "bp")] mod bp; -pub use common::{AnchorPair, RgbPsbt, RgbPsbtError, ScriptResolver}; +pub use common::{RgbPsbt, RgbPsbtError, ScriptResolver}; diff --git a/src/descriptor.rs b/src/descriptor.rs index 7f26f919..c0a9d5f7 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -26,26 +26,28 @@ use alloc::collections::{BTreeMap, BTreeSet}; use core::fmt::{self, Display, Formatter}; use std::collections::HashMap; +use amplify::confinement::Collection; use amplify::{Bytes32, Wrapper, WrapperMut}; use bpstd::dbc::tapret::TapretCommitment; -use bpstd::seals::{TxoSeal, TxoSealDef}; +use bpstd::seals::TxoSeal; use bpstd::{ - dbc, Derive, DeriveSet, DeriveXOnly, DerivedScript, Descriptor, KeyOrigin, Keychain, - LegacyKeySig, LegacyPk, NormalIndex, SigScript, SpkClass, StdDescr, TapDerivation, TapScript, - TapTree, TaprootKeySig, Terminal, Tr, TrKey, Witness, XOnlyPk, XpubAccount, XpubDerivable, + Derive, DeriveCompr, DeriveKey, DeriveSet, DeriveXOnly, DerivedScript, Descriptor, KeyOrigin, + Keychain, LegacyKeySig, LegacyPk, NormalIndex, SigScript, SpkClass, StdDescr, TapDerivation, + TapScript, TapTree, TaprootKeySig, Terminal, Tr, TrKey, Witness, XOnlyPk, XpubAccount, + XpubDerivable, }; use commit_verify::CommitVerify; use indexmap::IndexMap; -pub trait DescriptorRgb: Descriptor { - fn add_seal(&self, seal: TxoSeal); +pub trait DescriptorRgb: Descriptor { + fn add_seal(&self, seal: TxoSeal); } #[derive(Wrapper, WrapperMut, Clone, Eq, PartialEq, Debug, Default, From)] #[wrapper(Deref)] #[wrapper_mut(DerefMut)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] -pub struct SealDescr(BTreeSet); +pub struct SealDescr(BTreeSet); impl Display for SealDescr { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -61,8 +63,34 @@ impl Display for SealDescr { } } -#[derive(Clone, Display)] -#[display("opret({descr}, {seals})")] +#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Debug, Default, From)] +#[wrapper(Deref)] +#[wrapper_mut(DerefMut)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +pub struct TapretWeaks(BTreeMap>); + +impl Display for TapretWeaks { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("tweaks(")?; + let mut iter1 = self.iter().peekable(); + while let Some((term, tweaks)) = iter1.next() { + write!(f, "{term}=")?; + let mut iter2 = tweaks.iter().peekable(); + while let Some(tweak) = iter2.next() { + write!(f, "{tweak}")?; + if iter2.peek().is_some() { + f.write_str(",")?; + } + } + if iter1.peek().is_some() { + f.write_str(";")?; + } + } + f.write_str(")") + } +} + +#[derive(Clone, Display, From)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -74,174 +102,212 @@ impl Display for SealDescr { ) ) )] -pub struct Opret { - pub descr: StdDescr, - pub seals: SealDescr, - pub noise: Bytes32, +enum RgbDeriver { + #[from] + #[display(inner)] + OpretOnly(StdDescr), + + #[display("{tr},{tweaks}")] + Universal { + tr: Tr, + tweaks: TapretWeaks, + }, } -impl Opret { - pub fn new_unfunded(descr: impl Into>, noise: impl Into<[u8; 32]>) -> Self { - Self { - descr: descr.into(), - seals: empty!(), - noise: noise.into().into(), +impl Derive for RgbDeriver { + fn default_keychain(&self) -> Keychain { + match self { + RgbDeriver::OpretOnly(d) => d.default_keychain(), + RgbDeriver::Universal { tr, tweaks: _ } => tr.default_keychain(), + } + } + + fn keychains(&self) -> BTreeSet { + match self { + RgbDeriver::OpretOnly(d) => d.keychains(), + RgbDeriver::Universal { tr, tweaks: _ } => tr.keychains(), } } -} -impl Derive for Opret { - fn default_keychain(&self) -> Keychain { self.descr.default_keychain() } - fn keychains(&self) -> BTreeSet { self.descr.keychains() } fn derive( &self, keychain: impl Into, index: impl Into, ) -> impl Iterator { - self.descr.derive(keychain, index) + match self { + RgbDeriver::OpretOnly(d) => d.derive(keychain, index).collect::>().into_iter(), + RgbDeriver::Universal { tr, tweaks } => { + let keychain = keychain.into(); + let index = index.into(); + let terminal = Terminal::new(keychain, index); + let mut vec = Vec::with_capacity(tweaks.0.len()); + for internal_key in tr.as_internal_key().derive(keychain, index) { + for tweak in tweaks.get(&terminal).into_iter().flatten() { + let script_commitment = TapScript::commit(tweak); + let tap_tree = TapTree::with_single_leaf(script_commitment); + let script = DerivedScript::TaprootScript(internal_key.into(), tap_tree); + vec.push(script); + } + } + vec.into_iter() + } + } } } -impl Descriptor for Opret -where - Self: Clone, - StdDescr: Descriptor, +impl + DeriveCompr + DeriveXOnly> Descriptor + for RgbDeriver { - fn class(&self) -> SpkClass { self.descr.class() } + fn class(&self) -> SpkClass { + match self { + RgbDeriver::OpretOnly(d) => d.class(), + RgbDeriver::Universal { tr, tweaks: _ } => tr.class(), + } + } fn keys<'a>(&'a self) -> impl Iterator where K: 'a { - self.descr.keys() + match self { + RgbDeriver::OpretOnly(d) => d.keys().collect::>().into_iter(), + RgbDeriver::Universal { tr, tweaks: _ } => tr.keys().collect::>().into_iter(), + } } fn vars<'a>(&'a self) -> impl Iterator where (): 'a { - self.descr.vars() + match self { + RgbDeriver::OpretOnly(d) => d.vars().collect::>().into_iter(), + RgbDeriver::Universal { tr, tweaks: _ } => tr.vars().collect::>().into_iter(), + } + } + fn xpubs(&self) -> impl Iterator { + match self { + RgbDeriver::OpretOnly(d) => d.xpubs().collect::>().into_iter(), + RgbDeriver::Universal { tr, tweaks: _ } => tr.xpubs().collect::>().into_iter(), + } } - fn xpubs(&self) -> impl Iterator { self.descr.xpubs() } fn legacy_keyset(&self, terminal: Terminal) -> IndexMap { - self.descr.legacy_keyset(terminal) + match self { + RgbDeriver::OpretOnly(d) => d.legacy_keyset(terminal), + RgbDeriver::Universal { tr, tweaks: _ } => tr.legacy_keyset(terminal), + } } fn xonly_keyset(&self, terminal: Terminal) -> IndexMap { - self.descr.xonly_keyset(terminal) + match self { + RgbDeriver::OpretOnly(d) => d.xonly_keyset(terminal), + RgbDeriver::Universal { tr, tweaks: _ } => tr.xonly_keyset(terminal), + } } fn legacy_witness( &self, keysigs: HashMap<&KeyOrigin, LegacyKeySig>, ) -> Option<(SigScript, Witness)> { - self.descr.legacy_witness(keysigs) + match self { + RgbDeriver::OpretOnly(d) => d.legacy_witness(keysigs), + RgbDeriver::Universal { tr, tweaks: _ } => tr.legacy_witness(keysigs), + } } fn taproot_witness(&self, keysigs: HashMap<&KeyOrigin, TaprootKeySig>) -> Option { - self.descr.taproot_witness(keysigs) + match self { + RgbDeriver::OpretOnly(d) => d.taproot_witness(keysigs), + RgbDeriver::Universal { tr, tweaks: _ } => tr.taproot_witness(keysigs), + } } } -/// NB: Tapret wallet also supports opret contracts -#[derive(Clone, Eq, PartialEq, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] -pub struct Tapret { - pub tr: Tr, - pub tweaks: BTreeMap>, - pub seals: SealDescr, - pub noise: Bytes32, +#[derive(Clone, Display)] +#[display("rgb({deriver},{seals},noise({noise:x}))")] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde( + rename_all = "camelCase", + bound( + serialize = "K::Compr: serde::Serialize, K::XOnly: serde::Serialize", + deserialize = "K::Compr: serde::Deserialize<'de>, K::XOnly: serde::Deserialize<'de>" + ) + ) +)] +pub struct RgbDescr { + deriver: RgbDeriver, + seals: SealDescr, + noise: Bytes32, } -impl Display for Tapret { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str("tapret(")?; - match &self.tr { - Tr::KeyOnly(d) => Display::fmt(d.as_internal_key(), f)?, - } - if !self.tweaks.is_empty() { - f.write_str(",tweaks(")?; - let mut iter1 = self.tweaks.iter().peekable(); - while let Some((term, tweaks)) = iter1.next() { - write!(f, "{term}=")?; - let mut iter2 = tweaks.iter().peekable(); - while let Some(tweak) = iter2.next() { - write!(f, "{tweak}")?; - if iter2.peek().is_some() { - f.write_str(",")?; - } - } - if iter1.peek().is_some() { - f.write_str(";")?; - } - } - f.write_str(")")?; - } - if !self.seals.is_empty() { - write!(f, ",{}", self.seals)?; - } - f.write_str(")") +impl RgbDescr { + pub fn new_unfunded(deriver: impl Into>, noise: impl Into<[u8; 32]>) -> Self { + let deriver = match deriver.into() { + StdDescr::Wpkh(d) => RgbDeriver::OpretOnly(StdDescr::Wpkh(d)), + StdDescr::TrKey(tr) => RgbDeriver::Universal { tr: Tr::KeyOnly(tr), tweaks: empty!() }, + _ => unreachable!(), + }; + Self { deriver, seals: empty!(), noise: noise.into().into() } } -} -impl Tapret { - pub fn key_only_unfunded(internal_key: K, noise: impl Into<[u8; 32]>) -> Self { + pub fn key_only_unfunded(internal_key: K, noise: impl Into<[u8; 32]>) -> Self + where K: DeriveSet + DeriveKey { Self { - tr: Tr::KeyOnly(TrKey::from(internal_key)), - tweaks: empty!(), + deriver: RgbDeriver::Universal { + tr: Tr::KeyOnly(TrKey::from(internal_key)), + tweaks: empty!(), + }, seals: empty!(), noise: noise.into().into(), } } + pub fn noise(&self) -> Bytes32 { self.noise } + + pub fn seals(&self) -> impl Iterator { self.seals.iter() } + + pub fn add_seal(&mut self, seal: TxoSeal) { self.seals.push(seal); } + pub fn add_tweak(&mut self, terminal: Terminal, tweak: TapretCommitment) { - self.tweaks.entry(terminal).or_default().insert(tweak); + match &mut self.deriver { + RgbDeriver::OpretOnly(_) => { + panic!("attempting to add tapret tweaks to an opret-only wallet") + } + RgbDeriver::Universal { tr: _, tweaks } => { + tweaks.entry(terminal).or_default().insert(tweak); + } + } } } -impl Derive for Tapret { - fn default_keychain(&self) -> Keychain { self.tr.default_keychain() } - fn keychains(&self) -> BTreeSet { self.tr.keychains() } +impl Derive for RgbDescr { + fn default_keychain(&self) -> Keychain { self.deriver.default_keychain() } + fn keychains(&self) -> BTreeSet { self.deriver.keychains() } fn derive( &self, keychain: impl Into, index: impl Into, ) -> impl Iterator { - let keychain = keychain.into(); - let index = index.into(); - let terminal = Terminal::new(keychain, index); - self.tr - .as_internal_key() - .derive(keychain, index) - .flat_map(move |internal_key| { - self.tweaks - .get(&terminal) - .into_iter() - .flatten() - .map(move |tweak| { - let script_commitment = TapScript::commit(tweak); - let tap_tree = TapTree::with_single_leaf(script_commitment); - DerivedScript::TaprootScript(internal_key.into(), tap_tree) - }) - }) + self.deriver.derive(keychain, index) } } -impl Descriptor for Tapret { - fn class(&self) -> SpkClass { self.tr.class() } +impl + DeriveCompr + DeriveXOnly> Descriptor for RgbDescr { + fn class(&self) -> SpkClass { self.deriver.class() } fn keys<'a>(&'a self) -> impl Iterator where K: 'a { - self.tr.keys() + self.deriver.keys() } fn vars<'a>(&'a self) -> impl Iterator where (): 'a { - self.tr.vars() + self.deriver.vars() } - fn xpubs(&self) -> impl Iterator { self.tr.xpubs() } + fn xpubs(&self) -> impl Iterator { self.deriver.xpubs() } fn legacy_keyset(&self, terminal: Terminal) -> IndexMap { - self.tr.legacy_keyset(terminal) + self.deriver.legacy_keyset(terminal) } fn xonly_keyset(&self, terminal: Terminal) -> IndexMap { - self.tr.xonly_keyset(terminal) + self.deriver.xonly_keyset(terminal) } fn legacy_witness( &self, keysigs: HashMap<&KeyOrigin, LegacyKeySig>, ) -> Option<(SigScript, Witness)> { - self.tr.legacy_witness(keysigs) + self.deriver.legacy_witness(keysigs) } fn taproot_witness(&self, keysigs: HashMap<&KeyOrigin, TaprootKeySig>) -> Option { - self.tr.taproot_witness(keysigs) + self.deriver.taproot_witness(keysigs) } } diff --git a/src/wallet.rs b/src/wallet.rs index ae56e66d..7df3ca4b 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -26,32 +26,32 @@ use std::convert::Infallible; use amplify::Bytes32; use bpstd::psbt::PsbtConstructor; -use bpstd::seals::TxoSealDef; +use bpstd::seals::TxoSeal; use bpstd::{Address, Keychain, Network, Outpoint, XpubDerivable}; use bpwallet::{Layer2Empty, NoLayer2, Wallet, WalletCache, WalletData, WalletDescr}; use nonasync::persistence::{PersistenceError, PersistenceProvider}; -use rgb::popls::bp::{OpretProvider, TapretProvider, WalletProvider}; +use rgb::popls::bp::WalletProvider; use rgb::{AuthToken, SealAuthToken}; -use crate::descriptor::{Opret, Tapret}; +use crate::descriptor::RgbDescr; // TODO: Use layer 2 supporting Lightning #[derive(Wrapper, WrapperMut, From)] #[wrapper(Deref)] #[wrapper_mut(DerefMut)] -pub struct OpretWallet(pub Wallet, NoLayer2>); +pub struct RgbWallet(pub Wallet, NoLayer2>); -impl WalletProvider for OpretWallet { - fn noise_seed(&self) -> Bytes32 { self.noise } +impl WalletProvider for RgbWallet { + fn noise_seed(&self) -> Bytes32 { self.noise() } fn has_utxo(&self, outpoint: Outpoint) -> bool { self.0.utxo(outpoint).is_some() } fn utxos(&self) -> impl Iterator { self.0.utxos().map(|utxo| utxo.outpoint) } - fn register_seal(&mut self, seal: TxoSealDef) { + fn register_seal(&mut self, seal: TxoSeal) { let _ = self.0.descriptor_mut(|wd| { wd.with_descriptor_mut(|d| { - d.seals.insert(seal); + d.add_seal(seal); Ok::<_, Infallible>(()) }) }); @@ -60,13 +60,12 @@ impl WalletProvider for OpretWallet { fn resolve_seals( &self, seals: impl Iterator, - ) -> impl Iterator { + ) -> impl Iterator { seals .flat_map(|auth| { self.0 .descriptor() - .seals - .iter() + .seals() .filter(move |seal| seal.auth_token() == auth) }) .copied() @@ -74,18 +73,17 @@ impl WalletProvider for OpretWallet { fn next_address(&mut self) -> Address { self.0.next_address(Keychain::OUTER, true) } } -impl OpretProvider for OpretWallet {} -impl OpretWallet { +impl RgbWallet { pub fn create

( provider: P, - descr: Opret, + descr: RgbDescr, network: Network, autosave: bool, ) -> Result where P: Clone - + PersistenceProvider, Layer2Empty>> + + PersistenceProvider, Layer2Empty>> + PersistenceProvider> + PersistenceProvider> + PersistenceProvider @@ -98,83 +96,12 @@ impl OpretWallet { pub fn load

(provider: P, autosave: bool) -> Result where P: Clone - + PersistenceProvider, Layer2Empty>> + + PersistenceProvider, Layer2Empty>> + PersistenceProvider> + PersistenceProvider> + PersistenceProvider + 'static { - Wallet::load(provider, autosave).map(OpretWallet) - } -} - -#[derive(Wrapper, WrapperMut, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -pub struct TapretWallet(pub Wallet, NoLayer2>); - -impl WalletProvider for TapretWallet { - fn noise_seed(&self) -> Bytes32 { self.noise } - - fn has_utxo(&self, outpoint: Outpoint) -> bool { self.0.utxo(outpoint).is_some() } - - fn utxos(&self) -> impl Iterator { self.0.utxos().map(|utxo| utxo.outpoint) } - - fn register_seal(&mut self, seal: TxoSealDef) { - let _ = self.0.descriptor_mut(|wd| { - wd.with_descriptor_mut(|d| { - d.seals.insert(seal); - Ok::<_, Infallible>(()) - }) - }); - } - - fn resolve_seals( - &self, - seals: impl Iterator, - ) -> impl Iterator { - seals - .flat_map(|auth| { - self.0 - .descriptor() - .seals - .iter() - .filter(move |seal| seal.auth_token() == auth) - }) - .copied() - } - - fn next_address(&mut self) -> Address { self.0.next_address(Keychain::OUTER, true) } -} -impl TapretProvider for TapretWallet {} - -impl TapretWallet { - pub fn create

( - provider: P, - descr: Tapret, - network: Network, - autosave: bool, - ) -> Result - where - P: Clone - + PersistenceProvider, Layer2Empty>> - + PersistenceProvider> - + PersistenceProvider> - + PersistenceProvider - + 'static, - { - let mut wallet = Wallet::new_layer1(descr, network); - wallet.make_persistent(provider, autosave)?; - Ok(Self(wallet)) - } - - pub fn load

(provider: P, autosave: bool) -> Result - where P: Clone - + PersistenceProvider, Layer2Empty>> - + PersistenceProvider> - + PersistenceProvider> - + PersistenceProvider - + 'static { - Wallet::load(provider, autosave).map(TapretWallet) + Wallet::load(provider, autosave).map(RgbWallet) } } @@ -191,16 +118,9 @@ pub mod file { #[derive(Wrapper, WrapperMut, From)] #[wrapper(Deref)] #[wrapper_mut(DerefMut)] - pub struct DirRuntime(pub DirBarrow); + pub struct DirRuntime(DirBarrow); impl DirRuntime { - pub fn network(&self) -> Network { - match &self.0 { - DirBarrow::BcOpret(barrow) => barrow.wallet.network(), - DirBarrow::BcTapret(barrow) => barrow.wallet.network(), - } - } - pub fn construct_psbt( &mut self, bundle: &PrefabParamsSet, @@ -210,7 +130,7 @@ pub mod file { .iter() .flat_map(|params| ¶ms.using) .map(|used| used.outpoint); - let network = self.network(); + let network = self.0.wallet.network(); let beneficiaries = bundle .iter() .flat_map(|params| ¶ms.owned) @@ -223,15 +143,7 @@ pub mod file { .expect("script pubkey which is not representable as an address"); Beneficiary::new(address, seal.amount) }); - let (psbt, meta) = match &mut self.0 { - DirBarrow::BcOpret(barrow) => { - barrow.wallet.construct_psbt(closes, beneficiaries, params) - } - DirBarrow::BcTapret(barrow) => { - barrow.wallet.construct_psbt(closes, beneficiaries, params) - } - }?; - Ok((psbt, meta)) + self.0.wallet.construct_psbt(closes, beneficiaries, params) } } }