# Warp Update Propose

> Warp Update — Propose

- Skill: `hyperlane-xyz/warp-update-propose` (Agent Skill)
- Install (CLI): `npx skillmds@latest add hyperlane-xyz/warp-update-propose`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hyperlane-xyz/warp-update-propose/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: hyperlane-xyz (https://skillmd.com/u/hyperlane-xyz)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/hyperlane-xyz/warp-update-propose

---


# Warp Update — Propose

Run AFTER `/warp-update` (Wave 5; pending) — or any other flow — has executed `hyperlane warp apply` and emitted a receipts directory of per-chain Safe TX Builder JSON files + Squads instruction files. This skill takes those receipts and proposes each batch to its appropriate signer, dispatching automatically by protocol + governance context.

The heavy lifting lives in two infra scripts:

- `typescript/infra/scripts/safes/propose-warp-batch.ts` — reads `combined-chainId<id>-safe<addr8>-<ts>-receipts.json`, auto-detects which governance Safe owns each batch (AW / Foundation / Regular / Irregular / oUSDT), and posts via Safe Transaction Service using the Turnkey EvmLegacyDeployer signer.
- `typescript/infra/scripts/squads/propose-warp-batch.ts` — reads `<chain>-file-<ts>-receipts.json`, rehydrates each tx's `transaction_base58` back into Solana `TransactionInstruction[]`, and proposes via `submitProposalToSquads` using the Turnkey SealevelDeployer signer.

This skill orchestrates running both, surfaces a CONFIRM gate before any propose call lands on chain, and writes a summary the human can use to find proposals in Heimdall / Squads UI.

## Input

- **Linear ticket ID** (required, e.g. `AW-123`) — namespaces the proposal summary artifact.
- **Receipts directory** (required) — absolute path to the dir `warp apply` wrote into. Typically `/tmp/<customer>-<warp-route-id>-txs/` per the `/warp-update` strategy file's `--receipts-dir` arg.
- **Dry-run** (optional, default false) — if set, both underlying scripts run with `--dry-run` (deserialize + log without posting).
- **Chain filter** (optional, comma-separated) — limits which files are proposed. Passed through to both scripts as `--chain-filter`.

If the ticket ID or receipts dir is missing, ask the user.

### Artifact Context (Optional)

If `~/.hyperlane/update-context/<ticket-id>.yaml` exists (produced by `/warp-update-resolve-artifacts`), auto-load it for cross-referencing. Use it to enrich the inventory output (Step 1) with the artifact types each batch covers (router / proxyAdmin / fee:routing / fee:linear / ism / hook). If the file is missing, fall back to filename-only classification — the propose scripts work either way.

---

## Step 1: Inventory the Receipts Directory

List the JSON files in the directory and classify each by filename pattern:

```bash
ls <receipts-dir>/*.json
```

Two recognized patterns (from `typescript/cli/src/apply/warp.ts:writeCombinedBundles` and `typescript/deploy-sdk/src/AltVMFileSubmitter.ts`):

- `combined-chainId<id>-safe<addr8>-<ts>-receipts.json` → EVM Safe batch (`gnosisSafeTxBuilder` submitter)
- `<chain>-file-<ts>-receipts.json` → a **file-submitter** batch (`AltVMFileSubmitter`). This is NOT SVM-specific: the `file` submitter is used for any chain/owner without a native submitter — Sealevel/Squads, but also Cosmos/Starknet/Radix/Aleo, and EVM chains whose owner routes to `file` (Turnkey / timelock / custom multisig / ICA-controlled-by-EOA, per `/warp-update` Step 4a). Derive the protocol from the **chain name**, not from the `-file-` suffix.

For each file, derive:

- Chain name, then its protocol from the chain's metadata — do NOT assume `-file-` means SVM.
- For EVM Safe batches: the 8-hex safe prefix → resolve to a full safe address by cross-referencing every `GovernanceType` via the existing `getSafesByGovernanceForChain(chain)` helper. The first matching governance type wins.
- For a **Sealevel** file batch: the chain's Squads `multisigPda` from `squadsConfigs[chain]` — these are the only file batches the Squads propose script (§4b) handles.
- For any **other** file batch (Cosmos/Starknet/Radix/Aleo, or an EVM `file`-routed owner): there is no auto-propose path — mark it for **explicit human hand-off** (§4b), do not classify it as SVM.
- Tx count from the file body (parse JSON, count `transactions[]` for EVM Safe batches or `PrintableSvmTransaction[]` for file batches).

Files matching neither pattern: list as "skipped" with a clear reason. The propose scripts also skip them, so this is just a visibility pass.

Show the user the inventory:

```
EVM Safe batches (3 files):
  - combined-chainId1-safe3965AC3D-1234-receipts.json
      → ethereum, AW Safe (0x3965AC3D295641E452E0ea896a086A9cD7C6C5b6), 4 txs
  - combined-chainId42161-safe645FE065-1234-receipts.json
      → arbitrum, AW ICA (0x645FE06507C8a188494d3E755B248a8dbF3bd875), 3 txs
  - combined-chainId8453-safe8Ff4c563-1234-receipts.json
      → base, Foundation warpFees Safe (0x8Ff4c563f26db00e65bD93d9f662A51c304C09b0), 2 txs

SVM Squads batches (1 file):
  - solanamainnet-file-1234-receipts.json
      → solanamainnet, Squads multisig EvptYJrjGUB3FXDoW8w8LTpwg1TTS4W1f628c1BnscB4, 2 instructions

Skipped (0 files): —
```

If an artifact context is loaded, append per-batch artifact-coverage info ("this batch covers router on arbitrum + proxyAdmin on arbitrum") drawn from `groupedByOwner` in the context.

---

## Step 2: Cross-Reference Against Artifact Context (if loaded)

For each EVM batch:

- Look up the resolved safe address in the artifact context's `groupedByOwner` table.
- Confirm the governance type matches. If the context says `Foundation` but Step 1 resolved `AW`, surface a warning — likely a stale artifact context or a deploy.yaml drift.

For each SVM batch:

- Look up the multisig PDA in `squadsConfigs[chain]`.
- Cross-check against any Squads-type owners in the artifact context.

These are warnings only — they don't block the propose. If anything is genuinely wrong the human catches it at the CONFIRM gate.

---

## Step 3: Confirmation Gate

Show the full proposal plan in a single message:

```
About to propose <N> batches across <M> chains for ticket <ticket-id>.

EVM:
  - ethereum / AW Safe / 4 txs
  - arbitrum / AW ICA / 3 txs
  - base / Foundation warpFees Safe / 2 txs

SVM:
  - solanamainnet / Squads (EvptYJrj…URwJ) / 2 instructions

Signers:
  - EVM via Turnkey EvmLegacyDeployer (0xa7ECcdb9…d9Ba — AW + Foundation owner)
  - SVM via Turnkey SealevelDeployer

Dry-run: <yes/no>
Output artifact: ~/.hyperlane/proposals/<ticket-id>.yaml
```

End the message with:

```test
[CONFIRM: Propose <N> batches for <ticket-id>]
```

> **Note:** `[CONFIRM: ...]` is a Haggis-specific harness primitive — Haggis renders it as an inline approve/reject button. In other Claude Code contexts it is just text.

Do not proceed to Step 4 until the user confirms.

---

## Step 4: Execute Per Protocol

Run the two scripts in sequence (EVM first, then SVM). Both scripts handle per-file partial-success internally; one file failing doesn't block the rest.

### 4a. EVM Safe batches (skip if zero EVM files)

```bash
pnpm -C typescript/infra exec tsx scripts/safes/propose-warp-batch.ts \
  --directory <receipts-dir> \
  [--dry-run] \
  [--chain-filter <chains>]
```

The script:

- Walks `combined-*-safe*-receipts.json` files in the directory
- Auto-detects governance type per filename safe prefix via `getSafesByGovernanceForChain`
- Initializes the Turnkey EvmLegacyDeployer signer via `createTurnkeySigner('mainnet3', TurnkeyRole.EvmLegacyDeployer)`
- Wraps each file's `transactions[]` into a single multiSend via `createSafeTransaction(safeSdk, txData, /*onlyCalls=*/true)`
- Calls the refactored `proposeSafeTransaction(...)` which uses `signer._signTypedData` (Turnkey signs the EIP-712 hash directly — no raw key extraction)
- Prints per-file result + final summary table

Capture the script's stdout/stderr. Map each per-file result back to the inventory.

### 4b. SVM Squads batches (skip if zero SVM files)

```bash
pnpm -C typescript/infra exec tsx scripts/squads/propose-warp-batch.ts \
  --directory <receipts-dir> \
  [--dry-run] \
  [--chain-filter <chains>]
```

The script:

- Walks `<chain>-file-*-receipts.json` files
- Filters to Sealevel chains
- Initializes the Turnkey SealevelDeployer signer via `getTurnkeySealevelDeployerSigner(...)`
- Rehydrates each tx's `transaction_base58` via `VersionedTransaction.deserialize` + `TransactionMessage.decompile`
- Calls `submitProposalToSquads(chain, instructions, mpp, signerAdapter, memo)` per file
- Prints per-file result + final summary table

**Non-Sealevel file batches are silently filtered out here.** The `Filters to Sealevel chains` step drops any `<chain>-file-*` batch whose chain isn't Sealevel — so a Cosmos/Starknet/Radix/Aleo batch, or an EVM `file`-routed owner batch, is neither proposed nor reported as failed. Cross-check the §1 inventory: every file batch this script did not propose must be surfaced for **explicit human hand-off** (§6). Never report the ticket's proposals complete while a non-Sealevel file batch sits unproposed.

Capture the script's output similarly.

### Per-script failure handling

If a script exits non-zero (every file failed), DO NOT abort the orchestrator — log the protocol's failure, mark all its inventory entries as failed, and continue to the other protocol. Total-orchestrator-failure (both scripts had zero successes) results in a non-zero exit at the end.

---

## Step 5: Persist Proposal Summary

Write `~/.hyperlane/proposals/<ticket-id>.yaml`:

```yaml
ticket: <ticket-id>
proposedAt: '<ISO-8601 timestamp>'
receiptsDirectory: <abs-path>
dryRun: <true|false>

evm:
  proposed:
    - file: combined-chainId1-safe3965AC3D-1234-receipts.json
      chain: ethereum
      safe: '0x3965AC3D295641E452E0ea896a086A9cD7C6C5b6'
      governanceType: AW
      safeTxHash: '0xabc...'
      txCount: 4
  failed:
    - file: <filename>
      chain: <chain>
      safe: <safe>
      reason: <error>
      txCount: <n>
  skipped:
    - file: <filename>
      reason: <reason>

svm:
  proposed:
    - file: solanamainnet-file-1234-receipts.json
      chain: solanamainnet
      multisigPda: EvptYJrjGUB3FXDoW8w8LTpwg1TTS4W1f628c1BnscB4
      txCount: 2
  failed: []
  skipped: []

summary:
  totalProposed: <n>
  totalFailed: <n>
  totalSkipped: <n>
```

The artifact is consumed by humans who need to track proposal signing progress. Heimdall's UI also surfaces the EVM proposals once Safe Transaction Service has them indexed; Squads UI surfaces the SVM ones.

---

## Step 6: Hand Off

Tell the user:

> **Proposal summary saved to `~/.hyperlane/proposals/<ticket-id>.yaml`.**
>
> Where to track signing:
>
> - **AW Safe + Foundation Safe proposals**: visible in Heimdall (https://hyperlane.usehaggis.com) where executioners — including Haggis — can sign + execute. Heimdall polls Safe Transaction Service periodically; allow a minute for new proposals to appear.
> - **Squads proposals**: surface in the Squads UI at https://app.squads.so/ (or chain-specific equivalent). Solana signers review + sign there.
> - **Customer / Regular Safe proposals**: pushed to Safe Transaction Service directly. The customer signs in their own Safe app at `https://app.safe.global/transactions/queue?safe=<chain-shortname>:<safe-address>`. They'll need to import the safe in their app first if it's not already there.
> - **Other file batches (Cosmos / Starknet / Radix / Aleo, or an EVM `file`-routed owner like Turnkey / timelock / custom multisig)**: no auto-propose path — these were emitted as tx-file batches for manual submission. List each one (chain, owner, file path) and hand it to the owner to execute through their own signing tool; they are NOT proposed on-chain by this skill.

---

## Notes

- **Side effects**: this skill POSTs proposals to Safe Transaction Service / creates Squads on-chain proposals. The actions are reversible — Safe TX Service has a delete-tx API, Squads has a cancel-proposal instruction — but human signers can move quickly. Use `--dry-run` first if anything in the inventory looks off.
- **Idempotency**: re-running with the same receipts dir produces DUPLICATE proposals. Either delete the prior proposals (via the safes script's `safes/delete-tx.ts` or squads' `cancel-proposal.ts`) or don't re-run the same dir.
- **No GCP secrets in this skill**: secret access happens inside the propose scripts, not at the orchestrator level. The skill just shells out.
- **What "auto-detects governance" means**: the safes script walks every `GovernanceType` enum value, calls `getGovernanceSafes(type)[chain]`, and matches the filename's 8-hex prefix against the resolved safe. A single receipts dir can mix multiple governance contexts (router via AW, fee contracts via Foundation, etc.) — the script handles them all in one run.

