- Node.js >= 23
- pnpm >= 10.8.1
Note: The project is pre-configured for Ink Sepolia testnet, but you can easily switch to other supported networks.
Check available networks inconstants/chainConfig.ts
and update the example files by changing the Network name.
# Clone the repository
git clone https://github.com/gelatodigital/how-tos-1-smartwallet-sdk-examples.git
cd how-tos-1-smartwallet-sdk-examples
# Install dependencies
pnpm install
Create your environment file:
# Create .env file manually
touch .env
Add the following variables to your .env
file:
# Your private key (optional - random key will be generated if not provided)
PRIVATE_KEY=your_private_key_here
# Sponsor API key for gasless transactions (get from https://relay.gelato.network)
SPONSOR_API_KEY=your_sponsor_api_key_here
Quick Setup: You can start with just the SPONSOR_API_KEY
for sponsored transactions, or leave PRIVATE_KEY
empty to use a generated key.
For sponsored transactions (gasless), you'll need a Sponsor API Key:
- Visit the Gelato Relay App
- Create an account and generate a Sponsor API Key for Ink Sepolia
- Add the key to your
.env
file
Need help? Check out our How to Create a Sponsor API Key Guide
For testing on Ink Sepolia:
- WETH: Convert ETH to WETH using our helper script (see ERC20 section below)
Want to see it in action? Try this simple sponsored transaction:
# Run a sponsored transaction (requires SPONSOR_API_KEY)
pnpm sponsored
This will:
- Create a smart wallet
- Send a sponsored transaction
- Show you the transaction hash
pnpm sponsored
Send transactions without paying gas fees using your Sponsor API Key.
# First, get WETH for gas payments
pnpm getWeth
# Then run ERC20 example
pnpm erc20
Pay for transactions using WETH instead of native ETH.
pnpm native
Traditional transactions using native ETH for gas fees.
pnpm estimate
Learn how to estimate gas costs before sending transactions.
# Kernel smart account with sponsorship
pnpm kernel-sponsored
# Safe smart account with sponsorship
pnpm safe-sponsored
# Custom sponsored transactions
pnpm custom-sponsored
All examples use Ink Sepolia as the target chain, configured using viem. The chain is imported directly from viem/chains
:
import { inkSepolia } from 'viem/chains'
// Use in client configuration
const client = createWalletClient({
chain: inkSepolia,
transport: http(),
})
For transactions using WETH as the payment token, you'll need to convert your ETH to WETH first. The repository includes a helper script to do this:
tsx helper/getWeth.ts
By default, this script converts 0.1 ETH to WETH. To modify the amount:
- Open
helper/getWeth.ts
- Adjust the
amount
parameter in the script - Run the script again
For transactions using USDC as the payment token:
- Check the supported networks in
constants/chainConfigs.ts
- Get test USDC from the Circle Faucet for your chosen network
- Ensure you have enough USDC in your wallet for the transaction
Note: The amount of USDC needed will depend on the gas costs and transaction requirements of your specific operation.
This example demonstrates how to send a native ETH transaction using a smart wallet:
// Create a smart wallet client
const smartWalletClient = await createSmartWalletClient({
owner: privateKeyToAccount(process.env.PRIVATE_KEY!),
chain: inkSepolia,
transport: http(),
})
// Send native ETH
const hash = await smartWalletClient.sendTransaction({
to: '0x...',
value: parseEther('0.1'),
})
Run it with:
pnpm native
This example shows how to send ERC20 tokens (WETH) using a smart wallet:
// Create a smart wallet client
const smartWalletClient = await createSmartWalletClient({
owner: privateKeyToAccount(process.env.PRIVATE_KEY!),
chain: inkSepolia,
transport: http(),
})
// Send ERC20 tokens
const hash = await smartWalletClient.writeContract({
address: WETH_ADDRESS,
abi: erc20Abi,
functionName: 'transfer',
args: ['0x...', parseEther('0.1')],
})
Run it with:
pnpm erc20
This example demonstrates how to estimate gas costs for smart wallet operations:
// Create a smart wallet client
const smartWalletClient = await createSmartWalletClient({
owner: privateKeyToAccount(process.env.PRIVATE_KEY!),
chain: inkSepolia,
transport: http(),
})
// Estimate gas for a transaction
const gasEstimate = await smartWalletClient.estimateGas({
to: '0x...',
value: parseEther('0.1'),
})
Run it with:
pnpm estimate
This example shows how to send transactions with gas sponsorship:
// Create a sponsored smart wallet client
const smartWalletClient = await createSmartWalletClient({
owner: privateKeyToAccount(process.env.PRIVATE_KEY!),
chain: inkSepolia,
transport: http(),
sponsorApiKey: process.env.SPONSOR_API_KEY,
})
// Send sponsored transaction
const hash = await smartWalletClient.sendTransaction({
to: '0x...',
value: parseEther('0.1'),
})
Run it with:
pnpm sponsored
This example demonstrates how to use Kernel smart wallets with gas sponsorship:
// Create a Kernel smart wallet client
const smartWalletClient = await createSmartWalletClient({
owner: privateKeyToAccount(process.env.PRIVATE_KEY!),
chain: inkSepolia,
transport: http(),
sponsorApiKey: process.env.SPONSOR_API_KEY,
kernelVersion: '0.3.0',
})
// Send sponsored transaction
const hash = await smartWalletClient.sendTransaction({
to: '0x...',
value: parseEther('0.1'),
})
Run it with:
pnpm kernel-sponsored
// Create wallet client
const walletClient = createWalletClient({
account: signer,
chain: inkSepolia,
transport: http(""),
})
// Create Gelato smart wallet client
const smartWalletClient = await createGelatoSmartWalletClient(walletClient, {
wallet: "kernel",
})
// Execute sponsored transaction
const results = await smartWalletClient.execute({
payment: sponsored(process.env.NEXT_PUBLIC_SPONSOR_API_KEY || ""),
calls: [
// Your transaction calls here
],
})
Here's how to set up a Kernel smart wallet client directly:
// Create wallet client
const walletClient = createWalletClient({
account,
chain: inkSepolia,
transport: http(""),
})
// Sign authorization for Kernel account
const authorization = await walletClient.signAuthorization({
account,
contractAddress: KernelVersionToAddressesMap[kernelVersion].accountImplementationAddress,
})
// Create ECDSA validator
const validator = await signerToEcdsaValidator(publicClient, {
entryPoint,
kernelVersion,
signer: account,
})
// Create Kernel account
const kernelAccount = await createKernelAccount(publicClient as any, {
address: account.address,
eip7702Auth: authorization,
entryPoint,
kernelVersion,
plugins: { sudo: validator },
})
// Create Kernel client
const kernelClient = createKernelAccountClient({
account: kernelAccount,
chain: inkSepolia,
bundlerTransport: http(process.env.NEXT_PUBLIC_GELATO_RELAY_URL || ""),
paymaster: undefined,
userOperation: {
estimateFeesPerGas: async ({ bundlerClient }: { bundlerClient: any }) => {
return getUserOperationGasPrice(bundlerClient)
},
},
})
// Send user operation
const userOpHash = await kernelClient.sendUserOperation({
callData: "0x...",
maxFeePerGas: BigInt(0),
maxPriorityFeePerGas: BigInt(0),
})
The SDK supports multiple test networks including Ink Sepolia, Arbitrum Sepolia, and Base Sepolia. The chain configurations are managed in constants/chainConfig.ts
.
To test on Arbitrum Sepolia:
- Update your
.env
file with the appropriate RPC URL:
RPC_URL=https://sepolia-rollup.arbitrum.io/rpc
- Modify your client configuration to use Arbitrum Sepolia:
import { arbitrumSepolia } from 'viem/chains'
import { chainConfig } from '../constants/chainConfig'
// Create a smart wallet client for Arbitrum Sepolia
const smartWalletClient = await createSmartWalletClient({
owner: privateKeyToAccount(process.env.PRIVATE_KEY!),
chain: arbitrumSepolia,
transport: http(process.env.RPC_URL),
})
-
Available Payment Tokens:
- Native ETH: Use for gas fees and native transactions
- WETH: Available at
chainConfig.arbitrumSepolia.tokenContract
- USDC: Available at
chainConfig.arbitrumSepolia.usdcContract
-
Example: Sending a transaction with WETH on Arbitrum Sepolia:
import { chainConfig } from '../constants/chainConfig'
const tokenAddress = chainConfig.arbitrumSepolia.tokenContract
// Send WETH transaction
const hash = await smartWalletClient.writeContract({
address: tokenAddress,
abi: erc20Abi,
functionName: 'transfer',
args: ['0x...', parseEther('0.1')],
})
- Example: Sending a sponsored transaction:
const sponsoredClient = await createSmartWalletClient({
owner: privateKeyToAccount(process.env.PRIVATE_KEY!),
chain: arbitrumSepolia,
transport: http(process.env.RPC_URL),
sponsorApiKey: process.env.SPONSOR_API_KEY,
})
const hash = await sponsoredClient.sendTransaction({
to: '0x...',
value: parseEther('0.1'),
})
Important Notes:
- Get test ETH from the Arbitrum Sepolia Faucet
- For WETH transactions, use the
getWeth.ts
helper script to convert ETH to WETH - For USDC transactions, get test USDC from the Circle Faucet
- Monitor your transactions on Arbitrum Sepolia Explorer