/// <summary> /// delete a address /// </summary> /// <returns></returns> public async Task <object> DeleteAddress(UInt160[] addresses) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } var result = addresses.Select(scriptHash => CurrentWallet.DeleteAccount(scriptHash)).ToList(); if (CurrentWallet is NEP6Wallet wallet) { wallet.Save(); } return(result); }
private void OnListKeyCommand() { if (NoWallet()) { return; } foreach (WalletAccount account in CurrentWallet.GetAccounts().Where(p => p.HasKey)) { ConsoleHelper.Info(" Address: ", account.Address); ConsoleHelper.Info("ScriptHash: ", account.ScriptHash.ToString()); ConsoleHelper.Info(" PublicKey: ", account.GetKey().PublicKey.EncodePoint(true).ToHexString()); Console.WriteLine(); } }
private void OnShowGasCommand() { if (NoWallet()) { return; } BigInteger gas = BigInteger.Zero; using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) { gas += NativeContract.NEO.UnclaimedGas(snapshot, account, snapshot.Height + 1); } Console.WriteLine($"Unclaimed gas: {new BigDecimal(gas, NativeContract.GAS.Decimals)}"); }
private void OnImportWatchOnlyCommand(string addressOrFile) { UInt160 address = null; try { address = StringToAddress(addressOrFile); } catch (FormatException) { } if (address is null) { var fileInfo = new FileInfo(addressOrFile); if (!fileInfo.Exists) { Console.WriteLine($"Error: File '{fileInfo.FullName}' doesn't exists"); return; } if (fileInfo.Length > 1024 * 1024) { if (!ReadUserInput($"The file '{fileInfo.FullName}' is too big, do you want to continue? (yes|no)", false).IsYes()) { return; } } string[] lines = File.ReadAllLines(fileInfo.FullName).Where(u => !string.IsNullOrEmpty(u)).ToArray(); using (var percent = new ConsolePercent(0, lines.Length)) { for (int i = 0; i < lines.Length; i++) { address = StringToAddress(lines[i]); CurrentWallet.CreateAccount(address); percent.Value++; } } } else { WalletAccount account = CurrentWallet.CreateAccount(address); Console.WriteLine($"Address: {account.Address}"); } if (CurrentWallet is NEP6Wallet wallet) { wallet.Save(); } }
private void OnShowGasCommand() { if (NoWallet()) { return; } BigInteger gas = BigInteger.Zero; var snapshot = NeoSystem.StoreView; uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) { gas += NativeContract.NEO.UnclaimedGas(snapshot, account, height); } ConsoleHelper.Info("Unclaimed gas: ", new BigDecimal(gas, NativeContract.GAS.Decimals).ToString()); }
/// <summary> /// append signature for text /// </summary> /// <param name="text"></param> /// <param name="address"></param> /// <returns></returns> public async Task <object> AppendTextSignature(string text, UInt160 address) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } var account = CurrentWallet.GetAccount(address); if (!account.HasKey) { return(Error(ErrorCode.AddressNotFoundPrivateKey)); } try { KeyPair key = account.GetKey(); byte[] signature = Crypto.Sign(Encoding.UTF8.GetBytes(text), key.PrivateKey, key.PublicKey.EncodePoint(false)[1..]);
public async Task <object> ChangePassword(string oldPassword, string newPassword) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } if (CurrentWallet.ChangePassword(oldPassword, newPassword)) { if (CurrentWallet is NEP6Wallet wallet) { wallet.Save(); } return(true); } return(false); }
/// <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)); } }
private void OnExportKeyCommand(string path = null, UInt160 scriptHash = null) { if (NoWallet()) { return; } if (path != null && File.Exists(path)) { Console.WriteLine($"Error: File '{path}' already exists"); return; } string password = ReadUserInput("password", true); if (password.Length == 0) { Console.WriteLine("Cancelled"); return; } if (!CurrentWallet.VerifyPassword(password)) { Console.WriteLine("Incorrect password"); return; } IEnumerable <KeyPair> keys; if (scriptHash == null) { keys = CurrentWallet.GetAccounts().Where(p => p.HasKey).Select(p => p.GetKey()); } else { var account = CurrentWallet.GetAccount(scriptHash); keys = account?.HasKey != true?Array.Empty <KeyPair>() : new[] { account.GetKey() }; } if (path == null) { foreach (KeyPair key in keys) { Console.WriteLine(key.Export()); } } else { File.WriteAllLines(path, keys.Select(p => p.Export())); } }
private bool OnShowGasCommand(string[] args) { if (NoWallet()) { return(true); } BigInteger gas = BigInteger.Zero; var snapshot = NeoSystem.StoreView; uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) { gas += NativeContract.NEO.UnclaimedGas(snapshot, account, height); } Console.WriteLine($"Unclaimed gas: {new BigDecimal(gas, NativeContract.GAS.Decimals)}"); return(true); }
/// <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; }
/// <summary> /// show unclaimed gas amount /// </summary> /// <returns></returns> public async Task <object> ShowGas() { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } BigInteger gas = BigInteger.Zero; var snapshot = Helpers.GetDefaultSnapshot(); foreach (UInt160 account in CurrentWallet.GetAccounts().Where(a => !a.WatchOnly).Select(p => p.ScriptHash)) { gas += NativeContract.NEO.UnclaimedGas(snapshot, account, snapshot.GetHeight() + 1); } return(new UnclaimedGasModel() { UnclaimedGas = new BigDecimal(gas, NativeContract.GAS.Decimals) }); }
private void OnListAssetCommand() { if (NoWallet()) { return; } foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) { Console.WriteLine(account.ToAddress()); Console.WriteLine($"NEO: {CurrentWallet.GetBalance(NativeContract.NEO.Hash, account)}"); Console.WriteLine($"GAS: {CurrentWallet.GetBalance(NativeContract.GAS.Hash, account)}"); Console.WriteLine(); } Console.WriteLine("----------------------------------------------------"); Console.WriteLine("Total: " + "NEO: " + CurrentWallet.GetAvailable(NativeContract.NEO.Hash) + " GAS: " + CurrentWallet.GetAvailable(NativeContract.GAS.Hash)); Console.WriteLine(); Console.WriteLine("NEO hash: " + NativeContract.NEO.Hash); Console.WriteLine("GAS hash: " + NativeContract.GAS.Hash); }
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 OnUnregisterCandidateCommand(UInt160 account) { if (NoWallet()) { Console.WriteLine("Need open wallet!"); return; } ECPoint publicKey = CurrentWallet.GetAccount(account)?.GetKey()?.PublicKey; byte[] script; using (ScriptBuilder scriptBuilder = new ScriptBuilder()) { scriptBuilder.EmitAppCall(NativeContract.NEO.Hash, "unregisterCandidate", publicKey); script = scriptBuilder.ToArray(); } SendTransaction(script, account); }
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])); }
/// <summary> /// create new standard address /// </summary> /// <returns></returns> public async Task <object> CreateAddress() { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } var newAccount = CurrentWallet.CreateAccount(); if (CurrentWallet is NEP6Wallet wallet) { wallet.Save(); } return(new AccountModel() { AccountType = AccountType.Standard, Address = newAccount.Address, ScriptHash = newAccount.ScriptHash, }); }
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 OnListAssetCommand() { var snapshot = NeoSystem.StoreView; if (NoWallet()) { return; } foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) { Console.WriteLine(account.ToAddress(NeoSystem.Settings.AddressVersion)); ConsoleHelper.Info("NEO: ", $"{CurrentWallet.GetBalance(snapshot, NativeContract.NEO.Hash, account)}"); ConsoleHelper.Info("GAS: ", $"{CurrentWallet.GetBalance(snapshot, NativeContract.GAS.Hash, account)}"); Console.WriteLine(); } Console.WriteLine("----------------------------------------------------"); ConsoleHelper.Info("Total: NEO: ", $"{CurrentWallet.GetAvailable(snapshot, NativeContract.NEO.Hash),10} ", "GAS: ", $"{CurrentWallet.GetAvailable(snapshot, NativeContract.GAS.Hash),18}"); Console.WriteLine(); ConsoleHelper.Info("NEO hash: ", NativeContract.NEO.Hash.ToString()); ConsoleHelper.Info("GAS hash: ", NativeContract.GAS.Hash.ToString()); }
private void OnCreateAddressCommand(ushort count = 1) { if (NoWallet()) { return; } string path = "address.txt"; if (File.Exists(path)) { if (!ReadUserInput($"The file '{path}' already exists, do you want to overwrite it? (yes|no)", false).IsYes()) { return; } } List <string> addresses = new List <string>(); using (var percent = new ConsolePercent(0, count)) { Parallel.For(0, count, (i) => { WalletAccount account = CurrentWallet.CreateAccount(); lock (addresses) { addresses.Add(account.Address); percent.Value++; } }); } if (CurrentWallet is NEP6Wallet wallet) { wallet.Save(); } Console.WriteLine($"Export addresses to {path}"); File.WriteAllLines(path, addresses); }
private bool OnListAssetCommand(string[] args) { if (NoWallet()) { return(true); } var snapshot = NeoSystem.StoreView; foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) { Console.WriteLine(account.ToAddress(NeoSystem.Settings.AddressVersion)); Console.WriteLine($"NEO: {CurrentWallet.GetBalance(snapshot, NativeContract.NEO.Hash, account)}"); Console.WriteLine($"GAS: {CurrentWallet.GetBalance(snapshot, NativeContract.GAS.Hash, account)}"); Console.WriteLine(); } Console.WriteLine("----------------------------------------------------"); Console.WriteLine($"Total: NEO: {CurrentWallet.GetAvailable(snapshot, NativeContract.NEO.Hash),10} GAS: {CurrentWallet.GetAvailable(snapshot, NativeContract.GAS.Hash),18}"); Console.WriteLine(); Console.WriteLine("NEO hash: " + NativeContract.NEO.Hash); Console.WriteLine("GAS hash: " + NativeContract.GAS.Hash); return(true); }
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 bool OnImportMultisigAddress(string[] args) { if (NoWallet()) { return(true); } if (args.Length < 4) { Console.WriteLine("Error. Invalid parameters."); return(true); } int m = int.Parse(args[2]); int n = args.Length - 3; if (m < 1 || m > n || n > 1024) { Console.WriteLine("Error. Invalid parameters."); return(true); } ECPoint[] publicKeys = args.Skip(3).Select(p => ECPoint.Parse(p, ECCurve.Secp256r1)).ToArray(); Contract multiSignContract = Contract.CreateMultiSigContract(m, publicKeys); KeyPair keyPair = CurrentWallet.GetAccounts().FirstOrDefault(p => p.HasKey && publicKeys.Contains(p.GetKey().PublicKey))?.GetKey(); WalletAccount account = CurrentWallet.CreateAccount(multiSignContract, keyPair); if (CurrentWallet is NEP6Wallet wallet) { wallet.Save(); } Console.WriteLine("Multisig. Addr.: " + multiSignContract.ScriptHash.ToAddress()); return(true); }
private void OnDeleteAddressCommand(UInt160 address) { if (NoWallet()) { return; } if (ReadUserInput($"Warning: Irrevocable operation!\nAre you sure to delete account {address.ToAddress(NeoSystem.Settings.AddressVersion)}? (no|yes)").IsYes()) { if (CurrentWallet.DeleteAccount(address)) { if (CurrentWallet is NEP6Wallet wallet) { wallet.Save(); } ConsoleHelper.Info($"Address {address} deleted."); } else { ConsoleHelper.Warning($"Address {address} doesn't exist."); } } }
private void SignAndSendTx(Transaction tx) { ContractParametersContext context; try { context = new ContractParametersContext(tx); } catch (InvalidOperationException e) { Console.WriteLine($"Error creating contract params: " + GetExceptionMessage(e)); throw; } CurrentWallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); NeoSystem.Blockchain.Tell(tx); Console.WriteLine($"Signed and relayed transaction with hash={tx.Hash}"); return; } Console.WriteLine($"Failed sending transaction with hash={tx.Hash}"); }
private void OnRegisterCandidateCommand(UInt160 account) { var testGas = NativeContract.NEO.GetRegisterPrice(NeoSystem.StoreView) + (BigInteger)Math.Pow(10, NativeContract.GAS.Decimals) * 10; if (NoWallet()) { Console.WriteLine("Need open wallet!"); return; } WalletAccount currentAccount = CurrentWallet.GetAccount(account); if (currentAccount == null) { Console.WriteLine("This address isn't in your wallet!"); return; } else { if (currentAccount.Lock || currentAccount.WatchOnly) { Console.WriteLine("Locked or WatchOnly address."); return; } } ECPoint publicKey = currentAccount?.GetKey()?.PublicKey; byte[] script; using (ScriptBuilder scriptBuilder = new ScriptBuilder()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "registerCandidate", publicKey); script = scriptBuilder.ToArray(); } SendTransaction(script, account, (long)testGas); }
private void OnRegisterCandidateCommand(UInt160 account, decimal maxGas = RegisterGas) { var gas = new BigDecimal(maxGas, NativeContract.GAS.Decimals); if (NoWallet()) { Console.WriteLine("Need open wallet!"); return; } WalletAccount currentAccount = CurrentWallet.GetAccount(account); if (currentAccount == null) { Console.WriteLine("This address isn't in your wallet!"); return; } else { if (currentAccount.Lock || currentAccount.WatchOnly) { Console.WriteLine("Locked or WatchOnly address."); return; } } ECPoint publicKey = currentAccount?.GetKey()?.PublicKey; byte[] script; using (ScriptBuilder scriptBuilder = new ScriptBuilder()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "registerCandidate", publicKey); script = scriptBuilder.ToArray(); } SendTransaction(script, account, (long)gas.Value); }
private bool OnListAddressCommand(string[] args) { if (NoWallet()) { return(true); } var snapshot = NeoSystem.StoreView; foreach (var account in CurrentWallet.GetAccounts()) { var contract = account.Contract; var type = "Nonstandard"; if (account.WatchOnly) { type = "WatchOnly"; } else if (contract.Script.IsMultiSigContract()) { type = "MultiSignature"; } else if (contract.Script.IsSignatureContract()) { type = "Standard"; } else if (NativeContract.ContractManagement.GetContract(snapshot, account.ScriptHash) != null) { type = "Deployed-Nonstandard"; } Console.WriteLine($"{" Address: "}{account.Address}\t{type}"); Console.WriteLine($"{"ScriptHash: "}{account.ScriptHash}\n"); } return(true); }
/// <summary> /// create new multi address /// </summary> /// <returns></returns> public async Task <object> CreateMultiAddress(int limit, string[] publicKeys) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } ECPoint[] points = null; try { points = publicKeys.Select(p => ECPoint.DecodePoint(Helper.HexToBytes(p), ECCurve.Secp256r1)).ToArray(); } catch (FormatException ex) { return(Error(ErrorCode.InvalidPara, ex.Message)); } Contract contract = Contract.CreateMultiSigContract(limit, points); if (contract == null) { return(Error(ErrorCode.CreateMultiContractFail)); } var hashSet = new HashSet <ECPoint>(points); var key = CurrentWallet.GetAccounts().FirstOrDefault(p => p.HasKey && hashSet.Contains(p.GetKey().PublicKey))?.GetKey(); var newAccount = CurrentWallet.CreateAccount(contract, key); if (CurrentWallet is NEP6Wallet wallet) { wallet.Save(); } return(new AccountModel() { AccountType = AccountType.MultiSignature, Address = newAccount.Address, ScriptHash = newAccount.ScriptHash, }); }