// Note: This current implementation requires NeoScan running at port 4000 public override List <UnspentEntry> GetClaimable(UInt160 hash, out decimal amount) { var url = this.neoscanUrl + "/api/main_net/v1/get_claimable/" + hash.ToAddress(); var json = RequestUtils.GetWebRequest(url); var root = LunarLabs.Parser.JSON.JSONReader.ReadFromString(json); var result = new List <UnspentEntry>(); amount = root.GetDecimal("unclaimed"); root = root["claimable"]; foreach (var child in root.Children) { var txid = child.GetString("txid"); var index = child.GetUInt32("n"); var value = child.GetDecimal("unclaimed"); result.Add(new UnspentEntry() { hash = new UInt256(LuxUtils.ReverseHex(txid).HexToBytes()), index = index, value = value }); } return(result); }
// Note: This current implementation requires NeoScan running at port 4000 public override Dictionary <string, List <UnspentEntry> > GetUnspent(UInt160 hash) { var url = this.neoscanUrl + "/api/main_net/v1/get_balance/" + hash.ToAddress(); var json = RequestUtils.GetWebRequest(url); var root = LunarLabs.Parser.JSON.JSONReader.ReadFromString(json); var unspents = new Dictionary <string, List <UnspentEntry> >(); root = root["balance"]; foreach (var child in root.Children) { var symbol = child.GetString("asset"); List <UnspentEntry> list = new List <UnspentEntry>(); unspents[symbol] = list; var unspentNode = child.GetNode("unspent"); foreach (var entry in unspentNode.Children) { var txid = entry.GetString("txid"); var val = entry.GetDecimal("value"); var temp = new UnspentEntry() { hash = new UInt256(LuxUtils.ReverseHex(txid).HexToBytes()), value = val, index = entry.GetUInt32("n") }; list.Add(temp); } } return(unspents); }
public static string SymbolFromAssetID(byte[] assetID) { var str = assetID.ByteToHex(); var result = SymbolFromAssetID(str); if (result == null) { result = SymbolFromAssetID(LuxUtils.ReverseHex(str)); } return(result); }
public static byte[] GetAssetID(string symbol) { var info = GetAssetsInfo(); foreach (var entry in info) { if (entry.Key == symbol) { return(LuxUtils.ReverseHex(entry.Value).HexToBytes()); } } return(null); }
protected override InteropTransaction PullPlatformTransaction(string platformName, string chainName, Hash hash) { logger.Debug($"{platformName} pull tx: {hash}"); InteropTransaction tx = Read <InteropTransaction>(platformName, chainName, hash, StorageConst.Transaction); if (tx != null && tx.Hash != null) { logger.Debug($"Found tx {hash} in oracle storage"); return(tx); } switch (platformName) { case NeoWallet.NeoPlatform: NeoTx neoTx; UInt256 uHash = new UInt256(LuxUtils.ReverseHex(hash.ToString()).HexToBytes()); neoTx = _cli.NeoAPI.GetTransaction(uHash); var coldStorage = _cli.Settings.Oracle.SwapColdStorageNeo; tx = NeoInterop.MakeInteropTx(logger, neoTx, _cli.NeoAPI, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Neo], coldStorage); break; case EthereumWallet.EthereumPlatform: { var txRcpt = _cli.EthAPI.GetTransactionReceipt(hash.ToString()); tx = EthereumInterop.MakeInteropTx(_cli.Nexus, logger, txRcpt, _cli.EthAPI, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Ethereum]); break; } case BSCWallet.BSCPlatform: { var txRcpt = _cli.BscAPI.GetTransactionReceipt(hash.ToString()); tx = BSCInterop.MakeInteropTx(_cli.Nexus, logger, txRcpt, _cli.BscAPI, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.BSC]); break; } default: throw new OracleException("Uknown oracle platform: " + platformName); } if (!Persist <InteropTransaction>(platformName, chainName, tx.Hash, StorageConst.Transaction, tx)) { logger.Error($"Oracle transaction { hash } on platform { platformName } updated!"); } return(tx); }
public void GenerateInputsOutputs(UInt160 key, string symbol, IEnumerable <Transaction.Output> targets, out List <Transaction.Input> inputs, out List <Transaction.Output> outputs, decimal system_fee = 0) { var info = GetAssetsInfo(); var targetAssetID = LuxUtils.ReverseHex(info[symbol]).HexToBytes(); if (targets != null) { foreach (var t in targets) { if (t.assetID == null) { t.assetID = targetAssetID; } } } // else Console.WriteLine("ASSETID target already existed: " + symbol); GenerateInputsOutputs(key, targets, out inputs, out outputs, system_fee); }
private string ConvertArray(string s) { if (DebuggerUtils.IsHex(s)) { var bytes = s.HexToBytes(); s = DebuggerUtils.BytesToString(bytes); } else if (DebuggerUtils.IsValidWallet(s)) { var scriptHash = s.AddressToScriptHash(); s = DebuggerUtils.BytesToString(LuxUtils.ReverseHex(scriptHash.ByteToHex()).HexToBytes()); } else { return(null); } return(s); }
protected override InteropBlock PullPlatformBlock(string platformName, string chainName, Hash hash, NativeBigInt height = new NativeBigInt()) { if (hash == null && height == null) { throw new OracleException($"Fetching block not possible without hash or height"); } InteropBlock block = Read <InteropBlock>(platformName, chainName, hash, StorageConst.Block); if (height == null && block.Hash != null && block.Hash != Hash.Null) { return(block); } Tuple <InteropBlock, InteropTransaction[]> interopTuple; switch (platformName) { case NeoWallet.NeoPlatform: NeoBlock neoBlock; if (height == 0) { neoBlock = _cli.NeoAPI.GetBlock(new UInt256(LuxUtils.ReverseHex(hash.ToString()).HexToBytes())); } else { neoBlock = _cli.NeoAPI.GetBlock(height); } if (neoBlock == null) { throw new OracleException($"Neo block is null"); } interopTuple = NeoInterop.MakeInteropBlock(logger, neoBlock, _cli.NeoAPI, _cli.TokenSwapper.SwapAddresses[platformName]); break; case EthereumWallet.EthereumPlatform: //BlockWithTransactions ethBlock; //if (height == 0) //{ // //TODO MakeInteropBlock for a full block not done yet // //ethBlock = _cli.EthAPI.GetBlock(hash.ToString()); // //interopTuple = EthereumInterop.MakeInteropBlock(logger, ethBlock, _cli.EthAPI, _cli.TokenSwapper.swapAddress); //} //else //{ //} var hashes = _cli.Nexus.GetPlatformTokenHashes(EthereumWallet.EthereumPlatform, _cli.Nexus.RootStorage) .Select(x => x.ToString().Substring(0, 40)).ToArray(); interopTuple = EthereumInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.EthAPI, height, hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[platformName]); break; default: throw new OracleException("Uknown oracle platform: " + platformName); } if (interopTuple.Item1.Hash != Hash.Null) { var persisted = Persist <InteropBlock>(platformName, chainName, interopTuple.Item1.Hash, StorageConst.Block, interopTuple.Item1); if (persisted) { var transactions = interopTuple.Item2; foreach (var tx in transactions) { var txPersisted = Persist <InteropTransaction>(platformName, chainName, tx.Hash, StorageConst.Transaction, tx); } } else { logger.Error($"Persisting oracle block { interopTuple.Item1.Hash } on platform { platformName } failed!"); } } return(interopTuple.Item1); }
public Transaction GetTransaction(string hash) { var val = new UInt256(LuxUtils.ReverseHex(hash).HexToBytes()); return(GetTransaction(val)); }
public void GenerateInputsOutputs(UInt160 from_script_hash, IEnumerable <Transaction.Output> targets, out List <Transaction.Input> inputs, out List <Transaction.Output> outputs, decimal system_fee = 0) { var unspent = GetUnspent(from_script_hash); // filter any asset lists with zero unspent inputs unspent = unspent.Where(pair => pair.Value.Count > 0).ToDictionary(pair => pair.Key, pair => pair.Value); inputs = new List <Transaction.Input>(); outputs = new List <Transaction.Output>(); var from_address = from_script_hash.ToAddress(); var info = GetAssetsInfo(); // dummy tx to self if (targets == null) { string assetName = "GAS"; string assetID = info[assetName]; var targetAssetID = LuxUtils.ReverseHex(assetID).HexToBytes(); if (!unspent.ContainsKey(assetName)) { throw new NeoException($"Not enough {assetName} in address {from_address}"); } var src = unspent[assetName][0]; decimal selected = src.value; // Console.WriteLine("SENDING " + selected + " GAS to source"); inputs.Add(new Transaction.Input() { prevHash = src.hash, prevIndex = src.index, }); outputs.Add(new Transaction.Output() { assetID = targetAssetID, scriptHash = from_script_hash, value = selected }); return; } foreach (var target in targets) { if (target.scriptHash.Equals(from_script_hash)) { throw new NeoException("Target can't be same as input"); } } bool done_fee = false; foreach (var asset in info) { string assetName = asset.Key; string assetID = asset.Value; if (!unspent.ContainsKey(assetName)) { continue; } var targetAssetID = LuxUtils.ReverseHex(assetID).HexToBytes(); var thistargets = targets.Where(o => o.assetID.SequenceEqual(targetAssetID)); decimal cost = -1; foreach (var target in thistargets) { if (target.assetID.SequenceEqual(targetAssetID)) { if (cost < 0) { cost = 0; } cost += target.value; } } // incorporate fee in GAS utxo, if sending GAS bool sendfee = false; if (system_fee > 0 && assetName == "GAS") { done_fee = true; sendfee = true; if (cost < 0) { cost = 0; } cost += system_fee; } if (cost == -1) { continue; } var sources = unspent[assetName].OrderBy(src => src.value); decimal selected = 0; // >= cost ou > cost?? foreach (var src in sources) { if (selected >= cost && inputs.Count > 0) { break; } selected += src.value; inputs.Add(new Transaction.Input() { prevHash = src.hash, prevIndex = src.index, }); // Console.WriteLine("ADD inp " + src.ToString()); } if (selected < cost) { throw new NeoException($"Not enough {assetName} in address {from_address}"); } if (cost > 0) { foreach (var target in thistargets) { outputs.Add(target); } } if (selected > cost || cost == 0 || sendfee) /// is sendfee needed? yes if selected == cost { outputs.Add(new Transaction.Output() { assetID = targetAssetID, scriptHash = from_script_hash, value = selected - cost }); } } /* * if (system_fee > 0 && !done_fee && false) * { * var gasID = LuxUtils.ReverseHex(info["GAS"]).HexToBytes(); * var gassources = unspent["GAS"]; * // foreach (var src in gassources) * // Console.WriteLine("SRC: " + src.ToString()); * decimal feeselected = 0; * foreach (var src in gassources) * if (feeselected <= system_fee) * { * inputs.Add(new Transaction.Input() * { * prevHash = src.hash, * prevIndex = src.index, * }); * feeselected += src.value; * Console.WriteLine("add input " + feeselected); * break; * } * outputs.Add(new Transaction.Output() * { * assetID = gasID, * scriptHash = from_script_hash, * value = feeselected - system_fee * }); * } * * foreach (var i in inputs) * Console.WriteLine("INPUT " + i); * foreach (var i in output) * Console.WriteLine("OUTPUT " + i); * // chaining * if (lastTransactions.ContainsKey(from_address)) * { * var lastTx = lastTransactions[from_address]; * uint index = 0; * if (lastTx.outputs != null) * foreach (var output in lastTx.outputs) * { * if (output.assetID.SequenceEqual(targetAssetID) && output.scriptHash.Equals(from_script_hash)) * { * selected += output.value; * var input = new Transaction.Input() * { * prevHash = lastTx.Hash, * prevIndex = index, * }; * inputs.Add(input); * break; * } * index++; * } * } */ }
public static string GetStringFromScriptHash(byte[] hash) { return(LuxUtils.ReverseHex(hash.ToHexString())); }
static void Main(string[] args) { uint startBlock = 2298101; uint endblock = 2299480; string transactions_output_filename = "phantasma_transactions.csv"; string total_output_filename = "phantasma_totals.csv"; var soul_scripthash = new UInt160(LuxUtils.ReverseHex("4b4f63919b9ecfd2483f0c72ff46ed31b5bbb7a4").HexToBytes()); Console.WriteLine("Generating sale audit. This can take several minutes, please be patient."); var start_time = Environment.TickCount; var api = new LocalRPCNode(10332, "http://neoscan.io"); var blockCount = api.GetBlockHeight(); var balances = new Dictionary <string, decimal>(); var total_output = new List <string>(); var transaction_output = new List <string>(); var extra_refunds = new Dictionary <string, decimal>(); transaction_output.Add($"Tx type,Tx hash,Address,NEO sent"); for (uint height = startBlock; height <= endblock; height++) { var block = api.GetBlock(height); foreach (var tx in block.transactions) { foreach (var output in tx.outputs) { if (output.scriptHash == soul_scripthash) { Transaction other = null; foreach (var input in tx.inputs) { other = api.GetTransaction(input.prevHash); UInt160 src = other.outputs[input.prevIndex].scriptHash; var src_addr = src.ToAddress(); var ss = tx.type.ToString().Replace("Transaction", ""); var balance = balances.ContainsKey(src_addr) ? balances[src_addr] : 0; if (tx.type == TransactionType.InvocationTransaction) { balance += output.value; } else { var extra = extra_refunds.ContainsKey(src_addr) ? extra_refunds[src_addr] : 0; extra += output.value; extra_refunds[src_addr] = extra; } balances[src_addr] = balance; transaction_output.Add($"{ss},{tx.Hash},{src_addr},{output.value}"); break; } break; } } } } total_output.Add($"Address,SOUL received,NEO sent,NEO to be refunded"); foreach (KeyValuePair <string, decimal> entry in balances.OrderBy(x => x.Value)) { var total_sent = entry.Value; var refund_amount = entry.Value > 10 ? entry.Value - 10 : 0; var token_amount = (entry.Value > 10 ? 10 : entry.Value) * 273; if (extra_refunds.ContainsKey(entry.Key)) { var refund_value = extra_refunds[entry.Key]; refund_amount += refund_value; total_sent += refund_value; } total_output.Add($"{entry.Key},{token_amount},{total_sent},{refund_amount}"); } File.WriteAllLines(total_output_filename, total_output.ToArray()); File.WriteAllLines(transactions_output_filename, transaction_output.ToArray()); var total_blocks = (endblock - startBlock) + 1; var end_time = Environment.TickCount; var delta = (end_time - start_time) / 1000; Console.WriteLine("Finished in " + delta + " seconds, loaded " + total_blocks + " blocks"); }
public ApplicationLog[] GetApplicationLog(string hash) { var val = new UInt256(LuxUtils.ReverseHex(hash).HexToBytes()); return(GetApplicationLog(val)); }
protected override InteropBlock PullPlatformBlock(string platformName, string chainName, Hash hash, NativeBigInt height = new NativeBigInt()) { if (hash == null && height == null) { throw new OracleException($"Fetching block not possible without hash or height"); } InteropBlock block = Read <InteropBlock>(platformName, chainName, hash, StorageConst.Block); if (height == null && block.Hash != null && block.Hash != Hash.Null) { return(block); } Tuple <InteropBlock, InteropTransaction[]> interopTuple; switch (platformName) { case NeoWallet.NeoPlatform: NeoBlock neoBlock; if (height == 0) { neoBlock = _cli.NeoAPI.GetBlock(new UInt256(LuxUtils.ReverseHex(hash.ToString()).HexToBytes())); } else { neoBlock = _cli.NeoAPI.GetBlock(height); } if (neoBlock == null) { throw new OracleException($"Neo block is null"); } var coldStorage = _cli.Settings.Oracle.SwapColdStorageNeo; interopTuple = NeoInterop.MakeInteropBlock(logger, neoBlock, _cli.NeoAPI, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Neo], coldStorage); break; case EthereumWallet.EthereumPlatform: { var hashes = _cli.Nexus.GetPlatformTokenHashes(EthereumWallet.EthereumPlatform, _cli.Nexus.RootStorage) .Select(x => x.ToString().Substring(0, 40)).ToArray(); interopTuple = EthereumInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.EthAPI, height, hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Ethereum]); break; } case BSCWallet.BSCPlatform: { var hashes = _cli.Nexus.GetPlatformTokenHashes(BSCWallet.BSCPlatform, _cli.Nexus.RootStorage) .Select(x => x.ToString().Substring(0, 40)).ToArray(); interopTuple = BSCInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.BscAPI, height, hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.BSC]); break; } default: throw new OracleException("Uknown oracle platform: " + platformName); } if (interopTuple.Item1.Hash != Hash.Null) { var initialStore = Persist <InteropBlock>(platformName, chainName, interopTuple.Item1.Hash, StorageConst.Block, interopTuple.Item1); var transactions = interopTuple.Item2; if (!initialStore) { logger.Debug($"Oracle block { interopTuple.Item1.Hash } on platform { platformName } updated!"); } foreach (var tx in transactions) { var txInitialStore = Persist <InteropTransaction>(platformName, chainName, tx.Hash, StorageConst.Transaction, tx); if (!txInitialStore) { logger.Debug($"Oracle block { interopTuple.Item1.Hash } on platform { platformName } updated!"); } } } return(interopTuple.Item1); }
private bool InitInvoke() { var key = paramsList.Text; var f = _abi.functions[key]; DebugParameters = new DebugParameters(); //Get the private key used DebugParameters.PrivateKey = privateKeyInput.Text; //Get the witness mode CheckWitnessMode witnessMode; var ws = witnessComboBox.SelectedItem.ToString().Replace(" ", ""); if (!Enum.TryParse <CheckWitnessMode>(ws, out witnessMode)) { return(false); } DebugParameters.WitnessMode = witnessMode; //Get the trigger type TriggerType type; var ts = triggerComboBox.SelectedItem.ToString().Replace(" ", ""); if (!Enum.TryParse <TriggerType>(ts, out type)) { return(false); } DebugParameters.TriggerType = type; var HasRawScript = RawScriptText.Text.Length != 0; //Get the arguments list if (!HasRawScript) { var argList = ""; if (f.inputs != null) { int index = 0; foreach (var p in f.inputs) { var temp = ($"{key}_{f.name}").ToLower(); var name = inputGrid.Rows[index].Cells[0].Value; object val; // detect placeholder if (inputGrid.Rows[index].Cells[1].Style.ForeColor == Color.Gray) { val = ""; } else { val = ReadCellVal(index, 1); } if (val == null) { val = ""; // temporary hack, necessary to avoid VM crash } if (val != null && !val.Equals("")) { var param_key = (currentContractName + "_" + f.name + "_" + p.name).ToLower(); //Add our default running parameters for next time DebugParameters.DefaultParams[param_key] = val.ToString(); } if (index > 0) { argList += ","; } if (p.type == Emulator.Type.Array || p.type == Emulator.Type.ByteArray) { var s = val.ToString(); if (s.StartsWith("[") && s.EndsWith("]")) { val = s; } else if (s.StartsWith("\"") && s.EndsWith("\"")) { s = s.Substring(1, s.Length - 2); val = ConvertArray(s); if (val == null && p.type == Emulator.Type.ByteArray) { val = DebuggerUtils.BytesToString(LuxUtils.ReverseHex(LuxUtils.ByteToHex(System.Text.Encoding.UTF8.GetBytes(s))).HexToBytes()); } else { if (val == null) { ShowArgumentError(f, index, val); return(false); } } } else { ShowArgumentError(f, index, val); return(false); } var items = JSONReader.ReadFromString(val.ToString()); val = ""; int itemIndex = 0; foreach (var item in items) { if (itemIndex > 0) { val += ","; } if (item.Kind == LunarParser.NodeKind.String) { var vv = ConvertArray(item.Value); if (vv != null) { val += vv; } else { val += "\"" + item.Value + "\""; } } else { val += item.Value; } itemIndex++; } val = $"[{val}]"; } else { switch (p.type) { case Emulator.Type.String: { var s = val.ToString(); if (!s.StartsWith("\"") || !s.EndsWith("\"")) { ShowArgumentError(f, index, val); return(false); } break; } case Emulator.Type.Integer: { BigInteger n; var s = val.ToString(); if (string.IsNullOrEmpty(s) || !BigInteger.TryParse(s, out n)) { ShowArgumentError(f, index, val); ResetTabs(); return(false); } break; } case Emulator.Type.Boolean: { switch (val.ToString().ToLower()) { case "true": val = true; break; case "false": val = false; break; default: { ShowArgumentError(f, index, val); ResetTabs(); return(false); } } break; } } } argList += val; index++; } } if (key != _abi.entryPoint.name) { if (f.inputs == null || f.inputs.Count == 0) { argList = "[]"; } var operation = Char.ToLowerInvariant(key[0]) + key.Substring(1); argList = $"\"{operation}\", [{argList}]"; } //Set the arguments list try { DebugParameters.ArgList = DebuggerUtils.GetArgsListAsNode(argList); } catch { MessageBox.Show("Error parsing input!"); ResetTabs(); return(false); } } if (assetComboBox.SelectedIndex > 0) { foreach (var entry in Asset.Entries) { if (entry.name == assetComboBox.SelectedItem.ToString()) { BigInteger amount; BigInteger.TryParse(assetAmount.Text, out amount); if (amount > 0) { lastSentSymbol = entry.name; lastSentAmount = assetAmount.Text; amount *= Asset.Decimals; // fix decimals //Add the transaction info DebugParameters.Transaction.Add(entry.id, amount); } else { MessageBox.Show(entry.name + " amount must be greater than zero"); return(false); } break; } } } uint timestamp; if (!uint.TryParse(timestampBox.Text, out timestamp)) { MessageBox.Show("Invalid timestamp"); return(false); } else { DebugParameters.Timestamp = timestamp; } DebugParameters.RawScript = HasRawScript ? RawScriptText.Text.HexToBytes() : null; return(true); }
static void Main(string[] pargs) { //var api = new LocalRPCNode(10332, "http://neoscan.io"); var api = new RemoteRPCNode(10332, "http://neoscan.io"); { Console.WriteLine("amount " + new BigInteger("00943577".HexToBytes())); Console.WriteLine("to " + new UInt160("fc3f33cb3e2d79f82fadef5f407ac1576d304bc1".HexToBytes()).ToAddress()); Console.WriteLine("from " + new UInt160("a30cadcc858aa4b89d9db098ef154c5e1ab74464".HexToBytes()).ToAddress()); return; } { var snap_data = File.ReadAllLines("souls_snap.csv"); var snap = Snapshot.Import(snap_data); var avm_script = File.ReadAllBytes(@"D:\code\Crypto\PhantasmaNeo\PhantasmaContract\bin\Debug\PhantasmaContract.avm"); var soul_token = api.GetToken("SOUL"); var lines = new List <string>(); uint ico_war_time = 1527465600; uint ico_start_time = 1527379200; Console.WriteLine("Block,Stage,Tx Hash,Address,Action,NEO sent,NEO refund"); snap.Execute(soul_token, avm_script, vm => { var storage = vm.GetStorage(soul_token); var block = vm.currentBlock; int stage = (block.Timestamp < ico_war_time) ? ((block.Timestamp < ico_start_time) ? 0 : 1) : 2; //var bytes = storage.Get("totalSupply"); //var n = new BigInteger(bytes); foreach (var tx in block.transactions) { UInt160 src = null; /*foreach (var input in tx.inputs) * { * var input_tx = snap.GetTransaction(input.prevHash); * if (input_tx == null) * { * input_tx = api.GetTransaction(input.prevHash); * } * var output = input_tx.outputs[input.prevIndex]; * src = output.scriptHash; * } * * if (src == null) * { * continue; * }*/ decimal neo_sent = 0; foreach (var output in tx.outputs) { if (output.scriptHash == soul_token.ScriptHash) { neo_sent += output.value; } } var src_address = src != null ? src.ToAddress(): "???"; if (tx.Hash.ToString() == "0xc39fb2304f721382a40142ed8af9d4470850f39fabeef9bb8bad892a6b63f4d6") { src_address += ""; } if (tx.type == TransactionType.ContractTransaction) { decimal refund = 0; foreach (var output in tx.outputs) { if (output.scriptHash == soul_token.ScriptHash) { refund += output.value; } } Console.WriteLine($"Block #{block.Height},{stage},{tx.Hash},{src_address},contract,{neo_sent},{refund}"); } else { var notifications = vm.GetNotifications(tx); if (notifications != null) { foreach (var entry in notifications) { decimal refund = 0; if (entry.Name == "refund") { var bytes = (byte[])entry.Args[1]; var n = new BigInteger(bytes); refund = (decimal)(n / 100000000); } Console.WriteLine($"Block #{block.Height},{stage},{entry.Hash},{src_address},{entry.Name},{neo_sent},{refund}"); } } } } }); return; } uint roundBlock = 2320640; uint startBlock = 2313827; uint endBlock = 2320681; { var snap = new Snapshot(api.GetToken("SOUL"), startBlock, endBlock); var export = snap.Export(); File.WriteAllLines("souls_snap.csv", export.ToArray()); return; } //startBlock = roundBlock; var soul_hash = LuxUtils.ReverseHex("ed07cffad18f1308db51920d99a2af60ac66a7b3").HexToBytes(); var soul_hash_int = new UInt160(soul_hash); var startT = Environment.TickCount; uint maxblock = 0; var blockCount = api.GetBlockHeight(); var soul_balances = new Dictionary <UInt160, BigInteger>(); var bought = new Dictionary <UInt160, decimal>(); BigInteger max_supply = 91136510; // total token amount BigInteger team_supply = 14500000; // team token amount BigInteger advisor_supply = 5500000; // advisor token amount BigInteger platform_supply = 15000000; // company token amount BigInteger presale_supply = 43503435; // presale token amount BigInteger total_supply = team_supply + advisor_supply + presale_supply + platform_supply; var whitelist = new HashSet <UInt160>(); var maybe = new HashSet <UInt160>(); var sure = new HashSet <UInt160>(); var expected = new Dictionary <UInt160, decimal>(); var txlist = new List <string>(); for (uint height = startBlock; height <= endBlock; height++) { var block = api.GetBlock(height); //Console.WriteLine(height + " " + block.Timestamp.ToString()); foreach (var tx in block.transactions) { if (tx.type == TransactionType.ContractTransaction) { foreach (var output in tx.outputs) { if (output.scriptHash == soul_hash_int) { /*foreach (var input in tx.inputs) * { * var input_tx = api.GetTransaction(input.prevHash); * var outp = input_tx.outputs[input.prevIndex]; * var sender = outp.scriptHash; * Console.WriteLine($"refund,{tx.Hash},{sender.ToAddress()},{output.value}"); * break; * }*/ } } continue; } if (tx.type != TransactionType.InvocationTransaction) { continue; } List <AVMInstruction> ops; try { ops = NeoTools.Disassemble(tx.script); } catch { continue; } if (tx.Hash.ToString() == "0xcf530159dc7fa7d0ea38ca210b479b04da20039b3b6639cf4c06bf528d415339") { tx.gas += 0; } for (int i = 0; i < ops.Count; i++) { var op = ops[i]; if (op.opcode == OpCode.APPCALL && op.data.SequenceEqual(soul_hash)) { var engine = new ExecutionEngine(null); engine.LoadScript(tx.script); engine.Execute(null); var operation = engine.EvaluationStack.Peek().GetString(); var args = ((IEnumerable <StackItem>)engine.EvaluationStack.Peek(1)).ToList(); var witnesses = new HashSet <UInt160>(); foreach (var input in tx.inputs) { var input_tx = api.GetTransaction(input.prevHash); witnesses.Add(input_tx.outputs[input.prevIndex].scriptHash); } switch (operation) { case "mintTokens": { decimal neo_amount = 0; foreach (var output in tx.outputs) { if (output.scriptHash == soul_hash_int) { neo_amount += output.value; } } var sender = witnesses.First(); var cur_bought = bought.ContainsKey(sender) ? bought[sender] : 0; decimal refund = 0; if (block.Height >= roundBlock) { maybe.Add(sender); expected[sender] = neo_amount * 273; } if (!whitelist.Contains(sender)) { refund = neo_amount; neo_amount = 0; } else if (cur_bought + neo_amount > 10) { var temp = neo_amount; neo_amount = 10 - cur_bought; refund = temp - neo_amount; } if (neo_amount > 0) { BigInteger souls = (int)neo_amount * 273; /*if (souls + total_supply > max_supply) * { * souls = max_supply - total_supply; * }*/ total_supply += souls * 2; if (soul_balances.ContainsKey(sender)) { soul_balances[sender] += new BigInteger((long)(souls * 100000000)); } else { soul_balances[sender] = new BigInteger((long)(souls * 100000000)); } Console.WriteLine(block.Height + "," + tx.Hash + ",mint," + soul_hash_int.ToAddress() + "," + sender.ToAddress() + "," + souls); cur_bought += neo_amount; bought[sender] = cur_bought; } else if (refund > 0) { Console.WriteLine(block.Height + "," + tx.Hash + ",refund," + soul_hash_int.ToAddress() + "," + sender.ToAddress() + "," + refund); } break; } case "whitelistAddFree": { foreach (var addr in args) { var hash = new UInt160(addr.GetByteArray()); whitelist.Add(hash); } break; } case "whitelistAddFilled": { foreach (var addr in args) { var hash = new UInt160(addr.GetByteArray()); whitelist.Add(hash); bought[hash] = 2730; } break; } case "whitelistAddCap": { decimal cap = 0; int index = 0; foreach (var addr in args) { if (index == 0) { var amount = addr.GetBigInteger(); cap = (decimal)(amount / 100000000); } else { var hash = new UInt160(addr.GetByteArray()); whitelist.Add(hash); bought[hash] = cap; } index++; } break; } case "chainSwap": { throw new Exception("Exploit found"); break; } case "deploy": { soul_balances[new UInt160("Abyd4BcStNksGLmfdHtyyPbS1xzhceDKLs".AddressToScriptHash())] = new BigInteger((long)6316538 * (long)100000000); soul_balances[new UInt160("ARWHJefSbhayC2gurKkpjMHm5ReaJZLLJ3".AddressToScriptHash())] = new BigInteger((long)43503435 * (long)100000000); soul_balances[new UInt160("AQFQmVQi9VReLhym1tF3UfPk4EG3VKbAwN".AddressToScriptHash())] = new BigInteger((long)15000000 * (long)100000000); break; } case "transfer": { if (args.Count == 3) { var from = new UInt160(args[0].GetByteArray()); if (!witnesses.Contains(from)) { //throw new Exception("Invalid"); } if (maybe.Contains(from)) { sure.Add(from); } var to = new UInt160(args[1].GetByteArray()); var value = args[2].GetBigInteger(); var from_addr = from.ToAddress(); var to_addr = to.ToAddress(); /*if (from == watch) * { * Console.WriteLine("WATCH " + tx.Hash); * } * if (to == watch) * { * Console.WriteLine("WATCH " + tx.Hash); * }*/ decimal amount = (long)value; int places = 8; while (places > 0) { amount *= 0.1m; places--; } Console.WriteLine(block.Height + "," + tx.Hash + ",transfer," + from.ToAddress() + "," + to.ToAddress() + "," + amount); } break; } } } } } } /*var lines = new List<string>(); * foreach (var entry in soul_balances) * { * var k = (long)entry.Value; * if (k == 0) * { * continue; * } * var val = (decimal)k / 100000000m; * lines.Add(entry.Key.ToAddress() + "," + val); * } * File.WriteAllLines("sale_soul.csv", lines.ToArray());*/ var token = api.GetToken("SOUL"); foreach (var entry in maybe) { var addr = entry.ToAddress(); var balance = token.BalanceOf(addr); if (balance >= expected[entry]) { sure.Add(entry); } } foreach (var entry in sure) { maybe.Remove(entry); Console.WriteLine(entry.ToAddress() + "," + expected[entry]); if (expected[entry] > 50 * 273) { throw new Exception("AAAAAAAAA"); } } foreach (var entry in maybe) { Console.WriteLine(entry.ToAddress() + ",0"); } decimal total = 0; foreach (var entry in sure) { total += expected[entry]; } Console.WriteLine("TOTAL " + total); var endT = Environment.TickCount; var delta = (endT - startT) / 1000; Console.WriteLine("Finished in " + delta + " seconds, loaded " + maxblock + " blocks"); Console.ReadLine(); return; /* Console.WriteLine(tkk.BalanceOf("AYxnCZePKhrijk2TQymYYUqm74nuwCftwq")); * //var token = api.GetToken("SOUL"); * //var keys = KeyPair.FromWIF("KxnjzXUvK9BLojMrWVJF7jjdbHs37aXvHyFog4rARGNrAQ7LFjLP"); * * var token = api.GetToken("OBT"); * var keys = KeyPair.FromWIF("L5YiR4AdUibLeFf48W3P5P36aBTWANcDu6oQNkvpaQrrHreg4RZC"); * * var balance = token.BalanceOf(keys); * Console.WriteLine(balance); * * var transfers = new Dictionary<string, decimal>(); * transfers["AHXWzaYCNYBYvhSypfi2XpAiWz2cCXrDJr"] = 16.7m; * transfers["AHxXMh9cPjE3cYrA9DhWNSBY2hC3a62PcH"] = 16.7m; * transfers["AHY7SidKpLuNj881Mc4Vjsj1Y4jBbX5EPS"] = 16.7m; * * var txx = token.Transfer(keys, transfers); * Console.WriteLine(txx.Hash);*/ /* * uint startBlock = 2298101; * uint endblock = 2313169; * * var soul_hash = LuxUtils.ReverseHex("4b4f63919b9ecfd2483f0c72ff46ed31b5bbb7a4").HexToBytes(); * var soul_hash_int = new UInt160(soul_hash); * * * var startT = Environment.TickCount; * * uint maxblock = 0; * * var blockCount = api.GetBlockHeight(); * * var soul_balances = new Dictionary<UInt160, BigInteger>(); * var bought = new Dictionary<UInt160, decimal>(); * * BigInteger max_supply = 91136510; // total token amount * BigInteger team_supply = 14500000; // team token amount * BigInteger advisor_supply = 5500000; // advisor token amount * BigInteger platform_supply = 15000000; // company token amount * BigInteger presale_supply = 43503435; // presale token amount * * BigInteger total_supply = team_supply + advisor_supply + presale_supply + platform_supply; * * var watch = new UInt160( "AQkiyWfwxMT31epRRxWXbR7wvZJH944jqh".AddressToScriptHash()); * * for (uint height = startBlock; height<=endblock; height++) * { * var block = api.GetBlock(height); * * //Console.WriteLine(height + " " + block.Timestamp.ToString()); * * foreach (var tx in block.transactions) * { * if (tx.type != TransactionType.InvocationTransaction) * { * continue; * } * * List<AVMInstruction> ops; * try * { * ops = NeoTools.Disassemble(tx.script); * } * catch * { * continue; * } * * if (tx.Hash.ToString()== "0xcf530159dc7fa7d0ea38ca210b479b04da20039b3b6639cf4c06bf528d415339") * { * tx.gas += 0; * } * * for (int i = 0; i < ops.Count; i++) * { * var op = ops[i]; * * if (op.opcode == OpCode.APPCALL && op.data.SequenceEqual(soul_hash)) * { * var engine = new ExecutionEngine(null); * engine.LoadScript(tx.script); * engine.Execute(null); * * var operation = engine.EvaluationStack.Peek().GetString(); * * var witnesses = new HashSet<UInt160>(); * foreach (var input in tx.inputs) * { * var input_tx = api.GetTransaction(input.prevHash); * witnesses.Add(input_tx.outputs[input.prevIndex].scriptHash); * } * * switch (operation) * { * case "mintTokens": * { * decimal neo_amount = 0; * * if (block.Timestamp.ToTimestamp() < 1526947200) * { * break; * } * * if (block.Height> 2298690) * { * break; * } * * foreach (var output in tx.outputs) * { * if (output.scriptHash == soul_hash_int) * { * neo_amount += output.value; * } * } * * var sender = witnesses.First(); * var cur_bought = bought.ContainsKey(sender) ? bought[sender] : 0; * * if (cur_bought + neo_amount > 10) * { * neo_amount = 10 - cur_bought; * } * * foreach (var wit in witnesses) * { * if (wit == watch) * { * Console.WriteLine("WATCH " + tx.Hash); * break; * } * } * * if (neo_amount > 0) * { * BigInteger souls = (int)neo_amount * 273; * //if (souls + total_supply > max_supply) * //{ * // souls = max_supply - total_supply; * //} * * total_supply += souls * 2; * * if (soul_balances.ContainsKey(sender)) * { * soul_balances[sender] += new BigInteger((long)(souls * 100000000)); * } * else * { * soul_balances[sender] = new BigInteger((long)(souls * 100000000)); * } * * Console.WriteLine(tx.Hash + ",mint," + soul_hash_int.ToAddress() + "," + sender.ToAddress() + "," + souls); * cur_bought += neo_amount; * bought[sender] = cur_bought; * } * * break; * } * * case "chainSwap": * { * throw new Exception("Exploit found"); * break; * } * * case "transfer": * { * var args = (Neo.Lux.VM.Types.Array)engine.EvaluationStack.Peek(1); * * if (args.Count == 3) * { * var from = new UInt160(args[0].GetByteArray()); * * if (!witnesses.Contains(from)) * { * //throw new Exception("Invalid"); * } * * var to = new UInt160(args[1].GetByteArray()); * var value = args[2].GetBigInteger(); * * var from_addr = from.ToAddress(); * var to_addr = to.ToAddress(); * * if (from == watch) * { * Console.WriteLine("WATCH " + tx.Hash); * } * if (to == watch) * { * Console.WriteLine("WATCH " + tx.Hash); * } * * if (from_addr == "AdkLubeJgL3PCKc1Xv6CEv9PrzB4c5AKNk") * { * value += 0; * } * * if (soul_balances.ContainsKey(from)) * { * var src_balance = soul_balances[from]; * * if (src_balance >= value) * { * src_balance -= value; * soul_balances[from] = src_balance; * * if (soul_balances.ContainsKey(to)) * { * soul_balances[to] += value; * } * else * { * soul_balances[to] = value; * } * } * } * else * { * throw new Exception("Invalid balance"); * } * * decimal amount = (long)value; * int places = 8; * while (places > 0) * { * amount *= 0.1m; * places--; * } * * Console.WriteLine(tx.Hash + ",transfer," + from.ToAddress() + "," + to.ToAddress() + "," + amount); * } * * break; * } * } * * } * * } * } * } * * var lines = new List<string>(); * foreach(var entry in soul_balances) * { * var k = (long)entry.Value; * if (k == 0) * { * continue; * } * var val = (decimal)k / 100000000m; * lines.Add(entry.Key.ToAddress() + "," + val); * } * File.WriteAllLines("soul_snapshop.csv", lines.ToArray()); * * var endT = Environment.TickCount; * var delta = (endT - startT) / 1000; * Console.WriteLine("Finished in " + delta + " seconds, loaded "+maxblock+" blocks"); * * Console.ReadLine(); */ }
public void GenerateInputsOutputs(UInt160 from_script_hash, string symbol, IEnumerable <Transaction.Output> targets, out List <Transaction.Input> inputs, out List <Transaction.Output> outputs, decimal system_fee = 0) { var unspent = GetUnspent(from_script_hash); // filter any asset lists with zero unspent inputs unspent = unspent.Where(pair => pair.Value.Count > 0).ToDictionary(pair => pair.Key, pair => pair.Value); inputs = new List <Transaction.Input>(); outputs = new List <Transaction.Output>(); string assetID; var info = GetAssetsInfo(); if (info.ContainsKey(symbol)) { assetID = info[symbol]; } else { throw new NeoException($"{symbol} is not a valid blockchain asset."); } var from_address = from_script_hash.ToAddress(); if (!unspent.ContainsKey(symbol)) { throw new NeoException($"Not enough {symbol} in address {from_address}"); } decimal cost = 0; if (targets != null) { foreach (var target in targets) { if (target.scriptHash.Equals(from_script_hash)) { throw new NeoException("Target can't be same as input"); } cost += target.value; } } var targetAssetID = LuxUtils.ReverseHex(assetID).HexToBytes(); var sources = unspent[symbol]; decimal selected = 0; if (lastTransactions.ContainsKey(from_address)) { var lastTx = lastTransactions[from_address]; uint index = 0; foreach (var output in lastTx.outputs) { if (output.assetID.SequenceEqual(targetAssetID) && output.scriptHash.Equals(from_script_hash)) { selected += output.value; var input = new Transaction.Input() { prevHash = lastTx.Hash, prevIndex = index, }; inputs.Add(input); break; } index++; } } foreach (var src in sources) { if (selected >= cost && inputs.Count > 0) { break; } selected += src.value; var input = new Transaction.Input() { prevHash = src.hash, prevIndex = src.index, }; inputs.Add(input); } if (selected < cost) { throw new NeoException($"Not enough {symbol}"); } if (cost > 0 && targets != null) { foreach (var target in targets) { var output = new Transaction.Output() { assetID = targetAssetID, scriptHash = target.scriptHash, value = target.value }; outputs.Add(output); } } if (selected > cost || cost == 0) { var left = selected - cost; var change = new Transaction.Output() { assetID = targetAssetID, scriptHash = from_script_hash, value = left }; outputs.Add(change); } }