Skip to content

Commit 772bb1e

Browse files
crisdutcryptoquick
andauthored
Add fee-rate support (RGB PSBT) (#366)
* feat: add fee-rate in rgb psbt * feat: add minimum sats to fund vault * Bump bitmask-core to 0.6.3-rc.21. --------- Co-authored-by: Hunter Trujillo <[email protected]>
1 parent 5b2c600 commit 772bb1e

File tree

17 files changed

+962
-362
lines changed

17 files changed

+962
-362
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bitmask-core"
3-
version = "0.6.3-rc.20"
3+
version = "0.6.3-rc.21"
44
authors = [
55
"Jose Diego Robles <[email protected]>",
66
"Hunter Trujillo <[email protected]>",

src/bitcoin.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ use crate::{
3939
trace,
4040
};
4141

42+
// Minimum amount of satoshis to funding vault
43+
const MIN_FUNDS_SATS: u64 = 10000;
44+
4245
impl SerdeEncryptSharedKey for DecryptedWalletData {
4346
type S = BincodeSerializer<Self>;
4447
}
@@ -57,12 +60,17 @@ pub enum BitcoinError {
5760
/// Wrong Encrypted Descriptor Version
5861
#[error("Wrong Version: Encrypted descriptor is the wrong version. The version byte was: {0}")]
5962
WrongEncryptedDescriptorVersion(u8),
63+
#[error("Wrong Descriptor: Wallet supports only taproot descriptor")]
64+
WrongDescriptor,
6065
/// Upgrade unnecessary
6166
#[error("Descriptor does not need to be upgraded")]
6267
UpgradeUnnecessary,
6368
/// Wrong network
6469
#[error("Address provided is on the wrong network!")]
6570
WrongNetwork,
71+
/// Wrong Encrypted Descriptor Format
72+
#[error("Insufficient satoshis to create funding wallet. Minimum: {0} sats")]
73+
InsufficientFundSats(u64),
6674
/// Drain wallet unable to finalize PSBT
6775
#[error("Drain wallet was unable to finalize PSBT")]
6876
DrainWalletUnfinalizedPsbt,
@@ -296,13 +304,9 @@ pub async fn get_new_address(
296304
info!("get_new_address");
297305

298306
let wallet = get_wallet(descriptor, change_descriptor).await?;
299-
let address = wallet
300-
.lock()
301-
.await
302-
.get_address(AddressIndex::New)?
303-
.to_string();
307+
let address = wallet.lock().await.get_address(AddressIndex::New)?;
304308
info!(format!("address: {address}"));
305-
Ok(address)
309+
Ok(address.to_string())
306310
}
307311

308312
pub async fn validate_address(address: &Address) -> Result<(), BitcoinError> {
@@ -360,6 +364,14 @@ pub async fn fund_vault(
360364
uda_address_2: &str,
361365
fee_rate: Option<f32>,
362366
) -> Result<FundVaultDetails, BitcoinError> {
367+
let wallet = get_wallet(btc_descriptor_xprv, Some(btc_change_descriptor_xprv)).await?;
368+
let fee_rate = fee_rate.map(FeeRate::from_sat_per_vb);
369+
370+
let balance = wallet.lock().await.get_balance()?;
371+
if balance.confirmed < MIN_FUNDS_SATS {
372+
return Err(BitcoinError::InsufficientFundSats(MIN_FUNDS_SATS));
373+
};
374+
363375
let assets_address_1 = Address::from_str(assets_address_1)?;
364376
let assets_address_2 = Address::from_str(assets_address_2)?;
365377
let uda_address_1 = Address::from_str(uda_address_1)?;
@@ -384,9 +396,6 @@ pub async fn fund_vault(
384396
amount: rng.gen_range(600..1500),
385397
};
386398

387-
let wallet = get_wallet(btc_descriptor_xprv, Some(btc_change_descriptor_xprv)).await?;
388-
let fee_rate = fee_rate.map(FeeRate::from_sat_per_vb);
389-
390399
let asset_tx_details = create_transaction(
391400
vec![
392401
asset_invoice_1,

src/bitcoin/payment.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub async fn create_transaction(
5050
for invoice in invoices {
5151
builder.add_recipient(invoice.address.script_pubkey(), invoice.amount);
5252
}
53+
5354
builder.ordering(TxOrdering::Untouched); // TODO: Remove after implementing wallet persistence
5455
builder.enable_rbf().fee_rate(fee_rate.unwrap_or_default());
5556
builder.finish()?

src/bitcoin/psbt.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use bdk::{blockchain::Blockchain, psbt::PsbtUtils, SignOptions, TransactionDetails};
2-
use bitcoin::{consensus::serialize, util::psbt::PartiallySignedTransaction};
2+
use bitcoin::{consensus::serialize, hashes::hex::ToHex, util::psbt::PartiallySignedTransaction};
33
use thiserror::Error;
44

55
use crate::{
@@ -35,7 +35,7 @@ pub async fn sign_psbt(
3535
debug!("Signed PSBT:", base64::encode(&serialize(&psbt)));
3636
let fee_amount = psbt.fee_amount().expect("fee amount on PSBT is known");
3737
let tx = psbt.extract_tx();
38-
debug!("tx:", base64::encode(&serialize(&tx.clone())));
38+
debug!("tx:", &serialize(&tx.clone()).to_hex());
3939
let blockchain = get_blockchain().await;
4040
blockchain.broadcast(&tx).await?;
4141

@@ -105,7 +105,7 @@ pub async fn sign_psbt_with_multiple_wallets(
105105
debug!("Signed PSBT:", base64::encode(&serialize(&psbt)));
106106
let fee_amount = psbt.fee_amount().expect("fee amount on PSBT is known");
107107
let tx = psbt.extract_tx();
108-
debug!("tx:", base64::encode(&serialize(&tx.clone())));
108+
debug!("tx:", &serialize(&tx.clone()).to_hex());
109109
let blockchain = get_blockchain().await;
110110
blockchain.broadcast(&tx).await?;
111111

src/rgb.rs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ use self::{
8888
prefetch_resolver_user_utxo_status, prefetch_resolver_utxos, prefetch_resolver_waddress,
8989
prefetch_resolver_wutxo,
9090
},
91-
psbt::{fee_estimate, save_commit, CreatePsbtError},
91+
psbt::{save_commit, CreatePsbtError, EstimateFeeError},
9292
structs::{RgbAccount, RgbTransfer, RgbTransfers},
9393
transfer::{extract_transfer, AcceptTransferError, NewInvoiceError, NewPaymentError},
9494
wallet::{
@@ -464,10 +464,22 @@ pub enum TransferError {
464464
NoContract,
465465
/// Iface is required in this operation. Please, use the correct iface contract.
466466
NoIface,
467+
/// FeeRate is supported in this operation. Please, use the absolute fee value.
468+
NoFeeRate,
469+
/// Insufficient funds (expected: {input} sats / current: {output} sats)
470+
Inflation {
471+
/// Amount spent: input amounts
472+
input: u64,
473+
474+
/// Amount sent: sum of output value + transaction fee
475+
output: u64,
476+
},
467477
/// Auto merge fail in this opration
468478
WrongAutoMerge(String),
469479
/// Occurs an error in create step. {0}
470480
Create(CreatePsbtError),
481+
/// Occurs an error in estimate fee step. {0}
482+
Estimate(EstimateFeeError),
471483
/// Occurs an error in commitment step. {0}
472484
Commitment(DbcPsbtError),
473485
/// Occurs an error in payment step. {0}
@@ -515,11 +527,11 @@ async fn internal_create_psbt(
515527

516528
let PsbtRequest {
517529
asset_inputs,
518-
asset_descriptor_change,
519530
asset_terminal_change,
520531
bitcoin_inputs,
521532
bitcoin_changes,
522533
fee,
534+
..
523535
} = request;
524536

525537
let mut all_inputs = asset_inputs.clone();
@@ -531,15 +543,7 @@ async fn internal_create_psbt(
531543
// Retrieve transaction fee
532544
let fee = match fee {
533545
PsbtFeeRequest::Value(fee) => fee,
534-
PsbtFeeRequest::FeeRate(fee_rate) => fee_estimate(
535-
asset_inputs,
536-
asset_descriptor_change,
537-
asset_terminal_change.clone(),
538-
bitcoin_inputs,
539-
bitcoin_changes.clone(),
540-
fee_rate,
541-
resolver,
542-
),
546+
PsbtFeeRequest::FeeRate(_) => return Err(TransferError::NoFeeRate),
543547
};
544548

545549
let wallet = rgb_account.wallets.get("default");
@@ -600,19 +604,18 @@ pub async fn full_transfer_asset(
600604
_ => return Err(TransferError::NoWatcher),
601605
};
602606

603-
let (asset_inputs, bitcoin_inputs, bitcoin_changes) =
607+
let (asset_inputs, bitcoin_inputs, bitcoin_changes, fee_value) =
604608
prebuild_transfer_asset(request.clone(), &mut stock, &mut rgb_wallet, &mut resolver)
605609
.await?;
606610

607611
let FullRgbTransferRequest {
608612
rgb_invoice,
609613
change_terminal,
610-
fee,
611614
..
612615
} = request;
613616

614617
let psbt_req = PsbtRequest {
615-
fee,
618+
fee: PsbtFeeRequest::Value(fee_value),
616619
asset_inputs,
617620
bitcoin_inputs,
618621
bitcoin_changes,
@@ -1387,7 +1390,7 @@ pub async fn watcher_address(
13871390
name: &str,
13881391
address: &str,
13891392
) -> Result<WatcherUtxoResponse, WatcherError> {
1390-
let rgb_account = retrieve_account(sk).await.map_err(WatcherError::IO)?;
1393+
let mut rgb_account = retrieve_account(sk).await.map_err(WatcherError::IO)?;
13911394

13921395
let mut resp = WatcherUtxoResponse::default();
13931396
if let Some(wallet) = rgb_account.wallets.get(name) {
@@ -1406,6 +1409,14 @@ pub async fn watcher_address(
14061409
.into_iter()
14071410
.map(|utxo| utxo.outpoint.to_string())
14081411
.collect();
1412+
1413+
rgb_account
1414+
.wallets
1415+
.insert(RGB_DEFAULT_NAME.to_string(), wallet);
1416+
1417+
store_account(sk, rgb_account)
1418+
.await
1419+
.map_err(WatcherError::IO)?;
14091420
};
14101421

14111422
Ok(resp)
@@ -1560,6 +1571,7 @@ pub async fn watcher_unspent_utxos(
15601571
..Default::default()
15611572
};
15621573

1574+
sync_wallet(iface_index, &mut wallet, &mut resolver);
15631575
prefetch_resolver_utxos(
15641576
iface_index,
15651577
&mut wallet,
@@ -1568,7 +1580,6 @@ pub async fn watcher_unspent_utxos(
15681580
)
15691581
.await;
15701582
prefetch_resolver_user_utxo_status(iface_index, &mut wallet, &mut resolver, true).await;
1571-
sync_wallet(iface_index, &mut wallet, &mut resolver);
15721583

15731584
let utxos: HashSet<UtxoResponse> = next_utxos(iface_index, wallet.clone(), &mut resolver)
15741585
.map_err(|op| WatcherError::Validation(op.to_string()))?

0 commit comments

Comments
 (0)