Grove Spell 2026-07-02 Security Review

Summary

Overall, we consider the spell to be ready for deployment and safe

Deployment Verification

[Ethereum + Robinhood Chain] Onboard the Grove Liquidity Layer on Robinhood Chain, with USDG bridging via Paxos

Paxos USDC bridge rate limit

RateLimits:

  • LIMIT_ASSET_TRANSFER (USDC -> Paxos wallet)
  • key: 0x4139045de2f11ba23865c6cdf20084f6566d834b50716e469c5dbd8ed71faaf1 – recomputed and matches makeAssetDestinationKey(LIMIT_ASSET_TRANSFER, USDC, 0x8C0A…c2dB)
  • maxAmount = 50,000,000e6, slope = 50,000,000e6 / 1 days – as stated in the proposal
  • Token: Ethereum.USDC
  • Destination: Paxos USDC deposit wallet – as provided in the proposal
  • Covered by test:
    • GroveEthereum_20260716_Test.test_ETHEREUM_onboardPaxosUsdcBridgeRateLimit()

Paxos USDG bridge rate limit

RateLimits:

  • LIMIT_ASSET_TRANSFER (USDG -> Paxos USDG wallet)
  • key: 0x6514f636131e8989437496ad745c5671d7794873c5c1cd6d0a8b5b42031e5c9d - recomputed and matches makeAssetDestinationKey(LIMIT_ASSET_TRANSFER, USDG, 0xfC0a…b06e)
  • maxAmount = 50,000,000e6, slope = 50,000,000e6 / 1 days – as stated in the proposal
  • Token: USDG
  • Destination: Paxos USDG deposit wallet – as provided in the proposal
  • Covered by test:
    • GroveEthereum_20260716_Test.test_ROBINHOOD_onboardPaxosUsdgBridgeRateLimit()

Activate the Robinhood ForeignController

Roles setup

Before the spell
After the spell

Configuration

Test coverage

Covered by tests: - GroveEthereum_20260716_Test.test_ROBINHOOD_almSystemDeployment() - GroveEthereum_20260716_Test.test_ROBINHOOD_almSystemInitialization() - GroveEthereum_20260716_Test.test_ROBINHOOD_bridgedDeliveryAndExecution() - GroveEthereum_20260716_Test.test_ETHEREUM_groveProxyCanFundRobinhoodBridge()

[Robinhood Chain] Onboard the Robinhood Chain Morpho vault for Grove ALM deposits — deposit rate limit (50M USDG/day), unlimited withdrawal, and max exchange rate

GROVE_X_STEAKHOUSE_USDG_VAULT:

  • LIMIT_4626_DEPOSIT key: 0x056c8e9e2046ef2d9e785dd5ffd9eeb475b862bf46f551cf91825eab45225e48 - recomputed and matches keccak256(abi.encode(LIMIT_4626_DEPOSIT, vault))
  • maxAmount = 50,000,000e6, slope = 50,000,000e6 / 1 days – as stated in the proposal
  • LIMIT_4626_WITHDRAW -> unlimited (type(uint256).max, slope 0)
  • setMaxExchangeRate(vault, 1e18, 1.15e6)
  • Covered by test:
    • GroveEthereum_20260716_Test.test_ROBINHOOD_onboardGroveXSteakhouseUsdgVault()

[Ethereum] Transfer the full Grove syrupUSDC balance to the Spark ALM Proxy, with the equivalent USDS value returned by the coordinated Spark spell (Sky ecosystem request)

  • Token: syrupUSDC
  • Source: Grove ALM Proxy (Ethereum.ALM_PROXY)
  • Destination: Spark ALM Proxy (SparkContracts.ALM_PROXY)
  • Amount: full balance - live Grove balance = 85,943,747.637271 syrupUSDC, matching the value pinned in the test (GROVE_SYRUP_USDC_BALANCE)
  • Covered by test:
    • GroveEthereum_20260716_Test.test_ETHEREUM_transferSyrupUsdcToSpark()

