Skip to content

Commit c2d98cb

Browse files
committed
Merge remote-tracking branch 'origin/main' into dango
2 parents df4a7f8 + 776cc85 commit c2d98cb

856 files changed

Lines changed: 104831 additions & 32557 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/config.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
"@hyperlane-xyz/cli",
1111
"@hyperlane-xyz/cosmos-sdk",
1212
"@hyperlane-xyz/cosmos-types",
13-
"@hyperlane-xyz/eslint-config",
1413
"@hyperlane-xyz/github-proxy",
1514
"@hyperlane-xyz/helloworld",
1615
"@hyperlane-xyz/http-registry-server",

.claude/skills/verify-warp-contracts/SKILL.md

Lines changed: 348 additions & 0 deletions
Large diffs are not rendered by default.

.claude/skills/warp-route-check/skill.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,117 @@ hyperlane warp check \
398398

399399
**NOTE**: Warp check may show provider errors for newly added chains - this is expected.
400400

401+
### Step 8b: Test transferRemote on Fork
402+
403+
After verifying configuration with `warp check`, test that an actual token transfer works on the forked chains. This catches issues that config checks miss: broken `transferRemote` calldata, token accounting bugs (lock/mint/burn/unlock), and message dispatch failures.
404+
405+
#### 8b.1 Pick an Origin → Destination Pair
406+
407+
Choose one origin → destination pair from the warp route. Prefer a pair where both chains have transactions (i.e., both were modified), so you're testing the freshly configured path.
408+
409+
#### 8b.2 Bypass ISM on Destination (Required for Self-Relay)
410+
411+
Forked mainnet chains have real multisig ISMs that require validator signatures. Since there are no validators on anvil forks, you must set a permissive ISM on the destination so self-relay can deliver the message.
412+
413+
```bash
414+
# 1. Get the mailbox address for the destination chain from the forked registry
415+
DEST_MAILBOX=$(cast call <warp-router-address> "mailbox()(address)" --rpc-url http://localhost:<DEST-PORT>)
416+
417+
# 2. Get the mailbox owner
418+
MAILBOX_OWNER=$(cast call $DEST_MAILBOX "owner()(address)" --rpc-url http://localhost:<DEST-PORT>)
419+
420+
# 3. Get the current default ISM (to restore later if needed)
421+
OLD_ISM=$(cast call $DEST_MAILBOX "defaultIsm()(address)" --rpc-url http://localhost:<DEST-PORT>)
422+
423+
# 4. Deploy Hyperlane's TestIsm.
424+
# TestIsm returns Types.NULL from moduleType() and true from verify(bytes,bytes),
425+
# so `hyperlane warp send --relay` uses null metadata instead of trying to derive
426+
# multisig/routing metadata on the fork.
427+
TEST_DEPLOYER_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
428+
# Ensure Foundry dependencies are materialized in fresh worktrees/checkouts.
429+
pnpm -C solidity deps:soldeer
430+
TEST_ISM_ADDRESS=$(forge create \
431+
--root solidity \
432+
--broadcast \
433+
--rpc-url http://localhost:<DEST-PORT> \
434+
--private-key $TEST_DEPLOYER_KEY \
435+
contracts/test/TestIsm.sol:TestIsm \
436+
| awk '/Deployed to:/ {print $3}')
437+
438+
# Confirm the fork bypass ISM has the expected Hyperlane behavior:
439+
# moduleType() == 6 (Types.NULL) and verify(...) == true.
440+
cast call $TEST_ISM_ADDRESS "moduleType()(uint8)" --rpc-url http://localhost:<DEST-PORT>
441+
cast call $TEST_ISM_ADDRESS "verify(bytes,bytes)(bool)" 0x 0x --rpc-url http://localhost:<DEST-PORT>
442+
443+
# 5. Impersonate mailbox owner and set the permissive ISM
444+
cast rpc anvil_impersonateAccount $MAILBOX_OWNER --rpc-url http://localhost:<DEST-PORT>
445+
BALANCE="0x56BC75E2D63100000"
446+
cast rpc anvil_setBalance $MAILBOX_OWNER $BALANCE --rpc-url http://localhost:<DEST-PORT>
447+
cast send $DEST_MAILBOX "setDefaultIsm(address)" $TEST_ISM_ADDRESS --from $MAILBOX_OWNER --rpc-url http://localhost:<DEST-PORT> --unlocked
448+
cast rpc anvil_stopImpersonatingAccount $MAILBOX_OWNER --rpc-url http://localhost:<DEST-PORT>
449+
```
450+
451+
**NOTE**: If the warp router has a custom ISM set (not using the mailbox default), you'll need to impersonate the router owner and call `setInterchainSecurityModule(address)` on the router instead.
452+
453+
#### 8b.3 Fund the Test Sender
454+
455+
```bash
456+
# Generate a test private key (or use a well-known anvil key)
457+
TEST_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
458+
TEST_SENDER="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" # Anvil account 0
459+
460+
# Fund with native gas on origin
461+
cast rpc anvil_setBalance $TEST_SENDER "0x56BC75E2D63100000" --rpc-url http://localhost:<ORIGIN-PORT>
462+
463+
# For collateral/ERC20 routes: mint or transfer tokens to the test sender
464+
# Option A: If the token has a mint function (e.g., test tokens)
465+
# cast send <token-address> "mint(address,uint256)" $TEST_SENDER 1000000000000000000 ...
466+
467+
# Option B: Impersonate a whale holder and transfer
468+
# Find a top holder from the fork state, impersonate, and transfer
469+
# cast rpc anvil_impersonateAccount <whale> --rpc-url http://localhost:<ORIGIN-PORT>
470+
# cast send <token-address> "transfer(address,uint256)" $TEST_SENDER <amount> --from <whale> --rpc-url http://localhost:<ORIGIN-PORT> --unlocked
471+
472+
# Option C: For native token routes, setBalance is sufficient (already done above)
473+
474+
# Also fund on destination for self-relay gas
475+
cast rpc anvil_setBalance $TEST_SENDER "0x56BC75E2D63100000" --rpc-url http://localhost:<DEST-PORT>
476+
```
477+
478+
#### 8b.4 Run the Transfer
479+
480+
```bash
481+
HYP_KEY=$TEST_KEY \
482+
hyperlane warp send \
483+
--registry <YOUR-ACTUAL-forked-registry-url-from-step-4> \
484+
--warp-route-id <warp-route-id> \
485+
--origin <origin-chain> \
486+
--destination <destination-chain> \
487+
--amount 1 \
488+
--relay \
489+
--skip-validation \
490+
--yes
491+
```
492+
493+
**Key flags:**
494+
495+
- `--relay` — Self-relay the message (no real relayer on forks)
496+
- `--skip-validation` — Skip balance/collateral checks that may fail on forks
497+
- `--amount 1` — Use smallest practical amount (1 wei or 1 unit)
498+
499+
#### 8b.5 Verify Result
500+
501+
- **Success**: The CLI should log `Transfer was self-relayed!` and show the message ID
502+
- **Failure**: Check the error output. Common issues:
503+
- `Ownable: caller is not the owner` on ISM bypass → wrong mailbox owner or router has custom ISM
504+
- `insufficient funds` → test sender not funded with tokens (for collateral routes)
505+
- `message already delivered`ISM bypass not working, retry with router-level ISM override
506+
- Timeout waiting for delivery → self-relay failed, check ISM was properly set
507+
508+
**Capture output** to `/tmp/warp-transfer-test.log` for the final report.
509+
510+
**NOTE**: This step is optional but strongly recommended. If it fails due to ISM complexity (e.g., routing ISMs, aggregation ISMs), document the failure and move on — the config check in Step 8 still validates the deployment.
511+
401512
### Step 9: Interpret Results
402513

