protected override async Task RefundTimeReachedHandler( Swap swap, CancellationToken cancellationToken = default) { Log.Debug("Refund time reached for swap {@swapId}", swap.Id); try { var isRefundedResult = await TezosSwapRefundedHelper.IsRefundedAsync( swap : swap, currency : XtzConfig, attempts : MaxRefundCheckAttempts, attemptIntervalInSec : 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"); } }
public override async Task RedeemAsync( Swap swap, CancellationToken cancellationToken = default) { var xtzConfig = XtzConfig; var secretResult = await TezosSwapRedeemedHelper .IsRedeemedAsync( swap : swap, currency : xtzConfig, attempts : MaxRedeemCheckAttempts, attemptIntervalInSec : 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: xtzConfig, dataRepository: _account.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 TezosSwapRefundedHelper .IsRefundedAsync(swap, 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 _account .GetAddressAsync(swap.RedeemFromAddress, cancellationToken) .ConfigureAwait(false); if (walletAddress == null) { Log.Error("Can't get address {@address} for redeem from local db", swap.RedeemFromAddress); return; } var feeAmountInMtz = xtzConfig.RedeemFee + xtzConfig.RevealFee; var storageLimitInMtz = xtzConfig.RedeemStorageLimit * xtzConfig.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 = xtzConfig.SwapContractAddress, Amount = 0, Fee = xtzConfig.RedeemFee + xtzConfig.RevealFee, GasLimit = xtzConfig.RedeemGasLimit, StorageLimit = xtzConfig.RedeemStorageLimit, Params = CreateRedeemParams(swap), Type = BlockchainTransactionType.Output | BlockchainTransactionType.SwapRedeem, UseRun = true, UseSafeStorageLimit = true, UseOfflineCounter = true }; try { await _account.AddressLocker .LockAsync(redeemTx.From, cancellationToken) .ConfigureAwait(false); using var securePublicKey = _account.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 { _account.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: _account.DataRepository, txId: redeemTx.Id, confirmationHandler: RedeemConfirmedEventHandler, cancellationToken: cancellationToken); }
public override async Task RedeemAsync( Swap swap, CancellationToken cancellationToken = default) { var xtz = Xtz; var secretResult = await TezosSwapRedeemedHelper .IsRedeemedAsync( swap : swap, currency : xtz, attempts : MaxRedeemCheckAttempts, attemptIntervalInSec : RedeemCheckAttemptIntervalInSec, cancellationToken : cancellationToken) .ConfigureAwait(false); if (!secretResult.HasError && secretResult.Value != null) { RedeemConfirmedEventHandler(swap, null, cancellationToken); 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: xtz, txId: swap.RedeemTx.Id, confirmationHandler: RedeemConfirmedEventHandler, cancellationToken: cancellationToken) .FireAndForget(); return; } // check already refunded by initiator if (swap.IsAcceptor && swap.TimeStamp.ToUniversalTime().AddSeconds(DefaultInitiatorLockTimeInSeconds) < DateTime.UtcNow) { var isRefundedByParty = await TezosSwapRefundedHelper .IsRefundedAsync(swap, xtz, cancellationToken) .ConfigureAwait(false); if (isRefundedByParty != null && !isRefundedByParty.HasError && isRefundedByParty.Value) { swap.StateFlags |= SwapStateFlags.IsUnsettled; RaiseSwapUpdated(swap, SwapStateFlags.IsUnsettled); 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 _account .GetUnspentAddressesAsync( toAddress: swap.ToAddress, amount: 0, fee: 0, feePrice: 0, feeUsagePolicy: FeeUsagePolicy.EstimatedFee, addressUsagePolicy: AddressUsagePolicy.UseOnlyOneAddress, transactionType: BlockchainTransactionType.SwapRedeem, cancellationToken: cancellationToken) .ConfigureAwait(false)) .FirstOrDefault(); if (walletAddress == null) { Log.Error("Insufficient funds for redeem"); return; } var redeemTx = new TezosTransaction { Currency = xtz, CreationTime = DateTime.UtcNow, From = walletAddress.Address, To = xtz.SwapContractAddress, Amount = 0, Fee = xtz.RedeemFee + xtz.RevealFee, GasLimit = xtz.RedeemGasLimit, StorageLimit = xtz.RedeemStorageLimit, Params = RedeemParams(swap), UseDefaultFee = true, Type = BlockchainTransactionType.Output | BlockchainTransactionType.SwapRedeem }; var signResult = await SignTransactionAsync(redeemTx, cancellationToken) .ConfigureAwait(false); if (!signResult) { Log.Error("Transaction signing error"); return; } swap.RedeemTx = redeemTx; swap.StateFlags |= SwapStateFlags.IsRedeemSigned; RaiseSwapUpdated(swap, SwapStateFlags.IsRedeemSigned); await BroadcastTxAsync(swap, redeemTx, cancellationToken) .ConfigureAwait(false); swap.RedeemTx = redeemTx; swap.StateFlags |= SwapStateFlags.IsRedeemBroadcast; RaiseSwapUpdated(swap, SwapStateFlags.IsRedeemBroadcast); TrackTransactionConfirmationAsync( swap: swap, currency: xtz, txId: redeemTx.Id, confirmationHandler: RedeemConfirmedEventHandler, cancellationToken: cancellationToken) .FireAndForget(); }