public async Task <string> SendTransactionAsync(TransactionInput transactionInput)
        {
            if (transactionInput == null)
            {
                throw new ArgumentNullException(nameof(transactionInput));
            }

            if (string.IsNullOrEmpty(transactionInput.From))
            {
                throw new Exception("From address is null of empty");
            }

            if (string.IsNullOrEmpty(transactionInput.To))
            {
                throw new Exception("Cannot deploy a new contract via the GSN");
            }

            var value = transactionInput.Value.HexValue;

            if (value != "0" && value != "0x0")
            {
                throw new Exception("Cannot send funds via the GSN");
            }

            var relayHubAddress = await _relayHubManager
                                  .GetHubAddressAsync(_contractAddress)
                                  .ConfigureAwait(false);

            await ValidateRecipientBalance(
                relayHubAddress,
                transactionInput.To,
                transactionInput.Gas.Value,
                transactionInput.GasPrice.Value,
                new BigInteger(0))
            .ConfigureAwait(false);

            var relays = await _relayHubManager
                         .GetRelaysAsync(relayHubAddress, _relayPolicy)
                         .ConfigureAwait(false);

            foreach (var lazyRelay in relays)
            {
                var relay = lazyRelay.Value;

                if (!relay.Ready ||
                    relay.MinGasPrice.CompareTo(transactionInput.GasPrice.Value) == 1)
                {
                    continue;
                }

                try
                {
                    var hash = await RelayTransaction(relay, transactionInput, relayHubAddress)
                               .ConfigureAwait(false);

                    await _relayPolicy.GraceAsync(relay).ConfigureAwait(false);

                    return(hash);
                }
                catch
                {
                    await _relayPolicy.PenalizeAsync(relay).ConfigureAwait(false);

                    continue;
                }
            }

            return(null);
        }
Exemple #2
0
        public async Task <string> Relay(
            TransactionInput transaction,
            Func <Relay, TransactionInput, string, Task <string> > relayFunc)
        {
            var relayHubAddress = await _relayHubManager
                                  .GetHubAddressAsync(transaction.To)
                                  .ConfigureAwait(false);

            await _balanceValidator.Validate(
                relayHubAddress,
                transaction.To,
                transaction.Gas.Value,
                transaction.GasPrice.Value,
                new BigInteger(0))
            .ConfigureAwait(false);

            var relays = await _relayHubManager
                         .GetRelaysAsync(relayHubAddress, _relayPolicy)
                         .ConfigureAwait(false);

            BigInteger gasPrice    = transaction.GasPrice;
            BigInteger minGasPrice = default;

            foreach (var lazyRelay in relays)
            {
                var relay = lazyRelay.Value;

                if (minGasPrice == default)
                {
                    minGasPrice = relay.MinGasPrice;
                }

                if (!relay.Ready ||
                    relay.MinGasPrice.CompareTo(gasPrice) == 1)
                {
                    minGasPrice = BigInteger.Min(minGasPrice, relay.MinGasPrice);
                    continue;
                }

                try
                {
                    var nonce = await _relayHubManager
                                .GetNonceAsync(relayHubAddress, transaction.From)
                                .ConfigureAwait(false);

                    transaction.Nonce = new HexBigInteger(nonce);

                    var hash = await relayFunc(relay, transaction, relayHubAddress)
                               .ConfigureAwait(false);

                    await _relayPolicy.GraceAsync(relay).ConfigureAwait(false);

                    return(hash);
                }
                catch
                {
                    await _relayPolicy.PenalizeAsync(relay).ConfigureAwait(false);

                    continue;
                }
            }


            var message = minGasPrice.CompareTo(gasPrice) == 1 ?
                          $"Relay not found. Minimum relay gas price is {minGasPrice}, provided {gasPrice}" :
                          null;

            throw new GSNRelayNotFoundException(message);
        }