Skip to content

Commit

Permalink
Merge pull request #747 from BoltzExchange/harden-refunds
Browse files Browse the repository at this point in the history
Harden refunds
  • Loading branch information
michael1011 authored Dec 17, 2024
2 parents 30f34d0 + 58aa2dc commit d4479cf
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 132 deletions.
2 changes: 1 addition & 1 deletion boltzr/src/webhook/caller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl Caller {
) -> Result<CallResult, Box<dyn Error>> {
if let Some(status_include) = &hook.status {
if !status_include.contains(status) {
debug!("Not calling WebHook for swap {} because status update {} is not in include list", hook.id, status);
trace!("Not calling WebHook for swap {} because status update {} is not in include list", hook.id, status);
return Ok(CallResult::NotIncluded);
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/sidecar/Sidecar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class Sidecar extends BaseClient<

private static childProcess?: child_process.ChildProcessWithoutNullStreams;

private static maxConnectRetries = 10;
private static maxConnectRetries = 25;
private static connectRetryTimeout = 500;

private client?: BoltzRClient;
Expand Down
132 changes: 73 additions & 59 deletions lib/swap/SwapNursery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import {
swapTypeToPrettyString,
} from '../consts/Enums';
import TypedEventEmitter from '../consts/TypedEventEmitter';
import { ERC20SwapValues, EtherSwapValues } from '../consts/Types';
import { AnySwap, ERC20SwapValues, EtherSwapValues } from '../consts/Types';
import ChannelCreation from '../db/models/ChannelCreation';
import ReverseSwap, { nodeTypeToPrettyString } from '../db/models/ReverseSwap';
import Swap from '../db/models/Swap';
Expand Down Expand Up @@ -1399,49 +1399,53 @@ class SwapNursery extends TypedEventEmitter<SwapNurseryEvents> {
const chainCurrency = this.currencies.get(chainSymbol)!;
const lightningCurrency = this.currencies.get(lightningSymbol)!;

if (reverseSwap.transactionId) {
switch (chainCurrency.type) {
case CurrencyType.BitcoinLike:
case CurrencyType.Liquid:
await this.refundUtxo(chainCurrency, reverseSwap);
break;
try {
if (reverseSwap.transactionId) {
switch (chainCurrency.type) {
case CurrencyType.BitcoinLike:
case CurrencyType.Liquid:
await this.refundUtxo(chainCurrency, reverseSwap);
break;

case CurrencyType.Ether:
await this.refundEther(reverseSwap, chainSymbol);
break;
case CurrencyType.Ether:
await this.refundEther(reverseSwap, chainSymbol);
break;

case CurrencyType.ERC20:
await this.refundERC20(reverseSwap, chainSymbol);
break;
case CurrencyType.ERC20:
await this.refundERC20(reverseSwap, chainSymbol);
break;
}
} else {
this.emit(
'expiration',
await WrappedSwapRepository.setStatus(
reverseSwap,
SwapUpdateEvent.SwapExpired,
Errors.ONCHAIN_HTLC_TIMED_OUT().message,
),
);
}
} else {
this.emit(
'expiration',
await WrappedSwapRepository.setStatus(
reverseSwap,
SwapUpdateEvent.SwapExpired,
Errors.ONCHAIN_HTLC_TIMED_OUT().message,
),
);
}

const lightningClient = NodeSwitch.getReverseSwapNode(
lightningCurrency,
reverseSwap,
);

try {
await LightningNursery.cancelReverseInvoices(
lightningClient,
const lightningClient = NodeSwitch.getReverseSwapNode(
lightningCurrency,
reverseSwap,
true,
);

try {
await LightningNursery.cancelReverseInvoices(
lightningClient,
reverseSwap,
true,
);
} catch (e) {
this.logger.debug(
`Could not cancel invoices of Reverse Swap ${
reverseSwap.id
} because: ${formatError(e)}`,
);
}
} catch (e) {
this.logger.debug(
`Could not cancel invoices of Reverse Swap ${
reverseSwap.id
} because: ${formatError(e)}`,
);
await this.handleFailedRefund(reverseSwap, e);
}
};

Expand All @@ -1457,32 +1461,36 @@ class SwapNursery extends TypedEventEmitter<SwapNurseryEvents> {

const chainCurrency = this.currencies.get(chainSwap.sendingData.symbol)!;

if (chainSwap.sendingData.transactionId) {
switch (chainCurrency.type) {
case CurrencyType.BitcoinLike:
case CurrencyType.Liquid:
await this.chainSwapSigner.removeFromClaimable(chainSwap.id);
await this.refundUtxo(chainCurrency, chainSwap);
try {
if (chainSwap.sendingData.transactionId) {
switch (chainCurrency.type) {
case CurrencyType.BitcoinLike:
case CurrencyType.Liquid:
await this.chainSwapSigner.removeFromClaimable(chainSwap.id);
await this.refundUtxo(chainCurrency, chainSwap);

break;
break;

case CurrencyType.Ether:
await this.refundEther(chainSwap, chainCurrency.symbol);
break;
case CurrencyType.Ether:
await this.refundEther(chainSwap, chainCurrency.symbol);
break;

case CurrencyType.ERC20:
await this.refundERC20(chainSwap, chainCurrency.symbol);
break;
case CurrencyType.ERC20:
await this.refundERC20(chainSwap, chainCurrency.symbol);
break;
}
} else {
this.emit(
'expiration',
await WrappedSwapRepository.setStatus(
chainSwap,
SwapUpdateEvent.SwapExpired,
Errors.ONCHAIN_HTLC_TIMED_OUT().message,
),
);
}
} else {
this.emit(
'expiration',
await WrappedSwapRepository.setStatus(
chainSwap,
SwapUpdateEvent.SwapExpired,
Errors.ONCHAIN_HTLC_TIMED_OUT().message,
),
);
} catch (e) {
await this.handleFailedRefund(chainSwap, e);
}
};

Expand Down Expand Up @@ -1669,6 +1677,12 @@ class SwapNursery extends TypedEventEmitter<SwapNurseryEvents> {

return undefined;
};

private handleFailedRefund = async (swap: AnySwap, error: unknown) => {
const msg = `Refunding ${swapTypeToPrettyString(swap.type)} Swap ${swap.id} failed: ${formatError(error)}`;
this.logger.error(msg);
await this.notifications?.sendMessage(msg, true, true);
};
}

export default SwapNursery;
Loading

0 comments on commit d4479cf

Please sign in to comment.