Blockchain.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. using System;
  2. using System.Diagnostics;
  3. using System.Text;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Drawing;
  7. using System.Drawing.Imaging;
  8. using System.Threading.Tasks;
  9. using Newtonsoft.Json;
  10. using Console = HyperCube.Utils.AdvConsole;
  11. using System.Text.RegularExpressions;
  12. using QRCoder;
  13. using System.IO;
  14. using Microsoft.AspNetCore.Components;
  15. //0xe5D682717955d6C35d465A3485625C64655a04f4 - HCB in rinkeby
  16. //0xb504ba124b74333d8536db534f7fcdc174d6ee3d - system address rinkeby
  17. //0x413D9500A675d9b645034aC5f4325BF12ddeb7c1 bitcoin
  18. namespace HyperCube.Models
  19. {
  20. public struct TransactionObject
  21. {
  22. public string from;
  23. public string to;
  24. public string data;
  25. public string gas;
  26. public string value;
  27. }
  28. public class Blockchain
  29. {
  30. [Inject]
  31. AppData AppData { get; set; }
  32. public static Blockchain Dev
  33. {
  34. get {
  35. return loaded[0];
  36. }
  37. set { }
  38. }
  39. public static string tokenName;
  40. public static string decimals;
  41. public static string symbol;
  42. public static string tokenBalance;
  43. public static string balanceHCB;
  44. public static Dictionary<int, Blockchain> supported;
  45. //public static string Connected
  46. //{
  47. // get
  48. // {
  49. // var bc = AppData.CurrentAccount.GetSelectedBlockChain(); //acc selected
  50. // if (bc != null)
  51. // return $"{bc.name}";
  52. // return "none";
  53. // }
  54. //}
  55. public static string URLdefault = "127.0.0.1";
  56. //public static int defaultPort = 8545;
  57. public static int defaultPort = 8666;
  58. public static string defaultName = "Ethereum dev network";
  59. public static bool blockChainsInitialized = false;
  60. public static Dictionary<int, Blockchain> loaded = new();
  61. public Dictionary<int, SmartContract> contracts = new();
  62. public Dictionary<string, SmartContract> contractNames = new();
  63. public int id;
  64. public int port;
  65. public string url;
  66. public string address = "";
  67. public string name;
  68. public string balance;
  69. static Blockchain instance;
  70. public async static Task RegisterNetworks()
  71. {
  72. if (!blockChainsInitialized)
  73. {
  74. Console.WriteLine($"RegisterNetworks");
  75. var ethDev = new Blockchain(0, "Ethereum Dev Network", "127.0.0.1", 8545);
  76. var ethRinkeby = new Blockchain(1, "Ethereum Test Network", "127.0.0.1", 8666);
  77. await ethDev.Initialize();
  78. await ethRinkeby.Initialize();
  79. blockChainsInitialized = true;
  80. }
  81. }
  82. public static Blockchain Find(int id)
  83. {
  84. if (loaded.ContainsKey(id))
  85. return loaded[id];
  86. return null;
  87. }
  88. public async Task<string> GetBalanceToken(string contractAddress, string address)
  89. {
  90. TransactionObject transObj = new TransactionObject();
  91. transObj.to = contractAddress;
  92. //compile data
  93. //to.data = await compileFunction("decimals");
  94. //transObj.data = await compileFunction("name");
  95. //var answer = await RunFunction2("eth_call", transObj, "latest");
  96. ////Console.WriteLine("ImportERC20 len "+ answer.Length + " answer " + answer);
  97. //var parsed = ParseStringAnswer(answer);
  98. //int tokenlen = hex2dec(parsed[1]);
  99. //tokenName = HextoString(parsed[2]).Substring(0, tokenlen);
  100. //to.data = await compileFunction("balanceOf(address)");
  101. transObj.data = await compileFunction("symbol");
  102. var answer = await RunFunction2("eth_call", transObj, "latest");
  103. var parsed = ParseStringAnswer(answer);
  104. if (parsed.Length == 0)
  105. return null;
  106. int symlen = hex2dec(parsed[1]);
  107. symbol = HextoString(parsed[2]).Substring(0, symlen);
  108. //Console.WriteLine("ImportERC20 len " + answer.Length + " answer " + answer);
  109. transObj.data = await compileFunction("decimals");
  110. answer = await RunFunction2("eth_call", transObj, "latest");
  111. decimals = hex2dec(ParseStringAnswer(answer)[0]).ToString();
  112. transObj.data = await compileFunction($"function balanceOf(address account)");
  113. if (address != null)
  114. transObj.data += zerofill(address, 64, true);
  115. //answer = await RunFunction2("eth_call", to, AccountModel.Current.GetActualAddress(this));
  116. answer = await RunFunction2("eth_call", transObj, "latest");
  117. balanceHCB = ((double)AccountModel.ConvertBalance(ParseStringAnswer(answer)[0]) / 1000000000000000000.0).ToString();
  118. return null;
  119. }
  120. public async Task<string> Initialize()
  121. {
  122. if (!loaded.ContainsKey(id))
  123. loaded.Add(id, this);
  124. Console.WriteLine($"Initialize: {name}, loaded blockchains " + loaded.Count);
  125. string addr = await ListAccounts();
  126. await LoadContracts();
  127. Console.WriteLine("LoadContracts count " + contracts.Count);
  128. //Console.WriteLine("connected " + Connected);
  129. return $"{name} {url}:{port}";
  130. }
  131. public async Task ChangeOwner(string ERC20Address, string contractAddress)
  132. {
  133. TransactionObject transObj = new TransactionObject();
  134. transObj.from = address;
  135. transObj.to = ERC20Address;// "0xe5D682717955d6C35d465A3485625C64655a04f4";
  136. transObj.gas = "9000";
  137. transObj.value = contractAddress;
  138. transObj.data = await compileFunction($"function transferOwnership(address newOwner)");
  139. var answer = await RunFunction2("eth_sendTransaction", transObj);
  140. }
  141. public async Task<string> Verify(AccountModel verifier, ArticleModel article)
  142. {
  143. Console.WriteLine($"Verify starting");
  144. try
  145. {
  146. var bc = await verifier.GetSelectedBlockChain();
  147. VerifyContract verifyContract = SmartContract.Find("Verify", bc) as VerifyContract;
  148. if (verifyContract != null)
  149. {
  150. Console.WriteLine($"VerifyContract found");
  151. var transactionId = await verifyContract.Run(verifier, article);
  152. return transactionId;
  153. }
  154. else
  155. Console.WriteLine($"VerifyContract null");
  156. }
  157. catch (Exception e)
  158. {
  159. Console.WriteLine(e.Message + "stack trace" + e.StackTrace);
  160. }
  161. return "Verify failed";
  162. }
  163. public static string dec2hex(int decValue, bool prefix = true)
  164. {
  165. string hexValue = decValue.ToString("X");
  166. if (prefix)
  167. hexValue = "0x" + hexValue;
  168. return hexValue;
  169. }
  170. public static int hex2dec(string hexValue)
  171. {
  172. return Convert.ToInt32(hexValue, 16);
  173. }
  174. //public static Blockchain GetInstance()
  175. //{
  176. // if (instance == null)
  177. // instance = new Blockchain(URLdefault, defaultPort);
  178. // return instance;
  179. //}
  180. //Blockchain()
  181. //{
  182. //}
  183. public Blockchain(int id, string name, string url, int port)
  184. {
  185. this.id = id;
  186. this.url = url;
  187. this.port = port;
  188. this.name = name;
  189. }
  190. public async Task<string> CreateBlockchainAccount(AccountModel account, string pass)
  191. {
  192. Console.WriteLine($"Run CreateBlockchainAccount {account}");
  193. var res = await RunFunction("personal_newAccount", $"\"{pass}\"");
  194. string query;
  195. if (account != null)
  196. {
  197. Console.WriteLine($"CreateBlockchainAccount {account}: {res}");
  198. //query = $"update aspnetusers set eth_address='{res}' where UserName='{account.Name}'";
  199. var addr = account.GetActualAddress(this);
  200. if (addr == null)
  201. query = $"insert into account_wallets (uuid, blockchain_id, account_uuid, password_plain) values ('{res}',{id},'{account.UUID}','{account.PWDHash}')";
  202. else
  203. query = $"update account_wallets set uuid='{res}', password_plain='{account.PWDHash}' where account_uuid='{account.UUID}' and blockchain_id={id}";
  204. account.SetActualAddress(res, this);
  205. Console.WriteLine($"CreateBlockchainAccount query {query}");
  206. await MySQLConnector.Instance().SQLInsert(query);
  207. }
  208. else
  209. Console.WriteLine($"CreateBlockchainAccount {id}: {res}");
  210. address = res;
  211. if (account == null)
  212. {
  213. query = $"update blockchains set address_main='{res}' where id={id}";
  214. Console.WriteLine($"CreateBlockchainAccount query {query}");
  215. await MySQLConnector.Instance().SQLInsert(query);
  216. }
  217. return res;
  218. }
  219. public static string hex2bin(string hexstring)
  220. {
  221. string binarystring = String.Join(String.Empty, hexstring.Select( c => Convert.ToString(Convert.ToInt32(c.ToString(), 16), 2).PadLeft(4, '0') ));
  222. Console.WriteLine("bin " + binarystring);
  223. return binarystring;
  224. }
  225. public static string bin2hex(string code)
  226. {
  227. //code = "0x".bin2hex('getCount()');
  228. var bytes = Encoding.UTF8.GetBytes(code);
  229. var hex = BitConverter.ToString(bytes).Replace("-", "");
  230. Console.WriteLine("hex " + hex);
  231. return "0x" + hex;
  232. }
  233. public static string zerofill(string hex, int charCount, bool hexPrefix0x)
  234. {
  235. if (hexPrefix0x)
  236. hex = hex.Remove(0, 2);
  237. Console.WriteLine($"zerofill input {hex} count {hex.Length}");
  238. var res = hex.PadLeft(charCount, '0');
  239. Console.WriteLine($"zerofill out {hex} count {res.Length}");
  240. return res;
  241. }
  242. public async Task<string> ListAccounts()
  243. {
  244. Console.WriteLine($"ListAccounts blockchain {id}");
  245. string answer = "no";
  246. //{ "jsonrpc":"2.0","method":"eth_getCode","params":["0x938cae6f6c21ed9d55196e96ef880f562e530553", "latest" ],"id":1}
  247. //string req = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getCode\",\"params\":[\"0x874c6a51e62680d4594cd2555ed8fa47b63ed253\",\"latest\"],\"id\":1}";
  248. string req = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_accounts\", \"params\":[],\"id\":1}";
  249. answer = await Post.PostRequestAsync(this, req);
  250. //string json = Encoding.UTF8.GetString(bytedata, 1, bytedata.Length - 1);
  251. //try
  252. //{
  253. Console.WriteLine("Json string " + answer);
  254. dynamic jsonDe = JsonConvert.DeserializeObject(answer);
  255. var res = (Newtonsoft.Json.Linq.JArray)jsonDe.result;
  256. if (res.Count > 0 && id == 0) //Dev
  257. {
  258. address = jsonDe.result[0];
  259. }
  260. else
  261. {
  262. address = await GetAddress();
  263. if (address == "" || address == null)
  264. address = await CreateEthAddress("test_Password_212");
  265. }
  266. var query = $"update blockchains set address_main='{address}' where id={id}";
  267. Console.WriteLine("query " + query);
  268. await MySQLConnector.Instance().SQLInsert(query);
  269. Console.WriteLine("Json addr " + jsonDe.result[0]);
  270. return address;
  271. }
  272. public async Task<string> CreateEthAddress(string pass)
  273. {
  274. return await CreateBlockchainAccount(null, pass);
  275. }
  276. public async Task LoadContracts()
  277. {
  278. MySQLConnector dbCon = MySQLConnector.Instance();
  279. contracts = await dbCon.SQLSelectContracts(id);
  280. foreach (var contract in contracts.Values)
  281. {
  282. await contract.LoadFunction();
  283. }
  284. }
  285. public async Task<string> GetSHA3(string code)
  286. {
  287. var hex = bin2hex(code);
  288. var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"web3_sha3\",\"params\":[\"{hex}\"], \"id\":1}}";
  289. var answer = await Post.PostRequestAsync(this, req);
  290. dynamic jsonDe = JsonConvert.DeserializeObject(answer);
  291. Console.WriteLine("result " + jsonDe.result);
  292. return jsonDe.result;
  293. }
  294. public async Task<string> GetBalance(AccountModel account)
  295. {
  296. var addr = await account.GetOrCreateActualAddress(this);
  297. //var ret = await RunFunction("eth_getBalance", $"\"{addr}\",\"latest\"");
  298. Console.WriteLine($"GetBalance AccountModel addr {addr}");
  299. return await GetBalance(addr);
  300. }
  301. public async Task<string> GetBalance()
  302. {
  303. return await GetBalance(address);
  304. }
  305. //eth.getBalance('0xb504ba124b74333D8536DB534F7fcdC174d6Ee3d')
  306. public async Task<string> GetBalance(string address)
  307. {
  308. var ret = await RunFunction("eth_getBalance", $"\"{address}\",\"latest\"");
  309. var balanceWei = AccountModel.ConvertBalance(ret);
  310. var balanceToken = (double)balanceWei / 1000000000000000000.0;
  311. Console.WriteLine($"GetBalance balanceToken {balanceToken}");
  312. balance = balanceToken.ToString();
  313. return balance;
  314. }
  315. public async Task<string> RunFunction(string name, string parms)
  316. {
  317. Console.WriteLine($"RunFunction {name} params {parms}");
  318. var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"{name}\",\"params\":[{parms}], \"id\":1}}";
  319. var answer = await Post.PostRequestAsync(this, req);
  320. dynamic jsonDe = JsonConvert.DeserializeObject(answer);
  321. Console.WriteLine("RunFunction result " + jsonDe.result);
  322. return jsonDe.result;
  323. //return "test answer";
  324. }
  325. public async Task<string> RunFunction2(string name, TransactionObject to, string defaultBlock = null)
  326. {
  327. //транзакция добавления контракта 0x00bdbf1571aa69a2cf8c8c7913a01eaca3a4b7e5e7e49fc787cb81c0df2c2682
  328. Dictionary<string, string> paramDict = new Dictionary<string, string>();
  329. string parms = "{";
  330. if (to.from != null)
  331. paramDict["from"] = to.from;
  332. if (to.to != null)
  333. paramDict["to"] = to.to;
  334. if (to.data != null)
  335. {
  336. paramDict["data"] = "0x"+to.data;
  337. }
  338. int count = 0;
  339. foreach (var p in paramDict)
  340. {
  341. parms += $"\"{p.Key}\":\"{p.Value}\"";
  342. count++;
  343. if (paramDict.Count > count)
  344. {
  345. parms += ",";
  346. }
  347. }
  348. parms += "}";
  349. if (defaultBlock != null)
  350. parms += $", \"{defaultBlock}\"";
  351. Console.WriteLine($"RunFunction {name} params {parms} active bc: {this.address}");
  352. var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"{name}\",\"params\":[{parms}], \"id\":1}}";
  353. var answer = await Post.PostRequestAsync(this, req);
  354. dynamic jsonDe = JsonConvert.DeserializeObject(answer);
  355. Console.WriteLine("RunFunction result " + jsonDe.result);
  356. return jsonDe.result;
  357. //return "test answer";
  358. }
  359. public static string QRtest(string input)
  360. {
  361. QRCodeGenerator qrGenerator = new QRCodeGenerator();
  362. QRCodeData qrCodeData = qrGenerator.CreateQrCode(input, QRCodeGenerator.ECCLevel.Q);
  363. QRCode qrCode = new QRCode(qrCodeData);
  364. Bitmap qrCodeImage = qrCode.GetGraphic(7);
  365. //Image img = qrCodeImage;
  366. MemoryStream ms = new MemoryStream();
  367. BinaryWriter bw = new BinaryWriter(ms);
  368. //var fulltexname = Encoding.UTF8.GetBytes("http://" + myHostName + "/" + filename);
  369. //bw.Write(loc_id);
  370. //bw.Write(fulltexname);
  371. //return base64String;
  372. qrCodeImage.Save(ms, ImageFormat.Png);
  373. byte[] imageBytes = ms.ToArray();
  374. string base64String = Convert.ToBase64String(imageBytes);
  375. Console.WriteLine($"base64String {base64String}");
  376. return base64String;
  377. //Image.FromStream(ms);
  378. }
  379. public static List<string> ExecuteCommand(string cmd)
  380. {
  381. List<string> output = new List<string>();
  382. var processInfo = new ProcessStartInfo(@"e:\www\nodejs\test.bat", cmd );
  383. processInfo.CreateNoWindow = true;
  384. processInfo.UseShellExecute = false;
  385. processInfo.RedirectStandardError = true;
  386. processInfo.RedirectStandardOutput = true;
  387. var process = Process.Start(processInfo);
  388. process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Echo(e.Data, ref output);
  389. process.BeginOutputReadLine();
  390. process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
  391. Console.WriteLine("error>>" + e.Data);
  392. process.BeginErrorReadLine();
  393. process.WaitForExit();
  394. Console.WriteLine($"ExitCode: {process.ExitCode}");
  395. num = 0;
  396. process.Close();
  397. return output;
  398. }
  399. static int num = 0;
  400. static void Echo(string msg, ref List<string> output)
  401. {
  402. //if (num > 0)
  403. if (msg != null && msg.Length > 0)
  404. {
  405. Console.WriteLine("output >>" + msg);
  406. output.Add(msg);
  407. }
  408. num++;
  409. }
  410. async Task<string> mySHA3(string code)
  411. {
  412. var res = await GetSHA3(code);
  413. Console.WriteLine($"GetSHA3 {code} {res}");
  414. var ret = res.Substring(2, 8);
  415. return ret;
  416. }
  417. public async Task<string> compileFunction(string input, bool getsha = true)
  418. {
  419. //\s = пробел
  420. //\S = любой символ, кроме промельного
  421. //+ одно или более вхождений
  422. //. любой сивол, кроме перевода строки
  423. //* ноль или более вхождений «а»
  424. //скобки без экранирования = группы
  425. //function transfer(address recipient, uint256 amount)
  426. string pattern = @"function\s+(\S+)\s*\((.*)\).*";
  427. string replacement_name = "$1"; //номер найденной группы
  428. string replacement_params = "$2";
  429. string resultname = Regex.Replace(input, pattern, replacement_name).Trim();
  430. string param_pattern = @"(uint8|address|uint256)";
  431. string final = resultname + "(";
  432. if (input != resultname)
  433. {
  434. string resultparams = Regex.Replace(input, pattern, replacement_params).Trim();
  435. if (input != resultparams)
  436. {
  437. int i = 0;
  438. foreach (Match match in Regex.Matches(resultparams, param_pattern))
  439. {
  440. if (i > 0)
  441. final += "," + match.Value;
  442. else
  443. final += match.Value;
  444. i++;
  445. }
  446. }
  447. }
  448. string function_processed = final + ")";
  449. Console.WriteLine($"function_processed {function_processed}");
  450. if (getsha)
  451. {
  452. function_processed = await mySHA3(function_processed);
  453. }
  454. return function_processed;
  455. }
  456. //public double UInt256Conv(string input)
  457. //{
  458. // System.Numerics.BigInteger bigint1 = System.Numerics.BigInteger.Parse("329974300448100608374211110737048701521");
  459. // System.Numerics.BigInteger bigint2 = new System.Numerics.BigInteger(18);
  460. // return bigint1 / 18.0;
  461. //}
  462. public static string HextoString(string InputText)
  463. {
  464. byte[] bb = Enumerable.Range(0, InputText.Length)
  465. .Where(x => x % 2 == 0)
  466. .Select(x => Convert.ToByte(InputText.Substring(x, 2), 16))
  467. .ToArray();
  468. //return System.Text.Encoding.ASCII.GetString(bb);
  469. // or System.Text.Encoding.UTF7.GetString
  470. return System.Text.Encoding.UTF8.GetString(bb);
  471. // or System.Text.Encoding.Unicode.GetString
  472. // or etc.
  473. }
  474. public string[] ParseStringAnswer(string answer)
  475. {
  476. var ret = new string[] { };
  477. if (answer.Length > 2)
  478. {
  479. answer = answer.Substring(2, answer.Length - 2);
  480. int words = answer.Length / 64;
  481. ret = new string[words];
  482. for (int i = 0; i < words; i++)
  483. {
  484. var word = answer.Substring(i * 64, 64);
  485. ret[i] = word;
  486. Console.WriteLine($"word {i} {word}");
  487. Console.WriteLine($"str {i} {HextoString(word)}");
  488. var testbalance1 = (double)(AccountModel.ConvertBalance(word)/ 1000000000000000000);
  489. var testbalance2 = ((double)AccountModel.ConvertBalance(word) / 1000000000000000000.0);
  490. Console.WriteLine($"testbalance1 {testbalance1} testbalance2 {testbalance2} ");
  491. }
  492. }
  493. return ret;
  494. }
  495. //верификация запускает запрос на минт/перевод токенов от системы
  496. //количество вычисляется по конечной ценности, переданной в смарт и курсу к $$$$???
  497. //комиссия владельцам
  498. //4. Рабочий стол. Верификация
  499. //7. Календарь событий - тут добавление мероприятия запускает транзакции спонсирования
  500. //8. Персональные данные - роль
  501. //13. Цифровые активы
  502. //14. Блокчейн
  503. //накапать токенов эксперту и автору материала
  504. //0. делаем новый контракт с массивом ролей
  505. //1. делаем в нем управляющий код с подтверждениями на выпуск токенов
  506. //2. в рамках текущего токена - делаем овнером токена мульти контракт с ролями
  507. //3. этим же контрактом запускаем verify и другие контракты - функции
  508. //4. что должен фиксировать Verify?
  509. //5. как и где определять параметры запускаемых функций во внешних контрактах
  510. //6. определение курса токенов
  511. public async Task Mint(string tokenAmount, string addressTo)
  512. {
  513. //mint(address to, uint256 amount)
  514. TransactionObject transObj = new TransactionObject();
  515. transObj.from = address;
  516. transObj.to = "0xe5D682717955d6C35d465A3485625C64655a04f4";
  517. transObj.gas = "9000";
  518. transObj.value = tokenAmount;
  519. transObj.data = await compileFunction($"function mint(address to, uint256 amount)");
  520. if (addressTo != null && tokenAmount != null)
  521. {
  522. transObj.data += zerofill(addressTo, 64, true);
  523. transObj.data += zerofill(dec2hex(Convert.ToInt32(tokenAmount)), 64, true);
  524. }
  525. var answer = await RunFunction2("eth_sendTransaction", transObj);
  526. }
  527. public async Task TransferToken(string sender, string tokenContract, string addressTo, string tokenAmount)
  528. {
  529. //transfer(address recipient, uint256 amount)
  530. TransactionObject transObj = new TransactionObject();
  531. transObj.from = sender;
  532. transObj.to = tokenContract;
  533. transObj.gas = "9000";
  534. transObj.value = tokenAmount;
  535. transObj.data = await compileFunction($"function transfer(address recipient, uint256 amount)");
  536. if (addressTo != null && tokenAmount != null)
  537. {
  538. transObj.data += zerofill(addressTo, 64, true);
  539. transObj.data += zerofill(dec2hex(Convert.ToInt32(tokenAmount)), 64, true);
  540. }
  541. var answer = await RunFunction2("eth_sendTransaction", transObj);
  542. }
  543. public async Task ImportERC20(string contractAddress, string importAddress)
  544. {
  545. //"0xb504ba124b74333D8536DB534F7fcdC174d6Ee3d"
  546. //var gbh = await GetTByHash("0x00bdbf1571aa69a2cf8c8c7913a01eaca3a4b7e5e7e49fc787cb81c0df2c2682");
  547. //Console.WriteLine("GetTByHash " + gbh );
  548. //runfunction balanceOf totalSupply symbol name
  549. //RunContractRead
  550. TransactionObject transObj = new TransactionObject();
  551. transObj.to = contractAddress;
  552. //compile data
  553. //to.data = await compileFunction("decimals");
  554. transObj.data = await compileFunction("name");
  555. var answer = await RunFunction2("eth_call", transObj, "latest");
  556. //Console.WriteLine("ImportERC20 len "+ answer.Length + " answer " + answer);
  557. var parsed = ParseStringAnswer(answer);
  558. int tokenlen = hex2dec(parsed[1]);
  559. tokenName = HextoString(parsed[2]).Substring(0,tokenlen);
  560. //to.data = await compileFunction("balanceOf(address)");
  561. transObj.data = await compileFunction("symbol");
  562. answer = await RunFunction2("eth_call", transObj, "latest");
  563. parsed = ParseStringAnswer(answer);
  564. int symlen = hex2dec(parsed[1]);
  565. symbol = HextoString(parsed[2]).Substring(0, symlen);
  566. //Console.WriteLine("ImportERC20 len " + answer.Length + " answer " + answer);
  567. transObj.data = await compileFunction("decimals");
  568. answer = await RunFunction2("eth_call", transObj, "latest");
  569. decimals = hex2dec(ParseStringAnswer(answer)[0]).ToString();
  570. transObj.data = await compileFunction($"function balanceOf(address account)");
  571. if (address != null)
  572. transObj.data += zerofill(importAddress, 64, true);
  573. //answer = await RunFunction2("eth_call", to, AccountModel.Current.GetActualAddress(this));
  574. answer = await RunFunction2("eth_call", transObj, "latest");
  575. tokenBalance = ((double)AccountModel.ConvertBalance(ParseStringAnswer(answer)[0]) / 1000000000000000000.0).ToString();
  576. }
  577. public async void RunContractRead()
  578. {
  579. string answer = "no";
  580. string req = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"to\":\"0x874c6a51e62680d4594cd2555ed8fa47b63ed253\", \"data\":\"0xa87d942c\"},\"latest\"],\"id\":1}";
  581. //string req = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x0000000000000000000000000000000000000000000000000000000000000004\"}";
  582. //Console.WriteLine($"req " + req);
  583. await Post.PostRequestAsync(this, req);
  584. //Console.WriteLine($"answer {answer} len {answer.Length}" );
  585. address = answer;
  586. }
  587. public async Task<string> SendTransaction(string fromAddress, string toAddress, int wei)
  588. {
  589. var sum = dec2hex(wei);
  590. var gas = await GetEstimatedGasTransaction(wei);
  591. Console.WriteLine($"SendTransaction from {fromAddress} to {toAddress} sum {sum}");
  592. var answer = await RunFunction("eth_sendTransaction", $"{{\"from\":\"{address}\",\"to\":\"{toAddress}\",\"gas\":\"{gas}\", \"data\":\"\", \"value\":\"{sum}\"}}");
  593. return answer;
  594. }
  595. //{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{ "from":"0xD81eeE6b39d9556c3067A3551A3FB2882b92F327", "to":"0x119b58faddcdbc09cafcd272530aa079cec10004", "gas":"0x31b2ef", "data":"0x11111111"}], "id":1}
  596. public async Task<string> RunContractWrite(string contractAddress, string data, string gas, string value)
  597. {
  598. Console.WriteLine("RunContract contractAddress " + contractAddress);
  599. var answer = await RunFunction("eth_sendTransaction", $"{{\"from\":\"{address}\",\"to\":\"{contractAddress}\",\"gas\":\"{gas}\", \"data\":\"{data}\", \"value\":\"{value}\"}}");
  600. //$"{{ \"jsonrpc\":\"2.0\",\"method\":\"eth_sendTransaction\",\"params\":[{{\"from\":\"{address}\",\"to\":\"{contractAddress}\",\"gas\":\"0x31b2ef\", \"data\":\"{data}\"}}], \"id\":1}}";
  601. //var answer = await Post.PostRequestAsync(req);
  602. //dynamic jsonDe = JsonConvert.DeserializeObject(answer);
  603. //Console.WriteLine("result " + answer);
  604. return answer;
  605. }
  606. public async Task<string> GetTByHash(string transactionAddress)
  607. {
  608. string req = $"{{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionByHash\",\"params\":[\"{transactionAddress}\"],\"id\":1}}";
  609. Console.WriteLine("GetTByHash " + req);
  610. return await Post.PostRequestAsync(this, req);
  611. }
  612. public async Task<string> GetReceipt(string transactionAddress, bool returnAddress = false)
  613. {
  614. Console.WriteLine("transactionAddress " + transactionAddress);
  615. var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"{transactionAddress}\"], \"id\":1}}";
  616. var answer = await Post.PostRequestAsync(this, req);
  617. dynamic jsonDe = JsonConvert.DeserializeObject(answer);
  618. if (jsonDe.result != null)
  619. {
  620. var blockHash = jsonDe.result.blockHash;
  621. var blockNumber = jsonDe.result.blockNumber;
  622. var contractAddress = jsonDe.result.contractAddress;
  623. await MySQLConnector.Instance().SQLInsert($"insert into transactions (result, name) values ('{Convert.ToString(jsonDe.result)}', 'eth_getTransactionReceipt')");
  624. Console.WriteLine("result " + answer);
  625. if (returnAddress)
  626. return contractAddress;
  627. else
  628. return Convert.ToString(jsonDe.result);
  629. }
  630. else
  631. {
  632. Console.WriteLine("eth_getTransactionReceipt reuslt NULL " + transactionAddress);
  633. return null;
  634. }
  635. }
  636. //TODO add GAS!!!
  637. public async Task<object[]> AddContract(string name, string code, string bytecode)
  638. {
  639. Console.WriteLine("bytecode " + bytecode);
  640. var gas = await GetEstimatedGasContractAdd(bytecode);
  641. var req = $"{{ \"jsonrpc\":\"2.0\",\"method\":\"eth_sendTransaction\",\"params\":[{{\"from\":\"{address}\",\"gas\":\"{gas}\", \"data\":\"{bytecode}\"}}], \"id\":1}}";
  642. var answer = await Post.PostRequestAsync(this, req);
  643. dynamic jsonDe = JsonConvert.DeserializeObject(answer);
  644. var res = jsonDe.result;
  645. Console.WriteLine("result AddContract transactionAddress: " + res);
  646. if (res != null)
  647. {
  648. SmartContract newctr = new SmartContract(name, code, bytecode, this.id, gas);
  649. if (gas == null)
  650. gas = "invalid";
  651. 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})");
  652. newctr.ID = (int) id;
  653. contracts.Add((int)id, newctr);
  654. contractNames.Add(name, newctr);
  655. return new object[] { res, newctr };
  656. }
  657. return null;
  658. }
  659. public async Task<string> GetEstimatedGasTransaction(int weiAmount)
  660. {
  661. if (weiAmount > 0)
  662. {
  663. var ret = await RunFunction("eth_estimateGas", $"{{\"from\":\"{address}\",\"value\":\"{dec2hex(weiAmount)}\"}}");
  664. Console.WriteLine("GetEstimatedGas " + ret);
  665. return ret;
  666. }
  667. return null;
  668. }
  669. public async Task<string> GetEstimatedGasContractAdd(string bytecode)
  670. {
  671. var ret = await RunFunction("eth_estimateGas", $"{{\"from\":\"{address}\",\"data\":\"{bytecode}\"}}");
  672. Console.WriteLine("GetEstimatedGasContractAdd " + ret);
  673. return ret;
  674. }
  675. public async Task<string> GetAddress()
  676. {
  677. if (address == "")
  678. {
  679. address = await MySQLConnector.Instance().SQLSelectUUID("select address_main from blockchains where id="+id);
  680. }
  681. return address;
  682. //post запрос
  683. }
  684. }
  685. }