private async Task <bool> SignTransactionAsync( TezosTransaction tx, CancellationToken cancellationToken = default) { var walletAddress = await NYXAccount .GetAddressAsync( address : tx.From, cancellationToken : cancellationToken) .ConfigureAwait(false); return(await NYXAccount.Wallet .SignAsync( tx : tx, address : walletAddress, cancellationToken : cancellationToken) .ConfigureAwait(false)); }
protected override async Task <IEnumerable <TezosTransaction> > CreatePaymentTxsAsync( Swap swap, int lockTimeSeconds, CancellationToken cancellationToken = default) { Log.Debug("Create payment transactions for swap {@swapId}", swap.Id); var nyx = NYX; var nyxApi = nyx.BlockchainApi as ITokenBlockchainApi; var requiredAmountInTokens = AmountHelper.QtyToAmount(swap.Side, swap.Qty, swap.Price, nyx.DigitsMultiplier); var refundTimeStampUtcInSec = new DateTimeOffset(swap.TimeStamp.ToUniversalTime().AddSeconds(lockTimeSeconds)).ToUnixTimeSeconds(); var rewardForRedeemInTokenDigits = swap.IsInitiator ? swap.PartyRewardForRedeem.ToTokenDigits(nyx.DigitsMultiplier) : 0; var unspentAddresses = (await NYXAccount .GetUnspentAddressesAsync(cancellationToken) .ConfigureAwait(false)) .ToList() .SortList(new AvailableBalanceAscending()); unspentAddresses.RemoveRange(0, unspentAddresses.Count - 1); var transactions = new List <TezosTransaction>(); foreach (var walletAddress in unspentAddresses) { Log.Debug("Create swap payment tx from address {@address} for swap {@swapId}", walletAddress.Address, swap.Id); var balanceInTz = (await TezosAccount .GetAddressBalanceAsync( address: walletAddress.Address, cancellationToken: cancellationToken) .ConfigureAwait(false)) .Available; var balanceInTokens = (await NYXAccount .GetAddressBalanceAsync( address: walletAddress.Address, cancellationToken: cancellationToken) .ConfigureAwait(false)) .Available; Log.Debug("Available balance: {@balance}", balanceInTokens); var balanceInMtz = balanceInTz.ToMicroTez(); var balanceInTokenDigits = balanceInTokens.ToTokenDigits(nyx.DigitsMultiplier); var isRevealed = await _account .IsRevealedSourceAsync(walletAddress.Address, cancellationToken) .ConfigureAwait(false); var feeAmountInMtz = nyx.ApproveFee + nyx.InitiateFee + (isRevealed ? 0 : nyx.RevealFee); var storageLimitInMtz = (nyx.ApproveStorageLimit + nyx.InitiateStorageLimit) * nyx.StorageFeeMultiplier; if (balanceInMtz - feeAmountInMtz - storageLimitInMtz - Xtz.MicroTezReserve <= 0) { Log.Warning( "Insufficient funds at {@address}. Balance: {@balance}, " + "feeAmount: {@feeAmount}, storageLimit: {@storageLimit}.", walletAddress.Address, balanceInMtz, feeAmountInMtz, storageLimitInMtz); continue; } var amountInTokens = requiredAmountInTokens > 0 ? AmountHelper.DustProofMin(balanceInTokens, requiredAmountInTokens, nyx.DigitsMultiplier, nyx.DustDigitsMultiplier) : 0; if (amountInTokens == 0) { break; } requiredAmountInTokens -= amountInTokens; using var callingAddressPublicKey = new SecureBytes((await NYXAccount.GetAddressAsync(walletAddress.Address) .ConfigureAwait(false)) .PublicKeyBytes()); //todo: get allowance //var allowanceResult = await nyxApi // .TryGetTokenAllowanceAsync( // holderAddress: walletAddress.Address, // spenderAddress: nyx.SwapContractAddress, // callingAddress: walletAddress.Address, // securePublicKey: callingAddressPublicKey, // cancellationToken: cancellationToken) // .ConfigureAwait(false); //if (allowanceResult.HasError) //{ // Log.Error("Error while getting token allowance for {@address} with code {@code} and description {@description}", // walletAddress.Address, // allowanceResult.Error.Code, // allowanceResult.Error.Description); // continue; // todo: maybe add approve 0 //} //if (allowanceResult.Value > 0) //{ // transactions.Add(new TezosTransaction // { // Currency = nyx, // CreationTime = DateTime.UtcNow, // From = walletAddress.Address, // To = nyx.TokenContractAddress, // Fee = nyx.ApproveFee, // GasLimit = nyx.ApproveGasLimit, // StorageLimit = nyx.ApproveStorageLimit, // Params = ApproveParams(nyx.SwapContractAddress, 0), // UseDefaultFee = true, // Type = BlockchainTransactionType.TokenApprove // }); //} transactions.Add(new TezosTransaction { Currency = nyx, CreationTime = DateTime.UtcNow, From = walletAddress.Address, To = nyx.TokenContractAddress, Fee = nyx.ApproveFee, GasLimit = nyx.ApproveGasLimit, StorageLimit = nyx.ApproveStorageLimit, Params = ApproveParams(walletAddress.Address, nyx.SwapContractAddress, amountInTokens.ToTokenDigits(nyx.DigitsMultiplier)), UseDefaultFee = true, Type = BlockchainTransactionType.TokenApprove }); transactions.Add(new TezosTransaction { Currency = nyx, CreationTime = DateTime.UtcNow, From = walletAddress.Address, To = nyx.SwapContractAddress, Fee = feeAmountInMtz, GasLimit = nyx.InitiateGasLimit, StorageLimit = nyx.InitiateStorageLimit, Params = InitParams(swap, nyx.TokenContractAddress, amountInTokens.ToTokenDigits(nyx.DigitsMultiplier), refundTimeStampUtcInSec, (long)rewardForRedeemInTokenDigits), UseDefaultFee = true, Type = BlockchainTransactionType.Output | BlockchainTransactionType.SwapPayment }); if (requiredAmountInTokens <= 0) { break; } } if (requiredAmountInTokens > 0) { Log.Warning("Insufficient funds (left {@requredAmount}).", requiredAmountInTokens); return(Enumerable.Empty <TezosTransaction>()); } return(transactions); }