private void OnDeployCommand(string filePath, string manifestPath = null, JObject data = null) { if (NoWallet()) { return; } byte[] script = LoadDeploymentScript(filePath, manifestPath, data, out var nef, out var manifest); Transaction tx; try { tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script); } catch (InvalidOperationException e) { ConsoleHelper.Error(GetExceptionMessage(e)); return; } UInt160 hash = SmartContract.Helper.GetContractHash(tx.Sender, nef.CheckSum, manifest.Name); ConsoleHelper.Info("Contract hash: ", $"{hash}"); ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}"); ConsoleHelper.Info("Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay { return; } SignAndSendTx(NeoSystem.StoreView, tx); }
private void OnDeployCommand(string filePath, string manifestPath = null) { if (NoWallet()) { return; } byte[] script = LoadDeploymentScript(filePath, manifestPath, out var nef, out var manifest); Transaction tx; try { tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script); } catch (InvalidOperationException e) { Console.WriteLine("Error: " + GetExceptionMessage(e)); return; } UInt160 hash = SmartContract.Helper.GetContractHash(tx.Sender, nef.CheckSum, manifest.Name); Console.WriteLine($"Contract hash: {hash}"); Console.WriteLine($"Gas: {new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); Console.WriteLine(); SignAndSendTx(NeoSystem.StoreView, tx); }
private void OnSendCommand(UInt160 asset, UInt160 to, string amount) { if (NoWallet()) { return; } string password = ReadUserInput("password", true); if (password.Length == 0) { Console.WriteLine("Cancelled"); return; } if (!CurrentWallet.VerifyPassword(password)) { Console.WriteLine("Incorrect password"); return; } Transaction tx; AssetDescriptor descriptor = new AssetDescriptor(asset); if (!BigDecimal.TryParse(amount, descriptor.Decimals, out BigDecimal decimalAmount) || decimalAmount.Sign <= 0) { Console.WriteLine("Incorrect Amount Format"); return; } tx = CurrentWallet.MakeTransaction(new[] { new TransferOutput { AssetId = asset, Value = decimalAmount, ScriptHash = to } }); if (tx == null) { Console.WriteLine("Insufficient funds"); return; } ContractParametersContext context = new ContractParametersContext(tx); CurrentWallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); NeoSystem.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); Console.WriteLine($"TXID: {tx.Hash}"); } else { Console.WriteLine("SignatureContext:"); Console.WriteLine(context.ToString()); } }
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); }
private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contractParameters = null, UInt160[] witnessAddress = null) { List <Cosigner> signCollection = new List <Cosigner>(); if (witnessAddress != null && !NoWallet()) { using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { UInt160[] accounts = CurrentWallet.GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).Where(p => NativeContract.GAS.BalanceOf(snapshot, p).Sign > 0).ToArray(); foreach (var signAccount in accounts) { if (witnessAddress is null) { break; } foreach (var witness in witnessAddress) { if (witness.Equals(signAccount)) { signCollection.Add(new Cosigner() { Account = signAccount }); break; } } } } } Transaction tx = new Transaction { Sender = UInt160.Zero, Attributes = signCollection.ToArray(), Witnesses = Array.Empty <Witness>(), }; _ = OnInvokeWithResult(scriptHash, operation, tx, contractParameters); if (NoWallet()) { return; } try { tx = CurrentWallet.MakeTransaction(tx.Script, null, tx.Attributes); } catch (InvalidOperationException) { Console.WriteLine("Error: insufficient balance."); return; } if (!ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(tx); }
private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contractParameters = null, UInt160 sender = null, UInt160[] signerAccounts = null, decimal maxGas = 20) { var gas = new BigDecimal(maxGas, NativeContract.GAS.Decimals); Signer[] signers = Array.Empty <Signer>(); if (signerAccounts != null && !NoWallet()) { if (sender != null) { if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) { var signersList = signerAccounts.ToList(); signersList.Remove(sender); signerAccounts = signersList.Prepend(sender).ToArray(); } else if (!signerAccounts.Contains(sender)) { signerAccounts = signerAccounts.Prepend(sender).ToArray(); } } signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.CalledByEntry }).ToArray(); } Transaction tx = new Transaction { Signers = signers, Attributes = Array.Empty <TransactionAttribute>(), Witnesses = Array.Empty <Witness>(), }; if (!OnInvokeWithResult(scriptHash, operation, out _, tx, contractParameters, gas: (long)gas.Value)) { return; } if (NoWallet()) { return; } try { tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, tx.Script, sender, signers, maxGas: (long)gas.Value); } catch (InvalidOperationException e) { Console.WriteLine("Error: " + GetExceptionMessage(e)); return; } if (!ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(NeoSystem.StoreView, tx); }
/// <summary> /// Make and send transaction with script, sender /// </summary> /// <param name="script">script</param> /// <param name="account">sender</param> private void SendTransaction(byte[] script, UInt160 account = null) { List <Cosigner> signCollection = new List <Cosigner>(); if (account != null) { using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { UInt160[] accounts = CurrentWallet.GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).Where(p => NativeContract.GAS.BalanceOf(snapshot, p).Sign > 0).ToArray(); foreach (var signAccount in accounts) { if (account.Equals(signAccount)) { signCollection.Add(new Cosigner() { Account = signAccount }); break; } } } } try { Transaction tx = CurrentWallet.MakeTransaction(script, account, signCollection?.ToArray()); Console.WriteLine($"Invoking script with: '{tx.Script.ToHexString()}'"); using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, tx, null, 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.ToParameter().ToJson()))}"); Console.WriteLine(); if (engine.State.HasFlag(VMState.FAULT)) { Console.WriteLine("Engine faulted."); return; } } if (!ReadUserInput("relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(tx); } catch (InvalidOperationException) { Console.WriteLine("Error: insufficient balance."); return; } return; }
/// <summary> /// Make and send transaction with script, sender /// </summary> /// <param name="script">script</param> /// <param name="account">sender</param> private void SendTransaction(byte[] script, UInt160 account = null) { Signer[] signers = System.Array.Empty <Signer>(); if (account != null) { using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { signers = CurrentWallet.GetAccounts() .Where(p => !p.Lock && !p.WatchOnly && p.ScriptHash == account && NativeContract.GAS.BalanceOf(snapshot, p.ScriptHash).Sign > 0) .Select(p => new Signer() { Account = p.ScriptHash, Scopes = WitnessScope.CalledByEntry }) .ToArray(); } } try { Transaction tx = CurrentWallet.MakeTransaction(script, account, signers); Console.WriteLine($"Invoking script with: '{tx.Script.ToHexString()}'"); using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, tx, null, 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("Error: " + GetExceptionMessage(engine.FaultException)); return; } } if (!ReadUserInput("relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(tx); } catch (InvalidOperationException e) { Console.WriteLine("Error: " + GetExceptionMessage(e)); return; } return; }
/// <summary> /// Make and send transaction with script, sender /// </summary> /// <param name="script">script</param> /// <param name="account">sender</param> private void SendTransaction(byte[] script, UInt160 account = null) { Signer[] signers = System.Array.Empty <Signer>(); if (account != null) { using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { signers = CurrentWallet.GetAccounts() .Where(p => !p.Lock && !p.WatchOnly && p.ScriptHash == account && NativeContract.GAS.BalanceOf(snapshot, p.ScriptHash).Sign > 0) .Select(p => new Signer() { Account = p.ScriptHash, Scopes = WitnessScope.CalledByEntry }) .ToArray(); } } try { Transaction tx = CurrentWallet.MakeTransaction(script, account, signers); Console.WriteLine($"Invoking script with: '{tx.Script.ToBase64String()}'"); using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, container: tx)) { PrintExecutionOutput(engine, true); if (engine.State == VMState.FAULT) { return; } } if (!ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(tx); } catch (InvalidOperationException e) { Console.WriteLine("Error: " + GetExceptionMessage(e)); return; } return; }
/// <summary> /// show private key /// </summary> /// <returns></returns> public async Task <object> ClaimGas() { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } var addresses = CurrentWallet.GetAccounts().Where(a => !a.Lock && !a.WatchOnly && a.Contract.Script.IsSignatureContract()).Select(a => a.ScriptHash).ToList(); var balances = addresses.GetBalanceOf(NativeContract.NEO.Hash); balances = balances.Where(b => b.Value > 0).ToList(); if (balances.IsEmpty()) { return(Error(ErrorCode.NoNeedClaimGas)); } var outputs = balances.Select((t, index) => new TransferOutput() { AssetId = NativeContract.NEO.Hash, Value = t, ScriptHash = addresses[index], }).ToArray(); try { Transaction tx = CurrentWallet.MakeTransaction(Helpers.GetDefaultSnapshot(), outputs); if (tx == null) { return(Error(ErrorCode.ClaimGasFail)); } var(signSuccess, context) = CurrentWallet.TrySignTx(tx); if (!signSuccess) { return(Error(ErrorCode.SignFail, context.SafeSerialize())); } await tx.Broadcast(); return(new TransactionModel(tx)); } catch (Exception ex) { if (ex.Message.Contains("Insufficient GAS")) { return(Error(ErrorCode.GasNotEnough)); } return(Error(ErrorCode.ClaimGasFail, ex.Message)); } }
/// <summary> /// Make and send transaction with script, sender /// </summary> /// <param name="script">script</param> /// <param name="account">sender</param> /// <param name="gas">Max fee for running the script</param> private void SendTransaction(byte[] script, UInt160 account = null, long gas = TestModeGas) { Signer[] signers = System.Array.Empty <Signer>(); var snapshot = NeoSystem.StoreView; if (account != null) { signers = CurrentWallet.GetAccounts() .Where(p => !p.Lock && !p.WatchOnly && p.ScriptHash == account && NativeContract.GAS.BalanceOf(snapshot, p.ScriptHash).Sign > 0) .Select(p => new Signer() { Account = p.ScriptHash, Scopes = WitnessScope.CalledByEntry }) .ToArray(); } try { Transaction tx = CurrentWallet.MakeTransaction(snapshot, script, account, signers, maxGas: gas); ConsoleHelper.Info("Invoking script with: ", $"'{tx.Script.ToBase64String()}'"); using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: NeoSystem.Settings, gas: gas)) { PrintExecutionOutput(engine, true); if (engine.State == VMState.FAULT) { return; } } if (!ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(NeoSystem.StoreView, tx); } catch (InvalidOperationException e) { ConsoleHelper.Error(GetExceptionMessage(e)); return; } return; }
private Transaction MakeTransaction(List <TransferRequestModel> transfers) { var lookup = transfers.ToLookup(t => new { t.Sender, t.Asset }); using var sb = new ScriptBuilder(); var snapshot = Helpers.GetDefaultSnapshot(); foreach (var transferRequests in lookup) { var sender = transferRequests.Key.Sender; var assetHash = transferRequests.Key.Asset; BigInteger amount = 0; transferRequests.ForEach(t => amount += t.Amount.Value); Console.WriteLine($"Transfer[{transferRequests.Key.Asset}]:{transferRequests.Key.Sender}=>{amount}"); var balance = sender.GetBalanceOf(assetHash, snapshot).Value; if (balance < amount) { //balance not enough return(null); } foreach (var transfer in transferRequests) { sb.EmitDynamicCall(assetHash, "transfer", sender, transfer.Receiver, transfer.Amount.Value, null); sb.Emit(OpCode.ASSERT); } } var script = sb.ToArray(); var senders = transfers.Select(t => t.Sender).ToHashSet(); var cosigners = senders.Select(p => new Signer() { // default access for transfers should be valid only for first invocation Scopes = WitnessScope.CalledByEntry, Account = p }).ToArray(); return(CurrentWallet.MakeTransaction(snapshot, script, null, cosigners, new TransactionAttribute[0])); }
private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UInt160 from = null, string data = null, UInt160[] signersAccounts = null) { var snapshot = NeoSystem.StoreView; var asset = new AssetDescriptor(snapshot, NeoSystem.Settings, tokenHash); var value = new BigDecimal(amount, asset.Decimals); if (NoWallet()) { return; } Transaction tx; try { tx = CurrentWallet.MakeTransaction(snapshot, new[] { new TransferOutput { AssetId = tokenHash, Value = value, ScriptHash = to, Data = data } }, from: from, cosigners: signersAccounts?.Select(p => new Signer { // default access for transfers should be valid only for first invocation Scopes = WitnessScope.CalledByEntry, Account = p }) .ToArray() ?? Array.Empty <Signer>()); } catch (InvalidOperationException e) { ConsoleHelper.Error(GetExceptionMessage(e)); return; } if (!ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(snapshot, tx); }
private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, string data = null, UInt160 from = null, UInt160[] signersAccounts = null) { 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, Data = data } }, from: from, cosigners: signersAccounts?.Select(p => new Signer { // default access for transfers should be valid only for first invocation Scopes = WitnessScope.CalledByEntry, Account = p }) .ToArray() ?? new Signer[0]); } catch (InvalidOperationException e) { Console.WriteLine("Error: " + GetExceptionMessage(e)); return; } if (!ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(tx); }
private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contractParameters = null, UInt160[] signerAccounts = null) { Signer[] signers = Array.Empty <Signer>(); if (signerAccounts != null && !NoWallet()) { signers = CurrentWallet.GetAccounts().Where(p => !p.Lock && !p.WatchOnly && signerAccounts.Contains(p.ScriptHash)).Select(p => new Signer() { Account = p.ScriptHash, Scopes = WitnessScope.CalledByEntry }).ToArray(); } Transaction tx = new Transaction { Signers = signers, Witnesses = Array.Empty <Witness>(), }; _ = OnInvokeWithResult(scriptHash, operation, tx, contractParameters); if (NoWallet()) { return; } try { tx = CurrentWallet.MakeTransaction(tx.Script, signers.Length > 0 ? signers[0].Account : null, signers); } catch (InvalidOperationException) { Console.WriteLine("Error: insufficient balance."); return; } if (!ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(tx); }
private void OnDeployCommand(string filePath, string manifestPath = null) { if (NoWallet()) { return; } byte[] script = LoadDeploymentScript(filePath, manifestPath, out var scriptHash); Transaction tx; try { tx = CurrentWallet.MakeTransaction(script); } catch (InvalidOperationException) { Console.WriteLine("Engine faulted."); return; } Console.WriteLine($"Script hash: {scriptHash.ToString()}"); Console.WriteLine($"Gas: {new BigDecimal(tx.SystemFee, NativeContract.GAS.Decimals)}"); Console.WriteLine(); SignAndSendTx(tx); }
private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 from = null, string data = null, UInt160[] signerAccounts = null) { if (NoWallet()) { return; } string password = ReadUserInput("password", true); if (password.Length == 0) { ConsoleHelper.Info("Cancelled"); return; } if (!CurrentWallet.VerifyPassword(password)) { ConsoleHelper.Error("Incorrect password"); return; } var snapshot = NeoSystem.StoreView; Transaction tx; AssetDescriptor descriptor = new(snapshot, NeoSystem.Settings, asset); if (!BigDecimal.TryParse(amount, descriptor.Decimals, out BigDecimal decimalAmount) || decimalAmount.Sign <= 0) { ConsoleHelper.Error("Incorrect Amount Format"); return; } try { tx = CurrentWallet.MakeTransaction(snapshot, new[] { new TransferOutput { AssetId = asset, Value = decimalAmount, ScriptHash = to, Data = data } }, from: from, cosigners: signerAccounts?.Select(p => new Signer { // default access for transfers should be valid only for first invocation Scopes = WitnessScope.CalledByEntry, Account = p }) .ToArray() ?? Array.Empty <Signer>()); } catch (Exception e) { ConsoleHelper.Error(GetExceptionMessage(e)); return; } if (tx == null) { ConsoleHelper.Warning("Insufficient funds"); return; } ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", "Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) { return; } SignAndSendTx(NeoSystem.StoreView, tx); }
private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contractParameters = null, UInt160[] witnessAddress = null) { List <ContractParameter> parameters = new List <ContractParameter>(); List <Cosigner> signCollection = new List <Cosigner>(); if (!NoWallet() && witnessAddress != null) { using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { UInt160[] accounts = CurrentWallet.GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).Where(p => NativeContract.GAS.BalanceOf(snapshot, p).Sign > 0).ToArray(); foreach (var signAccount in accounts) { if (witnessAddress is null) { break; } foreach (var witness in witnessAddress) { if (witness.Equals(signAccount)) { signCollection.Add(new Cosigner() { Account = signAccount }); break; } } } } } if (contractParameters != null) { foreach (var contractParameter in contractParameters) { parameters.Add(ContractParameter.FromJson(contractParameter)); } } Transaction tx = new Transaction { Sender = UInt160.Zero, Attributes = Array.Empty <TransactionAttribute>(), Witnesses = Array.Empty <Witness>(), 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.ToParameter().ToJson()))}"); Console.WriteLine(); if (engine.State.HasFlag(VMState.FAULT)) { Console.WriteLine("Engine faulted."); return; } } if (NoWallet()) { return; } try { tx = CurrentWallet.MakeTransaction(tx.Script, null, tx.Attributes, tx.Cosigners); } catch (InvalidOperationException) { Console.WriteLine("Error: insufficient balance."); return; } if (!ReadUserInput("relay tx(no|yes)").IsYes()) { return; } SignAndSendTx(tx); }
/// <summary> /// send asset /// </summary> /// <param name="sender"></param> /// <param name="receivers"></param> /// <param name="asset"></param> /// <returns></returns> public async Task <object> SendToMultiAddress(MultiReceiverRequest[] receivers, string asset = "neo", UInt160 sender = null) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } if (receivers.IsEmpty()) { return(Error(ErrorCode.ParameterIsNull, $"receivers is null!")); } UInt160 assetHash = ConvertToAssetId(asset, out var convertError); if (assetHash == null) { return(Error(ErrorCode.InvalidPara, $"asset is not valid:{convertError}")); } var assetInfo = AssetCache.GetAssetInfo(assetHash); if (assetInfo == null) { return(Error(ErrorCode.InvalidPara, $"asset is not valid:{convertError}")); } if (sender != null) { var account = CurrentWallet.GetAccount(sender); if (account == null) { return(Error(ErrorCode.AddressNotFound)); } } var toes = new List <(UInt160 scriptHash, BigDecimal amount)>(); foreach (var receiver in receivers) { if (!BigDecimal.TryParse(receiver.Amount, assetInfo.Decimals, out BigDecimal sendAmount) || sendAmount.Sign <= 0) { return(Error(ErrorCode.InvalidPara, $"Incorrect Amount Format:{receiver.Amount}")); } toes.Add((receiver.Address, sendAmount)); } var outputs = toes.Select(t => new TransferOutput() { AssetId = assetHash, Value = t.amount, ScriptHash = t.scriptHash, }).ToArray(); try { Transaction tx = CurrentWallet.MakeTransaction(Helpers.GetDefaultSnapshot(), outputs, sender); if (tx == null) { return(Error(ErrorCode.BalanceNotEnough, "Insufficient funds")); } var(signSuccess, context) = CurrentWallet.TrySignTx(tx); if (!signSuccess) { return(Error(ErrorCode.SignFail, context.SafeSerialize())); } await tx.Broadcast(); return(new TransactionModel(tx)); } catch (Exception ex) { if (ex.Message.Contains("Insufficient GAS")) { return(Error(ErrorCode.GasNotEnough)); } return(Error(ErrorCode.TransferError, ex.Message)); } }
public async Task <object> DeployContract(string nefPath, string manifestPath = null, bool sendTx = false, UInt160 sender = null) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } if (nefPath.IsNull()) { return(Error(ErrorCode.ParameterIsNull, "nefPath is empty.")); } if (manifestPath.IsNull()) { manifestPath = Path.ChangeExtension(nefPath, ".manifest.json"); } // Read nef NefFile nefFile = ReadNefFile(nefPath); // Read manifest ContractManifest manifest = ReadManifestFile(manifestPath); // Basic script checks await CheckBadOpcode(nefFile.Script); // Build script using ScriptBuilder sb = new ScriptBuilder(); sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nefFile.ToArray(), manifest.ToJson().ToString()); //sb.EmitAppCall(NativeContract.Management.Hash, "deploy", nefFile.ToArray(), manifest.ToJson().ToString()); var script = sb.ToArray(); Transaction tx; try { tx = CurrentWallet.MakeTransaction(Helpers.GetDefaultSnapshot(), script, sender); } catch (InvalidOperationException ex) { return(Error(ErrorCode.EngineFault, ex.GetExMessage())); } catch (Exception ex) { if (ex.Message.Contains("Insufficient GAS")) { return(Error(ErrorCode.GasNotEnough)); } throw; } UInt160 hash = SmartContract.Helper.GetContractHash(tx.Sender, nefFile.CheckSum, manifest.Name); var oldContract = hash.GetContract(); if (oldContract != null) { return(Error(ErrorCode.ContractAlreadyExist)); } var result = new DeployResultModel { ContractHash = hash, GasConsumed = new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals) }; if (sendTx) { var(signSuccess, context) = CurrentWallet.TrySignTx(tx); if (!signSuccess) { return(Error(ErrorCode.SignFail, context.SafeSerialize())); } await tx.Broadcast(); result.TxId = tx.Hash; } return(result); }
/// <summary> /// send asset /// </summary> /// <param name="sender"></param> /// <param name="receiver"></param> /// <param name="amount"></param> /// <param name="asset"></param> /// <returns></returns> public async Task <object> SendToAddress(UInt160 receiver, string amount, string asset = "neo", UInt160 sender = null) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } if (receiver == null) { return(Error(ErrorCode.ParameterIsNull, $"receiver address is null!")); } UInt160 assetHash = ConvertToAssetId(asset, out var convertError); if (assetHash == null) { return(Error(ErrorCode.InvalidPara, $"asset is not valid:{convertError}")); } var assetInfo = AssetCache.GetAssetInfo(assetHash); if (assetInfo == null) { return(Error(ErrorCode.InvalidPara, $"asset is not valid:{convertError}")); } if (!BigDecimal.TryParse(amount, assetInfo.Decimals, out BigDecimal sendAmount) || sendAmount.Sign <= 0) { return(Error(ErrorCode.InvalidPara, "Incorrect Amount Format")); } if (sender != null) { var account = CurrentWallet.GetAccount(sender); if (account == null) { return(Error(ErrorCode.AddressNotFound)); } var balance = sender.GetBalanceOf(assetHash); if (balance.Value < sendAmount.Value) { return(Error(ErrorCode.BalanceNotEnough)); } } try { Transaction tx = CurrentWallet.MakeTransaction(Helpers.GetDefaultSnapshot(), new[] { new TransferOutput { AssetId = assetHash, Value = sendAmount, ScriptHash = receiver } }, sender); if (tx == null) { return(Error(ErrorCode.BalanceNotEnough, "Insufficient funds")); } var(signSuccess, context) = CurrentWallet.TrySignTx(tx); if (!signSuccess) { return(Error(ErrorCode.SignFail, context.SafeSerialize())); } await tx.Broadcast(); return(new TransactionModel(tx)); } catch (Exception ex) { if (ex.Message.Contains("Insufficient GAS")) { return(Error(ErrorCode.GasNotEnough)); } return(Error(ErrorCode.TransferError, ex.Message)); } }
private bool OnInvokeCommand(string[] args) { var scriptHash = UInt160.Parse(args[1]); List <ContractParameter> contractParameters = new List <ContractParameter>(); for (int i = 3; i < args.Length; i++) { contractParameters.Add(new ContractParameter() { // TODO: support contract params of type other than string. Type = ContractParameterType.String, Value = args[i] }); } Transaction tx = new Transaction { Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, Attributes = new TransactionAttribute[0], Witnesses = new Witness[0] }; using (ScriptBuilder scriptBuilder = new ScriptBuilder()) { scriptBuilder.EmitDynamicCall(scriptHash, args[2], contractParameters.ToArray()); tx.Script = scriptBuilder.ToArray(); Console.WriteLine($"Invoking script with: '{tx.Script.ToHexString()}'"); } using (ApplicationEngine engine = tx.Script.RunTestMode(null, tx)) { Console.WriteLine($"VM State: {engine.State}"); Console.WriteLine($"Gas Consumed: {engine.GasConsumed}"); Console.WriteLine($"Evaluation Stack: {new JArray(engine.ResultStack.Select(p => p.ToContractParameter().ToJson()))}"); Console.WriteLine(); if (engine.State.HasFlag(VMState.FAULT)) { Console.WriteLine("Engine faulted."); return(true); } } if (NoWallet()) { return(true); } try { tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, tx.Script); } catch (InvalidOperationException) { Console.WriteLine("Error: insufficient balance."); return(true); } if (!ReadUserInput("relay tx(no|yes)").IsYes()) { return(true); } return(SignAndSendTx(tx)); }
private bool OnSendCommand(string[] args) { if (args.Length != 4) { Console.WriteLine("error"); return(true); } if (NoWallet()) { return(true); } string password = ReadUserInput("password", true); if (password.Length == 0) { Console.WriteLine("cancelled"); return(true); } if (!CurrentWallet.VerifyPassword(password)) { Console.WriteLine("Incorrect password"); return(true); } UInt160 assetId; switch (args[1].ToLower()) { case "neo": assetId = NativeContract.NEO.Hash; break; case "gas": assetId = NativeContract.GAS.Hash; break; default: assetId = UInt160.Parse(args[1]); break; } UInt160 to = args[2].ToScriptHash(); var snapshot = NeoSystem.StoreView; Transaction tx; AssetDescriptor descriptor = new AssetDescriptor(snapshot, CliSettings.Default.Protocol, assetId); if (!BigDecimal.TryParse(args[3], descriptor.Decimals, out BigDecimal amount) || amount.Sign <= 0) { Console.WriteLine("Incorrect Amount Format"); return(true); } tx = CurrentWallet.MakeTransaction(snapshot, new[] { new TransferOutput { AssetId = assetId, Value = amount, ScriptHash = to } }); if (tx == null) { Console.WriteLine("Insufficient funds"); return(true); } ContractParametersContext context = new ContractParametersContext(snapshot, tx, CliSettings.Default.Protocol.Network); CurrentWallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); NeoSystem.Blockchain.Tell(tx); //NeoSystem.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); Console.WriteLine($"TXID: {tx.Hash}"); } else { Console.WriteLine("SignatureContext:"); Console.WriteLine(context.ToString()); } return(true); }
private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifestPath, UInt160 sender, UInt160[] signerAccounts = null, JObject data = null) { Signer[] signers = Array.Empty <Signer>(); if (NoWallet()) { return; } if (sender != null) { if (signerAccounts == null) { signerAccounts = new UInt160[1] { sender } } ; else if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) { var signersList = signerAccounts.ToList(); signersList.Remove(sender); signerAccounts = signersList.Prepend(sender).ToArray(); } else if (!signerAccounts.Contains(sender)) { signerAccounts = signerAccounts.Prepend(sender).ToArray(); } signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.CalledByEntry }).ToArray(); } Transaction tx = new Transaction { Signers = signers, Attributes = Array.Empty <TransactionAttribute>(), Witnesses = Array.Empty <Witness>() }; try { byte[] script = LoadUpdateScript(scriptHash, filePath, manifestPath, data, out var nef, out var manifest); tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script, sender, signers); } catch (InvalidOperationException e) { ConsoleHelper.Error(GetExceptionMessage(e)); return; } ContractState contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, scriptHash); if (contract == null) { ConsoleHelper.Warning($"Can't upgrade, contract hash not exist: {scriptHash}"); } else { ConsoleHelper.Info("Contract hash: ", $"{scriptHash}"); ConsoleHelper.Info("Updated times: ", $"{contract.UpdateCounter}"); ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}"); ConsoleHelper.Info("Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay { return; } SignAndSendTx(NeoSystem.StoreView, tx); } }
public async Task <object> UpdateContract(UInt160 contractHash, string nefPath, string manifestPath = null, bool sendTx = false, UInt160[] cosigners = null) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } if (nefPath.IsNull()) { return(Error(ErrorCode.ParameterIsNull, "nefPath is empty.")); } if (manifestPath.IsNull()) { manifestPath = Path.ChangeExtension(nefPath, ".manifest.json"); } // Read nef NefFile nefFile = ReadNefFile(nefPath); // Read manifest ContractManifest manifest = ReadManifestFile(manifestPath); // Basic script checks await CheckBadOpcode(nefFile.Script); // Build script using ScriptBuilder sb = new ScriptBuilder(); sb.EmitDynamicCall(contractHash, "update", nefFile.ToArray(), manifest.ToJson().ToString(), null); var script = sb.ToArray(); var singers = new List <Signer> { }; if (cosigners != null) { singers.AddRange(cosigners.Select(s => new Signer() { Account = s, Scopes = WitnessScope.Global })); } Transaction tx; try { tx = CurrentWallet.MakeTransaction(Helpers.GetDefaultSnapshot(), script, null, singers.ToArray()); } catch (InvalidOperationException ex) { return(Error(ErrorCode.EngineFault, ex.GetExMessage())); } catch (Exception ex) { if (ex.Message.Contains("Insufficient GAS")) { return(Error(ErrorCode.GasNotEnough)); } throw; } var result = new DeployResultModel { ContractHash = contractHash, GasConsumed = new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals) }; if (sendTx) { var(signSuccess, context) = CurrentWallet.TrySignTx(tx); if (!signSuccess) { return(Error(ErrorCode.SignFail, context.SafeSerialize())); } await tx.Broadcast(); result.TxId = tx.Hash; } return(result); }
private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 from = null, UInt160[] signerAccounts = null) { if (NoWallet()) { return; } string password = ReadUserInput("password", true); if (password.Length == 0) { Console.WriteLine("Cancelled"); return; } if (!CurrentWallet.VerifyPassword(password)) { Console.WriteLine("Incorrect password"); return; } Transaction tx; AssetDescriptor descriptor = new AssetDescriptor(asset); if (!BigDecimal.TryParse(amount, descriptor.Decimals, out BigDecimal decimalAmount) || decimalAmount.Sign <= 0) { Console.WriteLine("Incorrect Amount Format"); return; } try { tx = CurrentWallet.MakeTransaction(new[] { new TransferOutput { AssetId = asset, Value = decimalAmount, ScriptHash = to } }, from: from, cosigners: signerAccounts?.Select(p => new Signer { // default access for transfers should be valid only for first invocation Scopes = WitnessScope.CalledByEntry, Account = p }) .ToArray() ?? new Signer[0]); } catch (Exception e) { Console.WriteLine("Error: " + GetExceptionMessage(e)); return; } if (tx == null) { Console.WriteLine("Insufficient funds"); return; } ContractParametersContext context = new ContractParametersContext(tx); CurrentWallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); NeoSystem.Blockchain.Tell(tx); Console.WriteLine($"TXID: {tx.Hash}"); } else { Console.WriteLine("SignatureContext:"); Console.WriteLine(context.ToString()); } }