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
2 changes: 2 additions & 0 deletions content/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,8 @@ navigation:
contents:
- page: Privy
path: wallets/pages/third-party/signers/privy.mdx
- page: Openfort
path: wallets/pages/third-party/signers/openfort.mdx
- page: Turnkey
path: wallets/pages/third-party/signers/turnkey.mdx
- page: Other signers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,5 @@ console.log("Transaction confirmed:", txStatus.receipts?.[0]?.transactionHash);
See full integration guides for supported providers:

* [Privy](/docs/wallets/third-party/signers/privy)
* [Openfort](/docs/wallets/third-party/signers/openfort)
* [Turnkey](/docs/wallets/third-party/signers/turnkey)
306 changes: 306 additions & 0 deletions content/wallets/pages/third-party/signers/openfort.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
---
title: Openfort
description: Use Openfort with Smart Wallets for EIP-7702, sponsorship, and batching
slug: wallets/third-party/signers/openfort
---

<Info>`@alchemy/wallet-apis` (v5.x.x) is currently in beta but is the recommended replacement for `@account-kit/wallet-client` (v4.x.x). If you run into any issues, please [reach out](mailto:support@alchemy.com).</Info>

Upgrade existing Openfort embedded wallets to Smart Wallets to enable gasless transactions, batching, and more in under 10 minutes. Keep Openfort for authentication, no wallet migration needed. Add battle-tested transaction infrastructure using EIP-7702 to upgrade your wallets to Smart Wallets:

