Ownership and Permissions
Walrus Memory uses a layered permission model. The account owner has full control of the account, delegates store and recall memories but cannot change account settings, and the Seal seal_approve function grants decryption access to owners and registered delegates on active accounts.
What can an account owner do?
The owner is the Sui wallet address recorded by the MemWalAccount. The owner can:
- Add and remove delegate keys
- Deactivate (freeze) and reactivate the account when no Admin quarantine is active
- Decrypt any memory encrypted under their address through Seal
Each Sui address can only create one MemWalAccount: the AccountRegistry enforces this limit, so an attempt to create a second account from an address that already owns one is rejected instead of producing another account.
What can a delegate do?
A delegate key authenticates API calls through the relayer. Delegates can:
- Store memories (
remember,analyze) - Recall memories (
recall) - Restore namespaces (
restore) - Decrypt Seal-encrypted content (through
seal_approve)
Delegates cannot:
- Add or remove other delegate keys
- Deactivate or reactivate the account
- Transfer ownership
How does Seal access control work?
The contract's seal_approve function is the Seal policy that controls who can decrypt memories. Every key ID ends with the owner's address followed by the account's rotation counter. A key ID has this layout, in order:
- Prefix: any bytes (the SDK uses the UTF-8 bytes of the namespace)
BCS(owner_address): 32 bytesBCS(access_counter_version): 8 bytes, little-endian
This tail check applies to owners and delegates alike. Given it, access is granted if the caller is:
- The data owner, the caller is the account owner
- A registered delegate, the caller's Sui address is in the account's
delegate_keyslist
The account must also be active (not frozen). If the account is deactivated, all Seal access is denied.
Delegate authorization is account-wide. A namespace changes the Seal identity, but it does not stop another delegate on the same account from requesting that key.
The rotation counter
Seal derives one reusable key per identity, and a holder decrypts with that key without calling seal_approve again. An identity fixed at BCS(owner) would let any delegate who ever fetched that key keep decrypting new memories forever. Removing them onchain would never touch the copy in their hands. Tailing the ID with access_counter_version fixes this: withdrawing access (removing a delegate, freezing the account) bumps the counter, which changes the identity, which yields a key the removed delegate cannot fetch.
Two rules follow, and clients must respect both:
seal_approverejects any counter above the account's current one. Otherwise a delegate authorized right now could pre-fetch keys for every future identity and make rotation a no-op. Older counters stay approvable for callers who still pass the authorization check (the account owner and any Sui address still registered indelegate_keys), so owners keep access to their history. A removed delegate cannot getseal_approveto approve any request, at an older counter or the current one. Removal does not revoke a key the delegate already fetched: that copy still decrypts memories written under the counter it covers, and retracting those requires re-encryption.- Read the counter fresh from chain immediately before encrypting, never cache it, never accept it from a request body. Encrypting under a stale counter hands the data straight back to the delegate you just removed.
Rotation is forward-only: memories already written under an older counter stay readable with the older key. Retracting those requires re-encryption.
How do the permission layers work together?
These are separate layers that work together:
| Layer | Controls | Enforced by |
|---|---|---|
| Owner | Account control, keys, activation, ownership | Sui smart contract |
| Delegate | Application access, read/write memory | Sui smart contract + relayer verification |
| Relayer | Backend execution, encryption, storage, search | Server-side auth middleware |
The relayer verifies every request against the onchain contract before executing any operation. Even if the relayer is compromised, it cannot forge delegate permissions or change ownership, those are cryptographically enforced onchain.
What happens to fetched keys when you freeze an account?
Freezing stops seal_approve from approving any new key request, for owners and delegates alike. It does not revoke keys that a caller already fetched. Seal keys are reusable, and a holder decrypts with them without calling seal_approve again. A key fetched before the freeze keeps decrypting memories written under the counter it covers.
Freezing also bumps access_counter_version. Encryption never calls seal_approve, so a frozen account can still accumulate ciphertext. That ciphertext uses the new counter, which no one holds a key for, and no one can obtain that key until the owner reactivates the account. To cut off access to memories written before the freeze, re-encrypt them.