From 527473e62fdc01e27baf1222974e2c18e40b5cff Mon Sep 17 00:00:00 2001 From: Kamil Pyszkowski Date: Fri, 15 Nov 2024 14:44:59 +0100 Subject: [PATCH 01/12] Install posthog-js library --- dapp/.env | 5 +++++ dapp/package.json | 1 + dapp/src/DApp.tsx | 33 +++++++++++++++------------- dapp/src/constants/env.ts | 6 +++++ dapp/src/constants/featureFlags.ts | 3 +++ dapp/src/posthog/PostHogProvider.tsx | 26 ++++++++++++++++++++++ dapp/src/utils/hash.ts | 17 ++++++++++++++ dapp/src/vite-env.d.ts | 3 +++ pnpm-lock.yaml | 30 +++++++++++++++++++++++++ 9 files changed, 109 insertions(+), 15 deletions(-) create mode 100644 dapp/src/posthog/PostHogProvider.tsx create mode 100644 dapp/src/utils/hash.ts diff --git a/dapp/.env b/dapp/.env index 79f9dc9d6..3585e1a5c 100644 --- a/dapp/.env +++ b/dapp/.env @@ -18,6 +18,10 @@ VITE_GELATO_RELAY_API_KEY="htaJCy_XHj8WsE3w53WBMurfySDtjLP_TrNPPa6IPIc_" # this # Get the API key from: https://thegraph.com/studio/apikeys/. VITE_SUBGRAPH_API_KEY="" +# Posthog +VITE_POSTHOG_API_HOST="https://us.i.posthog.com" +VITE_POSTHOG_API_KEY="" + # Feature flags VITE_FEATURE_FLAG_GAMIFICATION_ENABLED="false" VITE_FEATURE_FLAG_WITHDRAWALS_ENABLED="false" @@ -26,4 +30,5 @@ VITE_FEATURE_FLAG_XVERSE_WALLET_ENABLED="false" VITE_FEATURE_FLAG_ACRE_POINTS_ENABLED="true" VITE_FEATURE_FLAG_TVL_ENABLED="true" VITE_FEATURE_GATING_DAPP_ENABLED="true" +VITE_FEATURE_POSTHOG_ENABLED="true" diff --git a/dapp/package.json b/dapp/package.json index 58e497878..b881b7a3e 100644 --- a/dapp/package.json +++ b/dapp/package.json @@ -39,6 +39,7 @@ "formik": "^2.4.5", "framer-motion": "^10.16.5", "mustache": "^4.2.0", + "posthog-js": "^1.186.1", "react": "^18.2.0", "react-confetti-explosion": "^2.1.2", "react-dom": "^18.2.0", diff --git a/dapp/src/DApp.tsx b/dapp/src/DApp.tsx index 31255b53d..bf6def3ca 100644 --- a/dapp/src/DApp.tsx +++ b/dapp/src/DApp.tsx @@ -19,6 +19,7 @@ import getWagmiConfig from "./wagmiConfig" import queryClient from "./queryClient" import { delay, logPromiseFailure } from "./utils" import { AcreLogo } from "./assets/icons" +import PostHogProvider from "./posthog/PostHogProvider" function SplashPage() { return ( @@ -62,21 +63,23 @@ function DAppProviders() { return ( - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + ) } diff --git a/dapp/src/constants/env.ts b/dapp/src/constants/env.ts index 034bd01a9..4d03b302e 100644 --- a/dapp/src/constants/env.ts +++ b/dapp/src/constants/env.ts @@ -22,6 +22,10 @@ const LATEST_COMMIT_HASH = import.meta.env.VITE_LATEST_COMMIT_HASH const ACRE_API_ENDPOINT = import.meta.env.VITE_ACRE_API_ENDPOINT +const POSTHOG_API_HOST = import.meta.env.VITE_POSTHOG_API_HOST + +const POSTHOG_API_KEY = import.meta.env.VITE_POSTHOG_API_KEY + export default { PROD, USE_TESTNET, @@ -35,4 +39,6 @@ export default { NETWORK_TYPE, LATEST_COMMIT_HASH, ACRE_API_ENDPOINT, + POSTHOG_API_HOST, + POSTHOG_API_KEY, } diff --git a/dapp/src/constants/featureFlags.ts b/dapp/src/constants/featureFlags.ts index 2d2062a9e..d23658a10 100644 --- a/dapp/src/constants/featureFlags.ts +++ b/dapp/src/constants/featureFlags.ts @@ -18,6 +18,8 @@ const TVL_ENABLED = import.meta.env.VITE_FEATURE_FLAG_TVL_ENABLED === "true" const GATING_DAPP_ENABLED = import.meta.env.VITE_FEATURE_GATING_DAPP_ENABLED === "true" +const POSTHOG_ENABLED = import.meta.env.VITE_FEATURE_POSTHOG_ENABLED === "true" + const featureFlags = { GAMIFICATION_ENABLED, OKX_WALLET_ENABLED, @@ -26,6 +28,7 @@ const featureFlags = { ACRE_POINTS_ENABLED, TVL_ENABLED, GATING_DAPP_ENABLED, + POSTHOG_ENABLED, } export default featureFlags diff --git a/dapp/src/posthog/PostHogProvider.tsx b/dapp/src/posthog/PostHogProvider.tsx new file mode 100644 index 000000000..39e733fee --- /dev/null +++ b/dapp/src/posthog/PostHogProvider.tsx @@ -0,0 +1,26 @@ +import React, { PropsWithChildren } from "react" +import { PostHogProvider as Provider } from "posthog-js/react" +import { PostHogConfig } from "posthog-js" +import { featureFlags, env } from "../constants" + +const options: Partial = { + api_host: env.POSTHOG_API_HOST, + capture_pageview: false, + persistence: "memory", +} + +function PostHogProvider(props: PropsWithChildren) { + const { children } = props + + if (!featureFlags.POSTHOG_ENABLED) { + return children + } + + return ( + + {children} + + ) +} + +export default PostHogProvider diff --git a/dapp/src/utils/hash.ts b/dapp/src/utils/hash.ts new file mode 100644 index 000000000..b59c5f976 --- /dev/null +++ b/dapp/src/utils/hash.ts @@ -0,0 +1,17 @@ +type HashAlgorithm = "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512" + +export const hashString = async ({ + algorithm = "SHA-256", + value, +}: { + algorithm?: HashAlgorithm + value: string +}) => + Array.prototype.map + .call( + new Uint8Array( + await crypto.subtle.digest(algorithm, new TextEncoder().encode(value)), + ), + (x: number) => `0${x.toString(16)}`.slice(-2), + ) + .join("") diff --git a/dapp/src/vite-env.d.ts b/dapp/src/vite-env.d.ts index 53f7175b8..b7ac44d68 100644 --- a/dapp/src/vite-env.d.ts +++ b/dapp/src/vite-env.d.ts @@ -14,9 +14,12 @@ interface ImportMetaEnv { readonly VITE_FEATURE_FLAG_ACRE_POINTS_ENABLED: string readonly VITE_FEATURE_FLAG_TVL_ENABLED: string readonly VITE_FEATURE_GATING_DAPP_ENABLED: string + readonly VITE_FEATURE_POSTHOG_ENABLED: string readonly VITE_SUBGRAPH_API_KEY: string readonly VITE_LATEST_COMMIT_HASH: string readonly VITE_ACRE_API_ENDPOINT: string + readonly VITE_POSTHOG_API_HOST: string + readonly VITE_POSTHOG_API_KEY: string } interface ImportMeta { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32d0141ee..6b93609f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,6 +86,9 @@ importers: mustache: specifier: ^4.2.0 version: 4.2.0 + posthog-js: + specifier: ^1.186.1 + version: 1.186.1 react: specifier: ^18.2.0 version: 18.3.1 @@ -3109,6 +3112,7 @@ packages: '@safe-global/safe-core-sdk-types@5.0.1': resolution: {integrity: sha512-xIlHZ9kaAIwEhR0OY0i2scdcQyrc0tDJ+eZZ04lhvg81cgYLY1Z5wfJQqazR2plPT1Hz0A9C79jYdUVvzoF/tw==} + deprecated: 'WARNING: This project has been renamed to @safe-global/types-kit. Please, migrate from @safe-global/safe-core-sdk-types@5.1.0 to @safe-global/types-kit@1.0.0.' '@safe-global/safe-deployments@1.37.0': resolution: {integrity: sha512-OInLNWC9EPem/eOsvPdlq4Gt/08Nfhslm9z6T92Jvjmcu6hs85vjfnDP1NrzwcOmsCarATU5NH2bTITd9VNCPw==} @@ -5054,6 +5058,9 @@ packages: core-js-compat@3.37.1: resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} + core-js@3.39.0: + resolution: {integrity: sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==} + core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -5873,6 +5880,7 @@ packages: ethereumjs-abi@0.6.8: resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} + deprecated: This library has been deprecated and usage is discouraged. ethereumjs-common@1.5.2: resolution: {integrity: sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA==} @@ -6058,6 +6066,9 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -8602,6 +8613,9 @@ packages: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} + posthog-js@1.186.1: + resolution: {integrity: sha512-m6TNW01nfqErwMxaZxNScYdMaUJO0s3bbmt/tboL29yZDnuHdOiYFbG+T4MCxdFxjWRa5gOR25bQD/SSt1t/4A==} + preact@10.22.0: resolution: {integrity: sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==} @@ -10472,6 +10486,9 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} + web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + web3-bzz@1.10.4: resolution: {integrity: sha512-ZZ/X4sJ0Uh2teU9lAGNS8EjveEppoHNQiKlOXAjedsrdWuaMErBPdLQjXfcrYvN6WM6Su9PMsAxf3FXXZ+HwQw==} engines: {node: '>=8.0.0'} @@ -18307,6 +18324,8 @@ snapshots: dependencies: browserslist: 4.23.1 + core-js@3.39.0: {} + core-util-is@1.0.2: {} core-util-is@1.0.3: {} @@ -19713,6 +19732,8 @@ snapshots: dependencies: pend: 1.2.0 + fflate@0.4.8: {} + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -22884,6 +22905,13 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 + posthog-js@1.186.1: + dependencies: + core-js: 3.39.0 + fflate: 0.4.8 + preact: 10.22.0 + web-vitals: 4.2.4 + preact@10.22.0: {} prelude-ls@1.1.2: {} @@ -25067,6 +25095,8 @@ snapshots: web-streams-polyfill@3.3.3: {} + web-vitals@4.2.4: {} + web3-bzz@1.10.4(bufferutil@4.0.8)(utf-8-validate@5.0.10): dependencies: '@types/node': 12.20.55 From df776a96f0b562b862009c66f6c4aafad19b8f72 Mon Sep 17 00:00:00 2001 From: Kamil Pyszkowski Date: Sat, 16 Nov 2024 03:19:31 +0100 Subject: [PATCH 02/12] Integrate basic dApp events with PostHog --- .../ConnectWalletButton.tsx | 7 +++++- dapp/src/components/Header/ConnectWallet.tsx | 9 +++++++- .../ActiveStakingStep/DepositBTCModal.tsx | 18 +++++++++++++-- .../ActiveUnstakingStep/SignMessageModal.tsx | 16 +++++++++++-- dapp/src/hooks/posthog/index.ts | 1 + dapp/src/hooks/posthog/usePostHogCapture.ts | 23 +++++++++++++++++++ dapp/src/hooks/posthog/usePostHogIdentity.ts | 21 +++++++++++++++++ dapp/src/hooks/useAcrePoints.ts | 8 +++++++ dapp/src/hooks/useInitApp.ts | 5 ++++ dapp/src/posthog/events.ts | 8 +++++++ 10 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 dapp/src/hooks/posthog/index.ts create mode 100644 dapp/src/hooks/posthog/usePostHogCapture.ts create mode 100644 dapp/src/hooks/posthog/usePostHogIdentity.ts create mode 100644 dapp/src/posthog/events.ts diff --git a/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx b/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx index 0747fdc8e..d865dd874 100644 --- a/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx +++ b/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx @@ -24,6 +24,7 @@ import { } from "@chakra-ui/react" import { IconArrowNarrowRight } from "@tabler/icons-react" import { AnimatePresence, Variants, motion } from "framer-motion" +import { usePostHogIdentity } from "#/hooks/posthog" import ArrivingSoonTooltip from "../ArrivingSoonTooltip" import { TextLg, TextMd } from "../shared/Typography" import ConnectWalletStatusLabel from "./ConnectWalletStatusLabel" @@ -71,6 +72,7 @@ export default function ConnectWalletButton({ const { closeModal } = useModal() const dispatch = useAppDispatch() const isMounted = useRef(false) + const { handleIdentification } = usePostHogIdentity() const [isLoading, setIsLoading] = useState(false) @@ -117,8 +119,11 @@ export default function ConnectWalletButton({ if (!btcAddress) return await handleSignMessageAndCreateSession(connector, btcAddress) + handleIdentification(btcAddress, { + connector: connectedConnector.id, + }) }, - [connector, handleSignMessageAndCreateSession], + [connector, handleSignMessageAndCreateSession, handleIdentification], ) const handleConnection = useCallback(() => { diff --git a/dapp/src/components/Header/ConnectWallet.tsx b/dapp/src/components/Header/ConnectWallet.tsx index e3424ed1d..9f99d6aa7 100644 --- a/dapp/src/components/Header/ConnectWallet.tsx +++ b/dapp/src/components/Header/ConnectWallet.tsx @@ -24,6 +24,7 @@ import { IconUserCode, } from "@tabler/icons-react" import { useMatch } from "react-router-dom" +import { usePostHogIdentity } from "#/hooks/posthog" function isChangeAccountFeatureSupported(embeddedApp: string | undefined) { return referralProgram.isEmbedApp(embeddedApp) @@ -39,11 +40,17 @@ export default function ConnectWallet() { size: "lg", }) const isDashboardPage = useMatch("/dashboard") + const { resetIdentity } = usePostHogIdentity() const handleConnectWallet = (isReconnecting: boolean = false) => { openModal(MODAL_TYPES.CONNECT_WALLET, { isReconnecting }) } + const handleDisconnectWallet = () => { + onDisconnect() + resetIdentity() + } + if (!address) { return (