Skip to content

Add app government#90

Open
crypt0fairy wants to merge 38 commits intomasterfrom
taras/gov
Open

Add app government#90
crypt0fairy wants to merge 38 commits intomasterfrom
taras/gov

Conversation

@crypt0fairy
Copy link
Copy Markdown

contract changes Layr-Labs/eigenx-contracts#9

@crypt0fairy crypt0fairy marked this pull request as ready for review March 24, 2026 19:54
…mmands

- ABI: getAppGoverned→getAppTimelocked, DirectUpgradeNotAllowed→TimelockRequired,
  GovernanceRequired→NotTimelocked
- SDK caller: getAppGoverned→getAppTimelocked, update error messages
- SDK app module: isGoverned→isTimelocked in interface and implementation
- CLI upgrade: block direct upgrade when app is timelocked
- CLI upgrade schedule/execute: new commands for timelocked two-step flow
- CLI ownership transfer: new command, shows timelocked mode note post-transfer
- Docs: add governance-commands.md documenting all new commands and flows
SDK:
- Update AppController ABI from latest contract (adds cancelUpgrade, team role functions, getAppOwner)
- Add cancelAppUpgrade, grantTeamRole, revokeTeamRole, getTeamRoleMembers, getAppOwner to caller.ts
- Add TeamRole enum to SDK
- Add cancelUpgrade, grantTeamRole, revokeTeamRole, getTeamRoleMembers to AppModule interface and implementation
- Export new functions and types from client/index.ts

CLI:
- ecloud compute app upgrade cancel — cancel a pending scheduled upgrade
- ecloud compute team grant <addr> --role=PAUSER|DEVELOPER — grant team role
- ecloud compute team revoke <addr> --role=PAUSER|DEVELOPER — revoke team role
- ecloud compute team list — show ADMIN/PAUSER/DEVELOPER members for an app
…e selection

- CLI now stores multiple identities (EOA, Safe, Timelock) per user in config
- Active identity is tracked per environment
- auth login: shows identity selector; 1 identity auto-prompts, replacing key wipes old identities and re-discovers Timelock for new EOA
- auth new/generate: rewritten with EOA/Safe/Timelock flows; enforces CANONICAL_SALT for deterministic Timelock addresses
- auth whoami: shows all identities with active marker and signing key status
- SDK: add deploySafe, deployTimelock, discoverTimelockForEOA, CANONICAL_SALT
- SDK: add SafeTimelockFactory and TimelockController ABIs
…ore replace

- auth new → Safe: auto-generate signing key if none exists, EOA always pre-filled as owner
- auth new → Timelock: EOA proposer defaults to signing key, Safe prompts for address
- Consistent warning message across all key-replace flows
- Show existing key in pager before warning so user can back it up
- Safe Transaction Service discovery in auth login (find Safes where EOA is owner)
- Remove redundant Safe identity entry when Safe+Timelock deployed together
executeGovernedUpgrade previously re-ran the full Docker build pipeline
to reconstruct the Release for on-chain hash verification. This would
fail with ReleaseMismatch on any non-deterministic build.

The Release is already emitted in full in the AppUpgradeScheduled event.
Add getScheduledRelease() to fetch and decode it from logs by matching
on readyAt, then pass it directly to executeUpgrade — no rebuild needed.

Also simplifies ExecuteGovernedUpgradeOptions and the execute CLI command,
removing all build flags (dockerfile, image-ref, env-file, instance-type,
log-visibility, resource-usage-monitoring) that are no longer required.
…ions

Add schedule/execute CLI commands and SDK methods for the three AppController
operations that require Timelock routing when an app is timelocked:
terminateApp, transferOwnership, and grantTeamRole(ADMIN).

- TimelockController ABI: add schedule, execute, hashOperation, getTimestamp
- caller.ts: add scheduleTimelockOp/executeTimelockOp primitives, per-op
  helpers (terminate, transferOwnership, grantTeamAdmin), and readyAt helpers
- AppModule: expose all new methods including getTimelockTerminateReadyAt,
  getTimelockTransferOwnershipReadyAt, getTimelockGrantAdminReadyAt
- CLI: app terminate schedule/execute, app ownership schedule-transfer/
  execute-transfer, team grant-admin schedule/execute
… consistent style

- Add new commands: ownership schedule/execute-transfer, terminate schedule/execute,
  upgrade cancel, team grant-admin schedule/execute
- Rename sections to command-group style (compute app, compute team, etc.)
- Shorten command names in table rows (remove ecloud compute app prefix)
- Replace emoji cell values with plain text (no permission, direct, yes, visible)
- Abbreviate column headers to TL(EOA) / TL(Safe)
- Update legend to document new cell value vocabulary
crypt0fairy and others added 15 commits April 9, 2026 17:33
Keyring commands (signing key):
- auth generate — generate new key + store in keyring (simplified, no Safe/Timelock)
- auth login — import existing key + store + discover identities on-chain
- auth logout — remove key from keyring + clear all identities

Identity commands (new):
- auth identity new — create Safe or Timelock (moved from auth generate)
- auth identity list — show all stored identities
- auth identity select — switch active identity per environment

Changes:
- auth generate no longer offers Safe/Timelock creation
- auth login no longer has identity selector (use auth identity select)
- auth logout now clears identities (prevents orphaned state)
- Added removeIdentity() to globalConfig.ts
- Added auth-flow-map.md with complete state transition table,
  decision trees for every command, and command tree with key requirements
Rename discoverTimelockForEOA to discoverTimelock — the underlying
calculateTimelockAddress works with any address (EOA or Safe) + salt.

