public override async Task PayAsync( Swap swap, CancellationToken cancellationToken = default) { if (swap.IsAcceptor && !swap.HasPartyPayment) { Log.Debug("Acceptor is not ready to broadcast {@currency} payment tx for swap {@swap}", Currency, swap.Id); return; } if (!CheckPayRelevance(swap)) { return; } var lockTimeInSeconds = swap.IsInitiator ? DefaultInitiatorLockTimeInSeconds : DefaultAcceptorLockTimeInSeconds; await CreatePaymentAsync(swap, lockTimeInSeconds) .ConfigureAwait(false); Log.Debug("Broadcast {@currency} payment tx for swap {@swap}", Currency, swap.Id); var currency = Currencies.GetByName(swap.SoldCurrency); // broadcast payment transaction var broadcastResult = await currency.BlockchainApi .TryBroadcastAsync(swap.PaymentTx, cancellationToken : cancellationToken) .ConfigureAwait(false); if (broadcastResult.HasError) { Log.Error("Error while broadcast {@currency} transaction. Code: {@code}. Description: {@description}", currency.Name, broadcastResult.Error.Code, broadcastResult.Error.Description); return; } var txId = broadcastResult.Value; swap.PaymentTxId = txId ?? throw new Exception("Transaction Id is null"); swap.StateFlags |= SwapStateFlags.IsPaymentBroadcast; RaiseSwapUpdated(swap, SwapStateFlags.IsPaymentBroadcast); Log.Debug("{@currency} payment txId {@id} for swap {@swap}", currency.Name, txId, swap.Id); // account new unconfirmed transaction await _account .UpsertTransactionAsync( tx : swap.PaymentTx, updateBalance : true, notifyIfUnconfirmed : false, cancellationToken : cancellationToken) .ConfigureAwait(false); // send payment txId to party SwapClient.SwapPaymentAsync(swap); await StartWaitForRedeemAsync(swap, cancellationToken) .ConfigureAwait(false); }
public override async Task BroadcastPaymentAsync(ClientSwap swap) { if (swap.IsAcceptor && (!swap.StateFlags.HasFlag(SwapStateFlags.HasPartyPayment) || !swap.StateFlags.HasFlag(SwapStateFlags.IsPartyPaymentConfirmed))) { Log.Debug("CounterParty is not ready to broadcast payment tx for swap {@swap}", swap.Id); return; } var lockTimeInSeconds = swap.IsInitiator ? DefaultInitiatorLockTimeInSeconds : DefaultAcceptorLockTimeInSeconds; await CreatePaymentAsync(swap, lockTimeInSeconds) .ConfigureAwait(false); Log.Debug("Broadcast payment tx for swap {@swap}", swap.Id); var currency = swap.SoldCurrency; // broadcast payment transaction var txId = await currency.BlockchainApi .BroadcastAsync(swap.PaymentTx) .ConfigureAwait(false); swap.PaymentTxId = txId ?? throw new Exception("Transaction Id is null"); swap.SetPaymentBroadcast(); RaiseSwapUpdated(swap, SwapStateFlags.IsPaymentBroadcast); Log.Debug("Payment txId {@id}", txId); // account new unconfirmed transaction await Account .UpsertTransactionAsync( tx : swap.PaymentTx, updateBalance : true, notifyIfUnconfirmed : false) .ConfigureAwait(false); // send payment txId to party SwapClient.SwapPaymentAsync(swap); if (swap.IsAcceptor) { var swapOutputs = ((IBitcoinBasedTransaction)swap.PaymentTx) .SwapOutputs() .ToList(); if (swapOutputs.Count != 1) { throw new InternalException( code: Errors.SwapError, description: "Payment tx must have only one swap output"); } // track counter party payment spent event TaskPerformer.EnqueueTask(new BitcoinBasedOutputSpentTask { Currency = currency, Swap = swap, OutputHash = txId, OutputIndex = swapOutputs.First().Index, Interval = DefaultOutputSpentCheckInterval, CompleteHandler = PaymentSpentEventHandler }); } // track payment transaction confirmation TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask { Currency = currency, Swap = swap, TxId = txId, Interval = DefaultConfirmationCheckInterval, CompleteHandler = PaymentConfirmedEventHandler }); }