Beispiel #1
0
        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));
        }
Beispiel #2
0
        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);
        }