示例#1
0
        public string SignTransaction(Account account, TransactionInput transaction, BigInteger?chainId = null)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException(nameof(transaction));
            }
            if (string.IsNullOrWhiteSpace(transaction.From))
            {
                transaction.From = account.Address;
            }
            else if (!transaction.From.IsTheSameAddress(account.Address))
            {
                throw new Exception("Invalid account used for signing, does not match the transaction input");
            }

            var nonce = transaction.Nonce;

            if (nonce == null)
            {
                throw new ArgumentNullException(nameof(transaction), "Transaction nonce has not been set");
            }

            var gasPrice = transaction.GasPrice;
            var gasLimit = transaction.Gas;

            var value = transaction.Value ?? new HexBigInteger(0);

            string signedTransaction = "";

            if (true)
            {
                signedTransaction = _transactionSigner.SignTransaction(account.PrivateKey,
                                                                       transaction.To,
                                                                       value.Value, nonce,
                                                                       gasPrice.Value, gasLimit.Value, transaction.Data, transaction.EpochNumber, transaction.Nonce, chainId);

                //var actualLength = signedTransaction.Length;
                //if (targetLength != actualLength)
                //{
                //    //ERROR
                //}
            }
            else
            {
                signedTransaction = _transactionSigner.SignTransaction(account.PrivateKey, chainId.Value,
                                                                       transaction.To,
                                                                       value.Value, nonce,
                                                                       gasPrice.Value, gasLimit.Value, transaction.Data);
            }

            return(signedTransaction);
        }
        private async Task <string> SignAndSendTransactionAsync(TransactionInput transaction)
        {
            if (Client == null)
            {
                throw new NullReferenceException("Client not configured");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException(nameof(transaction));
            }
            if (transaction.From.EnsureHexPrefix().ToLower() != Account.Address.EnsureHexPrefix().ToLower())
            {
                throw new Exception("Invalid account used signing");
            }
            SetDefaultGasPriceAndCostIfNotSet(transaction);

            var ethSendTransaction = new EthSendRawTransaction(Client);
            var nonce = await GetNonceAsync(transaction);

            var gasPrice = transaction.GasPrice;
            var gasLimit = transaction.Gas;

            var value = transaction.Value;

            if (value == null)
            {
                value = new HexBigInteger(0);
            }

            string signedTransaction;

            if (ChainId == null)
            {
                signedTransaction = _transactionSigner.SignTransaction(((Account)Account).PrivateKey,
                                                                       transaction.To,
                                                                       value.Value, nonce,
                                                                       gasPrice.Value, gasLimit.Value, transaction.Data);
            }
            else
            {
                signedTransaction = _transactionSigner.SignTransaction(((Account)Account).PrivateKey, ChainId.Value,
                                                                       transaction.To,
                                                                       value.Value, nonce,
                                                                       gasPrice.Value, gasLimit.Value, transaction.Data);
            }

            return(await ethSendTransaction.SendRequestAsync(signedTransaction.EnsureHexPrefix()).ConfigureAwait(false));
        }
示例#3
0
        public string SignTransaction(TransactionInput transaction)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException(nameof(transaction));
            }
            if (transaction.From.EnsureHexPrefix().ToLower() != Account.Address.EnsureHexPrefix().ToLower())
            {
                throw new Exception("Invalid account used signing");
            }
            SetDefaultGasPriceAndCostIfNotSet(transaction);

            var nonce = transaction.Nonce;

            if (nonce == null)
            {
                throw new ArgumentNullException(nameof(transaction), "Transaction nonce has not been set");
            }

            var gasPrice = transaction.GasPrice;
            var gasLimit = transaction.Gas;

            var value = transaction.Value;

            if (value == null)
            {
                value = new HexBigInteger(0);
            }

            string signedTransaction;

            if (ChainId == null)
            {
                signedTransaction = _transactionSigner.SignTransaction(((Account)Account).PrivateKey,
                                                                       transaction.To,
                                                                       value.Value, nonce,
                                                                       gasPrice.Value, gasLimit.Value, transaction.Data);
            }
            else
            {
                signedTransaction = _transactionSigner.SignTransaction(((Account)Account).PrivateKey, ChainId.Value,
                                                                       transaction.To,
                                                                       value.Value, nonce,
                                                                       gasPrice.Value, gasLimit.Value, transaction.Data);
            }

            return(signedTransaction);
        }
        public override async Task <JObject> ExecuteAsync(IClient client)
        {
            var senderAddress = "0x12890d2cce102216644c59daE5baed380d84830c";
            var privateKey    = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";
            var abi           =
                @"[{""constant"":false,""inputs"":[{""name"":""val"",""type"":""int256""}],""name"":""multiply"",""outputs"":[{""name"":""d"",""type"":""int256""}],""type"":""function""},{""inputs"":[{""name"":""multiplier"",""type"":""int256""}],""type"":""constructor""}]";
            var byteCode =
                "0x60606040526040516020806052833950608060405251600081905550602b8060276000396000f3606060405260e060020a60003504631df4f1448114601a575b005b600054600435026060908152602090f3";

            var multiplier = 7;

            var web3 = new Web3.Web3(new Account(privateKey), client);

            var receipt = await
                          web3.Eth.DeployContract.SendRequestAndWaitForReceiptAsync(abi, byteCode, senderAddress,
                                                                                    new HexBigInteger(900000), null, multiplier);

            var contract = web3.Eth.GetContract(abi, receipt.ContractAddress);

            var function         = contract.GetFunction("multiply");
            var transactionInput = function.CreateTransactionInput(senderAddress, null, null, 7);
            var signer           = new TransactionSigner();
            var nonce            = await web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(senderAddress);

            var signedTransaction = signer.SignTransaction(privateKey, transactionInput.To, 0, nonce.Value,
                                                           Transaction.DEFAULT_GAS_PRICE, 900000,
                                                           transactionInput.Data);

            var traceTransaction = new TraceRawTransaction(client);

            return(await traceTransaction.SendRequestAsync(signedTransaction.EnsureHexPrefix(),
                                                           new[] { TraceType.vmTrace }, BlockParameter.CreateLatest()));
        }
