API Reference

Every external function on the ERC-8004 Identity Adapter.

All functions live on Adapter8004 (src/Adapter8004.sol). Exact parameter types track the contract source — check the repo if a signature changes.

Initialization#

initialize(address identityRegistry_, address initialOwner)#

UUPS initializer. Called once via the proxy. Reverts with InvalidTokenContract if identityRegistry_ is zero and with OwnableInvalidOwner if initialOwner is zero. The implementation's constructor calls _disableInitializers(), so the bare implementation cannot be initialized.

Registration#

register(TokenStandard, address tokenContract, uint256 tokenId, string agentURI, MetadataEntry[] metadata) → uint256 agentId#

Registers a new ERC-8004 identity and binds it to (standard, tokenContract, tokenId). Reverts with:

  • InvalidTokenContracttokenContract == address(0)
  • NotController — caller does not currently control the external token

Emits AgentBound(agentId, standard, tokenContract, tokenId, registeredBy).

After registration the adapter calls unsetAgentWallet(agentId) on the registry to clear the default agentWallet slot.

Controller-gated writes#

Every function below calls _requireController(agentId, msg.sender), which reverts with UnknownAgent(agentId) if the id was never bound and NotController(account, agentId) if the caller does not currently control the bound token.

setAgentURI(uint256 agentId, string newURI)#

Forwards to identityRegistry.setAgentURI.

setMetadata(uint256 agentId, string key, bytes value)#

Forwards to identityRegistry.setMetadata.

setMetadataBatch(uint256 agentId, MetadataEntry[] metadata)#

Loops over metadata and forwards each entry to identityRegistry.setMetadata. Emits MetadataBatchSet(agentId, count, updatedBy) after the loop. The count can be zero — the event still fires.

setAgentWallet(uint256 agentId, address newWallet, uint256 deadline, bytes signature)#

Forwards to identityRegistry.setAgentWallet. The registry enforces the wallet-proof rule — see Concepts for the EIP-712 owner subtlety.

unsetAgentWallet(uint256 agentId)#

Forwards to identityRegistry.unsetAgentWallet. Idempotent.

Views#

bindingOf(uint256 agentId) → Binding#

Returns the Binding struct. Reverts with UnknownAgent(agentId) if the binding does not exist.

agentIdForBinding(TokenStandard, address tokenContract, uint256 tokenId) → (uint256 agentId, bool exists)#

Reverse lookup. Returns (0, false) if no binding exists. Because the adapter stores bindings as agentId + 1 internally, agentId = 0 is correctly distinguished from "unset" — the boolean is the source of truth.

isController(uint256 agentId, address account) → bool#

Returns true iff the bound token contract currently reports account as a holder per the standard's control rule. Returns false (no revert) if the agentId is unknown. This is the safe query to use before attempting a controller-gated write.

Admin#

setIdentityRegistry(address newRegistry)#

onlyOwner. Reverts with InvalidTokenContract if newRegistry is zero. Emits IdentityRegistryUpdated(previous, new, updatedBy).

Previously-registered bindings remain in the adapter's storage but writes targeted at their agentIds will now route into the new registry — which has no knowledge of those ids. See Admin & Upgrades for the operational implications.

upgradeToAndCall(address newImplementation, bytes data) (from UUPS)#

Owner-only. Gated by _authorizeUpgrade(onlyOwner). Renouncing ownership via renounceOwnership() permanently disables upgrades and registry swaps.

ERC-721 receiver#

onERC721Received(address, address, uint256, bytes) → bytes4#

Returns IERC721Receiver.onERC721Received.selector. The adapter never calls safeTransferFrom against the external bound token, but it implements the interface so it can receive the ERC-8004 token from the registry on register.

Errors#

ErrorWhen
InvalidTokenContract()Zero address passed as registry or tokenContract
NotController(address account, uint256 agentId)Caller isn't the current controller
UnknownAgent(uint256 agentId)agentId was never bound
BindingAlreadyExists(...)Binding slot already taken (depending on revision)
OwnableUnauthorizedAccount(address)Non-owner hitting an admin function
OwnableInvalidOwner(address)Zero address passed as initialOwner
InvalidInitialization()Re-initialization attempt

Events#

EventFired by
AgentBound(agentId, standard, tokenContract, tokenId, registeredBy)register
MetadataBatchSet(agentId, count, updatedBy)setMetadataBatch
IdentityRegistryUpdated(previous, new, updatedBy)setIdentityRegistry
OwnershipTransferred(...)Inherited from OwnableUpgradeable
Upgraded(newImplementation)Inherited from UUPS