Repository navigation
feat: MultichainResolver — parallel per-chain execution (F9) - #25
Merged
Merged
Conversation
Runs task-shaped plans across several chains at once, fanning out to the existing single-chain runners (runMultistepTasks/runSettled) per chain: constructor discriminates StepExecutor vs. Eip1193Provider entries (the latter lazily wrapped + cached), chain()/snapshot()/runAll()/runAllSettled() as pinned, per-chain `blocks` overrides, deterministic lowest-chainId error selection on runAll failure, and onPin firing once per chain. [v5]: duplicate-instance validation now scans the whole flattened plan (every chain's task array) before any chain begins execution, rejecting a branded task instance reused across two chains up front instead of letting two chains race to consume it. Raises the bundle-size gzip ceiling 15KB -> 18KB (measured delta: +2.72KB gzip) — a whole-library budget, not per-consumer cost, since "sideEffects": false lets tree-shaking consumers drop this entirely if unused. Updates the README bundle-size badge to match.
…ion, shared brand check P1: snapshot() invoked executor.getBlockNumber() directly inside .map(); a custom executor throwing SYNCHRONOUSLY (instead of rejecting a promise) aborted the mapping mid-way, leaving an earlier chain's already-created promise with no handler attached — a genuine unhandled rejection once that promise later rejected. Each call is now deferred through Promise.resolve().then(...) so .map() can never throw, guaranteeing every promise gets its no-op catch attached before any of them actually run. P2: the flattened cross-chain duplicate scan re-implemented the SINGLE_USE brand-truthiness check inline instead of sharing it with the single-chain runners. Extracted isSingleUseTask() in src/core/internal.ts as the one shared predicate, now used by rejectDuplicateInstances, markTasksConsumed, and the multichain flattened scan alike. Bundle-size ceiling stays at 18KB (measured +0.46KB gzip for this round); README badge updated to match.
halaprix
added a commit
that referenced
this pull request
Jul 23, 2026
* chore: release v1.3.0 - Version bump 1.2.0 → 1.3.0 in package.json and npm-lock - CHANGELOG.md: [1.3.0] entry with facts verified against git log v1.2.0..HEAD (PRs #25, #26, #27): * Added: MultichainResolver, examples/refinance.ts * Changed: handlers reimplemented on defineTask (parity-gated, observable deltas documented) * Bundle size 15→18KB (current 16.8KB measured) - README.md: updated bundle badge, added MultichainResolver to API table, added Multichain section with compiling example and refinance.ts pointer - MIGRATION.md: appended v1.2.x → v1.3.0 section (additive, no consumer action required) - SUMMARY.md: updated TOC with new sections - docs/benchmarks.md: updated size figures (13.9 → 16.8 KB) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: fix API accuracy — multichain, pinBlock, ethers - README multichain example: replace task instance reuse with factory pattern (flattened duplicate validation throws before any execution) - api-reference MultichainResolver.chain(): returns MulticallResolver (cached), throws on unknown chainId (not undefined) - Remove fake per-chain onPin Record — onPin is single inherited callback from BatchOptions; each chain reports once - Remove fake chainId < 1 validation rule — real rule: lowest-chainId rejection on concurrent failures - docs/index.html: Fix ethers claim — "requires an adapter" (domino doesn't depend on ethers) - pinBlock performance: Clarify +1 RPC only for absent/tag blocks; explicit blockNumber/blockHash add none - CHANGELOG: Correct MultichainResolver description (blocks map, not per-chain onPin; deterministic rejection) - Verify all snippets compile and bundle badge matches measured size Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: halaprix <halaprix@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
halaprix
added a commit
that referenced
this pull request
Jul 24, 2026
* feat: MultichainResolver — parallel per-chain execution (F9) Runs task-shaped plans across several chains at once, fanning out to the existing single-chain runners (runMultistepTasks/runSettled) per chain: constructor discriminates StepExecutor vs. Eip1193Provider entries (the latter lazily wrapped + cached), chain()/snapshot()/runAll()/runAllSettled() as pinned, per-chain `blocks` overrides, deterministic lowest-chainId error selection on runAll failure, and onPin firing once per chain. [v5]: duplicate-instance validation now scans the whole flattened plan (every chain's task array) before any chain begins execution, rejecting a branded task instance reused across two chains up front instead of letting two chains race to consume it. Raises the bundle-size gzip ceiling 15KB -> 18KB (measured delta: +2.72KB gzip) — a whole-library budget, not per-consumer cost, since "sideEffects": false lets tree-shaking consumers drop this entirely if unused. Updates the README bundle-size badge to match. * fix: MultichainResolver external review — snapshot() unhandled rejection, shared brand check P1: snapshot() invoked executor.getBlockNumber() directly inside .map(); a custom executor throwing SYNCHRONOUSLY (instead of rejecting a promise) aborted the mapping mid-way, leaving an earlier chain's already-created promise with no handler attached — a genuine unhandled rejection once that promise later rejected. Each call is now deferred through Promise.resolve().then(...) so .map() can never throw, guaranteeing every promise gets its no-op catch attached before any of them actually run. P2: the flattened cross-chain duplicate scan re-implemented the SINGLE_USE brand-truthiness check inline instead of sharing it with the single-chain runners. Extracted isSingleUseTask() in src/core/internal.ts as the one shared predicate, now used by rejectDuplicateInstances, markTasksConsumed, and the multichain flattened scan alike. Bundle-size ceiling stays at 18KB (measured +0.46KB gzip for this round); README badge updated to match. --------- Co-authored-by: halaprix <halaprix@users.noreply.github.com>
halaprix
added a commit
that referenced
this pull request
Jul 24, 2026
* chore: release v1.3.0 - Version bump 1.2.0 → 1.3.0 in package.json and npm-lock - CHANGELOG.md: [1.3.0] entry with facts verified against git log v1.2.0..HEAD (PRs #25, #26, #27): * Added: MultichainResolver, examples/refinance.ts * Changed: handlers reimplemented on defineTask (parity-gated, observable deltas documented) * Bundle size 15→18KB (current 16.8KB measured) - README.md: updated bundle badge, added MultichainResolver to API table, added Multichain section with compiling example and refinance.ts pointer - MIGRATION.md: appended v1.2.x → v1.3.0 section (additive, no consumer action required) - SUMMARY.md: updated TOC with new sections - docs/benchmarks.md: updated size figures (13.9 → 16.8 KB) * docs: fix API accuracy — multichain, pinBlock, ethers - README multichain example: replace task instance reuse with factory pattern (flattened duplicate validation throws before any execution) - api-reference MultichainResolver.chain(): returns MulticallResolver (cached), throws on unknown chainId (not undefined) - Remove fake per-chain onPin Record — onPin is single inherited callback from BatchOptions; each chain reports once - Remove fake chainId < 1 validation rule — real rule: lowest-chainId rejection on concurrent failures - docs/index.html: Fix ethers claim — "requires an adapter" (domino doesn't depend on ethers) - pinBlock performance: Clarify +1 RPC only for absent/tag blocks; explicit blockNumber/blockHash add none - CHANGELOG: Correct MultichainResolver description (blocks map, not per-chain onPin; deterministic rejection) - Verify all snippets compile and bundle badge matches measured size --------- Co-authored-by: halaprix <halaprix@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
halaprix
added a commit
that referenced
this pull request
Jul 24, 2026
* feat: MultichainResolver — parallel per-chain execution (F9) Runs task-shaped plans across several chains at once, fanning out to the existing single-chain runners (runMultistepTasks/runSettled) per chain: constructor discriminates StepExecutor vs. Eip1193Provider entries (the latter lazily wrapped + cached), chain()/snapshot()/runAll()/runAllSettled() as pinned, per-chain `blocks` overrides, deterministic lowest-chainId error selection on runAll failure, and onPin firing once per chain. [v5]: duplicate-instance validation now scans the whole flattened plan (every chain's task array) before any chain begins execution, rejecting a branded task instance reused across two chains up front instead of letting two chains race to consume it. Raises the bundle-size gzip ceiling 15KB -> 18KB (measured delta: +2.72KB gzip) — a whole-library budget, not per-consumer cost, since "sideEffects": false lets tree-shaking consumers drop this entirely if unused. Updates the README bundle-size badge to match. * fix: MultichainResolver external review — snapshot() unhandled rejection, shared brand check P1: snapshot() invoked executor.getBlockNumber() directly inside .map(); a custom executor throwing SYNCHRONOUSLY (instead of rejecting a promise) aborted the mapping mid-way, leaving an earlier chain's already-created promise with no handler attached — a genuine unhandled rejection once that promise later rejected. Each call is now deferred through Promise.resolve().then(...) so .map() can never throw, guaranteeing every promise gets its no-op catch attached before any of them actually run. P2: the flattened cross-chain duplicate scan re-implemented the SINGLE_USE brand-truthiness check inline instead of sharing it with the single-chain runners. Extracted isSingleUseTask() in src/core/internal.ts as the one shared predicate, now used by rejectDuplicateInstances, markTasksConsumed, and the multichain flattened scan alike. Bundle-size ceiling stays at 18KB (measured +0.46KB gzip for this round); README badge updated to match. --------- Co-authored-by: halaprix <halaprix@users.noreply.github.com>
halaprix
added a commit
that referenced
this pull request
Jul 24, 2026
* chore: release v1.3.0 - Version bump 1.2.0 → 1.3.0 in package.json and npm-lock - CHANGELOG.md: [1.3.0] entry with facts verified against git log v1.2.0..HEAD (PRs #25, #26, #27): * Added: MultichainResolver, examples/refinance.ts * Changed: handlers reimplemented on defineTask (parity-gated, observable deltas documented) * Bundle size 15→18KB (current 16.8KB measured) - README.md: updated bundle badge, added MultichainResolver to API table, added Multichain section with compiling example and refinance.ts pointer - MIGRATION.md: appended v1.2.x → v1.3.0 section (additive, no consumer action required) - SUMMARY.md: updated TOC with new sections - docs/benchmarks.md: updated size figures (13.9 → 16.8 KB) * docs: fix API accuracy — multichain, pinBlock, ethers - README multichain example: replace task instance reuse with factory pattern (flattened duplicate validation throws before any execution) - api-reference MultichainResolver.chain(): returns MulticallResolver (cached), throws on unknown chainId (not undefined) - Remove fake per-chain onPin Record — onPin is single inherited callback from BatchOptions; each chain reports once - Remove fake chainId < 1 validation rule — real rule: lowest-chainId rejection on concurrent failures - docs/index.html: Fix ethers claim — "requires an adapter" (domino doesn't depend on ethers) - pinBlock performance: Clarify +1 RPC only for absent/tag blocks; explicit blockNumber/blockHash add none - CHANGELOG: Correct MultichainResolver description (blocks map, not per-chain onPin; deterministic rejection) - Verify all snippets compile and bundle badge matches measured size --------- Co-authored-by: halaprix <halaprix@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements spec F9 (1.3.0):
MultichainResolver(src/engine/multichain.ts):Record<chainId, provider | executor>constructor with lazy, cachedEip1193Executorwrapping;chain(id)cached resolvers;snapshot()— parallel block map with all-chains capability check before any RPC (and rejection handlers attached before anything can abort — a synchronously-throwing custom executor can no longer leak an earlier chain's rejection);runAll/runAllSettledwith per-chainblocksoverrides; chains execute in parallel; single-Tgeneric (mixed shapes → per-chain calls, documented).DominoTaskReuseErrorconsuming nothing, killing the cross-chain consumption race; brand semantics shared with the runners via oneisSingleUseTaskpredicate (no drift).runAllrejects deterministically with the lowest-chainId rejection (others attached — no unhandled rejections; no cross-chain cancellation);onPinfires once per chain against each chain's own resolution.sideEffects: falsetree-shaking spares non-users); measured 17.12KB.Test evidence
307/307 (27 multichain tests incl. flattened-duplicate pre-execution rejection with zero dispatches, parallel-overlap assertions, per-chain block routing, lowest-chainId determinism, snapshot sync-throw regression), compat-vs-dist 38/38, full gate build-first.
Spec:
spec.md§ 1.3.0 F9.