From bb0c208c0c42047addc920c7a0f5233042dd47c6 Mon Sep 17 00:00:00 2001 From: Rafal Czajkowski Date: Wed, 11 Sep 2024 21:10:09 +0200 Subject: [PATCH] Clean up siww auth function Move the Acre API requests to separate functions and set the Acre API endpoint via env variables. --- dapp/.env | 1 + .../ConnectWalletButton.tsx | 51 +++++++++++-------- dapp/src/constants/env.ts | 3 ++ dapp/src/constants/time.ts | 3 ++ dapp/src/utils/acre-api.ts | 31 +++++++++++ dapp/src/utils/index.ts | 1 + dapp/src/utils/orangeKit.ts | 8 +-- dapp/src/vite-env.d.ts | 1 + 8 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 dapp/src/utils/acre-api.ts diff --git a/dapp/.env b/dapp/.env index 750d2de79..9b9a93186 100644 --- a/dapp/.env +++ b/dapp/.env @@ -11,6 +11,7 @@ VITE_REFERRAL=0 # TODO: Set this env variable in CI. VITE_TBTC_API_ENDPOINT="" +VITE_ACRE_API_ENDPOINT="http://localhost:8788/api/v1/" # API KEYS VITE_GELATO_RELAY_API_KEY="htaJCy_XHj8WsE3w53WBMurfySDtjLP_TrNPPa6IPIc_" # this key should not be used on production diff --git a/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx b/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx index 6fd71b089..6fee9cbbd 100644 --- a/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx +++ b/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx @@ -8,7 +8,13 @@ import { } from "#/hooks" import { setIsSignedMessage } from "#/store/wallet" import { OrangeKitConnector, OrangeKitError, OnSuccessCallback } from "#/types" -import { logPromiseFailure, orangeKit } from "#/utils" +import { + createSession, + deleteSession, + getSession, + logPromiseFailure, + orangeKit, +} from "#/utils" import { Button, Card, @@ -21,9 +27,9 @@ import { VStack, } from "@chakra-ui/react" import { useSignMessage } from "wagmi" +import { isAddressEqual } from "viem" import { IconArrowNarrowRight } from "@tabler/icons-react" import { AnimatePresence, Variants, motion } from "framer-motion" -import axios from "axios" import ArrivingSoonTooltip from "../ArrivingSoonTooltip" import { TextLg, TextMd } from "../shared/Typography" import ConnectWalletStatusLabel from "./ConnectWalletStatusLabel" @@ -86,39 +92,44 @@ export default function ConnectWalletButton({ const handleSignMessage = useCallback( async (connectedConnector: OrangeKitConnector, btcAddress: string) => { try { - const response = await axios.get< - { nonce: string } | { address: string } - >("http://localhost:8788/api/v1/session", { withCredentials: true }) + const session = await getSession() + const [ethAddress] = await connectedConnector.getAccounts() + + const hasSessionAddress = "address" in session + + const isSessionAddressEqual = hasSessionAddress + ? isAddressEqual(ethAddress, session.address as `0x${string}`) + : false - if ("address" in response.data) { - console.log("Nothing to sign. Session already exists") + if (hasSessionAddress && isSessionAddressEqual) { onSuccessSignMessage() return } - const { nonce } = response.data - console.log("nonce", nonce) + if (!hasSessionAddress && !isAddressEqual) { + await deleteSession() + } + + const hasNonce = "nonce" in session + if (!hasNonce) { + throw new Error("Session nonce not available") + } const message = orangeKit.createSignInWithWalletMessage( btcAddress, - nonce, + session.nonce, ) - console.log("message", message) + const signedMessage = await signMessageAsync({ message, connector: orangeKit.typeConversionToConnector(connectedConnector), }) - const createSessionResponse = await axios.post<{ success: boolean }>( - "http://localhost:8788/api/v1/session", - { message, signature: signedMessage }, - { withCredentials: true }, - ) - if (createSessionResponse.data.success) { - onSuccessSignMessage() - } + await createSession(message, signedMessage) + + onSuccessSignMessage() } catch (error) { - console.error("error", error) + console.error("Failed to sign siww message", error) setConnectionError(CONNECTION_ERRORS.INVALID_SIWW_SIGNATURE) } }, diff --git a/dapp/src/constants/env.ts b/dapp/src/constants/env.ts index 57945f2f1..d2b31b236 100644 --- a/dapp/src/constants/env.ts +++ b/dapp/src/constants/env.ts @@ -22,6 +22,8 @@ const NETWORK_TYPE = USE_TESTNET ? "testnet" : "mainnet" const LATEST_COMMIT_HASH = import.meta.env.VITE_LATEST_COMMIT_HASH +const ACRE_API_ENDPOINT = import.meta.env.VITE_ACRE_API_ENDPOINT + export default { PROD, USE_TESTNET, @@ -35,4 +37,5 @@ export default { MEZO_PORTAL_API_KEY, NETWORK_TYPE, LATEST_COMMIT_HASH, + ACRE_API_ENDPOINT, } diff --git a/dapp/src/constants/time.ts b/dapp/src/constants/time.ts index 0620f3abd..be6aa0899 100644 --- a/dapp/src/constants/time.ts +++ b/dapp/src/constants/time.ts @@ -10,3 +10,6 @@ export const REFETCH_INTERVAL_IN_MILLISECONDS = ONE_SEC_IN_MILLISECONDS * ONE_MINUTE_IN_SECONDS * 5 export const DATE_FORMAT_LOCALE_TAG = "us-US" + +// 3 hours +export const ACRE_SESSION_EXPIRATION_TIME = 10800000 diff --git a/dapp/src/utils/acre-api.ts b/dapp/src/utils/acre-api.ts new file mode 100644 index 000000000..0697c8ee2 --- /dev/null +++ b/dapp/src/utils/acre-api.ts @@ -0,0 +1,31 @@ +import { env } from "#/constants" +import axiosStatic from "axios" + +const axios = axiosStatic.create({ baseURL: env.ACRE_API_ENDPOINT }) + +export async function getSession() { + const response = await axios.get<{ nonce: string } | { address: string }>( + "session", + { + withCredentials: true, + }, + ) + + return response.data +} + +export async function createSession(message: string, signature: string) { + const response = await axios.post<{ success: boolean }>( + "session", + { message, signature }, + { withCredentials: true }, + ) + + if (!response.data) { + throw new Error("Failed to create Acre session") + } +} + +export async function deleteSession() { + await axios.delete("session") +} diff --git a/dapp/src/utils/index.ts b/dapp/src/utils/index.ts index 5cf970f2b..ffacbd41d 100644 --- a/dapp/src/utils/index.ts +++ b/dapp/src/utils/index.ts @@ -17,3 +17,4 @@ export { default as userAgent } from "./userAgent" export { default as referralProgram } from "./referralProgram" export { default as mezoPortalAPI } from "./mezoPortalApi" export { default as router } from "./router" +export * from "./acre-api" diff --git a/dapp/src/utils/orangeKit.ts b/dapp/src/utils/orangeKit.ts index 1e2653b9e..2cf96cb45 100644 --- a/dapp/src/utils/orangeKit.ts +++ b/dapp/src/utils/orangeKit.ts @@ -1,4 +1,8 @@ -import { CONNECTION_ERRORS, wallets } from "#/constants" +import { + ACRE_SESSION_EXPIRATION_TIME, + CONNECTION_ERRORS, + wallets, +} from "#/constants" import { ConnectionErrorData, OrangeKitError, @@ -24,8 +28,6 @@ const getWalletInfo = (connector: OrangeKitConnector) => { } } -const ACRE_SESSION_EXPIRATION_TIME = 10800000 - const isWalletInstalled = (connector: OrangeKitConnector) => { const provider = connector.getBitcoinProvider() return provider.isInstalled() diff --git a/dapp/src/vite-env.d.ts b/dapp/src/vite-env.d.ts index 556cb5767..9108fde70 100644 --- a/dapp/src/vite-env.d.ts +++ b/dapp/src/vite-env.d.ts @@ -16,6 +16,7 @@ interface ImportMetaEnv { readonly VITE_SUBGRAPH_API_KEY: string readonly VITE_MEZO_PORTAL_API_KEY: string readonly VITE_LATEST_COMMIT_HASH: string + readonly VITE_ACRE_API_ENDPOINT: string } interface ImportMeta {