How to Build an Agent Wallet

Joan Alavedra9 min read
How to Build an Agent Wallet

TLDR: Prompt an AI with this guide. Copy the prompt below into Claude, ChatGPT, or any LLM along with your Openfort credentials. It will scaffold the entire project for you.


_10
Prompt: Using sk_test_XXXX (API secret key) and WALLET_SECRET_HERE (wallet secret)
_10
from Openfort, follow the guide in openfort-backend-wallet-usdc-guide.md to create
_10
a TypeScript project that:
_10
_10
1. Creates a backend wallet
_10
2. Upgrades it to an EIP-7702 delegated account
_10
3. Sets up dynamic fee sponsorship to pay gas in USDC
_10
4. Sends a USDC transfer on Base Sepolia with gas paid in USDC
_10
_10
Create the project in TypeScript.

Replace sk_test_XXXX with your API secret key and WALLET_SECRET_HERE with your wallet secret from the Openfort Dashboard.

Agent wallets are server-side wallets that execute blockchain transactions autonomously. They power automated trading, scheduled payments, AI-driven commerce, and any workflow where a backend needs to sign and submit transactions without human intervention.

This guide walks through building one from scratch using Openfort backend wallets. By the end, you'll have a TypeScript project that creates a wallet, upgrades it with EIP-7702 delegation, configures USDC gas sponsorship, and sends a USDC transfer on Base Sepolia — with gas paid in USDC.

Prerequisites

You need two things from the Openfort Dashboard:

  • API Secret Key (sk_test_...): Found in your project settings
  • Wallet Secret: Generated when you enable backend wallets

You also need Node.js 18+ and a package manager (npm, pnpm, or yarn).

Project Setup

Initialize a TypeScript project and install the Openfort Node SDK:


_10
mkdir agent-wallet && cd agent-wallet
_10
npm init -y
_10
npm install @openfort/openfort-node dotenv
_10
npm install -D typescript tsx @types/node
_10
npx tsc --init

Create a .env file with your credentials:


_10
OPENFORT_API_KEY=sk_test_XXXX
_10
OPENFORT_WALLET_SECRET=WALLET_SECRET_HERE
_10
CHAIN_ID=84532

Step 1: Create a Backend Wallet

Backend wallets are EOAs managed by Openfort's TEE infrastructure. Keys are generated and stored inside a secure enclave — they never leave it. Signing latency is under 125ms.


_15
import Openfort from "@openfort/openfort-node";
_15
import "dotenv/config";
_15
_15
const openfort = new Openfort(process.env.OPENFORT_API_KEY!, {
_15
walletSecret: process.env.OPENFORT_WALLET_SECRET,
_15
});
_15
_15
async function createWallet() {
_15
const account = await openfort.accounts.evm.backend.create();
_15
console.log("Account ID:", account.id);
_15
console.log("Address:", account.address);
_15
return account;
_15
}
_15
_15
const wallet = await createWallet();

This creates a new EOA with a private key secured in a TEE. The account.id is your Openfort identifier for this wallet, and account.address is the standard Ethereum address you'll use onchain.

You can also import an existing wallet if you have one:


_10
const imported = await openfort.accounts.evm.backend.import({
_10
privateKey: "0x...",
_10
name: "MyExistingWallet",
_10
});

Step 2: Upgrade to an EIP-7702 Delegated Account

EIP-7702 lets an EOA temporarily delegate its execution to a smart contract implementation. Your backend wallet stays an EOA — it doesn't deploy a new contract — but it can borrow smart account capabilities: gas sponsorship, transaction batching, session keys, and more.

The delegation works by adding an authorization_list to a new transaction type (0x04). At the bytecode level, the EOA gets a special prefix (0xef0100) followed by the implementation contract address, creating a delegatecall proxy.

To upgrade your backend wallet, create a transaction intent with EIP-7702 delegation enabled:


_16
async function upgradeToSmartAccount(accountId: string) {
_16
const chainId = Number(process.env.CHAIN_ID);
_16
_16
// Create a transaction intent with 7702 delegation
_16
const transactionIntent = await openfort.transactionIntents.create({
_16
chainId,
_16
account: accountId,
_16
optimistic: false,
_16
// The 7702 delegation is handled by Openfort's infrastructure
_16
// when the account is used with a policy that supports it
_16
interactions: [],
_16
});
_16
_16
console.log("Delegation TX:", transactionIntent.id);
_16
return transactionIntent;
_16
}

