> ## Documentation Index
> Fetch the complete documentation index at: https://docs.defiloops.com/llms.txt
> Use this file to discover all available pages before exploring further.

# The contracts

> The on-chain layer: what is deployed, what each contract decides, and why the addresses move

Five kinds of contract, and between them they decide what an agent may do to an
account without anybody being asked at the time.

|                        | decides                                                                           |
| ---------------------- | --------------------------------------------------------------------------------- |
| **the account**        | who owns it and who may drive it, see [Your account, and the three keys](/kernel) |
| **AgentRegistry**      | which adapters may be installed at all, and whose agent key is still live         |
| **AdapterInstaller**   | how an adapter reaches an account without the owner signing on that chain         |
| **the adapters**       | the closed set of operations, each forcing the owner and the destination          |
| **AgentSelfCallGuard** | what a raw `execute` may not do, on the agent's validator                         |

There is one address per contract and it is the **same on every chain**. They are
derived by CREATE2 from initcode and a fixed salt, so an address is a fact about
a build rather than a deployment choice, which is why none of them is an
environment variable. A value that can be pointed somewhere else is a value that
can be pointed at an attacker.

## AgentRegistry

The whitelist. An adapter the registry does not list cannot be installed by
anybody, so a plan naming one reaches an account that never gained it.

It also holds the kill switch. `revoked[agent]` stops a key for every account on
that chain at once, with no redeploy and no migration, and the guardian who may
write it is set once, at initialisation. **A registry deployed without a guardian
answers every other question perfectly well and can revoke nothing.**

The registry is **per chain**. Each chain carries its own deployment, so
`revoked[agent]` is that chain's storage and a full revocation is one transaction
per chain: three today. Worth knowing before the day it is needed.

Whitelisting sets an activation delay of three days. That delay is a constant in
the contract and not a setting, because a configurable delay is one somebody sets
to zero, and the delay is the only thing that makes a hostile adapter visible
before it can act.

## AdapterInstaller

Installed in the account's genesis, and the only thing there that can install the
rest.

It exists because of a modifier. Kernel gates `installModule` behind
`onlyEntryPointOrSelfOrRoot`, so without it an adapter could only ever be
installed by **the owner sending a transaction on that chain**: four chains,
four signatures, before anything can run. The installer sits in the genesis as an
executor and asks the account to call *itself*, which satisfies the same
modifier. So anyone may bring an account's adapters up, and the relayer pays.

That is what makes a new chain cost the owner nothing.

## The adapters

The closed set of operations. What each one is, and the seven things every one of
them must force by construction, are on [Adapters](/adapters) and
[Your account, and the three keys](/kernel).

What belongs here is why their addresses are not stable across builds.

**Each adapter takes the registry as its only constructor argument.** The
registry's address is therefore inside every adapter's initcode, and a CREATE2
address is a hash of that initcode, so changing one line of AgentRegistry
re-sites every adapter at once. It has happened: the whole table moved when the
registry gained the whitelist.

The dangerous part is that nothing fails when it happens. A stale address table
does not error; it fails later, and elsewhere, as an account whose genesis names
contracts that are not there.

## VersionRegistry

Names which manifest is current, and grants nothing.

It exists because **AgentRegistry cannot see a downgrade.** Superseded adapters
stay whitelisted until somebody delists them, so an old manifest is a genuine
one: every address in it still passes `adapters()`. Something has to say which
set is the current one, and being unable to authorise anything is the point: a
contract that named the current version *and* granted rights would be a second
place to take over the account from.

## AgentSelfCallGuard

The hook on the agent's validator, and the one contract here whose address does
not move with the registry; it takes no constructor argument, so its initcode is
its bytecode alone.

It is a **denylist**, and [Your account, and the three keys](/kernel) says exactly
what that does and does not cover. The short version: it fully blocks control
takeover (the agent can never become owner or hand the account away) and it
does not block value movement by a selector it did not name.

## Deploying them

There is one deploy path and it is the only one. The address table in the code is
the record of where that put things; if the two ever disagree, the table is what
is wrong.

An adapter that is deployed is not yet usable: it has to be whitelisted on that
chain, and then installed on the account. Those are three separate facts and a
plan can fail on any of them, which is why the console reports each one.


## Related topics

- [FAQ](/faq.md)
- [Non-custodial, and unilateral control](/kernel.md)
- [Safe wallets, and the one thing they cannot do](/safe.md)
- [How it works](/platform.md)
- [Adapters](/adapters.md)
