Skip to main content

Smart Wallet

Full Documentation

This page is a full reference, explaining how to use Smart Wallet with the Wallet SDK to connect a smart wallet to your app.

For a complete overview of Smart Wallets, visit the Smart Wallet SDK documentation.

Let your users connect to any Smart Wallet.

A Smart Wallet is a wallet that is controlled by a smart contract following the ERC-4337 specification.

Usage

To connect to a smart wallet, a personal wallet (acting as the key to the smart wallet) must first be connected.

import { LocalWallet, SmartWallet } from "@thirdweb-dev/wallets";
import { Goerli } from "@thirdweb-dev/chains";

// First, connect the personal wallet, which can be any wallet (metamask, walletconnect, etc.)
// Here we're just generating a new local wallet which can be saved later
const personalWallet = new LocalWallet();
await personalWallet.generate();

// Setup the Smart Wallet configuration
const config: SmartWalletConfig = {
chain: Goerli, // the chain where your smart wallet will be or is deployed
factoryAddress: "{{factory_address}}", // your own deployed account factory address
clientId: "YOUR_CLIENT_ID", // Use client id if using on the client side, get it from dashboard settings
secretKey: "YOUR_SECRET_KEY", // Use secret key if using on the server, get it from dashboard settings
gasless: true, // enable or disable gasless transactions
};

// Then, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

// You can then use this wallet to perform transactions via the SDK
const sdk = await ThirdwebSDK.fromWallet(wallet, Goerli);

Configuration

Here's the full configuration object you can pass when instantiating the SmartWallet class.

Mandatory properties

chain

The chain that the Smart Wallet contract is deployed to.

Either a Chain object, from the @thirdweb-dev/chains package, a chain name, or an RPC URL.

factoryAddress

The address of the Smart Wallet Factory contract.

Must be a string.

clientId or secretKey (recommended)

Your API key can be obtained from the thirdweb dashboard.

If you're using your own bundler and paymaster, you can set this to an empty string.

You can use either the clientId or the secretKey depending on whether your application is client or server side.

Must be a string.

gasless

Whether to turn on or off gasless transactions.

  • If set to true, all gas fees will be paid by a paymaster.
  • If set to false, all gas fees will be paid by the Smart Wallet itself (needs to be funded).

Must be a boolean.

Optional properties

clientId or secretKey (optional)

Provide clientId or secretKey to use the thirdweb RPCs for given chains

If you are using the SmartWallet in a in frontend - provide a clientId, If you are using the SmartWallet in backend - you can provide a secretKey.

You can create a clientId / secretKey from thirdweb dashboard.

factoryInfo

Customize how the Smart Wallet Factory contract is interacted with. If not provided, the default functions will be used.

Must be a object. The object can contain the following properties:

  • createAccount - a function that returns the transaction object to create a new Smart Wallet.
  • getAccountAddress - a function that returns the address of the Smart Wallet contract given the owner address.
  • abi - optional ABI. If not provided, the ABI will be auto-resolved.

Example:

 const config: SmartWalletConfig = {
chain,
gasless,
factoryAddress,
clientId,
factoryInfo: {
createAccount: async (factory, owner) => {
return factory.prepare("customCreateAccount", [
owner,
getExtraData(),
]);
},
getAccountAddress: async (factory, owner) => {
return factory.call("getAccountAddress", [owner]);
},
abi: [...]
},
};
accountInfo

Customize how the Smart Wallet Account contract is interacted with. If not provided, the default functions will be used.

Must be a object. The object can contain the following properties:

  • execute - a function that returns the transaction object to execute an arbitrary transaction.
  • getNonce - a function that returns the current nonce of the account.
  • abi - optional ABI. If not provided, the ABI will be auto-resolved.

Example:

 const config: SmartWalletConfig = {
chain,
gasless,
factoryAddress,
clientId,
accountInfo: {
execute: async (account, target, value, data) => {
return account.prepare("customExecute", [
target, value, data
]);
},
getNonce: async (account) => {
return account.call("getNonce");
},
abi: [...]
},
};
bundlerUrl

Your own bundler URL to send user operations to. Uses thirdweb's bundler by default.

Must be a string.

paymasterUrl

Your own paymaster URL to send user operations to for gasless transactions. Uses thirdweb's paymaster by default.

Must be a string.

paymasterAPI

Fully customize how the paymaster data is computed.

Must be a PaymasterAPI class.

Example:

class MyPaymaster extends PaymasterAPI {
async getPaymasterAndData(
userOp: Partial<UserOperationStruct>,
): Promise<string> {
// your implementation, must return the signed paymaster data
}
}

const config: SmartWalletConfig = {
chain,
gasless,
factoryAddress,
clientId,
paymasterAPI: new MyPaymaster(),
};
entryPointAddress

The entrypoint contract address. Uses v0.6 by default.

Must be a string.

chains

Provide an array of chains you want to support.

Must be an array of Chain objects, from the @thirdweb-dev/chains package.

Defaults to thirdweb's default chains.

import { SmartWallet } from "@thirdweb-dev/wallets";
import { Ethereum } from "@thirdweb-dev/chains";

const wallet = new SmartWallet(
{
chains: [Ethereum],
},
);
dappMetadata

Information about your app that the wallet will display when your app tries to connect to it.

Must be an object containing name, url and optionally description and logoUrl properties.

import { SmartWallet } from "@thirdweb-dev/wallets";

