Seed Protocol
Contracts

Overview

What Seed Protocol's smart contracts do and how they run inside a user's thirdweb ManagedAccount.

Seed Protocol's contracts are a thin layer between a user's smart account and EAS (Ethereum Attestation Service). They let an account publish a whole item (its Seed, a Version and every property) in one call, check who's allowed to do that, and keep everything they create revocable by the owner. They don't store anything themselves: every published record is a plain EAS attestation made by the user's account. They're deployed on OP Sepolia, a testnet, and nowhere else; Deployments has the addresses.

What the contracts do and don't do

The vision is a record that outlives every organization involved, including Seed. That's why the record lives in EAS rather than in a Seed contract.

The contracts do:

  • Batch a publish. multiPublish creates every Seed and Version the batch is missing, fills in cross-references between items in the batch, in any direction, then points each property attestation at its Version and sends the properties to EAS, all in one transaction. The publish package sends an item and its related drafts as one multiPublish, so items that refer to each other are attested together.
  • Authorize callers. They run inside the user's account and accept a publish only from the account's admins, its ERC-4337 EntryPoint, or the account itself.
  • Force revocability. Every attestation they create is revocable, whatever the request says, so the owner can always revoke what a delegate published.
  • Give delegates a narrow path. The executor module lets a session key publish as the account and do nothing else: it can't revoke, and it can't call anything but EAS attest and multiAttest.

The contracts don't:

  • Hold data. There's no Seed registry. Seeds, Versions and properties are EAS attestations, and the account that published them is the attester. If the Seed contracts were replaced tomorrow, every existing attestation would stay in EAS, readable by anyone.
  • Revoke. Owners revoke by calling EAS directly from their account. No Seed contract has a revoke function.
  • Register schemas. The publish package registers EAS schemas for your models from the owner's account before it publishes. See Who registers them.
  • Validate content. They don't check that a property's data matches its model, that a Seed UID you pass belongs to you, or that a schema is a Seed schema. Readers decide what to trust, starting with the attester.

So you can read Seed data with any EAS client, and you could publish it without the contracts at all (the publish package can, with useDirectEas). The contracts are a convenience and an authorization layer.

The components

The contracts plug into a thirdweb ManagedAccount: an ERC-4337 smart account (EntryPoint v0.6) created by a thirdweb ManagedAccountFactory. The factory doubles as a Router: when an account receives a call it has no function for, its fallback asks the factory which extension implements that selector, then runs that extension's code with delegatecall. The code runs in the account's context, so address(this) is the account and every external call it makes comes from the account.

ContractKindWhat it's for
SeedProtocolExtensionRouter extensionmultiPublish and getEas. The path for publishes the account's admin signs.
SeedProtocolExecutorERC-7579 executor module (type 2)The same multiPublish, called by the account as an external module. The path for session keys.
SeedExecutorRouterExtensionRouter extensionGives a ManagedAccount the slice of ERC-7579 the executor needs: install, uninstall, and a locked-down executeFromExecutor.
SeedAccountAuthAbstract contractThe caller checks both Router extensions share. The Router itself authorizes nothing.
SeedPublishLibLibraryRequest preparation the extension and the executor share, so both paths enforce the same rules: refUID defaults, forced revocability, the exact msg.value check and the writes for cross-references.

Both Router extensions are plain, non-upgradeable contracts with the EAS address (and, for the router extension, the executor address) fixed in the constructor. Changing either means deploying a new contract and switching the factory's routing, which only the holder of the factory's EXTENSION_ROLE can do (who holds it today).

Whichever path a publish takes, EAS sees the account as the caller, so the account is the attester and, by Seed's rules, the author. Identity and signing explains why that matters.

Publishing through the extension is open to the account's admins, its EntryPoint and the account itself, so a session key reaches it only through the account's execute; installing or uninstalling the executor is open to admins and the EntryPoint only. Who may call it has the rules per function, and Security and session keys the threat model.

Which path the publish package takes

@seedprotocol/publish takes one of three routes, chosen when a publish starts from its config and the publishing account. Publish overview (Attestation routing) has the rules and the refusals.

RouteContracts involvedWhen the publish package takes it
EAS attest / multiAttest straight from the publishing account, a separate transaction for each Seed, Version and propertyNoneWith useDirectEas, or when the publisher is a plain wallet: no contract code, or an EIP-7702-delegated EOA
multiPublish on the user's ManagedAccountSeedProtocolExtensionWhen the publisher is a deployed smart account and no session key is publishing. An undeployed ManagedAccount is deployed first when the wallet can do it (ConnectButton's wallet can, and so can autoDeployManagedAccount with useModularExecutor)
A UserOp from a session key calling execute(executor, 0, multiPublish(...))SeedProtocolExecutor, SeedExecutorRouterExtensionWith useModularExecutor and modularAccountModuleContract, when the signer is an active automation session key on the account

When modularAccountModuleContract is set, ConnectButton and, with useModularExecutor, an interactive publish install the executor from the account's admin if the ManagedAccount routes the router extension and doesn't have it yet. A failed install doesn't stop the publish; it only leaves the account unable to publish with a session key. An account that installed an earlier executor counts as not having this one, so its admin installs again. A contract publish first checks that its target has the multiPublish the package sends, and fails with MULTI_PUBLISH_NOT_ROUTED if it doesn't. Every multiPublish is simulated from the sending account first, and a call that would revert isn't sent. When the simulation itself can't run, an interactive publish is sent anyway, and a session-key publish is refused.

Older Seed contracts are still on OP Sepolia, but the factory doesn't route to them. Accounts installed the executor from the 2026-10-03 set, so an account can still carry its configuration, and that executor can no longer publish for it. Not in use lists them all.

On this page