Skip to content

refactor(sdk): split RelayerDispatcher into ChainRouter [SDK-193]#414

Open
ghermet wants to merge 14 commits into
prereleasefrom
feature/sdk-193-split-relayerdispatcher-into-a-chain-router-and-a-per-chain
Open

refactor(sdk): split RelayerDispatcher into ChainRouter [SDK-193]#414
ghermet wants to merge 14 commits into
prereleasefrom
feature/sdk-193-split-relayerdispatcher-into-a-chain-router-and-a-per-chain

Conversation

@ghermet

@ghermet ghermet commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Splits RelayerDispatcher — which was both routing requests across chains and acting as a per-chain RelayerSDK facade — into two single-purpose concepts:

  • ChainRouter — owns the per-chain RelayerSDK instances and exposes router.relayer (active chain) and router.relayerForChain(id) (specific chain).
  • Per-chain RelayerSDK — unchanged, but now accessed exclusively via the router.

Services consume this.#router.relayer.X() instead of dispatching through a single RelayerSDK-shaped facade. Drops ZamaSDK.relayer, ZamaConfig.relayer, and the redundant ZamaConfig.chains from the public surface; ZamaSDK.router / ZamaConfig.router replace them. Clean break — no shims.

Test plan

  • pnpm typecheck clean across all packages
  • pnpm api-report clean (API reports regenerated, no drift)
  • pnpm test (sdk + react-sdk)
  • Manual smoke via examples app (shield/unshield/transfer)

🤖 Generated with Claude Code

ghermet and others added 9 commits June 15, 2026 15:01
…rForChain [SDK-193]

Service call sites become `router.relayer.X()` (instead of `router.active.X()`),
and the explicit per-chain accessor becomes `router.relayerForChain(chainId)`
(instead of `router.for(chainId)`).

- `relayer` names the type (`RelayerSDK`) instead of the lifecycle state.
- `relayerForChain` mirrors `switchChain` and avoids the JS-reserved `for`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Only ChainRouter remains in the SDK surface; ZamaSDK.terminate() now calls
router.terminate(). buildZamaConfig still constructs a RelayerDispatcher
(which extends ChainRouter); Task 6 swaps that to ChainRouter and removes
the dispatcher entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
buildZamaConfig now constructs ChainRouter directly. The deprecated
RelayerDispatcher subclass and its tests are removed; chain-router.test.ts
covers the surviving chain-management behaviour. Public surface drops
RelayerDispatcher; WorkerLike re-exports from chain-router.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- RelayerDispatcher class export removed
- ChainRouter class export added (with `relayer` getter and `relayerForChain` method)
- ZamaConfig.relayer → router; ZamaSDK.relayer → router
- Decryption namespace ctor signature: relayer → router

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolved ZamaConfig duplicated the chain list (chains + router.chains). The
ChainRouter owns the chain registry; consumers read config.router.chains
instead. Only one in-tree reader (ZamaSDK's registry-address loop) needed
adjusting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cla-bot cla-bot Bot added the cla-signed label Jun 15, 2026
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

Public API Changes

sdk-query.api.md
--- a/sdk-query.api.md
+++ b/sdk-query.api.md
@@ -978,8 +978,7 @@
 
 // @public
 export type ZamaConfig = {
-    readonly chains: readonly FheChain[];
-    readonly relayer: RelayerDispatcher;
+    readonly router: ChainRouter;
     readonly provider: GenericProvider;
     readonly signer: GenericSigner | undefined;
     readonly storage: GenericStorage;
@@ -1199,7 +1198,7 @@
     readonly provider: GenericProvider;
     readonly registry: WrappersRegistry;
     // (undocumented)
-    readonly relayer: RelayerDispatcher;
+    readonly router: ChainRouter;
     // (undocumented)
     readonly signer: GenericSigner | undefined;
     // (undocumented)
sdk.api.md
--- a/sdk.api.md
+++ b/sdk.api.md
@@ -598,6 +598,18 @@
 }
 
 // @public
+export class ChainRouter implements Disposable {
+    [Symbol.dispose](): void;
+    constructor(chains: readonly [FheChain, ...FheChain[]], configs: Readonly<Record<number, RelayerConfig>>);
+    get chain(): FheChain;
+    get chains(): readonly FheChain[];
+    get relayer(): RelayerSDK;
+    relayerForChain(chainId: number): RelayerSDK;
+    switchChain(chainId: number): void;
+    terminate(): void;
+}
+
+// @public
 export const chains: Record<number, FheChain>;
 
 // @public
@@ -6154,7 +6166,7 @@
     constructor(opts: {
         signer: GenericSigner | undefined;
         provider: GenericProvider;
-        relayer: RelayerDispatcher;
+        router: ChainRouter;
         decryptionService: DecryptionService | undefined;
     });
     decryptPublicValues(encryptedValues: EncryptedValue[]): Promise<DecryptPublicValuesResult>;
@@ -13089,43 +13101,6 @@
 }
 
 // @public
