Giving an AI agent its own wallet: how we did it with Turnkey on Base
Autonomous Agent Wallets: Architecting Secure On-Chain Economics for Untrusted Runtimes
Current Situation Analysis
The evolution of AI agents from passive assistants to autonomous economic actors introduces a critical infrastructure gap. As agents begin to bid on tasks, purchase compute resources, and settle payments with other agents, they require the ability to hold and transfer value. However, the standard approach to blockchain wallets—generating a keypair and storing the private key—is fundamentally incompatible with agent runtimes.
Agent environments are inherently untrusted. Large Language Models (LLMs) generate code dynamically, and the execution context is vulnerable to prompt injection, dependency compromise, and data leakage. If an agent holds a raw private key, a single adversarial input can exfiltrate the key or manipulate the agent into signing a transaction that drains its funds. This security boundary is often misunderstood; developers frequently attempt to mitigate risk with simple environment variable obfuscation or client-side signing, both of which fail against a determined exploit in the agent's runtime.
The industry requires a model where agents possess economic agency without key exposure. This demands a managed signing architecture where cryptographic operations occur in isolated enclaves, and the agent interacts only through a policy-enforced relay. Furthermore, the choice of settlement layer is non-negotiable for micro-economics. High gas fees on Layer 1 networks render agent-to-agent payments economically unviable. Low-cost Layer 2 solutions with native stablecoin support are essential to ensure that transaction costs do not exceed the value of the work being performed.
WOW Moment: Key Findings
The following comparison illustrates why managed enclave signing is the only viable path for autonomous agents that require economic participation. Traditional custody models either sacrifice security or eliminate agent autonomy entirely.
| Approach | Key Exposure Risk | Agent Autonomy | Operational Complexity | Micro-Economic Viability |
|---|---|---|---|---|
| Raw Private Key | Critical | Full | Low | High |
| Server-Side Custody | None | None | High | Medium |
| Managed Enclave (Turnkey) | None | Controlled | Medium | High |
Why this matters: The Managed Enclave approach decouples economic capability from key possession. By routing all signing through a secure infrastructure provider like Turnkey, the platform guarantees that no private key material ever touches the agent's memory space. The agent retains the ability to initiate transactions, earn revenue, and pay for services, but every action is validated against strict policies before a signature is produced. This enables a closed economic loop where agents can operate as independent workers rather than cost centers.
Core Solution
The architecture relies on a relay pattern backed by Turnkey's key management infrastructure. Each agent is provisioned with a dedicated sub-organization and wallet within Turnkey. The agent authenticates via API credentials and submits transaction requests to a backend service. This service validates the request, constructs the transaction payload, and invokes Turnkey's signing API. Turnkey performs the signature within a hardware security module (HSM) enclave and returns the signed transaction, which is then broadcast to the blockchain.
Architecture Decisions
- Turnkey Sub-Organizations: Turnkey allows the creation of hierarchical organizations. A parent organization manages the platform, while sub-organizations are created per agent. This isolates agent assets and permissions, ensuring that a compromise in one agent does not affect others.
- Base as Settlement Layer: Base (Chain ID
8453) is selected for its low transaction fees and native USDC support. Gas costs on Base are typically fractions of a cent, making it feasible to settle micro-tasks. USDC provides a stable unit of account, eliminating the volatility risk associated with speculative tokens and removing the need for agents to perform token swaps. - Policy-Enforced Relay: The backend service acts as a policy engine. It verifies that the agent has sufficient balance, that the transaction targets an allowed contract, and that the function call matches an approved ABI. This prevents the agent from executing arbitrary code on-chain.
Implementation
The following TypeScript example demonstrates the relay service implementation. This code handles agent requests, interacts with Turnkey for signing, and manages the transaction lifecycle.
import { TurnkeyClient } from '@turnkey/sdk-server';
import { createPublicClient, http, encodeFunctionData } from 'viem';
import { base } from 'viem/chains';
// Configuration for Turnkey and Base
const TURNKEY_API_KEY_ID = process.env.TURNKEY_API_KEY_ID!;
const TURNKEY_API_KEY_PRIV = process.env.TURNKEY_API_KEY_PRIV!;
const BASE_RPC_URL = process.env.BASE_RPC_URL!;
// Initialize clients
const turnkeyClient = new TurnkeyClient({
apiPrivateKey: TURNKEY_API_KEY_PRIV,
apiPublicKey: TURNKEY_API_KEY_ID,
baseUrl: 'https://api.turnkey.com',
});
const baseClient = createPublicClient({
chain: base,
transport: http(BASE_RPC_URL),
});
// Agent transaction request structure
interface AgentTxRequest {
agentId: string;
targetContract: `0x${string}`;
functionName: string;
args: any[];
abi: any[];
}
// Relay service handler
async function executeAgentTransaction(request: AgentTxRequest) {
// 1. Resolve agent wallet details from database
const agentWallet = await getAgentWallet(request.agentId);
if (!agentWallet) {
throw new Error('Agent wallet not found');
}
// 2. Validate transaction against policy
await validateTransactionPolicy(agentWallet, request);
// 3. Encode function data
const data = encodeFunctionData({
abi: request.abi,
functionName: request.functionName,
args: request.args,
});
// 4. Estimate gas and prepare transaction
const gasEstimate = await baseClient.estimateGas({
to: request.targetContract,
data: data,
account: agentWallet.address,
});
const txParams = {
to: request.targetContract,
data: data,
gas: gasEstimate.toString(),
// Gas price parameters would be fetched dynamically in production
};
// 5. Request signature from Turnkey enclave
const signResult = await turnkeyClient.signTransaction({
organizationId: agentWallet.turnkeyOrgId,
walletId: agentWallet.turnkeyWalletId,
transaction: JSON.stringify(txParams),
type: 'EVMTX',
});
// 6. Broadcast signed transaction
const txHash = await baseClient.sendRawTransaction({
serializedTransaction: signResult.signedTransaction,
});
return {
success: true,
txHash,
agentId: request.agentId,
};
}
// Placeholder for policy validation logic
async function validateTransactionPolicy(wallet: any, request: AgentTxRequest) {
// Check allowed contracts
// Check function allowlists
// Verify balance
// Rate limiting checks
}
Rationale for Choices:
- Viem Integration: Using
viemfor encoding and client interactions provides a lightweight, type-safe interface for Ethereum operations. - Dynamic Gas Estimation: Gas limits are estimated on-chain before signing to prevent transaction failures due to insufficient gas.
- Policy Validation: The
validateTransactionPolicyfunction is critical. It ensures that the agent cannot request transactions to unauthorized contracts or invoke restricted functions. - Turnkey
signTransaction: This method triggers the signing process within Turnkey's secure infrastructure. The private key never leaves the enclave, and the signed transaction is returned directly to the relay service.
Pitfall Guide
Deploying agent wallets in production requires careful attention to security, reliability, and economic efficiency. The following pitfalls are common in early implementations.
Nonce Desynchronization
- Explanation: Agents often issue concurrent requests. If the relay service does not manage nonces sequentially, transactions may fail or be dropped due to nonce collisions.
- Fix: Implement a nonce manager that tracks the pending nonce for each agent wallet. Serialize transaction submissions or use a queue to ensure nonces increment correctly.
Input Injection via Calldata
- Explanation: An agent might attempt to inject malicious calldata that bypasses simple string checks.
- Fix: Strictly validate the ABI and function arguments. Use allowlists for contracts and functions. Decode the calldata on the backend and verify that the arguments match expected types and ranges.
Gas Volatility on Layer 2
- Explanation: Base gas fees can spike during network congestion. Fixed gas limits may result in failed transactions or excessive costs.
- Fix: Implement dynamic gas estimation and set maximum gas price caps. Monitor network conditions and adjust gas parameters accordingly. Use EIP-1559 fee estimation for predictable costs.
Enclave Rate Limiting
- Explanation: Turnkey and other signing providers have rate limits. High-frequency agent activity can trigger throttling.
- Fix: Implement backpressure mechanisms in the relay service. Queue requests and batch them where possible. Monitor Turnkey API usage and adjust concurrency limits.
Revert Handling and Error Propagation
- Explanation: Agents need to know why a transaction failed to adjust their behavior. Simply returning a transaction hash is insufficient.
- Fix: Decode revert reasons from failed transactions. Return structured error messages to the agent, including the function that failed and the reason. Implement retry logic for transient errors.
USDC Approval Flows
- Explanation: Agents often need to approve token spending before executing trades or payments. Forgetting to handle approvals leads to failed transactions.
- Fix: Automate approval transactions. Check token allowances before executing token transfers. Set approval limits to minimize risk.
Key Rotation Blindspots
- Explanation: If Turnkey keys are rotated or wallets are recreated, the agent's state may become stale.
- Fix: Implement event listeners for wallet changes. Update the agent's wallet reference in the database immediately after any Turnkey configuration change.
Production Bundle
Action Checklist
- Define Agent Policies: Create a comprehensive policy document specifying allowed contracts, functions, and transaction limits for each agent type.
- Provision Turnkey Sub-Organizations: Set up a parent organization and create sub-organizations for each agent. Generate API keys for the relay service.
- Implement Nonce Manager: Build a robust nonce management system to handle concurrent transaction requests without collisions.
- Deploy Policy Engine: Code the validation logic to check transaction requests against allowlists and balance requirements.
- Configure Gas Strategy: Implement dynamic gas estimation and caps tailored to Base network conditions.
- Set Up Monitoring: Configure alerts for failed transactions, rate limit breaches, and unusual spending patterns.
- Audit ABI Allowlists: Regularly review and update the list of allowed ABIs to ensure agents can only interact with trusted contracts.
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|---|---|---|
| High-Volume Micro-Tasks | Turnkey + Base | Low gas fees and secure managed signing enable profitable micro-economics. | Low per transaction; Turnkey subscription cost. |
| Enterprise Internal Agents | Self-Hosted MPC | Data sovereignty requirements may dictate on-premise key management. | High infrastructure and maintenance costs. |
| Simple Bot Automation | Server-Side Wallet | Simplicity is prioritized over agent autonomy; no need for agent-specific wallets. | Minimal; single wallet management. |
| Cross-Chain Agents | Turnkey + Multi-Chain Relay | Turnkey supports multiple chains; relay service handles chain-specific logic. | Moderate; increased complexity in relay service. |
Configuration Template
Use this template to configure the Turnkey client and Base connection for the relay service.
// turnkey.config.ts
export const turnkeyConfig = {
baseUrl: 'https://api.turnkey.com',
apiKeyId: process.env.TURNKEY_API_KEY_ID,
apiKeyPriv: process.env.TURNKEY_API_KEY_PRIV,
organizationId: process.env.TURNKEY_PARENT_ORG_ID,
};
// base.config.ts
export const baseConfig = {
chainId: 8453,
rpcUrl: process.env.BASE_RPC_URL,
usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
maxGasPrice: '1000000000', // 1 Gwei cap
};
// policy.config.ts
export const agentPolicies = {
allowedContracts: [
'0x...', // Escrow contract
'0x...', // USDC contract
],
allowedFunctions: [
'submitProof',
'transfer',
'approve',
],
maxTransactionValue: '1000000000000000000', // 1 USDC in wei
};
Quick Start Guide
- Create Turnkey Organization: Log in to the Turnkey dashboard and create a parent organization. Generate API keys for your relay service.
- Deploy Agent Wallet: Use the Turnkey API to create a sub-organization and wallet for your first agent. Record the
organizationIdandwalletId. - Integrate Relay Service: Implement the relay service using the provided code template. Configure the Turnkey client and Base connection.
- Test on Base Sepolia: Deploy your contracts to Base Sepolia and test the transaction flow. Verify that the agent can submit transactions and that the relay service enforces policies.
- Monitor and Iterate: Deploy to production and monitor transaction success rates, gas costs, and policy violations. Adjust configurations as needed.
Mid-Year Sale — Unlock Full Article
Base plan from just $4.99/mo or $49/yr
Sign in to read the full article and unlock all tutorials.
Sign In / Register — Start Free Trial7-day free trial · Cancel anytime · 30-day money-back
