Exemplo n.º 1
0
        protected override async Task RefundTimeReachedHandler(
            Swap swap,
            CancellationToken cancellationToken = default)
        {
            Log.Debug("Refund time reached for swap {@swapId}", swap.Id);

            try
            {
                var isRefundedResult = await Fa12SwapRefundedHelper.IsRefundedAsync(
                    swap : swap,
                    currency : Fa12Config,
                    tezos : XtzConfig,
                    attempts : TezosSwap.MaxRefundCheckAttempts,
                    attemptIntervalInSec : TezosSwap.RefundCheckAttemptIntervalInSec,
                    cancellationToken : cancellationToken)
                                       .ConfigureAwait(false);

                if (!isRefundedResult.HasError)
                {
                    if (isRefundedResult.Value)
                    {
                        await RefundConfirmedEventHandler(swap, swap.RefundTx, cancellationToken)
                        .ConfigureAwait(false);
                    }
                    else
                    {
                        await RefundAsync(swap, cancellationToken)
                        .ConfigureAwait(false);
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e, "Error in refund time reached handler");
            }
        }
Exemplo n.º 2
0
        public override async Task RedeemAsync(
            Swap swap,
            CancellationToken cancellationToken = default)
        {
            var fa12 = Fa12Config;

            var secretResult = await Fa12SwapRedeemedHelper
                               .IsRedeemedAsync(
                swap : swap,
                currency : fa12,
                tezos : XtzConfig,
                attempts : TezosSwap.MaxRedeemCheckAttempts,
                attemptIntervalInSec : TezosSwap.RedeemCheckAttemptIntervalInSec,
                cancellationToken : cancellationToken)
                               .ConfigureAwait(false);

            if (!secretResult.HasError && secretResult.Value != null)
            {
                await RedeemConfirmedEventHandler(swap, null, cancellationToken)
                .ConfigureAwait(false);

                return;
            }

            if (swap.StateFlags.HasFlag(SwapStateFlags.IsRedeemBroadcast) &&
                swap.RedeemTx != null &&
                swap.RedeemTx.CreationTime != null &&
                swap.RedeemTx.CreationTime.Value.ToUniversalTime() + TimeSpan.FromMinutes(5) > DateTime.UtcNow)
            {
                // redeem already broadcast
                _ = TrackTransactionConfirmationAsync(
                    swap: swap,
                    currency: fa12,
                    dataRepository: Fa12Account.DataRepository,
                    txId: swap.RedeemTx.Id,
                    confirmationHandler: RedeemConfirmedEventHandler,
                    cancellationToken: cancellationToken);

                return;
            }

            // check already refunded by initiator
            if (swap.IsAcceptor &&
                swap.TimeStamp.ToUniversalTime().AddSeconds(DefaultInitiatorLockTimeInSeconds) < DateTime.UtcNow)
            {
                var isRefundedByParty = await Fa12SwapRefundedHelper
                                        .IsRefundedAsync(swap, fa12, XtzConfig, cancellationToken)
                                        .ConfigureAwait(false);

                if (isRefundedByParty != null &&
                    !isRefundedByParty.HasError &&
                    isRefundedByParty.Value)
                {
                    swap.StateFlags |= SwapStateFlags.IsUnsettled;

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

                    return;
                }
            }

            if (swap.IsInitiator)
            {
                var redeemDeadline = swap.TimeStamp.ToUniversalTime().AddSeconds(DefaultAcceptorLockTimeInSeconds) - RedeemTimeReserve;

                if (DateTime.UtcNow > redeemDeadline)
                {
                    Log.Error("Redeem dedline reached for swap {@swap}", swap.Id);
                    return;
                }
            }

            Log.Debug("Create redeem for swap {@swapId}", swap.Id);

            var walletAddress = await TezosAccount
                                .GetAddressAsync(swap.RedeemFromAddress, cancellationToken)
                                .ConfigureAwait(false);

            if (walletAddress == null)
            {
                Log.Error("Can't get address {@address} for redeem from local db", swap.RedeemFromAddress);
                return;
            }

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

            var feeAmountInMtz    = fa12.RedeemFee + fa12.RevealFee;
            var storageLimitInMtz = fa12.RedeemStorageLimit * fa12.StorageFeeMultiplier;

            if (walletAddress.Balance.ToMicroTez() < feeAmountInMtz + storageLimitInMtz)
            {
                Log.Error("Insufficient funds for redeem");
                return;
            }

            var redeemTx = new TezosTransaction
            {
                Currency     = XtzConfig.Name,
                CreationTime = DateTime.UtcNow,
                From         = walletAddress.Address,
                To           = fa12.SwapContractAddress,
                Amount       = 0,
                Fee          = fa12.RedeemFee + fa12.RevealFee,
                GasLimit     = fa12.RedeemGasLimit,
                StorageLimit = fa12.RedeemStorageLimit,
                Params       = CreateRedeemParams(swap),
                Type         = BlockchainTransactionType.Output | BlockchainTransactionType.SwapRedeem,

                UseRun = true,
                UseSafeStorageLimit = true,
                UseOfflineCounter   = true
            };

            try
            {
                await TezosAccount.AddressLocker
                .LockAsync(redeemTx.From, cancellationToken)
                .ConfigureAwait(false);

                using var securePublicKey = TezosAccount.Wallet
                                            .GetPublicKey(XtzConfig, walletAddress.KeyIndex, walletAddress.KeyType);

                // fill operation
                var(fillResult, isRunSuccess, hasReveal) = await redeemTx
                                                           .FillOperationsAsync(
                    securePublicKey : securePublicKey,
                    tezosConfig : XtzConfig,
                    headOffset : TezosConfig.HeadOffset,
                    cancellationToken : cancellationToken)
                                                           .ConfigureAwait(false);

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

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

                swap.RedeemTx    = redeemTx;
                swap.StateFlags |= SwapStateFlags.IsRedeemSigned;

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

                await BroadcastTxAsync(swap, redeemTx, cancellationToken)
                .ConfigureAwait(false);
            }
            catch
            {
                throw;
            }
            finally
            {
                TezosAccount.AddressLocker.Unlock(redeemTx.From);
            }

            swap.RedeemTx    = redeemTx;
            swap.StateFlags |= SwapStateFlags.IsRedeemBroadcast;

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

            _ = TrackTransactionConfirmationAsync(
                swap: swap,
                currency: XtzConfig,
                dataRepository: Fa12Account.DataRepository,
                txId: redeemTx.Id,
                confirmationHandler: RedeemConfirmedEventHandler,
                cancellationToken: cancellationToken);
        }