Forwarding has two independent gates: the deployment setting and an append-only database switch.
It is effective only when FORWARDING_ENABLED resolves to the native Boolean true and the latest
forwarding_switch_events row is enabled. Missing state, invalid config, or a database read failure
fails closed.
./vendor/bin/sail artisan forwarding:status
./vendor/bin/sail artisan forwarding:switch disable --actor=operator:alice --reason=incident_123
./vendor/bin/sail artisan forwarding:switch enable --actor=operator:alice --reason=change_456Actor and reason are mandatory. Repeating the current state is idempotent. Enabling is rejected
unless the deployment parent gate is already the native Boolean true; disabling remains available
regardless of the parent setting. There is no HTTP or UI switch.
New settlement reservations and the final pre-broadcast transition re-read the effective gate while holding the shared PostgreSQL advisory lock. The transaction commits before RPC, signing, or broadcast. UTXO, EVM native, ERC-20, and ERC-20 gas funding use the same fail-closed boundary.
Disabling prevents new work from crossing that boundary. A reservation that has not crossed it is
closed as retry-safe. Work already marked broadcasting, broadcasted, confirmed, or
needs_reconciliation continues through evidence reconciliation; ambiguous work is never sent
again merely because the switch changed.
Re-enabling does not automatically release held or disabled backlog. A normal explicit refresh or redispatch is still required.
- Stop queue workers and the scheduler.
- Set
FORWARDING_ENABLED=false, rebuild the config cache, and deploy migrations/code. - Restart workers and confirm
forwarding:statusreports disabled. - Inspect existing reserved and broadcast-ambiguous records; keep reconciliation running.
- Set the parent config to native Boolean
true, rebuild config cache, and restart workers. - Confirm the database switch is still disabled.
- Enable it as a separate operator action with an explicit actor and reason.
For rollback, disable the database switch before stopping workers, keep the parent config false, and preserve switch and settlement evidence. Do not run an older worker build that does not enforce the database switch.
The authoritative implementation is in app/Services/Forwarding,
app/Services/Settlement, app/Services/Evm/EvmGasFundingBoundary.php, and the forwarding tests.