* [#1 gas abstraction infrastructure](https://www.bundlebear.com/erc4337-bundlers/all) on the market
* [370M+](https://www.bundlebear.com/erc4337-paymasters/all) sponsored transactions
* 99.9% SLAs
* Trusted by Worldcoin, JP Morgan, Gensyn, and more

<Tabs>
<Tab title="React" language="react">
## Setup

Follow these steps to use Openfort signers with the Wallet Client SDK.

### Installation

<CodeGroup>
```shell npm
npm install @alchemy/wallet-apis @openfort/react wagmi viem @tanstack/react-query
```

```shell bun
bun add @alchemy/wallet-apis @openfort/react wagmi viem @tanstack/react-query
```

```shell yarn
yarn add @alchemy/wallet-apis @openfort/react wagmi viem @tanstack/react-query
```

```shell pnpm
pnpm add @alchemy/wallet-apis @openfort/react wagmi viem @tanstack/react-query
```
</CodeGroup>

### Prerequisites: Get your keys (API key, Policy ID, Openfort Publishable Key)

* Alchemy API key:
* Go to the [Alchemy Dashboard](https://dashboard.alchemy.com/)
* Create or select an app and copy the API key
* Gas sponsorship Policy ID (Gas Manager):
* Create a gas sponsorship policy in the [dashboard](https://dashboard.alchemy.com/services/gas-manager/configuration) and copy its Policy ID
* Openfort Publishable Key:
* Go to the [Openfort Dashboard](https://dashboard.openfort.xyz/)
* Create or select a project and copy the Publishable Key
* Openfort Shield Publishable Key:
* In the [Openfort Dashboard](https://dashboard.openfort.xyz/), navigate to Shield settings and copy the Shield Publishable Key

<Warning>
The gas sponsorship policy must be linked to the application behind your Alchemy API key for sponsorship to work.
</Warning>

### 1. Configure OpenfortProvider

Wrap your app with `OpenfortProvider` from `@openfort/react`, along with wagmi and React Query providers:

```tsx
import { OpenfortProvider, getDefaultConfig } from "@openfort/react";
import { WagmiProvider, createConfig } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { arbitrumSepolia } from "viem/chains";

const config = createConfig(
getDefaultConfig({
appName: "My App",
chains: [arbitrumSepolia],
})
);

const queryClient = new QueryClient();

export function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<OpenfortProvider
publishableKey="your-openfort-publishable-key"
walletConfig={{
shieldPublishableKey: "your-shield-publishable-key",
}}
>
<YourApp />
</OpenfortProvider>
</QueryClientProvider>
</WagmiProvider>
);
}
```

### 2. Get a signer from Openfort

Use wagmi's `useWalletClient` hook to get a viem `WalletClient` from the Openfort embedded wallet:

```tsx
import { useWalletClient } from "wagmi";
import type { WalletClient } from "viem";

const useOpenfortSigner = (): WalletClient | undefined => {
const { data: walletClient } = useWalletClient();
return walletClient;
};
```

### 3. Handle login

Use Openfort's React hooks to manage authentication state and conditionally render your wallet UI:

```tsx
import { useUser, useUI, useSignOut } from "@openfort/react";

function OpenfortWallet() {
const { isLoading, isAuthenticated } = useUser();
const { setOpen } = useUI();
const { signOut } = useSignOut();
const signer = useOpenfortSigner();

if (isLoading) {
return <p>Loading...</p>;
}

if (!isAuthenticated) {
return <button onClick={() => setOpen(true)}>Login with Openfort</button>;
}

return (
<div>
<button onClick={() => signOut()}>Logout</button>
{signer ? <SendTransaction signer={signer} /> : <p>Loading signer...</p>}
</div>
);
}
```

### 4. Request an account and send a transaction

Openfort provides a `WalletClient` signer, which does not support EIP-7702 authorization signing. Use [`requestAccount`](/wallets/transactions/using-eip-7702#how-to-use-non-7702-mode) to create a smart wallet, then pass the account address to `sendCalls`. The returned address is stable for a given signer and can be stored — you don't need to call `requestAccount` before every transaction:

```tsx
import { useMemo, useCallback } from "react";
import { zeroAddress } from "viem";
import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
import { arbitrumSepolia } from "viem/chains";
import type { WalletClient } from "viem";

function SendTransaction({ signer }: { signer: WalletClient }) {
const client = useMemo(
() =>
createSmartWalletClient({
signer,
transport: alchemyWalletTransport({
apiKey: "YOUR_ALCHEMY_API_KEY",
}),
chain: arbitrumSepolia,
paymaster: {
policyId: "YOUR_GAS_MANAGER_POLICY_ID",
},
}),
[signer],
);

const handleSend = useCallback(async () => {
// Request a smart wallet (required for WalletClient signers)
const { address } = await client.requestAccount({
creationHint: { accountType: "sma-b" },
});

// Send the transaction using the smart wallet address
const { id } = await client.sendCalls({
account: address,
calls: [{ to: zeroAddress, value: BigInt(0), data: "0x" }],
});

// Wait for the transaction to be confirmed
const result = await client.waitForCallsStatus({ id });
console.log(`Transaction hash: ${result.receipts?.[0]?.transactionHash}`);
}, [client]);

return <button onClick={handleSend}>Send transaction</button>;
}
```

### Notes

* See the [Sponsor gas](/wallets/transactions/sponsor-gas) guide for more on gas sponsorship configuration.
* Learn more about Openfort's React SDK in the [Openfort documentation](https://www.openfort.io/docs/products/embedded-wallet/react/quickstart).
</Tab>

<Tab title="JavaScript" language="typescript">
## Setup

Use the `@openfort/openfort-js` package with the Wallet Client SDK in a browser environment.

### Installation

<CodeGroup>
```shell npm
npm install @openfort/openfort-js @alchemy/wallet-apis viem
```

```shell bun
bun add @openfort/openfort-js @alchemy/wallet-apis viem
```

```shell yarn
yarn add @openfort/openfort-js @alchemy/wallet-apis viem
```

```shell pnpm
pnpm add @openfort/openfort-js @alchemy/wallet-apis viem
```
</CodeGroup>

### Prerequisites: Get your keys

* Alchemy API key:
* Go to the [Alchemy Dashboard](https://dashboard.alchemy.com/)
* Create or select an app and copy the API key
* Gas sponsorship Policy ID (Gas Manager):
* Create a gas sponsorship policy in the [dashboard](https://dashboard.alchemy.com/services/gas-manager/configuration) and copy its Policy ID
* Openfort Publishable Key:
* Go to the [Openfort Dashboard](https://dashboard.openfort.xyz/)
* Create or select a project and copy the Publishable Key
* Openfort Shield Publishable Key:
* In the [Openfort Dashboard](https://dashboard.openfort.xyz/), navigate to Shield settings and copy the Shield Publishable Key

<Warning>
The gas sponsorship policy must be linked to the application behind your Alchemy API key for sponsorship to work.
</Warning>

### Send a transaction

```ts
import Openfort from "@openfort/openfort-js";
import { createWalletClient, custom } from "viem";
import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
import { arbitrumSepolia } from "viem/chains";

// Initialize Openfort
const openfort = new Openfort({
baseConfiguration: {
publishableKey: process.env.OPENFORT_PUBLISHABLE_KEY!,
},
shieldConfiguration: {
shieldPublishableKey: process.env.OPENFORT_SHIELD_PUBLISHABLE_KEY!,
},
});

// Authenticate the user — verification is required before using the wallet
await openfort.auth.requestEmailOTP({ email: "user@example.com" });
await openfort.auth.verifyEmailOTP({ email: "user@example.com", code: "123456" });

// Get the EIP-1193 provider from Openfort
const provider = await openfort.embeddedWallet.getEthereumProvider();
const [address] = await provider.request({ method: "eth_requestAccounts" });

// Create a viem WalletClient from the Openfort provider
const signer = createWalletClient({
account: address,
chain: arbitrumSepolia,
transport: custom(provider),
});

// Create the Smart Wallet client
const client = createSmartWalletClient({
signer,
transport: alchemyWalletTransport({ apiKey: process.env.ALCHEMY_API_KEY! }),
chain: arbitrumSepolia,
paymaster: { policyId: process.env.ALCHEMY_POLICY_ID! },
});

// Request a smart wallet (required for WalletClient signers)
// The returned address is stable for a given signer and can be stored for later use
const { address: accountAddress } = await client.requestAccount({
creationHint: { accountType: "sma-b" },
});

// Send the transaction using the smart wallet address
const { id } = await client.sendCalls({
account: accountAddress,
calls: [
{
to: "0x0000000000000000000000000000000000000000",
value: BigInt(0),
data: "0x",
},
],
});

// Wait for the transaction to be confirmed
const result = await client.waitForCallsStatus({ id });
console.log(`Transaction hash: ${result.receipts?.[0]?.transactionHash}`);
```

### Notes

* See the [Sponsor gas](/wallets/transactions/sponsor-gas) guide for more on gas sponsorship configuration.
* This example uses Openfort's `@openfort/openfort-js` client-side package. `@alchemy/wallet-apis` can be used in any JavaScript environment.
* Learn more about Openfort's embedded wallets in the [Openfort documentation](https://www.openfort.io/docs).
</Tab>
</Tabs>
Loading