diff --git a/apps/web/app/account/create/components/account-create-form.tsx b/apps/web/app/account/create/components/account-create-form.tsx
index 319c37e7..207b8a82 100644
--- a/apps/web/app/account/create/components/account-create-form.tsx
+++ b/apps/web/app/account/create/components/account-create-form.tsx
@@ -3,13 +3,11 @@
import * as React from "react";
import { cn } from "@/lib/utils";
-import { Icons } from "@/components/ui/icons";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Form,
FormControl,
- FormDescription,
FormField,
FormItem,
FormLabel,
@@ -18,7 +16,7 @@ import {
import { useSession } from "next-auth/react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
-import { date, z } from "zod";
+import { z } from "zod";
import {
AccountCreateQuery,
AccountType,
@@ -31,7 +29,6 @@ import { loadingAtom } from "@paybox/recoil";
import { RocketIcon } from "@radix-ui/react-icons";
import { toast } from "sonner";
-import { Label } from "@/components/ui/label";
import {
Card,
@@ -41,20 +38,12 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card"
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select"
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
-import { Link } from "lucide-react";
import { useRouter } from "next/navigation";
import { AvatarUpload } from "./avatar-upload";
import { accountsAtom, defaultAccountNumberAtom } from "@paybox/recoil";
@@ -76,9 +65,6 @@ export function AccountCreateForm({
const [defaultNumber, setDefaultAccountNumber] = useRecoilState(defaultAccountNumberAtom);
const setAccounts = useSetRecoilState(accountsAtom);
- React.useEffect(() => {
- setDefaultAccountNumber(defaultAccountNumber);
- }, [defaultAccountNumber])
const form = useForm
>({
resolver: zodResolver(AccountCreateQuery),
@@ -88,6 +74,15 @@ export function AccountCreateForm({
},
});
+ React.useEffect(() => {
+ setDefaultAccountNumber(defaultAccountNumber);
+ }, [defaultAccountNumber]);
+
+ React.useEffect(() => {
+ form.setValue("name", `Account ${defaultNumber}`);
+ }, [defaultNumber]);
+
+
async function onSubmit(values: z.infer) {
const call = async () => {
try {
@@ -118,12 +113,6 @@ export function AccountCreateForm({
"Authorization": `Bearer ${jwt}`
},
}).then(res => res.json());
- setAccounts((oldAccounts) => {
- return [...oldAccounts, response.account]
- });
- setDefaultAccountNumber((oldNumber) => {
- return oldNumber + 1;
- });
return { account: response.account, status: response.status, msg: response.msg }
} catch (error) {
throw new Error("Error creating Account");
@@ -135,7 +124,10 @@ export function AccountCreateForm({
if (status == responseStatus.Error) {
return toast.error(msg)
}
- //TODO: set the account to the atom
+ setAccounts((oldAccounts) => {
+ return [...oldAccounts, account]
+ });
+ setDefaultAccountNumber((oldNumber) => oldNumber + 1);
return `Account '${account.name}' Created Successfully`
},
error({ status, msg }: { status: responseStatus, msg: string }) {
diff --git a/apps/web/app/account/page.tsx b/apps/web/app/account/page.tsx
index 02d80fe1..320d9c18 100644
--- a/apps/web/app/account/page.tsx
+++ b/apps/web/app/account/page.tsx
@@ -1,4 +1,12 @@
-export default function Page({ params }: { params: { id: string } }) {
+import { getServerSession } from "next-auth"
+import { authOptions } from "../api/auth/[...nextauth]/util"
+
+export default async function Page({ params, children }: { params: { id: string }, children: React.ReactNode }) {
+ const session = await getServerSession(authOptions);
console.log(params)
- return My Post: {params.id}
-}
\ No newline at end of file
+ return (
+
+ {children}
+
+ );
+}
diff --git a/apps/web/lib/config.ts b/apps/web/lib/config.ts
index e7c5da64..36f67d67 100644
--- a/apps/web/lib/config.ts
+++ b/apps/web/lib/config.ts
@@ -1,4 +1,7 @@
import { VAPID_PUBLIC_KEY_DEFAULT } from "@paybox/common";
export const VAPID_PUBLIC_KEY =
- process.env.VAPID_PUBLIC_KEY || VAPID_PUBLIC_KEY_DEFAULT;
\ No newline at end of file
+ process.env.VAPID_PUBLIC_KEY || VAPID_PUBLIC_KEY_DEFAULT;
+
+export const PRIVATE_KEY_ENCRYPTION_KEY =
+ process.env.PRIVATE_KEY_ENCRYPTION_KEY || "e53e0e6fb7120f8793e0127371f6265a52e9baecdbf3e336f7965a6b5bad9282";
\ No newline at end of file
diff --git a/apps/web/lib/helper.ts b/apps/web/lib/helper.ts
index f63e4fa7..0ece5c17 100644
--- a/apps/web/lib/helper.ts
+++ b/apps/web/lib/helper.ts
@@ -1,4 +1,5 @@
-
+import crypto from 'crypto';
+import { PRIVATE_KEY_ENCRYPTION_KEY } from './config';
export function toBase64(file: File) {
return new Promise((resolve, reject) => {
@@ -40,4 +41,36 @@ export function urlBase64ToUint8Array(base64String: string) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
+}
+
+const commonEncryptionKey = crypto
+ .createHash('sha256')
+ .update(PRIVATE_KEY_ENCRYPTION_KEY)
+ .digest();
+
+
+/**
+ *
+ * @param encryptedPrivateKey
+ * @param password
+ * @returns
+ */
+export const decryptWithPassword = (
+ encryptedPrivateKey: string,
+ password: string,
+): string => {
+ const [iv, commonCipherIv, encrypted] = encryptedPrivateKey.split(':');
+
+ const hashedPassword = crypto.createHash('sha256').update(password).digest();
+ const commonDecipher = crypto.createDecipheriv('aes-256-cbc', commonEncryptionKey, Buffer.from(commonCipherIv, 'hex'));
+
+ let decryptedPrivateKey = commonDecipher.update(encrypted, 'hex', 'hex');
+ decryptedPrivateKey += commonDecipher.final('hex');
+
+ const decipher = crypto.createDecipheriv('aes-256-cbc', hashedPassword, Buffer.from(iv, 'hex'));
+
+ let privateKey = decipher.update(decryptedPrivateKey, 'hex', 'utf8');
+ privateKey += decipher.final('utf8');
+
+ return privateKey;
}
\ No newline at end of file
diff --git a/apps/web/package.json b/apps/web/package.json
index f398d5ae..c4350edf 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -53,6 +53,7 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cmdk": "^0.2.0",
+ "crypto": "^1.0.1",
"date-fns": "^3.4.0",
"emoji-mart": "^5.5.2",
"eslint": "8.56.0",
diff --git a/backend/api/.env.example b/backend/api/.env.example
index 28b8320f..33d99d9a 100644
--- a/backend/api/.env.example
+++ b/backend/api/.env.example
@@ -25,4 +25,5 @@ PROCESS=
NOTIF_KAFKA_ID=
NOTIF_KAFKA_URL=
CHAT_KAFKA_URL=
-CHAT_KAFKA_ID=
\ No newline at end of file
+CHAT_KAFKA_ID=
+PRIVATE_KEY_ENCRYPTION_KEY=
\ No newline at end of file
diff --git a/backend/api/src/auth/util.ts b/backend/api/src/auth/util.ts
index ff25ac0d..9c97f336 100644
--- a/backend/api/src/auth/util.ts
+++ b/backend/api/src/auth/util.ts
@@ -1,7 +1,7 @@
import { response, type Request, type Response } from "express";
import { importPKCS8, importSPKI, jwtVerify, SignJWT } from "jose";
import bcryptjs from "bcryptjs";
-import { AUTH_JWT_PRIVATE_KEY, AUTH_JWT_PUBLIC_KEY, GMAIL, TWILLO_NUMBER } from "../config";
+import { AUTH_JWT_PRIVATE_KEY, AUTH_JWT_PUBLIC_KEY, GMAIL, PRIVATE_KEY_ENCRYPTION_KEY, TWILLO_NUMBER } from "../config";
import {
Address,
CLIENT_URL,
@@ -275,7 +275,7 @@ export const updateKey = async (bucketName: string, key: string, newKey: string)
// 'Upload-Date': new Date().toISOString(),
'owner': 'paybox'
}
- }) ;
+ });
const deleteCommand = new DeleteObjectCommand({
Bucket: bucketName,
@@ -296,3 +296,60 @@ export const calculateGas = (gasLimit: BigInt, gasPrice: BigInt): number => {
const maxGasFeeInWei = Number(gasLimit) * Number(gasPrice);
return maxGasFeeInWei / 1e18;
};
+
+const commonEncryptionKey = crypto
+ .createHash('sha256')
+ .update(PRIVATE_KEY_ENCRYPTION_KEY)
+ .digest();
+
+/**
+ *
+ * @param privateKey
+ * @param password
+ * @returns
+ */
+export const encryptWithPassword = (
+ privateKey: string,
+ password: string,
+): string => {
+ const hashedPassword = crypto.createHash('sha256').update(password).digest();
+ const iv = crypto.randomBytes(16);
+ const cipher = crypto.createCipheriv('aes-256-cbc', hashedPassword, iv);
+
+ let encryptedPrivateKey = cipher.update(privateKey, 'utf8', 'hex');
+ encryptedPrivateKey += cipher.final('hex');
+
+ const commonCipherIv = crypto.randomBytes(16);
+ const commonCipher = crypto.createCipheriv('aes-256-cbc', commonEncryptionKey, commonCipherIv);
+
+ encryptedPrivateKey = commonCipher.update(encryptedPrivateKey, 'hex', 'hex');
+ encryptedPrivateKey += commonCipher.final('hex');
+
+ return iv.toString('hex') + ':' + commonCipherIv.toString('hex') + ':' + encryptedPrivateKey;
+}
+
+/**
+ *
+ * @param encryptedPrivateKey
+ * @param password
+ * @returns
+ */
+export const decryptWithPassword = (
+ encryptedPrivateKey: string,
+ password: string,
+): string => {
+ const [iv, commonCipherIv, encrypted] = encryptedPrivateKey.split(':');
+
+ const hashedPassword = crypto.createHash('sha256').update(password).digest();
+ const commonDecipher = crypto.createDecipheriv('aes-256-cbc', commonEncryptionKey, Buffer.from(commonCipherIv, 'hex'));
+
+ let decryptedPrivateKey = commonDecipher.update(encrypted, 'hex', 'hex');
+ decryptedPrivateKey += commonDecipher.final('hex');
+
+ const decipher = crypto.createDecipheriv('aes-256-cbc', hashedPassword, Buffer.from(iv, 'hex'));
+
+ let privateKey = decipher.update(decryptedPrivateKey, 'hex', 'utf8');
+ privateKey += decipher.final('utf8');
+
+ return privateKey;
+}
\ No newline at end of file
diff --git a/backend/api/src/config.ts b/backend/api/src/config.ts
index 9012f3c7..998db0c5 100644
--- a/backend/api/src/config.ts
+++ b/backend/api/src/config.ts
@@ -74,4 +74,7 @@ export const CHAT_KAFKA_URL =
process.env.CHAT_KAFKA_URL || KAFKA_URL;
export const CHAT_KAFKA_ID =
- process.env.CHAT_KAFKA_ID || KAFKA_CLIENT_ID;
\ No newline at end of file
+ process.env.CHAT_KAFKA_ID || KAFKA_CLIENT_ID;
+
+export const PRIVATE_KEY_ENCRYPTION_KEY =
+ process.env.PRIVATE_KEY_ENCRYPTION_KEY || "e53e0e6fb7120f8793e0127371f6265a52e9baecdbf3e336f7965a6b5bad9282";
\ No newline at end of file
diff --git a/backend/api/src/routes/account.ts b/backend/api/src/routes/account.ts
index fb108bf5..6066eb64 100644
--- a/backend/api/src/routes/account.ts
+++ b/backend/api/src/routes/account.ts
@@ -56,6 +56,14 @@ accountRouter.post("/", accountCreateRateLimit, async (req, res) => {
if (id) {
const { name, imgUrl } = AccountCreateQuery.parse(req.query);
+ let hashPassword = (await Redis.getRedisInst().clientCache.getClientCache(id))?.password
+ || (await getPassword(id)).hashPassword;
+ if (!hashPassword) {
+ return res
+ .status(404)
+ .json({ status: responseStatus.Error, msg: "Account Not Found" });
+ }
+
/**
* Create an public and private key
*/
@@ -65,8 +73,8 @@ accountRouter.post("/", accountCreateRateLimit, async (req, res) => {
.status(503)
.json({ msg: "Database Error", status: responseStatus.Error });
}
- const solKeys = await (new SolOps()).createAccount(query.secretPhase);
- const ethKeys = (new EthOps()).createAccount(query.secretPhase);
+ const solKeys = await (new SolOps()).createAccount(query.secretPhase, hashPassword);
+ const ethKeys = (new EthOps()).createAccount(query.secretPhase, hashPassword);
const mutation = await createAccount(
id,
query.id,
@@ -164,17 +172,27 @@ accountRouter.post("/privateKey", checkPassword, async (req, res) => {
//@ts-ignore
const id = req.id;
if (id) {
- const { network, accountId } = AccountGetPrivateKey.parse(req.body);
+ const { accountId } = AccountGetPrivateKey.parse(req.body);
+
+ let hashPassword = (await Redis.getRedisInst().clientCache.getClientCache(id))?.password
+ || (await getPassword(id)).hashPassword;
+ if (!hashPassword) {
+ return res
+ .status(404)
+ .json({ status: responseStatus.Error, msg: "Account Not Found" });
+ }
- const query = await getPrivate(accountId, network);
- if (query.status == dbResStatus.Error || query.privateKey == undefined) {
+ const query = await getPrivate(accountId);
+ if (query.status == dbResStatus.Error || query.sol == undefined || query.eth == undefined) {
return res
.status(503)
.json({ msg: "Database Error", status: responseStatus.Error });
}
return res.status(200).json({
status: responseStatus.Ok,
- privateKey: query.privateKey,
+ sol: query.sol,
+ eth: query.eth,
+ hashPassword,
});
}
return res
@@ -278,12 +296,21 @@ accountRouter.post("/private", async (req, res) => {
const id = req.id;
if (id) {
const { secretKey, name, network } = ImportAccountSecret.parse(req.query);
+
+ let hashPassword = (await Redis.getRedisInst().clientCache.getClientCache(id))?.password
+ || (await getPassword(id)).hashPassword;
+ if (!hashPassword) {
+ return res
+ .status(404)
+ .json({ status: responseStatus.Error, msg: "Account Not Found" });
+ }
+
let keys = {} as WalletKeys;
switch (network) {
case Network.Sol:
- keys = await (new SolOps()).fromSecret(secretKey);
+ keys = await (new SolOps()).fromSecret(secretKey, hashPassword);
case Network.Eth:
- keys = (new EthOps).fromSecret(secretKey);
+ keys = (new EthOps).fromSecret(secretKey, hashPassword);
case Network.Bitcoin:
case Network.USDC:
break;
diff --git a/backend/api/src/routes/client.ts b/backend/api/src/routes/client.ts
index a924275b..f069a8b0 100644
--- a/backend/api/src/routes/client.ts
+++ b/backend/api/src/routes/client.ts
@@ -30,11 +30,12 @@ import {
updatePassword,
validateClient,
genRand,
- checkPassword,
- extractClientId,
+ checkPassword,
+ extractClientId,
isValidated,
validatePassword,
setJWTCookie,
+ getPassword,
} from "@paybox/backend-common";
import { Redis } from "../index";
import {
@@ -43,7 +44,7 @@ import {
sendOTP,
setHashPassword,
} from "../auth/util";
-import { resendOtpLimiter } from "../auth/middleware";
+import { resendOtpLimiter } from "../auth/middleware";
import {
Client,
ClientSigninFormValidate,
@@ -144,9 +145,17 @@ clientRouter.patch("/valid", extractClientId, isValidated, async (req, res) => {
.json({ msg: "Invalid otp 🥲", status: responseStatus.Error });
}
+ let hashPassword = (await Redis.getRedisInst().clientCache.getClientCache(tempCache))?.password
+ || (await getPassword(tempCache)).hashPassword;
+ if (!hashPassword) {
+ return res
+ .status(404)
+ .json({ status: responseStatus.Error, msg: "Account Not Found" });
+ }
+
const seed = generateSeed(SECRET_PHASE_STRENGTH);
- const solKeys = await (new SolOps()).createWallet(seed);
- const ethKeys = (new EthOps()).createWallet(seed);
+ const solKeys = await (new SolOps()).createWallet(seed, hashPassword);
+ const ethKeys = (new EthOps()).createWallet(seed, hashPassword);
const validate = await validateClient(id, seed, 'Account 1', solKeys, ethKeys);
if (validate.status == dbResStatus.Error || validate.walletId == undefined || validate.account == undefined) {
@@ -162,12 +171,12 @@ clientRouter.patch("/valid", extractClientId, isValidated, async (req, res) => {
/**
* Cache
*/
- await Redis.getRedisInst().wallet.handleValid({
- id: validate.walletId,
- clientId: id,
- accounts: [validate.account],
- }, id, validate.account);
-
+ await Redis.getRedisInst().wallet.handleValid({
+ id: validate.walletId,
+ clientId: id,
+ accounts: [validate.account],
+ }, id, validate.account);
+
return res
.status(200)
.json({
@@ -248,7 +257,7 @@ clientRouter.post("/providerAuth", async (req, res) => {
/**
* Check password
*/
- if(password) {
+ if (password) {
const isCorrectPass = await validatePassword(
password,
client.password as string,
diff --git a/backend/api/src/sockets/eth.ts b/backend/api/src/sockets/eth.ts
index a3fe5025..1f23033e 100644
--- a/backend/api/src/sockets/eth.ts
+++ b/backend/api/src/sockets/eth.ts
@@ -17,6 +17,7 @@ import {
} from "@paybox/common";
import { EthNetwok } from "../types/address";
import { INFURA_PROJECT_ID } from "../config";
+import { encryptWithPassword } from "../auth";
interface EthereumTransactionData {
@@ -50,11 +51,11 @@ export class EthOps {
* @param secretPhrase
* @returns
*/
- createWallet(secretPhrase: string): WalletKeys {
+ createWallet(secretPhrase: string, hashPassword: string): WalletKeys {
const wallet = ethers.Wallet.fromPhrase(secretPhrase);
const keys: WalletKeys = {
- privateKey: wallet.privateKey,
+ privateKey: encryptWithPassword(wallet.privateKey, hashPassword),
publicKey: wallet.address,
};
return keys;
@@ -65,7 +66,7 @@ export class EthOps {
* @param secretPhrase
* @returns
*/
- createAccount(secretPhrase: string): WalletKeys {
+ createAccount(secretPhrase: string, hashPassword: string): WalletKeys {
const accountIndex = Math.round(Date.now() / 1000);
const path = `m/44'/60'/${accountIndex}'/0/0`;
const wallet = ethers.HDNodeWallet.fromPhrase(
@@ -75,7 +76,7 @@ export class EthOps {
);
const keys: WalletKeys = {
- privateKey: wallet.privateKey,
+ privateKey: encryptWithPassword(wallet.privateKey, hashPassword),
publicKey: wallet.address,
};
return keys;
@@ -110,11 +111,11 @@ export class EthOps {
* @param secretKey
* @returns
*/
- fromSecret(secretKey: string): WalletKeys {
+ fromSecret(secretKey: string, hashPassword: string): WalletKeys {
const wallet = new ethers.Wallet(secretKey);
const keys: WalletKeys = {
- privateKey: wallet.privateKey,
+ privateKey: encryptWithPassword(wallet.privateKey, hashPassword),
publicKey: wallet.address,
};
return keys;
diff --git a/backend/api/src/sockets/sol.ts b/backend/api/src/sockets/sol.ts
index 33fc6810..e7ad5771 100644
--- a/backend/api/src/sockets/sol.ts
+++ b/backend/api/src/sockets/sol.ts
@@ -28,6 +28,7 @@ import {
import bs58 from "bs58";
import * as bip32 from "bip32";
import { derivePath } from "ed25519-hd-key";
+import { encryptWithPassword } from "../auth";
export class SolOps {
private connection: Connection;
@@ -38,24 +39,26 @@ export class SolOps {
this.connection = new Connection(this.rpcUrl, "confirmed");
}
- async createWallet(secretPhrase: string): Promise {
+ async createWallet(secretPhrase: string, hashPassword: string): Promise {
const seedBuffer = await bip39.mnemonicToSeed(secretPhrase);
const seedKeyArray = Uint8Array.from(seedBuffer.subarray(0, 32));
const keyPair = Keypair.fromSeed(seedKeyArray);
+
return {
publicKey: keyPair.publicKey.toBase58(),
- privateKey: base58.encode(keyPair.secretKey),
+ privateKey: encryptWithPassword(base58.encode(keyPair.secretKey), hashPassword),
};
}
- async createAccount(secretPhrase: string): Promise {
+ async createAccount(secretPhrase: string, hashPassword: string): Promise {
const accountIndex = Math.round(Date.now() / 1000);
const path = `m/44'/501'/${accountIndex}'/0'`;
const derivedSeed = derivePath(path, secretPhrase).key;
const keyPair = Keypair.fromSeed(derivedSeed);
+ console.log('from back', base58.encode(keyPair.secretKey));
return {
publicKey: keyPair.publicKey.toBase58(),
- privateKey: base58.encode(keyPair.secretKey),
+ privateKey: encryptWithPassword(base58.encode(keyPair.secretKey), hashPassword),
};
}
@@ -80,7 +83,7 @@ export class SolOps {
return accounts;
}
- async fromSecret(secretKey: string): Promise {
+ async fromSecret(secretKey: string, hashPassword: string): Promise {
const decodedBytes = bs58.decode(secretKey);
console.log(decodedBytes);
const privateKeyArray = new Uint8Array(decodedBytes);
@@ -88,7 +91,7 @@ export class SolOps {
const keyPair = Keypair.fromSecretKey(decodedBytes);
return {
publicKey: keyPair.publicKey.toBase58(),
- privateKey: base58.encode(keyPair.secretKey),
+ privateKey: encryptWithPassword(base58.encode(keyPair.secretKey), hashPassword),
};
}
diff --git a/backend/backend-common/src/db/account.ts b/backend/backend-common/src/db/account.ts
index 383aad18..19f68cf5 100644
--- a/backend/backend-common/src/db/account.ts
+++ b/backend/backend-common/src/db/account.ts
@@ -185,41 +185,45 @@ export const updateAccountName = async (
*/
export const getPrivate = async (
accountId: string,
- network: Network,
): Promise<{
status: dbResStatus;
- privateKey?: string;
-}> => {
- const returning = {
- [network]: {
- privateKey: true,
- },
+ sol?: {
+ privateKey: string
};
- const response = await chain("query")(
- {
- account: [
- {
- where: {
- id: { _eq: accountId },
- },
- },
- returning,
- ],
- },
- { operationName: "getPrivate" },
- );
- //@ts-ignore
- if (response.account[0][network]?.privateKey) {
+ eth?: {
+ privateKey: string
+ }
+}> => {
+ const response = await chain("query")({
+ account: [{
+ limit: 1,
+ where: {
+ id: { _eq: accountId }
+ }
+ }, {
+ sol: {
+ privateKey: true
+ },
+ eth: {
+ privateKey: true
+ },
+ }]
+ });
+ if (response.account[0].eth?.privateKey && response.account[0].sol?.privateKey) {
return {
status: dbResStatus.Ok,
- //@ts-ignore
- privateKey: response.account[0][network]?.privateKey,
- };
- }
+ sol: {
+ privateKey: response.account[0].sol.privateKey as string
+ },
+ eth: {
+ privateKey: response.account[0].eth.privateKey as string
+ }
+ }
+ };
return {
status: dbResStatus.Error,
};
-};
+}
/**
* Remove Account
@@ -353,7 +357,7 @@ export const getAccounts = async (
order_by: [{
createdAt: order_by["asc"]
}]
- },
+ },
{
id: true,
eth: {
diff --git a/backend/backend-common/src/db/friendship.ts b/backend/backend-common/src/db/friendship.ts
index ab82005c..79d0cf83 100644
--- a/backend/backend-common/src/db/friendship.ts
+++ b/backend/backend-common/src/db/friendship.ts
@@ -182,6 +182,7 @@ export const acceptFriendship = async (
return {
status: dbResStatus.Ok,
friendshipStatus: response.update_friendship?.returning[0].status as FriendshipStatus,
+ //@ts-ignore
to: response.update_friendship?.returning[0].client1.id === clientId ? response.update_friendship?.returning[0].client2.username as string : response.update_friendship?.returning[0].client1.username as string
}
}
@@ -236,6 +237,7 @@ export const putFriendshipStatus = async (
return {
status: dbResStatus.Ok,
friendshipStatus: response.update_friendship?.returning[0].status as FriendshipStatus,
+ //@ts-ignore
to: response.update_friendship?.returning[0].client1.id === clientId ? response.update_friendship?.returning[0].client2.username as string : response.update_friendship?.returning[0].client1.username as string
}
}
diff --git a/backend/hasura/docker-compose.yml b/backend/hasura/docker-compose.yml
index 2667cc46..e256c4be 100644
--- a/backend/hasura/docker-compose.yml
+++ b/backend/hasura/docker-compose.yml
@@ -29,7 +29,7 @@ services:
timeout: 5s
hasura:
- image: hasura/graphql-engine:v2.38.0
+ image: hasura/graphql-engine:v2.18.0.cli-migrations-v3
ports:
- 8112:8080
depends_on:
diff --git a/backend/hasura/hasura/metadata/databases/default/tables/public_friendship.yaml b/backend/hasura/hasura/metadata/databases/default/tables/public_friendship.yaml
index 1800f541..4f16bcd5 100644
--- a/backend/hasura/hasura/metadata/databases/default/tables/public_friendship.yaml
+++ b/backend/hasura/hasura/metadata/databases/default/tables/public_friendship.yaml
@@ -12,10 +12,10 @@ configuration:
updated_at: updatedAt
custom_root_fields: {}
object_relationships:
- - name: client1
+ - name: client
using:
foreign_key_constraint_on: clientId1
- - name: client2
+ - name: clientByClientid2
using:
foreign_key_constraint_on: clientId2
array_relationships:
diff --git a/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/down.sql b/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/down.sql
new file mode 100644
index 00000000..9a1299a4
--- /dev/null
+++ b/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/down.sql
@@ -0,0 +1,3 @@
+-- Could not auto-generate a down migration.
+-- Please write an appropriate down migration for the SQL below:
+-- drop schema "check" cascade;
diff --git a/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/up.sql b/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/up.sql
new file mode 100644
index 00000000..2a17fc26
--- /dev/null
+++ b/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/up.sql
@@ -0,0 +1 @@
+drop schema "check" cascade;
diff --git a/backend/zeus/src/codegen/types.ts b/backend/zeus/src/codegen/types.ts
index fe55ac0d..34458cb8 100644
--- a/backend/zeus/src/codegen/types.ts
+++ b/backend/zeus/src/codegen/types.ts
@@ -2082,9 +2082,9 @@ export type Friendship = {
/** An aggregate relationship */
chats_aggregate: Chat_Aggregate;
/** An object relationship */
- client1: Client;
+ client: Client;
/** An object relationship */
- client2: Client;
+ clientByClientid2: Client;
clientId1: Scalars['uuid']['output'];
clientId2: Scalars['uuid']['output'];
createdAt: Scalars['timestamptz']['output'];
@@ -2167,8 +2167,8 @@ export type Friendship_Bool_Exp = {
_or?: InputMaybe>;
chats?: InputMaybe;
chats_aggregate?: InputMaybe;
- client1?: InputMaybe;
- client2?: InputMaybe;
+ client?: InputMaybe;
+ clientByClientid2?: InputMaybe;
clientId1?: InputMaybe;
clientId2?: InputMaybe;
createdAt?: InputMaybe;
@@ -2186,8 +2186,8 @@ export enum Friendship_Constraint {
/** input type for inserting data into table "friendship" */
export type Friendship_Insert_Input = {
chats?: InputMaybe;
- client1?: InputMaybe;
- client2?: InputMaybe;
+ client?: InputMaybe;
+ clientByClientid2?: InputMaybe;
clientId1?: InputMaybe;
clientId2?: InputMaybe;
createdAt?: InputMaybe;
@@ -2264,8 +2264,8 @@ export type Friendship_On_Conflict = {
/** Ordering options when selecting data from "friendship". */
export type Friendship_Order_By = {
chats_aggregate?: InputMaybe;
- client1?: InputMaybe;
- client2?: InputMaybe;
+ client?: InputMaybe;
+ clientByClientid2?: InputMaybe;
clientId1?: InputMaybe;
clientId2?: InputMaybe;
createdAt?: InputMaybe;
@@ -3362,7 +3362,6 @@ export type Notification_Subscription = {
id: Scalars['uuid']['output'];
p256dh: Scalars['String']['output'];
updatedAt: Scalars['timestamptz']['output'];
- uuid: Scalars['uuid']['output'];
};
/** aggregated selection of "notification_subscription" */
@@ -3425,11 +3424,12 @@ export type Notification_Subscription_Bool_Exp = {
id?: InputMaybe;
p256dh?: InputMaybe;
updatedAt?: InputMaybe;
- uuid?: InputMaybe;
};
/** unique or primary key constraints on table "notification_subscription" */
export enum Notification_Subscription_Constraint {
+ /** unique or primary key constraint on columns "endpoint" */
+ NotificationSubscriptionEndpointKey = 'notification_subscription_endpoint_key',
/** unique or primary key constraint on columns "id" */
NotificationSubscriptionPkey = 'notification_subscription_pkey'
}
@@ -3444,7 +3444,6 @@ export type Notification_Subscription_Insert_Input = {
id?: InputMaybe;
p256dh?: InputMaybe;
updatedAt?: InputMaybe;
- uuid?: InputMaybe;
};
/** aggregate max on columns */
@@ -3457,7 +3456,6 @@ export type Notification_Subscription_Max_Fields = {
id?: Maybe;
p256dh?: Maybe;
updatedAt?: Maybe;
- uuid?: Maybe;
};
/** order by max() on columns of table "notification_subscription" */
@@ -3469,7 +3467,6 @@ export type Notification_Subscription_Max_Order_By = {
id?: InputMaybe;
p256dh?: InputMaybe;
updatedAt?: InputMaybe;
- uuid?: InputMaybe;
};
/** aggregate min on columns */
@@ -3482,7 +3479,6 @@ export type Notification_Subscription_Min_Fields = {
id?: Maybe;
p256dh?: Maybe;
updatedAt?: Maybe;
- uuid?: Maybe;
};
/** order by min() on columns of table "notification_subscription" */
@@ -3494,7 +3490,6 @@ export type Notification_Subscription_Min_Order_By = {
id?: InputMaybe;
p256dh?: InputMaybe;
updatedAt?: InputMaybe;
- uuid?: InputMaybe;
};
/** response of any mutation on the table "notification_subscription" */
@@ -3523,7 +3518,6 @@ export type Notification_Subscription_Order_By = {
id?: InputMaybe;
p256dh?: InputMaybe;
updatedAt?: InputMaybe;
- uuid?: InputMaybe;
};
/** primary key columns input for table: notification_subscription */
@@ -3546,9 +3540,7 @@ export enum Notification_Subscription_Select_Column {
/** column name */
P256dh = 'p256dh',
/** column name */
- UpdatedAt = 'updatedAt',
- /** column name */
- Uuid = 'uuid'
+ UpdatedAt = 'updatedAt'
}
/** input type for updating data in table "notification_subscription" */
@@ -3560,7 +3552,6 @@ export type Notification_Subscription_Set_Input = {
id?: InputMaybe;
p256dh?: InputMaybe;
updatedAt?: InputMaybe;
- uuid?: InputMaybe;
};
/** Streaming cursor of the table "notification_subscription" */
@@ -3580,7 +3571,6 @@ export type Notification_Subscription_Stream_Cursor_Value_Input = {
id?: InputMaybe;
p256dh?: InputMaybe;
updatedAt?: InputMaybe;
- uuid?: InputMaybe;
};
/** update columns of table "notification_subscription" */
@@ -3598,9 +3588,7 @@ export enum Notification_Subscription_Update_Column {
/** column name */
P256dh = 'p256dh',
/** column name */
- UpdatedAt = 'updatedAt',
- /** column name */
- Uuid = 'uuid'
+ UpdatedAt = 'updatedAt'
}
export type Notification_Subscription_Updates = {
diff --git a/backend/zeus/src/zeus/const.ts b/backend/zeus/src/zeus/const.ts
index 063a1c16..5c22e3bc 100644
--- a/backend/zeus/src/zeus/const.ts
+++ b/backend/zeus/src/zeus/const.ts
@@ -755,8 +755,8 @@ export const AllTypesProps: Record = {
_or: "friendship_bool_exp",
chats: "chat_bool_exp",
chats_aggregate: "chat_aggregate_bool_exp",
- client1: "client_bool_exp",
- client2: "client_bool_exp",
+ client: "client_bool_exp",
+ clientByClientid2: "client_bool_exp",
clientId1: "uuid_comparison_exp",
clientId2: "uuid_comparison_exp",
createdAt: "timestamptz_comparison_exp",
@@ -767,8 +767,8 @@ export const AllTypesProps: Record = {
friendship_constraint: "enum" as const,
friendship_insert_input: {
chats: "chat_arr_rel_insert_input",
- client1: "client_obj_rel_insert_input",
- client2: "client_obj_rel_insert_input",
+ client: "client_obj_rel_insert_input",
+ clientByClientid2: "client_obj_rel_insert_input",
clientId1: "uuid",
clientId2: "uuid",
createdAt: "timestamptz",
@@ -802,8 +802,8 @@ export const AllTypesProps: Record = {
},
friendship_order_by: {
chats_aggregate: "chat_aggregate_order_by",
- client1: "client_order_by",
- client2: "client_order_by",
+ client: "client_order_by",
+ clientByClientid2: "client_order_by",
clientId1: "order_by",
clientId2: "order_by",
createdAt: "order_by",
@@ -2744,8 +2744,8 @@ export const ReturnTypes: Record = {
friendship: {
chats: "chat",
chats_aggregate: "chat_aggregate",
- client1: "client",
- client2: "client",
+ client: "client",
+ clientByClientid2: "client",
clientId1: "uuid",
clientId2: "uuid",
createdAt: "timestamptz",
diff --git a/backend/zeus/src/zeus/index.ts b/backend/zeus/src/zeus/index.ts
index 8bd1bb9a..52546988 100644
--- a/backend/zeus/src/zeus/index.ts
+++ b/backend/zeus/src/zeus/index.ts
@@ -4279,9 +4279,9 @@ export type ValueTypes = {
ValueTypes["chat_aggregate"],
];
/** An object relationship */
- client1?: ValueTypes["client"];
+ client?: ValueTypes["client"];
/** An object relationship */
- client2?: ValueTypes["client"];
+ clientByClientid2?: ValueTypes["client"];
clientId1?: boolean | `@${string}`;
clientId2?: boolean | `@${string}`;
createdAt?: boolean | `@${string}`;
@@ -4385,12 +4385,12 @@ export type ValueTypes = {
| undefined
| null
| Variable;
- client1?:
+ client?:
| ValueTypes["client_bool_exp"]
| undefined
| null
| Variable;
- client2?:
+ clientByClientid2?:
| ValueTypes["client_bool_exp"]
| undefined
| null
@@ -4435,12 +4435,12 @@ export type ValueTypes = {
| undefined
| null
| Variable;
- client1?:
+ client?:
| ValueTypes["client_obj_rel_insert_input"]
| undefined
| null
| Variable;
- client2?:
+ clientByClientid2?:
| ValueTypes["client_obj_rel_insert_input"]
| undefined
| null
@@ -4567,12 +4567,12 @@ export type ValueTypes = {
| undefined
| null
| Variable;
- client1?:
+ client?:
| ValueTypes["client_order_by"]
| undefined
| null
| Variable;
- client2?:
+ clientByClientid2?:
| ValueTypes["client_order_by"]
| undefined
| null
@@ -12215,9 +12215,9 @@ export type ResolverInputTypes = {
ResolverInputTypes["chat_aggregate"],
];
/** An object relationship */
- client1?: ResolverInputTypes["client"];
+ client?: ResolverInputTypes["client"];
/** An object relationship */
- client2?: ResolverInputTypes["client"];
+ clientByClientid2?: ResolverInputTypes["client"];
clientId1?: boolean | `@${string}`;
clientId2?: boolean | `@${string}`;
createdAt?: boolean | `@${string}`;
@@ -12288,8 +12288,11 @@ export type ResolverInputTypes = {
| ResolverInputTypes["chat_aggregate_bool_exp"]
| undefined
| null;
- client1?: ResolverInputTypes["client_bool_exp"] | undefined | null;
- client2?: ResolverInputTypes["client_bool_exp"] | undefined | null;
+ client?: ResolverInputTypes["client_bool_exp"] | undefined | null;
+ clientByClientid2?:
+ | ResolverInputTypes["client_bool_exp"]
+ | undefined
+ | null;
clientId1?: ResolverInputTypes["uuid_comparison_exp"] | undefined | null;
clientId2?: ResolverInputTypes["uuid_comparison_exp"] | undefined | null;
createdAt?:
@@ -12308,11 +12311,11 @@ export type ResolverInputTypes = {
/** input type for inserting data into table "friendship" */
["friendship_insert_input"]: {
chats?: ResolverInputTypes["chat_arr_rel_insert_input"] | undefined | null;
- client1?:
+ client?:
| ResolverInputTypes["client_obj_rel_insert_input"]
| undefined
| null;
- client2?:
+ clientByClientid2?:
| ResolverInputTypes["client_obj_rel_insert_input"]
| undefined
| null;
@@ -12390,8 +12393,11 @@ export type ResolverInputTypes = {
| ResolverInputTypes["chat_aggregate_order_by"]
| undefined
| null;
- client1?: ResolverInputTypes["client_order_by"] | undefined | null;
- client2?: ResolverInputTypes["client_order_by"] | undefined | null;
+ client?: ResolverInputTypes["client_order_by"] | undefined | null;
+ clientByClientid2?:
+ | ResolverInputTypes["client_order_by"]
+ | undefined
+ | null;
clientId1?: ResolverInputTypes["order_by"] | undefined | null;
clientId2?: ResolverInputTypes["order_by"] | undefined | null;
createdAt?: ResolverInputTypes["order_by"] | undefined | null;
@@ -17573,9 +17579,9 @@ export type ModelTypes = {
/** An aggregate relationship */
chats_aggregate: ModelTypes["chat_aggregate"];
/** An object relationship */
- client1: ModelTypes["client"];
+ client: ModelTypes["client"];
/** An object relationship */
- client2: ModelTypes["client"];
+ clientByClientid2: ModelTypes["client"];
clientId1: ModelTypes["uuid"];
clientId2: ModelTypes["uuid"];
createdAt: ModelTypes["timestamptz"];
@@ -17622,8 +17628,8 @@ export type ModelTypes = {
_or?: Array | undefined;
chats?: ModelTypes["chat_bool_exp"] | undefined;
chats_aggregate?: ModelTypes["chat_aggregate_bool_exp"] | undefined;
- client1?: ModelTypes["client_bool_exp"] | undefined;
- client2?: ModelTypes["client_bool_exp"] | undefined;
+ client?: ModelTypes["client_bool_exp"] | undefined;
+ clientByClientid2?: ModelTypes["client_bool_exp"] | undefined;
clientId1?: ModelTypes["uuid_comparison_exp"] | undefined;
clientId2?: ModelTypes["uuid_comparison_exp"] | undefined;
createdAt?: ModelTypes["timestamptz_comparison_exp"] | undefined;
@@ -17635,8 +17641,8 @@ export type ModelTypes = {
/** input type for inserting data into table "friendship" */
["friendship_insert_input"]: {
chats?: ModelTypes["chat_arr_rel_insert_input"] | undefined;
- client1?: ModelTypes["client_obj_rel_insert_input"] | undefined;
- client2?: ModelTypes["client_obj_rel_insert_input"] | undefined;
+ client?: ModelTypes["client_obj_rel_insert_input"] | undefined;
+ clientByClientid2?: ModelTypes["client_obj_rel_insert_input"] | undefined;
clientId1?: ModelTypes["uuid"] | undefined;
clientId2?: ModelTypes["uuid"] | undefined;
createdAt?: ModelTypes["timestamptz"] | undefined;
@@ -17702,8 +17708,8 @@ export type ModelTypes = {
/** Ordering options when selecting data from "friendship". */
["friendship_order_by"]: {
chats_aggregate?: ModelTypes["chat_aggregate_order_by"] | undefined;
- client1?: ModelTypes["client_order_by"] | undefined;
- client2?: ModelTypes["client_order_by"] | undefined;
+ client?: ModelTypes["client_order_by"] | undefined;
+ clientByClientid2?: ModelTypes["client_order_by"] | undefined;
clientId1?: ModelTypes["order_by"] | undefined;
clientId2?: ModelTypes["order_by"] | undefined;
createdAt?: ModelTypes["order_by"] | undefined;
@@ -20942,9 +20948,9 @@ export type GraphQLTypes = {
/** An aggregate relationship */
chats_aggregate: GraphQLTypes["chat_aggregate"];
/** An object relationship */
- client1: GraphQLTypes["client"];
+ client: GraphQLTypes["client"];
/** An object relationship */
- client2: GraphQLTypes["client"];
+ clientByClientid2: GraphQLTypes["client"];
clientId1: GraphQLTypes["uuid"];
clientId2: GraphQLTypes["uuid"];
createdAt: GraphQLTypes["timestamptz"];
@@ -20993,8 +20999,8 @@ export type GraphQLTypes = {
_or?: Array | undefined;
chats?: GraphQLTypes["chat_bool_exp"] | undefined;
chats_aggregate?: GraphQLTypes["chat_aggregate_bool_exp"] | undefined;
- client1?: GraphQLTypes["client_bool_exp"] | undefined;
- client2?: GraphQLTypes["client_bool_exp"] | undefined;
+ client?: GraphQLTypes["client_bool_exp"] | undefined;
+ clientByClientid2?: GraphQLTypes["client_bool_exp"] | undefined;
clientId1?: GraphQLTypes["uuid_comparison_exp"] | undefined;
clientId2?: GraphQLTypes["uuid_comparison_exp"] | undefined;
createdAt?: GraphQLTypes["timestamptz_comparison_exp"] | undefined;
@@ -21007,8 +21013,8 @@ export type GraphQLTypes = {
/** input type for inserting data into table "friendship" */
["friendship_insert_input"]: {
chats?: GraphQLTypes["chat_arr_rel_insert_input"] | undefined;
- client1?: GraphQLTypes["client_obj_rel_insert_input"] | undefined;
- client2?: GraphQLTypes["client_obj_rel_insert_input"] | undefined;
+ client?: GraphQLTypes["client_obj_rel_insert_input"] | undefined;
+ clientByClientid2?: GraphQLTypes["client_obj_rel_insert_input"] | undefined;
clientId1?: GraphQLTypes["uuid"] | undefined;
clientId2?: GraphQLTypes["uuid"] | undefined;
createdAt?: GraphQLTypes["timestamptz"] | undefined;
@@ -21077,8 +21083,8 @@ export type GraphQLTypes = {
/** Ordering options when selecting data from "friendship". */
["friendship_order_by"]: {
chats_aggregate?: GraphQLTypes["chat_aggregate_order_by"] | undefined;
- client1?: GraphQLTypes["client_order_by"] | undefined;
- client2?: GraphQLTypes["client_order_by"] | undefined;
+ client?: GraphQLTypes["client_order_by"] | undefined;
+ clientByClientid2?: GraphQLTypes["client_order_by"] | undefined;
clientId1?: GraphQLTypes["order_by"] | undefined;
clientId2?: GraphQLTypes["order_by"] | undefined;
createdAt?: GraphQLTypes["order_by"] | undefined;
diff --git a/packages/common/src/validations/account.ts b/packages/common/src/validations/account.ts
index 3233ec7f..2dead34a 100644
--- a/packages/common/src/validations/account.ts
+++ b/packages/common/src/validations/account.ts
@@ -44,7 +44,6 @@ export const AccountGetPrivateKey = z.object({
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,
"should be a valid UUID.",
),
- network: z.nativeEnum(Network),
});
export const AccountDelete = z.object({
diff --git a/packages/recoil/src/atoms/account.tsx b/packages/recoil/src/atoms/account.tsx
index ee0e4f37..95fa8892 100644
--- a/packages/recoil/src/atoms/account.tsx
+++ b/packages/recoil/src/atoms/account.tsx
@@ -1,5 +1,6 @@
-import { AccountType } from "@paybox/common";
-import { atom } from "recoil";
+import { AccountType, BACKEND_URL, responseStatus } from "@paybox/common";
+import { atom, selector } from "recoil";
+import { clientAtom } from "./client";
export const accountAtom = atom({
default: null,
@@ -15,4 +16,36 @@ export const accountsAtom = atom({
export const defaultAccountNumberAtom = atom({
default: 1,
key: "defaultAccountNumberAtom",
+});
+
+export const getAccountNumber = selector({
+ key: 'getAccountNumber',
+ get: async ({ get }) => {
+ const jwt = get(clientAtom)?.jwt;
+ try {
+ const {status, putUrl, number}: {status: responseStatus, putUrl: string, number: number} = await fetch(`${BACKEND_URL}/account/defaultMetadata`, {
+ method: "get",
+ headers: {
+ "Content-type": "application/json",
+ //@ts-ignore
+ "Authorization": `Bearer ${jwt}`
+ }
+ }).then(res => res.json());
+ if(status == responseStatus.Error) {
+ return 1;
+ }
+ return number + 1;
+ } catch (error) {
+ console.error(error)
+ return 1;
+ }
+ },
+});
+
+export const accountPrivateKeysAtom = atom<{
+ network: "Solana" | "Ethereum",
+ privateKey: string,
+}[]>({
+ default: [],
+ key: "accountPrivateKeysAtom",
});
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index b62b2c2a..f8dc72f7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10148,7 +10148,7 @@ crypto-js@^4.1.1:
crypto@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037"
integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==
cssesc@^3.0.0: