예제 #1
0
        /// <summary>
        /// send asset
        /// </summary>
        /// <returns></returns>
        public async Task <object> SendTo(TransferRequest[] transfers)
        {
            if (CurrentWallet == null)
            {
                return(Error(ErrorCode.WalletNotOpen));
            }
            if (transfers.IsEmpty())
            {
                return(Error(ErrorCode.ParameterIsNull));
            }

            var transferList = new List <TransferRequestModel>();

            foreach (var transferRequest in transfers)
            {
                var(transfer, error) = ParseTransferRequest(transferRequest);
                if (error.NotNull())
                {
                    return(Error(ErrorCode.InvalidPara, error));
                }
                transferList.Add(transfer);
            }

            try
            {
                var tx = MakeTransaction(transferList);
                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));
                }

                var error     = ex.Message;
                var currentEx = ex;
                while (currentEx.InnerException != null)
                {
                    currentEx = currentEx.InnerException;
                    error    += $"\r\n{currentEx.Message}";
                }
                return(Error(ErrorCode.TransferError, error));
            }
        }
예제 #2
0
        /// <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));
            }
        }
예제 #3
0
        /// <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));
            }
        }
예제 #4
0
        /// <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));
            }
        }
예제 #5
0
        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);
        }
예제 #6
0
        public async Task <object> InvokeContract(InvokeContractParameterModel para)
        {
            if (CurrentWallet == null)
            {
                return(Error(ErrorCode.WalletNotOpen));
            }
            if (para.ContractHash == null || para.Method.IsNull())
            {
                return(Error(ErrorCode.ParameterIsNull));
            }
            var contract = para.ContractHash.GetContract();

            if (contract == null)
            {
                return(Error(ErrorCode.UnknownContract));
            }

            ContractParameter[] contractParameters = null;
            try
            {
                contractParameters = para.Parameters?.Select(JsonToContractParameter).ToArray();
            }
            catch (Exception e)
            {
                return(Error(ErrorCode.InvalidPara));
            }

            var signers = new List <Signer>();

            if (para.Cosigners.NotEmpty())
            {
                signers.AddRange(para.Cosigners.Select(s => new Signer()
                {
                    Account = s.Account, Scopes = s.Scopes, AllowedContracts = new UInt160[0]
                }));
            }

            Transaction tx = null;

            using ScriptBuilder sb = new ScriptBuilder();
            sb.EmitDynamicCall(para.ContractHash, para.Method, contractParameters);

            try
            {
                tx = CurrentWallet.InitTransaction(sb.ToArray(), null, signers.ToArray());
            }
            catch (InvalidOperationException ex)
            {
                return(Error(ErrorCode.EngineFault, $"{ex.Message}\r\n   InnerError:{ex.InnerException}"));
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("Insufficient GAS"))
                {
                    return(Error(ErrorCode.GasNotEnough));
                }
                throw;
            }

            var(signSuccess, context) = CurrentWallet.TrySignTx(tx);
            if (!signSuccess)
            {
                return(Error(ErrorCode.SignFail, context.SafeSerialize()));
            }
            var result = new InvokeResultModel();

            using ApplicationEngine engine = tx.Script.RunTestMode(null, tx);
            result.VmState       = engine.State;
            result.GasConsumed   = new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals);
            result.ResultStack   = engine.ResultStack.Select(p => JStackItem.FromJson(p.ToContractParameter().ToJson())).ToList();
            result.Notifications = engine.Notifications?.Select(ConvertToEventModel).ToList();
            if (engine.State.HasFlag(VMState.FAULT))
            {
                return(Error(ErrorCode.EngineFault));
            }
            if (!para.SendTx)
            {
                return(result);
            }
            await tx.Broadcast();

            result.TxId = tx.Hash;
            return(result);
        }
예제 #7
0
        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);
        }