Esempio n. 1
0
        public override Task PrepareToReceiveAsync(ClientSwap swap)
        {
            // initiator waits "accepted" event, acceptor waits "initiated" event
            var handler = swap.IsInitiator
                ? SwapAcceptedEventHandler
                : (OnTaskDelegate)SwapInitiatedEventHandler;

            var lockTimeSeconds = swap.IsInitiator
                ? DefaultAcceptorLockTimeInSeconds
                : DefaultInitiatorLockTimeInSeconds;

            var refundTimeStampUtcInSec = new DateTimeOffset(swap.TimeStamp.ToUniversalTime().AddSeconds(lockTimeSeconds)).ToUnixTimeSeconds();

            TaskPerformer.EnqueueTask(new TezosSwapInitiatedControlTask
            {
                Currency        = Currency,
                Swap            = swap,
                Interval        = TimeSpan.FromSeconds(30),
                RefundTimestamp = refundTimeStampUtcInSec,
                CompleteHandler = handler,
                CancelHandler   = SwapCanceledEventHandler
            });

            return(Task.CompletedTask);
        }
Esempio n. 2
0
        private async Task RestoreForPurchasedCurrencyAsync(ClientSwap swap)
        {
            if (swap.RewardForRedeem > 0 &&
                swap.StateFlags.HasFlag(SwapStateFlags.IsPaymentBroadcast))
            {
                // may be swap already redeemed by someone else
                await WaitForRedeemAsync(swap)
                .ConfigureAwait(false);
            }
            else if (swap.StateFlags.HasFlag(SwapStateFlags.IsRedeemBroadcast) &&
                     !swap.StateFlags.HasFlag(SwapStateFlags.IsRedeemConfirmed))
            {
                if (!(swap.RedeemTx is TezosTransaction redeemTx))
                {
                    Log.Error("Can't restore swap {@id}. Redeem tx is null", swap.Id);
                    return;
                }

                TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask
                {
                    Currency        = Currency,
                    Swap            = swap,
                    Interval        = DefaultConfirmationCheckInterval,
                    TxId            = redeemTx.Id,
                    CompleteHandler = RedeemConfirmedEventHandler
                });
            }
        }
