Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wallet_ffi): added 2 functions, wallet_preview_coin_split and wallet_preview_coin_join #4264

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions base_layer/wallet/src/output_manager_service/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ pub enum OutputManagerRequest {
RevalidateTxos,
CreateCoinSplit((Vec<Commitment>, MicroTari, usize, MicroTari)),
CreateCoinSplitEven((Vec<Commitment>, usize, MicroTari)),
PreviewCoinJoin((Vec<Commitment>, MicroTari)),
PreviewCoinSplitEven((Vec<Commitment>, usize, MicroTari)),
CreateCoinJoin {
commitments: Vec<Commitment>,
fee_per_gram: MicroTari,
Expand Down Expand Up @@ -177,6 +179,16 @@ impl fmt::Display for OutputManagerRequest {
GetInvalidOutputs => write!(f, "GetInvalidOutputs"),
ValidateUtxos => write!(f, "ValidateUtxos"),
RevalidateTxos => write!(f, "RevalidateTxos"),
PreviewCoinJoin((commitments, fee_per_gram)) => write!(
f,
"PreviewCoinJoin(commitments={:#?}, fee_per_gram={})",
commitments, fee_per_gram
),
PreviewCoinSplitEven((commitments, number_of_splits, fee_per_gram)) => write!(
f,
"PreviewCoinSplitEven(commitments={:#?}, number_of_splits={}, fee_per_gram={})",
commitments, number_of_splits, fee_per_gram
),
CreateCoinSplit(v) => write!(f, "CreateCoinSplit ({:?})", v.0),
CreateCoinSplitEven(v) => write!(f, "CreateCoinSplitEven ({:?})", v.0),
CreateCoinJoin {
Expand Down Expand Up @@ -272,6 +284,7 @@ pub enum OutputManagerResponse {
CoinbaseAbandonedSet,
ClaimHtlcTransaction((TxId, MicroTari, MicroTari, Transaction)),
OutputStatusesByTxId(OutputStatusesByTxId),
CoinPreview((Vec<MicroTari>, MicroTari)),
}

pub type OutputManagerEventSender = broadcast::Sender<Arc<OutputManagerEvent>>;
Expand Down Expand Up @@ -673,6 +686,41 @@ impl OutputManagerHandle {
}
}

pub async fn preview_coin_join_with_commitments(
&mut self,
commitments: Vec<Commitment>,
fee_per_gram: MicroTari,
) -> Result<(Vec<MicroTari>, MicroTari), OutputManagerError> {
match self
.handle
.call(OutputManagerRequest::PreviewCoinJoin((commitments, fee_per_gram)))
.await??
{
OutputManagerResponse::CoinPreview((expected_outputs, fee)) => Ok((expected_outputs, fee)),
_ => Err(OutputManagerError::UnexpectedApiResponse),
}
}

pub async fn preview_coin_split_with_commitments_no_amount(
&mut self,
commitments: Vec<Commitment>,
split_count: usize,
fee_per_gram: MicroTari,
) -> Result<(Vec<MicroTari>, MicroTari), OutputManagerError> {
match self
.handle
.call(OutputManagerRequest::PreviewCoinSplitEven((
commitments,
split_count,
fee_per_gram,
)))
.await??
{
OutputManagerResponse::CoinPreview((expected_outputs, fee)) => Ok((expected_outputs, fee)),
_ => Err(OutputManagerError::UnexpectedApiResponse),
}
}

/// Create a coin split transaction.
/// Returns (tx_id, tx, utxos_total_value).
pub async fn create_coin_split(
Expand Down
84 changes: 84 additions & 0 deletions base_layer/wallet/src/output_manager_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,18 @@ where
let outputs = self.fetch_invalid_outputs()?.into_iter().map(|v| v.into()).collect();
Ok(OutputManagerResponse::InvalidOutputs(outputs))
},
OutputManagerRequest::PreviewCoinJoin((commitments, fee_per_gram)) => {
Ok(OutputManagerResponse::CoinPreview(
self.preview_coin_join_with_commitments(commitments, fee_per_gram)
.await?,
))
},
OutputManagerRequest::PreviewCoinSplitEven((commitments, number_of_splits, fee_per_gram)) => {
Ok(OutputManagerResponse::CoinPreview(
self.preview_coin_split_with_commitments_no_amount(commitments, number_of_splits, fee_per_gram)
.await?,
))
},
OutputManagerRequest::CreateCoinSplit((commitments, amount_per_split, split_count, fee_per_gram)) => {
if commitments.is_empty() {
self.create_coin_split_auto(Some(amount_per_split), split_count, fee_per_gram)
Expand Down Expand Up @@ -1716,6 +1728,78 @@ where
)
}

pub async fn preview_coin_join_with_commitments(
&self,
commitments: Vec<Commitment>,
fee_per_gram: MicroTari,
) -> Result<(Vec<MicroTari>, MicroTari), OutputManagerError> {
let src_outputs = self.resources.db.fetch_unspent_outputs_for_spending(
UtxoSelectionCriteria::specific(commitments),
MicroTari::zero(),
None,
)?;

let accumulated_amount = src_outputs
.iter()
.fold(MicroTari::zero(), |acc, x| acc + x.unblinded_output.value);

let fee = self
.get_fee_calc()
.calculate(fee_per_gram, 1, src_outputs.len(), 1, self.default_metadata_size());

Ok((vec![accumulated_amount.saturating_sub(fee)], fee))
}

pub async fn preview_coin_split_with_commitments_no_amount(
&mut self,
commitments: Vec<Commitment>,
number_of_splits: usize,
fee_per_gram: MicroTari,
) -> Result<(Vec<MicroTari>, MicroTari), OutputManagerError> {
if commitments.is_empty() {
return Err(OutputManagerError::NoCommitmentsProvided);
}

if number_of_splits == 0 {
return Err(OutputManagerError::InvalidArgument(
"number_of_splits must be greater than 0".to_string(),
));
}

let src_outputs = self.resources.db.fetch_unspent_outputs_for_spending(
UtxoSelectionCriteria::specific(commitments),
MicroTari::zero(),
None,
)?;

let fee = self.get_fee_calc().calculate(
fee_per_gram,
1,
src_outputs.len(),
number_of_splits,
self.default_metadata_size() * number_of_splits,
);

let accumulated_amount = src_outputs
.iter()
.fold(MicroTari::zero(), |acc, x| acc + x.unblinded_output.value);

let aftertax_amount = accumulated_amount.saturating_sub(fee);
let amount_per_split = MicroTari(aftertax_amount.as_u64() / number_of_splits as u64);
let unspent_remainder = MicroTari(aftertax_amount.as_u64() % amount_per_split.as_u64());
let mut expected_outputs = vec![];

for i in 1..=number_of_splits {
expected_outputs.push(if i == number_of_splits {
amount_per_split + unspent_remainder
} else {
amount_per_split
});
}

Ok((expected_outputs, fee))
}

async fn create_coin_split_with_commitments(
&mut self,
commitments: Vec<Commitment>,
Expand Down
53 changes: 53 additions & 0 deletions base_layer/wallet/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,31 @@ where
signature.verify_challenge(&public_key, challenge.clone().as_slice())
}

/// Appraise the expected outputs and a fee
pub async fn preview_coin_split_with_commitments_no_amount(
&mut self,
commitments: Vec<Commitment>,
split_count: usize,
fee_per_gram: MicroTari,
) -> Result<(Vec<MicroTari>, MicroTari), WalletError> {
self.output_manager_service
.preview_coin_split_with_commitments_no_amount(commitments, split_count, fee_per_gram)
.await
.map_err(WalletError::OutputManagerError)
}

/// Appraise the expected outputs and a fee
pub async fn preview_coin_join_with_commitments(
&mut self,
commitments: Vec<Commitment>,
fee_per_gram: MicroTari,
) -> Result<(Vec<MicroTari>, MicroTari), WalletError> {
self.output_manager_service
.preview_coin_join_with_commitments(commitments, fee_per_gram)
.await
.map_err(WalletError::OutputManagerError)
}

/// Do a coin split
pub async fn coin_split(
&mut self,
Expand Down Expand Up @@ -593,6 +618,34 @@ where
}
}

/// Do a coin split
pub async fn coin_split_even_with_commitments(
&mut self,
commitments: Vec<Commitment>,
split_count: usize,
fee_per_gram: MicroTari,
message: String,
) -> Result<TxId, WalletError> {
let coin_split_tx = self
.output_manager_service
.create_coin_split_even(commitments, split_count, fee_per_gram)
.await;

match coin_split_tx {
Ok((tx_id, split_tx, amount)) => {
let coin_tx = self
.transaction_service
.submit_transaction(tx_id, split_tx, amount, message)
.await;
match coin_tx {
Ok(_) => Ok(tx_id),
Err(e) => Err(WalletError::TransactionServiceError(e)),
}
},
Err(e) => Err(WalletError::OutputManagerError(e)),
}
}

pub async fn coin_join(
&mut self,
commitments: Vec<Commitment>,
Expand Down
Loading