# Manage modules \[Register, authorize, and execute modules on your Vehicle]

Modules are external contracts a Vehicle runs against its own storage, for things like claiming Merkl rewards. The ModulesManager is a shared registry of approved module addresses plus a per-target allowlist keyed `target -> module -> bool`. It never executes anything itself: the Vehicle `delegatecall`s the module from its own `executeModule`.

A module is its address; there are no module IDs and no update function. Registration and removal take effect immediately, with no timelock. Safety comes from the two-sided opt-in: a module must be registered by a `MODULE_MANAGER` and allowed by the target before it can run.

| Role | Checked on | Allows |
|------|------------|--------|
| `MODULE_MANAGER` | ModulesManager | `addModule`, `removeModule` |
| `VEHICLE_ALLOW` | Vehicle | `allowModule` on that Vehicle |
| `VEHICLE_EXEC` | Vehicle | `executeModule` on that Vehicle |

## Register and allow

```solidity [Solidity]
// 1. Register globally (MODULE_MANAGER)
modulesManager.addModule(moduleAddress);
// Reverts ExistingModule if already registered, ZeroCode if not a contract

// 2. Allow it on each Vehicle that should run it (VEHICLE_ALLOW)
vehicle.allowModule(moduleAddress, true);
// Reverts ModuleNotFound if unregistered, AlreadyAllowed if already on

modulesManager.isRegistered(moduleAddress);
modulesManager.allowed(address(vehicle), moduleAddress);
```

The Vehicle forwards `allowModule` to the ModulesManager it was wired to at spawn time, through the `modulesManager` field of the factory's `SpawnParams`; the factory checks that manager came from the trusted `ModulesManagerFactory`. Read it back with `vehicle.modulesManager()`.

## Execute

Execute on the target, not on the ModulesManager.

```solidity [Solidity]
vehicle.executeModule(moduleAddress, abi.encode(...));  // VEHICLE_EXEC
```

The Vehicle checks the caller's role, requires `isRegistered(module)` and `allowed(address(this), module)`, `delegatecall`s `IModule.exec(data)`, and emits `ModuleExecuted(module, data, msg.value)`. It reverts `ModuleNotFound`, `ModuleNotAllowed`, or `MissingModulesManager` when no manager is configured.

Targets must implement `IModuleTarget`, whose only function is `executeModule(address module, bytes calldata data)`. Every Railnet Vehicle does, through `BaseVehicle`. Conduits are not module targets and have no ModulesManager.

## Remove and replace

```solidity [Solidity]
modulesManager.removeModule(oldModule);        // MODULE_MANAGER, immediate everywhere
modulesManager.addModule(newModule);           // the replacement is a new address
vehicle.allowModule(newModule, true);          // re-allow on every Vehicle that needs it
vehicle.allowModule(someModule, false);        // revoke on one Vehicle, keep it registered
```

Removal stops execution everywhere at once, because every execution re-checks `isRegistered`. It does not clear per-target allowances, so targets keep a stale entry and should disallow explicitly when a module is gone for good. Allowances are per address and never carry over to a replacement. `allowModule(module, false)` reverts `AlreadyDisallowed` when the Vehicle was not allowing it.