403514
Analyze the warp check output carefully:
@@ -516,6 +627,14 @@ Create a comprehensive markdown report with the following sections:
516627

517628
[List of chains not modified and their expected violations]
518629

630+
## Transfer Test Results
631+
632+
- **Origin → Destination**: <chain-a><chain-b>
633+
- **Amount**: <amount>
634+
- **Result**: ✅ Success / ❌ Failed (reason)
635+
- **Message ID**: <id> (if successful)
636+
- **ISM Bypass**: Yes (TestIsm deployed at <address> set on destination mailbox)
637+
519638
## Decoded Transactions (Heimdall Output)
520639

521640
```json

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
typescript/sdk/src/cw-types/*.types.ts linguist-generated=true
2+
typescript/svm-sdk/src/hyperlane/program-bytes.ts linguist-generated=true binary
23
rust/main/chains/hyperlane-ethereum/abis/*.abi.json linguist-generated=true
34
solidity/contracts/interfaces/avs/*.sol linguist-vendored=true
45
solidity/contracts/avs/ECDSA*.sol linguist-vendored=true

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,5 @@ typescript/rebalancer-sim @Mo-Hussain @nambrot @paulbalaji
4040
typescript/relayer @Mo-Hussain @yorhodes @paulbalaji
4141

4242
## Shared Tooling
43-
typescript/eslint-config @xeno097 @paulbalaji
43+
oxlint.json @xeno097 @paulbalaji
4444
typescript/tsconfig @xeno097 @paulbalaji

.github/workflows/claude-code-review.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ jobs:
7777
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
7878
with:
7979
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
80-
prompt: "Use agent teams to run /claude-review, then use /inline-pr-comments to post findings as a consolidated PR review with inline comments"
80+
prompt: 'Use agent teams to run /claude-review, then use /inline-pr-comments to post findings as a consolidated PR review with inline comments'
8181
track_progress: true
8282
use_sticky_comment: false
8383
claude_args: |
@@ -132,7 +132,7 @@ jobs:
132132
PR_NUMBER: ${{ github.event.issue.number }}
133133
with:
134134
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
135-
prompt: "Use agent teams to run /claude-security-review, then use /inline-pr-comments to post findings as a consolidated PR review with inline comments"
135+
prompt: 'Use agent teams to run /claude-security-review, then use /inline-pr-comments to post findings as a consolidated PR review with inline comments'
136136
track_progress: true
137137
use_sticky_comment: false
138138
claude_args: |
@@ -200,7 +200,7 @@ jobs:
200200
PR_NUMBER: ${{ github.event.issue.number }}
201201
with:
202202
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
203-
prompt: "Use agent teams to run /claude-tob-review, then use /inline-pr-comments to post findings as a consolidated PR review with inline comments"
203+
prompt: 'Use agent teams to run /claude-tob-review, then use /inline-pr-comments to post findings as a consolidated PR review with inline comments'
204204
track_progress: true
205205
use_sticky_comment: false
206206
claude_args: |
@@ -271,7 +271,7 @@ jobs:
271271
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
272272
with:
273273
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
274-
prompt: "When you have specific code feedback on changed lines, use /inline-pr-comments to deliver it as a consolidated GitHub review with inline comments."
274+
prompt: 'When you have specific code feedback on changed lines, use /inline-pr-comments to deliver it as a consolidated GitHub review with inline comments.'
275275
track_progress: true
276276
use_sticky_comment: false
277-
claude_args: "--model ${{ env.CLAUDE_SONNET_MODEL }}"
277+
claude_args: '--model ${{ env.CLAUDE_SONNET_MODEL }}'

.github/workflows/ghcr-cleanup.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
hyperlane-agent
4141
hyperlane-monorepo
4242
hyperlane-node-services
43-
image-tags: "pr-*"
43+
image-tags: 'pr-*'
4444
tag-selection: tagged
4545
cut-off: 1w
4646
keep-n-most-recent: 5

.github/workflows/node-services-docker.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ jobs:
128128
|-------|-----|
129129
| hyperlane-node-services | \`${TAG_SHA_DATE}\` |
130130
131-
**Services included:** rebalancer, warp-monitor, ccip-server, keyfunder, relayer
131+
**Services included:** rebalancer, warp-monitor, ccip-server, keyfunder, relayer, fee-quoting
132132
133133
**Full image path:**
134134
\`\`\`

.github/workflows/release.yml

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ on:
1010
- 'typescript/**'
1111
- '!typescript/infra/**'
1212
- '!typescript/ccip-server/**'
13-
- '!typescript/eslint-config/**'
1413
- '!typescript/github-proxy/**'
1514
- '!typescript/http-registry-server/**'
1615
- '!typescript/tsconfig/**'
@@ -31,6 +30,11 @@ on:
3130
- alpha
3231
- rc
3332
- preview
33+
include_zksync:
34+
description: 'Include ZKSync build artifacts (adds ~6min)'
35+
required: false
36+
default: false
37+
type: boolean
3438

3539
concurrency: ${{ github.workflow }}-${{ github.ref }}
3640

@@ -255,6 +259,19 @@ jobs:
255259
- name: Install dependencies
256260
run: pnpm install --frozen-lockfile
257261

262+
# Need to install foundry for the build step. `hardhat-foundry` expects foundry to be installed.
263+
- name: Setup Foundry
264+
uses: ./.github/actions/setup-foundry
265+
266+
# Build BEFORE snapshot versioning so turbo cache hits are preserved.
267+
# Snapshot versioning rewrites every package.json, which invalidates turbo hashes.
268+
- name: Build packages
269+
run: pnpm run build
270+
271+
- name: Build ZKSync artifacts
272+
if: inputs.include_zksync
273+
run: pnpm run build:zk
274+
258275
- name: Create snapshot versions
259276
run: pnpm exec changeset version --snapshot ${{ inputs.snapshot_tag }}
260277

@@ -264,13 +281,6 @@ jobs:
264281
SNAPSHOT_VERSION=$(node -p "require('./typescript/sdk/package.json').version")
265282
echo "snapshot=$SNAPSHOT_VERSION" >> $GITHUB_OUTPUT
266283
267-
# Need to install foundry for the build step. `hardhat-foundry` expects foundry to be installed.
268-
- name: Setup Foundry
269-
uses: ./.github/actions/setup-foundry
270-
271-
- name: Build packages
272-
run: pnpm run build && pnpm run build:zk
273-
274284
- name: Publish beta packages
275285
run: pnpm exec changeset publish --tag ${{ inputs.snapshot_tag }} --no-git-tag
276286
env:
@@ -289,3 +299,31 @@ jobs:
289299
echo "npm install @hyperlane-xyz/sdk@${{ inputs.snapshot_tag }}" >> $GITHUB_STEP_SUMMARY
290300
echo "npm install @hyperlane-xyz/cli@${{ inputs.snapshot_tag }}" >> $GITHUB_STEP_SUMMARY
291301
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
302+
303+
notify-publish-failure:
304+
if: >-
305+
always() && (
306+
needs.publish-release.result == 'failure' ||
307+
needs.check-latest-published.result == 'failure' ||
308+
needs.cli-install-cross-platform-release-test.result == 'failure'
309+
)
310+
needs:
311+
[
312+
check-latest-published,
313+
cli-install-cross-platform-release-test,
314+
publish-release,
315+
]
316+
runs-on: ubuntu-latest
317+
steps:
318+
- name: Notify Slack on publish failure
319+
uses: slackapi/slack-github-action@v3
320+
with:
321+
webhook: ${{ secrets.SLACK_INCIDENTS_WEBHOOK }}
322+
webhook-type: incoming-webhook
323+
payload: |
324+
text: ":red-siren: NPM package publish failed — see workflow run for details"
325+
blocks:
326+
- type: "section"
327+
text:
328+
type: "mrkdwn"
329+
text: ":red-siren: *NPM package publish failed*\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View workflow run #${{ github.run_number }}>"

.github/workflows/rust-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ jobs:
191191
git config user.name "${{ steps.generate-token.outputs.app-slug }}[bot]"
192192
git config user.email "${BOT_USER_ID}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com"
193193
194-
BRANCH_NAME="release-agents-v${NEW_VERSION}"
194+
BRANCH_NAME="release-agents"
195195
196196
# Create branch from current HEAD (which is main)
197197
git checkout -B "$BRANCH_NAME"

0 commit comments

Comments
 (0)