{"slug": "erc-8350-an-on-chain-standard-for-verifiable-ai-memory-state", "title": "ERC-8350: an on-chain standard for verifiable AI memory state", "summary": "A new Ethereum standard, ERC-8350, defines a minimal on-chain registry interface for committing authorized state transitions of autonomous-agent memory without placing raw memory in calldata. Each transition is represented by an ExperienceDelta identified by an EIP-712 struct hash and applied to a linear per-space state machine, with a Memory Space identifier derived as keccak256 of the MemorySpace type hash, initialController, and a bytes32 salt. The proposal keeps payload semantics, storage, memory taxonomies, inference proofs, deletion attestations, and markets outside the core interface, making declared agent memory history tamper-evident and attributable without proving the agent actually used the committed memory.", "body_md": "This ERC defines a minimal registry interface for committing authorized state\ntransitions of autonomous-agent memory without placing raw memory in calldata.\nEach transition is represented by an ExperienceDelta, identified by an\nEIP-712 struct hash, and applied to a linear per-space state\nmachine. A memory space has a controller and a replaceable authorizer. Both\nexternally owned accounts and ERC-1271 contract accounts are\nsupported. Payload semantics, storage, memory taxonomies, inference proofs,\ndeletion attestations, and markets are intentionally outside the core interface.\n\nMotivation\n\nAgent systems commonly keep long-lived memory in private databases while using\nEthereum for identity, payment, or execution. Existing applications can publish\nan opaque content hash, but a hash alone does not establish:\n\nwhich state it advances;\n\nwhether the transition is the unique successor of the current state;\n\nwho controls the namespace and who may authorize updates;\n\nwhether all externally meaningful references were signed; or\n\nwhether independent implementations derive the same transition identifier.\n\nPublishing raw prompts, embeddings, preferences, policies, or latent state is\nincompatible with privacy and is often uneconomical. This ERC therefore commits\nonly to a private delta, optional provenance, an interpretation profile, and an\noptional private locator. The registry verifies authorization and state-machine\ncontinuity while remaining agnostic to the underlying memory engine.\n\nAgent operators, wallet and application developers, auditors, and counterparties\nneed a shared way to refer to an agent’s memory history across implementations\nwithout disclosing the memory itself. They can verify that a declared state\nadvanced through an authorized, gapless sequence while prompts, embeddings,\npolicies, and other private witness data remain off-chain.\n\nExample uses include carrying a continuity checkpoint when an agent moves between\nproviders, selectively opening evidence to an auditor against a committed\ntransition, and detecting rollback or substitution relative to a known on-chain\nhead. This ERC does not prove that an agent actually used the committed memory,\nthat the private witness is true or available, or that an agent’s decisions were\ncorrect. It makes the declared state history tamper-evident and attributable.\n\nSpecification\n\nThe key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”,\n“SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this\ndocument are to be interpreted as described in\nRFC 2119 and\nRFC 8174.\n\nDefinitions\n\nMemory Space: a namespace with one linear state history.\n\nController: the account authorized to replace the controller or authorizer.\n\nAuthorizer: the account authorized to approve state transitions.\n\nExperience Delta: the fixed-width transition claim defined below.\n\nPrivate witness: off-chain data required to open a commitment, including\npayloads, salts, encryption metadata, and locators.\n\nTransition ID: the EIP-712 hashStruct of an Experience Delta.\n\nState root: the accumulator produced from the previous state root and the\naccepted Transition ID.\n\nMemory Space identifier\n\nThe initial controller MUST choose a bytes32 salt. The Memory Space identifier\nMUST be derived as:\n\n```\nMEMORY_SPACE_TYPE =\n  \"MemorySpace(address initialController,bytes32 salt)\"\n\nspaceId = keccak256(abi.encode(\n  keccak256(bytes(MEMORY_SPACE_TYPE)),\n  initialController,\n  salt\n))\n```\n\ninitialController MUST NOT be the zero address. This derivation prevents an\nunrelated account from pre-registering an identifier selected by another\ncontroller. The salt MAY remain private until registration.\n\nExperience Delta v1\n\nv1 names the wire format fixed by the ExperienceDelta and MemoryState\ntype strings, the EIP-712 signing-domain version, and the baseline commitment\ndomain tags defined below. Changing any of these values changes transition\nidentifiers, state roots, signing digests, or baseline commitments and is\ntherefore not wire-compatible with v1.\n\nThe following struct and field order are normative:\n\n```\nstruct ExperienceDelta {\n    bytes32 spaceId;\n    uint64 sequence;\n    bytes32 prevStateRoot;\n    bytes32 deltaCommitment;\n    bytes32 provenanceCommitment;\n    bytes32 profileId;\n    bytes32 locatorCommitment;\n}\n```\n\nThe fields have these meanings:\n\nspaceId identifies the Memory Space.\n\nsequence is a strictly increasing counter beginning at 1.\n\nprevStateRoot is the current state root before this transition and is zero\nfor the first transition.\n\ndeltaCommitment binds the private memory operation or encrypted delta and\nMUST NOT be zero.\n\nprovenanceCommitment optionally binds inputs, inference attestations, or\nother causal material. Zero means absent.\n\nprofileId identifies the off-chain interpretation and commitment profile and\nMUST NOT be zero.\n\nlocatorCommitment optionally binds a private off-chain locator. Zero means\nabsent. A raw locator is not part of this interface.\n\nRaw memory, salts, encryption keys, and raw locators MUST NOT be supplied to the\nregistry through this struct or any other required core argument.\n\nTransition ID\n\nThe exact EIP-712 type string is:\n\n```\nExperienceDelta(bytes32 spaceId,uint64 sequence,bytes32 prevStateRoot,bytes32 deltaCommitment,bytes32 provenanceCommitment,bytes32 profileId,bytes32 locatorCommitment)\n```\n\nThe Transition ID MUST be calculated as:\n\n```\ntransitionId = keccak256(abi.encode(\n  keccak256(bytes(EXPERIENCE_DELTA_TYPE)),\n  delta.spaceId,\n  delta.sequence,\n  delta.prevStateRoot,\n  delta.deltaCommitment,\n  delta.provenanceCommitment,\n  delta.profileId,\n  delta.locatorCommitment\n))\n```\n\nThere is no alternate JSON, JCS, CBOR, or application-specific Transition ID.\n\nState transition\n\nThe exact state type string is:\n\n```\nMemoryState(bytes32 prevStateRoot,bytes32 transitionId)\n```\n\nAfter accepting a transition, the registry MUST calculate:\n\n```\nnextStateRoot = keccak256(abi.encode(\n  keccak256(bytes(MEMORY_STATE_TYPE)),\n  delta.prevStateRoot,\n  transitionId\n))\n```\n\nFor an empty space the current state root and sequence are zero. A registry MUST\naccept a transition only if sequence == currentSequence + 1 and\nprevStateRoot == currentStateRoot. It MUST then atomically store the Transition\nID, next state root, and sequence.\n\nImmutability of the enforcing logic\n\nThe linearity guarantee above is a property of the deployed code, not of the\nrecorded data. A registry whose implementation can be replaced can be made to\naccept a transition violating sequence == currentSequence + 1, while still\nreproducing every test vector in this document; passing the vectors and providing\nthe guarantee are therefore distinct claims.\n\nA conforming registry MUST NOT be deployed behind an upgrade mechanism able to\nreplace the logic enforcing sequence linearity, state root chaining, or signature\nvalidation, and MUST expose no upgrade authority over that logic. Extensions and\noff-chain tooling MAY be upgraded independently, provided they cannot alter the\nacceptance rules above.\n\nSigning domain\n\nAll registration, authorization-update, and transition signatures MUST use the\nEIP-712 domain:\n\n```\nname              = \"AgentMemoryState\"\nversion           = \"1\"\nchainId           = current chain ID\nverifyingContract = registry address\n```\n\nThe signed digest is:\n\n```\nkeccak256(0x1901 || domainSeparator || structHash)\n```\n\nThe domain prevents a signature from being replayed on another chain or another\nregistry. A transitionId remains a chain-independent content identifier; its\nsignature does not.\n\nReferencing a transition\n\nA spaceId is derived from the controller and salt only, so it is stable across\nchains. The same Memory Space identifier can therefore be used for histories on\nmore than one chain. Two chains MAY hold different histories under the same\nspaceId, so (spaceId, transitionId) alone does not determine which history is\nmeant.\n\nA conforming transition reference MUST identify the registry address and the\nchain on which that registry is deployed, in addition to spaceId and\ntransitionId. The chain context MAY be implicit when the reference is emitted\non the same chain as the registry.\n\nThis is a verification requirement, not only a resolution convenience. The\nsigning domain sets verifyingContract to the registry address, so the signed\ndigest cannot be reconstructed — and the authorizer’s signature therefore cannot\nbe checked — without knowing which registry accepted the transition. An otherwise\ncomplete reference that omits the registry or chain context is not independently\nverifiable.\n\nSpace registration\n\nRegistration MUST bind the Space to non-zero controller and authorizer\naddresses. The supplied spaceId MUST equal deriveSpaceId(controller, salt).\nThe registration struct is:\n\n```\nSpaceRegistration(bytes32 spaceId,address controller,address authorizer)\n```\n\nThe controller MUST authorize its EIP-712 struct hash. A Memory Space MUST be\nregistered at most once. A relayer MAY submit the authorization without becoming\ncontroller or authorizer.\n\nAuthorization updates\n\nThe controller MAY atomically replace both controller and authorizer. Each Space\nmaintains a uint64 configNonce, initially zero. An update MUST use\nnonce == currentConfigNonce + 1 and the struct:\n\n```\nSpaceAuthorization(bytes32 spaceId,address newController,address newAuthorizer,uint64 nonce)\n```\n\nThe current controller MUST authorize the update. Both replacement addresses\nMUST be non-zero. The nonce prevents replay of an earlier configuration.\n\nSignature validation\n\nA registry MUST NOT select between ECDSA and ERC-1271 validation by account code\npresence alone. An externally owned account delegated under EIP-7702\ncarries code of the form 0xef0100 || delegate, and many delegates implement no\nsignature policy; branching on code presence would reject those accounts outright.\n\nA signature satisfying either scheme MUST be accepted, evaluated in this order. When\nthe authorizer has non-empty code, the registry MUST first call isValidSignature as\nspecified by ERC-1271 and accept the signature on the 0x1626ba7e magic value.\nOtherwise, or when that call reverts, returns fewer than 32 bytes, or returns any other\nvalue, the registry MUST recover the signer from a canonical, non-malleable 65-byte\nECDSA signature and require equality with the configured account. A signature of any\nother length MUST be rejected without attempting recovery.\n\nA registry MAY accept an empty signature when msg.sender is exactly the account\nwhose authorization is required. It MUST NOT treat an empty signature submitted\nby any other caller as authorized.\n\nBaseline private commitments\n\nProfiles MAY define stronger schemes, including zero-knowledge commitments. A\nconforming implementation SHOULD support the following domain-separated baseline:\n\n```\nDELTA_DOMAIN      = keccak256(bytes(\"AgentMemoryState.deltaCommitment.v1\"))\nPROVENANCE_DOMAIN = keccak256(bytes(\"AgentMemoryState.provenanceCommitment.v1\"))\nLOCATOR_DOMAIN    = keccak256(bytes(\"AgentMemoryState.locatorCommitment.v1\"))\n\ndeltaCommitment = keccak256(abi.encode(\n  DELTA_DOMAIN,\n  profileId,\n  deltaSalt,\n  keccak256(payloadBytes)\n))\n\nprovenanceCommitment = keccak256(abi.encode(\n  PROVENANCE_DOMAIN,\n  provenanceSalt,\n  keccak256(provenanceBytes)\n))\n\nlocatorCommitment = keccak256(abi.encode(\n  LOCATOR_DOMAIN,\n  locatorSalt,\n  keccak256(bytes(locator))\n))\n```\n\nEach salt is 32 bytes and SHOULD be independently sampled. For low-entropy\nplaintext, the salt MUST remain secret or payloadBytes MUST be ciphertext\nproduced with a fresh high-entropy key and nonce. A public salt does not prevent\ntargeted dictionary attacks against low-entropy content.\n\nInterface\n\n```\ninterface IAgentMemoryState {\n    struct ExperienceDelta {\n        bytes32 spaceId;\n        uint64 sequence;\n        bytes32 prevStateRoot;\n        bytes32 deltaCommitment;\n        bytes32 provenanceCommitment;\n        bytes32 profileId;\n        bytes32 locatorCommitment;\n    }\n\n    event SpaceRegistered(\n        bytes32 indexed spaceId,\n        address indexed controller,\n        address indexed authorizer\n    );\n\n    event SpaceAuthorizationUpdated(\n        bytes32 indexed spaceId,\n        address indexed controller,\n        address indexed authorizer,\n        uint64 configNonce\n    );\n\n    event TransitionCommitted(\n        bytes32 indexed spaceId,\n        bytes32 indexed transitionId,\n        uint64 indexed sequence,\n        bytes32 prevStateRoot,\n        bytes32 nextStateRoot,\n        bytes32 deltaCommitment,\n        bytes32 provenanceCommitment,\n        bytes32 profileId,\n        bytes32 locatorCommitment,\n        address authorizer\n    );\n\n    function deriveSpaceId(address initialController, bytes32 salt)\n        external pure returns (bytes32 spaceId);\n\n    function registerSpace(\n        bytes32 spaceId,\n        address controller,\n        address authorizer,\n        bytes32 salt,\n        bytes calldata controllerSignature\n    ) external;\n\n    function updateSpaceAuthorization(\n        bytes32 spaceId,\n        address newController,\n        address newAuthorizer,\n        bytes calldata controllerSignature\n    ) external;\n\n    function commitTransition(\n        ExperienceDelta calldata delta,\n        bytes calldata authorizerSignature\n    ) external returns (bytes32 transitionId, bytes32 nextStateRoot);\n\n    function head(bytes32 spaceId) external view returns (\n        bytes32 transitionId,\n        bytes32 stateRoot,\n        uint64 sequence\n    );\n\n    function spaceAuthorization(bytes32 spaceId) external view returns (\n        address controller,\n        address authorizer,\n        uint64 configNonce\n    );\n}\n```\n\nImplementations MAY expose additional read methods but MUST NOT change the\nmeaning of the normative functions, hashes, or events.\n\nObservation time\n\nAn implementation MAY record block.timestamp as the time at which a transition\nwas observed on-chain. Application-supplied timestamps MUST NOT determine\ntransition ordering. Timestamps inside private payloads remain profile data.\n\nOut of scope\n\nThis ERC does not define agent identity, raw memory storage, data availability,\nretrieval, a universal memory taxonomy, inference verification, branching or\nmerge rules, deletion claims, licensing, payment, tokenization, cross-chain\nmigration, or machine consciousness. Such systems MAY reference a Space,\nTransition ID, or state root without becoming a dependency of the core.\n\nRationale\n\nOne fixed-width Delta\n\nA fixed-width struct is straightforward for independent implementations while\nbinding state, private change, provenance, interpretation, and location.\nRemoving authors and timestamps from the Delta avoids confusing self-asserted\nmetadata with registry authorization or chain observation.\n\nState roots instead of previous record pointers\n\nA previous-record pointer proves only list linkage. Binding the exact prior state\nroot and computing the next root makes the transition relation explicit and\nprevents an update from claiming an unrelated prior memory state.\n\nController and authorizer separation\n\nThe controller is an administrative recovery boundary. The authorizer may be a\nhot EOA, multisignature account, smart account, or policy contract. Rotation\ndoes not change the Space identifier or its state history.\n\nCommitted locator instead of URI calldata\n\nA public URI can leak storage topology, tenant identifiers, or access tokens. A\nlocator commitment is signed, cannot be replaced by a relayer, and can be opened\nselectively to an authorized retriever.\n\nProfiles instead of a fixed memory enum\n\nText, vectors, tool traces, policies, and model-specific latent representations\nevolve independently. profileId lets applications define these semantics\nwithout freezing one product taxonomy into the core registry.\n\nExtensions are separate\n\nDeletion attestations and memory markets have different trust, authorization,\nand security requirements. Keeping them outside this interface allows the state\nprimitive to be reviewed and implemented without adopting those claims.\n\nBackwards Compatibility\n\nThis ERC introduces a new interface and does not change an existing standard.\nEarly prototypes that used JCS identifiers, unsigned URI arguments, fixed memory\nenums, or previousDelta pointers are not wire-compatible with v1 and require an\nexplicit migration checkpoint into a new Space.\n\nTest Cases\n\nFor the canonical v1 vector:\n\n```\nExperienceDelta typehash:\n0x4f020f86bc06d852f1fde17853b4d92a70214eeab8e09718028124af097d070d\n\nMemoryState typehash:\n0xf3148762556cbf851baf4b9a205e18ff4e6b366a58a3a1ef58e8626ba41beadb\n\nMemorySpace typehash:\n0x9ae5478f084ad3b841da58a9cb2354d153cddec59ee64d0cb741fa9d08884531\n\ntransitionId:\n0xdd00dd6eb3aec704b5455502647a0caacf23be6c724eda4a60d9645291e7f4e5\n\nnextStateRoot:\n0x9684a8d3571c5cd9c1e3abb1b0c0797b9fef6965e9002aeefba91e8cb1163754\n```\n\nThe complete input, private commitment witnesses, domain separator, signing\ndigest, registration hash, and authorization-update hash are provided in\nthe machine-readable test vector.\n\nkeccak256(rawMemory) is not a hiding commitment for low-entropy values. A salt\nprevents precomputation but does not prevent targeted guessing when the salt is\npublic. Sensitive or low-entropy payloads therefore need encryption or a secret\nsalt, as required in the Specification.\n\nEquality and metadata leakage\n\nEven private commitments expose timing, update frequency, Space relationships,\nand profile identifiers. Reusing salts, ciphertext, or locator witnesses can\nalso reveal equality. Profiles can mitigate this with padding, batching, and\nsalt or key rotation where the leakage matters.\n\nAuthorization compromise\n\nA compromised authorizer can append valid-looking state. A compromised\ncontroller can replace the authorizer or controller. Deployments are advised to\nuse contract-account policies, threshold authorization, spending or rate limits,\nand operational recovery procedures appropriate to the value of the Space.\n\nContract signature behavior\n\nERC-1271 validation is external code execution through STATICCALL. The\nSpecification requires the exact magic value, handling of reverts and malformed\nreturn data, and completing authorization before state is mutated; an\nimplementation that relaxes any of these accepts forged authorization.\n\nDelegated accounts\n\nAn account delegated under EIP-7702 carries code while its underlying key stays valid,\nso code presence alone does not separate a contract account from an externally owned\none. Deciding validation by code presence locks out delegated accounts whose delegate\nimplements no signature policy. Conversely, because delegation does not revoke the key,\na delegate policy is not the only authorization path: a valid ECDSA signature from the\nunderlying key still authorizes a transition. Deployments that rely on a delegate’s\nthreshold, spending, or session policy need to account for that residual path, and\nshould treat key custody as equally sensitive after delegation.\n\nReplay and relayers\n\nThe EIP-712 domain prevents cross-chain and cross-registry signature replay.\nspaceId, sequence, prior root, and locator commitment prevent a relayer from\nmoving or modifying a signed transition. A relayer can still withhold a valid\ntransaction or race another submission of the same transition.\n\nAvailability and truth\n\nA valid commitment proves neither data availability nor truth of the committed\nmemory. It proves that the configured authorizer approved a state transition.\nApplications requiring availability, inference correctness, or provenance truth\nneed separate mechanisms, and cannot infer them from this registry alone.\n\nDeletion claims\n\nNeither revocation nor key-destruction evidence can prove universal erasure of\ndata already copied by another party. Extensions are expected to describe\ndeletion records as attestations with a stated scope, not as absolute proofs of\ndeletion.\n\nUpgradeability\n\nAn upgradeable registry can change hashing or authorization semantics after users\nsign transitions. Because a replaced implementation can accept a transition that\nviolates sequence linearity while still reproducing every published test vector,\nnon-upgradeability of the enforcing logic is a precondition of the non-forgeability\nproperty rather than a deployment preference. It is stated normatively under\n“Immutability of the enforcing logic” in the Specification, and repeated here\nbecause a requirement stated only in this section is read as informative.\n\nEvidence that no upgrade authority exists can include empty\nERC-1967 implementation and admin slots, plus deployed source\nthat exposes no owner, admin, initializer, or proxy. These checks assess\ndeployment immutability; vector conformance alone does not establish it.", "url": "https://wpnews.pro/news/erc-8350-an-on-chain-standard-for-verifiable-ai-memory-state", "canonical_source": "https://eips.ethereum.org/EIPS/eip-8350", "published_at": "2026-10-06 10:30:12+00:00", "updated_at": "2026-10-06 10:49:25.760496+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "artificial-intelligence"], "entities": ["ERC-8350", "Ethereum", "EIP-712", "ExperienceDelta", "Memory Space", "ERC-1271", "RFC 2119", "RFC 8174"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/erc-8350-an-on-chain-standard-for-verifiable-ai-memory-state", "markdown": "https://wpnews.pro/news/erc-8350-an-on-chain-standard-for-verifiable-ai-memory-state.md", "text": "https://wpnews.pro/news/erc-8350-an-on-chain-standard-for-verifiable-ai-memory-state.txt", "jsonld": "https://wpnews.pro/news/erc-8350-an-on-chain-standard-for-verifiable-ai-memory-state.jsonld"}}