feat(sdk): use routing ISM setBatch/removeBatch when available#8656
feat(sdk): use routing ISM setBatch/removeBatch when available#8656paulbalaji wants to merge 1 commit intopbio/routing-ism-batch-opsfrom
Conversation
27c8ea9 to
d98449d
Compare
Adds a PACKAGE_VERSION gate on the target routing ISM. When it reports >= 11.4.0 (where setBatch/removeBatch were introduced), consolidate enrollments and unenrollments into chunked setBatch/removeBatch txs sized by domainRoutingInitializationSize(destination). Older ISMs fall back to per-domain set()/remove() loops. Applies to three paths: - Reconfigure-existing-ISM enrollments and unenrollments - Post-initializer follow-on enrollments on new DomainRoutingIsm / IncrementalDomainRoutingIsm deploys - DefaultFallbackRoutingIsm new deploys (initialize with initial batch + setBatch remainder, matching the sharding already done on the proxy-factory path)
d98449d to
c432f9d
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c432f9d. Configure here.
| overrides, | ||
| destination, | ||
| logger, | ||
| }); |
There was a problem hiding this comment.
Fallback routing ISM enrollments fail when signer differs from owner
High Severity
The initialize call passes config.owner as the owner, which immediately transfers ownership away from the deploying signer. The subsequent enrollDomains call for remaining domains (beyond initialBatchSize) uses the signer to invoke set/setBatch, which are onlyOwner. When config.owner differs from the signer, all remaining enrollments revert. The DomainRoutingIsm path handles this correctly by deploying with signerAddress as owner, enrolling all domains, and then calling transferOwnership — the DefaultFallbackRoutingIsm path needs the same pattern.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit c432f9d. Configure here.
| `Unenrolling originDomain ${originDomain} from preexisting routing ISM at ${existingIsmAddress}...`, | ||
| ); | ||
| const tx = await routingIsm.remove(originDomain, overrides); | ||
| await this.multiProvider.handleTx(destination, tx); |
There was a problem hiding this comment.
Dead isms record written but never read
Low Severity
The isms record declared at line 558 is assigned at line 578 (isms[originDomain] = ism.address) but is never read afterward. It became dead code when the inline routingIsm.set(originDomain, isms[originDomain], overrides) calls were replaced by the new enrollDomains helper, which uses the separate enrollAddresses array instead. Both the declaration and the write can be removed.
Reviewed by Cursor Bugbot for commit c432f9d. Configure here.


Summary
Wires
HyperlaneIsmFactoryto use thesetBatch/removeBatchfunctions added toDomainRoutingIsmin #8655 (targets@hyperlane-xyz/core11.4.0). Version-gated viaPACKAGE_VERSION()on the target routing ISM — if it's ≥ 11.4.0, enrollments / unenrollments are consolidated into chunked batched txs sized bydomainRoutingInitializationSize(destination). Older ISMs fall back to the existing per-domainset()/remove()loops.Why
#8583 shipped per-chain sharding of the routing ISM initializer to stay under block gas limits on citrea / shibarium / etc. The follow-on loop is still one tx per domain, so a 150-domain ISM deploy on a 120-per-shard chain = 1 proxy deploy + 30 individual enrollment txs. With
setBatch, that becomes 1 proxy deploy + 1 tx for the remaining 30 domains.Paths touched
deployOwnableRoutingIsm,existingIsmAddress && isOwnerbranch). Enrollments + unenrollments both usesetBatch/removeBatchwhen supported.DomainRoutingIsm/IncrementalDomainRoutingIsmdeploy (post-factory.deploy(initial)remainder loop). UsessetBatchfor the tail.DefaultFallbackRoutingIsmdeploy. Previously called the batchedinitialize(address,uint32[],address[])with all domains in one tx (same gas-limit risk as the pre-fix: batch deployer transactions and bump gas buffers #8583 factory path). Now shards:initializewith initial chunk +setBatchfor the remainder.Version gate
Returns false on any failure (absent
PACKAGE_VERSION, RPC error, malformed version) → safe fallback to per-domain loop.Test plan
pnpm -C typescript/sdk build— no new errors inHyperlaneIsmFactory.ts(35 pre-existing errors in unrelated Aleo / Cosmos / Radix / Tron adapters remain on main)setBatchLocal dev caveat
Until a release cycle bumps
@hyperlane-xyz/coreto 11.4.0, locally-built routing ISMs still reportPACKAGE_VERSION = "11.3.1"and the SDK will take the fallback path during local testing. This resolves automatically on the first release PR that picks up #8655's changeset.Note
Medium Risk
Changes on-chain deployment/reconfiguration transaction behavior for routing ISMs by switching from per-domain calls to chunked batched calls when available, which could affect gas usage and failure modes. Risk is mitigated by
PACKAGE_VERSION()gating with an automatic per-domain fallback for older contracts.Overview
HyperlaneIsmFactorynow consolidates routing ISM domain enrollments and unenrollments into chunked batched transactions viasetBatch/removeBatchwhen the target routing ISM reportsPACKAGE_VERSION() >= 11.4.0, falling back to the existing per-domainset/removeloops otherwise.This also shards
DefaultFallbackRoutingIsminitialization by callinginitializewith only the firstdomainRoutingInitializationSize(destination)domains and enrolling the remainder via the same batched/fallback path, reducing tx count and avoiding block gas limit issues on low-capacity chains. A changeset bumps@hyperlane-xyz/sdkminor to reflect the behavior change.Reviewed by Cursor Bugbot for commit c432f9d. Bugbot is set up for automated code reviews on this repo. Configure here.