Esempio n. 3
0
        private void RedeemPartyControlCompletedEventHandler(BackgroundTask task)
        {
            var redeemControlTask = task as TezosRedeemControlTask;
            var swap = redeemControlTask?.Swap;

            if (swap == null)
            {
                return;
            }

            Log.Debug("Handle redeem party control completed event for swap {@swapId}", swap.Id);

            if (swap.IsAcceptor)
            {
                swap.Secret = redeemControlTask.Secret;
                swap.SetRedeemConfirmed();
                RaiseSwapUpdated(swap, SwapStateFlags.IsRedeemConfirmed);

                // get transactions & update balance for address
                TaskPerformer.EnqueueTask(new AddressBalanceUpdateTask
                {
                    Account  = Account,
                    Address  = swap.ToAddress,
                    Currency = Currency,
                });
            }
        }
        public override async Task HandlePartyPaymentAsync(ClientSwap swap, ClientSwap clientSwap)
        {
            Log.Debug("Handle party's payment txId for swap {@swapId}", swap.Id);

            if (swap.PartyPaymentTxId != null)
            {
                throw new InternalException(
                          code: Errors.WrongSwapMessageOrder,
                          description: $"Party's payment txId already received for swap {swap.Id}");
            }

            if (clientSwap.PartyPaymentTxId == null)
            {
                throw new InternalException(
                          code: Errors.InvalidPaymentTxId,
                          description: "TxId is null");
            }

            swap.PartyPaymentTxId = clientSwap.PartyPaymentTxId;
            RaiseSwapUpdated(swap, SwapStateFlags.Empty);

            // get party payment tx from block-chain
            var currency = (BitcoinBasedCurrency)swap.PurchasedCurrency;

            var tx = await GetPaymentTxAsync(currency, swap.PartyPaymentTxId)
                     .ConfigureAwait(false);

            var refundLockTime = swap.IsInitiator
                ? DefaultAcceptorLockTimeInSeconds
                : DefaultInitiatorLockTimeInSeconds;

            if (!BitcoinBasedTransactionVerifier.TryVerifyPartyPaymentTx(
                    tx: tx,
                    swap: swap,
                    secretHash: swap.SecretHash,
                    refundLockTime: refundLockTime,
                    error: out var error))
            {
                throw new InternalException(error);
            }

            swap.PartyPaymentTx = tx;
            RaiseSwapUpdated(swap, SwapStateFlags.HasPartyPayment);

            // track initiator payment confirmation
            TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask
            {
                Currency        = swap.PurchasedCurrency,
                Swap            = swap,
                TxId            = swap.PartyPaymentTxId,
                Interval        = DefaultConfirmationCheckInterval,
                CompleteHandler = PartyPaymentConfirmedEventHandler
            });
        }
        private async void PaymentConfirmedEventHandler(BackgroundTask task)
        {
            var confirmationCheckTask = task as TransactionConfirmationCheckTask;
            var swap = confirmationCheckTask?.Swap;

            if (swap == null)
            {
                return;
            }

            Log.Debug("Handle payment confirmed event for swap {@swapId}", swap.Id);

            swap.SetPaymentConfirmed();
            RaiseSwapUpdated(swap, SwapStateFlags.IsPaymentConfirmed);

            try
            {
                if (confirmationCheckTask.Transactions.Any())
                {
                    await Account
                    .UpsertTransactionAsync(
                        tx : confirmationCheckTask.Transactions.First(),
                        updateBalance : true)
                    .ConfigureAwait(false);
                }

                var refundTimeUtc = swap.TimeStamp.ToUniversalTime() +
                                    TimeSpan.FromSeconds(swap.IsInitiator
                                        ? DefaultInitiatorLockTimeInSeconds
                                        : DefaultAcceptorLockTimeInSeconds);

                TaskPerformer.EnqueueTask(new RefundTimeControlTask
                {
                    Currency        = Currency,
                    Swap            = swap,
                    Interval        = DefaultRefundInterval,
                    RefundTimeUtc   = refundTimeUtc,
                    CompleteHandler = RefundTimeControlEventHandler
                });
            }
            catch (Exception e)
            {
                Log.Error(e, "Error while handle payment tx confirmed event");
            }

            if (swap.IsInitiator)
            {
                RaiseInitiatorPaymentConfirmed(swap);
            }
            else
            {
                RaiseAcceptorPaymentConfirmed(swap);
            }
        }
Esempio n. 6
0
        public void AssignTaskToUser(int taskId, int userId)
        {
            var task          = unitOfWork.TaskRepository.GetByID(taskId);
            var user          = unitOfWork.UserRepository.GetByID(userId);
            var taskPerformer = new TaskPerformer()
            {
                Task = task, User = user
            };

            unitOfWork.TaskPerformerRepository.Insert(taskPerformer);
            unitOfWork.Save();
        }