Development Stage Checklist

Preparation

  • LIST every commit since the last externally reviewed spell:

    • 0010b42 feat: create 20260716 spell
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • 81b0298 test: improve tests
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • c9c9ac7 ci: wire ROBINHOOD_RPC_URL into test workflow
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • 15fa507 feat: set Paxos USDC and USDG deposit wallet addresses
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • e1c047b feat: wire deployed Robinhood payload into Ethereum spell
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
      • Note: commit changes were reverted by 802b213
    • 802b213 fix: address July 16 spell review feedback
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • c8fc435 feat: transfer all syrupUSDC from the ALM Proxy to the Spark ALM Proxy
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • 8ee6ac1 fix: lower Paxos bridge and Steakhouse vault rate limits to 25M per day
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
      • Note: commit changes were reverted by aeef113
    • 99eed70 refactor: type the ERC4626 onboarding helper for both controllers
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • 64353ca test: cover Robinhood bridge funding and bridged delivery
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • 9407e0e test: keep foreign forks at execution time after bridged execution
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • 93f9823 test: assert Steakhouse vault underlying and decimals
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • aeef113 fix: restore Paxos bridge and Steakhouse vault rate limits to 50M per day
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • 295fb9d Merge branch ‘main’ into jul-16-spell
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • e92efae chore: address review feedback — trim comments, align formatting, restore warp-back
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • 2ad97ba test: address review feedback in the 20260716 test
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
    • f897cdd test: remove foreign-payload warp-back for delayed executors
      • Content matches description: no unrelated changes.
      • No security-related changes are present in this commit.
  • Verify solc version matches the Prime Agent protocol standard based on prior contracts.

Spell Description & Comments

  • Spell PR has clear description.
  • Spell contract has a clear description. — NatSpec title/author on both GroveEthereum_20260716 and GroveRobinhood_20260716.
  • Every significant action and parameter change are clearly commented in the code. — each action has an // [Chain] Item N: comment + forum link.
  • Every significant action has valid source url (forum post, poll, atlas).
  • Every parameter change is clearly commented with before/after values. — // BEFORE: 0 on every rate-limit/exchange-rate arg.

Proposed changes

  • LIST every forum post proposing changes for this Prime Agent / target date:
  • Verify spell content matches the combined scope of the forum posts.
  • Verify forum posts contain all new addresses, constructor arguments and rate limits.

Contract Structure & Code Quality

  • The only external non-view function in the spell contract is execute().
  • There are no methods that can modify contract state after deployment.
  • No unused imports, interfaces, methods, or variables.
  • All function visibility modifiers are explicitly declared.
  • No redundant code or commented-out functionality.
  • Addresses fetched from the registry where present, otherwise constant with trusted source. — mainnet uses Ethereum.* / SparkContracts.*, Robinhood uses local constants (registry has no Robinhood.* yet).
  • LIST every address used in the spell:

StarGuard execution

  • IF a StarGuard module is onboarded, the following checks are done:
    • The spell exposes view-only interface function isExecutable() external view returns (bool result).
    • isExecutable returns true
    • The test ensures the spell is executable before expiration (i.e. isExecutable outputs true before StarGuard.maxDelay() is passed).
    • Third-party actors can not take advantage of the fact that Spell will be executed in a later block than the Core spell, otherwise suggest direct execution.

