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())); }
public void Test_SignAndRecover() { var keyPair = new EcdsaKeyPair("0xD95D6DB65F3E2223703C5D8E205D98E3E6B470F067B0F94F6C6BF73D4301CE48" .HexToBytes().ToPrivateKey()); var signer = new TransactionSigner(); var abi = ContractEncoder.Encode("hello()"); var tx = new Transaction { To = ContractRegisterer.LatokenContract, Invocation = ByteString.CopyFrom(abi), From = keyPair.PublicKey.GetAddress(), GasPrice = 123123, /* TODO: "calculate gas limit for input size" */ GasLimit = GasMetering.DefaultBlockGasLimit, Nonce = 0, Value = new BigInteger(0).ToUInt256() }; // using old chain id var receipt = signer.Sign(tx, keyPair, false); Assert.AreEqual(receipt.Hash.ToHex(), receipt.FullHash(false).ToHex()); var publicKey = receipt.RecoverPublicKey(false); Assert.AreEqual(keyPair.PublicKey.ToHex(), publicKey.ToHex()); Assert.AreEqual(keyPair.PublicKey.GetAddress().ToHex(), publicKey.GetAddress().ToHex()); // using new chain id receipt = signer.Sign(tx, keyPair, true); Assert.AreEqual(receipt.Hash.ToHex(), receipt.FullHash(true).ToHex()); publicKey = receipt.RecoverPublicKey(true); Assert.AreEqual(keyPair.PublicKey.ToHex(), publicKey.ToHex()); Assert.AreEqual(keyPair.PublicKey.GetAddress().ToHex(), publicKey.GetAddress().ToHex()); }
public IntegrationDependencies(TransactionFetcher fetcher) { Fetcher = fetcher; Hasher = new TransactionHasher(Fetcher); SignerMap = new SignerMap(new PayToPubKeySigner(Fetcher, Hasher), new PayToPubKeyHashSigner(Fetcher, Hasher)); Signer = new TransactionSigner(Fetcher, new ScriptClassifier(), SignerMap); }
/// <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 AccountSignerTransactionManager(IClient rpcClient, Account account, BigInteger?chainId = null) { ChainId = chainId; Account = account ?? throw new ArgumentNullException(nameof(account)); Client = rpcClient; _transactionSigner = new TransactionSigner(); }
public TransactionSignedUnityRequest(string url, string privateKey, string account) { _url = url; _account = account; _privateKey = privateKey; _transactionSigner = new TransactionSigner(); _ethSendTransactionRequest = new EthSendRawTransactionUnityRequest(_url); _transactionCountRequest = new EthGetTransactionCountUnityRequest(_url); }
public TransactionSignedUnityRequest(Account account, string url) { _url = url; _account = account; _transactionSigner = new TransactionSigner(); _ethSendTransactionRequest = new EthSendRawTransactionUnityRequest(_url); _transactionCountRequest = new EthGetTransactionCountUnityRequest(_url); _ethEstimateGasUnityRequest = new EthEstimateGasUnityRequest(_url); _ethGasPriceUnityRequest = new EthGasPriceUnityRequest(_url); }
public AccountSignerTransactionManager(IClient rpcClient, string privateKey) { if (privateKey == null) { throw new ArgumentNullException(nameof(privateKey)); } Client = rpcClient; _account = EthECKey.GetPublicAddress(privateKey); _privateKey = privateKey; _transactionSigner = new TransactionSigner(); }
public TransactionSignedUnityRequest(string url, string privateKey) { _url = url; _account = EthECKey.GetPublicAddress(privateKey); _privateKey = privateKey; _transactionSigner = new TransactionSigner(); _ethSendTransactionRequest = new EthSendRawTransactionUnityRequest(_url); _transactionCountRequest = new EthGetTransactionCountUnityRequest(_url); _ethEstimateGasUnityRequest = new EthEstimateGasUnityRequest(_url); _ethGasPriceUnityRequest = new EthGasPriceUnityRequest(_url); }
protected virtual void InitialiseInnerServices() { Eth = new EthApiContractService(Client); Shh = new ShhApiService(Client); Net = new NetApiService(Client); Personal = new PersonalApiService(Client); Convert = new UnitConversion(); sha3Keccack = new Sha3Keccack(); OfflineTransactionSigner = new TransactionSigner(); addressUtil = new AddressUtil(); }
// Creates, Signs and publishes a new transaction public static TransactionHash createSignPublishTransaction(string abi, string contractAddress, string signingPrivateKey, string contractFunction, params object [] inputParams) { // Sign the transaction offline first string signedTransaction = new TransactionSigner().SignTransaction( signingPrivateKey, // privateKey contractAddress, // to 0, // amount in wei to send with transaction web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(EthECKey.GetPublicAddress(signingPrivateKey)).Result, // nonce value AppModelConfig.defaultGasPrice, // gasPrice AppModelConfig.defaultGasLimit, // gasLimit web3.Eth.GetContract(abi, contractAddress).GetFunction(contractFunction).GetData(inputParams) // data ); // Publish the raw and signed transaction try { return(new TransactionHash { Hash = web3.Eth.Transactions.SendRawTransaction.SendRequestAsync(signedTransaction).Result }); } catch (Exception exc) { // If the transaction was rejected by the blockchain return and throw an HTTP Error throw new HttpError( HttpStatusCode.NotAcceptable, AppModelConfig.TransactionProcessingError, AppModelConfig.TransactionProcessingErrorMessage + " --- " + exc.Message); } // *************************************************************************************** // Alternative method of publishing transactions by not using offline transaction signing // => Disadvantage of this method is that every transaction creates a new web3 connection // => Advantage of this method is that multiple transactions can be published at the same time (no issues with nonce values) // *************************************************************************************** // Function contractFunction = // new Web3(new Account(signingPrivateKey), AppModelConfig.WEB3_URL_ENDPOINT).Eth.GetContract(abi, address).GetFunction(function); // // Create, Sign and publish transaction // try { // return new TransactionHash { // Hash = contractFunction.SendTransactionAsync( // EthECKey.GetPublicAddress(signingPrivateKey), // new HexBigInteger(4712388), // null, // inputParams // ).Result // }; // } catch { // // If the transaction was rejected by the blockchain return and throw an HTTP Error // throw new HttpError( // HttpStatusCode.NotAcceptable, // AppModelConfig.TransactionProcessingError, // AppModelConfig.TransactionProcessingErrorMessage); // } }
public AccountSignerTransactionManager(IClient rpcClient, string privateKey) { if (privateKey == null) { throw new ArgumentNullException(nameof(privateKey)); } Client = rpcClient; _account = new Account(privateKey); _account.NonceService = new InMemoryNonceService(_account.Address, rpcClient); _transactionSigner = new TransactionSigner(); }
public void Test_Tx_Pool_Replacement() { _blockManager.TryBuildGenesisBlock(); TestTxPoolAdding(); var privateKey = Crypto.GeneratePrivateKey().ToPrivateKey(); var keyPair = new EcdsaKeyPair(privateKey); AddRandomTxesToPool(keyPair, out var randomTxes); var rnd = new Random(); randomTxes = randomTxes.OrderBy(item => rnd.Next()).ToList(); bool useNewChainId = HardforkHeights.IsHardfork_9Active(_blockManager.GetHeight() + 1); var signer = new TransactionSigner(); foreach (var tx in randomTxes) { Console.WriteLine($"nonce: {tx.Transaction.Nonce}"); var newTx = new Transaction(tx.Transaction); // lower price newTx.GasPrice = tx.Transaction.GasPrice - 1; var randomTx = TestUtils.GetRandomTransaction(useNewChainId).Transaction; newTx.To = randomTx.To; newTx.Value = randomTx.Value; newTx.GasLimit = randomTx.GasLimit; var newTxReceipt = signer.Sign(newTx, keyPair, useNewChainId); var result = _transactionPool.Add(newTxReceipt); Console.WriteLine($"old gas price: {tx.Transaction.GasPrice}, new gas price: {newTxReceipt.Transaction.GasPrice}"); Assert.AreEqual(OperatingError.Underpriced, result); // equal price newTx.GasPrice = tx.Transaction.GasPrice; newTxReceipt = signer.Sign(newTx, keyPair, useNewChainId); result = _transactionPool.Add(newTxReceipt); Console.WriteLine($"old gas price: {tx.Transaction.GasPrice}, new gas price: {newTxReceipt.Transaction.GasPrice}"); Assert.AreEqual(OperatingError.Underpriced, result); // higher price newTx.GasPrice = tx.Transaction.GasPrice + 1; newTxReceipt = signer.Sign(newTx, keyPair, useNewChainId); result = _transactionPool.Add(newTxReceipt); Console.WriteLine($"old gas price: {tx.Transaction.GasPrice}, new gas price: {newTxReceipt.Transaction.GasPrice}"); Assert.AreEqual(OperatingError.DuplicatedTransaction, result); // higher price and all fields same newTx = new Transaction(tx.Transaction); newTx.GasPrice = tx.Transaction.GasPrice + 1; newTxReceipt = signer.Sign(newTx, keyPair, useNewChainId); result = _transactionPool.Add(newTxReceipt); Console.WriteLine($"old gas price: {tx.Transaction.GasPrice}, new gas price: {newTxReceipt.Transaction.GasPrice}"); Assert.AreEqual(OperatingError.Ok, result); } }
public SignedTransactionManager(IClient rpcClient, string privateKey, string account) { if (privateKey == null) { throw new ArgumentNullException(nameof(privateKey)); } if (account == null) { throw new ArgumentNullException(nameof(account)); } _rpcClient = rpcClient; _privateKey = privateKey; _account = account; _transactionSigner = new TransactionSigner(); }
public void Test_SignIssue() { var keyPair = new EcdsaKeyPair("0xd95d6db65f3e2223703c5d8e205d98e3e6b470f067b0f94f6c6bf73d4301ce48" .HexToBytes().ToPrivateKey()); var signer = new TransactionSigner(); var data = "0x0061736d01000000011c0660017f006000017f60037f7f7f0060027f7f0060000060017f017f0290010703656e76156765745f7472616e736665727265645f66756e6473000003656e760d6765745f63616c6c5f73697a65000103656e760f636f70795f63616c6c5f76616c7565000203656e760c6c6f61645f73746f72616765000303656e760a7365745f72657475726e000303656e760b73797374656d5f68616c74000003656e760c736176655f73746f72616765000303060504050202040405017001010105030100020608017f01418080040b071202066d656d6f72790200057374617274000b0ab806052e004100410036028080044100410036028480044100410036028c800441003f0041107441f0ff7b6a36028880040ba60101047f418080042101024003400240200128020c0d002001280208220220004f0d020b200128020022010d000b41002101410028020821020b02402002200041076a41787122036b22024118490d00200120036a41106a22002001280200220436020002402004450d00200420003602040b2000200241706a3602082000410036020c2000200136020420012000360200200120033602080b2001410136020c200141106a0b2d002000411f6a21000340200120002d00003a0000200141016a21012000417f6a21002002417f6a22020d000b0b2d002001411f6a21010340200120002d00003a00002001417f6a2101200041016a21002002417f6a22020d000b0b820402047f047e230041a0016b2200240020001000024002400240024002402000290300200041106a29030084200041086a290300200041186a29030084844200520d00100741001001220136020441002001100822023602084100200120021002200141034d0d014100200228020022033602000240200341eea3f68405460d00200341d4c78168470d0220004180016a41186a420037030020004200370390012000420037038801200042003703800120004180016a200041e0006a1003200041206a41186a200041e0006a41186a2903003703002000200041f0006a2903003703302000200041e8006a290300370328200020002903603703204100450d0341004100100441011005000b2001417c6a4120490d03200241046a200041c0006a41201009200041c8006a2903002104200041d0006a2903002105200041c0006a41186a29030021062000290340210720004180016a41186a4200370300200041e0006a41186a200637030020004200370390012000420037038801200042003703800120002005370370200020043703682000200737036020004180016a200041e0006a100641010d0441004100100441011005000b41004100100441011005000b41004100100441011005000b200041206a4120100822004120100a20004120100441001005000b200041a0016a240041030f0b41004100100441001005000b00740970726f647563657273010c70726f6365737365642d62790105636c616e675431302e302e3120286769743a2f2f6769746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a65637420623661313733343336373838653638333239636335653965653066363531623630336136333765332900ad01046e616d6501a5010c00156765745f7472616e736665727265645f66756e6473010d6765745f63616c6c5f73697a65020f636f70795f63616c6c5f76616c7565030c6c6f61645f73746f72616765040a7365745f72657475726e050b73797374656d5f68616c74060c736176655f73746f72616765070b5f5f696e69745f6865617008085f5f6d616c6c6f63090b5f5f62653332746f6c654e0a0b5f5f6c654e746f626533320b057374617274" .HexToBytes(); var tx = new Transaction { To = UInt160Utils.Empty, Invocation = ByteString.CopyFrom(data), From = "0x6Bc32575ACb8754886dC283c2c8ac54B1Bd93195".HexToBytes().ToUInt160(), GasPrice = 1, GasLimit = 5369560, Nonce = 0, Value = new BigInteger(0).ToUInt256() }; // using old chain id var receipt = signer.Sign(tx, keyPair, false); Assert.AreEqual(receipt.Hash.ToHex(), receipt.FullHash(false).ToHex()); var txHashFromWeb3Py = "0x0bd482bdd02f75f4897658f39c6ddf0a4ef0c58b2f4c3acdf0474ba497a0a6d5"; Assert.AreEqual(receipt.Hash.ToHex(), txHashFromWeb3Py); var publicKey = receipt.RecoverPublicKey(false); Assert.AreEqual(keyPair.PublicKey.ToHex(), publicKey.ToHex()); Assert.AreEqual(keyPair.PublicKey.GetAddress().ToHex(), publicKey.GetAddress().ToHex()); // using new chain id receipt = signer.Sign(tx, keyPair, true); Assert.AreEqual(receipt.Hash.ToHex(), receipt.FullHash(true).ToHex()); txHashFromWeb3Py = "0x45361b6213f2f7115feb7044ab9f52e03f2c7e49bb1866b5d094a0e39f0fa2f6"; Assert.AreEqual(receipt.Hash.ToHex(), txHashFromWeb3Py); publicKey = receipt.RecoverPublicKey(true); Assert.AreEqual(keyPair.PublicKey.ToHex(), publicKey.ToHex()); Assert.AreEqual(keyPair.PublicKey.GetAddress().ToHex(), publicKey.GetAddress().ToHex()); }
public static TransactionReceipt GetRandomTransactionFromAddress(EcdsaKeyPair keyPair, ulong nonce, bool useNewChainId) { var signer = new TransactionSigner(); byte[] random = new byte[32]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(random); var randomValue = new Random().Next(1, 100); var tx = new Transaction { To = random.Slice(0, 20).ToUInt160(), From = keyPair.PublicKey.GetAddress(), GasPrice = (ulong)Money.Parse("0.0000001").ToWei(), GasLimit = 100000000, Nonce = nonce, Value = Money.Parse($"{randomValue}.0").ToUInt256() }; return(signer.Sign(tx, keyPair, useNewChainId)); }
static void Main(string[] args) { KeyVaultClient kvc = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken)); var signer = new AzureKeyVaultExternalSigner(kvc, URI); var publicKey = signer.GetPublicKeyAsync().Result; System.Console.WriteLine(publicKey.ToHex()); var msgHash = new Util.Sha3Keccack().CalculateHash("Hello").HexToByteArray(); var ethExternalSigner = new EthECKeyExternalSigner(signer); var signature = ethExternalSigner.SignAndCalculateVAsync(msgHash).Result; var publicKeyRecovered = EthECKey.RecoverFromSignature(signature, msgHash); System.Console.WriteLine(publicKeyRecovered.GetPubKey().ToHex()); var transfer = new TransferFunction(); transfer.To = "0x1996a57077877D38e18A1BE44A55100D77b8fA1D"; transfer.FromAddress = publicKeyRecovered.GetPublicAddress(); transfer.Value = 1; transfer.Nonce = 1; transfer.GasPrice = 100; transfer.Gas = 1000; var rpcClient = new RpcClient(new Uri("http://localhost:8545")); var transactionInput = transfer.CreateTransactionInput("0x12890d2cce102216644c59daE5baed380d84830c"); var externalAccount = new ExternalAccount(ethExternalSigner, 1); externalAccount.InitialiseAsync().Wait(); externalAccount.InitialiseDefaultTransactionManager(rpcClient); var signature2 = externalAccount.TransactionManager.SignTransactionAsync(transactionInput).Result; var transactionSigner = new TransactionSigner(); var publicKeyRecovered2 = transactionSigner.GetPublicKey(signature2, 1); System.Console.WriteLine(publicKeyRecovered2.ToHex()); System.Console.ReadLine(); }
public static TransactionReceipt GetCustomTransaction(string value, string gasPrice, bool useNewChainId) { var signer = new TransactionSigner(); byte[] random = new byte[32]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(random); var keyPair = new EcdsaKeyPair(random.ToPrivateKey()); var tx = new Transaction { To = random.Slice(0, 20).ToUInt160(), From = keyPair.PublicKey.GetAddress(), GasPrice = (ulong)Money.Parse(gasPrice).ToWei(), GasLimit = 100000000, Nonce = 0, Value = Money.Parse(value).ToUInt256() }; return(signer.Sign(tx, keyPair, useNewChainId)); }
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))); }
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 AccountOfflineTransactionSigner() { _transactionSigner = new TransactionSigner(); }
public AccountSignerTransactionManager(IClient rpcClient, Account account) { _account = account ?? throw new ArgumentNullException(nameof(account)); Client = rpcClient; _transactionSigner = new TransactionSigner(); }
/// <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 AccountOfflineTransactionSigner(TransactionSigner transactionSigner) { _transactionSigner = transactionSigner; }
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); }
public async Task <IActionResult> Post(JsonRpcClientReq req, int chainid = 0) { if (chainid == 0) { return(BadRequest("chainid error")); } switch (req.Method) { case "eth_sendRawTransaction": { var signer = new TransactionSigner(); var addr = signer.GetSenderAddress(req.Params[0].ToString()); var rpc = NodeChoose.ChooseServer(chainid, addr); if (string.IsNullOrEmpty(rpc)) { return(BadRequest("not find suitable rpc server")); } var sendResult = await SendRequest(req, rpc); if (sendResult.result) { return(new ContentResult() { Content = sendResult.response, ContentType = "application/json", StatusCode = 200 }); } return(BadRequest(sendResult.response)); } default: { var cache = EthRpcCache.Instance.CheckCache(chainid, req); if (cache.hasCache) { Logger.Debug($"{req} in cache"); //update resp id var respObj = JObject.Parse(cache.result); respObj["id"] = req.Id; respObj["cache"] = cache.strategy.ToString(); return(new ContentResult() { Content = respObj.ToString(Formatting.None), ContentType = "application/json", StatusCode = 200 }); } var rpc = NodeChoose.ChooseServer(chainid); if (string.IsNullOrEmpty(rpc)) { return(BadRequest("not find suitable rpc server")); } var sendResult = await SendRequest(req, rpc); if (sendResult.result) { var respObj = JObject.Parse(sendResult.response); switch (cache.strategy) { case RpcCacheStrategy.NotCache: break; case RpcCacheStrategy.CacheInMemory: case RpcCacheStrategy.CacheInDb: var cacheResult = EthRpcCache.Instance.AddCache(chainid, req, sendResult.response); respObj["cacheOption"] = cache.strategy.ToString(); respObj["cacheResult"] = cacheResult; break; } return(new ContentResult() { Content = respObj.ToString(Formatting.None), ContentType = "application/json", StatusCode = 200 }); } return(BadRequest(sendResult.response)); } } }
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 void Test_Tx_Building() { var signer = new TransactionSigner(); var keyPair = new EcdsaKeyPair("0xD95D6DB65F3E2223703C5D8E205D98E3E6B470F067B0F94F6C6BF73D4301CE48" .HexToBytes().ToPrivateKey()); var tx = new Transaction { To = "0xB8CD3195faf7da8a87A2816B9b4bBA2A19D25dAb".HexToUInt160(), From = keyPair.PublicKey.GetAddress(), GasPrice = (ulong)Money.Parse("0.0000001").ToWei(), GasLimit = 100000000, Nonce = 0, Value = Money.Parse("20.0").ToUInt256() }; Console.WriteLine($"Tx: from: {tx.From.ToHex()}, to: {tx.To.ToHex()}"); // using old chain id // this is correct RLP of unsigned ethereum tx with chain id 25, check at https://toolkit.abdk.consulting/ethereum#transaction var expectedRawHash = "0xef8085174876e8008405f5e10094b8cd3195faf7da8a87a2816b9b4bba2a19d25dab8901158e460913d0000080198080" .HexToBytes() .Keccak(); Assert.AreEqual(expectedRawHash, tx.RawHash(false)); // this is correct RLP of signed ethereum tx with chain id 25, check at https://toolkit.abdk.consulting/ethereum#transaction // signature is deterministic in compliance with https://tools.ietf.org/html/rfc6979 var expectedFullHash = "0xf86f8085174876e8008405f5e10094b8cd3195faf7da8a87a2816b9b4bba2a19d25dab8901158e460913d000008055a0c763aabd0587adb01786db24eac39c76a22bfcf97d19ad07f3b64ddd2294bdeba04710bc793cd49e4a957cc4babec18c27eabd8c873267b1fdb4943f16de22321f" .HexToBytes() .Keccak(); var receipt = signer.Sign(tx, keyPair, false); Assert.AreEqual( expectedFullHash, receipt.Hash ); var pubKey = receipt.RecoverPublicKey(false); Assert.AreEqual(receipt.Transaction.From.ToHex(), pubKey.GetAddress().ToHex()); // using new chain id // this is correct RLP of unsigned ethereum tx with chain id 225, check at https://toolkit.abdk.consulting/ethereum#transaction expectedRawHash = "0xf08085174876e8008405f5e10094b8cd3195faf7da8a87a2816b9b4bba2a19d25dab8901158e460913d000008081e18080" .HexToBytes() .Keccak(); Assert.AreEqual(expectedRawHash, tx.RawHash(true)); // this is correct RLP of signed ethereum tx with chain id 225, check at https://toolkit.abdk.consulting/ethereum#transaction // signature is deterministic in compliance with https://tools.ietf.org/html/rfc6979 expectedFullHash = "0xf8718085174876e8008405f5e10094b8cd3195faf7da8a87a2816b9b4bba2a19d25dab8901158e460913d00000808201e5a07daf59f5e3223da3732ff0f0ffc464c533a881245fe00d09573c792f8a5f055aa067da9775fd1253f05215f961a019b619cc4d2aa8e2ae6c29c8232152f6692c24" .HexToBytes() .Keccak(); receipt = signer.Sign(tx, keyPair, true); Assert.AreEqual( expectedFullHash, receipt.Hash ); pubKey = receipt.RecoverPublicKey(true); Assert.AreEqual(receipt.Transaction.From.ToHex(), pubKey.GetAddress().ToHex()); }