private string GetAddress(string UserMasterPublicKeyHot, string UserMasterPublicKeyCold, string NinkiMasterPublicKey, string path)
        {
            string[] errorMessage = new string[1];
            bool     isError      = false;

            //verify path
            foreach (char item in path)
            {
                if (!(Char.IsDigit(item) || item == '/' || item == 'm'))
                {
                    isError = true;
                }
            }

            string retaddress = "";

            string[] keys = new string[3];
            try
            {
                Console.WriteLine(UserMasterPublicKeyHot);

                BIP32 bip322 = new BIP32(UserMasterPublicKeyHot, _csprng.Getsecp256k1());

                BIP32  bip3221     = bip322.Derive(path);
                string derivedKey2 = HexString.FromByteArray(bip3221.eckey.pubKey);

                Console.WriteLine(UserMasterPublicKeyCold);

                BIP32  bip323      = new BIP32(UserMasterPublicKeyCold, _csprng.Getsecp256k1());
                BIP32  bip3231     = bip323.Derive(path);
                string derivedKey3 = HexString.FromByteArray(bip3231.eckey.pubKey);

                Console.WriteLine(NinkiMasterPublicKey);

                BIP32  bip321       = new BIP32(NinkiMasterPublicKey, _csprng.Getsecp256k1());
                BIP32  bip3211      = bip321.Derive(path);
                string derivedNinki = HexString.FromByteArray(bip3211.eckey.pubKey);

                retaddress = GetMultiSig2Of3Address(derivedKey2, derivedKey3, derivedNinki);

                keys[0] = derivedKey2;
                keys[1] = derivedKey3;
                keys[2] = derivedNinki;

                if (isError)
                {
                    return("ErrInvalid");
                }
            }
            catch (Exception ex)
            {
                errorMessage[0] = "ErrSystem";
                return("ErrInvalid");
            }

            return(retaddress);
        }
        public IActionResult CreateFriend([FromForm] string guid, [FromForm] string sharedid, [FromForm] string username, [FromForm] string node, [FromForm] string packetForFriend, [FromForm] string validationHash)
        {
            //add a db transaction to this function

            if (!Helper.IsCallerValid(guid, sharedid, _connstrWallet))
            {
                ErrorObject ro = new ErrorObject();
                ro.message = "ErrInvalid";
                ro.error   = true;
                return(Json(ro));
            }

            if (validationHash == null)
            {
                validationHash = "";
            }

            string errorMessage = "";
            bool   isError      = false;
            string cacheKey     = "";


            string[] spnode = node.Split('/');

            int nodeLeaf = int.Parse(spnode[spnode.Length - 1]);

            NpgsqlConnection conn = new NpgsqlConnection(_connstrWallet);

            conn.Open();

            NpgsqlTransaction tran = conn.BeginTransaction();

            try
            {
                NpgsqlCommand com = new NpgsqlCommand("sp_createfriend", conn);
                com.Transaction = tran;
                com.CommandType = CommandType.StoredProcedure;
                com.Parameters.Add(new NpgsqlParameter("p_guid", guid));
                com.Parameters.Add(new NpgsqlParameter("p_username", username));
                com.Parameters.Add(new NpgsqlParameter("p_packetforfriend", packetForFriend));
                com.Parameters.Add(new NpgsqlParameter("p_validationhash", validationHash));

                NpgsqlDataReader fread = com.ExecuteReader();

                if (fread.HasRows)
                {
                    if (fread.Read())
                    {
                        cacheKey = fread.GetString(0);
                    }
                }
                fread.Dispose();
                //walletidFriend

                //if there is a recipricol rejected request
                //reactivate the request to give the user the opportunity to accept


                //of course we have to derive from scratch here
                string ninkiPrivateKey = "";

                NpgsqlCommand cmd = new NpgsqlCommand("sp_getmasterkey", conn);
                cmd.Transaction = tran;
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new NpgsqlParameter("p_guid", guid));
                NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow);
                if (reader.HasRows)
                {
                    reader.Read();
                    ninkiPrivateKey = reader.GetString(0);
                }
                else
                {
                    isError      = true;
                    errorMessage = "ErrAccount";
                }
                reader.Dispose();


                ninkiPrivateKey = Helper.Decrypt(ninkiPrivateKey, _csprng);

                //use as seed
                BIP32 bip32  = new BIP32(ninkiPrivateKey, _csprng.Getsecp256k1());
                BIP32 bip321 = bip32.Derive("m/0/" + nodeLeaf.ToString());

                string publicKeyCache           = Helper.Encrypt(bip321.ExtendedPublicKeyString(null), _csprng);
                string privateKeyCacheEncrypted = Helper.Encrypt(bip321.ExtendedPrivateKeyString(null), _csprng);

                NpgsqlCommand cmd2 = new NpgsqlCommand("sp_createnodecache", conn);
                cmd2.Transaction = tran;
                cmd2.CommandType = CommandType.StoredProcedure;
                //com.Transaction = tran;
                cmd2.Parameters.Add(new NpgsqlParameter("p_guid", guid));
                cmd2.Parameters.Add(new NpgsqlParameter("p_nodelevel", node));
                cmd2.Parameters.Add(new NpgsqlParameter("p_ninkipub", publicKeyCache));
                cmd2.Parameters.Add(new NpgsqlParameter("p_ninkipk", privateKeyCacheEncrypted));
                cmd2.ExecuteNonQuery();

                tran.Commit();
                //derive the root ninki keys and cache in the NodeKeyCache table
            }
            catch (Exception ex)
            {
                tran.Rollback();
                isError      = true;
                errorMessage = "ErrSystem";
            }
            finally
            {
                conn.Close();
            }

            if (isError)
            {
                ErrorObject ro = new ErrorObject();
                ro.message = errorMessage;
                ro.error   = true;
                return(Json(ro));
            }
            else
            {
                CreateFriendReturnObject ret = new CreateFriendReturnObject();
                ret.CacheKey = cacheKey;
                return(Json(ret));
            }
        }