wallets
Wallets on Ethereum
What You Probably Got Wrong
EIP-7702 is live. Since Pectra (May 7, 2025), regular EOAs can delegate execution to smart-contract code without migrating wallets. This enables batching, gas sponsorship, and session-key-style UX. This is NOT "coming soon." It shipped.
Account abstraction status: ERC-4337 is growing but still early (Feb 2026). Major implementations: Kernel (ZeroDev), Biconomy, Alchemy Account Kit, Pimlico. EntryPoint v0.7: 0x0000000071727De22E5E9d8BAf0edAc6f37da032.
Safe secures $60B+ in assets (and has processed $1.4T+ in total value). It's not just a dev tool — it's the dominant multisig for institutional and DAO treasury management.
EIP-7702: Smart EOAs (Live Since May 2025)
EOAs can authorize delegated code execution from smart-contract code. This is not automatically "one and done" - the delegation can stay active until it is replaced or explicitly cleared.
How it works:
- The wallet signs a message that says which contract code the EOA can use.
- A special EIP-7702 transaction submits that signed message.
- The EOA can then run that contract logic (batching, sponsorship, permissions) as if it were account logic.
- This is not automatically "one and done" - the delegation can stay active until it is replaced or explicitly cleared.
- If the transaction later fails, the delegation update itself can still remain.
What this enables:
- Batch 10 token approvals into one transaction
- Gas sponsorship / meta-transactions for EOA users
- Session keys with limited permissions
- Custom authorization logic
- Eliminates "approval fatigue" (approve + execute → one step)
Status (Feb 2026): Deployed on mainnet. MetaMask, Rainbow adding support. Still early for production agents — use standard EOAs or Safe until tooling matures.
Safe (Gnosis Safe) Multisig
Key Addresses (v1.4.1, deterministic across chains)
| Contract | Address |
|---|---|
| Safe Singleton | 0x41675C099F32341bf84BFc5382aF534df5C7461a |
| Safe Proxy Factory | 0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67 |
| MultiSend | 0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526 |
Same addresses on Mainnet, Arbitrum, Base, and all major chains.
Safe for AI Agents
Pattern: 1-of-2 Safe
- Owner 1: Agent's wallet (hot, automated)
- Owner 2: Human's wallet (cold, recovery)
- Threshold: 1 (agent can act alone)
Benefits: If agent key is compromised, human removes it. Human can always recover funds. Agent can batch transactions.
🚨 NEVER COMMIT SECRETS TO GIT
This is the #1 way AI agents lose funds and leak credentials. Bots scrape GitHub in real-time and exploit leaked secrets within seconds — even from private repos, even if deleted immediately. A secret committed to Git is compromised forever.
This happens constantly with AI coding agents. The agent generates a deploy script, hardcodes a key, runs git add ., and the wallet is drained before the next prompt. Or the agent pastes an Alchemy API key into scaffold.config.ts and it ends up in a public repo.
This applies to ALL secrets:
- Wallet private keys — funds drained instantly
- API keys — Alchemy, Infura, Etherscan, WalletConnect
- RPC URLs with embedded keys —
https://base-mainnet.g.alchemy.com/v2/YOUR_KEY - OAuth tokens, bearer tokens, passwords
Prevention
# .gitignore (MUST exist in every project)
.env
.env.*
*.key
*.pem
broadcast/
cache/
# Verify before every commit
git diff --cached --name-only | grep -iE '\.env|key|secret|private'
# If this matches ANYTHING, stop and fix it
# Nuclear option: scan entire repo history
git log --all -p | grep -iE 'private.?key|0x[a-fA-F0-9]{64}'
If You Already Committed a Key
- Assume it's compromised. Don't hope nobody saw it.
- Transfer all funds immediately to a new wallet.
- Rotate the key. Generate a new one. The old one is burned forever.
- Clean Git history with
git filter-repoor BFG Repo Cleaner — but this is damage control, not prevention. The key is already compromised. - Revoke any token approvals from the compromised address.
Safe Patterns for AI Agents
# Load key from environment (NEVER hardcode)
cast send ... --private-key $DEPLOYER_PRIVATE_KEY
# Or use encrypted keystore
cast send ... --keystore ~/.foundry/keystores/deployer --password-file .password
# Or use hardware wallet
cast send ... --ledger
Rule of thumb: If grep -r "0x[a-fA-F0-9]{64}" . matches anything in your source code, you have a problem. Same for grep -r "g.alchemy.com/v2/[A-Za-z0-9]" or any RPC URL with an embedded API key.
CRITICAL Guardrails for AI Agents
Key Safety Rules
- NEVER extract a private key from any wallet without explicit human permission.
- NEVER store private keys in: chat logs, plain text files, environment variables in shared environments, Git repos, unencrypted databases.
- NEVER move funds without human confirmation. Show: amount, destination (checksummed), gas cost, what it does. Wait for explicit "yes."
- Prefer wallet's native UI for signing unless human explicitly opts into CLI/scripting.
- Use a dedicated wallet with limited funds for agent operations. Never the human's main wallet.
- Double-check addresses. Use
ethers.getAddress()or equivalent for checksum validation. A single wrong character = permanent loss. - Test on testnet first. Or use local Anvil fork.
- Implement spending limits. Require human approval above threshold. Use Safe multisig for high-value operations.
- Log all transactions (never keys). Keep audit trail.
- Assume keys will be compromised. Design so a compromised agent key doesn't mean total loss.
Storage Options (Worst to Best)
❌ Plain text in code/logs — NEVER
❌ Environment variables in shared environments — NEVER
❌ Committed to Git — NEVER
⚠️ Local .env file — testing only
✅ Encrypted keystore (password-protected)
✅ Hardware wallet / Cloud KMS / TEE
Safe Transaction Pattern
async function sendSafely(wallet, to, value) {
const checksummedTo = ethers.getAddress(to); // validates
const gasEstimate = await wallet.estimateGas({ to: checksummedTo, value });
const feeData = await wallet.provider.getFeeData();
const gasCost = gasEstimate * feeData.maxFeePerGas;
const totalCostUSD = Number(ethers.formatEther(value + gasCost)) * 2000; // ⚠️ Use a Chainlink feed for real price
if (totalCostUSD > 10) {
// Show details and wait for human approval
}
const tx = await wallet.sendTransaction({
to: checksummedTo,
value,
gasLimit: gasEstimate * 120n / 100n, // 20% buffer
maxFeePerGas: feeData.maxFeePerGas,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
});
const receipt = await tx.wait();
logTransaction({ hash: tx.hash, to: checksummedTo, value, block: receipt.blockNumber });
return receipt;
}
Further Reading
- Safe docs: https://docs.safe.global/
- EIP-7702 spec: https://eips.ethereum.org/EIPS/eip-7702
- ERC-4337 spec: https://eips.ethereum.org/EIPS/eip-4337