diff --git a/neo-cli/CLI/MainService.Contracts.cs b/neo-cli/CLI/MainService.Contracts.cs index b7ab38503..6f3b42bca 100644 --- a/neo-cli/CLI/MainService.Contracts.cs +++ b/neo-cli/CLI/MainService.Contracts.cs @@ -41,6 +41,55 @@ private void OnDeployCommand(string filePath, string manifestPath = null) SignAndSendTx(tx); } + /// + /// Process "invoke" command + /// + /// Script hash + /// Operation + /// Transaction + /// Contract parameters + private VM.Types.StackItem OnInvokeWithResult(UInt160 scriptHash, string operation, IVerifiable verificable = null, JArray contractParameters = null) + { + List parameters = new List(); + + if (contractParameters != null) + { + foreach (var contractParameter in contractParameters) + { + parameters.Add(ContractParameter.FromJson(contractParameter)); + } + } + + byte[] script; + + using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + { + scriptBuilder.EmitAppCall(scriptHash, operation, parameters.ToArray()); + script = scriptBuilder.ToArray(); + Console.WriteLine($"Invoking script with: '{script.ToHexString()}'"); + } + + if (verificable is Transaction tx) + { + tx.Script = script; + } + + using (ApplicationEngine engine = ApplicationEngine.Run(script, verificable, testMode: true)) + { + Console.WriteLine($"VM State: {engine.State}"); + Console.WriteLine($"Gas Consumed: {new BigDecimal(engine.GasConsumed, NativeContract.GAS.Decimals)}"); + Console.WriteLine($"Result Stack: {new JArray(engine.ResultStack.Select(p => p.ToJson()))}"); + + if (engine.State.HasFlag(VMState.FAULT) || !engine.ResultStack.TryPop(out VM.Types.StackItem ret)) + { + Console.WriteLine("Engine faulted."); + return null; + } + + return ret; + } + } + /// /// Process "invoke" command /// @@ -51,10 +100,9 @@ private void OnDeployCommand(string filePath, string manifestPath = null) [ConsoleCommand("invoke", Category = "Contract Commands")] private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contractParameters = null, UInt160[] witnessAddress = null) { - List parameters = new List(); List signCollection = new List(); - if (!NoWallet() && witnessAddress != null) + if (witnessAddress != null && !NoWallet()) { using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { @@ -77,14 +125,6 @@ private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contra } } - if (contractParameters != null) - { - foreach (var contractParameter in contractParameters) - { - parameters.Add(ContractParameter.FromJson(contractParameter)); - } - } - Transaction tx = new Transaction { Sender = UInt160.Zero, @@ -93,25 +133,7 @@ private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contra Cosigners = signCollection.ToArray() }; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) - { - scriptBuilder.EmitAppCall(scriptHash, operation, parameters.ToArray()); - tx.Script = scriptBuilder.ToArray(); - Console.WriteLine($"Invoking script with: '{tx.Script.ToHexString()}'"); - } - - using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, tx, testMode: true)) - { - Console.WriteLine($"VM State: {engine.State}"); - Console.WriteLine($"Gas Consumed: {new BigDecimal(engine.GasConsumed, NativeContract.GAS.Decimals)}"); - Console.WriteLine($"Evaluation Stack: {new JArray(engine.ResultStack.Select(p => p.ToJson()))}"); - Console.WriteLine(); - if (engine.State.HasFlag(VMState.FAULT)) - { - Console.WriteLine("Engine faulted."); - return; - } - } + _ = OnInvokeWithResult(scriptHash, operation, tx, contractParameters); if (NoWallet()) return; try diff --git a/neo-cli/CLI/MainService.NEP5.cs b/neo-cli/CLI/MainService.NEP5.cs new file mode 100644 index 000000000..3987c307d --- /dev/null +++ b/neo-cli/CLI/MainService.NEP5.cs @@ -0,0 +1,94 @@ +using Neo.ConsoleService; +using Neo.IO.Json; +using Neo.Network.P2P.Payloads; +using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Globalization; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "transfer" command + /// + /// Script hash + /// To + /// Ammount + [ConsoleCommand("transfer", Category = "NEP5 Commands")] + private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount) + { + var asset = new AssetDescriptor(tokenHash); + var value = BigDecimal.Parse(amount.ToString(CultureInfo.InvariantCulture), asset.Decimals); + + if (NoWallet()) return; + + Transaction tx; + try + { + tx = CurrentWallet.MakeTransaction(new[] + { + new TransferOutput + { + AssetId = tokenHash, + Value = value, + ScriptHash = to + } + }, from: null); + } + catch (InvalidOperationException) + { + Console.WriteLine("Error: insufficient balance."); + return; + } + if (!ReadUserInput("relay tx(no|yes)").IsYes()) + { + return; + } + SignAndSendTx(tx); + } + + /// + /// Process "balanceOf" command + /// + /// Script hash + /// Address + [ConsoleCommand("balanceOf", Category = "NEP5 Commands")] + private void OnBalanceOfCommand(UInt160 tokenHash, UInt160 address) + { + var arg = new JObject(); + arg["type"] = "Hash160"; + arg["value"] = address.ToString(); + + var result = OnInvokeWithResult(tokenHash, "balanceOf", null, new JArray(arg)); + + Console.WriteLine($"Result : {((PrimitiveType)result).GetBigInteger()}"); + } + + /// + /// Process "name" command + /// + /// Script hash + [ConsoleCommand("name", Category = "NEP5 Commands")] + private void OnNameCommand(UInt160 tokenHash) + { + var result = OnInvokeWithResult(tokenHash, "name", null); + + Console.WriteLine($"Result : {((PrimitiveType)result).GetString()}"); + } + + /// + /// Process "decimals" command + /// + /// Script hash + [ConsoleCommand("decimals", Category = "NEP5 Commands")] + private void OnDecimalsCommand(UInt160 tokenHash) + { + var result = OnInvokeWithResult(tokenHash, "decimals", null); + + Console.WriteLine($"Result : {((PrimitiveType)result).GetBigInteger()}"); + } + } +} diff --git a/neo-cli/CLI/MainService.cs b/neo-cli/CLI/MainService.cs index efb22c8be..ece3cca1f 100644 --- a/neo-cli/CLI/MainService.cs +++ b/neo-cli/CLI/MainService.cs @@ -18,6 +18,7 @@ using Neo.Wallets.SQLite; using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; @@ -117,6 +118,7 @@ public MainService() : base() RegisterCommandHander((str) => ECPoint.Parse(str.Trim(), ECCurve.Secp256r1)); RegisterCommandHander((str) => str.Select(u => ECPoint.Parse(u.Trim(), ECCurve.Secp256r1)).ToArray()); RegisterCommandHander((str) => JObject.Parse(str)); + RegisterCommandHander((str) => decimal.Parse(str, CultureInfo.InvariantCulture)); RegisterCommandHander((obj) => (JArray)obj); RegisterCommand(this);