SmartWallet
Let your users connect to a Smart Wallet .
A Smart Wallet is a wallet that is controlled by a smart contract following the ERC-4337 specification .
For a complete overview of Smart Wallets, visit the Smart Wallet SDK documentation
References
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 laterconst personalWallet = new LocalWallet();await personalWallet.generate(); // Setup the Smart Wallet configurationconst 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 walletconst wallet = new SmartWallet(config);await wallet.connect({ personalWallet,}); // You can then use this wallet to perform transactions via the SDKconst sdk = await ThirdwebSDK.fromWallet(wallet, Goerli);
> {}
function constructor(
The options
object includes the following properties:
Required 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
.
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 (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
.
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.
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.
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.
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, // highlight-start paymasterAPI: new MyPaymaster(), // highlight-end};
entryPointAddress
The entrypoint contract address. Uses v0.6 by default.
Must be a string
.
deployOnSign
Whether to deploy the smart wallet when the user signs a message. Defaults to true.
Must be a boolean
.
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 .
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 },});
Add another admin to the smart wallet.
function addAdmin( adminAddress: string,): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
auto-connect the wallet if possible
function autoConnect(): Promise<string>;
Connect the SmartWallet with given personalWallet
function connect(): Promise<string>;
The connectOptions
object includes the following properties:
personalWallet
The instance of a personal wallet that can sign transactions on the Smart Wallet.
Must be of type EVMWallet
instance such as CoinbaseWallet
or MetamaskWallet
.
Create and add a session key to the Smart Wallet with specific permissions.
// Then you can add session keys with permissionsawait 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 });
function createSessionKey( keyAddress: string, permissions: { approvedCallTargets: Array<string> | "*"; expirationDate?: number | Date; nativeTokenLimitPerTransaction?: string | number; startDate?: number | Date; },): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
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[];}
let permissions: { approvedCallTargets: Array<string> | "*"; expirationDate?: number | Date; nativeTokenLimitPerTransaction?: string | number; startDate?: number | Date;};
Manually deploy the smart wallet contract. If already deployed this will throw an error.
Note that this is not necessary as the smart wallet will be deployed automatically on the first transaction the user makes.
const tx = await wallet.deploy();
function deploy(): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
Manually deploy the smart wallet contract. If already deployed this will do nothing. Note that this is not necessary as the smart wallet will be deployed automatically on the first transaction the user makes.
await wallet.deployIfNeeded();
Estimate the gas cost of a single transaction
function estimate(): Promise<{ details: { deployCost: BigNumber; deployGasLimit: BigNumber; gasPrice: BigNumber; totalCost: BigNumber; transactionCost: BigNumber; transactionGasLimit: BigNumber; }; ether: string; wei: BigNumber;}>;
Estimate the gas cost of a batch of transactions
function estimateBatch(): Promise<{ details: { deployCost: BigNumber; deployGasLimit: BigNumber; gasPrice: BigNumber; totalCost: BigNumber; transactionCost: BigNumber; transactionGasLimit: BigNumber; }; ether: string; wei: BigNumber;}>;
Estimate the gas cost of a batch of raw transactions
function estimateBatchRaw( transactions: Array<Deferrable<TransactionRequest>>,): Promise<{ details: { deployCost: BigNumber; deployGasLimit: BigNumber; gasPrice: BigNumber; totalCost: BigNumber; transactionCost: BigNumber; transactionGasLimit: BigNumber; }; ether: string; wei: BigNumber;}>;
Estimate the gas cost of a single raw transaction
function estimateRaw( transactions: Deferrable<TransactionRequest>,): Promise<{ details: { deployCost: BigNumber; deployGasLimit: BigNumber; gasPrice: BigNumber; totalCost: BigNumber; transactionCost: BigNumber; transactionGasLimit: BigNumber; }; ether: string; wei: BigNumber;}>;
Execute a single transaction and wait for confirmations
const transaction = prepareTransaction();await wallet.execute(transaction);
function execute( Omit<TransactionResultWithMetadata<unknown>, "data"> >,): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
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.
Omit<TransactionResultWithMetadata<unknown>, "data">>;
Execute multiple transactions in a single batch and wait for confirmations, only requiring one signature from the personal wallet.
// Then you can execute multiple transactions at onceconst transactions = [ prepareTransaction1(), prepareTransaction2(), prepareTransaction3(),];await wallet.executeBatch(transactions);
function executeBatch(): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
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.
Execute multiple raw transactions in a single batch and wait for confirmations
function executeBatchRaw( transactions: Array<Deferrable<TransactionRequest>>,): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
Execute a single raw transaction and wait for confirmations
function executeRaw( transaction: Deferrable<TransactionRequest>,): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
Get the underlying account contract of the smart wallet.
The account contract of the smart wallet.
Get all the admins and session keys active on the smart wallet.
Returns the Wallet Connector used by the wallet
function getConnector(): Promise<SmartWalletConnector>;
Get the underlying account factory contract of the smart wallet.
The account factory contract.
Get the personal wallet that is connected to the Smart Wallet.
const personalWallet = wallet.getPersonalWallet();
Check whether the connected signer can execute a given transaction using the smart wallet.
function hasPermissionToExecute( Omit<TransactionResultWithMetadata<unknown>, "data"> >,): Promise<boolean>;
The transaction to execute using the smart wallet.
Omit<TransactionResultWithMetadata<unknown>, "data">>;
Check if the smart wallet contract is deployed
const isDeployed = await wallet.isDeployed();
function isDeployed(): Promise<boolean>;
Remove an admin from the smart wallet.
function removeAdmin( adminAddress: string,): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
Revoke a session key from the Smart Wallet.
await wallet.revokeSessionKey( "0x...", // the session key address);
function revokeSessionKey( keyAddress: string,): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
Send a single transaction without waiting for confirmations
function send( Omit<TransactionResultWithMetadata<unknown>, "data"> >,): Promise<TransactionResponse>;
the transaction to send
Omit<TransactionResultWithMetadata<unknown>, "data">>;
Send a multiple transaction in a batch without waiting for confirmations
function sendBatch( transactions: Array< >,): Promise<TransactionResponse>;
An array of transactions to send. 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.
let transactions: Array<>;
Send multiple raw transaction in a batch without waiting for confirmations
function sendBatchRaw( transactions: Array<Deferrable<TransactionRequest>>,): Promise<TransactionResponse>;
Send a single raw transaction without waiting for confirmations
function sendRaw( transaction: Deferrable<TransactionRequest>,): Promise<TransactionResponse>;
Verify the signature of a message. It returns true
if the signature is valid, false
otherwise
function verifySignature( message: string, signature: string, address: string, chainId: number,): Promise<boolean>;
AbstractClientWallet.addListener
event: T, fn: ( ) => void, context?: any,): this;
let fn: () => void;
AbstractClientWallet.disconnect
Disconnect the wallet
function disconnect(): Promise<void>;
AbstractClientWallet.emit
Calls each of the listeners registered for a given event.
event: T,): boolean;
AbstractClientWallet.eventNames
Return an array listing the events for which the emitter has registered listeners.
AbstractClientWallet.getAddress
Returns the account address of the connected wallet
function getAddress(): Promise<string>;
AbstractClientWallet.getBalance
Returns the balance of the connected wallet for the specified token address. If no token address is specified, it returns the balance of the native token
function getBalance( tokenAddress: string,): Promise<{ decimals: number; displayValue: string; name: string; symbol: string; value: BigNumber;}>;
AbstractClientWallet.getChainId
Returns the chain id of the network that the wallet is connected to
function getChainId(): Promise<number>;
AbstractClientWallet.getSigner
Get ethers Signer object of the connected wallet
function getSigner(): Promise<Signer>;
AbstractClientWallet.listenerCount
Return the number of listeners listening to a given event.
AbstractClientWallet.listeners
Return the listeners registered for a given event.
event: T,): Array< ( ) => void>;
let returnType: Array< ( ) => void>;
AbstractClientWallet.off
event: T, fn?: ( ) => void, context?: any, once?: boolean,): this;
let fn: () => void;
AbstractClientWallet.on
Add a listener for a given event.
event: T, fn: ( ) => void, context?: any,): this;
let fn: () => void;
AbstractClientWallet.once
Add a one-time listener for a given event.
event: T, fn: ( ) => void, context?: any,): this;
let fn: () => void;
AbstractClientWallet.removeListener
Remove the listeners of a given event.
event: T, fn?: ( ) => void, context?: any, once?: boolean,): this;
let fn: () => void;
AbstractClientWallet.signMessage
Sign a message with the connected wallet and return the signature
function signMessage(message: string | Bytes): Promise<string>;
AbstractClientWallet.switchChain
Switch to different Network/Blockchain in the connected wallet
function switchChain(chainId: number): Promise<void>;
AbstractClientWallet.transfer
Transfers some amount of tokens to the specified address
function transfer( to: string, amount: string | number, currencyAddress: string,): Promise<Omit<TransactionResultWithMetadata<unknown>, "data">>;
AbstractClientWallet.updateChains
Update the chains supported by the wallet. This is useful if wallet was initialized with some chains and this needs to be updated without re-initializing the wallet
function updateChains(chains: Array<Chain>): Promise<void>;
let walletId: string;
let prefixed: string | boolean;