Now when creating a Timelock via auth identity new, the CLI checks
for existing Timelocks for both EOA and Safe proposers before deploying.
This prevents duplicate deployments since addresses are deterministic
via CREATE2 with CANONICAL_SALT.
List now queries apps across all identity addresses from config (EOA,
Safe, Timelock), grouped by owner with active identity marked. Falls
back to signing key address if no identities configured.

No private key needed for reads — uses addresses from config.
List queries apps across all identity addresses (EOA, Safe, Timelock),
grouped by owner with active identity marked. Uses private key for
API authentication — backend resolves Safe/Timelock ownership on-chain.

Update auth-flow-map with backend ownership resolution flow.
New SDK modules:
- safe.ts: Safe Transaction Service proposal (read nonce, sign tx hash,
  post to Safe API)
- identity-router.ts: sendWithIdentity() routes transactions based on
  active identity type (EOA direct / Safe propose / Timelock schedule)

CLI changes:
- identityTransaction.ts: shared utilities for identity context display
  and routing
- start, stop, terminate: show active identity before sending, route
  through identity router when identity is Safe or Timelock

EOA behavior unchanged — existing code path preserved.
Safe/Timelock paths: propose to Safe Transaction Service or schedule
on Timelock via the identity router.
- auth identity new: replace discoverTimelock (single canonical-salt lookup)
  with getTimelocksByDeployer (full factory registry scan), supporting
  multiple timelocks per proposer
- auth whoami: fix misleading hints — 'auth new' → 'auth gen'/'auth login',
  'auth login' to switch → 'auth identity select'
- environment.ts: update sepolia-dev AppController address to latest deploy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After handling existing timelocks, ask whether to deploy another with a
different delay instead of always returning early.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds optional `salt` parameter to `DeployTimelockOptions` in the SDK so
callers can override the default CANONICAL_SALT (bytes32(0)). In the CLI,
when a user chooses to deploy an additional timelock beyond the first,
a cryptographically random 32-byte salt is generated to avoid CREATE2
collision.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Salt is keccak256(abi.encodePacked(minDelay)), so the same delay cannot
be deployed twice for the same proposer (CREATE2 reverts), and different
delays produce distinct Timelock addresses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bare numbers like "22" now error (previously silently treated as seconds).
Both delay prompts validate with the same regex before accepting, so the
user gets inline feedback rather than a thrown error post-confirmation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
crypt0fairy and others added 10 commits April 16, 2026 10:35
Previously the build-time compiled value always won, so BUILD_TYPE=dev
had no effect when running a prod build. Runtime env var now takes
precedence so the dev alias works without rebuilding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When all timelocks are already stored, display the known delay next to
each address so users can distinguish between them without guessing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dedup ABIs

- auth sync: new command to rescan chain and rebuild identities from stored signing key
- auth identity new: proposer selector (EOA + on-chain Safes with threshold/owner info),
  PROPOSER_ROLE filter for existing timelocks, deterministic salt keccak256(proposer, minDelay)
- auth login/sync: read getMinDelay() from chain, store human-readable delay (e.g. "24h")
- StoredIdentity: add threshold/owners fields for Safes; formatIdentity shows "Safe 1/1 · 0xabc…xyz"
- contractAbis.ts: shared SAFE_ABI, TIMELOCK_ABI, fetchSafeInfo(), fetchTimelockDelay() — eliminates
  inline ABI duplicates across new.ts, login.ts, sync.ts
- format.ts: add formatDelay(seconds: bigint) → human-readable string
- team grant/revoke: route all role operations through identity (Safe/Timelock)
  via encodeGrantTeamRoleData/encodeRevokeTeamRoleData; previously only ADMIN
  went through identity routing, PAUSER/DEVELOPER were sent directly as EOA
- add encodeRevokeTeamRoleData to SDK (ABI, encoder fn, barrel exports)
- fix gas estimation crash for Safe/Timelock identities in start/stop/terminate/
  transfer: skip estimation when identity is not EOA (msg.sender mismatch causes
  revert); estimateGas still runs for EOA path
- fix getPrivateKeyInteractive(environment) bug in all compute commands — was
  passing environment string "sepolia-dev" as the private key parameter
- remove acceptAdmin from deploy batch — eigenx-contracts emptied App.initialize,
  2-step admin handshake no longer needed
- whoami: add verbose flag to show full addresses in identity display
- whoami fetches pending ops for all Timelock identities via getPendingOperations()
  (single view call per Timelock, no log scanning, no RPC range limits)
- pending ops show description (decoded function name), countdown to executable, and op ID
- TimelockController ABI: add getPendingOperations, getPendingOperationIds, events
- SDK: getPendingTimelockOps() + PendingTimelockOp type exported
- whoami: add --rpc-url flag (reads ECLOUD_RPC_URL env var)
- environment.ts: update sepolia-dev AppController to 0x6A56214b79d24469f066AdfD1F28bB929824daCE
sync: replace factory deployer lookup with hasRole(PROPOSER_ROLE, safe) check — TimelockControllerImpl uses AccessControl not AccessControlEnumerable so getRoleMember doesn't exist

deploySafe: predict address before deploy and skip if already exists to handle re-runs gracefully

identity new: surface existing predicted Safe in proposer selector
All governance commands (upgrade, stop, start, terminate, transfer,
team grant, team revoke) now support --execute <op-id> and --cancel <op-id>
to complete or abort pending Timelock operations. Pending ops are also
shown in app list and app info output.

Shared utilities: timelockExecute.ts (execute/cancel handlers),
timelockFlags in flags.ts, formatCountdown in format.ts.
Also includes describeCalldata improvement to show app address in
pending op descriptions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant