Blockchain.cs 43 KB

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