/// <summary>
        /// Send an amount to a given address.
        /// amount is a real and is rounded to 8 decimal places. Returns the transaction ID <txid> if successful.
        /// </summary>
        /// <param name="toAddress">Target address</param>
        /// <param name="amount">Send amount</param>
        /// <param name="comment">Optional comment tied to the transaction</param>
        /// <param name="commentTo">Optional comment tied to the transaction</param>
        /// <returns>Wallet response wrapper; Success: transaction id, Error: WalletError object</returns>
        public static async Task <ParsedWalletResponse <string> > SendToAddressAsync(this WalletClient client,
                                                                                     string toAddress,
                                                                                     decimal amount,
                                                                                     string comment   = null,
                                                                                     string commentTo = null)
        {
            //make internal request to the wallet implementation
            var response = await client.MakeRequestAsync("sendtoaddress",
                                                         toAddress,
                                                         amount,
                                                         comment,
                                                         commentTo);

            if (response.Error == null)
            {
                return(ParsedWalletResponse <string> .CreateContent(response.Result));
            }
            else
            {
                return(ParsedWalletResponse <string> .CreateError(response.Error));
            }
        }
        static async Task CreateCornaddyInternal(BitcornResponse cornResponse, BitcornContext dbContext, WalletServer walletServer, UserWallet userWallet, string accessToken)
        {
            using (var client = new WalletClient(walletServer.Endpoint, accessToken))
            {
                var response = await client.GetNewAddressAsync("main");

                if (!response.IsError)
                {
                    var address = response.GetParsedContent();
                    userWallet.CornAddy     = address;
                    userWallet.WalletServer = walletServer.Index;

                    cornResponse.WalletObject = address;
                    await dbContext.SaveAsync();
                }
                //we got an error, fetch the internal wallet error code and figure out what to do
                else
                {
                    //get wallet error response
                    //var error = response.GetError();
                    cornResponse.WalletAvailable = false;
                }
            }
        }
        /// <summary>
        /// Returns an object containing various wallet state info.
        /// </summary>
        /// <returns>Wallet response wrapper; Success: WalletInfo object, Error: WalletError object</returns>
        public static async Task <ParsedWalletResponse <WalletInfo?> > GetWalletInfoAsync(this WalletClient client)
        {
            //make internal request to the wallet implementation
            var response = await client.MakeRequestAsync("getwalletinfo");

            if (response.Error == null)
            {
                //try deserialize walletinfo
                WalletInfo walletInfo = default(WalletInfo);

                try
                {
                    walletInfo = JsonConvert.DeserializeObject <WalletInfo>(response.Result);
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                return(ParsedWalletResponse <WalletInfo?> .CreateContent(walletInfo));
            }
            else
            {
                return(ParsedWalletResponse <WalletInfo?> .CreateError(response.Error));
            }
        }
        /// <summary>
        /// Get detailed information about in-wallet transaction <txid>.
        /// </summary>
        /// <param name="txid">Transaction id</param>
        /// <returns>Wallet response wrapper; Success: Transaction info object, Error: WalletError object</returns>
        public static async Task <ParsedWalletResponse <BlockchainTX> > GetTransactionAsync(this WalletClient client,
                                                                                            string txid,
                                                                                            bool includeWatchonly = false)
        {
            //make internal request to the wallet implementation
            var response = await client.MakeRequestAsync("gettransaction", txid, includeWatchonly);

            if (response.Error == null)
            {
                BlockchainTX transactionInfo = default(BlockchainTX);

                try
                {
                    transactionInfo = JsonConvert.DeserializeObject <BlockchainTX>(response.Result);
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                return(ParsedWalletResponse <BlockchainTX> .CreateContent(transactionInfo));
            }
            else
            {
                return(ParsedWalletResponse <BlockchainTX> .CreateError(response.Error));
            }
        }
        /// <summary>
        /// Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].
        /// If [account] not provided it'll return recent transactions from all accounts.
        /// </summary>
        /// <param name="walletAccount">List from this wallet account</param>
        /// <param name="count">How many transactions should be listed</param>
        /// <param name="from">Start index for the listing</param>
        /// <returns>Wallet response wrapper; Success: Json array of the transactions, Error: WalletError object</returns>
        public static async Task <ParsedWalletResponse <JArray> > ListTransactionsAsync(this WalletClient client,
                                                                                        string walletAccount  = null,
                                                                                        int count             = 10,
                                                                                        int from              = 0,
                                                                                        bool includeWatchonly = false)
        {
            WalletResponse response = null;

            //this has to be checked for null because if the walletAccount is null in the request object, this will be invalid request
            if (walletAccount != null)
            {
                //make internal request to the wallet implementation
                response = await client.MakeRequestAsync("listtransactions",
                                                         walletAccount,
                                                         count,
                                                         from,
                                                         includeWatchonly);
            }
            else
            {
                //not defining wallet account in the request is fine, but it cannot be defined as null
                //make internal request to the wallet implementation
                response = await client.MakeRequestAsync("listtransactions");
            }

            if (response.Error == null)
            {
                try
                {
                    var jsonArray = JArray.Parse(response.Result);
                    return(ParsedWalletResponse <JArray> .CreateContent(jsonArray));
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else
            {
                return(ParsedWalletResponse <JArray> .CreateError(response.Error));
            }
        }
        /// <summary>
        /// Returns Object that has account names as keys, account balances as values.
        /// </summary>
        /// <param name="miniumConfirmations"></param>
        /// <returns>Wallet response wrapper; Success: KeyValuePair array of the account balances, Error: WalletError object</returns>
        public static async Task <ParsedWalletResponse <KeyValuePair <string, decimal>[]> > ListAccountsAsync(this WalletClient client,
                                                                                                              int miniumConfirmations = 1,
                                                                                                              bool includeWatchonly   = false)
        {
            //make internal request to the wallet implementation
            var response = await client.MakeRequestAsync("listaccounts");

            if (response.Error == null)
            {
                //convert the response to KeyValuePair
                List <KeyValuePair <string, decimal> > list = new List <KeyValuePair <string, decimal> >();

                try
                {
                    foreach (var item in JObject.Parse(response.Result))
                    {
                        list.Add(new KeyValuePair <string, decimal>(item.Key, (decimal)item.Value));
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                return(ParsedWalletResponse <KeyValuePair <string, decimal>[]> .CreateContent(list.ToArray()));
            }
            else
            {
                return(ParsedWalletResponse <KeyValuePair <string, decimal>[]> .CreateError(response.Error));
            }
        }
        public static async Task <BitcornResponse> Withdraw(BitcornContext dbContext, IConfiguration configuration, User user, string cornAddy, decimal amount, string platform)
        {
            var cornResponse = new BitcornResponse();

            cornResponse.WalletAvailable = true;
            try
            {
                if (user.IsBanned)
                {
                    return(cornResponse);
                }
                if (user.UserWallet.Balance < amount)
                {
                    return(cornResponse);
                }

                var server = await dbContext.GetWalletServer(user.UserWallet);

                if (!server.Enabled || !server.WithdrawEnabled)
                {
                    cornResponse.WalletAvailable = false;
                    return(cornResponse);
                }

                string accessToken = await GetWalletServerAccessToken(configuration);

                //failed to fetch access token
                if (!CheckAccessTokenExists(accessToken))
                {
                    throw new UnauthorizedAccessException("Failed to fetch wallet server access token");
                }

                using (var client = new WalletClient(server.Endpoint, accessToken))
                {
                    var response = await client.SendToAddressAsync(cornAddy, amount);

                    if (!response.IsError)
                    {
                        string txId = response.GetParsedContent();
                        await DebitWithdrawTx(txId, user, server, amount, dbContext, platform);

                        cornResponse.WalletObject = txId;
                    }
                    //we got an error, fetch the internal wallet error code and figure out what to do
                    else
                    {
                        //get wallet error response
                        var error = response.GetError();

                        //invalid withdrawal address
                        if (error.Code == WalletErrorCodes.RPC_INVALID_ADDRESS_OR_KEY)
                        {
                            cornResponse.UserError = true;
                        }
                        //too much immature corn to complete this transaction at this time
                        else if (error.Code == WalletErrorCodes.RPC_WALLET_INSUFFICIENT_FUNDS)
                        {
                            cornResponse.WalletAvailable = false;
                        }
                        //wallet server was not reached
                        else if (error.Code == WalletErrorCodes.HTTP_ERROR)
                        {
                            cornResponse.WalletAvailable = false;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw e;
            }

            return(cornResponse);
        }