const wallet = new SmartWallet({
dappMetadata: {
name: "thirdweb powered dApp",
url: "https://thirdweb.com",
description: "thirdweb powered dApp", // optional
logoUrl: "https://thirdweb.com/favicon.ico", // optional
},
});
walletId

An ID for the wallet that is used to store the wallet in the walletStorage.

import { SmartWallet } from "@thirdweb-dev/wallets";

const wallet = new SmartWallet(
{
walletId: "wallet-id",
},
);
walletConnectReceiver

Enables the wallet to be available to listen for WalletConnect events.

Note that to fully support this there needs to be a UI component to handle WalletConnect uris (wc://) and pass it to the wallet.

Defaults to undefined.

export type WalletConnectReceiverConfig = {
walletConnectReceiver?:
| {
walletConnectWalletMetadata?: WCMetadata;
walletConnectV2ProjectId?: string;
walletConnectV2RelayUrl?: string;
}
| true;
};
walletConnectV2ProjectId

The WalletConnect V2 projectId. You can get one in the WalletConnect portal.

Defaults to a common projectId set by thirdweb. This should be ok for testing but note that if you want to deploy your mobile app it may make sense to create your own as WalletConnect may throttle traffic coming from the same projectId.

walletConnectV2RelayUrl

Define a custom Relay Server URL. Defaults to "wss://relay.walletconnect.com"

walletConnectWalletMetadata

Metadata that will be displayed in the dApp once your SmartWallet is connected to it.

{
name: string; // defaults to: "Thirdweb Smart Wallet",
description: string; // defaults to: "Thirdweb Smart Wallet",
url: string: // defaults to: "https://thirdweb.com",
icons: string[]; // defaults to: ["https://thirdweb.com/favicon.ico"],
};

Methods

Inherits all the public methods from the AbstractClientWallet class.

connect

Connect the smart wallet to your app using a personal wallet.

This personal wallet must be connected before connecting to a Smart wallet.

import { CoinbaseWallet, SmartWallet } from "@thirdweb-dev/wallets";
import { Ethereum } from "@thirdweb-dev/chains";

// First, connect the personal wallet
const personalWallet = new CoinbaseWallet();
const personalWalletAddress = await personalWallet.connect();

// Then, connect the Smart wallet
const smartWallet = new SmartWallet(config);
const smartWalletAddress = await smartWallet.connect({
personalWallet,
});
Configuration

personalWallet

The instance of a personal wallet that can sign transactions on the Smart Wallet.

Must be an EVMWallet instance such as CoinbaseWallet or MetamaskWallet.

Returns a string containing the wallet address, or throws an error if the connection fails.

string;

execute

Execute a single transaction as the connected Smart Wallet.

// first, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

// Then you can execute transactions directly
const transaction = prepareTransaction();
await wallet.execute(transaction);
Configuration

transaction

The transaction to execute. Must be of type Transaction from the @thirdweb-dev/sdk package.

Creating these transactions can be done easily using the Transaction Builder from the thirdweb SDK.

Returns a TransactionResult containing the transaction receipt.

TransactionResult;

executeBatch

Execute multiple transactions as the connected Smart Wallet at once, only requiring one signature from the personal wallet.

// first, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

// Then you can execute multiple transactions at once
const transactions = [
prepareTransaction1(),
prepareTransaction2(),
prepareTransaction3(),
];
await wallet.executeBatch(transactions);
Configuration

transactions

An array of transactions to execute. Must be of type Transaction[] from the @thirdweb-dev/sdk package.

Creating these transactions can be done easily using the Transaction Builder from the thirdweb SDK.

Returns a TransactionResult containing the transaction receipt.

TransactionResult;

createSessionKey

Create and add a session key to the Smart Wallet with specific permissions.

// first, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

// Then you can add session keys with permissions
await wallet.createSessionKey(
"0x...", // the session key address
{
approvedCallTargets: ["0x..."], // the addresses of contracts that the session key can call
nativeTokenLimitPerTransaction: 0.1, // the maximum amount of native token (in ETH) that the session key can spend per transaction
startDate: new Date(), // the date when the session key becomes active
expirationDate = new Date(Date.now() + 24 * 60 * 60 * 1000); // the date when the session key expires
}
);
Configuration

keyAddress

The address of the session key to add to the Smart Wallet.

permissions

The specific permissions to give to the session key. Must be of type SignerPermissionsInput from the @thirdweb-dev/sdk package.

{
startDate: Date;
expirationDate: Date;
nativeTokenLimitPerTransaction: number;
approvedCallTargets: string[];
}

revokeSessionKey

Revoke a session key from the Smart Wallet.

// first, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

// Then you can revoke session keys
await wallet.revokeSessionKey(
"0x...", // the session key address
);
Configuration

keyAddress

The address of the session key to revoke.

isDeployed

Check if the Smart Wallet is deployed onchain.

// first, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

const isDeployed = await wallet.isDeployed();
console.log("Smart Wallet deployed:", isDeployed); // true or false

deploy

Force deploy the Smart Wallet onchain. Will throw if already deployed.

// first, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

const tx = await wallet.deploy();
console.log("Smart Wallet deployed:", tx); // the transaction receipt

deployIfNeeded

Force deploy the Smart Wallet onchain. If already deployed, will do nothing.

// first, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

await wallet.deployIfNeeded();

getPersonalWallet

Get the personal wallet that is connected to the Smart Wallet.

// first, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});

const personalWallet = wallet.getPersonalWallet();