Skip to content

Commit

Permalink
fix: avoid dust transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
crisdut committed Dec 13, 2023
1 parent 971bd3a commit b2a88db
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 189 deletions.
35 changes: 26 additions & 9 deletions src/rgb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,12 @@ use self::{
RgbTransferV1, RgbTransfersV1,
},
swap::{
complete_bid, complete_offer, get_auction_highest_bid, get_public_offer, get_public_offers,
get_swap_bid_by_buyer, get_swap_bid_by_seller, get_swap_bids_by_offer, next_auction_offer,
publish_auction_bid, publish_auction_offers, publish_public_bid, publish_public_offer,
publish_swap_bid, remove_public_offers, update_transfer_bid, update_transfer_offer,
PsbtSwapEx, RgbBid, RgbBidSwap, RgbOffer, RgbOfferErrors, RgbOfferOptions, RgbOfferSwap,
RgbOrderStatus, RgbSwapStrategy,
complete_bid, complete_offer, get_auction_highest_bid, get_next_auction_offer,
get_public_offer, get_public_offers, get_swap_bid_by_buyer, get_swap_bid_by_seller,
get_swap_bids_by_offer, next_auction_offer, publish_auction_bid, publish_auction_offers,
publish_public_bid, publish_public_offer, publish_swap_bid, remove_public_offers,
update_transfer_bid, update_transfer_offer, PsbtSwapEx, RgbBid, RgbBidSwap, RgbOffer,
RgbOfferErrors, RgbOfferOptions, RgbOfferSwap, RgbOrderStatus, RgbSwapStrategy,
},
transfer::{extract_transfer, AcceptTransferError, NewInvoiceError, NewPaymentError},
wallet::{
Expand Down Expand Up @@ -967,6 +967,7 @@ pub async fn create_seller_offer(
bitcoin_price,
seller_address: seller_address.to_string(),
seller_psbt: seller_psbt.clone(),
bundle_id: None,
};

let mut my_offers = retrieve_offers(sk).await.map_err(RgbSwapError::IO)?;
Expand Down Expand Up @@ -1029,13 +1030,15 @@ pub async fn create_auction_offers(
.await?;

let RgbOffer {
offer_id,
contract_id,
asset_amount,
asset_precision,
seller_address,
bitcoin_price,
seller_psbt,
strategy,
bundle_id,
..
} = new_offer.clone();

Expand Down Expand Up @@ -1063,12 +1066,13 @@ pub async fn create_auction_offers(
collection.push(RgbOfferSwap::from(new_offer.clone()));

resp.push(RgbOfferResponse {
offer_id: new_offer.clone().offer_id,
offer_id,
contract_id: contract_id.clone(),
contract_amount,
bitcoin_price,
seller_address: seller_address.to_string(),
seller_psbt: final_psbt,
bundle_id,
});
}

Expand Down Expand Up @@ -1965,7 +1969,7 @@ async fn internal_finish_auction(
.map_err(|op| RgbSwapError::WrongPsbtFinal(op.to_string()))?;

let outpoint = Outpoint::new(txid, 0);
next_auction_offer(offer, outpoint)
next_auction_offer(offer.clone(), outpoint)
.await
.map_err(|op| RgbSwapError::WrongPsbtFinal(op.to_string()))?;

Expand All @@ -1988,14 +1992,27 @@ pub async fn list_auctions() -> Result<Vec<RgbAuctionOfferResponse>, RgbSwapErro
.map_err(RgbSwapError::Auction)?
.into_iter()
.filter(|x| {
x.strategy == RgbSwapStrategy::Auction && x.expire_at.unwrap_or_default().sub(utc) <= 0
x.strategy == RgbSwapStrategy::Auction
&& x.bundle_id.is_some()
&& x.expire_at.unwrap_or_default().sub(utc) <= 0
})
.map(RgbAuctionOfferResponse::from)
.collect();

Ok(auction_offers)
}

pub async fn get_next_offer(
bundle_id: &str,
) -> Result<Option<RgbAuctionOfferResponse>, RgbSwapError> {
let auction_offers = get_next_auction_offer(bundle_id)
.await
.map_err(RgbSwapError::Auction)?
.map(RgbAuctionOfferResponse::from);

Ok(auction_offers)
}

pub async fn accept_transfer(
sk: &str,
request: AcceptRequest,
Expand Down
6 changes: 3 additions & 3 deletions src/rgb/cambria.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::rgb::structs::{RgbAccountV0, RgbAccountV1};
use crate::rgb::structs::{
RgbAccountV0, RgbAccountV1, RgbTransferV0, RgbTransferV1, RgbTransfersV0, RgbTransfersV1,
};
use postcard::from_bytes;

use super::structs::{RgbTransferV0, RgbTransferV1, RgbTransfersV0, RgbTransfersV1};

#[derive(Debug, Clone, Eq, PartialEq, Display, From, Error)]
#[display(doc_comments)]
pub enum ModelVersionError {
Expand Down
22 changes: 9 additions & 13 deletions src/rgb/carbonado.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,21 @@ use postcard::{from_bytes, to_allocvec};
use rgbstd::{persistence::Stock, stl::LIB_ID_RGB};
use strict_encoding::{StrictDeserialize, StrictSerialize};

use crate::carbonado::{auctions_retrieve, auctions_store, marketplace_store};
use crate::rgb::crdt::{LocalRgbAccount, LocalRgbOffers, RawRgbAccount};

use crate::rgb::swap::{RgbBids, RgbOffers};
use crate::{
carbonado::{marketplace_retrieve, retrieve, store},
carbonado::{
auctions_retrieve, auctions_store, marketplace_retrieve, marketplace_store, retrieve, store,
},
rgb::{
cambria::{ModelVersion, RgbAccountVersions},
cambria::{ModelVersion, RgbAccountVersions, RgbtransferVersions},
constants::RGB_STRICT_TYPE_VERSION,
crdt::LocalRgbOfferBid,
structs::RgbAccountV1,
crdt::{
LocalRgbAccount, LocalRgbAuctions, LocalRgbOfferBid, LocalRgbOffers, RawRgbAccount,
},
structs::{RgbAccountV1, RgbTransfersV1},
swap::{RgbAuctionSwaps, RgbBidSwap, RgbBids, RgbOffers, RgbPublicSwaps},
},
};

use super::cambria::RgbtransferVersions;
use super::crdt::LocalRgbAuctions;
use super::structs::RgbTransfersV1;
use super::swap::{RgbAuctionSwaps, RgbBidSwap, RgbPublicSwaps};

const RGB_ACCOUNT_VERSION: [u8; 3] = *b"v10";
const RGB_TRANSFER_VERSION: [u8; 3] = *b"v10";

Expand Down
4 changes: 1 addition & 3 deletions src/rgb/crdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ use std::{

use crate::rgb::{
structs::{RgbAccountV0, RgbAccountV1},
swap::{RgbBidSwap, RgbPublicSwaps},
swap::{RgbAuctionSwaps, RgbBidSwap, RgbPublicSwaps},
};

use super::swap::RgbAuctionSwaps;

#[derive(Debug, Clone, Eq, PartialEq, Display, From, Error)]
#[display(doc_comments)]
pub enum RgbMergeError {
Expand Down
159 changes: 81 additions & 78 deletions src/rgb/prebuild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,23 @@ use crate::{

use crate::rgb::{
constants::{BITCOIN_DEFAULT_FETCH_LIMIT, RGB_DEFAULT_FETCH_LIMIT},
contract::export_contract,
contract::{export_boilerplate, export_contract},
fs::RgbPersistenceError,
prefetch::prefetch_resolver_txs,
prefetch::{
prefetch_resolver_allocations, prefetch_resolver_user_utxo_status, prefetch_resolver_utxos,
},
psbt::estimate_fee,
resolvers::ExplorerResolver,
structs::AddressAmount,
structs::RgbExtractTransfer,
structs::{AddressAmount, ContractAmount, RgbExtractTransfer},
swap::RgbSwapStrategy,
swap::{get_public_offer, RgbBid, RgbOfferSwap},
transfer::extract_transfer,
wallet::sync_wallet,
wallet::{get_address, next_utxos},
RgbSwapError, SaveTransferError, TransferError,
};

use super::{contract::export_boilerplate, structs::ContractAmount};

pub const DUST_LIMIT_SATOSHI: u64 = 546;

pub async fn prebuild_transfer_asset(
Expand Down Expand Up @@ -423,6 +421,7 @@ pub async fn prebuild_seller_swap(
iface: iface_name,
contract_amount: target_amount,
bitcoin_changes,
strategy,
..
} = request;

Expand Down Expand Up @@ -513,15 +512,13 @@ pub async fn prebuild_seller_swap(
let mut assets_allocs = vec![];

let mut total_asset_bitcoin_unspend: u64 = 0;
for alloc in allocations.iter() {
// // TODO: Make more tests!
// let sig_hash = if assets_inputs.len() <= 0 {
// PsbtSigHashRequest::NonePlusAnyoneCanPay
// } else {
// PsbtSigHashRequest::NonePlusAnyoneCanPay
// };
let sig_hash = PsbtSigHashRequest::NonePlusAnyoneCanPay;

let asset_sig_hash = match strategy {
RgbSwapStrategy::Auction => PsbtSigHashRequest::NonePlusAnyoneCanPay,
RgbSwapStrategy::P2P | RgbSwapStrategy::HotSwap => PsbtSigHashRequest::NonePlusAnyoneCanPay,
};

for alloc in allocations.iter() {
match alloc.value {
AllocationValue::Value(alloc_value) => {
if asset_total >= target_amount {
Expand All @@ -532,18 +529,14 @@ pub async fn prebuild_seller_swap(
descriptor: universal_desc.clone(),
utxo: alloc.utxo.clone(),
utxo_terminal: alloc.derivation.to_string(),
sigh_hash: Some(sig_hash),
sigh_hash: Some(asset_sig_hash.clone()),
tapret: None,
};
if !assets_inputs
.clone()
.into_iter()
.any(|x: PsbtInputRequest| x.utxo == alloc.utxo)
{
// let mut empty_input = input.clone();
// empty_input.sigh_hash = Some(PsbtSigHashRequest::None);

// assets_inputs.push(empty_input);
assets_inputs.push(input);
assets_allocs.push(alloc.clone());
total_asset_bitcoin_unspend += asset_unspent_utxos
Expand All @@ -564,7 +557,7 @@ pub async fn prebuild_seller_swap(
descriptor: universal_desc.clone(),
utxo: alloc.utxo.clone(),
utxo_terminal: alloc.derivation.to_string(),
sigh_hash: Some(sig_hash),
sigh_hash: Some(asset_sig_hash),
tapret: None,
};
if !assets_inputs
Expand All @@ -590,70 +583,80 @@ pub async fn prebuild_seller_swap(
}
}

// Get All Bitcoin UTXOs
let total_bitcoin_spend: u64 = bitcoin_changes
.clone()
.into_iter()
.map(|x| {
let recipient = AddressAmount::from_str(&x).expect("invalid address amount format");
recipient.amount
})
.sum();
let mut bitcoin_inputs = vec![];

let bitcoin_indexes = [0, 1];
for bitcoin_index in bitcoin_indexes {
sync_wallet(bitcoin_index, rgb_wallet, resolver);
prefetch_resolver_utxos(
bitcoin_index,
rgb_wallet,
resolver,
Some(BITCOIN_DEFAULT_FETCH_LIMIT),
)
.await;
prefetch_resolver_user_utxo_status(bitcoin_index, rgb_wallet, resolver, false).await;

let mut unspent_utxos =
next_utxos(bitcoin_index, rgb_wallet.clone(), resolver).map_err(|_| {
RgbSwapError::IO(RgbPersistenceError::RetrieveRgbAccount("".to_string()))
})?;
let (bitcoin_inputs, change_value) = match strategy {
RgbSwapStrategy::P2P | RgbSwapStrategy::HotSwap => {
// Get All Bitcoin UTXOs
let total_bitcoin_spend: u64 = bitcoin_changes
.clone()
.into_iter()
.map(|x| {
let recipient =
AddressAmount::from_str(&x).expect("invalid address amount format");
recipient.amount
})
.sum();
let mut bitcoin_inputs = vec![];

let bitcoin_indexes = [0, 1];
for bitcoin_index in bitcoin_indexes {
sync_wallet(bitcoin_index, rgb_wallet, resolver);
prefetch_resolver_utxos(
bitcoin_index,
rgb_wallet,
resolver,
Some(BITCOIN_DEFAULT_FETCH_LIMIT),
)
.await;
prefetch_resolver_user_utxo_status(bitcoin_index, rgb_wallet, resolver, false)
.await;

let mut unspent_utxos = next_utxos(bitcoin_index, rgb_wallet.clone(), resolver)
.map_err(|_| {
RgbSwapError::IO(RgbPersistenceError::RetrieveRgbAccount("".to_string()))
})?;

all_unspents.append(&mut unspent_utxos);
}

all_unspents.append(&mut unspent_utxos);
}
let mut bitcoin_total = total_asset_bitcoin_unspend;
let total_spendable = total_bitcoin_spend;

let mut bitcoin_total = total_asset_bitcoin_unspend;
let total_spendable = total_bitcoin_spend;
let bitcoin_sigh_hash = PsbtSigHashRequest::NonePlusAnyoneCanPay;
for utxo in all_unspents {
if bitcoin_total > total_spendable {
break;
} else {
let TerminalPath { app, index } = utxo.derivation.terminal;
let btc_input = PsbtInputRequest {
descriptor: universal_desc.clone(),
utxo: utxo.outpoint.to_string(),
utxo_terminal: format!("/{app}/{index}"),
sigh_hash: Some(bitcoin_sigh_hash.clone()),
tapret: None,
};
if !bitcoin_inputs
.clone()
.into_iter()
.any(|x: PsbtInputRequest| x.utxo == utxo.outpoint.to_string())
{
bitcoin_inputs.push(btc_input);
bitcoin_total += utxo.amount;
}
}
}

for utxo in all_unspents {
if bitcoin_total > total_spendable {
break;
} else {
let TerminalPath { app, index } = utxo.derivation.terminal;
let btc_input = PsbtInputRequest {
descriptor: universal_desc.clone(),
utxo: utxo.outpoint.to_string(),
utxo_terminal: format!("/{app}/{index}"),
sigh_hash: Some(PsbtSigHashRequest::NonePlusAnyoneCanPay),
tapret: None,
};
if !bitcoin_inputs
.clone()
.into_iter()
.any(|x: PsbtInputRequest| x.utxo == utxo.outpoint.to_string())
{
bitcoin_inputs.push(btc_input);
bitcoin_total += utxo.amount;
let change_value = bitcoin_total - total_spendable;
if bitcoin_total < total_spendable {
return Err(RgbSwapError::Inflation {
input: bitcoin_total,
output: total_spendable,
});
}
}
}

let change_value = bitcoin_total - total_spendable;
if bitcoin_total < total_spendable {
return Err(RgbSwapError::Inflation {
input: bitcoin_total,
output: total_spendable,
});
}
(bitcoin_inputs, change_value)
}
RgbSwapStrategy::Auction => (vec![], total_asset_bitcoin_unspend),
};

Ok((
assets_allocs,
Expand Down
4 changes: 2 additions & 2 deletions src/rgb/prefetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ use std::{collections::BTreeMap, str::FromStr};
use strict_encoding::StrictDeserialize;
use wallet::onchain::ResolveTx;

use super::resolvers::ExploreClientExtError;
use super::structs::MediaMetadata;
use crate::rgb::resolvers::ExploreClientExtError;
use crate::rgb::structs::MediaMetadata;

#[cfg(not(target_arch = "wasm32"))]
pub async fn prefetch_resolver_rgb(
Expand Down
Loading

0 comments on commit b2a88db

Please sign in to comment.