Skip to content

Commit 7be3c3e

Browse files
committed
PoC of schema
1 parent 9800d09 commit 7be3c3e

12 files changed

Lines changed: 431 additions & 411 deletions

File tree

crates/wallet-abi/src/error.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use lwk_wollet::blocking::EsploraClient;
2-
use std::sync::{MutexGuard, PoisonError};
31
use lwk_wollet::elements::UnblindError;
42
use thiserror::Error;
53

@@ -100,7 +98,7 @@ pub enum WalletAbiError {
10098
LWKWollet(#[from] lwk_wollet::Error),
10199

102100
#[error("TXOut unblinding error: {0}")]
103-
Unblind(#[from] UnblindError)
101+
Unblind(#[from] UnblindError),
104102
}
105103

106104
/// Errors that occur during binary or hex encoding/decoding operations.

crates/wallet-abi/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub use lwk_common::Network;
2828
pub use lwk_simplicity::error::ProgramError;
2929
pub use lwk_simplicity::runner::run_program;
3030
pub use lwk_simplicity::signer::{finalize_transaction, get_and_verify_env, get_sighash_all};
31-
pub use schema::bundle::*;
31+
pub use schema::runtime_params::*;
3232
pub use scripts::{
3333
control_block, create_p2tr_address, get_new_asset_entropy, hash_script, load_program,
3434
simplicity_leaf_version, tap_data_hash,

crates/wallet-abi/src/runtime/input_resolution.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,20 @@
4444
//! ```
4545
//!
4646
47-
use crate::runtime::params::RuntimeParamsEnvelope;
48-
use crate::runtime::{get_finalizer_spec_key, WalletRuntimeConfig};
49-
use crate::{AmountFilter, AssetFilter, AssetVariant, FinalizerSpec, InputBlinder, InputIssuance, InputIssuanceKind, InputSchema, LockFilter, UTXOSource, WalletAbiError, WalletSourceFilter};
47+
use crate::runtime::{WalletRuntimeConfig, get_finalizer_spec_key};
48+
use crate::{
49+
AmountFilter, AssetFilter, AssetVariant, FinalizerSpec, InputBlinder, InputIssuance,
50+
InputIssuanceKind, InputSchema, LockFilter, RuntimeParams, UTXOSource, WalletAbiError,
51+
WalletSourceFilter,
52+
};
5053

5154
use std::collections::{BTreeMap, HashMap, HashSet};
5255

5356
use lwk_wollet::elements::confidential::{Asset, AssetBlindingFactor, Value, ValueBlindingFactor};
5457
use lwk_wollet::elements::hashes::Hash;
5558
use lwk_wollet::elements::pset::{Input, PartiallySignedTransaction};
56-
use lwk_wollet::elements::{secp256k1_zkp, AssetId, ContractHash, OutPoint, TxOut, TxOutSecrets};
57-
use lwk_wollet::{WalletTxOut, EC};
59+
use lwk_wollet::elements::{AssetId, ContractHash, OutPoint, TxOut, TxOutSecrets, secp256k1_zkp};
60+
use lwk_wollet::{EC, WalletTxOut};
5861

5962
type CandidateScore = (u64, u64, u64, String, u32);
6063

@@ -92,7 +95,7 @@ struct ResolvedInputMaterial {
9295
/// add_balance(&mut balances, "L-BTC", 2).unwrap();
9396
/// assert_eq!(balances.get("L-BTC"), Some(&12));
9497
/// ```
95-
fn add_balance(
98+
pub(super) fn add_balance(
9699
map: &mut BTreeMap<AssetId, u64>,
97100
asset_id: AssetId,
98101
amount_sat: u64,
@@ -190,7 +193,7 @@ fn validate_output_input_index(
190193
/// assert_eq!(derive(3, InputIssuanceKind::Reissue(base)), base);
191194
/// assert_ne!(derive(3, InputIssuanceKind::New(base)), base);
192195
/// ```
193-
fn derive_issuance_entropy(outpoint: OutPoint, issuance: &InputIssuance) -> Midstate {
196+
pub(super) fn derive_issuance_entropy(outpoint: OutPoint, issuance: &InputIssuance) -> Midstate {
194197
match issuance.kind {
195198
InputIssuanceKind::New => AssetId::generate_asset_entropy(
196199
outpoint,
@@ -256,13 +259,13 @@ fn apply_issuance_to_pset_input(
256259
Some(issuance.token_amount_sat)
257260
};
258261

259-
if let InputIssuanceKind::Reissue = issuance.kind {
262+
if issuance.kind == InputIssuanceKind::Reissue {
260263
// TODO: investigate the purpose of this field, and make it functionally correct.
261264
let mut nonce = secrets.asset_bf.into_inner();
262265
if nonce == secp256k1_zkp::ZERO_TWEAK {
263266
let mut one = [0u8; 32];
264267
one[0] = 1;
265-
nonce = secp256k1_zkp::Tweak::from_slice(&one).expect("tweak from [0,..,1] is correct")
268+
nonce = secp256k1_zkp::Tweak::from_slice(&one).expect("tweak from [0,..,1] is correct");
266269
}
267270
pset_input.issuance_blinding_nonce = Some(nonce);
268271
}
@@ -374,7 +377,7 @@ impl WalletRuntimeConfig {
374377
/// Build demand from output specs and store issuance-linked entries as deferred.
375378
fn resolve_output_demands(
376379
&self,
377-
params: &RuntimeParamsEnvelope,
380+
params: &RuntimeParams,
378381
state: &mut ResolutionState,
379382
) -> Result<(), WalletAbiError> {
380383
// Convert output-level asset requirements into equation demand.
@@ -533,12 +536,16 @@ impl WalletRuntimeConfig {
533536
let mut pset_input = Input::from_prevout(material.outpoint);
534537
pset_input.sequence = Some(input.sequence);
535538
pset_input.witness_utxo = Some(material.tx_out.clone());
539+
pset_input.amount = Some(material.secrets.value);
540+
pset_input.asset = Some(material.secrets.asset);
536541

537542
if let Some(issuance) = input.issuance.as_ref() {
538543
apply_issuance_to_pset_input(&mut pset_input, issuance, &material.secrets)?;
539544
}
540545

541-
pset_input.proprietary.insert(get_finalizer_spec_key(), input.finalizer.encode());
546+
pset_input
547+
.proprietary
548+
.insert(get_finalizer_spec_key(), input.finalizer.encode());
542549
pst.add_input(pset_input);
543550

544551
Ok(())
@@ -615,7 +622,7 @@ impl WalletRuntimeConfig {
615622
fn resolve_declared_inputs(
616623
&self,
617624
pst: &mut PartiallySignedTransaction,
618-
params: &RuntimeParamsEnvelope,
625+
params: &RuntimeParams,
619626
wallet_snapshot: &[WalletTxOut],
620627
state: &mut ResolutionState,
621628
) -> Result<(), WalletAbiError> {
@@ -697,7 +704,11 @@ impl WalletRuntimeConfig {
697704
let tx_out = self.fetch_tx_out(&selected.outpoint)?;
698705
let mut pset_input = Input::from_prevout(selected.outpoint);
699706
pset_input.witness_utxo = Some(tx_out);
700-
pset_input.proprietary.insert(get_finalizer_spec_key(), FinalizerSpec::Wallet.encode());
707+
pset_input.amount = Some(selected.unblinded.value);
708+
pset_input.asset = Some(selected.unblinded.asset);
709+
pset_input
710+
.proprietary
711+
.insert(get_finalizer_spec_key(), FinalizerSpec::Wallet.encode());
701712
pst.add_input(pset_input);
702713

703714
add_balance(
@@ -772,7 +783,7 @@ impl WalletRuntimeConfig {
772783
pub(super) fn resolve_inputs(
773784
&self,
774785
pst: PartiallySignedTransaction,
775-
params: &RuntimeParamsEnvelope,
786+
params: &RuntimeParams,
776787
) -> Result<PartiallySignedTransaction, WalletAbiError> {
777788
// Phase 1: initialize demand/supply state and load wallet snapshot once.
778789
// We keep all equation state in a dedicated struct so each phase mutates a single object.

crates/wallet-abi/src/runtime/mod.rs

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
pub mod params;
21
pub mod utils;
32

43
mod input_resolution;
4+
mod output_resolution;
55

66
use crate::error::WalletAbiError;
7-
use crate::runtime::params::RuntimeParamsEnvelope;
87
use crate::schema::tx_create::{TransactionInfo, TxCreateRequest, TxCreateResponse};
9-
use crate::{FinalizerSpec, InputSchema, LockFilter, SchemaBundle, UTXOSource};
8+
use crate::{FinalizerSpec, InputSchema, LockFilter, RuntimeParams, UTXOSource};
109

1110
use std::path::Path;
1211
use std::str::FromStr;
@@ -25,15 +24,15 @@ use lwk_wollet::blocking::EsploraClient;
2524
use lwk_wollet::elements::hex::ToHex;
2625
use lwk_wollet::elements::pset::PartiallySignedTransaction;
2726
use lwk_wollet::elements::pset::raw::ProprietaryKey;
28-
use lwk_wollet::elements::{OutPoint, Script, TxOut, TxOutSecrets, secp256k1_zkp};
27+
use lwk_wollet::elements::{Address, OutPoint, Script, TxOut, TxOutSecrets, secp256k1_zkp};
2928
use lwk_wollet::elements_miniscript::ToPublicKey;
3029
use lwk_wollet::secp256k1::{Keypair, XOnlyPublicKey};
3130
use lwk_wollet::{EC, Wollet, WolletDescriptor};
3231
use simplicityhl::elements::{Transaction, encode};
3332
use simplicityhl::tracker::TrackerLogLevel;
3433

3534
pub(crate) fn get_finalizer_spec_key() -> ProprietaryKey {
36-
ProprietaryKey::from_pset_pair(1, "finalizer-spec".as_bytes().to_vec())
35+
ProprietaryKey::from_pset_pair(1, b"finalizer-spec".to_vec())
3736
}
3837

3938
#[derive(Debug)]
@@ -120,16 +119,18 @@ impl WalletRuntimeConfig {
120119
)?)
121120
}
122121

123-
pub fn signer_address(&self) -> Result<XOnlyPublicKey, WalletAbiError> {
124-
let keypair = self.signer_keypair()?;
122+
pub fn signer_x_only_public_key(&self) -> Result<XOnlyPublicKey, WalletAbiError> {
123+
Ok(self.signer_keypair()?.x_only_public_key().0)
124+
}
125+
126+
pub fn signer_receive_address(&self) -> Result<Address, WalletAbiError> {
127+
let descriptor = self.get_descriptor()?;
125128

126-
Ok(keypair.x_only_public_key().0)
129+
Ok(descriptor.address(0, self.network.address_params())?)
127130
}
128131

129132
pub(crate) fn signer_keypair(&self) -> Result<Keypair, WalletAbiError> {
130-
let x_private = self.x_private(Bip::Bip87)?;
131-
132-
Ok(x_private.to_keypair(&EC))
133+
Ok(self.x_private(Bip::Bip87)?.to_keypair(&EC))
133134
}
134135

135136
pub fn sync_wallet(&mut self) -> Result<(), WalletAbiError> {
@@ -184,42 +185,35 @@ impl WalletRuntimeConfig {
184185
) -> Result<TxCreateResponse, WalletAbiError> {
185186
self.ensure_defaults()?;
186187

187-
let bundle = SchemaBundle::from_uri(&request.schema_uri)?;
188-
let params = RuntimeParamsEnvelope::from_request_params(&request.params)?;
189-
190-
self.pre_sync_inputs(&params.inputs)?;
188+
self.pre_sync_inputs(&request.params.inputs)?;
191189

192-
let finalized_tx = self.finalize(&params)?;
190+
let finalized_tx = self.finalize(&request.params)?;
193191

194-
let txid = finalized_tx.txid().to_string();
192+
let txid = finalized_tx.txid();
195193

196194
let inner_esplora = self
197195
.esplora
198196
.lock()
199197
.map_err(|e| WalletAbiError::EsploraPoisoned(e.to_string()))?;
200198

201-
let published_txid = if request.broadcast {
202-
Some(inner_esplora.broadcast(&finalized_tx)?)
203-
} else {
204-
None
205-
};
199+
if request.broadcast {
200+
let published_txid = inner_esplora.broadcast(&finalized_tx)?;
201+
assert_eq!(txid, published_txid);
202+
}
206203

207204
let response = TxCreateResponse::ok(
208205
request,
209-
&bundle.schema_id,
210-
&bundle.schema_version,
211206
TransactionInfo {
212207
tx_hex: encode::serialize_hex(&finalized_tx),
213208
txid,
214209
},
215-
published_txid,
216210
None,
217211
);
218212

219213
Ok(response)
220214
}
221215

222-
fn finalize(&self, params: &RuntimeParamsEnvelope) -> Result<Transaction, WalletAbiError> {
216+
fn finalize(&self, params: &RuntimeParams) -> Result<Transaction, WalletAbiError> {
223217
let fee_estimation_build = self.build_transaction(params, 1u64)?;
224218

225219
let finalized_tx = self.finalize_all_inputs(fee_estimation_build)?;
@@ -243,13 +237,14 @@ impl WalletRuntimeConfig {
243237

244238
fn build_transaction(
245239
&self,
246-
params: &RuntimeParamsEnvelope,
240+
params: &RuntimeParams,
247241
fee_target_sat: u64,
248242
) -> Result<PartiallySignedTransaction, WalletAbiError> {
249243
let mut pst = PartiallySignedTransaction::new_v2();
250244
pst.global.tx_data.fallback_locktime = params.locktime;
251245

252246
pst = self.resolve_inputs(pst, params)?;
247+
pst = self.balance_out(pst, params, fee_target_sat)?;
253248

254249
Ok(pst)
255250
}
@@ -300,7 +295,7 @@ impl WalletRuntimeConfig {
300295
input_index,
301296
)?;
302297

303-
let witness = resolve_witness(&witness, &self, &env)?;
298+
let witness = resolve_witness(&witness, self, &env)?;
304299

305300
let pruned = run_program(&program, witness, &env, TrackerLogLevel::None)?.0;
306301

@@ -313,7 +308,7 @@ impl WalletRuntimeConfig {
313308
simplicity_program_bytes,
314309
cmr.as_ref().to_vec(),
315310
control_block(cmr, internal_key.pubkey.to_x_only_pubkey()).serialize(),
316-
])
311+
]);
317312
}
318313
}
319314
}
@@ -335,7 +330,7 @@ impl WalletRuntimeConfig {
335330
}
336331
},
337332
UTXOSource::Provided { .. } => {}
338-
};
333+
}
339334
}
340335

341336
Ok(())

0 commit comments

Comments
 (0)