A Smart Wallet is an ERC-4337 compatible account abstraction wallet. The Smart Wallet API uses the same smart contract as the Frontend SDK. This new feature is currently in beta.
The Wallet API supports creation of SmartWallets as a backend wallet, offering features like paymaster for sponsoring gas and batch transactions.
If you are interested in using SmartWallet for your users in your frontend application, navigate to the Frontend SDK instead.
A Smart Wallet is a single address that works across EVM networks. For now, only Base Mainnet and Base Sepolia are supported. As we introduce new networks, existing SmartWallets will have the same address and be automatically supported.
A SmartWallet has a single owner, which is the account backed by a private key that signs transactions for the wallet. Think of a private key as the password to a wallet. For more, see What is a private key?.
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";import { createSmartWallet } from "@coinbase/coinbase-sdk";import { Coinbase } from "@coinbase/coinbase-sdk";// This key must be stored securely and persisted across sessions! See Securing a Smart Wallet below for more information.const privateKey = generatePrivateKey();const owner = privateKeyToAccount(privateKey);const smartWallet = await createSmartWallet({ signer: owner});// Get the smart wallet addressconst smartWalletAddress = smartWallet.address;
We recommend using Viem to create the private key and owner account of the SmartWallet.
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";import { createSmartWallet } from "@coinbase/coinbase-sdk";import { Coinbase } from "@coinbase/coinbase-sdk";// This key must be stored securely and persisted across sessions! See Securing a Smart Wallet below for more information.const privateKey = generatePrivateKey();const owner = privateKeyToAccount(privateKey);const smartWallet = await createSmartWallet({ signer: owner});// Get the smart wallet addressconst smartWalletAddress = smartWallet.address;
We recommend using eth-account to create the private key and owner account of the SmartWallet.
from eth_account import Accountfrom cdp import *# This key must be stored securely and persisted across sessions! See Securing a Smart Wallet below for more information.private_key = Account.create().keyowner = Account.from_key(private_key)smart_wallet = SmartWallet.create(account=owner)# Get the smart wallet addresssmart_wallet_address = smart_wallet.address
A UserOperation is used to execute transactions through a Smart Wallet, using account abstraction to enable features like batch transactions and sponsored gas fees without needing a traditional EOA wallet.
sendUserOperation is how you send operations for the SmartWallet. It supports batch transactions and paymaster for sponsoring.
You can either provide an ABI and the function to call, or the encoded function data. The next example demonstrates a batch transaction that
sends ETH to a destination address and calls a function on a contract.
Copy
Ask AI
const smartWallet = await createSmartWallet({ signer: owner});const ABI = [ { inputs: [ { internalType: "uint256", name: "a", type: "uint256" }, { internalType: "bool", name: "b", type: "bool" }, { internalType: "address", name: "c", type: "address" }, ], name: "someFunction", outputs: [], stateMutability: "nonpayable", type: "function", },] as const; // This "as const" is very important!const userOperation = await smartWallet.sendUserOperation({ calls: [ { to: "0x1234567890123456789012345678901234567890", value: parseEther("0.0000005"), data: "0x", }, { to: "0xb720E683CB90838F23F66a37Adb26c24e04D1b60", abi: ABI, functionName: "someFunction", args: [123n, true, "0x3234567890123456789012345678901234567890"], }, ], chainId: 84532,});const userOperationResult = await waitForUserOperation(userOperation);// You can now use the result to see the status and get the transactionHash if it was successful.
For ABIs, make sure to include as const as this is needed by Typescript for proper compilation.
sendUserOperation is how you send operations for the SmartWallet. It supports batch transactions and paymaster for sponsoring.
You can either provide an ABI and the function to call, or the encoded function data. The next example demonstrates a batch transaction that
sends ETH to a destination address and calls a function on a contract.
Copy
Ask AI
const smartWallet = await createSmartWallet({ signer: owner});const ABI = [ { inputs: [ { internalType: "uint256", name: "a", type: "uint256" }, { internalType: "bool", name: "b", type: "bool" }, { internalType: "address", name: "c", type: "address" }, ], name: "someFunction", outputs: [], stateMutability: "nonpayable", type: "function", },] as const; // This "as const" is very important!const userOperation = await smartWallet.sendUserOperation({ calls: [ { to: "0x1234567890123456789012345678901234567890", value: parseEther("0.0000005"), data: "0x", }, { to: "0xb720E683CB90838F23F66a37Adb26c24e04D1b60", abi: ABI, functionName: "someFunction", args: [123n, true, "0x3234567890123456789012345678901234567890"], }, ], chainId: 84532,});const userOperationResult = await waitForUserOperation(userOperation);// You can now use the result to see the status and get the transactionHash if it was successful.
For ABIs, make sure to include as const as this is needed by Typescript for proper compilation.
send_user_operation is how you send operations for the SmartWallet. It supports batch transactions and paymaster for sponsoring.
You can either provide an ABI and the function to call, or the encoded function data. The next example demonstrates a batch transaction that
sends ETH to a destination address and calls a function on a contract.
Copy
Ask AI
smart_wallet = SmartWallet.create(account=owner)ABI = [ { "inputs": [ {"internalType": "uint256", "name": "a", "type": "uint256"}, {"internalType": "bool", "name": "b", "type": "bool"}, {"internalType": "address", "name": "c", "type": "address"}, ], "name": "someFunction", "outputs": [], "stateMutability": "nonpayable", "type": "function", },]value = Web3.to_wei(Decimal("0.0000005"), "ether")user_operation = smart_wallet.send_user_operation( calls=[ FunctionCall( to="0xb720E683CB90838F23F66a37Adb26c24e04D1b60", abi=ABI, function_name="someFunction", args=[123, True, "0x3234567890123456789012345678901234567890"], ), EncodedCall(to="0x1234567890123456789012345678901234567890", data="0x", value=value), ], chain_id=84532,)user_operation.wait(interval_seconds=0.2, timeout_seconds=20)# You can now check the status of the operation and get the transaction hash if it was successful.
For Base Sepolia, the CDP API automatically sponsors gas for the SmartWallet, so you don’t need any gas to send user operations! For Base Mainnet, you can pass in a Paymaster URL to the sendUserOperation function to sponsor the gas for the operation.
Check out the Paymaster docs for more information and getting started with your own Paymaster.
The private key for the owner account must be securely stored. It is your responsibility as the developer to securely store this key. For example, you may choose to store this data in an encrypted database.
Secure your Private Key
Losing the private key for the owner of the SmartWallet could result in a loss of funds. Please take all necessary precautions to secure this key.