Smart Wallet
Let your users connect to their Smart Wallet.
A Smart Wallet is a wallet that is controlled by a smart contract following the ERC-4337 specification.
Features
Smart Wallets work a little differently than other wallets since it's controlled by a programmable smart contract rather than a regular externally-owned account (EOA). This programmable wallet contract can:
- Holds any assets
- Pay for its own gas
- Execute transactions in batches
- Have multiple owners
- Assign roles and permissions
And more! Smart Wallets can be customized to each application's needs using the Solidity SDK.
Requirements
- A deployed account factory contract, you can deploy one in 1-click via the explore page
- An API key, which you can obtain from the thirdweb dashboard
The API key lets you access thirdweb's bundler and paymaster infrastructure, which is required for the smart wallet to operate and optionally enable gasless transactions.
The SmartWallet API is composable - you can bring in your own 4337-compatible factory contract and you can also use your own bundler or paymaster services.
Supported chains
With a thirdweb API key, you get access to bundler and paymaster infrastructure on the following chains:
- Goerli
- Mumbai
- Base Goerli
- Optimism Goerli
- Arbitrum Goerli
- Linea testnet
more chains added every week, to get support for a specific chain contact us.
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, 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();
await personalWallet.connect();
// 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
thirdwebApiKey: "{{api_key}}", // obtained from the thirdweb dashboard
gasless: true, // enable or disable gasless transactions
};
// Then, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.connect({
personalWallet,
});
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, or a chain name, or a RPC url.
factoryAddress
The address of the Smart Wallet Factory contract.
Must be a string
.
thirdwebApiKey
Your thirdweb API key, can be obtained from the thirdweb dashboard.
If you're using your own bundler and paymaster, you can set this to empty string.
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
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,
thirdwebApiKey,
factoryInfo: {
createAccount: (factory, owner) => {
return factory.prepare("customCreateAccount", [
owner,
getExtraData(),
]);
},
getAccountAddress(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,
thirdwebApiKey,
accountInfo: {
execute: (account, target, value, data) => {
return account.prepare("customExecute", [
target, value, data
]);
},
getNonce(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
.
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 our default chains.
import { SafeWallet } from "@thirdweb-dev/wallets";
import { Ethereum } from "@thirdweb-dev/chains";
const walletWithOptions = new SafeWallet(
{
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
, description
and logoUrl
properties.
import { SafeWallet } from "@thirdweb-dev/wallets";
const walletWithOptions = new SafeWallet({
dappMetadata: {
name: "thirdweb powered dApp",
url: "https://thirdweb.com",
description: "thirdweb powered dApp",
logoUrl: "https://thirdweb.com/favicon.ico",
},
});
walletId
An ID for the wallet used to store the wallet in the walletStorage
.
import { SafeWallet } from "@thirdweb-dev/wallets";
const walletWithOptions = new SafeWallet(
{
walletId: "wallet-id",
},
);
Methods
Inherhits all the public methods from the AbstractClientWallet
class.
connect
Prompt the user to connect their smart wallet to your app.
Note: A 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();
await personalWallet.connect();
// Then, connect the Smart wallet
const wallet = new SmartWallet(config);
await wallet.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 undefined
if the connection failed.
string | undefined;
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;