-export class RelayerDispatcher implements RelayerSDK, Disposable {
-    // (undocumented)
-    [Symbol.dispose](): void;
-    constructor(chains: readonly [FheChain, ...FheChain[]], configs: Readonly<Record<number, RelayerConfig>>);
-    // (undocumented)
-    get chain(): FheChain;
-    // (undocumented)
-    get chains(): readonly FheChain[];
-    // (undocumented)
-    createDelegatedUserDecryptEIP712(publicKey: Hex, contractAddresses: Address[], delegatorAddress: Address, startTimestamp: number, durationDays?: number): Promise<KmsDelegatedDecryptEIP712Type>;
-    // (undocumented)
-    createEIP712(publicKey: Hex, contractAddresses: Address[], startTimestamp: number, durationDays?: number): Promise<EIP712TypedData>;
-    // (undocumented)
-    delegatedUserDecrypt(params: DelegatedDecryptValuesParams): Promise<Readonly<Record<EncryptedValue, ClearValue>>>;
-    // (undocumented)
-    encrypt(params: EncryptParams): Promise<EncryptResult>;
-    // (undocumented)
-    generateKeypair(): Promise<KeypairType<Hex>>;
-    // (undocumented)
-    getAclAddress(): Promise<Address>;
-    // (undocumented)
-    getPublicKey(): Promise<PublicKeyData | null>;
-    // (undocumented)
-    getPublicParams(bits: number): Promise<PublicParamsData | null>;
-    // (undocumented)
-    publicDecrypt(encryptedValues: EncryptedValue[]): Promise<DecryptPublicValuesResult>;
-    // (undocumented)
-    requestZKProofVerification(zkProof: ZKProofLike): Promise<InputProofBytesType>;
-    // (undocumented)
-    switchChain(chainId: number): void;
-    // (undocumented)
-    terminate(): void;
-    // (undocumented)
-    userDecrypt(params: DecryptValuesParams): Promise<Readonly<Record<EncryptedValue, ClearValue>>>;
-}
-
-// @public
 export class RelayerRequestFailedError extends ZamaError {
     constructor(message: string, statusCode?: number, options?: ErrorOptions);
     readonly statusCode: number | undefined;
@@ -19801,8 +19776,7 @@
 
 // @public
 export type ZamaConfig = {
-    readonly chains: readonly FheChain[];
-    readonly relayer: RelayerDispatcher;
+    readonly router: ChainRouter;
     readonly provider: GenericProvider;
     readonly signer: GenericSigner | undefined;
     readonly storage: GenericStorage;
@@ -19920,7 +19894,7 @@
     readonly provider: GenericProvider;
     readonly registry: WrappersRegistry;
     // (undocumented)
-    readonly relayer: RelayerDispatcher;
+    readonly router: ChainRouter;
     // (undocumented)
     readonly signer: GenericSigner | undefined;
     // (undocumented)

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 92.1% (🎯 80%) 3102 / 3368
🔵 Statements 92.18% 3196 / 3467
🔵 Functions 92.32% (🎯 80%) 1034 / 1120
🔵 Branches 84.69% (🎯 80%) 1195 / 1411
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/react-sdk/src/test-fixtures/wrapper.tsx 100% 100% 100% 100%
packages/sdk/src/zama-sdk.ts 94.11% 83.33% 100% 94.11% 74, 165
packages/sdk/src/config/build.ts 100% 100% 100% 100%
packages/sdk/src/config/types.ts 100% 100% 100% 100%
packages/sdk/src/credentials/credential-service.ts 96.29% 88.23% 100% 96.2% 129, 164, 259
packages/sdk/src/namespaces/decryption.ts 100% 100% 100% 100%
packages/sdk/src/query/delegation-status.ts 100% 100% 100% 100%
packages/sdk/src/services/decryption-service.ts 95.28% 84.84% 95.83% 95.04% 145, 165, 191, 211, 339
packages/sdk/src/services/delegation-service.ts 87.32% 82.85% 100% 87.32% 67-69, 83-85, 101-102, 105-107, 148-149, 228, 252
packages/sdk/src/services/encryption-service.ts 100% 100% 100% 100%
packages/sdk/src/services/lifecycle-service.ts 96.77% 100% 91.66% 96.66% 39
packages/sdk/src/test-fixtures/chain.ts 100% 100% 100% 100%
packages/sdk/src/test-fixtures/relayer.ts 92.3% 100% 87.5% 92.3% 96
packages/sdk/src/test-fixtures/sdk.ts 100% 100% 100% 100%
packages/sdk/src/test-fixtures/services.ts 95.23% 94.87% 93.33% 95.23% 122
Generated in workflow #2554 for commit 856fc1d by the Vitest Coverage Report Action

ghermet and others added 4 commits June 15, 2026 15:10
After ZamaConfig.chains was removed (the router now owns the chain list),
test fixtures still set chains: [chain] via `as unknown as ZamaConfig` casts.
Dead now — the router fixture (which depends on the chain fixture) already
encapsulates the chain. Drops the FheChain import and the chain dep from
WrapperDeps in the react-sdk wrapper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… [SDK-193]

- TSDoc on ChainRouter members (constructor, chain, chains, relayer,
  relayerForChain, switchChain, terminate, [Symbol.dispose])
- Refresh API report to clear the resulting `(undocumented)` markers
- Drop the stale `RelayerDispatcher` reference from the SDK-205 migration
  doc — class was deleted in SDK-193

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The node e2e specs under test/playwright/tests/node/ were missed during
the ChainRouter migration — they still called sdk.relayer.X(), which is
undefined now that ZamaSDK exposes the router instead. 9 specs across 4
files were failing with `Cannot read properties of undefined (reading
'generateKeypair')`. Rename to sdk.router.relayer.X() throughout.

The drift wasn't caught at typecheck time because tests/ is outside
test/playwright/tsconfig.json's include — only fixtures/ and top-level
*.ts are typechecked there.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ghermet ghermet marked this pull request as ready for review June 16, 2026 07:24
@ankurdotb ankurdotb added the do not merge This is not ready to be merged, waiting on someone else's work label Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed do not merge This is not ready to be merged, waiting on someone else's work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants