Ejemplo n.º 1
0
        public async Task <int> GetCounter(Atomex.Tezos tezos, string address)
        {
            var rpc = new Rpc(tezos.RpcNodeUri);

            var head = await rpc
                       .GetHeader()
                       .ConfigureAwait(false);

            return(await GetCounter(tezos, address, head)
                   .ConfigureAwait(false));
        }
Ejemplo n.º 2
0
        public TzktApi(Atomex.Tezos currency)
        {
            _currency   = currency;
            _baseUri    = currency.BaseUri;
            _rpcNodeUri = currency.RpcNodeUri;

            _headers = new HttpRequestHeaders
            {
                new KeyValuePair <string, IEnumerable <string> >("User-Agent", new string[] { "Atomex" })
            };
        }
Ejemplo n.º 3
0
        public async Task <int> GetCounter(
            Atomex.Tezos tezos,
            string address,
            JObject head,
            bool ignoreCache = false)
        {
            var rpc = new Rpc(tezos.RpcNodeUri);

            var account = await rpc
                          .GetAccountForBlock(head["hash"].ToString(), address)
                          .ConfigureAwait(false);

            var counter = int.Parse(account["counter"].ToString());

            lock (_syncRoot)
            {
                if (_counters.TryGetValue(address, out var offlineCounter))
                {
                    if (!ignoreCache &&
                        offlineCounter.Value > counter &&
                        DateTime.UtcNow - offlineCounter.LastUpdatedTimeUtc <= ExpirationTimeOut)
                    {
                        return(++offlineCounter.Value);
                    }
                    else
                    {
                        //++counter;
                        _counters[address] = new CounterEntry
                        {
                            Value = ignoreCache ? counter : counter + 1,
                            LastUpdatedTimeUtc = DateTime.UtcNow
                        };

                        return(++counter);
                    }
                }
                else
                {
                    //++counter;
                    _counters.Add(address, new CounterEntry
                    {
                        Value = ignoreCache ? counter : counter + 1,
                        LastUpdatedTimeUtc = DateTime.UtcNow
                    });

                    return(++counter);
                }
            }
        }
        public static Task StartSwapRedeemedControlAsync(
            Swap swap,
            Currency currency,
            Atomex.Tezos tezos,
            DateTime refundTimeUtc,
            TimeSpan interval,
            bool cancelOnlyIfRefundTimeReached = true,
            Action <Swap, byte[], CancellationToken> redeemedHandler   = null,
            Action <Swap, DateTime, CancellationToken> canceledHandler = null,
            CancellationToken cancellationToken = default)
        {
            return(Task.Run(async() =>
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    var isRedeemedResult = await IsRedeemedAsync(
                        swap: swap,
                        currency: currency,
                        tezos: tezos,
                        cancellationToken: cancellationToken)
                                           .ConfigureAwait(false);

                    if (isRedeemedResult.HasError && isRedeemedResult.Error.Code != Errors.RequestError) // has error
                    {
                        canceledHandler?.Invoke(swap, refundTimeUtc, cancellationToken);
                        break;
                    }
                    else if (!isRedeemedResult.HasError && isRedeemedResult.Value != null) // has secret
                    {
                        redeemedHandler?.Invoke(swap, isRedeemedResult.Value, cancellationToken);
                        break;
                    }

                    if (!cancelOnlyIfRefundTimeReached || DateTime.UtcNow >= refundTimeUtc)
                    {
                        canceledHandler?.Invoke(swap, refundTimeUtc, cancellationToken);
                        break;
                    }

                    await Task.Delay(interval, cancellationToken)
                    .ConfigureAwait(false);
                }
            }, cancellationToken));
        }
        public static Task StartSwapInitiatedControlAsync(
            Swap swap,
            Currency currency,
            Atomex.Tezos tezos,
            long refundTimeStamp,
            TimeSpan interval,
            Action <Swap, CancellationToken> initiatedHandler = null,
            Action <Swap, CancellationToken> canceledHandler  = null,
            CancellationToken cancellationToken = default)
        {
            return(Task.Run(async() =>
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    if (swap.IsCanceled)
                    {
                        canceledHandler?.Invoke(swap, cancellationToken);
                        break;
                    }

                    var isInitiatedResult = await IsInitiatedAsync(
                        swap: swap,
                        currency: currency,
                        tezos: tezos,
                        refundTimeStamp: refundTimeStamp,
                        cancellationToken: cancellationToken)
                                            .ConfigureAwait(false);

                    if (isInitiatedResult.HasError && isInitiatedResult.Error.Code != Errors.RequestError)
                    {
                        canceledHandler?.Invoke(swap, cancellationToken);
                        break;
                    }
                    else if (!isInitiatedResult.HasError && isInitiatedResult.Value)
                    {
                        initiatedHandler?.Invoke(swap, cancellationToken);
                        break;
                    }

                    await Task.Delay(interval, cancellationToken)
                    .ConfigureAwait(false);
                }
            }, cancellationToken));
        }
 public static ICurrencySwap Create(
     Currency currency,
     IAccount account,
     ISwapClient swapClient)
 {
     return(currency switch
     {
         BitcoinBasedCurrency _ => (ICurrencySwap) new BitcoinBasedSwap(
             account: account.GetCurrencyAccount <BitcoinBasedAccount>(currency.Name),
             swapClient: swapClient,
             currencies: account.Currencies),
         ERC20 _ => (ICurrencySwap) new ERC20Swap(
             account: account.GetCurrencyAccount <ERC20Account>(currency.Name),
             ethereumAccount: account.GetCurrencyAccount <EthereumAccount>("ETH"),
             swapClient: swapClient,
             currencies: account.Currencies),
         Atomex.Ethereum _ => (ICurrencySwap) new EthereumSwap(
             account: account.GetCurrencyAccount <EthereumAccount>(currency.Name),
             swapClient: swapClient,
             currencies: account.Currencies),
         NYX _ => (ICurrencySwap) new NYXSwap(
             account: account.GetCurrencyAccount <NYXAccount>(currency.Name),
             tezosAccount: account.GetCurrencyAccount <TezosAccount>("XTZ"),
             swapClient: swapClient,
             currencies: account.Currencies),
         FA2 _ => (ICurrencySwap) new FA2Swap(
             account: account.GetCurrencyAccount <FA2Account>(currency.Name),
             tezosAccount: account.GetCurrencyAccount <TezosAccount>("XTZ"),
             swapClient: swapClient,
             currencies: account.Currencies),
         FA12 _ => (ICurrencySwap) new FA12Swap(
             account: account.GetCurrencyAccount <FA12Account>(currency.Name),
             tezosAccount: account.GetCurrencyAccount <TezosAccount>("XTZ"),
             swapClient: swapClient,
             currencies: account.Currencies),
         Atomex.Tezos _ => (ICurrencySwap) new TezosSwap(
             account: account.GetCurrencyAccount <TezosAccount>(currency.Name),
             swapClient: swapClient,
             currencies: account.Currencies),
         _ => throw new NotSupportedException($"Not supported currency {currency.Name}"),
     });
Ejemplo n.º 7
0
        public static async Task <Result <bool> > IsRefundedAsync(
            Swap swap,
            Currency currency,
            Atomex.Tezos tezos,
            int attempts,
            int attemptIntervalInSec,
            CancellationToken cancellationToken = default)
        {
            var attempt = 0;

            while (!cancellationToken.IsCancellationRequested && attempt < attempts)
            {
                ++attempt;

                var isRefundedResult = await IsRefundedAsync(
                    swap : swap,
                    currency : currency,
                    tezos : tezos,
                    cancellationToken : cancellationToken)
                                       .ConfigureAwait(false);

                if (isRefundedResult.HasError && isRefundedResult.Error.Code != Errors.RequestError) // has error
                {
                    return(isRefundedResult);
                }

                if (!isRefundedResult.HasError)
                {
                    return(isRefundedResult);
                }

                await Task.Delay(TimeSpan.FromSeconds(attemptIntervalInSec), cancellationToken)
                .ConfigureAwait(false);
            }

            return(new Error(Errors.MaxAttemptsCountReached, "Max attempts count reached for refund check"));
        }
 public TezosRevealChecker(Atomex.Tezos tezos)
 {
     _tezos     = tezos;
     _addresses = new Dictionary <string, TezosAddressInfo>();
 }
Ejemplo n.º 9
0
        public static async Task <Result <bool> > IsRefundedAsync(
            Swap swap,
            Currency currency,
            Atomex.Tezos tezos,
            CancellationToken cancellationToken = default)
        {
            try
            {
                Log.Debug("Tezos FA2: check refund event");

                var fa2 = (TezosTokens.FA2)currency;

                var contractAddress = fa2.SwapContractAddress;

                var blockchainApi = (ITezosBlockchainApi)tezos.BlockchainApi;

                var txsResult = await blockchainApi
                                .TryGetTransactionsAsync(contractAddress, cancellationToken : cancellationToken)
                                .ConfigureAwait(false);

                if (txsResult == null)
                {
                    return(new Error(Errors.RequestError, $"Connection error while getting {contractAddress} transactions"));
                }

                if (txsResult.HasError)
                {
                    Log.Error("Error while get transactions from contract {@contract}. Code: {@code}. Description: {@desc}",
                              contractAddress,
                              txsResult.Error.Code,
                              txsResult.Error.Description);

                    return(txsResult.Error);
                }

                var txs = txsResult.Value
                          ?.Cast <TezosTransaction>()
                          .ToList();

                if (txs != null)
                {
                    foreach (var tx in txs)
                    {
                        if (tx.To == contractAddress && IsSwapRefund(tx, swap.SecretHash))
                        {
                            return(true);
                        }

                        if (tx.BlockInfo?.BlockTime == null)
                        {
                            continue;
                        }

                        var blockTimeUtc = tx.BlockInfo.BlockTime.Value.ToUniversalTime();
                        var swapTimeUtc  = swap.TimeStamp.ToUniversalTime();

                        if (blockTimeUtc < swapTimeUtc)
                        {
                            break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e, "Tezos FA2 refund control task error");

                return(new Error(Errors.InternalError, e.Message));
            }

            return(false);
        }
Ejemplo n.º 10
0
        public async Task <bool> AutoFillOperations(Atomex.Tezos tezos, JObject head, JArray operations, bool defaultFee = true)
        {
            var runResults = await RunOperations(head, operations)
                             .ConfigureAwait(false);

            foreach (var result in runResults.SelectToken("contents"))
            {
                decimal gas = 0, storage_diff = 0, size = 0, fee = 0;

                var metaData        = result["metadata"];
                var operationResult = metaData?["operation_result"];

                if (operationResult?["status"]?.ToString() == "applied")
                {
                    try
                    {
                        gas  = tezos.GasReserve + operationResult?["consumed_gas"]?.Value <decimal>() ?? 0;
                        gas += metaData
                               ?.SelectToken("internal_operation_results")
                               ?.Sum(res => res["result"]?["consumed_gas"]?.Value <decimal>() ?? 0) ?? 0;

                        //storage = operationResult?["storage_size"]?.Value<decimal>() ?? 0;

                        storage_diff  = operationResult?["paid_storage_size_diff"]?.Value <decimal>() ?? 0;
                        storage_diff += tezos.ActivationStorage * (operationResult?["allocated_destination_contract"]?.ToString() == "True" ? 1 : 0);
                        storage_diff += tezos.ActivationStorage * metaData?["internal_operation_results"]
                                        ?.Where(res => res["result"]?["allocated_destination_contract"]?.ToString() == "True")
                                        .Count() ?? 0;
                        storage_diff += metaData
                                        ?.SelectToken("internal_operation_results")
                                        ?.Sum(res => res["result"]?["paid_storage_size_diff"]?.Value <decimal>() ?? 0) ?? 0;

                        var op = operations
                                 .Children <JObject>()
                                 .FirstOrDefault(o => o["counter"] != null && o["counter"].ToString() == result["counter"].ToString());

                        op["gas_limit"]     = gas.ToString();
                        op["storage_limit"] = storage_diff.ToString();

                        JToken forgedOpLocal = Forge.ForgeOperationsLocal(null, op);

                        ///Checking for local and node forging results equality

                        //JToken forgedOp = await ForgeOperations(head, op);

                        //if (forgedOpLocal.ToString() != forgedOp.ToString().Substring((int)tezos.HeadSizeInBytes * 2))
                        //    Log.Error("Local operation forge result differs from remote"); //process the error

                        size = forgedOpLocal.ToString().Length / 2 + Math.Ceiling((tezos.HeadSizeInBytes + tezos.SigSizeInBytes) / operations.Count);
                        fee  = tezos.MinimalFee + tezos.MinimalNanotezPerByte * size + (long)Math.Ceiling(tezos.MinimalNanotezPerGasUnit * gas) + 1;
                        if (defaultFee)
                        {
                            op["fee"] = fee.ToString();
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error("Transaction autofilling error: " + ex.Message.ToString()); //process the error
                        return(false);
                    }
                }
                else
                {
                    Log.Error("Transaction running failed: "); //process the error
                    Log.Error(result.ToString());
                    return(false);
                }
            }
            return(true);
        }
Ejemplo n.º 11
0
        public static async Task <Result <byte[]> > IsRedeemedAsync(
            Swap swap,
            Currency currency,
            Atomex.Tezos tezos,
            CancellationToken cancellationToken = default)
        {
            try
            {
                Log.Debug("Tezos NYX: check redeem event");

                var nyx = (TezosTokens.NYX)currency;

                var contractAddress = nyx.SwapContractAddress;

                var blockchainApi = (ITezosBlockchainApi)tezos.BlockchainApi;

                var txsResult = await blockchainApi
                                .TryGetTransactionsAsync(contractAddress, cancellationToken : cancellationToken)
                                .ConfigureAwait(false);

                if (txsResult == null)
                {
                    return(new Error(Errors.RequestError, $"Connection error while getting txs from contract {contractAddress}"));
                }

                if (txsResult.HasError)
                {
                    Log.Error("Error while get transactions from contract {@contract}. Code: {@code}. Description: {@desc}",
                              contractAddress,
                              txsResult.Error.Code,
                              txsResult.Error.Description);

                    return(txsResult.Error);
                }

                var txs = txsResult.Value
                          ?.Cast <TezosTransaction>()
                          .ToList();

                if (txs != null)
                {
                    foreach (var tx in txs)
                    {
                        if (tx.To == contractAddress && IsSwapRedeem(tx, swap.SecretHash))
                        {
                            // redeem!
                            var secret = GetSecret(tx);

                            Log.Debug("Redeem event received with secret {@secret}", Convert.ToBase64String(secret));

                            return(secret);
                        }

                        if (tx.BlockInfo?.BlockTime == null)
                        {
                            continue;
                        }

                        var blockTimeUtc = tx.BlockInfo.BlockTime.Value.ToUniversalTime();
                        var swapTimeUtc  = swap.TimeStamp.ToUniversalTime();

                        if (blockTimeUtc < swapTimeUtc)
                        {
                            break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e, "Tezos NYX redeem control task error");

                return(new Error(Errors.InternalError, e.Message));
            }

            return((byte[])null);
        }
        public static async Task <Result <bool> > IsInitiatedAsync(
            Swap swap,
            Currency currency,
            Atomex.Tezos tezos,
            long refundTimeStamp,
            CancellationToken cancellationToken = default)
        {
            try
            {
                Log.Debug("Tezos FA12: check initiated event");

                var fa12 = (TezosTokens.FA12)currency;

                var side = swap.Symbol
                           .OrderSideForBuyCurrency(swap.PurchasedCurrency)
                           .Opposite();

                var requiredAmountInTokenDigits = AmountHelper
                                                  .QtyToAmount(side, swap.Qty, swap.Price, fa12.DigitsMultiplier)
                                                  .ToTokenDigits(fa12.DigitsMultiplier);

                var requiredRewardForRedeemInTokenDigits = swap.IsAcceptor ? swap.RewardForRedeem.ToTokenDigits(fa12.DigitsMultiplier) : 0;

                var contractAddress                      = fa12.SwapContractAddress;
                var detectedAmountInTokenDigits          = 0m;
                var detectedRedeemFeeAmountInTokenDigits = 0m;

                long detectedRefundTimestamp = 0;

                var blockchainApi = (ITezosBlockchainApi)tezos.BlockchainApi;

                var txsResult = await blockchainApi
                                .TryGetTransactionsAsync(contractAddress, cancellationToken : cancellationToken)
                                .ConfigureAwait(false);

                if (txsResult == null)
                {
                    return(new Error(Errors.RequestError, $"Connection error while getting txs from contract {contractAddress}"));
                }

                if (txsResult.HasError)
                {
                    Log.Error("Error while get transactions from contract {@contract}. Code: {@code}. Description: {@desc}",
                              contractAddress,
                              txsResult.Error.Code,
                              txsResult.Error.Description);

                    return(txsResult.Error);
                }

                var txs = txsResult.Value
                          ?.Cast <TezosTransaction>()
                          .ToList();

                if (txs == null || !txs.Any())
                {
                    return(false);
                }

                foreach (var tx in txs)
                {
                    if (tx.IsConfirmed && tx.To == contractAddress)
                    {
                        var detectedPayment = false;

                        if (IsSwapInit(tx, fa12.TokenContractAddress, swap.SecretHash, swap.ToAddress))
                        {
                            // init payment to secret hash!
                            detectedPayment                      = true;
                            detectedAmountInTokenDigits         += GetAmount(tx);
                            detectedRedeemFeeAmountInTokenDigits = GetRedeemFee(tx);
                            detectedRefundTimestamp              = GetRefundTimestamp(tx);
                        }
                        ///not implemented
                        //else if (IsSwapAdd(tx, swap.SecretHash))
                        //{
                        //    detectedPayment = true;
                        //    detectedAmountInMtz += tx.Amount;
                        //}

                        if (detectedPayment && detectedAmountInTokenDigits >= requiredAmountInTokenDigits)
                        {
                            if (swap.IsAcceptor && detectedRedeemFeeAmountInTokenDigits != requiredRewardForRedeemInTokenDigits)
                            {
                                Log.Debug(
                                    "Invalid redeem fee in initiated event. Expected value is {@expected}, actual is {@actual}",
                                    requiredRewardForRedeemInTokenDigits,
                                    detectedRedeemFeeAmountInTokenDigits);

                                return(new Error(
                                           code: Errors.InvalidRewardForRedeem,
                                           description: $"Invalid redeem fee in initiated event. Expected value is {requiredRewardForRedeemInTokenDigits}, actual is {detectedRedeemFeeAmountInTokenDigits}"));
                            }

                            if (detectedRefundTimestamp != refundTimeStamp)
                            {
                                Log.Debug(
                                    "Invalid refund timestamp in initiated event. Expected value is {@expected}, actual is {@actual}",
                                    refundTimeStamp,
                                    detectedRefundTimestamp);

                                return(new Error(
                                           code: Errors.InvalidRewardForRedeem,
                                           description: $"Invalid refund timestamp in initiated event. Expected value is {refundTimeStamp}, actual is {detectedRefundTimestamp}"));
                            }

                            return(true);   // todo: check also token contract transfers
                        }
                    }

                    if (tx.BlockInfo?.BlockTime == null)
                    {
                        continue;
                    }

                    var blockTimeUtc = tx.BlockInfo.BlockTime.Value.ToUniversalTime();
                    var swapTimeUtc  = swap.TimeStamp.ToUniversalTime();

                    if (blockTimeUtc < swapTimeUtc)
                    {
                        return(false);
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e, "Tezos token swap initiated control task error");

                return(new Error(Errors.InternalError, e.Message));
            }

            return(false);
        }