示例#5
0
        /// <summary>
        /// Sends a message to an ethereum smart contract with the intent to change a part of the contract on the blockchain.
        /// </summary>
        /// <typeparam name="TFunc"> The type of the function to execute. </typeparam>
        /// <param name="function"> The function to execute. </param>
        /// <param name="privateKey"> The private key of the address executing the contract function. </param>
        /// <param name="contractAddress"> The address of the contract which will process the message. </param>
        /// <param name="gasPrice"> The gas price (in wei) to use to send the transaction. </param>
        /// <param name="gasLimit"> The gas limit (in wei) to use to send the transaction. </param>
        /// <param name="value"> The amount of eth (in wei) to send with the transaction. </param>
        /// <returns> Task which returns the TransactionPoller which will await the transaction result. </returns>
        public static async Task <TransactionPoller> SendContractMessage <TFunc>(
            TFunc function,
            string privateKey,
            string contractAddress,
            BigInteger gasPrice,
            BigInteger gasLimit,
            BigInteger value) where TFunc : FunctionMessage, new()
        {
            EthECKey ethECKey = new EthECKey(privateKey);

            function.SetDefaultFromAddressIfNotSet(ethECKey.GetPublicAddress());
            function.Gas      = gasLimit;
            function.GasPrice = gasPrice;

            InMemoryNonceService nonceService = new InMemoryNonceService(ethECKey.GetPublicAddress(), NetworkProvider.GetWeb3().Client);

            TransactionSigner signer       = new TransactionSigner();
            string            signedTxData = signer.SignTransaction(
                privateKey,
                NetworkProvider.GetActiveNetworkChain(),
                contractAddress,
                value,
                (await nonceService.GetNextNonceAsync()).Value,
                gasPrice,
                gasLimit,
                function.CreateTransactionInput(contractAddress).Data);

            EthSendRawTransaction rawTransaction = new EthSendRawTransaction(NetworkProvider.GetWeb3().Client);

            return(new TransactionPoller(await rawTransaction.SendRequestAsync(signedTxData)));
        }
        public static async Task <string> Meacoin_Offline_Transaction(string privateKey, string _addressFrom, string _addressTo, int amount)
        {
            //get the function
            var function = meaToken.Contract.GetFunction("transfer");
            //get the data
            var data = function.GetData(new object[] { _addressTo, new BigInteger(amount) });
            //nonce
            var txCount = await web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(_addressFrom, BlockParameter.CreatePending());

            //signing the transaction
            var encoded = transactionSigner.SignTransaction(privateKey, meaToken.Contract.Address, 0, txCount.Value, 1000000000000L, 900000, data);
            //transaction hash
            var txId = await web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + encoded);

            //verify transaction
            var status = transactionSigner.VerifyTransaction(encoded);

            Console.WriteLine("Status : " + status);
            //returning transaction hash
            return(txId);
        }
示例#7
0
        public string Sign(string privkey, SmartMarket.Models.API.Transaction tx)
        {
            var signed = signer.SignTransaction(
                privateKey: privkey,
                to: tx.To,
                data: tx.Data,
                nonce: tx.Nonce,
                gasLimit: tx.GasLimit,
                gasPrice: tx.GasPrice,
                amount: tx.Amount
                );

            return("0x" + signed);
        }
        private async Task <string> SignAndSendTransaction(TransactionInput transaction)
        {
            if (Client == null)
            {
                throw new NullReferenceException("Client not configured");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException(nameof(transaction));
            }
            if (transaction.From.EnsureHexPrefix().ToLower() != _account.EnsureHexPrefix().ToLower())
            {
                throw new Exception("Invalid account used signing");
            }
            var ethSendTransaction = new EthSendRawTransaction(Client);
            var nonce = await GetNonceAsync(transaction);

            var gasPrice = transaction.GasPrice;

            if (gasPrice == null)
            {
                gasPrice = new HexBigInteger(Transaction.DEFAULT_GAS_PRICE);
            }

            var gasLimit = transaction.Gas;

            if (gasLimit == null)
            {
                gasLimit = new HexBigInteger(Transaction.DEFAULT_GAS_LIMIT);
            }

            var value = transaction.Value;

            if (value == null)
            {
                value = new HexBigInteger(0);
            }

            var signedTransaction = _transactionSigner.SignTransaction(_privateKey, transaction.To, value.Value, nonce,
                                                                       gasPrice.Value, gasLimit.Value, transaction.Data);

            return(await ethSendTransaction.SendRequestAsync(signedTransaction.EnsureHexPrefix()).ConfigureAwait(false));
        }
    public IEnumerator SendRawTransaction()
    {
        //unpack first
        string json = File.ReadAllText(@"ks");

        KeyStoreService keystore = new KeyStoreService();

        byte[] privateKey;
        try
        {
            privateKey = keystore.DecryptKeyStoreFromJson("", json);  //live
        }
        catch (DecryptionException exc)
        {
            Debug.Log("password invalid");
            throw exc;
        }


        int nonce = 1; // GetPending transaction count + 1;

        TransactionSigner signer = new TransactionSigner();
        string            signedTransactionData = signer.SignTransaction(privateKey, m_addr,
                                                                         new BigInteger(0.002f * m_ether),
                                                                         new BigInteger(nonce),
                                                                         new BigInteger(20L * m_gwei),
                                                                         new BigInteger(21000));

        Assert.IsTrue(signer.VerifyTransaction(signedTransactionData));

        Debug.Log(signer.GetSenderAddress(signedTransactionData));

        EthSendRawTransactionUnityRequest req = new EthSendRawTransactionUnityRequest(m_endpoint);

        yield return(req.SendRequest(signedTransactionData));

        Debug.Log(req.Result);
    }
示例#10
0
        /// <summary>
        /// Sends a given amount of ether to an address.
        /// </summary>
        /// <param name="privateKey"> The private key of the address which is sending the ether. </param>
        /// <param name="addressTo"> The address the ether is being sent to. </param>
        /// <param name="amount"> The amount of ether being sent, in eth. (not wei) </param>
        /// <param name="gasPrice"> The gas price (in wei) to use to send the transaction. </param>
        /// <param name="gasLimit"> The gas limit (in wei) to use to send the transaction. </param>
        /// <returns> Task which returns the TransactionPoller which will await the transaction result. </returns>
        public static async Task <TransactionPoller> SendEther(string privateKey, string addressTo, decimal amount, BigInteger gasPrice, BigInteger gasLimit)
        {
            BigInteger value = SolidityUtils.ConvertToUInt(amount, 18);

            EthECKey ethECKey = new EthECKey(privateKey);

            InMemoryNonceService nonceService = new InMemoryNonceService(ethECKey.GetPublicAddress(), NetworkProvider.GetWeb3().Client);

            TransactionSigner signer       = new TransactionSigner();
            string            signedTxData = signer.SignTransaction(
                privateKey,
                NetworkProvider.GetActiveNetworkChain(),
                addressTo,
                value,
                (await nonceService.GetNextNonceAsync()).Value,
                gasPrice,
                gasLimit,
                string.Empty);

            EthSendRawTransaction rawTransaction = new EthSendRawTransaction(NetworkProvider.GetWeb3().Client);

            return(new TransactionPoller(await rawTransaction.SendRequestAsync(signedTxData)));
        }
示例#11
0
        private async Task SendRawTransaction(TimestampDao timestamp, IWeb3 web3, string secretKey, double estimateGasPrice, EthSettings ethSettings)
        {
            if (!Enum.TryParse(ethSettings.Network, true, out Chain networkChain))
            {
                networkChain = Chain.MainNet;
                _logger.Warning($"Unable to parse '{ethSettings.Network}' to type '{typeof(Chain)}', so setting default to '{networkChain}'.");
            }

            bool proofVerified = _ethHelper.VerifyStamp(timestamp);

            if (!proofVerified)
            {
                var message = $"Unable to verify the signature '{timestamp.Signature}'.";
                _logger.Warning(message);
                throw new TimestampException(message);
            }

            string proofStr = JsonConvert.SerializeObject(
                new
            {
                file      = timestamp.FileName,
                hash      = timestamp.FileHash,
                publicKey = timestamp.PublicKey,
                signature = timestamp.Signature
            });

            var txData = HexStringUTF8ConvertorExtensions.ToHexUTF8(proofStr);

            var fromAddress = web3.TransactionManager.Account.Address;
            var futureNonce = await web3.TransactionManager.Account.NonceService.GetNextNonceAsync();

            _logger.Information($"Signed transaction on chain: {networkChain}, To: {ethSettings.ToAddress}, Nonce: {futureNonce}, GasPrice: {estimateGasPrice}, From Address :{fromAddress}");

            var offlineTransactionSigner = new TransactionSigner();
            var encoded = offlineTransactionSigner.SignTransaction(
                secretKey,
                networkChain,
                ethSettings.ToAddress,
                Web3.Convert.ToWei(0, UnitConversion.EthUnit.Gwei),
                futureNonce,
                Web3.Convert.ToWei(estimateGasPrice, UnitConversion.EthUnit.Gwei),
                new BigInteger(100000),
                txData);

            var verified = offlineTransactionSigner.VerifyTransaction(encoded);

            if (!verified)
            {
                var message = $"Unable to verify the transaction for data '{txData}'.";
                _logger.Error(message);
                throw new TimestampException(message);
            }

            try
            {
                var txId = await web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + encoded);

                timestamp.Address       = fromAddress;
                timestamp.Nonce         = (long)futureNonce.Value;
                timestamp.TransactionId = txId;
                timestamp.Network       = networkChain.ToString();
                timestamp.BlockNumber   = -1;

                if (string.IsNullOrWhiteSpace(txId))
                {
                    timestamp.Status = TimestampState.Failed;
                    var message = $"Transaction failed for an user '{timestamp.UserId}' with file name '{timestamp.FileName}'.";
                    _logger.Error(message);
                }
            }
            catch (RpcResponseException ex)
            {
                await web3.TransactionManager.Account.NonceService.ResetNonce();

                if (ex.Message.Contains("nonce too low", StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new RpcClientNonceException(ex.Message);
                }
                else if (ex.Message.Contains("transaction underpriced", StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new RpcClientUnderpricedException(ex.Message);
                }

                throw;
            }
        }
示例#12
0
        public IEnumerator SignAndSendTransaction(TransactionInput transactionInput)
        {
            if (transactionInput == null)
            {
                throw new ArgumentNullException("transactionInput");
            }

            var nonce = transactionInput.Nonce;

            if (nonce == null)
            {
                yield return(_transactionCountRequest.SendRequest(_account, Nethereum.RPC.Eth.DTOs.BlockParameter.CreateLatest()));

                if (_transactionCountRequest.Exception == null)
                {
                    nonce = _transactionCountRequest.Result;
                }
                else
                {
                    this.Exception = _transactionCountRequest.Exception;
                    yield break;
                }
            }

            var gasPrice = transactionInput.GasPrice;

            if (gasPrice == null)
            {
                gasPrice = new HexBigInteger(Transaction.DEFAULT_GAS_PRICE);
            }

            var gasLimit = transactionInput.Gas;

            if (gasLimit == null)
            {
                gasLimit = new HexBigInteger(Transaction.DEFAULT_GAS_LIMIT);
            }

            var value = transactionInput.Value;

            if (value == null)
            {
                value = new HexBigInteger(0);
            }

            var signedTransaction = _transactionSigner.SignTransaction(_privateKey, transactionInput.To, value.Value, nonce,
                                                                       gasPrice.Value, gasLimit.Value, transactionInput.Data);


            yield return(_ethSendTransactionRequest.SendRequest(signedTransaction));

            if (_ethSendTransactionRequest.Exception == null)
            {
                this.Result = _ethSendTransactionRequest.Result;
            }
            else
            {
                this.Exception = _ethSendTransactionRequest.Exception;
                yield break;
            }
        }
示例#13
0
        public bool Run(IConfiguration cfg, string signerHexStr, string[] command, out string msg)
        {
            Debug.Assert(command != null);
            Debug.Assert(command.Length > 0);
            if (command[0].Equals("verify"))
            {
                Debug.Assert(command.Length == 7);
                string txId = command[1];
                string destinationAddressString = command[2];
                string destinationAmount        = command[3];
                string sighash             = command[4];
                string sourceAddressString = command[5];
                string networkId           = command[6];

                // TODO disable confirmation count config for release build
                string confirmationsCount = cfg["confirmationsCount"];
                if (string.IsNullOrWhiteSpace(confirmationsCount))
                {
                    msg = "ethereum.confirmationsCount is not set";

                    return(false);
                }
                if (!int.TryParse(confirmationsCount, out int confirmationsExpected))
                {
                    msg = "ethereum.confirmationsCount is not an int";

                    return(false);
                }

                string rpcUrl = cfg["rpc"];
                if (string.IsNullOrWhiteSpace(rpcUrl))
                {
                    msg = "ethereum.rpc is not set";

                    return(false);
                }

                var web3 = new Nethereum.Web3.Web3(rpcUrl);

                var tx            = web3.Eth.Transactions.GetTransactionByHash.SendRequestAsync(txId).Result;
                int confirmations = 0;
                if (tx.BlockNumber != null)
                {
                    var blockNumber = web3.Eth.Blocks.GetBlockNumber.SendRequestAsync().Result;
                    confirmations = (int)(blockNumber.Value - tx.BlockNumber.Value);
                }

                if (confirmations < confirmationsExpected)
                {
                    msg = "Invalid transaction: not enough confirmations";
                    return(false);
                }

                if (!sourceAddressString.Equals(tx.From, System.StringComparison.OrdinalIgnoreCase))
                {
                    msg = "Invalid transaction: wrong sourceAddressString";
                    return(false);
                }

                if (networkId.Equals("creditcoin"))
                {
                    string creditcoinContract = cfg["creditcoinContract"];

                    if (string.IsNullOrWhiteSpace(creditcoinContract))
                    {
                        msg = "ethereum.creditcoinContract is not set";

                        return(false);
                    }

                    string creditcoinContractAbi = cfg["creditcoinContractAbi"];
                    if (string.IsNullOrWhiteSpace(creditcoinContractAbi))
                    {
                        msg = "ethereum.creditcoinContractAbi is not set";

                        return(false);
                    }

                    var contract = web3.Eth.GetContract(creditcoinContractAbi, creditcoinContract);
                    var burn     = contract.GetFunction("exchange");
                    var inputs   = burn.DecodeInput(tx.Input);
                    Debug.Assert(inputs.Count == 2);
                    var value = inputs[0].Result.ToString();
                    if (destinationAmount != value)
                    {
                        msg = "Invalid transaction: wrong amount";
                        return(false);
                    }

                    var tag = inputs[1].Result.ToString();
                    if (!tag.Equals(sighash))
                    {
                        msg = "Invalid transaction: wrong sighash";
                        return(false);
                    }
                }
                else
                {
                    if (destinationAmount != tx.Value.Value.ToString())
                    {
                        msg = "Invalid transaction: wrong amount";
                        return(false);
                    }

                    if (tx.Input == null)
                    {
                        msg = "Invalid transaction: expecting data";
                        return(false);
                    }

                    if (!sighash.StartsWith("0x"))
                    {
                        sighash = "0x" + sighash;
                    }
                    if (!tx.Input.Equals(sighash, System.StringComparison.OrdinalIgnoreCase))
                    {
                        msg = "Invalid transaction: wrong sighash";
                        return(false);
                    }

                    if (!tx.To.Equals(destinationAddressString, System.StringComparison.OrdinalIgnoreCase))
                    {
                        msg = "Invalid transaction: wrong destinationAddressString";
                        return(false);
                    }
                }

                msg = null;
                return(true);
            }
            else if (command[0].Equals("unlock"))
            {
                var ccSigner  = new Signer(RpcHelper.HexToBytes(signerHexStr));
                var txBuilder = new TxBuilder(ccSigner);

                Debug.Assert(command.Length == 5);
                string kind = command[1];
                string addressFromString = command[2];

                HttpClient httpClient = new HttpClient();

                string txFrom;
                string amountString;
                string feeString;
                string addressToString;
                string networkId;

                string ccCommand;

                if (kind.Equals("funds"))
                {
                    string dealOrderId            = command[3];
                    string addressToUnlockFundsTo = command[4];

                    var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{dealOrderId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var dealOrder = DealOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{dealOrder.AskOrderId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var askOrder = AskOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{askOrder.TransferId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var transfer = Transfer.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{addressToUnlockFundsTo}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var address = Address.Parser.ParseFrom(protobuf);
                    if (!askOrder.Sighash.Equals(address.Sighash))
                    {
                        msg = "The address doesn't match the ask order";
                        return(false);
                    }
                    txFrom          = transfer.Txid;
                    amountString    = transfer.Amount;
                    feeString       = transfer.Fee;
                    addressToString = address.Address_;
                    networkId       = transfer.Network;
                    ccCommand       = "UnlockFunds";
                }
                else if (kind.Equals("collateral"))
                {
                    string repaymentOrderId             = command[3];
                    string addressToUnlockCollateralsTo = command[4];

                    var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{repaymentOrderId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var repaymentOrder = RepaymentOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{repaymentOrder.DealId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var dealOrder = DealOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{dealOrder.AskOrderId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var askOrder = AskOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{askOrder.TransferId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var transfer = Transfer.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{addressToUnlockCollateralsTo}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var address = Address.Parser.ParseFrom(protobuf);
                    if (!askOrder.Sighash.Equals(address.Sighash))
                    {
                        msg = "The address doesn't match the ask order";
                        return(false);
                    }
                    txFrom          = transfer.Txid;
                    amountString    = transfer.Amount;
                    feeString       = transfer.Fee;
                    addressToString = address.Address_;
                    networkId       = transfer.Network;
                    ccCommand       = "UnlockCollateral";
                }
                else
                {
                    msg = "unknown unlock kind";
                    return(false);
                }

                string secret = cfg["secret"];
                if (string.IsNullOrWhiteSpace(secret))
                {
                    msg = "ethereum.secret is not set";
                    return(false);
                }
                var ethereumPrivateKey = secret;

                // TODO disable confirmation count config for release build
                string confirmationsCount = cfg["confirmationsCount"];
                if (string.IsNullOrWhiteSpace(confirmationsCount))
                {
                    msg = "ethereum.confirmationsCount is not set";
                    return(false);
                }
                if (!int.TryParse(confirmationsCount, out int confirmationsExpected))
                {
                    msg = "ethereum.confirmationsCount is not an int";
                    return(false);
                }

                string rpcUrl = cfg["rpc"];
                if (string.IsNullOrWhiteSpace(rpcUrl))
                {
                    msg = "ethereum.rpc is not set";
                    return(false);
                }

                BigInteger fee;
                if (!BigInteger.TryParse(feeString, out fee))
                {
                    msg = "Invalid progress data";
                    return(false);
                }

                var web3 = new Nethereum.Web3.Web3(rpcUrl);

                BigInteger transferAmount;
                if (!BigInteger.TryParse(amountString, out transferAmount) || transferAmount <= 0)
                {
                    msg = "Invalid amount";
                    return(false);
                }

                string sourceAddress = EthECKey.GetPublicAddress(ethereumPrivateKey);

                if (!sourceAddress.Equals(addressFromString, StringComparison.OrdinalIgnoreCase))
                {
                    msg = "The deal is for a different client";
                    return(false);
                }

                var txCount = web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(sourceAddress).Result;
                TransactionSigner signer = new TransactionSigner();
                var    gasLimit          = web3.Eth.Transactions.EstimateGas.SendRequestAsync(new Nethereum.RPC.Eth.DTOs.CallInput(string.Empty, addressToString, new Nethereum.Hex.HexTypes.HexBigInteger(transferAmount))).Result;
                var    gasPrice          = web3.Eth.GasPrice.SendRequestAsync().Result;
                string txRaw             = signer.SignTransaction(ethereumPrivateKey, addressToString, transferAmount + fee, txCount, gasPrice, gasLimit, string.Empty);
                string payTxId           = web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + txRaw).Result;

                while (true)
                {
                    var receipt = web3.Eth.TransactionManager.TransactionReceiptService.PollForReceiptAsync(payTxId).Result;
                    if (receipt.BlockNumber != null)
                    {
                        var blockNumber = web3.Eth.Blocks.GetBlockNumber.SendRequestAsync().Result;
                        if (blockNumber.Value - receipt.BlockNumber.Value >= confirmationsExpected)
                        {
                            break;
                        }
                    }
                    Thread.Sleep(1000);
                }

                command = new string[] { ccCommand, command[3], command[4] };
                var tx = txBuilder.BuildTx(command, out msg);
                Debug.Assert(tx != null);
                Debug.Assert(msg == null);
                var content = new ByteArrayContent(tx);
                content.Headers.Add("Content-Type", "application/octet-stream");
                msg = RpcHelper.CompleteBatch(httpClient, $"{creditcoinUrl}/batches", content);
            }

            msg = "Unknown command: " + command[0];
            return(false);
        }
示例#14
0
        /// <summary>
        /// TODO: This should be made in to a unit test but it's annoying to add the UI for a unit test as the Trezor requires human intervention for the pin
        /// </summary>
        /// <returns></returns>
        private async static Task Go()
        {
            try
            {
                using (var trezorHid = await Connect())
                {
                    using (var trezorManager = new TrezorManager(GetPin, trezorHid))
                    {
                        await trezorManager.InitializeAsync();

                        var tasks = new List <Task>();

                        for (var i = 0; i < 50; i++)
                        {
                            tasks.Add(DoGetAddress(trezorManager, i));
                        }

                        await Task.WhenAll(tasks);

                        for (var i = 0; i < 50; i++)
                        {
                            var address = await GetAddress(trezorManager, i);

                            Console.WriteLine($"Index: {i} (No change) - Address: {address}");

                            if (address != _Addresses[i])
                            {
                                throw new Exception("The ordering got messed up");
                            }
                        }

                        var ethAddress = await trezorManager.GetAddressAsync("ETH", 60, false, 0, false, AddressType.Ethereum);

                        Console.WriteLine($"First ETH address: {ethAddress}");

                        //This fails with 'Safety check failed'
                        //See https://github.com/trezor/trezor-mcu/issues/143
                        //https://github.com/trezor/trezor-mcu/blob/master/firmware/ethereum.c
                        //Which values here need leading zeros? Is Unicode the correct encoding?



                        var message = new EthereumSignMessage
                        {
                            AddressNs = KeyPath.Parse("m/44'/60'/0'/0/0").Indexes,
                            Message   = Encoding.UTF8.GetBytes("Hello").ToHex().ToHexBytes()
                        };

                        var messageSignature = await trezorManager.SendMessageAsync <EthereumMessageSignature, EthereumSignMessage>(message);

                        //Same as first address
                        Console.WriteLine(ToHex(messageSignature.Address));

                        var signer            = new Nethereum.Signer.EthereumMessageSigner();
                        var messageSignature2 = signer.EncodeUTF8AndSign("Hello2", new EthECKey(
                                                                             "0x2e14c29aaecd1b7c681154d41f50c4bb8b6e4299a431960ed9e860e39cae6d29"));
                        // var recoveredAddress = signer.EncodeUTF8AndEcRecover("Hello", messageSignature.Signature.ToHex());
                        //Same as recovered address
                        //Console.WriteLine(recoveredAddress);

                        //var txMessage = new EthereumSignTx
                        //{
                        //    Nonce = 1.ToHexBytes(),
                        //    GasPrice = 1000000000.ToHexBytes(),
                        //    GasLimit = 21000.ToHexBytes(),
                        //    To = "689c56aef474df92d44a1b70850f808488f9769c".ToHexBytes(),
                        //    Value = 1000000000000000.ToHexBytes(),
                        //    //Value = "de0b6b3a7640000".ToHexBytes(),
                        //    AddressNs = KeyPath.Parse("m/44'/60'/0'/0/0").Indexes,
                        //    ChainId = 1
                        //};



                        var txMessage = new EthereumSignTx
                        {
                            Nonce    = 10.ToBytesForRLPEncoding().ToHex().ToHexBytes(),
                            GasPrice = 10.ToBytesForRLPEncoding().ToHex().ToHexBytes(),
                            GasLimit = 21000.ToBytesForRLPEncoding().ToHex().ToHexBytes(),
                            To       = "689c56aef474df92d44a1b70850f808488f9769c".ToHexBytes(),
                            Value    = BigInteger.Parse("10000000000000000000").ToBytesForRLPEncoding().ToHex().ToHexBytes(),
                            //Value = "de0b6b3a7640000".ToHexBytes(),
                            AddressNs = KeyPath.Parse("m/44'/60'/0'/0/0").Indexes,
                            //ChainId = 1
                        };
                        var transaction = await trezorManager.SendMessageAsync <EthereumTxRequest, EthereumSignTx>(txMessage);

                        var transactionSigner = new TransactionSigner();
                        var sigature2         = transactionSigner.SignTransaction("0x2e14c29aaecd1b7c681154d41f50c4bb8b6e4299a431960ed9e860e39cae6d29",
                                                                                  "0x689c56aef474df92d44a1b70850f808488f9769c", 10, 10, 10, 21000);
                        var transactionRecovered = new Transaction(sigature2.HexToByteArray());
                        //var transactionChainId = new TransactionChainId(sigature2.HexToByteArray(), 1);


                        Console.WriteLine("All good");

                        Console.ReadLine();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Console.ReadLine();
            }
        }
示例#15
0
        public bool Run(bool txid, IConfiguration cfg, HttpClient httpClient, ITxBuilder txBuilder, Dictionary <string, string> settings, string progressId, string pluginsFolder, string url, string[] command, out bool inProgress, out string msg)
        {
            Debug.Assert(command != null);
            if (command.Length < 2)
            {
                inProgress = false;
                msg        = "invalid parameter count";
                return(false);
            }

            bool erc20 = command[0].Equals("collectCoins", StringComparison.OrdinalIgnoreCase);

            if (erc20 || command[0].Equals("registerTransfer", StringComparison.OrdinalIgnoreCase))
            {
                // ethereum RegisterTransfer gain orderId
                // ethereum CollectCoins amount

                string progress = Path.Combine(pluginsFolder, $"{name}_progress{progressId}.txt");

                inProgress = false;

                if (erc20 && command.Length != 2 || !erc20 && command.Length != 3)
                {
                    msg = "invalid parameter count";
                    return(false);
                }

                string gainString   = "0";
                string orderId      = null;
                string amountString = null;
                if (erc20)
                {
                    amountString = command[1];
                }
                else
                {
                    gainString = command[1];
                    orderId    = command[2];
                }

                string secret = cfg["secret"];
                if (string.IsNullOrWhiteSpace(secret))
                {
                    msg = "ethereum.secret is not set";
                    return(false);
                }
                var ethereumPrivateKey = secret;

#if DEBUG
                string confirmationsCount = cfg["confirmationsCount"];
                if (int.TryParse(confirmationsCount, out int parsedCount))
                {
                    mConfirmationsExpected = parsedCount;
                }
#endif

                string rpcUrl = cfg["rpc"];
                if (string.IsNullOrWhiteSpace(rpcUrl))
                {
                    msg = "ethereum.rpc is not set";
                    return(false);
                }

                string ethSrcAddress = EthECKey.GetPublicAddress(ethereumPrivateKey);
                var    web3          = new Nethereum.Web3.Web3(rpcUrl);

                string srcAddressId = null;
                string dstAddressId = null;
                if (!erc20)
                {
                    var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{url}/state/{orderId}", out msg);
                    if (protobuf == null)
                    {
                        msg = "failed to extract address data through RPC";
                        return(false);
                    }
                    if (orderId.StartsWith(RpcHelper.creditCoinNamespace + RpcHelper.dealOrderPrefix))
                    {
                        var dealOrder = DealOrder.Parser.ParseFrom(protobuf);
                        if (gainString.Equals("0"))
                        {
                            srcAddressId = dealOrder.SrcAddress;
                            dstAddressId = dealOrder.DstAddress;
                        }
                        else
                        {
                            dstAddressId = dealOrder.SrcAddress;
                            srcAddressId = dealOrder.DstAddress;
                        }
                        amountString = dealOrder.Amount;
                    }
                    else if (orderId.StartsWith(RpcHelper.creditCoinNamespace + RpcHelper.repaymentOrderPrefix))
                    {
                        var repaymentOrder = RepaymentOrder.Parser.ParseFrom(protobuf);
                        if (gainString.Equals("0"))
                        {
                            srcAddressId = repaymentOrder.SrcAddress;
                            dstAddressId = repaymentOrder.DstAddress;
                        }
                        else
                        {
                            dstAddressId = repaymentOrder.SrcAddress;
                            srcAddressId = repaymentOrder.DstAddress;
                        }
                        amountString = repaymentOrder.Amount;
                    }
                    else
                    {
                        msg = "unexpected referred order";
                        return(false);
                    }
                }

                string payTxId;
                if (File.Exists(progress))
                {
                    Console.WriteLine("Found unfinished action, retrying...");
                    payTxId = File.ReadAllText(progress);
                }
                else
                {
                    string ethDstAddress = null;
                    if (!erc20)
                    {
                        var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{url}/state/{srcAddressId}", out msg);
                        if (protobuf == null)
                        {
                            msg = "failed to extract address data through RPC";
                            return(false);
                        }
                        var srcAddress = Address.Parser.ParseFrom(protobuf);

                        protobuf = RpcHelper.ReadProtobuf(httpClient, $"{url}/state/{dstAddressId}", out msg);
                        if (protobuf == null)
                        {
                            msg = "failed to extract address data through RPC";
                            return(false);
                        }
                        Address dstAddress = Address.Parser.ParseFrom(protobuf);

                        if (!srcAddress.Blockchain.Equals(name) || !dstAddress.Blockchain.Equals(name))
                        {
                            msg = $"ethereum RegisterTransfer can only transfer ether.\nThis source is registered for {srcAddress.Blockchain} and destination for {dstAddress.Blockchain}";
                            return(false);
                        }
                        ethDstAddress = dstAddress.Value;

                        if (!ethSrcAddress.Equals(srcAddress.Value, StringComparison.OrdinalIgnoreCase))
                        {
                            msg = "The deal is for a different client";
                            return(false);
                        }
                    }

                    BigInteger transferAmount;
                    if (!BigInteger.TryParse(amountString, out transferAmount) || transferAmount <= 0)
                    {
                        msg = "Invalid amount";
                        return(false);
                    }
                    BigInteger gain;
                    if (!BigInteger.TryParse(gainString, out gain))
                    {
                        msg = "Invalid amount";
                        return(false);
                    }
                    transferAmount = transferAmount + gain;
                    if (transferAmount < 0)
                    {
                        msg = "Invalid amount";
                        return(false);
                    }

                    var txCount = web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(ethSrcAddress).Result;
                    TransactionSigner signer = new TransactionSigner();

                    HexBigInteger gasPrice;

                    string gasPriceInGweiString = cfg["gasPriceInGwei"];
                    if (int.TryParse(gasPriceInGweiString, out int gasPriceOverride))
                    {
                        gasPrice = new HexBigInteger(Nethereum.Util.UnitConversion.Convert.ToWei(gasPriceOverride, Nethereum.Util.UnitConversion.EthUnit.Gwei));
                    }
                    else
                    {
                        gasPrice = web3.Eth.GasPrice.SendRequestAsync().Result;
                    }
                    Console.WriteLine("gasPrice: " + gasPrice.Value.ToString());

                    string        to;
                    string        data;
                    BigInteger    amount;
                    HexBigInteger gasLimit;
                    if (erc20)
                    {
                        string creditcoinContract    = cfg["creditcoinContract"];
                        string creditcoinContractAbi = cfg["creditcoinContractAbi"];

                        to = creditcoinContract;

                        var contract      = web3.Eth.GetContract(creditcoinContractAbi, creditcoinContract);
                        var burn          = contract.GetFunction("exchange");
                        var functionInput = new object[] { transferAmount, txBuilder.getSighash() };
                        data     = burn.GetData(functionInput);
                        gasLimit = burn.EstimateGasAsync(functionInput).Result;
                        amount   = 0;
                    }
                    else
                    {
                        gasLimit = web3.Eth.Transactions.EstimateGas.SendRequestAsync(new Nethereum.RPC.Eth.DTOs.CallInput(orderId, ethDstAddress, new Nethereum.Hex.HexTypes.HexBigInteger(transferAmount))).Result;
                        Console.WriteLine("gasLimit: " + gasLimit.Value.ToString());

                        to     = ethDstAddress;
                        data   = orderId;
                        amount = transferAmount;
                    }

                    string txRaw = signer.SignTransaction(ethereumPrivateKey, to, amount, txCount, gasPrice, gasLimit, data);
                    payTxId = web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + txRaw).Result;
                    Console.WriteLine("Ethereum Transaction ID: " + payTxId);

                    File.WriteAllText(progress, $"{payTxId}");
                }

                inProgress = true;
                while (true)
                {
                    var receipt = web3.Eth.TransactionManager.TransactionReceiptService.PollForReceiptAsync(payTxId).Result;
                    if (receipt.BlockNumber != null)
                    {
                        var blockNumber = web3.Eth.Blocks.GetBlockNumber.SendRequestAsync().Result;
                        if (blockNumber.Value - receipt.BlockNumber.Value >= mConfirmationsExpected)
                        {
                            break;
                        }
                    }
                    Thread.Sleep(1000);
                }
                File.Delete(progress);
                inProgress = false;

                if (erc20)
                {
                    command = new string[] { command[0], ethSrcAddress, amountString, payTxId };
                }
                else
                {
                    command = new string[] { command[0], gainString, orderId, payTxId };
                }
                var tx = txBuilder.BuildTx(command, out msg);
                if (tx == null)
                {
                    return(false);
                }

                Debug.Assert(msg == null);

                var content = new ByteArrayContent(tx);
                content.Headers.Add("Content-Type", "application/octet-stream");

                msg = RpcHelper.CompleteBatch(httpClient, url, "batches", content, txid);

                return(true);
            }
            else
            {
                inProgress = false;
                msg        = "Unknown command: " + command[0];
                return(false);
            }
        }
示例#16
0
        public bool Run(IConfiguration cfg, HttpClient httpClient, ITxBuilder txBuilder, Dictionary <string, string> settings, string pluginsFolder, string url, string[] command, out bool inProgress, out string msg)
        {
            Debug.Assert(command != null);
            Debug.Assert(command.Length > 1);
            if (command[0].Equals("registerTransfer", StringComparison.OrdinalIgnoreCase))
            {
                // ethereum RegisterTransfer registeredSourceId amount

                string progress = Path.Combine(pluginsFolder, $"{name}_progress.txt");

                inProgress = false;

                Debug.Assert(command.Length == 3 || command.Length == 4);
                string registeredSourceId = command[1];
                string amountString       = command[2];
                bool   erc20 = command.Length == 4;

                string secret = cfg["secret"];
                if (string.IsNullOrWhiteSpace(secret))
                {
                    msg = "ethereum.secret is not set";

                    return(false);
                }
                var ethereumPrivateKey = secret;

                // TODO disable confirmation count config for release build
                string confirmationsCount = cfg["confirmationsCount"];
                if (string.IsNullOrWhiteSpace(confirmationsCount))
                {
                    msg = "ethereum.confirmationsCount is not set";

                    return(false);
                }
                if (!int.TryParse(confirmationsCount, out int confirmationsExpected))
                {
                    msg = "ethereum.confirmationsCount is not an int";

                    return(false);
                }

                string rpcUrl = cfg["rpc"];
                if (string.IsNullOrWhiteSpace(rpcUrl))
                {
                    msg = "ethereum.rpc is not set";

                    return(false);
                }

                var web3 = new Nethereum.Web3.Web3(rpcUrl);

                string     payTxId;
                BigInteger fee;
                if (File.Exists(progress))
                {
                    Console.WriteLine("Found unfinished action, retrying...");
                    var data = File.ReadAllText(progress).Split(':');
                    if (data.Length != 2)
                    {
                        msg = "Invalid progress data";
                        return(false);
                    }
                    payTxId = data[0];
                    if (!BigInteger.TryParse(data[1], out fee))
                    {
                        msg = "Invalid progress data";
                        return(false);
                    }
                }
                else
                {
                    var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{url}/state/{registeredSourceId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var address = Address.Parser.ParseFrom(protobuf);

                    string destinationAddress;
                    if (!settings.TryGetValue("sawtooth.escrow." + name, out destinationAddress))
                    {
                        msg = "Escrow not found for " + name;
                        return(false);
                    }

                    BigInteger transferAmount;
                    if (!BigInteger.TryParse(amountString, out transferAmount) || transferAmount <= 0)
                    {
                        msg = "Invalid amount";
                        return(false);
                    }

                    if (!address.Blockchain.Equals(name))
                    {
                        msg = $"ethereum RegisterTransfer can only transfer ether.\nThis source is registered for {address.Blockchain}";
                        return(false);
                    }

                    string sourceAddress = EthECKey.GetPublicAddress(ethereumPrivateKey);

                    if (!sourceAddress.Equals(address.Address_, StringComparison.OrdinalIgnoreCase))
                    {
                        msg = "The deal is for a different client";
                        return(false);
                    }

                    var txCount = web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(sourceAddress).Result;
                    TransactionSigner signer = new TransactionSigner();

                    // TODO maybe add a y/n choice for user to decline or configurable gas price override
                    var gasPrice = web3.Eth.GasPrice.SendRequestAsync().Result;
                    Console.WriteLine("gasPrice: " + gasPrice.Value.ToString());

                    string        to;
                    string        data;
                    BigInteger    amount;
                    HexBigInteger gasLimit;
                    if (erc20)
                    {
                        string creditcoinContract    = cfg["creditcoinContract"];
                        string creditcoinContractAbi = cfg["creditcoinContractAbi"];

                        to = creditcoinContract;

                        var contract      = web3.Eth.GetContract(creditcoinContractAbi, creditcoinContract);
                        var burn          = contract.GetFunction("exchange");
                        var functionInput = new object[] { transferAmount, address.Sighash };
                        data     = burn.GetData(functionInput);
                        gasLimit = burn.EstimateGasAsync(functionInput).Result;
                        fee      = gasLimit.Value * gasPrice.Value;
                        amount   = 0;
                    }
                    else
                    {
                        gasLimit = web3.Eth.Transactions.EstimateGas.SendRequestAsync(new Nethereum.RPC.Eth.DTOs.CallInput(registeredSourceId, destinationAddress, new Nethereum.Hex.HexTypes.HexBigInteger(transferAmount))).Result;
                        Console.WriteLine("gasLimit: " + gasLimit.Value.ToString());

                        fee    = gasLimit.Value * gasPrice.Value;
                        to     = destinationAddress;
                        data   = address.Sighash;
                        amount = transferAmount + fee;
                    }

                    string txRaw = signer.SignTransaction(ethereumPrivateKey, to, amount, txCount, gasPrice, gasLimit, data);
                    payTxId = web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + txRaw).Result;
                    Console.WriteLine("Ethereum Transaction ID: " + payTxId);

                    File.WriteAllText(progress, $"{payTxId}:{fee.ToString()}");
                }

                inProgress = true;
                while (true)
                {
                    var receipt = web3.Eth.TransactionManager.TransactionReceiptService.PollForReceiptAsync(payTxId).Result;
                    if (receipt.BlockNumber != null)
                    {
                        var blockNumber = web3.Eth.Blocks.GetBlockNumber.SendRequestAsync().Result;
                        if (blockNumber.Value - receipt.BlockNumber.Value >= confirmationsExpected)
                        {
                            break;
                        }
                    }
                    Thread.Sleep(1000);
                }
                File.Delete(progress);
                inProgress = false;

                command = new string[] { command[0], registeredSourceId, amountString, erc20 ? "0" : fee.ToString(), payTxId, erc20 ? "creditcoin" : "1" };
                var tx = txBuilder.BuildTx(command, out msg);
                if (tx == null)
                {
                    return(false);
                }

                Debug.Assert(msg == null);

                var content = new ByteArrayContent(tx);
                content.Headers.Add("Content-Type", "application/octet-stream");

                msg = RpcHelper.CompleteBatch(httpClient, $"{url}/batches", content);

                return(true);
            }
            else
            {
                inProgress = false;
                msg        = "Unknown command: " + command[0];
                return(false);
            }
        }
        public IEnumerator SignAndSendTransaction(TransactionInput transactionInput)
        {
            if (transactionInput == null)
            {
                throw new ArgumentNullException("transactionInput");
            }

            if (!string.IsNullOrEmpty(_signedTxData))
            {
                yield return(_ethSendTransactionRequest.SendRequest(_signedTxData));
            }
            else
            {
                if (transactionInput.Gas == null)
                {
                    if (EstimateGas)
                    {
                        yield return(_ethEstimateGasUnityRequest.SendRequest(transactionInput));

                        if (_ethEstimateGasUnityRequest.Exception == null)
                        {
                            var gas = _ethEstimateGasUnityRequest.Result;
                            transactionInput.Gas = gas;
                        }
                        else
                        {
                            this.Exception = _ethEstimateGasUnityRequest.Exception;
                            yield break;
                        }
                    }
                    else
                    {
                        transactionInput.Gas = new HexBigInteger(Transaction.DEFAULT_GAS_LIMIT);
                    }
                }

                if (transactionInput.GasPrice == null)
                {
                    yield return(_ethGasPriceUnityRequest.SendRequest());

                    if (_ethGasPriceUnityRequest.Exception == null)
                    {
                        var gasPrice = _ethGasPriceUnityRequest.Result;
                        transactionInput.GasPrice = gasPrice;
                    }
                    else
                    {
                        this.Exception = _ethGasPriceUnityRequest.Exception;
                        yield break;
                    }
                }

                var nonce = transactionInput.Nonce;

                if (nonce == null)
                {
                    yield return(_transactionCountRequest.SendRequest(_account.Address, Nethereum.RPC.Eth.DTOs.BlockParameter.CreateLatest()));

                    if (_transactionCountRequest.Exception == null)
                    {
                        nonce = _transactionCountRequest.Result;
                    }
                    else
                    {
                        this.Exception = _transactionCountRequest.Exception;
                        yield break;
                    }
                }

                if (string.IsNullOrEmpty(transactionInput.From))
                {
                    transactionInput.From = _account.Address;
                }

                var value = transactionInput.Value;
                if (value == null)
                {
                    value = new HexBigInteger(0);
                }

                var signedTransaction = _transactionSigner.SignTransaction(_account.PrivateKey, transactionInput.To, value.Value, nonce,
                                                                           transactionInput.GasPrice.Value, transactionInput.Gas.Value, transactionInput.Data);

                yield return(_ethSendTransactionRequest.SendRequest(signedTransaction));

                _account.PrivateKey.ClearBytes();
                GC.Collect();
            }

            if (_ethSendTransactionRequest.Exception == null)
            {
                Result = _ethSendTransactionRequest.Result;
            }
            else
            {
                Exception = _ethSendTransactionRequest.Exception;
            }
        }
        public IEnumerator SignAndSendTransaction(TransactionInput transactionInput)
        {
            if (transactionInput == null)
            {
                throw new ArgumentNullException("transactionInput");
            }

            if (string.IsNullOrEmpty(transactionInput.From))
            {
                transactionInput.From = _account;
            }

            if (!transactionInput.From.IsTheSameAddress(_account))
            {
                throw new Exception("Transaction Input From address does not match private keys address");
            }

            if (transactionInput.Gas == null)
            {
                if (EstimateGas)
                {
                    yield return(_ethEstimateGasUnityRequest.SendRequest(transactionInput));

                    if (_ethEstimateGasUnityRequest.Exception == null)
                    {
                        var gas = _ethEstimateGasUnityRequest.Result;
                        transactionInput.Gas = gas;
                    }
                    else
                    {
                        this.Exception = _ethEstimateGasUnityRequest.Exception;
                        yield break;
                    }
                }
                else
                {
                    transactionInput.Gas = new HexBigInteger(Transaction.DEFAULT_GAS_LIMIT);
                }
            }

            if (transactionInput.GasPrice == null)
            {
                yield return(_ethGasPriceUnityRequest.SendRequest());

                if (_ethGasPriceUnityRequest.Exception == null)
                {
                    var gasPrice = _ethGasPriceUnityRequest.Result;
                    transactionInput.GasPrice = gasPrice;
                }
                else
                {
                    this.Exception = _ethGasPriceUnityRequest.Exception;
                    yield break;
                }
            }

            var nonce = transactionInput.Nonce;

            if (nonce == null)
            {
                yield return(_transactionCountRequest.SendRequest(_account, Nethereum.RPC.Eth.DTOs.BlockParameter.CreateLatest()));

                if (_transactionCountRequest.Exception == null)
                {
                    nonce = _transactionCountRequest.Result;
                }
                else
                {
                    this.Exception = _transactionCountRequest.Exception;
                    yield break;
                }
            }

            var value = transactionInput.Value;

            if (value == null)
            {
                value = new HexBigInteger(0);
            }

            string signedTransaction;

            if (_chainId == null)
            {
                signedTransaction = _transactionSigner.SignTransaction(_privateKey, transactionInput.To, value.Value, nonce,
                                                                       transactionInput.GasPrice.Value, transactionInput.Gas.Value, transactionInput.Data);
            }
            else
            {
                signedTransaction = _transactionSigner.SignTransaction(_privateKey, _chainId.Value, transactionInput.To, value.Value, nonce,
                                                                       transactionInput.GasPrice.Value, transactionInput.Gas.Value, transactionInput.Data);
            }


            yield return(_ethSendTransactionRequest.SendRequest(signedTransaction));

            if (_ethSendTransactionRequest.Exception == null)
            {
                this.Result = _ethSendTransactionRequest.Result;
            }
            else
            {
                this.Exception = _ethSendTransactionRequest.Exception;
                yield break;
            }
        }