feat: world chain account implementation#656
Conversation
|
@cursoragent review |
|
You need to increase your spend limit or enable usage-based billing to run background agents. Go to Cursor |
|
@cursor review |
|
/otto review with GPT 5.5 Max Thinking |
|
Let me fetch the PR details first.
I'll let you know when it's done! 🔍 |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 8da0f22. Configure here.
|
|
||
| /// @inheritdoc IWorldChainAccount | ||
| function isValidSignatureForAdmin(bytes32 hash, bytes calldata signature) | ||
| external |
There was a problem hiding this comment.
Critical: these validation dispatch functions perform DELEGATECALL but are callable by any EOA/contract. The restricted-frame invariant only holds when the manager uses STATICCALL; a direct CALL to this function executes the installed verifier in the account's storage with normal state-mutating EVM semantics, so verifier code can SSTORE account validation state, emit logs, make external calls/reenter, etc. This violates the interface's no-non-manager mutation boundary and makes verifier bugs exploitable by anyone. Please gate isValidSignatureForAdmin, isValidSignatureForVerifier, and evaluateSessionPolicyForVerifier with onlyManager (or equivalent) before any delegatecall; the manager can still STATICCALL them.
There was a problem hiding this comment.
+1 I think this comment makes sense. Those fns should be only callable by the world chain account manager, so we could add a modifier that restricts access to it
There was a problem hiding this comment.
This is not the case
There was a problem hiding this comment.
Why? From the spec it seems these fns are only callable by world chain account manager. If we don't want this, I would specify in the wip better
| /// and running each verifier's installation hook. The hash rotation atomically retires | ||
| /// every entry from the prior key ring without an explicit per-element wipe. | ||
| function _installKeyRing(WorldChainAccountVerifier[] calldata sessionVerifiers) internal { | ||
| IWorldChainAccount.KeyRingStorage storage $ = _keyRingStorage(); |
There was a problem hiding this comment.
High: _installKeyRing does not enforce the WIP key-ring invariants at the router boundary (length in 1..MAX_SESSION_VERIFIERS, non-zero deployed verifier addresses, and no duplicate verifier addresses) before committing keyRingHash/running hooks. Duplicates are especially problematic because keyRingHash commits to multiple descriptors while sessionKeyRing is keyed only by address; the hook runs multiple times and final verifier storage may correspond to only the last descriptor. Relying only on manager validation leaves a manager/predeploy upgrade bug able to install a ring the router cannot faithfully represent. Please validate the full set first, then set keyRingHash and run hooks.
There was a problem hiding this comment.
+1 this comment makes sense
There was a problem hiding this comment.
as mentioned on slack, we should revisit this!
| /// @custom:security-contact security@toolsforhumanity.com | ||
| contract WorldChainAccountUpgradeableBeacon is UpgradeableBeacon { | ||
| constructor(address implementation_, address initialOwner) UpgradeableBeacon(implementation_, initialOwner) {} | ||
| } |
There was a problem hiding this comment.
High: a global UpgradeableBeacon lets the owner change account logic, the immutable MANAGER, and storage assumptions for every account without changing each account's runtime code hash. WIP domains/address derivation and txpool cache invalidation bind WORLD_CHAIN_ACCOUNT_ROUTER_CODE_HASH/keyRingHash, not the beacon implementation hash/version, so an upgrade can silently change validation semantics for already-created accounts and pending signatures. If upgradeability remains, the spec/code should bind or gate implementation versions (e.g. fork/timelock governance plus storage-layout checks and golden tests); otherwise the router implementation should be immutable.
| contract WorldChainAccountBeaconProxy is BeaconProxy { | ||
| /// @notice The single global `WorldChainAccountUpgradeableBeacon` predeploy. | ||
| /// TODO: FIXME(Osiris): Update Spec | ||
| address internal constant WORLD_CHAIN_ACCOUNT_BEACON = 0x000000000000000000000000000000000000B0cC; |
There was a problem hiding this comment.
Spec mismatch: this hard-coded beacon predeploy is not currently an activation parameter in WIP-1001, while the proxy runtime/code hash depends on the immutable beacon address. If clients/managers derive WORLD_CHAIN_ACCOUNT_ROUTER_CODE_HASH with a different beacon address, accounts can satisfy the expected proxy code shape while pointing at the wrong or nonexistent beacon and all calls brick. Please finalize the beacon address in the spec/activation params and add code-hash golden tests.
There was a problem hiding this comment.
+1, this needs to be added to the wip
There was a problem hiding this comment.
/// TODO: FIXME(Osiris): Update Spec
|
Overall verdict: changes requested before merge. The implementation is compact and broadly follows the WIP-1001 shape, but this is a consensus/account-auth boundary and the inline blockers should be resolved with adversarial tests before landing. I verified the documented ERC-7201 slot derivation and compiled the changed contracts with solc-js 0.8.28 in this workspace. I could not run the Foundry suite here because |
|
The GPT-5.5 subagent has completed the review. Here's a summary of what was done: ✅ Review complete on PR #656 — "feat: world chain account implementation" The subagent:
Links:
|
alessandromazza98
left a comment
There was a problem hiding this comment.
There are some comments that make sense to be addressed.
Requesting changes to point those out, once they're addressed, it's good to be merged
| contract WorldChainAccountBeaconProxy is BeaconProxy { | ||
| /// @notice The single global `WorldChainAccountUpgradeableBeacon` predeploy. | ||
| /// TODO: FIXME(Osiris): Update Spec | ||
| address internal constant WORLD_CHAIN_ACCOUNT_BEACON = 0x000000000000000000000000000000000000B0cC; |
There was a problem hiding this comment.
+1, this needs to be added to the wip
| /// and running each verifier's installation hook. The hash rotation atomically retires | ||
| /// every entry from the prior key ring without an explicit per-element wipe. | ||
| function _installKeyRing(WorldChainAccountVerifier[] calldata sessionVerifiers) internal { | ||
| IWorldChainAccount.KeyRingStorage storage $ = _keyRingStorage(); |
There was a problem hiding this comment.
+1 this comment makes sense
| IWorldChainSessionVerifier.ExecutionTraceContext calldata context | ||
| ) external override sessionInstalled(verifier) returns (bool allowed) { | ||
| bytes memory ret = | ||
| verifier.functionDelegateCall(abi.encodeCall(IWorldChainSessionVerifier.evaluateSessionPolicy, (context))); |
|
|
||
| /// @inheritdoc IWorldChainAccount | ||
| function isValidSignatureForAdmin(bytes32 hash, bytes calldata signature) | ||
| external |
There was a problem hiding this comment.
+1 I think this comment makes sense. Those fns should be only callable by the world chain account manager, so we could add a modifier that restricts access to it
alessandromazza98
left a comment
There was a problem hiding this comment.
I'm actually approving because I don't want to block you, but please take a look at those comments and address them before merging
| struct KeyRingStorage { | ||
| address adminVerifier; | ||
| bytes32 keyRingHash; | ||
| mapping(address verifier => bytes32 keyRingHash) sessionKeyRing; |
There was a problem hiding this comment.
not unique in current design.
There was a problem hiding this comment.
i still think this struct generally is very elegant implementation tho 👍
| /// caller other than `WORLD_CHAIN_ACCOUNT_MANAGER`. Replaces any previously installed | ||
| /// key ring on `setKeyRing`. | ||
| /// @param sessionVerifiers The ordered session verifier set to install. | ||
| function installKeyRing(WorldChainAccountVerifier[] calldata sessionVerifiers) external; |
There was a problem hiding this comment.
super nit, but it probably should be Keyring not KeyRing
| /// verifier writes any validation-affecting state into its own deterministic account | ||
| /// storage namespace. Uses OpenZeppelin's `Address.functionDelegateCall`, which reverts | ||
| /// with the callee's returndata on failure. | ||
| function _runInstallHook(address verifier, bytes calldata installation) private { |
There was a problem hiding this comment.
would it make sense to add a function to the session verifier namespace which defines the storage slot (erc7201) of that verifier (e.g based on a name) and double checks no verifiers clash? otherwise they might override each others storage and you look yourself out of your account potentially.
There was a problem hiding this comment.
Yes, this is a great idea
| /// and running each verifier's installation hook. The hash rotation atomically retires | ||
| /// every entry from the prior key ring without an explicit per-element wipe. | ||
| function _installKeyRing(WorldChainAccountVerifier[] calldata sessionVerifiers) internal { | ||
| IWorldChainAccount.KeyRingStorage storage $ = _keyRingStorage(); |
There was a problem hiding this comment.
as mentioned on slack, we should revisit this!
| import {IWorldChainAccountRouterErrors} from "../interfaces/IWorldChainAccountRouterErrors.sol"; | ||
|
|
||
| /// @title Dispatch | ||
| /// @author 0xOsiris, World Contributors |
There was a problem hiding this comment.
it better not have a vulnerability then xD
Note
High Risk
High risk because it introduces new core account-router contracts that rely on
DELEGATECALLfor signature/policy validation and manage verifier installation/storage invariants, which are security-critical paths.Overview
Implements the WIP-1001 account router as a new
WorldChainAccountcontract deployed behind a global beacon (WorldChainAccountUpgradeableBeacon) and reached viaWorldChainAccountBeaconProxy.The router now enforces manager-only installation of an immutable admin verifier and a rotating session key ring (ERC-7201 namespaced storage), and dispatches EIP-1271 signature checks plus session-policy evaluation to installed verifiers via controlled
DELEGATECALL(rejecting unknown verifiers before any verifier code runs).Adds
Dispatchfallback handling with an explicitUnknownSelectorerror, definesIWorldChainAccount+IWorldChainAccountRouterErrors, and updateswip-1001.mdreferences fromIWorldChainAccountRoutertoIWorldChainAccount.Reviewed by Cursor Bugbot for commit 8da0f22. Configure here.