-
Notifications
You must be signed in to change notification settings - Fork 0
P-1114 Add Formo + Turnkey embedded wallet integration example #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+7,557
−0
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
f01b57a
Add with-turnkey example for Formo SDK integration
claude a4cbac1
Fix PR review issues: EIP-1193 provider, unused var, GitHub link
claude 9c5df1d
Fix Turnkey package versions and update to v5 SDK API
claude 953329c
Add EIP-1193 event emitter methods to Turnkey provider
claude 77af742
Cache EIP-1193 provider instance across getProvider() calls
claude 85b44e1
Replace custom EIP-1193 provider with @turnkey/eip-1193-provider
claude 37e2ec1
Use connectAsync instead of connect to catch wagmi connection errors
claude a8ae6ed
Remove redundant disconnect bridge — autocapture already handles it
claude 768dca6
Fix balance display precision and remove unnecessary force-dynamic
claude 56fd570
Replace Node.js crypto UUID import, extract balance helper, update RE…
claude 253fab7
Move setTimeout into useEffect for proper cleanup on unmount
claude bbc59d6
Fix prerequisites wording: Node.js and pnpm are both required
claude 04e374f
Subscribe to provider events for external state changes
claude 8e923fc
Remove event listeners on disconnect to prevent stale emissions
claude 46855d0
Use pnpm exclusively in README, warn on missing Formo write key
claude ad0b263
Address PR review feedback for with-turnkey example
claude 9552e64
Fix passkey login flow to initiate session when none exists
claude 9c3f8db
Add 'Create New Account' button for new Turnkey users
claude 60a5052
Fix signup email validation and login for sub-org passkeys
claude 23e8799
Fix stale closure: add signupEmail to useCallback deps
claude 386670e
Move sub-org creation to server-side API route
claude b893cf2
Remove wagmi, use Turnkey EIP-1193 provider directly with Formo
claude 17163a8
Fix stale closure bugs: turnkeyClient undefined after login and chain…
claude ad3494d
Address PR review feedback: fix docs, validate env vars, use toHex
claude 3e52a81
Memoize formoOptions to prevent unnecessary SDK re-initialization
claude 6ff820f
Address PR review feedback: docs, naming, and type safety
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Turnkey Configuration | ||
| # Get your Organization ID from https://app.turnkey.com/ | ||
| NEXT_PUBLIC_TURNKEY_ORGANIZATION_ID=your-turnkey-organization-id | ||
|
|
||
| # Relying Party ID for passkey authentication (use "localhost" for local dev) | ||
| NEXT_PUBLIC_TURNKEY_RP_ID=localhost | ||
|
|
||
| # Server-side Turnkey API keys (required for sub-org creation) | ||
| # Create an API key in your Turnkey dashboard under "API Keys" | ||
| TURNKEY_API_PUBLIC_KEY=your-turnkey-api-public-key | ||
| TURNKEY_API_PRIVATE_KEY=your-turnkey-api-private-key | ||
|
|
||
| # Formo Configuration | ||
| # Get your Write Key from https://app.formo.so/ | ||
| NEXT_PUBLIC_FORMO_WRITE_KEY=your-formo-write-key |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,161 @@ | ||||||||||||||||||||||||||
| # Formo + Turnkey Example App | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| This is an example Next.js application demonstrating integration between [Turnkey](https://www.turnkey.com/) embedded wallets and the [Formo Analytics SDK](https://formo.so/). | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Features | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **Turnkey Authentication**: Login with passkeys to access embedded wallets — no browser extensions needed | ||||||||||||||||||||||||||
| - **Formo Analytics Integration**: Track wallet events and custom analytics | ||||||||||||||||||||||||||
| - **EIP-1193 Provider**: Direct integration with Turnkey's `@turnkey/eip-1193-provider` for signing and transactions | ||||||||||||||||||||||||||
| - **Event Testing UI**: Test all major Formo SDK event types: | ||||||||||||||||||||||||||
| - Page events | ||||||||||||||||||||||||||
| - Connect/Disconnect events (auto-captured) | ||||||||||||||||||||||||||
| - Signature events (auto-captured) | ||||||||||||||||||||||||||
| - Transaction events (auto-captured) | ||||||||||||||||||||||||||
| - Custom events | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Prerequisites | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - Node.js 18+ and pnpm 9.15.4 | ||||||||||||||||||||||||||
| - A [Turnkey](https://app.turnkey.com/) account and Organization ID | ||||||||||||||||||||||||||
| - A [Formo](https://app.formo.so/) account and Write Key | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Quick Start | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 1. **Clone the repository** | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||
| git clone https://github.com/getformo/examples.git | ||||||||||||||||||||||||||
| cd examples/with-turnkey | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 2. **Install dependencies** | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||
| pnpm install | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 3. **Configure environment variables** | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Copy the example environment file and add your credentials: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||
| cp .env.example .env | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Edit `.env` with your values: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```env | ||||||||||||||||||||||||||
| NEXT_PUBLIC_TURNKEY_ORGANIZATION_ID=your-turnkey-organization-id | ||||||||||||||||||||||||||
| NEXT_PUBLIC_TURNKEY_RP_ID=localhost | ||||||||||||||||||||||||||
| TURNKEY_API_PUBLIC_KEY=your-turnkey-api-public-key | ||||||||||||||||||||||||||
| TURNKEY_API_PRIVATE_KEY=your-turnkey-api-private-key | ||||||||||||||||||||||||||
| NEXT_PUBLIC_FORMO_WRITE_KEY=your-formo-write-key | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
Comment on lines
+48
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The environment variable example in the
Suggested change
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 4. **Run the development server** | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||
| pnpm dev | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 5. Open [http://localhost:3000](http://localhost:3000) in your browser | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Project Structure | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
| src/ | ||||||||||||||||||||||||||
| ├── app/ | ||||||||||||||||||||||||||
| │ ├── api/ | ||||||||||||||||||||||||||
| │ │ └── create-sub-org/ | ||||||||||||||||||||||||||
| │ │ └── route.ts # Server-side Turnkey sub-organization creation | ||||||||||||||||||||||||||
| │ ├── globals.css # Global styles with Tailwind | ||||||||||||||||||||||||||
| │ ├── layout.tsx # Root layout with providers | ||||||||||||||||||||||||||
| │ ├── page.tsx # Main demo page with wallet UI and event testing | ||||||||||||||||||||||||||
| │ └── providers.tsx # Turnkey and Formo providers | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
devin-ai-integration[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## How It Works | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Turnkey Authentication | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Turnkey provides embedded wallets secured by passkeys. When a user authenticates: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 1. The user creates a passkey and a Turnkey sub-organization is created via the server-side API route | ||||||||||||||||||||||||||
| 2. The user authenticates via passkeys using `@turnkey/sdk-react` | ||||||||||||||||||||||||||
| 3. The app fetches the user's wallets from the Turnkey API | ||||||||||||||||||||||||||
| 4. An EIP-1193 provider is created via `@turnkey/eip-1193-provider`, enabling signing, transactions, and chain switching | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Formo Analytics | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The Formo SDK automatically captures wallet events when `autocapture: true` is enabled: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| | Event | Description | Auto-captured | | ||||||||||||||||||||||||||
| |-------|-------------|---------------| | ||||||||||||||||||||||||||
| | `page` | Page view events | Yes | | ||||||||||||||||||||||||||
| | `connect` | Wallet connected | Yes | | ||||||||||||||||||||||||||
| | `disconnect` | Wallet disconnected | Yes | | ||||||||||||||||||||||||||
| | `signature` | Message signing (personal_sign, signTypedData) | Yes | | ||||||||||||||||||||||||||
| | `transaction` | Transaction events (eth_sendTransaction) | Yes | | ||||||||||||||||||||||||||
| | `chain` | Chain/network changes | Yes | | ||||||||||||||||||||||||||
| | `track` | Custom events | No (manual) | | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Manual Event Tracking | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||
| import { useFormo } from "@formo/analytics"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| function MyComponent() { | ||||||||||||||||||||||||||
| const formo = useFormo(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Track custom event | ||||||||||||||||||||||||||
| await formo.track("button_clicked", { | ||||||||||||||||||||||||||
| button_id: "cta-main", | ||||||||||||||||||||||||||
| page: "home" | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Track page event | ||||||||||||||||||||||||||
| await formo.page("category", "page-name", { | ||||||||||||||||||||||||||
| custom_property: "value" | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Provider Setup | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The key setup in `providers.tsx`: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||
| import { TurnkeyProvider } from "@turnkey/sdk-react"; | ||||||||||||||||||||||||||
| import { FormoAnalyticsProvider } from "@formo/analytics"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Provider nesting order: | ||||||||||||||||||||||||||
| // TurnkeyProvider > WalletContext > FormoAnalyticsProvider | ||||||||||||||||||||||||||
| <FormoAnalyticsProvider | ||||||||||||||||||||||||||
| writeKey={formoWriteKey} | ||||||||||||||||||||||||||
| options={{ | ||||||||||||||||||||||||||
| provider, // EIP-1193 provider from Turnkey | ||||||||||||||||||||||||||
| autocapture: true, | ||||||||||||||||||||||||||
| tracking: true, | ||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||
| {children} | ||||||||||||||||||||||||||
| </FormoAnalyticsProvider> | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The Formo SDK hooks into the EIP-1193 provider to auto-capture wallet connect/disconnect, chain changes, signatures, and transactions. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Supported Chains | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The app is configured for Sepolia (testnet). To support additional chains, you would need to update the `chainParam` configuration in `page.tsx` and add a chain-switching UI along with dynamic provider configuration. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Resources | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - [Turnkey Documentation](https://docs.turnkey.com/) | ||||||||||||||||||||||||||
| - [Turnkey Embedded Wallet Quickstart](https://docs.turnkey.com/getting-started/embedded-wallet-quickstart) | ||||||||||||||||||||||||||
| - [Formo Documentation](https://docs.formo.so/) | ||||||||||||||||||||||||||
| - [Formo SDK Installation](https://docs.formo.so/install) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## License | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| MIT | ||||||||||||||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import type { NextConfig } from "next"; | ||
|
|
||
| const nextConfig: NextConfig = { | ||
| reactStrictMode: true, | ||
| }; | ||
|
|
||
| export default nextConfig; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| { | ||
| "name": "formo-example-turnkey", | ||
| "version": "0.1.0", | ||
| "private": true, | ||
| "scripts": { | ||
| "dev": "next dev --turbopack", | ||
| "build": "next build", | ||
| "start": "next start", | ||
| "lint": "next lint" | ||
| }, | ||
| "dependencies": { | ||
| "@formo/analytics": "^1.28.2", | ||
| "@heroicons/react": "^2.2.0", | ||
| "@turnkey/eip-1193-provider": "^3.4.26", | ||
| "@turnkey/sdk-browser": "^5.15.2", | ||
| "@turnkey/sdk-react": "^5.5.6", | ||
| "@turnkey/sdk-server": "^5.1.1", | ||
| "next": "^15.5.9", | ||
| "react": "^19.0.0", | ||
| "react-dom": "^19.0.0", | ||
| "react-toastify": "^11.0.5", | ||
| "viem": "^2.44.4" | ||
| }, | ||
| "devDependencies": { | ||
| "@eslint/eslintrc": "^3.2.0", | ||
| "@tailwindcss/postcss": "^4.1.18", | ||
| "@types/node": "^22.12.0", | ||
| "@types/react": "^19.0.7", | ||
| "@types/react-dom": "^19.0.3", | ||
| "eslint": "^9.18.0", | ||
| "eslint-config-next": "^15.5.9", | ||
| "postcss": "^8.5.1", | ||
| "tailwindcss": "^4.0.0", | ||
| "typescript": "^5.7.3" | ||
| }, | ||
| "packageManager": "pnpm@9.15.4" | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The environment variable setup instructions are incomplete. The
create-sub-orgfunctionality requires server-side Turnkey API keys (TURNKEY_API_PUBLIC_KEYandTURNKEY_API_PRIVATE_KEY), but they are not mentioned here. Please add them to this section to ensure users can set up the example correctly.Here is the complete set of variables that should be in the
.envfile: