The HyperliquidGridStrategy lets a syndicate run a grid-trading book across whitelisted Hyperliquid perp assets. USDC is pulled from the vault and parked on HyperCore margin via the L1Write precompile. A keeper EOA (the proposer) drives the grid by calling updateParams every ~60s with batched limit orders. The strategy keeps an on-chain mirror of every resting GTC CLOID it has placed, so settlement can self-cancel without keeper assistance.
Not yet available on Robinhood testnet (chain 46630), Sherwood’s current deployment target. This strategy depends on Hyperliquid/HyperEVM precompiles and will come online as Sherwood expands to more chains.
This strategy holds leveraged perp positions on a centralized-matching venue. A run-away market or keeper outage can leave grids one-sided; HyperCore liquidations destroy vault equity up to the deposit. Use conservative leverage, set per-order and per-tick caps at init, and monitor positions directly on Hyperliquid.
Architecture
Lifecycle
| Phase | What happens | Who calls |
|---|
| Execute | Pull USDC → bridgeUsdcToSpot (EVM → HC spot via Circle) → sendUsdClassTransfer (spot → perp margin). Leverage is set off-chain via the exchange API before the proposal opens. | Governor (proposal execution) |
| Finalize-for-HyperCore | One-time finalizeForHyperCore(0, FinalizeVariant.FirstStorageSlot, 0) so HC auto-credits bridged USDC to this clone’s spot account. initialize() stamps address(this) into slot 0 (_hcSelf); HC reads it post-block to confirm registration — no deployer-nonce math. The CLI runs it as a separate tx immediately after initialize(). | Proposer |
| Executed | Keeper calls updateParams with one of: place batch of GTC orders, cancel a list of CLOIDs, atomic cancel-and-place. Each order’s CLOID is tracked in _liveCloids[ai]. | Proposer only |
| Book accounting | While Executed, the strategy tracks its own HyperCore equity (L1Read.accountMarginSummary) for keeper/monitoring purposes. This is the strategy’s internal book — it is not a vault live-NAV source. Vault deposits/redeems during the proposal go through the Lane B async queue. | Keeper (read) |
| Settle | Walk every tracked CLOID and cancel, then force-close all asset positions (reduce-only IOC at min/max price), then request async USD transfer back to spot. | Governor |
| Sweep | sweepToVault() pushes USDC to the vault when async transfer arrives. Repeatable for partial arrivals. initiateReturn() is permissionless and re-runs the spot transfer if residual perp equity remains. | Anyone |
Batch Calls
Execute
Settle
After settle(), anyone can call strategy.sweepToVault() once the async USD transfer lands. Funds can only flow to the vault.
InitParams
On-chain risk caps:
leverage must be 1–50; maxOrderSize and maxOrdersPerTick must be non-zero
assetIndices is bounded at 32 entries; trading any non-whitelisted asset reverts with AssetNotWhitelisted
- Each individual order’s
sz * limitPx / 1e6 must be ≤ maxOrderSize — OrderTooLarge otherwise. This is a per-order bound, not a cumulative exposure cap; the keeper is trusted to compose grids correctly within whitelisted assets.
- A single
updateParams call may not place more than maxOrdersPerTick orders (TooManyOrders)
Proposer Actions (Executed state)
Encoded as updateParams(abi.encode(action, ...)):
| Action | Encoding | Description |
|---|
1 — place grid | (uint8, GridOrder[]) | Place a batch of GTC limit orders. Each GridOrder is (assetIndex, isBuy, limitPx, sz, cloid). CLOIDs are tracked on-chain so settlement can self-cancel. |
2 — cancel | (uint8, uint32 assetIndex, uint128[] cloids) | Cancel an explicit list of CLOIDs by asset. |
3 — cancel-and-place | (uint8, uint32 assetIndex, uint128[] cancelCloids, GridOrder[] orders) | Atomic: cancel given CLOIDs then place the new batch. Used to refresh a side of the grid in one tx. |
Position state is not tracked on-chain — the keeper reads HyperCore directly (L1Read.position2) to know fills. The on-chain CLOID mirror exists purely so _settle can self-cancel resting orders before the IOC sweep.
Vault Liquidity During a Proposal
This strategy is Lane B only by design — it does not override positions(), so the vault reports no priceable position and there is no oracle instant-lane. While a grid proposal is active, vault deposits and redeems go through the Lane B async queue: requestDeposit / requestRedeem escrow in the VaultWithdrawalQueue and settle at the single frozen, realized per-proposal price stamped when the proposal settles. Outside a proposal, entry/exit is instant ERC-4626 against vault float. See Deposits & Withdrawals for the full two-lane model.
Internal book accounting
Separately from vault NAV, the strategy tracks its own HyperCore book for keeper and monitoring purposes: it sums HyperCore perp equity (L1Read.accountMarginSummary), HyperCore spot USDC, and the strategy’s EVM USDC balance, all in USDC-6-decimal units, reconciling that observable total against the in-flight high-water mark (inFlightToHc) with a Circle-fee-sized tolerance (a cross-block bridge window falls back to inFlightToHc so the internal figure stays stable). This is the strategy’s private accounting — the vault never reads it as a live-NAV source; vault pricing during a proposal is Lane B only.
Risk Notes
- HyperCore registration is required before execute. The CLI calls
finalizeForHyperCore(0, FinalizeVariant.FirstStorageSlot, 0) immediately after initialize(). Without it, the EVM → HC-spot bridge in _execute() can’t auto-credit the clone’s HC spot account, so the subsequent spot → perp class transfer operates on an empty balance and the funds never reach margin. finalizeForHyperCore reverts with AlreadyFinalized if called twice.
- Settlement order matters.
_settle walks _liveCloids[asset] from the tail and pops, guaranteeing resting orders are cancelled before the reduce-only IOC sweep. This eliminates the race where a resting buy could fill against the force-close at a stale price.
- Async settlement.
settle() does not immediately return funds. After IOC fills, residual perp balance lingers; sweepToVault() may need to be called multiple times. initiateReturn() is permissionless and re-runs the spot transfer if any perp equity remains.
- Liquidation: HyperCore liquidates positions that breach maintenance margin. The on-chain contract has no view into liquidation state — settlement and sweep still work, but returned USDC may be well below
depositAmount.
- No off-chain risk system on-chain. Per-order caps are the only on-chain limit. Cumulative grid exposure is the keeper’s responsibility.
CLI Usage
| Flag | Description | Default |
|---|
--amount <n> | USDC collateral to deploy (omit to use full vault balance at execute time) | dynamic-all |
--leverage <n> | Per-asset leverage (1–50) | 5 |
--max-order-size <amount> | Max USD per individual order | 10000 |
--max-orders-per-tick <n> | Max orders placed per updateParams call | 20 |
--asset-indices <list> | Comma-separated HyperCore perp asset indices | 0 |
After the proposal executes, the keeper drives the grid with sherwood proposal update-params using the action encodings above. A reference grid loop ships in cli/src/grid/ — see cli/src/grid/SKILL.md for the signal stack and ATR-based level placement.
Addresses (HyperEVM reference)
| Contract | Address |
|---|
| HyperliquidGridStrategy template | 0x20348e428050031647d671F0e24752C01D4b7379 |
| USDC | 0xb88339CB7199b77E23DB6E890353E22632Ba630f |
| SyndicateFactory | 0xd05Ae0E8bcf13075C29817c805d6Cc14F214393a |
| SyndicateGovernor | 0x67AD3D5F3d127Ef923Fd6f67b178633c408D3fd3 |