Esempio n. 7
0
        public void AssignUserToTask(int userId, int taskId)
        {
            var task = unitOfWork.TaskRepository.GetByID(taskId);
            var user = unitOfWork.UserRepository.GetByID(userId);

            var taskPerformer = new TaskPerformer();

            taskPerformer.Task = task;
            taskPerformer.User = user;

            unitOfWork.TaskPerformerRepository.Insert(taskPerformer);
            unitOfWork.Save();
        }
        public override async Task RedeemAsync(ClientSwap swap)
        {
            var currency = swap.PurchasedCurrency;

            var redeemAddress = await Account
                                .GetFreeInternalAddressAsync(currency)
                                .ConfigureAwait(false);

            // create redeem tx
            swap.RedeemTx = await CreateRedeemTxAsync(
                swap : swap,
                paymentTx : (IBitcoinBasedTransaction)swap.PartyPaymentTx,
                redeemAddress : redeemAddress.Address)
                            .ConfigureAwait(false);

            // sign redeem tx
            swap.RedeemTx = await SignRedeemTxAsync(
                swap : swap,
                redeemTx : (IBitcoinBasedTransaction)swap.RedeemTx,
                paymentTx : (IBitcoinBasedTransaction)swap.PartyPaymentTx,
                redeemAddress : redeemAddress)
                            .ConfigureAwait(false);

            swap.SetRedeemSigned();
            RaiseSwapUpdated(swap, SwapStateFlags.IsRedeemSigned);

            // broadcast redeem tx
            await BroadcastRedeemAsync(
                swap : swap,
                redeemTx : swap.RedeemTx)
            .ConfigureAwait(false);

            swap.SetRedeemBroadcast();
            RaiseSwapUpdated(swap, SwapStateFlags.IsRedeemBroadcast);

            // add new unconfirmed transaction
            await Account
            .UpsertTransactionAsync(
                tx : swap.RedeemTx,
                updateBalance : true)
            .ConfigureAwait(false);

            TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask
            {
                Currency        = swap.PurchasedCurrency,
                Swap            = swap,
                Interval        = DefaultConfirmationCheckInterval,
                TxId            = swap.RedeemTx.Id,
                CompleteHandler = RedeemConfirmedEventHandler
            });
        }
        private Task RestoreForSoldCurrencyAsync(ClientSwap swap)
        {
            if (swap.StateFlags.HasFlag(SwapStateFlags.IsPaymentBroadcast))
            {
                if (!(swap.PaymentTx is EthereumTransaction))
                {
                    Log.Error("Can't restore swap {@id}. Payment tx is null.", swap.Id);

                    return(Task.CompletedTask);
                }

                var lockTimeInSeconds = swap.IsInitiator
                    ? DefaultInitiatorLockTimeInSeconds
                    : DefaultAcceptorLockTimeInSeconds;

                // start redeem control
                TaskPerformer.EnqueueTask(new EthereumRedeemControlTask
                {
                    Currency        = Currency,
                    RefundTimeUtc   = swap.TimeStamp.ToUniversalTime().AddSeconds(lockTimeInSeconds),
                    Swap            = swap,
                    CompleteHandler = RedeemControlCompletedEventHandler,
                    CancelHandler   = RedeemControlCanceledEventHandler
                });
            }
            else
            {
                if (DateTime.UtcNow < swap.TimeStamp.ToUniversalTime() + DefaultMaxSwapTimeout)
                {
                    if (swap.IsInitiator)
                    {
                        // todo: initiate swap

                        //await InitiateSwapAsync(swapState)
                        //    .ConfigureAwait(false);
                    }
                    else
                    {
                        // todo: request secret hash from server
                    }
                }
                else
                {
                    swap.Cancel();
                    RaiseSwapUpdated(swap, SwapStateFlags.IsCanceled);
                }
            }

            return(Task.CompletedTask);
        }
        private async void RefundTimeControlEventHandler(BackgroundTask task)
        {
            var refundTimeControlTask = task as RefundTimeControlTask;
            var swap = refundTimeControlTask?.Swap;

            if (swap == null)
            {
                return;
            }

            try
            {
                var refundTx = (IBitcoinBasedTransaction)swap.RefundTx;

                var txId = await Currency.BlockchainApi
                           .BroadcastAsync(refundTx)
                           .ConfigureAwait(false);

                if (txId == null)
                {
                    throw new Exception("Transaction Id is null");
                }

                Log.Debug("Refund tx id {@txId} for swap {@swapId}", txId, swap.Id);

                // todo: check result

                swap.SetRefundBroadcast();
                RaiseSwapUpdated(swap, SwapStateFlags.IsRefundBroadcast);

                await Account
                .UpsertTransactionAsync(
                    tx : refundTx,
                    updateBalance : true)
                .ConfigureAwait(false);

                TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask
                {
                    Currency        = Currency,
                    Swap            = swap,
                    Interval        = DefaultConfirmationCheckInterval,
                    TxId            = swap.RefundTx.Id,
                    CompleteHandler = RefundConfirmedEventHandler
                });
            }
            catch (Exception e)
            {
                Log.Error(e, "Refund task error");
            }
        }