On-boarding new contracts

  • [Robinhood] ALM_PROXY
    • Source verified (Blockscout).
    • Source matches audited GitHub source: grove-alm-controller v1.8.0
    • Compilation optimizations match repo.
    • Consistent license.
    • LIST constructor arguments:
    • Access control:
      • Expected admin (GROVE_EXECUTOR) has DEFAULT_ADMIN_ROLE.
      • Deployer has no access.
      • No other addresses have access.
  • [Robinhood] ALM_CONTROLLER
    • Source verified (Blockscout).
    • Source matches audited GitHub source: grove-alm-controller v1.8.0, runtime exact match after resolving 6 external library links, metadata hash identical, all linked libs deployed on Robinhood.
    • Compilation optimizations match repo.
    • Consistent license.
    • LIST constructor arguments (verified via getters):
    • Access control:
      • Expected admin (GROVE_EXECUTOR) has DEFAULT_ADMIN_ROLE.
      • Deployer has no access.
      • No other addresses have access (FREEZER / RELAYER ungranted pre-spell, set at spell exec).
  • [Robinhood] ALM_RATE_LIMITS
    • Source verified (Blockscout).
    • Source matches audited GitHub source: grove-alm-controller v1.8.0
    • Compilation optimizations match repo.
    • Consistent license.
    • LIST constructor arguments:
    • Access control:
      • Expected admin (GROVE_EXECUTOR) has DEFAULT_ADMIN_ROLE.
      • Deployer has no access.
      • No other addresses have access (CONTROLLER ungranted pre-spell).
  • [Robinhood] GROVE_EXECUTOR
    • Source verified (Blockscout).
    • Source matches audited GitHub source: grove-gov-relay v1.2.0
    • Compilation optimizations match repo.
    • Consistent license.
    • LIST constructor arguments:
      • delay = 86400 (1 day), gracePeriod = 604800 (7 days)
        • The value has valid external source.
    • Access control:
  • [Robinhood] ROBINHOOD_GROVE_RECEIVER

Dependency checks

  • LIST every submodule / imported code:
    • grove-alm-controller v1.8.0
      • Matches audited commit.
      • Matches the deployed Robinhood ALM contracts
    • grove-gov-relay @ f314e24
      • Executor matches v1.1.0 audited version–
      • Matches the deployed Robinhood Executor contract
    • xchain-helpers v1.2.0
      • Matches audited commit.
      • Matches the deployed Robinhood ArbitrumReceiver contract
    • grove-address-registry @ ca03516
      • Matches audited commit. – we assume any changes here are trusted
    • spark-address-registry @ d324708
      • Matches audited commit. – we assume any changes here are trusted

Interfaces

  • No unused static interfaces.
  • Declared interfaces not duplicating standard libs.
  • Interface matches the deployed contract.
  • Each static interface declares only functions actually used in the spell code.

Variable Declarations

  • Every contract variable is constant or immutable.
  • Every precision variable matches expected value
  • LIST every precision variable:
    • 50_000_000e6 – items 1c, 2
      • The precision matches source.
    • 50_000_000e6 / 1 days - slopes for all three limits
      • The precision matches source.
    • 1e18 (shareUnit) - groveUSDG shares
      • The precision matches source.
    • 1.15e6 - maxAssetsPerShare
      • The precision matches source.
  • Rates expressed correctly.
  • Rates match their source.

Deployment & Execution Security

  • No selfdestruct().
  • No delegatecall() to untrusted contracts.
  • No tx.origin.
  • No external calls that could revert and fail execution.
  • No loops with unbounded gas.
  • No timestamp-dependent logic across the GSM delay.
  • All math checked.
  • No unchecked return values.

Access Control

  • Spell execution cannot be front-run.
  • No privileged functions accessible by unauthorized users.

Parameter Changes & Protocol Integration

  • Protocol invariants maintained.
  • All parameter changes use the appropriate helper functions IF available.
  • Parameter changes match the Executive Sheet / Atlas edit.
  • Spell interacts correctly with existing components.
  • Proper error handling for external interactions.

