> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sherwood.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Hyperliquid Grid

> On-chain grid trading on Hyperliquid perps via HyperEVM precompiles

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.

<Note>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.</Note>

<Warning>
  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.
</Warning>

## Architecture

```mermaid theme={null}
graph TD
    V["Vault (USDC)"] -->|"execute: pull USDC"| S["HyperliquidGridStrategy clone"]
    S -->|"bridgeUsdcToSpot (Circle CoreDepositWallet)"| C1["HyperCore spot"]
    C1 -->|"sendUsdClassTransfer (spot → perp)"| C2["HyperCore perp margin"]

    P["Proposer / keeper"] -->|"updateParams: place / cancel / cancel-and-place"| S
    S -->|"sendLimitOrder (GTC) + tracked CLOID"| C3["HyperCore orderbook"]

    subgraph "Internal book accounting"
        S -->|"L1Read.accountMarginSummary"| C4["HyperCore equity (strategy's own view)"]
    end

    subgraph "Settlement"
        S2["Strategy clone"] -->|"cancel tracked CLOIDs + force-close + class transfer"| C5["HyperCore"]
        C5 -->|"async arrival"| S3["Strategy clone (EVM side)"]
        S3 -->|"sweepToVault()"| V2["Vault (USDC + P&L)"]
    end
```

## Lifecycle

```
Pending → execute() → finalizeForHyperCore() → Executed → (place/cancel ticks) → settle() → Settled → sweep
```

| 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

```
[USDC.approve(strategy, depositAmount), strategy.execute()]
```

### Settle

```
[strategy.settle()]
```

After `settle()`, anyone can call `strategy.sweepToVault()` once the async USD transfer lands. Funds can only flow to the vault.

## InitParams

```solidity theme={null}
(
  address  asset,             // USDC on HyperEVM
  uint256  depositAmount,     // USDC to park as perp margin (fits in uint64; 0 = full vault balance at execute)
  uint32   leverage,          // 1–50, applied per asset on execute
  uint256  maxOrderSize,      // Per-order USD notional cap (sz * limitPx / 1e6)
  uint32   maxOrdersPerTick,  // Max orders the keeper can place in one updateParams call
  uint32[] assetIndices       // Whitelist of HyperCore perp asset indices the keeper may trade
)
```

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](/protocol/vault-liquidity#lane-b-async-request-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](/protocol/vault-liquidity) 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

```bash theme={null}
sherwood strategy propose hyperliquid-grid \
  --vault 0x... \
  --amount 5000 \
  --leverage 5 \
  --max-order-size 200 \
  --max-orders-per-tick 20 \
  --asset-indices 0,3 \
  --name "BTC+ETH Grid 5x" \
  --duration 7d
```

| 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` |
