// Array request, string service, Action<string> callback, string callbackUrl public async Task <Texture2D> SendTransaction() { // Uri for transaction string baseRequestUri = "meta://transaction?", trxRequestUri = ""; // URI for to, value, data baseRequestUri += "t=" + to + "&v=" + HexBigIntegerConvertorExtensions.ToHex(value, true) + "&d=" + HexStringUTF8ConvertorExtensions.ToHexUTF8(data); // URI for usage baseRequestUri += "&u=" + usage; // URI for callbackUrl and callback if (!string.IsNullOrEmpty(callbackUrl)) { baseRequestUri += "&c=" + WWW.EscapeURL(callbackUrl); } else { baseRequestUri += "&c=https%3A%2F%2F0s5eebblre.execute-api.ap-northeast-2.amazonaws.com/dev?key=" + session; } Debug.Log("Transaction baseRequestUri: " + baseRequestUri); // URI for IPFS IPFSClass ipfs = new IPFSClass(); trxRequestUri = await ipfs.IpfsAdd(baseRequestUri); Debug.Log("Transaction trxRequestUri(IPFS hash): " + trxRequestUri); // Polling request using timer timer = new Timer { Interval = 2000 }; timer.Elapsed += HttpRequest; timer.AutoReset = true; timer.Enabled = true; timer.Start(); // Make QRCode for request QRcode.QRcode metaQR = new QRcode.QRcode(); return(metaQR.MakeQR(256, trxRequestUri)); }
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; } }