Skip to content

Using server wallets with smart wallets

This guide explains how to use smart wallets from your server. Using server wallets as smart wallets gives your application all the benefits of account abstraction, including gas sponsorship, with the flexibilty of server wallets.

In this setup, you create a server wallet that servers as a signer for the smart wallet. Note that the server wallet's address is not the smart wallet address in this case - it simply authorizes actions taken by the smart wallet. All transactions and assets are tied to the smart wallet.

TIP

This guide uses Kernel as the smart wallet contract provider, but your implementation can use any smart wallet provider.

0: Install necessary depedencies

This guide uses Privy's server SDK to create the server wallet, Pimlico's permissionless package, and viem. Install these packages with the following command:

sh
npm i @privy-io/server-auth permissionless viem

1: Create a server wallet

Create a privy client and use the create method from Privy's SDK to create a server wallet. If you already have a server wallet you wish to use, you can skip this step.

ts
import {PrivyClient} from '@privy-io/server-auth';

// Initialize your Privy client
const privy = new PrivyClient('your privy app id', 'your privy app secret');

// Create a server wallet
const {id: walletId, address, chainType} = await privy.walletApi.create({chainType: 'ethereum'});

2: Get a viem LocalAccount for the server wallet

Create a viem LocalAccount object representing the server wallet. Use the createViemAccount method from Privy's SDK.

tsx
import {createViemAccount} from '@privy-io/server-auth/viem';

// Create a viem account instance for a wallet
const serverWalletAccount = await createViemAccount({
  walletId,
  address,
  privy,
});

3: Create a smart wallet

Use permissionless to create a smart wallet with the server wallet as the signer. Learn more about creating smart wallet accounts in the permissionless docs.

tsx
import {toKernelSmartAccount} from 'permissionless/accounts';
import {entryPoint07Address} from 'viem/account-abstraction';

const kernelSmartAccount = await toKernelSmartAccount({
  client: publicClient,
  entryPoint: {
    address: entryPoint07Address,
    version: '0.7',
  },
  owner: serverWalletAccount,
});

4: Create a client for the smart wallet

You can use this smart wallet client to request signatures and transactions from the smart wallet. Learn more about making transactions on the client in the permissonless docs.

tsx
import {createSmartAccountClient, walletClientToCustomSigner} from 'permissionless';
import {createPublicClient, http} from 'viem';

const bundlerUrl = 'your bundler URL';
const paymasterUrl = 'your paymaster URL';

// Create a viem public client for RPC calls
const publicClient = createPublicClient({
  chain: sepolia, // Replace this with the chain of your choice
  transport: http(), // Optionally include an RPC override
});

// Create the paymaster client to sponsor gas fees on transactions
const paymasterClient = createPimlicoClient({
  transport: http(paymasterUrl),
  entryPoint: kernelSmartAccount.entryPoint,
});

// Create the SmartAccountClient for requesting signatures and transactions (RPCs)
const smartAccountClient = createSmartAccountClient({
  account: kernelSmartAccount,
  chain: sepolia,
  paymaster: paymasterClient,
  bundlerTransport: http(bundlerUrl),
  userOperation: {
    estimateFeesPerGas: async () => (await paymasterClient.getUserOperationGasPrice()).fast,
  },
});