Esempio n. 11
0
        public override async Task BroadcastPaymentAsync(ClientSwap swap)
        {
            var lockTimeInSeconds = swap.IsInitiator
                ? DefaultInitiatorLockTimeInSeconds
                : DefaultAcceptorLockTimeInSeconds;

            var txs = (await CreatePaymentTxsAsync(swap, lockTimeInSeconds)
                       .ConfigureAwait(false))
                      .ToList();

            if (txs.Count == 0)
            {
                Log.Error("Can't create payment transactions");
                return;
            }

            var signResult = await SignPaymentTxsAsync(txs)
                             .ConfigureAwait(false);

            if (!signResult)
            {
                return;
            }

            swap.PaymentTx = txs.First();
            swap.SetPaymentSigned();
            RaiseSwapUpdated(swap, SwapStateFlags.IsPaymentSigned);

            foreach (var tx in txs)
            {
                await BroadcastTxAsync(swap, tx)
                .ConfigureAwait(false);
            }

            swap.PaymentTx = txs.First();
            swap.SetPaymentBroadcast();
            RaiseSwapUpdated(swap, SwapStateFlags.IsPaymentBroadcast);

            // start redeem control
            TaskPerformer.EnqueueTask(new EthereumRedeemControlTask
            {
                Currency        = Currency,
                RefundTimeUtc   = swap.TimeStamp.ToUniversalTime().AddSeconds(lockTimeInSeconds),
                Swap            = swap,
                CompleteHandler = RedeemControlCompletedEventHandler,
                CancelHandler   = RedeemControlCanceledEventHandler
            });
        }
Esempio n. 12
0
        public override Task WaitForRedeemAsync(ClientSwap swap)
        {
            Log.Debug("Wait redeem for swap {@swapId}", swap.Id);

            // start redeem control
            TaskPerformer.EnqueueTask(new TezosRedeemControlTask
            {
                Currency        = Currency,
                RefundTimeUtc   = swap.TimeStamp.ToUniversalTime().AddSeconds(DefaultAcceptorLockTimeInSeconds),
                Swap            = swap,
                CompleteHandler = RedeemPartyControlCompletedEventHandler,
                CancelHandler   = RedeemPartyControlCanceledEventHandler
            });

            return(Task.CompletedTask);
        }
Esempio n. 13
0
        private void RefundTimeReachedEventHandler(BackgroundTask task)
        {
            var refundTimeControlTask = task as RefundTimeControlTask;
            var swap = refundTimeControlTask?.Swap;

            if (swap == null)
            {
                return;
            }

            Log.Debug("Refund time reached for swap {@swapId}", swap.Id);

            TaskPerformer.EnqueueTask(new TezosRefundControlTask
            {
                Currency        = Currency,
                Swap            = swap,
                CompleteHandler = RefundConfirmedEventHandler,
                CancelHandler   = RefundEventHandler
            });
        }
Esempio n. 14
0
        private void RedeemControlCanceledEventHandler(BackgroundTask task)
        {
            var redeemControlTask = task as TezosRedeemControlTask;
            var swap = redeemControlTask?.Swap;

            if (swap == null)
            {
                return;
            }

            Log.Debug("Handle redeem control canceled event for swap {@swapId}", swap.Id);

            TaskPerformer.EnqueueTask(new RefundTimeControlTask
            {
                Currency        = Currency,
                RefundTimeUtc   = redeemControlTask.RefundTimeUtc,
                Swap            = swap,
                CompleteHandler = RefundTimeReachedEventHandler
            });
        }
Esempio n. 15
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Supervisor"/> class.
        /// </summary>
        /// <param name="fMainParam">The f main parameter.</param>
        public Supervisor(MDIParentForm fMainParam)
        {
            frmMain = fMainParam;
            var fileName = AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + @"\Config\ElevenSettings.xml";

            GlobalSettings = ElevenSettings.Load(fileName);

            if (string.IsNullOrEmpty(GlobalSettings.FolderSettings.Logs))
            {
                GlobalSettings.FolderSettings.Logs = AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + "Logs";
            }

            //Path Log - Creazione
            if (!Directory.Exists(GlobalSettings.FolderSettings.Logs))
            {
                Directory.CreateDirectory(GlobalSettings.FolderSettings.Logs);
            }

            Log = new LogManager(GlobalSettings.FolderSettings.Logs + Path.DirectorySeparatorChar + "Eleven_" + PreciseDateTime.Now.ToString("yyyyMMdd") + ".log");

            Log.LogEvent("[---------------------------------------------]");
            Log.LogEvent("[E-LEVEN][" + Assembly.GetExecutingAssembly().GetName().Version + "]");

            //Creazione Task
            taskPerformer = new TaskPerformer(this);

            //Gatewqay
            gateway = new Gateway(1, 1);

            InitExchanges();

            //Engine  e = new Engine(
            // Engine = new Engine(frmMain, gateway);

            //InitSecurities();

            System.Threading.Tasks.Task.Factory.StartNew(() => InitSecuritiesDelay());
        }
        private Task RestoreForPurchasedCurrencyAsync(ClientSwap swap)
        {
            if (swap.StateFlags.HasFlag(SwapStateFlags.IsRedeemBroadcast) &&
                !swap.StateFlags.HasFlag(SwapStateFlags.IsRedeemConfirmed))
            {
                if (!(swap.RedeemTx is IBitcoinBasedTransaction redeemTx))
                {
                    Log.Error("Can't restore swap {@id}. Redeem tx is null", swap.Id);
                    return(Task.CompletedTask);
                }

                TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask
                {
                    Currency        = Currency,
                    Swap            = swap,
                    Interval        = DefaultConfirmationCheckInterval,
                    TxId            = redeemTx.Id,
                    CompleteHandler = RedeemConfirmedEventHandler
                });
            }

            return(Task.CompletedTask);
        }
