Skip to content
Merged
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
12 changes: 8 additions & 4 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@
"smart-wallet/concepts/features/optional/spend-permissions",
"smart-wallet/concepts/features/optional/batch-operations",
"smart-wallet/concepts/features/optional/custom-gas-tokens",
"smart-wallet/concepts/features/optional/sub-accounts"
"smart-wallet/concepts/features/optional/sub-accounts",
"smart-wallet/concepts/features/optional/profiles"
]
}
]
Expand Down Expand Up @@ -242,7 +243,8 @@
"pages": [
"smart-wallet/guides/sub-accounts",
"smart-wallet/guides/sub-accounts/setup",
"smart-wallet/guides/sub-accounts/using-sub-accounts"
"smart-wallet/guides/sub-accounts/using-sub-accounts",
"smart-wallet/guides/sub-accounts/sub-accounts-with-privy"
]
},
"smart-wallet/guides/spend-permissions"
Expand All @@ -251,7 +253,8 @@
{
"group": "Examples",
"pages": [
"smart-wallet/examples/coin-a-joke-app"
"smart-wallet/examples/coin-a-joke-app",
"smart-wallet/examples/onchain-vibes-store-with-profiles"
]
},
{
Expand Down Expand Up @@ -305,7 +308,8 @@
"smart-wallet/technical-reference/spend-permissions/coinbase-fetchpermissions"
]
},
"smart-wallet/technical-reference/sub-account-reference"
"smart-wallet/technical-reference/sdk/sub-account-reference",
"smart-wallet/technical-reference/profiles-reference"
]
},
{
Expand Down
102 changes: 102 additions & 0 deletions docs/smart-wallet/concepts/features/optional/profiles.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
title: 'Profiles'
---

## Overview

Profiles allow developers to request personal information from Smart Wallet users during a transaction. This is useful for applications that need:

- Email addresses for notifications or account creation
- Physical addresses for shipping products
- Phone numbers for verification
- Names for personalization

Smart Wallet handles the collection of this information and it is left to the developer
to validate it and store it as they see fit while following the standards and regulations in place.
Users can choose to use profile info (securely stored with Coinbase) or enter new information when asked for it.

<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<img
alt="Profiles Demo"
src="https://i.imgur.com/rC674pl.gif"
width="1000"
loading="lazy"
style={{ borderRadius: "16px" }}
/>
<em>Profiles Demo</em>
</div>

<Info>
**Privacy First**

Users always have full control over their data. They can choose to share or withhold any information, and they're clearly shown what data you're requesting.

</Info>

## How it works

When you send a request for a transaction to Smart Wallet,
you can specify the information you need from the user.

```ts
const response = await provider?.request({
method: "wallet_sendCalls",
params: [
{
version: "1.0",
chainId: numberToHex(84532), // Base Sepolia testnet
calls: [
{
to: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // USDC contract address on Base Sepolia
data: encodeFunctionData({
abi: erc20Abi,
functionName: "transfer",
args: [
"0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
parseUnits("0.01", 6),
],
}),
},
], // Simple transfer of 0.01 USDC to the contract
capabilities: {
dataCallback: {
requests: [
{
type: "email",
optional: false,
},
{
type: "physicalAddress",
optional: false,
},
],
callbackURL: YOUR_CALLBACK_URL, // eg. https://your-url.com/api/data-validation
},
},
},
],
});
```

This adds an additional step to the transaction where the user is prompted to share their email address and their physical address like so:

<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<img
alt="Profiles Demo"
src="/images/smart-wallet/ProfilesScreenshot.png"
width="300"
loading="lazy"
/>
<em>Profiles Screenshot</em>
</div>

Once the user has shared their information, the callbackURL is called with the data.
The callbackURL is a route on your server that you define and is used to validate the data.

You are also able to update the request based on the response from the user.

## Start using Profiles

Profiles is currently in alpha and only available in a dev environment on all networks.

To start using Profiles, you can follow the [Profiles guide](/identity/smart-wallet/guides/profiles).
2 changes: 1 addition & 1 deletion docs/smart-wallet/examples/coin-a-joke-app.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "Coin Your Bangers: Turn Your Jokes into Coins"
sidebarTitle: "Coin Your Bangers"
sidebarTitle: "Coin Your Bangers (Sub Accounts)"
---

import { GithubRepoCard } from "/snippets/GithubRepoCard.mdx"
Expand Down
182 changes: 182 additions & 0 deletions docs/smart-wallet/examples/onchain-vibes-store-with-profiles.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
title: 'Onchain Vibes Store (Profiles)'
description: 'How Onchain Vibes Store uses Coinbase Smart Wallet Profiles for secure user data collection during onchain checkout.'
---

import {GithubRepoCard} from "/snippets/GithubRepoCard.mdx";

## Overview

Onchain Vibes Store demonstrates how to use [**Smart Wallet Profiles**](/smart-wallet/concepts/features/optional/profiles)
to securely collect user information (like email and physical address)
during an onchain transaction. This feature enables seamless, privacy-first
data collection for e-commerce and other onchain apps.

## What Are Smart Wallet Profiles?

Smart Wallet Profiles allow your app to request personal information from users as part of a transaction. Supported data types include:

- Email address
- Phone number
- Physical address
- Name
- Onchain wallet address

Users are always in control: they see exactly what you request and can choose to share or withhold any information.

## How It Works in This App

1. **User clicks Buy**: The checkout UI lets users select what info to share (email, address).
2. **App requests data**: The app sends a transaction with a `dataCallback` capability, specifying the requested data and a callback URL for validation.
3. **Smart Wallet prompts the user**: The wallet UI collects the requested info.
4. **Validation**: The wallet POSTs the data to your callback API for validation.
5. **Transaction proceeds**: If validation passes, the transaction completes and the app displays the collected info.

<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<img
alt="Onchain Vibes Store"
src="https://i.imgur.com/rC674pl.gif"
width="1000"
loading="lazy"
/>
</div>
<div style={{ textAlign: 'center', marginTop: '0.5rem', fontStyle: 'italic' }}>
Onchain Vibes Store Quick Demo
</div>

## Skip ahead

If you want to skip ahead and just get the final code, you can find it here:

<GithubRepoCard title="Onchain Vibes Store" githubUrl="https://github.com/base/demos/tree/master/smart-wallet/onchain-vibes-store" />


## UI Walkthrough: CheckoutButton

The main logic lives in `src/components/CheckoutButton.tsx`:

```tsx src/components/CheckoutButton.tsx
const requests = [];
if (dataToRequest.email) requests.push({ type: "email", optional: false });
if (dataToRequest.address) requests.push({ type: "physicalAddress", optional: false });

const response: any = await provider?.request({
method: "wallet_sendCalls",
params: [{
version: "1.0",
chainId: numberToHex(84532), // Base Sepolia
calls: [
{
to: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // USDC contract
data: encodeFunctionData({
abi: erc20Abi,
functionName: "transfer",
args: [
"0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
parseUnits("0.01", 6),
],
}),
},
],
capabilities: {
dataCallback: {
requests,
callbackURL: getCallbackURL(),
},
},
}],
});
```

- The user selects which data to share (checkboxes for email/address).
- The app sends a transaction with a `dataCallback` capability.
- The callback URL is set to your API endpoint (must be HTTPS, e.g. via ngrok in dev).

---

## API Walkthrough: Data Validation

The callback API is implemented in `src/api/data-validation/route.ts`:

```ts src/api/data-validation/route.ts
export async function POST(request: NextRequest) {
const requestData = await request.json();
try {
const email = requestData.requestedInfo.email;
const physicalAddress = requestData.requestedInfo.physicalAddress;
const errors: any = {};
if (email && email.endsWith("@example.com")) {
errors.email = "Example.com emails are not allowed";
}
if (physicalAddress) {
if (physicalAddress.postalCode && physicalAddress.postalCode.length < 5) {
if (!errors.physicalAddress) errors.physicalAddress = {};
errors.physicalAddress.postalCode = "Invalid postal code";
}
if (physicalAddress.countryCode === "XY") {
if (!errors.physicalAddress) errors.physicalAddress = {};
errors.physicalAddress.countryCode = "We don't ship to this country";
}
}
if (Object.keys(errors).length > 0) {
return NextResponse.json({ errors });
}
return NextResponse.json({
calls: requestData.calls,
chainId: requestData.chainId,
capabilities: requestData.capabilities
});
} catch (error) {
return NextResponse.json({ errors: { server: "Server error validating data" } });
}
}
```

- The API receives the user's data, validates it, and returns errors if needed.
- If validation passes, it must return the original `calls`, `chainId`, and `capabilities`.
- If errors are returned, the wallet prompts the user to correct their info.

---

## Wagmi & Wallet Setup

The app uses Wagmi and the Coinbase Wallet connector, configured for Smart Wallet and profiles:

```ts
import { coinbaseWallet } from "wagmi/connectors";
const cbWalletConnector = coinbaseWallet({
appName: "Vibes Store",
preference: {
keysUrl: "https://keys.coinbase.com/connect",
options: "smartWalletOnly",
},
});
```

---

## Testing Locally

1. Start your dev server: `npm run dev`
2. Start ngrok: `ngrok http 3000`
3. Set `VITE_NGROK_URL` in your `.env` to your ngrok HTTPS URL
4. Try a purchase and share profile data

---

## Best Practices

- **Only request what you need**: Ask for the minimum info required.
- **Explain why**: Tell users why you need each field.
- **Validate thoroughly**: Implement robust server-side validation.
- **Handle errors gracefully**: Show clear error messages.
- **Use HTTPS**: Your callback URL must be HTTPS (ngrok for local dev).

---

## Resources

- [Profiles Guide](/smart-wallet/guides/profiles)
- [Profiles Reference](/smart-wallet/technical-reference/profiles-reference)
- [Smart Wallet Docs](/smart-wallet/quickstart)
- [Wagmi Docs](https://wagmi.sh/)
Loading