Once delegated, your EOA can be used with ERC-4337 UserOperations. The bundler packages operations and sends them to the EntryPoint contract, which calls your upgraded EOA for validation and execution.

The key benefit: your agent wallet address stays the same. Any tokens, NFTs, or contract approvals at that address remain intact. You're adding capabilities, not migrating.

Step 3: Set Up Dynamic Fee Sponsorship (Pay Gas in USDC)

By default, transactions on EVM chains require the native token (ETH on Base) for gas. With Openfort's PaymasterV3, you can pay gas in USDC instead. This is critical for agent wallets — your agents hold USDC for transactions, so they should pay gas in USDC too. No need to manage ETH balances separately.

Openfort supports three sponsorship strategies:

StrategyDescription
pay_for_userFull gas sponsorship — you cover everything
charge_custom_tokensDynamic rate using a live oracle for ERC-20 conversion
fixed_rateFixed amount of ERC-20 per transaction

For agent wallets, charge_custom_tokens is the right choice. It uses a live exchange rate so you're always paying the correct amount in USDC.

Register the USDC Contract

First, register the USDC token contract with Openfort:


_10
const chainId = Number(process.env.CHAIN_ID); // 84532 for Base Sepolia
_10
_10
const usdcContract = await openfort.contracts.create({
_10
name: "USDC on Base Sepolia",
_10
chainId,
_10
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // USDC on Base Sepolia
_10
});
_10
_10
console.log("USDC Contract ID:", usdcContract.id);

Create a Dynamic Fee Policy

Create a policy that charges gas fees in USDC at the current market rate:


_11
const policy = await openfort.policies.create({
_11
name: "USDC Dynamic Gas Policy",
_11
chainId,
_11
strategy: {
_11
sponsorSchema: "charge_custom_tokens",
_11
tokenContract: usdcContract.id,
_11
tokenContractAmount: "0", // "0" = dynamic/oracle rate
_11
},
_11
});
_11
_11
console.log("Policy ID:", policy.id);

Setting tokenContractAmount to "0" tells Openfort to use the live exchange rate. The paymaster calculates gas cost in ETH, converts it to USDC using the current rate, and deducts that amount from the sender's USDC balance.

Add Policy Rules

Define which contract functions the policy applies to:


_10
await openfort.policyRules.create({
_10
policy: policy.id,
_10
type: "contract_functions",
_10
contract: usdcContract.id,
_10
functionName: "transfer",
_10
});

Fund the Paymaster

Before the paymaster can sponsor transactions, it needs native token deposits. Deposit ETH to the Openfort Paymaster contract on Base Sepolia using the depositFor function. You can find the paymaster address in the Openfort Dashboard under entity addresses.

Step 4: Send a USDC Transfer with Gas Paid in USDC

Now bring it all together. Send a USDC transfer where the gas fee is automatically deducted in USDC:


_27
async function sendUSDCTransfer(
_27
accountId: string,
_27
policyId: string,
_27
usdcContractId: string,
_27
recipient: string,
_27
amount: string // in USDC base units (6 decimals). "1000000" = 1 USDC
_27
) {
_27
const chainId = Number(process.env.CHAIN_ID);
_27
_27
const transactionIntent = await openfort.transactionIntents.create({
_27
chainId,
_27
account: accountId,
_27
policy: policyId,
_27
optimistic: false,
_27
interactions: [
_27
{
_27
contract: usdcContractId,
_27
functionName: "transfer",
_27
functionArgs: [recipient, amount],
_27
},
_27
],
_27
});
_27
_27
console.log("Transaction Intent ID:", transactionIntent.id);
_27
console.log("Status:", transactionIntent.response?.status);
_27
return transactionIntent;
_27
}

Call the function to send 1 USDC:


_10
const tx = await sendUSDCTransfer(
_10
wallet.id, // from Step 1
_10
policy.id, // from Step 3
_10
usdcContract.id, // from Step 3
_10
"0xRECIPIENT_ADDRESS",
_10
"1000000" // 1 USDC (6 decimals)
_10
);

