Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/smart-accounts/signers/privy/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
NEXT_PUBLIC_PIMLICO_API_KEY=
NEXT_PUBLIC_PRIVY_APP_ID=
37 changes: 37 additions & 0 deletions examples/smart-accounts/signers/privy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
/.yarn/

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
66 changes: 66 additions & 0 deletions examples/smart-accounts/signers/privy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# MetaMask Smart Accounts & Privy Quickstart

This is a NextJS MetaMask Smart Accounts & Privy Quickstart created with [`@metamask/create-gator-app`](https://www.npmjs.com/package/@metamask/create-gator-app).

This template is meant to help you bootstrap your own projects with Metamask Smart Acounts. It helps you build smart accounts with account abstraction, and powerful delegation features.

Learn more about [Metamask Smart Accounts](https://docs.metamask.io/smart-accounts-kit/concepts/smart-accounts/).

## Prerequisites

1. **Pimlico API Key**: In this template, you’ll use Pimlico’s
bundler and paymaster services to submit user operations and
sponsor transactions. You can get your API key from [Pimlico’s dashboard](https://dashboard.pimlico.io/apikeys).

2. **Privy App ID**: Please create a new project on Privy Dashboard, and get your App ID.

## Project structure

```bash
template/
├── public/ # Static assets
├── src/
│ ├── app/ # App router pages
│ ├── components/ # UI Components
│ ├── hooks/ # Custom React hooks
│ ├── providers/ # Custom React Context Provider
│ └── utils/ # Utils for the starter
├── .env # Environment variables
├── .gitignore # Git ignore rules
├── next.config.ts # Next.js configuration
└── tsconfig.json # TypeScript configuration
```

## Setup environment variables

Update the following environment variables in the `.env` file at
the root of your project.

```
NEXT_PUBLIC_PIMLICO_API_KEY =

# Enter your Privy App ID
NEXT_PUBLIC_PRIVY_APP_ID =
```

## Getting started

First, start the development server using the package manager
you chose during setup.

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```

Open [http://localhost:3000](http://localhost:3000) in your browser to view the app.

## Learn more

To learn more about MetaMask Smart Accounts, take a look at the following resources:

- [Quickstart](https://docs.metamask.io/smart-accounts-kit/get-started/smart-account-quickstart/) - Get started quickly with the MetaMask Smart Accounts
- [Delegation quickstart](https://docs.metamask.io/smart-accounts-kit/guides/delegation/execute-on-smart-accounts-behalf/) - Get started quickly with creating a MetaMask smart account and completing the delegation lifecycle (creating, signing, and redeeming a delegation).
16 changes: 16 additions & 0 deletions examples/smart-accounts/signers/privy/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const compat = new FlatCompat({
baseDirectory: __dirname,
});

const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];

export default eslintConfig;
6 changes: 6 additions & 0 deletions examples/smart-accounts/signers/privy/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
};

export default nextConfig;
35 changes: 35 additions & 0 deletions examples/smart-accounts/signers/privy/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "privy",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"allow-scripts": "echo 'n/a'"
},
"dependencies": {
"@metamask/smart-accounts-kit": "^0.2.0",
"@privy-io/react-auth": "3.7.0",
"@privy-io/wagmi": "^2.1.0",
"@tanstack/react-query": "^5.90.12",
"next": "15.4.8",
"permissionless": "^0.3.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"viem": "^2.41.2",
"wagmi": "^3.1.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.4.8",
"tailwindcss": "^4",
"typescript": "^5"
}
}
5 changes: 5 additions & 0 deletions examples/smart-accounts/signers/privy/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const config = {
plugins: ["@tailwindcss/postcss"],
};

export default config;
1 change: 1 addition & 0 deletions examples/smart-accounts/signers/privy/public/file.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/smart-accounts/signers/privy/public/globe.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/smart-accounts/signers/privy/public/next.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/smart-accounts/signers/privy/public/vercel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/smart-accounts/signers/privy/public/window.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "tailwindcss";
35 changes: 35 additions & 0 deletions examples/smart-accounts/signers/privy/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { AppProvider } from "@/providers/AppProvider";

const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});

const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});

export const metadata: Metadata = {
title: "MetaMask Smart Accounts x Privy Example",
description: "A example for using Privy as a signer for MetaMask Smart Accounts",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" className="dark:text-white">
<body
className={`${geistSans.variable} ${geistMono.variable} bg-white dark:bg-black text-black dark:text-white font-geist-sans antialiased max-w-full overflow-x-hidden`}
>
<AppProvider>{children}</AppProvider>
</body>
</html>
);
}
18 changes: 18 additions & 0 deletions examples/smart-accounts/signers/privy/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

import Steps from "@/components/Steps";
import Footer from "@/components/Footer";

export default function Home() {
return (
<div className="grid items-center justify-items-center min-h-screen p-8 gap-4 font-geist-sans">
<h1 className="text-3xl font-bold text-center max-w-2xl leading-relaxed">
MetaMask Smart Accounts x Privy Quickstart
</h1>
<main className="flex flex-col gap-6 row-start-2">
<Steps />
</main>
<Footer />
</div>
);
}
20 changes: 20 additions & 0 deletions examples/smart-accounts/signers/privy/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ButtonHTMLAttributes, ReactNode } from "react";

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children: ReactNode;
}

export default function Button({
children,
className = "",
...props
}: ButtonProps) {
const baseClasses =
'w-fit px-4 py-2 text-sm font-semibold text-white bg-gradient-to-br from-indigo-500 to-blue-500 hover:from-indigo-600 hover:to-blue-600 rounded-lg cursor-pointer transition-all duration-200 ease-in-out shadow-md hover:scale-102 active:scale-95 min-h-4 inline-flex items-center justify-center border-none disabled:opacity-50 disabled:cursor-not-allowed';

return (
<button className={`${baseClasses} ${className}`} {...props}>
{children}
</button>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";

import Button from "@/components/Button";
import { useConnectOrCreateWallet } from "@privy-io/react-auth";

export default function ConnectButton() {
const { connectOrCreateWallet } = useConnectOrCreateWallet();

return (
<div className="flex gap-2">
<Button onClick={() => connectOrCreateWallet()}>
Connect with Privy
</Button>
</div>
);
}
40 changes: 40 additions & 0 deletions examples/smart-accounts/signers/privy/src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Image from "next/image";

export default function Footer() {
return (
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-start">
<a
href="https://docs.metamask.io/smart-accounts-kit/"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
>
<Image
aria-hidden
src="/file.svg"
alt="File icon"
width={16}
height={16}
className="flex-shrink-0"
/>
Docs
</a>
<a
href="https://github.com/metamask/gator-examples"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
>
<Image
aria-hidden
src="/window.svg"
alt="Window icon"
width={16}
height={16}
className="flex-shrink-0"
/>
Examples
</a>
</footer>
);
}
Loading
Loading