Wallet-Scoped Sessions: The Identity Primitive Autonomous EVM Agents Are Missing
Most autonomous agent frameworks are still stateless. They spin up, do a thing, and die. The moment the process restarts — or the user reconnects a wallet — the agent forgets who it was acting as. For any agent that moves real value, that amnesia is not a minor inconvenience. It's a trust boundary that has never actually been defined.
The fix is not "add a database." It's a specific architectural primitive: the wallet-scoped session. And once you build it correctly, a lot of downstream problems — reconnects, interrupted withdrawals, multi-chain routing — become trivial.
The problem with stateless agents
Take the canonical "autonomous trading bot" you see in tutorials. The happy path looks like this:
- Read a wallet private key from an env var.
- Connect to an RPC.
- Approve a token, swap, log the tx hash.
- Exit.
The moment anything goes wrong — a restart, a dropped WebSocket, a user disconnecting their wallet — the agent has no memory of the transaction it was in the middle of. Worse, it has no stable identity to rebuild from.
Three concrete failure modes follow:
-
Interrupted withdrawal. A
withdrawcall that got broadcast but never confirmed is now orphaned. The agent doesn't know whether the transfer landed, whether to retry, or whether to stop entirely. - Broken identity. An agent that "becomes" a different wallet on restart is a security incident, not a feature. If your agent can silently switch signers, nothing it did before is trustworthy.
- No continuity. Users reconnect a wallet expecting to resume the session they had. They get a blank slate instead.
These are not solved by better prompts. They're solved by modeling sessions correctly.
The core primitive: bind the session to a signer, not to a process
A wallet-scoped session is a state object keyed by a verified signer address, not by a running process. The invariant is simple:
A session's identity is derived from the wallet that authenticated it, and that binding survives process restarts and reconnects.
Conceptually:
Session {
signer: 0x... // the verified wallet address
chainId: int // the chain this session is scoped to
state: Active | Paused | Standby
pendingOps: [] // in-flight withdrawals / transfers
continuity: TransferContinuity
}
The key insight is that signer is discovered through an authentication channel, not pasted in as a config value. A wallet proves it controls an address by signing a session nonce. From that point on, the agent treats signer as the single source of truth for "who is operating."
The wallet auth channel
This is the part almost everyone skips. Connecting a wallet is not just "read the address." It's an authentication handshake:
1. Agent generates a session nonce.
2. Wallet signs the nonce → proof the user controls the address.
3. Agent derives the session key from (address, nonce, chainId).
4. Agent persists the binding. The process can now die safely.
On reconnect, you don't re-ask "who are you?" — you verify the signer against the stored binding and resume the same session. The identity is stable even though the process is not.
This is why "Connect Wallet" in a well-designed agent surface should do more than hydrate a balance. It should establish a wallet-scoped identity that outlives the connection.
Transfer continuity: the part that actually matters
Once you have a stable session, you can make transfers safe to interrupt. The naive agent fires a transaction and forgets it. A session-aware agent records the intent before broadcasting, then reconciles after.
A minimal Solidity sketch of the reconciliation loop an agent runs on resume:
// The agent, on session resume, resolves every pending op against on-chain truth.
function reconcile(bytes32 opId) external view returns (OpStatus) {
PendingOp memory op = pendingOps[opId];
if (op.broadcasted && !op.confirmed) {
// Query receipt; decide retry vs. abort based on the session's policy.
return _receiptExists(op.txHash) ? OpStatus.Confirmed : OpStatus.Pending;
}
return op.confirmed ? OpStatus.Confirmed : OpStatus.Pending;
}
The point isn't the exact code — it's the policy layer it represents. An agent with transfer continuity knows, after a crash, whether a withdrawal already left the wallet. That single fact is the difference between "the money is safe" and "we double-spent."
Off-chain, you model this as a small state machine:
PENDING → BROADCAST → CONFIRMED
↘ FAILED → (retry | abort)
Each transition is persisted under the session key. Reconnect → replay the state machine → you're back exactly where you left off. No orphans.
Why scoping matters across chains
A wallet is not a chain. The same signer can act on Ethereum, Arbitrum, Base, OP, ZKsync, and Linea. If your session is keyed only by address, you collapse all of those into one ambiguous blob.
Wallet-scoped sessions solve this by making the scope explicit: (signer, chainId). Balance hydration, network switching, and withdrawal rails all become session-scoped controls rather than global state. The agent knows which chain it's operating on, and the user sees a control surface that reflects exactly that.
This also means chain routing becomes a session decision, not a hardcoded one. The same agent, same signer, different chainId, different behavior — without losing identity.
What you get for free once sessions are real
- Reconnects that resume instead of restart. Users pick up where they left off.
- Safe withdrawals. Interrupted transfers reconcile against on-chain truth, never double-spend.
- Auditable identity. Everything an agent did is attributable to a verified signer, which is the minimum bar for anything touching real funds.
- Multi-chain without chaos. One identity, N scopes, zero ambiguity.
Most agent frameworks skip this and pay for it in production. The teams that get autonomous agents to actually hold value all converge on the same pattern: make the session a first-class object, bind it to a signer, and treat continuity as a feature rather than an afterthought.
If you'd rather use a live implementation than build this yourself: BBIO (Blockchain Behavioral Intelligence Operator) runs a wallet-scoped session model in production — wallet binding, live session control, and transfer continuity across 10 EVM networks (Ethereum, Arbitrum One, Base, OP Mainnet, ZKsync Era, Linea, and more). It's in free beta right now. Connect a wallet and watch how the identity primitive is supposed to feel.
Top comments (0)