The transaction flow:

  1. Openfort constructs a UserOperation with the USDC transfer calldata
  2. The paymaster calculates gas cost and converts it to USDC at the current rate
  3. The bundler submits the operation to the EntryPoint
  4. The EntryPoint validates the operation through your EIP-7702 delegated account
  5. The USDC transfer executes, and the gas fee is deducted from your USDC balance

No ETH needed. The agent wallet only needs USDC.

Putting It All Together

Here's the complete flow in a single script:


_65
import Openfort from "@openfort/openfort-node";
_65
import "dotenv/config";
_65
_65
const openfort = new Openfort(process.env.OPENFORT_API_KEY!, {
_65
walletSecret: process.env.OPENFORT_WALLET_SECRET,
_65
});
_65
_65
const chainId = Number(process.env.CHAIN_ID); // 84532
_65
_65
async function main() {
_65
// 1. Create a backend wallet
_65
console.log("Creating backend wallet...");
_65
const account = await openfort.accounts.evm.backend.create();
_65
console.log(`Wallet: ${account.address}`);
_65
_65
// 2. Register USDC contract
_65
console.log("Registering USDC contract...");
_65
const usdcContract = await openfort.contracts.create({
_65
name: "USDC on Base Sepolia",
_65
chainId,
_65
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
_65
});
_65
_65
// 3. Create dynamic fee sponsorship policy
_65
console.log("Creating USDC gas policy...");
_65
const policy = await openfort.policies.create({
_65
name: "USDC Dynamic Gas Policy",
_65
chainId,
_65
strategy: {
_65
sponsorSchema: "charge_custom_tokens",
_65
tokenContract: usdcContract.id,
_65
tokenContractAmount: "0",
_65
},
_65
});
_65
_65
// 4. Add policy rules
_65
await openfort.policyRules.create({
_65
policy: policy.id,
_65
type: "contract_functions",
_65
contract: usdcContract.id,
_65
functionName: "transfer",
_65
});
_65
_65
// 5. Fund your wallet with test USDC
_65
// Visit https://faucet.circle.com/ to get Base Sepolia USDC
_65
console.log(`Fund ${account.address} with test USDC from https://faucet.circle.com/`);
_65
console.log("Then run the transfer...");
_65
_65
// 6. Send USDC transfer with gas paid in USDC
_65
// Uncomment after funding:
_65
// const tx = await openfort.transactionIntents.create({
_65
// chainId,
_65
// account: account.id,
_65
// policy: policy.id,
_65
// optimistic: false,
_65
// interactions: [{
_65
// contract: usdcContract.id,
_65
// functionName: "transfer",
_65
// functionArgs: ["0xRECIPIENT_ADDRESS", "1000000"],
_65
// }],
_65
// });
_65
// console.log("Transaction:", tx.id);
_65
}
_65
_65
main().catch(console.error);

Run it with:


_10
npx tsx main.ts

What You Can Build With This

Agent wallets are the building block for autonomous onchain systems:

  • AI-powered trading agents that execute strategies without manual approval
  • Automated payment processing — payroll, subscriptions, disbursements
  • DCA (Dollar-Cost Averaging) bots that buy tokens on a schedule
  • Cross-border remittance systems that convert and send stablecoins
  • Backend services that interact with smart contracts as part of your application logic

Combine this with wallet permissions to let users grant agents scoped access to their accounts, or with programmable wallet controls to enforce spending limits and contract allowlists at the infrastructure level.

Key References

ResourceLink
Openfort Node SDKgithub.com/openfort-xyz/openfort-node
Backend Wallets Docsopenfort.io/docs/products/server/wallet
Gas Sponsorship Docsopenfort.io/docs/configuration/gas-sponsorship
EIP-7702 Deep Diveopenfort.io/blog/eip-7702-with-erc-4337
Recipes Hubgithub.com/openfort-xyz/recipes-hub
USDC Faucet (Base Sepolia)faucet.circle.com

Agent wallets turn your backend into a first-class blockchain participant. TEE-secured keys, EIP-7702 smart account powers, and USDC gas sponsorship — everything an autonomous agent needs to transact onchain without managing ETH balances or exposing private keys.

Ready to build? Get your API keys from the Openfort Dashboard and start with the code above, or explore the recipes hub for more complete examples.

Share this article

Keep Reading