Esempio n. 17
0
        private async Task RefundAsync(
            ClientSwap swap,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            Log.Debug("Create refund for swap {@swap}", swap.Id);

            var walletAddress = (await Account.GetUnspentAddressesAsync(
                                     currency: Currency,
                                     amount: 0,
                                     fee: Xtz.RefundFee.ToTez() + Xtz.RefundStorageLimit.ToTez(),
                                     feePrice: 0,
                                     isFeePerTransaction: true,
                                     addressUsagePolicy: AddressUsagePolicy.UseOnlyOneAddress,
                                     cancellationToken: cancellationToken)
                                 .ConfigureAwait(false))
                                .FirstOrDefault();

            if (walletAddress == null)
            {
                Log.Error("Insufficient funds for refund");
                return;
            }

            var refundTx = new TezosTransaction(Xtz)
            {
                From         = walletAddress.Address,
                To           = Xtz.SwapContractAddress,
                Fee          = Xtz.RefundFee,
                GasLimit     = Xtz.RefundGasLimit,
                StorageLimit = Xtz.RefundStorageLimit,
                Params       = RefundParams(swap),
                Type         = TezosTransaction.OutputTransaction
            };

            var signResult = await SignTransactionAsync(refundTx, cancellationToken)
                             .ConfigureAwait(false);

            if (!signResult)
            {
                Log.Error("Transaction signing error");
                return;
            }

            swap.RefundTx = refundTx;
            swap.SetRefundSigned();
            RaiseSwapUpdated(swap, SwapStateFlags.IsRefundSigned);

            await BroadcastTxAsync(swap, refundTx, cancellationToken)
            .ConfigureAwait(false);

            swap.RefundTx = refundTx;
            swap.SetRefundBroadcast();
            RaiseSwapUpdated(swap, SwapStateFlags.IsRefundBroadcast);

            TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask
            {
                Currency        = Currency,
                Swap            = swap,
                Interval        = DefaultConfirmationCheckInterval,
                TxId            = refundTx.Id,
                CompleteHandler = RefundConfirmedEventHandler
            });
        }
        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
            });
        }
        private async Task RestoreForSoldCurrencyAsync(ClientSwap swap)
        {
            if (swap.StateFlags.HasFlag(SwapStateFlags.IsPaymentBroadcast))
            {
                if (!(swap.PaymentTx is IBitcoinBasedTransaction tx))
                {
                    Log.Error("Can't restore swap {@id}. Payment tx is null.", swap.Id);
                    return;
                }

                // check payment transaction spent
                var api = (IInOutBlockchainApi)Currency.BlockchainApi;

                var spentPoint = await api
                                 .IsTransactionOutputSpent(tx.Id, tx.SwapOutputs().First().Index) // todo: check specific output
                                 .ConfigureAwait(false);

                if (spentPoint != null && (swap.RefundTx == null ||
                                           (swap.RefundTx != null && spentPoint.Hash != swap.RefundTx.Id)))
                {
                    // raise redeem for counter party in other chain
                    if (swap.IsAcceptor)
                    {
                        PaymentSpentEventHandler(swap, spentPoint);
                    }
                    // else
                    //    nothing to do (waiting for redeem confirmation in another chain)
                    return;
                }

                if (!(swap.RefundTx is IBitcoinBasedTransaction refundTx))
                {
                    Log.Error("Can't restore swap {@id}. Refund tx is null", swap.Id);
                    return;
                }

                if (swap.StateFlags.HasFlag(SwapStateFlags.IsRefundBroadcast))
                {
                    // wait for refund confirmation
                    TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask
                    {
                        Currency        = Currency,
                        Swap            = swap,
                        Interval        = DefaultConfirmationCheckInterval,
                        TxId            = refundTx.Id,
                        CompleteHandler = RefundConfirmedEventHandler
                    });
                }
                else
                {
                    var refundTimeUtc = swap.TimeStamp.ToUniversalTime() +
                                        TimeSpan.FromSeconds(swap.IsInitiator
                                            ? DefaultInitiatorLockTimeInSeconds
                                            : DefaultAcceptorLockTimeInSeconds);

                    // refund control
                    TaskPerformer.EnqueueTask(new RefundTimeControlTask
                    {
                        Currency        = Currency,
                        Swap            = swap,
                        Interval        = DefaultRefundInterval,
                        RefundTimeUtc   = refundTimeUtc,
                        CompleteHandler = RefundTimeControlEventHandler
                    });
                }
            }
            else
            {
                if (DateTime.UtcNow < swap.TimeStamp.ToUniversalTime() + DefaultMaxSwapTimeout)
                {
                    if (swap.IsInitiator)
                    {
                        // todo: initiate swap

                        //await InitiateSwapAsync(swapState)
                        //    .ConfigureAwait(false);
                    }
                    else
                    {
                        // todo: request secret hash from server
                    }
                }
                else
                {
                    swap.Cancel();
                    RaiseSwapUpdated(swap, SwapStateFlags.IsCanceled);
                }
            }
        }
