mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-08 06:22:39 -04:00
fix(asb): Would silently fail if Monero refund transaction publish failed (#254)
This commit is contained in:
parent
3e6b25a0c8
commit
29da23ea60
5 changed files with 65 additions and 54 deletions
|
@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
- ASB: Fixed an issue where the ASB would silently fail if the publication of the Monero refund transaction failed.
|
||||||
|
|
||||||
## [1.0.0-rc.12] - 2025-01-14
|
## [1.0.0-rc.12] - 2025-01-14
|
||||||
|
|
||||||
## [1.0.0-rc.11] - 2024-12-22
|
## [1.0.0-rc.11] - 2024-12-22
|
||||||
|
|
|
@ -32,6 +32,7 @@ Consider joining the designated [Matrix chat](https://matrix.to/#/%23unstoppable
|
||||||
### Using Docker
|
### Using Docker
|
||||||
|
|
||||||
Running the ASB and its required services (Bitcoin node, Monero node, wallet RPC) can be complex to set up manually. We provide a Docker Compose solution that handles all of this automatically. See our [docker-compose repository](https://github.com/UnstoppableSwap/asb-docker-compose) for setup instructions and configuration details.
|
Running the ASB and its required services (Bitcoin node, Monero node, wallet RPC) can be complex to set up manually. We provide a Docker Compose solution that handles all of this automatically. See our [docker-compose repository](https://github.com/UnstoppableSwap/asb-docker-compose) for setup instructions and configuration details.
|
||||||
|
|
||||||
## ASB Details
|
## ASB Details
|
||||||
|
|
||||||
The ASB is a long running daemon that acts as the trading partner to the swap CLI.
|
The ASB is a long running daemon that acts as the trading partner to the swap CLI.
|
||||||
|
@ -212,6 +213,7 @@ Sparrow wallet import works as follows:
|
||||||

|

|
||||||
|
|
||||||
If the bitcoin amount in your wallet doesn't match "asb balance" output and you don't see (all) the transactions you need to increase the gap limit:
|
If the bitcoin amount in your wallet doesn't match "asb balance" output and you don't see (all) the transactions you need to increase the gap limit:
|
||||||
|
|
||||||
- go to Settings > Advanced... > Gap limit
|
- go to Settings > Advanced... > Gap limit
|
||||||
|
|
||||||

|

|
||||||
|
|
|
@ -116,47 +116,37 @@ impl Wallet {
|
||||||
/// keys. The generated wallet will be opened, all funds sweeped to the
|
/// keys. The generated wallet will be opened, all funds sweeped to the
|
||||||
/// main_address and then the wallet will be re-loaded using the internally
|
/// main_address and then the wallet will be re-loaded using the internally
|
||||||
/// stored name.
|
/// stored name.
|
||||||
pub async fn create_from(
|
pub async fn create_from_keys_and_sweep(
|
||||||
&self,
|
&self,
|
||||||
file_name: String,
|
file_name: String,
|
||||||
private_spend_key: PrivateKey,
|
private_spend_key: PrivateKey,
|
||||||
private_view_key: PrivateViewKey,
|
private_view_key: PrivateViewKey,
|
||||||
restore_height: BlockHeight,
|
restore_height: BlockHeight,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let public_spend_key = PublicKey::from_private_key(&private_spend_key);
|
// Close the default wallet, generate the new wallet from the keys and load it
|
||||||
let public_view_key = PublicKey::from_private_key(&private_view_key.into());
|
self.create_from_and_load(
|
||||||
|
|
||||||
let temp_wallet_address =
|
|
||||||
Address::standard(self.network, public_spend_key, public_view_key);
|
|
||||||
|
|
||||||
// Close the default wallet before generating the other wallet to ensure that
|
|
||||||
// it saves its state correctly
|
|
||||||
let _ = self.inner.lock().await.close_wallet().await?;
|
|
||||||
|
|
||||||
let _ = self
|
|
||||||
.inner
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.generate_from_keys(
|
|
||||||
file_name,
|
file_name,
|
||||||
temp_wallet_address.to_string(),
|
private_spend_key,
|
||||||
private_spend_key.to_string(),
|
private_view_key,
|
||||||
PrivateKey::from(private_view_key).to_string(),
|
restore_height,
|
||||||
restore_height.height,
|
|
||||||
String::from(""),
|
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Try to send all the funds from the generated wallet to the default wallet
|
// Refresh the generated wallet
|
||||||
match self.refresh(3).await {
|
if let Err(error) = self.refresh(20).await {
|
||||||
Ok(_) => match self
|
return Err(anyhow::anyhow!(error)
|
||||||
|
.context("Failed to refresh generated wallet for sweeping to default wallet"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sweep all the funds from the generated wallet to the default wallet
|
||||||
|
let sweep_result = self
|
||||||
.inner
|
.inner
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.sweep_all(self.main_address.to_string())
|
.sweep_all(self.main_address.to_string())
|
||||||
.await
|
.await;
|
||||||
{
|
|
||||||
|
match sweep_result {
|
||||||
Ok(sweep_all) => {
|
Ok(sweep_all) => {
|
||||||
for tx in sweep_all.tx_hash_list {
|
for tx in sweep_all.tx_hash_list {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
|
@ -166,15 +156,10 @@ impl Wallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
tracing::warn!(
|
return Err(
|
||||||
address = %self.main_address,
|
anyhow::anyhow!(error).context("Failed to transfer Monero to default wallet")
|
||||||
"Failed to transfer Monero to default wallet: {:#}", error
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Err(error) => {
|
|
||||||
tracing::warn!("Failed to refresh generated wallet: {:#}", error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = self
|
let _ = self
|
||||||
|
|
|
@ -522,7 +522,7 @@ impl State3 {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
monero_wallet
|
monero_wallet
|
||||||
.create_from(
|
.create_from_keys_and_sweep(
|
||||||
file_name,
|
file_name,
|
||||||
spend_key,
|
spend_key,
|
||||||
view_key,
|
view_key,
|
||||||
|
|
|
@ -427,15 +427,37 @@ where
|
||||||
spend_key,
|
spend_key,
|
||||||
state3,
|
state3,
|
||||||
} => {
|
} => {
|
||||||
|
// We retry indefinitely to refund the Monero funds, until the refund transaction is confirmed
|
||||||
|
let backoff = backoff::ExponentialBackoffBuilder::new()
|
||||||
|
.with_max_elapsed_time(None)
|
||||||
|
.with_max_interval(Duration::from_secs(60))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
backoff::future::retry_notify(
|
||||||
|
backoff,
|
||||||
|
|| async {
|
||||||
state3
|
state3
|
||||||
.refund_xmr(
|
.refund_xmr(
|
||||||
monero_wallet,
|
monero_wallet,
|
||||||
monero_wallet_restore_blockheight,
|
monero_wallet_restore_blockheight,
|
||||||
swap_id.to_string(),
|
swap_id.to_string(),
|
||||||
spend_key,
|
spend_key,
|
||||||
transfer_proof,
|
transfer_proof.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(backoff::Error::transient)
|
||||||
|
},
|
||||||
|
|e, wait_time: Duration| {
|
||||||
|
tracing::warn!(
|
||||||
|
swap_id = %swap_id,
|
||||||
|
error = ?e,
|
||||||
|
"Failed to refund Monero. We will retry in {} seconds",
|
||||||
|
wait_time.as_secs()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("We should never run out of retries while refunding Monero");
|
||||||
|
|
||||||
AliceState::XmrRefunded
|
AliceState::XmrRefunded
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue