Example #1
0
        private async Task RestoreSwapAsync(
            Swap swap,
            CancellationToken cancellationToken = default)
        {
            if (swap.StateFlags.HasFlag(SwapStateFlags.IsPaymentSigned) &&
                !swap.StateFlags.HasFlag(SwapStateFlags.IsPaymentBroadcast))
            {
                var txResult = await GetCurrencySwap(swap.SoldCurrency)
                               .TryToFindPaymentAsync(swap, cancellationToken)
                               .ConfigureAwait(false);

                if (txResult == null || txResult.HasError)
                {
                    return; // can't get tx from blockchain
                }
                if (txResult.Value != null)
                {
                    swap.PaymentTx   = txResult.Value;
                    swap.PaymentTxId = txResult.Value.Id;
                    swap.StateFlags |= SwapStateFlags.IsPaymentBroadcast;

                    await UpdateSwapAsync(swap, SwapStateFlags.IsPaymentBroadcast, cancellationToken)
                    .ConfigureAwait(false);

                    if (txResult.Value.IsConfirmed)
                    {
                        swap.StateFlags |= SwapStateFlags.IsPaymentConfirmed;
                    }

                    await UpdateSwapAsync(swap, SwapStateFlags.IsPaymentConfirmed, cancellationToken)
                    .ConfigureAwait(false);
                }
            }

            if (swap.StateFlags.HasFlag(SwapStateFlags.IsPaymentBroadcast))
            {
                bool waitForRedeem = true;

                if (!swap.StateFlags.HasFlag(SwapStateFlags.IsPaymentConfirmed) &&
                    DateTime.UtcNow > swap.TimeStamp.ToUniversalTime() + DefaultMaxPaymentTimeout)
                {
                    var currency = _account.Currencies
                                   .GetByName(swap.PaymentTx.Currency);

                    var result = await currency
                                 .IsTransactionConfirmed(
                        txId : swap.PaymentTx.Id,
                        cancellationToken : cancellationToken)
                                 .ConfigureAwait(false);

                    if (result.HasError || !result.Value.IsConfirmed)
                    {
                        waitForRedeem = false;

                        Log.Debug("Swap {@id} canceled in RestoreSwapAsync. Timeout reached.", swap.Id);

                        swap.StateFlags |= SwapStateFlags.IsCanceled;

                        await UpdateSwapAsync(swap, SwapStateFlags.IsCanceled, cancellationToken)
                        .ConfigureAwait(false);
                    }
                }

                if (waitForRedeem)
                {
                    await GetCurrencySwap(swap.SoldCurrency)
                    .StartWaitForRedeemAsync(swap, cancellationToken)
                    .ConfigureAwait(false);

                    if (swap.IsInitiator)
                    {
                        // check acceptor payment confirmation
                        await GetCurrencySwap(swap.PurchasedCurrency)
                        .StartPartyPaymentControlAsync(swap, cancellationToken)
                        .ConfigureAwait(false);
                    }

                    if (swap.IsAcceptor && swap.RewardForRedeem > 0)
                    {
                        await GetCurrencySwap(swap.PurchasedCurrency)
                        .StartWaitForRedeemBySomeoneAsync(swap, cancellationToken)
                        .ConfigureAwait(false);
                    }
                }
            }
            else
            {
                if (IsPaymentDeadlineReached(swap))
                {
                    await CancelSwapByTimeoutAsync(swap, cancellationToken)
                    .ConfigureAwait(false);

                    return;
                }

                if (swap.IsAcceptor)
                {
                    if (!swap.Status.HasFlag(SwapStatus.Initiated)) // not initiated
                    {
                        // try to get actual swap status from server and accept swap
                        _swapClient.SwapStatusAsync(new Request <Swap>()
                        {
                            Id = $"get_swap_{swap.Id}", Data = swap
                        });
                    }
                    else if (swap.Status.HasFlag(SwapStatus.Initiated) && // initiated but not accepted
                             !swap.Status.HasFlag(SwapStatus.Accepted))
                    {
                        // try to get actual swap status from server and accept swap
                        _swapClient.SwapStatusAsync(new Request <Swap>()
                        {
                            Id = $"get_swap_{swap.Id}", Data = swap
                        });
                    }
                    else if (swap.Status.HasFlag(SwapStatus.Initiated) && // initiated and accepted
                             swap.Status.HasFlag(SwapStatus.Accepted))
                    {
                        // wait for initiator tx
                        await GetCurrencySwap(swap.PurchasedCurrency)
                        .StartPartyPaymentControlAsync(swap)
                        .ConfigureAwait(false);
                    }
                }
                else if (swap.IsInitiator)
                {
                    if (!swap.Status.HasFlag(SwapStatus.Initiated)) // not initiated
                    {
                        // initiate
                        await InitiateSwapAsync(swap)
                        .ConfigureAwait(false);
                    }
                    else if (swap.Status.HasFlag(SwapStatus.Initiated) && // initiated but not accepted
                             !swap.Status.HasFlag(SwapStatus.Accepted))
                    {
                        // try to get actual swap status from server
                        _swapClient.SwapStatusAsync(new Request <Swap>()
                        {
                            Id = $"get_swap_{swap.Id}", Data = swap
                        });
                    }
                    else if (swap.Status.HasFlag(SwapStatus.Initiated) && // initiated and accepted
                             swap.Status.HasFlag(SwapStatus.Accepted))
                    {
                        // broadcast initiator payment again
                        await GetCurrencySwap(swap.SoldCurrency)
                        .PayAsync(swap)
                        .ConfigureAwait(false);

                        if (swap.StateFlags.HasFlag(SwapStateFlags.IsPaymentBroadcast))
                        {
                            // start redeem control async
                            await GetCurrencySwap(swap.SoldCurrency)
                            .StartWaitForRedeemAsync(swap)
                            .ConfigureAwait(false);
                        }

                        await GetCurrencySwap(swap.PurchasedCurrency)
                        .StartPartyPaymentControlAsync(swap)
                        .ConfigureAwait(false);
                    }
                }
            }
        }