Esempio n. 20
0
        private async Task RefundAsync(
            ClientSwap swap,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            Log.Debug("Create refund for swap {@swap}", swap.Id);

            var walletAddress = (await Account.GetUnspentAddressesAsync(
                                     currency: Currency,
                                     amount: 0, // todo: account storage fee
                                     fee: Eth.RefundGasLimit,
                                     feePrice: Eth.GasPriceInGwei,
                                     isFeePerTransaction: true,
                                     addressUsagePolicy: AddressUsagePolicy.UseOnlyOneAddress)
                                 .ConfigureAwait(false))
                                .FirstOrDefault();

            if (walletAddress == null)
            {
                Log.Error("Insufficient funds for refund");
                return;
            }

            var nonce = await EthereumNonceManager.Instance
                        .GetNonce(Eth, walletAddress.Address)
                        .ConfigureAwait(false);

            var message = new RefundFunctionMessage
            {
                FromAddress  = walletAddress.Address,
                HashedSecret = swap.SecretHash,
                GasPrice     = Atomix.Ethereum.GweiToWei(Eth.GasPriceInGwei),
                Nonce        = nonce,
            };

            message.Gas = await EstimateGasAsync(message, new BigInteger(Eth.RefundGasLimit))
                          .ConfigureAwait(false);

            var txInput = message.CreateTransactionInput(Eth.SwapContractAddress);

            var refundTx = new EthereumTransaction(Eth, txInput)
            {
                Type = EthereumTransaction.OutputTransaction
            };

            var signResult = await SignTransactionAsync(refundTx, cancellationToken)
                             .ConfigureAwait(false);

            if (!signResult)
            {
                Log.Error("Transaction signing error");
                return;
            }

            swap.RefundTx = refundTx;
            swap.SetRefundSigned();
            RaiseSwapUpdated(swap, SwapStateFlags.IsRefundSigned);

            await BroadcastTxAsync(swap, refundTx, cancellationToken)
            .ConfigureAwait(false);

            swap.RefundTx = refundTx;
            swap.SetRefundBroadcast();
            RaiseSwapUpdated(swap, SwapStateFlags.IsRefundBroadcast);

            TaskPerformer.EnqueueTask(new TransactionConfirmationCheckTask
            {
                Currency        = Currency,
                Swap            = swap,
                Interval        = DefaultConfirmationCheckInterval,
                TxId            = refundTx.Id,
                CompleteHandler = RefundConfirmedEventHandler
            });
        }