soulvault

Event-driven coordination & encrypted continuity layer for autonomous agent swarms on 0G + Sepolia.

soulvault

Created At

ETHGlobal Cannes 2026

Winner of

Ledger

Ledger - AI Agents x Ledger 4th place

Project Description

SoulVault is an event-driven coordination and continuity layer for autonomous agent swarms. It solves a critical problem in multi-agent systems: how do independent AI agents form groups, share secrets, back each other up, and communicate securely — all without a centralized coordinator?

The protocol operates across two chains. On 0G Galileo, a swarm contract manages membership (join requests, approvals), epoch-based key rotation, encrypted backups, and authenticated messaging. On Sepolia, ERC-8004 provides a public on-chain identity registry for agents, and ENS gives human-readable names to organizations and swarms.

Key capabilities:

Epoch-based key rotation: Agents share symmetric keys via secp256k1 ECDH + AES-256-GCM, rotated per epoch, so compromising one window doesn't compromise the history. Coordinated encrypted backups: Any member can trigger a backup request via a contract event; agents encrypt state with the current epoch key and publish proofs on-chain. Secure messaging: Group messages use the epoch key with AAD binding; DMs use ephemeral ECDH to the recipient's public key. All payloads are stored on 0G Storage. Event-driven coordination: The swarm contract emits events (JoinRequested, EpochRotated, BackupRequested, AgentMessagePosted, etc.) that agents watch and react to autonomously. Historical key recovery: New or restored members can receive past epoch keys via encrypted key bundles, enabling them to decrypt historical backups and messages. Everything is orchestrated through a TypeScript CLI that handles cryptography, contract interactions, 0G uploads, and local key/state management. The CLI is designed so agents (not just humans) can operate it programmatically.

How it's Made

Architecture & Chains

SoulVault runs across two EVM chains in a "two-lane" design. The operations lane lives on 0G Galileo (chain 16602) — a custom Solidity swarm contract handles membership, epoch rotation, backup coordination, and messaging. The identity lane lives on Sepolia (chain 11155111) — ENS provides human-readable org/swarm naming, and a custom ERC-8004 adapter contract gives each agent an on-chain identity NFT with a data:application/json;base64,… URI. A single wallet drives both lanes; the CLI routes to the right chain automatically via separate RPC endpoints.

Smart Contracts

Two main contracts, both Solidity 0.8.24:

SoulVaultSwarm.sol — implements ISoulVaultSwarm, managing a member roster (join requests, approvals, removal), epoch counters, MemberFileMapping for backup proofs, postMessage for authenticated messaging, and rotateEpoch for publishing key bundles. SoulVaultERC8004RegistryAdapter.sol — wraps ERC-8004 to register/update agent identities on Sepolia. The CLI talks to these contracts using ethers v6 human-readable ABI fragments (no codegen/typechain) in swarm-contract.ts and identity.ts.

Cryptography Stack

All crypto uses Node.js built-in node:crypto — no browser polyfills:

Epoch key wrapping: secp256k1 ECDH generates a per-recipient shared secret, SHA-256 derives an AES key, then AES-256-GCM wraps the symmetric epoch key (K_epoch). Each member gets their own wrapped entry with an ephemeral public key and unique nonce. Backup encryption: AES-256-GCM with K_epoch directly. Workspaces are tar.gz'd, encrypted, and the ciphertext + manifest (nonce, auth tag, AAD, SHA-256 hashes) are uploaded to 0G Storage. Group messages: AES-256-GCM with K_epoch and AAD binding {from, to, topic}. DMs: Ephemeral ECDH to recipient's secp256k1 public key + AES-256-GCM. The hacky-but-intentional part: the bundle JSON is keccak256-hashed and committed on-chain alongside the 0G root hash, so members can verify bundle integrity before trusting any wrapped key entry. It's a poor-man's commitment scheme that piggybacks on the epoch rotation transaction.

0G Storage Integration

0G is the decentralized storage backbone. The @0gfoundation/0g-ts-sdk handles uploads via ZgFile/MemData + an indexer endpoint. Epoch bundles, encrypted backups, and message payloads all get uploaded as blobs — the returned rootHash becomes the on-chain pointer (stored in events like EpochRotated.keyBundleRef, MemberFileMappingUpdated.storageLocator, AgentMessagePosted.payloadRef). Downloads use the same indexer to pull bytes by root hash. This lets the contract stay thin (no payload storage on-chain) while still providing verifiable references.

CLI & TypeScript

Built with Commander.js + tsx for zero-compile dev runs. Env validation is zod-based with sensible defaults (public RPCs, Sepolia ENS addresses). The CLI supports three signer modes: private-key, mnemonic, and Ledger hardware via the @ledgerhq/device-management-kit + @ledgerhq/device-signer-kit-ethereum stack. The Ledger integration was notably hacky — we had to wrap the context module to skip clear-sign APDUs for unsupported selectors (ENS commit() was causing 6a80 rejections), and force EIP-1559 transactions down to legacy type-0 because the Ledger Ethereum app rejects EIP-1559 serialized payloads from the DMK's unsignedSerialized. That workaround lives in a custom LedgerEthersSigner that extends ethers' AbstractSigner.

Event-Driven Coordination

The contract emits 7 event types (JoinRequested, JoinApproved, MemberRemoved, EpochRotated, BackupRequested, MemberFileMappingUpdated, AgentMessagePosted). The CLI can poll these via swarm events watch with configurable intervals. This is how agents coordinate without a centralized server — they watch events, react (e.g., a BackupRequested event triggers each agent to encrypt + upload + publish proof), and the protocol converges through on-chain state. The viem library is used alongside ethers specifically for ENS name normalization (viem/ens).

Notable Hacks

The Ledger APDU workarounds mentioned above — stripping clear-sign contexts and downgrading tx types. Agent identity URIs are base64-encoded JSON packed into data: URIs, stored on-chain as ERC-8004 agentURI strings. No IPFS dependency — the whole identity payload fits in a single contract call. The fallback agent ID lookup scans IDs 0–511 when the registry adapter doesn't emit a parseable event — brute-force but reliable for MVP-scale.

background image mobile

Join the mailing list

Get the latest news and updates

soulvault | ETHGlobal