Testing

  • LIST each spell action:
    • _onboardPaxosUsdcBridgeRateLimit (Mainnet Item 1c) tested via test_ETHEREUM_onboardPaxosUsdcBridgeRateLimit
      • The unit test ensures the new value was changed in the spell.
      • The end-to-end test is sufficient to ensure correctness the high-level goal behind this spell action.
    • _transferSyrupUsdcToSpark (Item 3) tested via test_ETHEREUM_transferSyrupUsdcToSpark
      • The unit test ensures the new value was changed in the spell.
      • The end-to-end test is sufficient to ensure correctness the high-level goal behind this spell action.
    • _initializeLiquidityLayer (Robinhood Item 1b) tested via test_ROBINHOOD_almSystemDeployment, test_ROBINHOOD_almSystemInitialization
      • The unit test ensures the new value was changed in the spell.
      • The end-to-end test is sufficient to ensure correctness the high-level goal behind this spell action.
    • _onboardPaxosUsdgBridge (Robinhood Item 1c) tested via test_ROBINHOOD_onboardPaxosUsdgBridgeRateLimit
      • The unit test ensures the new value was changed in the spell.
      • The end-to-end test is sufficient to ensure correctness the high-level goal behind this spell action.
    • _onboardGroveXSteakhouseUsdgVault (Robinhood Item 2) tested via test_ROBINHOOD_onboardGroveXSteakhouseUsdgVault
      • The unit test ensures the new value was changed in the spell.
      • The end-to-end test is sufficient to ensure correctness the high-level goal behind this spell action.
  • Robinhood governance-relay delivery (Robinhood Items 1b/1c/2) tested via test_ROBINHOOD_bridgedDeliveryAndExecution, test_ETHEREUM_groveProxyCanFundRobinhoodBridge
    • The unit test ensures the new value was changed in the spell.
    • The end-to-end test is sufficient to ensure correctness the high-level goal behind this spell action.
  • All actions are covered by tests.
  • Integration tests verify end-to-end execution flow.
  • Gas tests ensure execution within block gas limit
  • All tests are passing in CI at f897cdd3e1ddd10060b1434ecdcd6f3ef4b74cb4.
  • All tests listed above are not skipped
  • All tests are passing locally at f897cdd3e1ddd10060b1434ecdcd6f3ef4b74cb4:
[PASS] test_AVALANCHE_ForeignRecipientsSet() (gas: 3343903)
[SKIP] test_AVALANCHE_PayloadBytecodeMatches() (gas: 0)
[PASS] test_BASE_ForeignRecipientsSet() (gas: 3223789)
[SKIP] test_BASE_PayloadBytecodeMatches() (gas: 0)
[PASS] test_ETHEREUM_ExecutionCost() (gas: 3340345)
[PASS] test_ETHEREUM_ForeignRecipientsSet() (gas: 3368752)
[PASS] test_ETHEREUM_PauAllocatorIlkHasZeroFee() (gas: 21162)
[PASS] test_ETHEREUM_PayloadBytecodeMatches() (gas: 1876406)
[PASS] test_ETHEREUM_PsmFeesAreZero() (gas: 3355440)
[PASS] test_ETHEREUM_groveProxyCanFundRobinhoodBridge() (gas: 10128)
[PASS] test_ETHEREUM_onboardPaxosUsdcBridgeRateLimit() (gas: 11264977)
[PASS] test_ETHEREUM_transferSyrupUsdcToSpark() (gas: 3353566)
[PASS] test_PLUME_ForeignRecipientsSet() (gas: 3160115)
[SKIP] test_PLUME_PayloadBytecodeMatches() (gas: 0)
[PASS] test_ROBINHOOD_PayloadBytecodeMatches() (gas: 1995760)
[PASS] test_ROBINHOOD_almSystemDeployment() (gas: 250631)
[PASS] test_ROBINHOOD_almSystemInitialization() (gas: 3137194)
[PASS] test_ROBINHOOD_bridgedDeliveryAndExecution() (gas: 861671)
[PASS] test_ROBINHOOD_onboardGroveXSteakhouseUsdgVault() (gas: 4222021)
[PASS] test_ROBINHOOD_onboardPaxosUsdgBridgeRateLimit() (gas: 3766932)