diff --git a/apps/marginfi-v2-ui/src/components/desktop/Points/PointsSignIn.tsx b/apps/marginfi-v2-ui/src/components/desktop/Points/PointsSignIn.tsx index 1893a84e30..cc679e2b09 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/Points/PointsSignIn.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/Points/PointsSignIn.tsx @@ -25,7 +25,7 @@ export const PointsSignIn: FC = ({}) => { toast.info("Logging in..."); const blockhashInfo = await connection.getLatestBlockhash(); try { - await firebaseApi.login(wallet, useAuthTx ? "tx" : "memo", blockhashInfo); + await firebaseApi.login(wallet); // localStorage.setItem("authData", JSON.stringify(signedAuthData)); toast.success("Logged in successfully"); } catch (loginError: any) { diff --git a/apps/marginfi-v2-ui/src/components/desktop/Points/PointsSignUp.tsx b/apps/marginfi-v2-ui/src/components/desktop/Points/PointsSignUp.tsx index ce3000b641..35d6af91e0 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/Points/PointsSignUp.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/Points/PointsSignUp.tsx @@ -41,7 +41,7 @@ export const PointsSignUp: FC = ({ referralCode }) => { toast.info("Logging in..."); const blockhashInfo = await connection.getLatestBlockhash(); try { - await firebaseApi.signup(wallet, useAuthTx ? "tx" : "memo", blockhashInfo, finalReferralCode); + await firebaseApi.signup(wallet, finalReferralCode); // localStorage.setItem("authData", JSON.stringify(signedAuthData)); toast.success("Signed up successfully"); } catch (signupError: any) { diff --git a/apps/marginfi-v2-ui/src/pages/api/user/login.ts b/apps/marginfi-v2-ui/src/pages/api/user/login.ts index 302b9ef294..92de7640e3 100644 --- a/apps/marginfi-v2-ui/src/pages/api/user/login.ts +++ b/apps/marginfi-v2-ui/src/pages/api/user/login.ts @@ -20,13 +20,15 @@ import { initFirebaseIfNeeded(); export interface LoginRequest { - method: SigningMethod; - signedAuthDataRaw: string; + walletAddress: string; + // method: SigningMethod; + // signedAuthDataRaw: string; } export default async function handler(req: NextApiRequest, res: any) { - const { method, signedAuthDataRaw } = req.body; + const { walletAddress } = req.body; + /* signing logic let signer; try { const loginData = validateAndUnpackLoginData(signedAuthDataRaw, method); @@ -46,15 +48,17 @@ export default async function handler(req: NextApiRequest, res: an status = STATUS_INTERNAL_ERROR; } return res.status(status).json({ error: error.message }); - } + }*/ let user; try { - const userResult = await getFirebaseUserByWallet(signer); + const userResult = await getFirebaseUserByWallet(walletAddress); if (userResult === undefined) { - await logLoginAttempt(signer, null, signedAuthDataRaw, false); + await logLoginAttempt(walletAddress, null, "", false); Sentry.captureException({ message: "User not found" }); return res.status(STATUS_NOT_FOUND).json({ error: "User not found" }); + } else { + await logLoginAttempt(walletAddress, user.uid, "", true); } user = userResult; } catch (error: any) { @@ -62,16 +66,18 @@ export default async function handler(req: NextApiRequest, res: an return res.status(STATUS_INTERNAL_ERROR).json({ error: error.message }); // An unexpected error occurred } - await logLoginAttempt(signer, user.uid, signedAuthDataRaw, true); - // Generate a custom token for the client to log in - const customToken = await admin.auth().createCustomToken(signer); + const customToken = await admin.auth().createCustomToken(walletAddress); - return res.status(STATUS_OK).json({ status: "success", uid: signer, token: customToken }); + return res.status(STATUS_OK).json({ status: "success", uid: walletAddress, token: customToken }); } // -------- Helpers +/** + * @deprecated + * Signing functionality + */ export function validateAndUnpackLoginData( signedAuthDataRaw: string, signingMethod: SigningMethod diff --git a/apps/marginfi-v2-ui/src/pages/api/user/signup.ts b/apps/marginfi-v2-ui/src/pages/api/user/signup.ts index 0c5240636b..1eda0263b8 100644 --- a/apps/marginfi-v2-ui/src/pages/api/user/signup.ts +++ b/apps/marginfi-v2-ui/src/pages/api/user/signup.ts @@ -9,6 +9,7 @@ import base58 from "bs58"; import nacl from "tweetnacl"; import { SigningMethod, + SignupPayload, STATUS_BAD_REQUEST, STATUS_UNAUTHORIZED, STATUS_INTERNAL_ERROR, @@ -19,43 +20,42 @@ import { initFirebaseIfNeeded(); export interface SignupRequest { - method: SigningMethod; - signedAuthDataRaw: string; + walletAddress: string; + payload: SignupPayload; + // method: SigningMethod; + // signedAuthDataRaw: string; } export default async function handler(req: NextApiRequest, res: any) { - const { method, signedAuthDataRaw } = req.body; + const { walletAddress, payload } = req.body; Sentry.setContext("signup_args", { - method, - signedAuthDataRaw, + walletAddress, }); - let signer; - let payload; - try { - const signupData = validateAndUnpackSignupData(signedAuthDataRaw, method); - signer = signupData.signer.toBase58(); - payload = signupData.payload; - } catch (error: any) { - Sentry.captureException(error); - let status; - switch (error.message) { - case "Invalid signup tx": - case "Invalid signup payload": - status = STATUS_BAD_REQUEST; - break; - case "Invalid signature": - status = STATUS_UNAUTHORIZED; - break; - default: - status = STATUS_INTERNAL_ERROR; - } - return res.status(status).json({ error: error.message }); - } + // try { + // const signupData = validateAndUnpackSignupData(signedAuthDataRaw, method); + // signer = signupData.signer.toBase58(); + // payload = signupData.payload; + // } catch (error: any) { + // Sentry.captureException(error); + // let status; + // switch (error.message) { + // case "Invalid signup tx": + // case "Invalid signup payload": + // status = STATUS_BAD_REQUEST; + // break; + // case "Invalid signature": + // status = STATUS_UNAUTHORIZED; + // break; + // default: + // status = STATUS_INTERNAL_ERROR; + // } + // return res.status(status).json({ error: error.message }); + // } try { - const user = await getFirebaseUserByWallet(signer); + const user = await getFirebaseUserByWallet(walletAddress); if (user) { Sentry.captureException({ message: "User already exists" }); return res.status(STATUS_BAD_REQUEST).json({ error: "User already exists" }); @@ -66,23 +66,27 @@ export default async function handler(req: NextApiRequest, res: a } try { - await createFirebaseUser(signer, payload.referralCode); + await createFirebaseUser(walletAddress, payload.referralCode); console.log("successfully created new user"); } catch (createUserError: any) { Sentry.captureException(createUserError); return res.status(STATUS_INTERNAL_ERROR).json({ error: createUserError.message }); } - await logSignupAttempt(signer, payload.uuid, signedAuthDataRaw, true); + await logSignupAttempt(walletAddress, payload.uuid, "", true); // Generate a custom token for the client to sign in - const customToken = await admin.auth().createCustomToken(signer); + const customToken = await admin.auth().createCustomToken(walletAddress); - return res.status(STATUS_OK).json({ status: "success", uid: signer, token: customToken }); + return res.status(STATUS_OK).json({ status: "success", uid: walletAddress, token: customToken }); } // -------- Helpers +/** + * @deprecated + * Signing functionality + */ export function validateAndUnpackSignupData( signedAuthDataRaw: string, signingMethod: SigningMethod diff --git a/apps/marginfi-v2-ui/src/pages/points.tsx b/apps/marginfi-v2-ui/src/pages/points.tsx index 51b8c611fd..f528dd80e5 100644 --- a/apps/marginfi-v2-ui/src/pages/points.tsx +++ b/apps/marginfi-v2-ui/src/pages/points.tsx @@ -23,9 +23,7 @@ import { const Points = () => { const { connected } = useWalletContext(); const { query: routerQuery } = useRouter(); - // useUserProfileStore(() => { - // state - // }) + const [currentFirebaseUser, hasUser, userPointsData] = useUserProfileStore((state) => [ state.currentFirebaseUser, state.hasUser, @@ -35,17 +33,6 @@ const Points = () => { const referralCode = React.useMemo(() => routerQuery.referralCode as string | undefined, [routerQuery.referralCode]); const [isReferralCopied, setIsReferralCopied] = React.useState(false); - // React.useEffect(() => { - // fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet, isOverride }).catch(console.error); - // const id = setInterval(() => { - // setIsRefreshingStore(true); - // fetchMrgnlendState().catch(console.error); - // }, 30_000); - // return () => clearInterval(id); - // }, [wallet, isOverride]); // eslint-disable-line react-hooks/exhaustive-deps - // ^ crucial to omit both `connection` and `fetchMrgnlendState` from the dependency array - // TODO: fix... - return ( <> points diff --git a/packages/marginfi-v2-ui-state/src/lib/firebase.ts b/packages/marginfi-v2-ui-state/src/lib/firebase.ts index 57a2d2ce19..57fdccbd2b 100644 --- a/packages/marginfi-v2-ui-state/src/lib/firebase.ts +++ b/packages/marginfi-v2-ui-state/src/lib/firebase.ts @@ -32,6 +32,17 @@ interface UserData { id: string; } +async function loginOrSignup(wallet: Wallet) { + const walletAddress = wallet.publicKey.toBase58(); + const user = await getUser(walletAddress); + + if (user) { + await login(wallet); + } else { + await signup(wallet); + } +} + async function getUser(walletAddress: string): Promise { const response = await fetch("/api/user/get", { method: "POST", @@ -60,25 +71,13 @@ const LoginPayloadStruct = object({ }); type LoginPayload = Infer; -async function loginOrSignup(wallet: Wallet) { - const user = await getUser(wallet.publicKey); - - if (user) { - } else { - } -} +async function login(wallet: Wallet) { + // const authData = { uuid: uuidv4() }; + // const signedAuthDataRaw = + // signingMethod === "tx" ? await signLoginTx(wallet, authData, blockhash) : await signLoginMemo(wallet, authData); + await loginWithAddress(wallet.publicKey.toBase58()); -async function login( - wallet: Wallet, - signingMethod: SigningMethod, - blockhash: BlockhashWithExpiryBlockHeight -): Promise<{ signingMethod: SigningMethod; signedAuthDataRaw: string }> { - const authData = { uuid: uuidv4() }; - const signedAuthDataRaw = - signingMethod === "tx" ? await signLoginTx(wallet, authData, blockhash) : await signLoginMemo(wallet, authData); - await loginWithAuthData(signingMethod, signedAuthDataRaw); - - return { signingMethod, signedAuthDataRaw }; + // return { signingMethod, signedAuthDataRaw }; } const SignupPayloadStruct = object({ @@ -87,12 +86,7 @@ const SignupPayloadStruct = object({ }); type SignupPayload = Infer; -async function signup( - wallet: Wallet, - signingMethod: SigningMethod, - blockhash: BlockhashWithExpiryBlockHeight, - referralCode?: string -): Promise<{ signingMethod: SigningMethod; signedAuthDataRaw: string }> { +async function signup(wallet: Wallet, referralCode?: string) { if (referralCode !== undefined && typeof referralCode !== "string") { throw new Error("Invalid referral code provided."); } @@ -102,15 +96,28 @@ async function signup( uuid, referralCode, }; - const signedAuthDataRaw = - signingMethod === "tx" ? await signSignupTx(wallet, authData, blockhash) : await signSignupMemo(wallet, authData); + // const signedAuthDataRaw = + // signingMethod === "tx" ? await signSignupTx(wallet, authData, blockhash) : await signSignupMemo(wallet, authData); + + await signupWithAddress(wallet.publicKey.toBase58(), authData); + // return { signingMethod, signedAuthDataRaw }; +} + +export { getUser, signup, login, SignupPayloadStruct, LoginPayloadStruct }; +export type { UserData, SignupPayload }; + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +async function signupWithAddress(walletAddress: string, payload: SignupPayload) { const response = await fetch("/api/user/signup", { method: "POST", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ method: signingMethod, signedAuthDataRaw }), + body: JSON.stringify({ walletAddress, payload }), }); const data = await response.json(); @@ -126,17 +133,54 @@ async function signup( if (!data.token) throw new Error("Something went wrong during sign-up"); await signinFirebaseAuth(data.token); +} - return { signingMethod, signedAuthDataRaw }; +async function loginWithAddress(walletAddress: string) { + const response = await fetch("/api/user/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ walletAddress }), + }); + const data = await response.json(); + + if (!data.token) throw new Error("Something went wrong during sign-in"); + await signinFirebaseAuth(data.token); } -export { getUser, signup, login, SignupPayloadStruct, LoginPayloadStruct }; -export type { UserData, SignupPayload }; +/** + * @deprecated + * Signing functionality + */ +async function signupWithAuthData(signingMethod: SigningMethod, signedAuthDataRaw: string) { + const response = await fetch("/api/user/signup", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ method: signingMethod, signedAuthDataRaw }), + }); + const data = await response.json(); -// ---------------------------------------------------------------------------- -// Helpers -// ---------------------------------------------------------------------------- + switch (response.status) { + case STATUS_BAD_REQUEST: + throw new Error(data.error); + case STATUS_UNAUTHORIZED: + case STATUS_INTERNAL_ERROR: + throw new Error("Something went wrong during sign-up"); + default: { + } + } + + if (!data.token) throw new Error("Something went wrong during sign-up"); + await signinFirebaseAuth(data.token); +} +/** + * @deprecated + * Signing functionality + */ async function loginWithAuthData(signingMethod: SigningMethod, signedAuthDataRaw: string) { const response = await fetch("/api/user/login", { method: "POST", @@ -153,7 +197,7 @@ async function loginWithAuthData(signingMethod: SigningMethod, signedAuthDataRaw /** * @deprecated - * Will be re-added once data is sensitive + * Signing functionality */ async function signSignupMemo(wallet: Wallet, authData: SignupPayload): Promise { if (!wallet.publicKey) { @@ -176,7 +220,7 @@ async function signSignupMemo(wallet: Wallet, authData: SignupPayload): Promise< /** * @deprecated - * Will be re-added once data is sensitive + * Signing functionality */ async function signSignupTx( wallet: Wallet, @@ -201,7 +245,7 @@ async function signSignupTx( /** * @deprecated - * Will be re-added once data is sensitive + * Signing functionality */ async function signLoginMemo(wallet: Wallet, authData: LoginPayload): Promise { if (!wallet.publicKey) { @@ -224,7 +268,7 @@ async function signLoginMemo(wallet: Wallet, authData: LoginPayload): Promise=12.12.47" - "@grpc/grpc-js@~1.8.0": version "1.8.21" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.21.tgz#d282b122c71227859bf6c5866f4c40f4a2696513" @@ -3785,16 +3809,13 @@ "@grpc/proto-loader" "^0.7.0" "@types/node" ">=12.12.47" -"@grpc/proto-loader@^0.6.13": - version "0.6.13" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.13.tgz#008f989b72a40c60c96cd4088522f09b05ac66bc" - integrity sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g== +"@grpc/grpc-js@~1.9.0": + version "1.9.11" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.11.tgz#7b21195c910a49c0bb5d0df21d28a30c4e174851" + integrity sha512-QDhMfbTROOXUhLHMroow8f3EHiCKUOh6UwxMP5S3EuXMnWMNSVIhatGZRwkpg9OUTYdZPsDUVH3cOAkWhGFUJw== dependencies: - "@types/long" "^4.0.1" - lodash.camelcase "^4.3.0" - long "^4.0.0" - protobufjs "^6.11.3" - yargs "^16.2.0" + "@grpc/proto-loader" "^0.7.8" + "@types/node" ">=12.12.47" "@grpc/proto-loader@^0.7.0": version "0.7.9" @@ -3806,6 +3827,16 @@ protobufjs "^7.2.4" yargs "^17.7.2" +"@grpc/proto-loader@^0.7.8": + version "0.7.10" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.10.tgz#6bf26742b1b54d0a473067743da5d3189d06d720" + integrity sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.4" + yargs "^17.7.2" + "@hapi/hoek@^9.0.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -11671,15 +11702,6 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -14762,24 +14784,24 @@ firebase-admin@^11.9.0: "@google-cloud/firestore" "^6.6.0" "@google-cloud/storage" "^6.9.5" -firebase@^9.22.1: - version "9.23.0" - resolved "https://registry.yarnpkg.com/firebase/-/firebase-9.23.0.tgz#71fea60d704bfed8e92162911544fd6564a04d0e" - integrity sha512-/4lUVY0lUvBDIaeY1q6dUYhS8Sd18Qb9CgWkPZICUo9IXpJNCEagfNZXBBFCkMTTN5L5gx2Hjr27y21a9NzUcA== +firebase@^10.6.0: + version "10.6.0" + resolved "https://registry.yarnpkg.com/firebase/-/firebase-10.6.0.tgz#cee12b311dbf79d3958e8dd8b12fd335521997eb" + integrity sha512-bnYwHwZ6zB+dM6mGQPEXcFHtAT2WoVzG6H4SIR8HzURVGKJxBW+TqfP3qcJQjTZV3tDqDTo/XZkVmoU/SovV8A== dependencies: "@firebase/analytics" "0.10.0" "@firebase/analytics-compat" "0.2.6" - "@firebase/app" "0.9.13" + "@firebase/app" "0.9.23" "@firebase/app-check" "0.8.0" "@firebase/app-check-compat" "0.3.7" - "@firebase/app-compat" "0.2.13" + "@firebase/app-compat" "0.2.23" "@firebase/app-types" "0.9.0" - "@firebase/auth" "0.23.2" - "@firebase/auth-compat" "0.4.2" - "@firebase/database" "0.14.4" - "@firebase/database-compat" "0.3.4" - "@firebase/firestore" "3.13.0" - "@firebase/firestore-compat" "0.3.12" + "@firebase/auth" "1.4.0" + "@firebase/auth-compat" "0.4.9" + "@firebase/database" "1.0.1" + "@firebase/database-compat" "1.0.1" + "@firebase/firestore" "4.3.2" + "@firebase/firestore-compat" "0.3.22" "@firebase/functions" "0.10.0" "@firebase/functions-compat" "0.3.5" "@firebase/installations" "0.6.4" @@ -20591,7 +20613,7 @@ protobufjs@7.2.4: "@types/node" ">=13.7.0" long "^5.0.0" -protobufjs@^6.10.2, protobufjs@^6.11.3: +protobufjs@^6.10.2: version "6.11.4" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.4.tgz#29a412c38bf70d89e537b6d02d904a6f448173aa" integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== @@ -24837,11 +24859,6 @@ yargs-parser@^18.1.2, yargs-parser@^18.1.3: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" @@ -24880,19 +24897,6 @@ yargs@^15.1.0, yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yargs@^17.0.1, yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"