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)); }
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())); }
/// <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); }
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); }
/// <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))); }
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; } }
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; } }
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); }
/// <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(); } }
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); } }
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; } }