Skip to content

Mainnet bridge router deploy — handoff ​

Session 2026-06-24 deployed Hyperlane core on sanect mainnet but stopped before deploying the bridge routers (SanectHypAdapter + WSanectHyp) because of a compile-time blocker. This doc captures the state, the blocker, and the recipe to finish in a dedicated session.

State at handoff ​

✅ Hyperlane core deployed on sanect mainnet (chain 7628). Mailbox at 0x2CB7861CC3dA9148763538C75DdCf5772e5c03e1. Full address table in CLAUDE.md "Hyperlane core (mainnet…)" section. ProxyAdmin owned by protocol-governance EOA 0x4BE2d1eC…0912. Trusted-relayer ISM trusting deployer 0xF88e82c5…0321.

✅ Local registry at ~/.hyperlane/chains/sanect/ has mainnet metadata + addresses. The original testnet addresses.yaml was stale (cached from the testnet bridge work 10 days earlier under chain name "sanect") — we removed it before deploying core. If a future operator works on testnet bridge again, they'll need to re-create that file or use a different chain name.

⛔ Bridge router deploy blocked — forge script DeployHyperlaneBridge fails to compile because:

  1. dex/foundry.toml has skip = ["lib/hyperlane-monorepo/**", "contracts/bridge/**"] (added in commit ae73f49, Jun 15 2026, after OZ got bumped to v5 and Hyperlane's vendored contracts started failing because they import Address.isContract which v5 removed).
  2. The @hyperlane-xyz/core/ remapping isn't in dex/foundry.toml at all.
  3. dex/lib/hyperlane-monorepo/ is gitignored — installed locally via forge install hyperlane-xyz/hyperlane-monorepo but never committed. May or may not be present on a given checkout.

The testnet bridge "just worked" on Jun 14 2026 because at THAT moment forge install OpenZeppelin/openzeppelin-contracts pulled OZ v4 (latest at that point). Later a re-install pulled v5, broke the bridge compile, and the skip was added rather than reverting OZ.

Recipe (next session) ​

1. Install the missing libs (if not already present) ​

bash
cd /mnt/c/Github/sanect-node/dex

# OZ v4 alongside the existing v5 — pinned tag, separate dir
test -d lib/openzeppelin-contracts-v4 || \
  git clone --depth 1 -b v4.9.6 \
    https://github.com/OpenZeppelin/openzeppelin-contracts.git \
    lib/openzeppelin-contracts-v4

# Hyperlane monorepo (if absent)
test -d lib/hyperlane-monorepo || \
  forge install hyperlane-xyz/hyperlane-monorepo --no-commit --no-git

2. Add a [profile.bridge] to dex/foundry.toml ​

Don't touch the default profile — the dex tree relies on OZ v5. Add a separate profile that switches to v4 + adds the Hyperlane remapping + clears the skip list:

toml
[profile.bridge]
src = "contracts"
out = "out-bridge"
libs = ["lib"]
script = "script"
solc_version = "0.8.24"
optimizer = true
optimizer_runs = 999999
via_ir = false
skip = []
remappings = [
    "forge-std/=lib/forge-std/src/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts-v4/contracts/",
    "@hyperlane-xyz/core/=lib/hyperlane-monorepo/solidity/",
]

Build target separate (out-bridge/) so the dex profile's out/ artifacts stay clean.

3. Verify compile ​

bash
cd /mnt/c/Github/sanect-node/dex
FOUNDRY_PROFILE=bridge forge build --contracts contracts/bridge

Must succeed before going near a hardware wallet.

4. Deploy (assumes core mainnet addresses from current session) ​

bash
export RPC_URL=https://rpc.sanect.com
export ETH_RPC_URL=https://ethereum-rpc.publicnode.com   # or Alchemy
export DEPLOYER_PRIVATE_KEY=0x<role-EOA hex>
export SANECT_MAILBOX_ADDR=0x2CB7861CC3dA9148763538C75DdCf5772e5c03e1
export ETH_MAILBOX_ADDR=0xc005dc82818d67AF737725bD4bf75435d065D239
export WSNCT=0x4f35BD61FEd919aA9933C6333e388b3B7E1108Dc

cd /mnt/c/Github/sanect-node/dex

# 4a. SanectHypAdapter on sanect (~0.005 SNCT)
HYP_MAILBOX=$SANECT_MAILBOX_ADDR MODE=adapter WSNCT=$WSNCT \
  FOUNDRY_PROFILE=bridge \
  forge script script/DeployHyperlaneBridge.s.sol:DeployHyperlaneBridge \
    --rpc-url $RPC_URL --broadcast --private-key $DEPLOYER_PRIVATE_KEY -vvv
# Capture: ADAPTER=<deployed addr>

# 4b. WSanectHyp synthetic on Ethereum (~0.0006 ETH at 0.2 gwei)
HYP_MAILBOX=$ETH_MAILBOX_ADDR MODE=synthetic \
  FOUNDRY_PROFILE=bridge \
  forge script script/DeployHyperlaneBridge.s.sol:DeployHyperlaneBridge \
    --rpc-url $ETH_RPC_URL --broadcast --private-key $DEPLOYER_PRIVATE_KEY -vvv
# Capture: SYNTHETIC=<deployed addr>

# 4c. Enroll on sanect side (~0.0001 SNCT)
cast send $ADAPTER "enrollRemoteRouter(uint32,bytes32)" \
  1 $(cast --to-uint256 $SYNTHETIC) \
  --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY

# 4d. Enroll on Ethereum side (~0.0001 ETH)
cast send $SYNTHETIC "enrollRemoteRouter(uint32,bytes32)" \
  7628 $(cast --to-uint256 $ADAPTER) \
  --rpc-url $ETH_RPC_URL --private-key $DEPLOYER_PRIVATE_KEY

5. Stand up relayer ​

docs/mainnet-bridge-setup.md Step 3 (Docker container) — unchanged from the existing runbook. Pre-fund relayer wallet with ~0.02 ETH on Ethereum (covers ~300 inbound deliveries at current gas) and ~5 SNCT on sanect.

6. Round-trip test ​

docs/mainnet-bridge-setup.md Step 4 — 1-wei round trip.

7. Update CLAUDE.md ​

Add bridge router addresses to the "Hyperlane core (mainnet…)" section.

Notes for the next operator ​

  • Deployer balance at handoff: 9.94 SNCT + 0.0647 ETH. Bridge router deploy + enrollment burns ~0.006 SNCT + ~0.001 ETH at current gas. Plenty of headroom.
  • Stale ~/.hyperlane/chains/sanect/addresses.yaml was deleted during this session. The current file has mainnet addresses — don't let testnet work overwrite it.
  • Verification on Blockscout: Hyperlane CLI failed to auto-verify every deployed contract because Blockscout returns HTML at /api instead of Etherscan-shape JSON. Contracts work regardless. If we want the "Verified" badge on scan.sanect.com, paste source via Blockscout UI manually (Hyperlane contracts are all public source on the github monorepo).
  • Ethereum L1 canonical Mailbox (0xc005dc…D239) hasn't changed in the Hyperlane ecosystem; safe to reuse.
  • Day-7 ISM upgrade: testnet uses single TrustedRelayerIsm. Mainnet should upgrade to MessageIdMultisigIsm + multi-validator set before meaningful bridge volume. See existing docs/mainnet-bridge-setup.md Step "Day-7 follow-up".