using System; using System.Diagnostics; using System.Text; using System.Collections.Generic; using System.Linq; using System.Drawing; using System.Drawing.Imaging; using System.Threading.Tasks; using Newtonsoft.Json; using Console = HyperCube.Utils.AdvConsole; using System.Text.RegularExpressions; using QRCoder; using System.IO; using Microsoft.AspNetCore.Components; using System.Numerics; //0xe5D682717955d6C35d465A3485625C64655a04f4 - HCB in rinkeby //0xb504ba124b74333d8536db534f7fcdc174d6ee3d - system address rinkeby //0x413D9500A675d9b645034aC5f4325BF12ddeb7c1 bitcoin namespace HyperCube.Models { public struct TransactionObject { /// /// transaction sender /// public string from; /// /// transaction receiver /// public string to; /// /// payload - function pointer and all other custom parameters /// public string data; /// /// gas amount /// public string gas; /// /// value in Wei /// public string value; } public class Blockchain { [Inject] AppData AppData { get; set; } public static Blockchain Dev { get { return loaded[0]; } set { } } public const string MultiOwnerContractRinkeby = "0x7eca4E373De5E9ad27Be283612a75e632aCB81f2"; public const string HCBAddress = "0xe5D682717955d6C35d465A3485625C64655a04f4"; public const string QNMAddress = "0xE895a91B041e8450A1AFb9F54b8362a8ae3bb3d3"; public static string tokenName; public static string decimals; public static string symbol; public static string tokenBalance; public static string balanceToken; public static Dictionary supported; //public static string Connected //{ // get // { // var bc = AppData.CurrentAccount.GetSelectedBlockChain(); //acc selected // if (bc != null) // return $"{bc.name}"; // return "none"; // } //} public static string URLdefault = "127.0.0.1"; //public static int defaultPort = 8545; public static int defaultPort = 8666; public static string defaultName = "Ethereum dev network"; public static bool blockChainsInitialized = false; public static Dictionary loaded = new(); public Dictionary contracts = new(); public Dictionary contractNames = new(); public int id; public int port; public string url; public string address = ""; public string name; public string balance; static Blockchain instance; public async static Task RegisterNetworks() { if (!blockChainsInitialized) { Console.WriteLine($"RegisterNetworks"); var ethDev = new Blockchain(0, "Ethereum Dev Network", "127.0.0.1", 8545); var ethRinkeby = new Blockchain(1, "Ethereum Test Network", "127.0.0.1", 8666); await ethDev.Initialize(); await ethRinkeby.Initialize(); blockChainsInitialized = true; } } public static Blockchain Find(int id) { if (loaded.ContainsKey(id)) return loaded[id]; return null; } public async Task GetBalanceToken(string contractAddress, string address) { TransactionObject transObj = new TransactionObject(); transObj.to = contractAddress; //compile data //to.data = await compileFunction("decimals"); //transObj.data = await compileFunction("name"); //var answer = await RunFunction2("eth_call", transObj, "latest"); ////Console.WriteLine("ImportERC20 len "+ answer.Length + " answer " + answer); //var parsed = ParseStringAnswer(answer); //int tokenlen = hex2dec(parsed[1]); //tokenName = HextoString(parsed[2]).Substring(0, tokenlen); //to.data = await compileFunction("balanceOf(address)"); transObj.data = await compileFunction("symbol"); var answer = await RunFunction2("eth_call", transObj, "latest"); var parsed = ParseStringAnswer(answer); if (parsed.Length == 0) return null; int symlen = hex2dec(parsed[1]); symbol = HextoString(parsed[2]).Substring(0, symlen); //Console.WriteLine("ImportERC20 len " + answer.Length + " answer " + answer); transObj.data = await compileFunction("decimals"); answer = await RunFunction2("eth_call", transObj, "latest"); decimals = hex2dec(ParseStringAnswer(answer)[0]).ToString(); transObj.data = await compileFunction($"function balanceOf(address account)"); if (address != null) transObj.data += zerofill(address, 64, true); //answer = await RunFunction2("eth_call", to, AccountModel.Current.GetActualAddress(this)); answer = await RunFunction2("eth_call", transObj, "latest"); balanceToken = ((double)AccountModel.ConvertBalance(ParseStringAnswer(answer)[0]) / 1000000000000000000.0).ToString(); return balanceToken; } public async Task Initialize() { if (!loaded.ContainsKey(id)) loaded.Add(id, this); Console.WriteLine($"Initialize: {name}, loaded blockchains " + loaded.Count); string addr = await ListAccounts(); await LoadContracts(); Console.WriteLine("LoadContracts count " + contracts.Count); //Console.WriteLine("connected " + Connected); return $"{name} {url}:{port}"; } public async Task ChangeOwner(string ERC20Address, string contractAddress) { TransactionObject transObj = new TransactionObject(); transObj.from = address; transObj.to = ERC20Address; transObj.data = await compileFunction($"function transferOwnership(address newOwner)"); var answer = await RunFunction2("eth_sendTransaction", transObj); } public async Task ChangeOwnerMulti() { TransactionObject transObj = new TransactionObject(); transObj.from = address; transObj.to = MultiOwnerContractRinkeby; //transObj.data = zerofill(dec2hex(36), 64, true); //36 bytes len of data. Для ремикса это не нужно, он сам вставляет длину массива transObj.data += await compileFunction($"function transferOwnership(address newOwner)"); //4 bytes transObj.data += zerofill("0xD3ae749f1253b320ea2b90dc235ed72c80447AFF", 64, true); //32 bytes Console.WriteLine($"transObj.data {transObj.data}"); //var answer = await RunFunction2("eth_sendTransaction", transObj); } public async Task Transactions(string multiOwnerContract) { TransactionObject transObj = new TransactionObject(); transObj.to = multiOwnerContract; transObj.data = await compileFunction($"transactionCount"); var answer = await RunFunction2("eth_call", transObj, "latest"); } public async Task Approve(string owner, string spender, string amount, string tokenAddress) { TransactionObject transObj = new TransactionObject(); transObj.from = owner; transObj.to = tokenAddress; transObj.data = await compileFunction($"function approve(address spender, uint256 amount)"); if (tokenAddress != null) { transObj.data += zerofill(spender, 64, true); transObj.data += zerofill(dec2hex(amount), 64, true); } var answer = await RunFunction2("eth_sendTransaction", transObj); } public async Task SubmitTransaction(string owner, long tokenvalue, string receiver, string tokenAddress = QNMAddress) { //"submitTransaction(address destination, uint value, address tokenAddress)" //var tokenAmount = float.Parse(tokenvalue, System.Globalization.CultureInfo.InvariantCulture);// * 1000000000000000000; //ETHtoERC20(address tokenAddress) //ERC20toETH(address tokenAddress, address sender, uint256 tokenAmount, uint256 ethAmount) public payable returns(bool) TransactionObject transObj = new TransactionObject(); transObj.from = owner; transObj.to = MultiOwnerContractRinkeby; transObj.data = await compileFunction($"function submitTransaction(address destination, uint256 value, address tokenAddress)"); if (tokenvalue > 0) { transObj.data += zerofill(receiver, 64, true); transObj.data += zerofill(dec2hex(tokenvalue), 64, true); transObj.data += zerofill(tokenAddress, 64, true); } var answer = await RunFunction2("eth_sendTransaction", transObj); return ParseStringAnswer(answer)[0]; } // //ETHtoERC20 - шлем эфир на контракт, контракт шлет юзеру ERC20 по курсу со своего счета через transfer //ETHtoERC20 - шлем ERC20 на контракт, получаем эфир по курсу //запуск контрактом TransferFrom юзером на адрес контракта //контракт шлет юзеру эфир по курсу со своего счета //нужна проверка балансов системы и юзера перед обменом public async Task ExchangeCurrency(string from_token_selected, string to_token_selected, string tokenAddress, string senderAccountAddress, string fi, string ti) { //ETHtoERC20(address tokenAddress, uint256 tokenAmount) //ERC20toETH(address tokenAddress, address sender, uint256 tokenAmount, uint256 ethAmount) public payable returns(bool) TransactionObject transObj = new TransactionObject(); transObj.from = senderAccountAddress; transObj.to = MultiOwnerContractRinkeby; transObj.gas = dec2hex("90000"); var valFrom = decimal.Parse(fi, System.Globalization.CultureInfo.InvariantCulture); var valTo = decimal.Parse(ti, System.Globalization.CultureInfo.InvariantCulture); if (to_token_selected == "qnm") { transObj.data = await compileFunction($"function ETHtoERC20(address tokenAddress, uint256 tokenAmount)"); BigInteger tokenAmount = (BigInteger)(valTo * 1000000000000000000m); BigInteger ethAmount = (BigInteger)(valFrom * 1000000000000000000m); Console.WriteLine($"######################################ETHtoERC20 valTo {valTo} tokenAmount {tokenAmount} valFrom {valFrom} ethAmount {ethAmount}"); transObj.value = dec2hex(ethAmount); if (tokenAddress != null && tokenAmount > 0) { transObj.data += zerofill(tokenAddress, 64, true); transObj.data += zerofill(dec2hex(tokenAmount), 64, true); } } else { BigInteger tokenAmount = (BigInteger)(valFrom * 1000000000000000000); BigInteger ethAmount = (BigInteger)(valTo * 1000000000000000000); //сначала нужен аппрув перевода! //from=erc20 to=eth var amount = float.Parse(fi, System.Globalization.CultureInfo.InvariantCulture); var appr = Approve(senderAccountAddress, MultiOwnerContractRinkeby, tokenAmount.ToString(), QNMAddress); await Task.WhenAll(appr); //sender возможно можно заменить на msg.sender transObj.data = await compileFunction($"function ERC20toETH(address tokenAddress, address sender, uint256 tokenAmount, uint256 ethAmount)"); Console.WriteLine($"######################################ERC20toETH valTo {valTo} tokenAmount {tokenAmount} valFrom {valFrom} ethAmount {ethAmount}"); if (tokenAddress != null && tokenAmount != null) { transObj.data += zerofill(tokenAddress, 64, true); transObj.data += zerofill(senderAccountAddress, 64, true); transObj.data += zerofill(dec2hex(tokenAmount), 64, true); transObj.data += zerofill(dec2hex(ethAmount), 64, true); } } var answer = await RunFunction2("eth_sendTransaction", transObj); } //ETHtoERC20(address tokenAddress, uint256 tokenAmount) public async Task Verify(AccountModel verifier, ArticleModel article) { Console.WriteLine($"Verify starting"); try { var bc = await verifier.GetSelectedBlockChain(); VerifyContract verifyContract = SmartContract.Find("Verify", bc) as VerifyContract; if (verifyContract != null) { Console.WriteLine($"VerifyContract found"); var transactionId = await verifyContract.Run(verifier, article); return transactionId; } else Console.WriteLine($"VerifyContract null"); } catch (Exception e) { Console.WriteLine(e.Message + "stack trace" + e.StackTrace); } return "Verify failed"; } public static string dec2hex(BigInteger decValue, bool prefix = true) { var hexValue = decValue.ToString("X"); if (prefix) hexValue = "0x" + hexValue; return hexValue; } public static string dec2hex(string decValue, bool prefix = true) { var hexValue = BigInteger.Parse(decValue, System.Globalization.CultureInfo.InvariantCulture).ToString("X"); if (prefix) hexValue = "0x" + hexValue; return hexValue; } public static int hex2dec(string hexValue) { return Convert.ToInt32(hexValue, 16); } //public static Blockchain GetInstance() //{ // if (instance == null) // instance = new Blockchain(URLdefault, defaultPort); // return instance; //} //Blockchain() //{ //} public Blockchain(int id, string name, string url, int port) { this.id = id; this.url = url; this.port = port; this.name = name; } public async Task CreateBlockchainAccount(AccountModel account, string pass) { Console.WriteLine($"Run CreateBlockchainAccount {account}"); var res = await RunFunction("personal_newAccount", $"\"{pass}\""); string query; if (account != null) { Console.WriteLine($"CreateBlockchainAccount {account}: {res}"); //query = $"update aspnetusers set eth_address='{res}' where UserName='{account.Name}'"; var addr = account.GetActualAddress(this); if (addr == null) query = $"insert into account_wallets (uuid, blockchain_id, account_uuid, password_plain, added) values ('{res}',{id},'{account.UUID}','{account.PWDHash}', NOW())"; else query = $"update account_wallets set uuid='{res}', password_plain='{account.PWDHash}', added = NOW() where account_uuid='{account.UUID}' and blockchain_id={id}"; account.SetActualAddress(res, this); Console.WriteLine($"CreateBlockchainAccount query {query}"); await MySQLConnector.Instance().SQLInsert(query); } else Console.WriteLine($"CreateBlockchainAccount {id}: {res}"); address = res; if (account == null) { query = $"update blockchains set address_main='{res}' where id={id}"; Console.WriteLine($"CreateBlockchainAccount query {query}"); await MySQLConnector.Instance().SQLInsert(query); } return res; } public static string hex2bin(string hexstring) { string binarystring = String.Join(String.Empty, hexstring.Select( c => Convert.ToString(Convert.ToInt32(c.ToString(), 16), 2).PadLeft(4, '0') )); Console.WriteLine("bin " + binarystring); return binarystring; } public static string bin2hex(string code) { //code = "0x".bin2hex('getCount()'); var bytes = Encoding.UTF8.GetBytes(code); var hex = BitConverter.ToString(bytes).Replace("-", ""); Console.WriteLine("hex " + hex); return "0x" + hex; } public static string zerofill(string hex, int charCount, bool hexPrefix0x) { if (hexPrefix0x) hex = hex.Remove(0, 2); Console.WriteLine($"zerofill input {hex} count {hex.Length}"); var res = hex.PadLeft(charCount, '0'); Console.WriteLine($"zerofill out {hex} count {res.Length}"); return res; } public async Task ListAccounts() { Console.WriteLine($"ListAccounts blockchain {id}"); string answer = "no"; //{ "jsonrpc":"2.0","method":"eth_getCode","params":["0x938cae6f6c21ed9d55196e96ef880f562e530553", "latest" ],"id":1} //string req = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getCode\",\"params\":[\"0x874c6a51e62680d4594cd2555ed8fa47b63ed253\",\"latest\"],\"id\":1}"; string req = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_accounts\", \"params\":[],\"id\":1}"; answer = await Post.PostRequestAsync(this, req); //string json = Encoding.UTF8.GetString(bytedata, 1, bytedata.Length - 1); //try //{ Console.WriteLine("Json string " + answer); dynamic jsonDe = JsonConvert.DeserializeObject(answer); var res = (Newtonsoft.Json.Linq.JArray)jsonDe.result; if (res.Count > 0 && id == 0) //Dev { address = jsonDe.result[0]; } else { address = await GetAddress(); if (address == "" || address == null) address = await CreateEthAddress("test_Password_212"); } var query = $"update blockchains set address_main='{address}' where id={id}"; Console.WriteLine("query " + query); await MySQLConnector.Instance().SQLInsert(query); Console.WriteLine("Json addr " + jsonDe.result[0]); return address; } public async Task CreateEthAddress(string pass) { return await CreateBlockchainAccount(null, pass); } public async Task LoadContracts() { MySQLConnector dbCon = MySQLConnector.Instance(); contracts = await dbCon.SQLSelectContracts(id); foreach (var contract in contracts.Values) { await contract.LoadFunction(); } } public async Task GetSHA3(string code) { var hex = bin2hex(code); var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"web3_sha3\",\"params\":[\"{hex}\"], \"id\":1}}"; var answer = await Post.PostRequestAsync(this, req); dynamic jsonDe = JsonConvert.DeserializeObject(answer); Console.WriteLine("result " + jsonDe.result); return jsonDe.result; } public async Task GetBalance(AccountModel account) { var addr = await account.GetOrCreateActualAddress(this); //var ret = await RunFunction("eth_getBalance", $"\"{addr}\",\"latest\""); Console.WriteLine($"GetBalance AccountModel addr {addr}"); return await GetBalance(addr); } public async Task GetBalance() { return await GetBalance(address); } //eth.getBalance('0xb504ba124b74333D8536DB534F7fcdC174d6Ee3d') public async Task GetBalance(string address) { var ret = await RunFunction("eth_getBalance", $"\"{address}\",\"latest\""); var balanceWei = AccountModel.ConvertBalance(ret); var balanceEth = Math.Round((double)balanceWei / 1000000000000000000.0, 4); Console.WriteLine($"GetBalance balanceEth {balanceEth}"); balance = balanceEth.ToString(); return balance; } public async Task RunFunction(string name, string parms) { Console.WriteLine($"RunFunction {name} params {parms}"); var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"{name}\",\"params\":[{parms}], \"id\":1}}"; var answer = await Post.PostRequestAsync(this, req); dynamic jsonDe = JsonConvert.DeserializeObject(answer); Console.WriteLine("RunFunction result " + jsonDe.result); return jsonDe.result; //return "test answer"; } public async Task RunFunction2(string name, TransactionObject to, string defaultBlock = null) { //транзакция добавления контракта 0x00bdbf1571aa69a2cf8c8c7913a01eaca3a4b7e5e7e49fc787cb81c0df2c2682 Dictionary paramDict = new Dictionary(); string parms = "{"; if (to.from != null) paramDict["from"] = to.from; if (to.to != null) paramDict["to"] = to.to; if (to.gas != null) paramDict["gas"] = to.gas; if (to.value != null) paramDict["value"] = to.value; if (to.data != null) { paramDict["data"] = "0x"+to.data; } int count = 0; foreach (var p in paramDict) { parms += $"\"{p.Key}\":\"{p.Value}\""; count++; if (paramDict.Count > count) { parms += ","; } } parms += "}"; if (defaultBlock != null) parms += $", \"{defaultBlock}\""; Console.WriteLine($"RunFunction {name} params {parms} active bc: {this.address}"); var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"{name}\",\"params\":[{parms}], \"id\":1}}"; var answer = await Post.PostRequestAsync(this, req); dynamic jsonDe = JsonConvert.DeserializeObject(answer); Console.WriteLine("RunFunction result " + jsonDe.result); return jsonDe.result; //return "test answer"; } public static string QRtest(string input) { QRCodeGenerator qrGenerator = new QRCodeGenerator(); QRCodeData qrCodeData = qrGenerator.CreateQrCode(input, QRCodeGenerator.ECCLevel.Q); QRCode qrCode = new QRCode(qrCodeData); Bitmap qrCodeImage = qrCode.GetGraphic(7); //Image img = qrCodeImage; MemoryStream ms = new MemoryStream(); BinaryWriter bw = new BinaryWriter(ms); //var fulltexname = Encoding.UTF8.GetBytes("http://" + myHostName + "/" + filename); //bw.Write(loc_id); //bw.Write(fulltexname); //return base64String; qrCodeImage.Save(ms, ImageFormat.Png); byte[] imageBytes = ms.ToArray(); string base64String = Convert.ToBase64String(imageBytes); Console.WriteLine($"base64String {base64String}"); return base64String; //Image.FromStream(ms); } public static List ExecuteCommand(string cmd) { List output = new List(); var processInfo = new ProcessStartInfo(@"e:\www\nodejs\test.bat", cmd ); processInfo.CreateNoWindow = true; processInfo.UseShellExecute = false; processInfo.RedirectStandardError = true; processInfo.RedirectStandardOutput = true; var process = Process.Start(processInfo); process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Echo(e.Data, ref output); process.BeginOutputReadLine(); process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("error>>" + e.Data); process.BeginErrorReadLine(); process.WaitForExit(); Console.WriteLine($"ExitCode: {process.ExitCode}"); num = 0; process.Close(); return output; } static int num = 0; static void Echo(string msg, ref List output) { //if (num > 0) if (msg != null && msg.Length > 0) { Console.WriteLine("output >>" + msg); output.Add(msg); } num++; } async Task mySHA3(string code) { var res = await GetSHA3(code); Console.WriteLine($"GetSHA3 {code} {res}"); var ret = res.Substring(2, 8); return ret; } public async Task compileFunction(string input, bool getsha = true) { //\s = пробел //\S = любой символ, кроме пробельного //+ одно или более вхождений //. любой сивол, кроме перевода строки //* ноль или более вхождений «а» //скобки без экранирования = группы //function transfer(address recipient, uint256 amount) string pattern = @"function\s+(\S+)\s*\((.*)\).*"; string replacement_name = "$1"; //номер найденной группы string replacement_params = "$2"; string resultname = Regex.Replace(input, pattern, replacement_name).Trim(); string param_pattern = @"(uint8|address|uint256)"; string final = resultname + "("; if (input != resultname) { string resultparams = Regex.Replace(input, pattern, replacement_params).Trim(); if (input != resultparams) { int i = 0; foreach (Match match in Regex.Matches(resultparams, param_pattern)) { if (i > 0) final += "," + match.Value; else final += match.Value; i++; } } } string function_processed = final + ")"; Console.WriteLine($"function_processed {function_processed}"); if (getsha) { function_processed = await mySHA3(function_processed); } return function_processed; } //public double UInt256Conv(string input) //{ // System.Numerics.BigInteger bigint1 = System.Numerics.BigInteger.Parse("329974300448100608374211110737048701521"); // System.Numerics.BigInteger bigint2 = new System.Numerics.BigInteger(18); // return bigint1 / 18.0; //} public static string HextoString(string InputText) { byte[] bb = Enumerable.Range(0, InputText.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(InputText.Substring(x, 2), 16)) .ToArray(); //return System.Text.Encoding.ASCII.GetString(bb); // or System.Text.Encoding.UTF7.GetString return System.Text.Encoding.UTF8.GetString(bb); // or System.Text.Encoding.Unicode.GetString // or etc. } public string[] ParseStringAnswer(string answer) { var ret = new string[] { }; Console.WriteLine($"ParseStringAnswer: {name}, answer.Length " + answer.Length); if (answer.Length > 2) { answer = answer.Substring(2, answer.Length - 2); int words = answer.Length / 64; ret = new string[words]; for (int i = 0; i < words; i++) { var word = answer.Substring(i * 64, 64); ret[i] = word; Console.WriteLine($"word {i} {word}"); Console.WriteLine($"str {i} {HextoString(word)}"); var testbalance1 = (double)(AccountModel.ConvertBalance(word)/ 1000000000000000000); var testbalance2 = ((double)AccountModel.ConvertBalance(word) / 1000000000000000000.0); Console.WriteLine($"testbalance1 {testbalance1} testbalance2 {testbalance2} "); } } return ret; } //верификация запускает запрос на минт/перевод токенов от системы //количество вычисляется по конечной ценности, переданной в смарт и курсу к $$$$??? //комиссия владельцам //4. Рабочий стол. Верификация //7. Календарь событий - тут добавление мероприятия запускает транзакции спонсирования //8. Персональные данные - роль //13. Цифровые активы //14. Блокчейн //накапать токенов эксперту и автору материала //0. делаем новый контракт с массивом ролей //1. делаем в нем управляющий код с подтверждениями на выпуск токенов //2. в рамках текущего токена - делаем овнером токена мульти контракт с ролями //3. этим же контрактом запускаем verify и другие контракты - функции //4. что должен фиксировать Verify? //5. как и где определять параметры запускаемых функций во внешних контрактах //6. определение курса токенов public async Task Mint(string tokenAmount, string addressTo) { //mint(address to, uint256 amount) TransactionObject transObj = new TransactionObject(); transObj.from = address; transObj.to = QNMAddress; transObj.gas = "9000"; transObj.data = await compileFunction($"function mint(address to, uint256 amount)"); if (addressTo != null && tokenAmount != null) { transObj.data += zerofill(addressTo, 64, true); transObj.data += zerofill(dec2hex(tokenAmount), 64, true); } var answer = await RunFunction2("eth_sendTransaction", transObj); } public async Task TransferToken(string sender, string tokenContract, string addressTo, string tokenAmount) { //transfer(address recipient, uint256 amount) TransactionObject transObj = new TransactionObject(); transObj.from = sender; transObj.to = tokenContract; transObj.data = await compileFunction($"function transfer(address recipient, uint256 amount)"); if (addressTo != null && tokenAmount != null) { transObj.data += zerofill(addressTo, 64, true); transObj.data += zerofill(dec2hex(Convert.ToInt32(tokenAmount)), 64, true); } var answer = await RunFunction2("eth_sendTransaction", transObj); } public async Task ImportERC20(string contractAddress, string importAddress) { //"0xb504ba124b74333D8536DB534F7fcdC174d6Ee3d" //var gbh = await GetTByHash("0x00bdbf1571aa69a2cf8c8c7913a01eaca3a4b7e5e7e49fc787cb81c0df2c2682"); //Console.WriteLine("GetTByHash " + gbh ); //runfunction balanceOf totalSupply symbol name //RunContractRead TransactionObject transObj = new TransactionObject(); transObj.to = contractAddress; //compile data //to.data = await compileFunction("decimals"); transObj.data = await compileFunction("name"); var answer = await RunFunction2("eth_call", transObj, "latest"); //Console.WriteLine("ImportERC20 len "+ answer.Length + " answer " + answer); var parsed = ParseStringAnswer(answer); int tokenlen = hex2dec(parsed[1]); tokenName = HextoString(parsed[2]).Substring(0,tokenlen); //to.data = await compileFunction("balanceOf(address)"); transObj.data = await compileFunction("symbol"); answer = await RunFunction2("eth_call", transObj, "latest"); parsed = ParseStringAnswer(answer); int symlen = hex2dec(parsed[1]); symbol = HextoString(parsed[2]).Substring(0, symlen); //Console.WriteLine("ImportERC20 len " + answer.Length + " answer " + answer); transObj.data = await compileFunction("decimals"); answer = await RunFunction2("eth_call", transObj, "latest"); decimals = hex2dec(ParseStringAnswer(answer)[0]).ToString(); transObj.data = await compileFunction($"function balanceOf(address account)"); if (address != null) transObj.data += zerofill(importAddress, 64, true); //answer = await RunFunction2("eth_call", to, AccountModel.Current.GetActualAddress(this)); answer = await RunFunction2("eth_call", transObj, "latest"); tokenBalance = ((double)AccountModel.ConvertBalance(ParseStringAnswer(answer)[0]) / 1000000000000000000.0).ToString(); } public async Task BalanceOf(string contractAddress, string holderAddress) { TransactionObject transObj = new TransactionObject(); transObj.to = contractAddress; transObj.data = await compileFunction($"function balanceOf(address account)"); if (address != null) transObj.data += zerofill(holderAddress, 64, true); //answer = await RunFunction2("eth_call", to, AccountModel.Current.GetActualAddress(this)); var answer = await RunFunction2("eth_call", transObj, "latest"); tokenBalance = ((double)AccountModel.ConvertBalance(ParseStringAnswer(answer)[0]) / 1000000000000000000.0).ToString(); return tokenBalance; } public async void RunContractRead() { string answer = "no"; string req = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"to\":\"0x874c6a51e62680d4594cd2555ed8fa47b63ed253\", \"data\":\"0xa87d942c\"},\"latest\"],\"id\":1}"; //string req = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x0000000000000000000000000000000000000000000000000000000000000004\"}"; //Console.WriteLine($"req " + req); await Post.PostRequestAsync(this, req); //Console.WriteLine($"answer {answer} len {answer.Length}" ); address = answer; } public async Task SendTransaction(string fromAddress, string toAddress, int wei) { var sum = dec2hex(wei); var gas = await GetEstimatedGasTransaction(wei); Console.WriteLine($"SendTransaction from {fromAddress} to {toAddress} sum {sum}"); var answer = await RunFunction("eth_sendTransaction", $"{{\"from\":\"{address}\",\"to\":\"{toAddress}\",\"gas\":\"{gas}\", \"data\":\"\", \"value\":\"{sum}\"}}"); return answer; } //{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{ "from":"0xD81eeE6b39d9556c3067A3551A3FB2882b92F327", "to":"0x119b58faddcdbc09cafcd272530aa079cec10004", "gas":"0x31b2ef", "data":"0x11111111"}], "id":1} public async Task RunContractWrite(string contractAddress, string data, string gas, string value) { Console.WriteLine("RunContract contractAddress " + contractAddress); var answer = await RunFunction("eth_sendTransaction", $"{{\"from\":\"{address}\",\"to\":\"{contractAddress}\",\"gas\":\"{gas}\", \"data\":\"{data}\", \"value\":\"{value}\"}}"); //$"{{ \"jsonrpc\":\"2.0\",\"method\":\"eth_sendTransaction\",\"params\":[{{\"from\":\"{address}\",\"to\":\"{contractAddress}\",\"gas\":\"0x31b2ef\", \"data\":\"{data}\"}}], \"id\":1}}"; //var answer = await Post.PostRequestAsync(req); //dynamic jsonDe = JsonConvert.DeserializeObject(answer); //Console.WriteLine("result " + answer); return answer; } public async Task GetTByHash(string transactionAddress) { string req = $"{{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionByHash\",\"params\":[\"{transactionAddress}\"],\"id\":1}}"; Console.WriteLine("GetTByHash " + req); return await Post.PostRequestAsync(this, req); } public async Task GetReceipt(string transactionAddress, bool returnAddress = false) { Console.WriteLine("transactionAddress " + transactionAddress); var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"{transactionAddress}\"], \"id\":1}}"; var answer = await Post.PostRequestAsync(this, req); dynamic jsonDe = JsonConvert.DeserializeObject(answer); if (jsonDe.result != null) { var blockHash = jsonDe.result.blockHash; var blockNumber = jsonDe.result.blockNumber; var contractAddress = jsonDe.result.contractAddress; await MySQLConnector.Instance().SQLInsert($"insert into transactions (result, name) values ('{Convert.ToString(jsonDe.result)}', 'eth_getTransactionReceipt')"); Console.WriteLine("result " + answer); if (returnAddress) return contractAddress; else return Convert.ToString(jsonDe.result); } else { Console.WriteLine("eth_getTransactionReceipt reuslt NULL " + transactionAddress); return null; } } //TODO add GAS!!! public async Task AddContract(string name, string code, string bytecode) { Console.WriteLine("bytecode " + bytecode); var gas = await GetEstimatedGasContractAdd(bytecode); var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"eth_sendTransaction\",\"params\":[{{\"from\":\"{address}\",\"gas\":\"{gas}\", \"data\":\"{bytecode}\"}}], \"id\":1}}"; var answer = await Post.PostRequestAsync(this, req); dynamic jsonDe = JsonConvert.DeserializeObject(answer); var res = jsonDe.result; Console.WriteLine("result AddContract transactionAddress: " + res); if (res != null) { SmartContract newctr = new SmartContract(name, code, bytecode, this.id, gas); if (gas == null) gas = "invalid"; long id = await MySQLConnector.Instance().SQLInsert($"insert into smart_contracts (code, bytecode, name, date_add, gas_cost, blockchain_id) values ('{code}','{bytecode}','{name}',NOW(), '{gas}', {this.id})"); newctr.ID = (int) id; contracts.Add((int)id, newctr); contractNames.Add(name, newctr); return new object[] { res, newctr }; } return null; } public async Task GetEstimatedGasTransaction(int weiAmount) { if (weiAmount > 0) { var ret = await RunFunction("eth_estimateGas", $"{{\"from\":\"{address}\",\"value\":\"{dec2hex(weiAmount)}\"}}"); Console.WriteLine("GetEstimatedGas " + ret); return ret; } return null; } public async Task GetEstimatedGasContractAdd(string bytecode) { var ret = await RunFunction("eth_estimateGas", $"{{\"from\":\"{address}\",\"data\":\"{bytecode}\"}}"); Console.WriteLine("GetEstimatedGasContractAdd " + ret); return ret; } public async Task GetAddress() { if (address == "") { address = await MySQLConnector.Instance().SQLSelectUUID("select address_main from blockchains where id="+id); } return address; //post запрос } } }