Skip to content

✨ server: support multi-chain account creation in activity webhook#965

Merged
cruzdanilo merged 1 commit intomainfrom
create
Apr 17, 2026
Merged

✨ server: support multi-chain account creation in activity webhook#965
cruzdanilo merged 1 commit intomainfrom
create

Conversation

@cruzdanilo
Copy link
Copy Markdown
Member

@cruzdanilo cruzdanilo commented Apr 16, 2026

closes #960

Summary by CodeRabbit

  • New Features

    • Multi-chain support for account creation via the activity webhook; deployments can run on the event network.
  • Bug Fixes

    • Runtime validation of event networks with clear rejection of unsupported networks.
    • Market, notification and auto-credit behavior now respect the resolved chain (yield messaging skipped off the primary chain).
  • Tests

    • Added/updated tests for multi-chain deployment flows, event-network deployments, and error handling.
  • Refactor

    • Per-chain RPC/tracing and client wiring reorganized for chain-specific execution and extensibility.

@cruzdanilo cruzdanilo requested a review from nfmelendez as a code owner April 16, 2026 02:14
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 16, 2026

🦋 Changeset detected

Latest commit: e76f034

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@exactly/server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

Warning

Rate limit exceeded

@cruzdanilo has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 32 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 48 minutes and 32 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 908b0305-e278-40b9-b4ab-b26a9b5f046b

📥 Commits

Reviewing files that changed from the base of the PR and between c1ef521 and e76f034.

📒 Files selected for processing (6)
  • .changeset/new-koi-curl.md
  • server/hooks/activity.ts
  • server/test/hooks/activity.test.ts
  • server/utils/alchemy.ts
  • server/utils/keeper.ts
  • server/utils/traceClient.ts

Walkthrough

Adds multi-chain account-creation to the activity webhook: runtime network resolution via a NETWORKS registry, chain-specific Alchemy RPC and wallet clients with tracing, keeper extender generification and DI, trace client extraction, and corresponding test updates for event-network flows.

Changes

Cohort / File(s) Summary
Changeset
​.changeset/new-koi-curl.md
New changeset declaring a patch release for @exactly/server noting multi-chain account-creation support in the activity webhook.
Activity Webhook
server/hooks/activity.ts
Runtime-validate event.network against NETWORKS; derive chain from payload; create chain-specific Alchemy public/trace clients; inject traced RPC into account creation flow; conditional market lookups, fees, and early return when event chain differs from configured chain; enhanced Sentry context and request capture.
Activity Tests
server/test/hooks/activity.test.ts
Mock viem.createPublicClient, add event-network deployment test, tighten async timeouts, refactor market/wait helpers, and adjust stubs/spies for chain-specific client behavior.
Keeper extender
server/utils/keeper.ts
Generalize extender to generic WalletClient<Transport, Chain, PrivateKeyAccount>; make publicClient/traceClient injectable (narrowed via Pick); add fees?: "auto" option altering fee fields; use keeper.chain.id for nonce resets.
Trace client extraction
server/utils/traceClient.ts
Extract trace logic into exported trace function typed against Client.request and switch default public client to .extend(trace).
Alchemy utils & NETWORKS
server/utils/alchemy.ts
Replace network constant with network(id = chain.id) function; add exported NETWORKS: Map<string, AlchemyChain>; update webhook lookup/creation and validation to use runtime network mapping and stricter NETWORKS validation.

Sequence Diagram(s)

sequenceDiagram
    participant Webhook as Activity Webhook
    participant Validator as Network Validator
    participant NETWORKS as NETWORKS Map
    participant Alchemy as Alchemy RPC Client
    participant Wallet as Wallet Client
    participant Keeper as Keeper/Extender
    participant Sentry as Sentry/Tracing

    Webhook->>Validator: receive payload, validate `event.network`
    Validator->>NETWORKS: lookup chain by network string
    NETWORKS-->>Validator: return Chain or error
    Validator-->>Webhook: resolved chain

    alt chain == configured chain
        Webhook->>Alchemy: create public & trace clients (.extend(trace))
        Alchemy->>Alchemy: getCode / trace calls
        Webhook->>Keeper: extender(..., { publicClient, traceClient })
        Webhook->>Wallet: createWalletClient(...).extend(...).exaSend(createAccount, fees: undefined)
        Wallet-->>Webhook: exaSend result
        Webhook->>Sentry: set context and capture requests
        Webhook->>Webhook: market lookup / poke / auto-credit
    else chain != configured chain
        Webhook->>Wallet: createWalletClient(...).extend(...).exaSend(createAccount, fees: "auto")
        Wallet-->>Webhook: exaSend result
        Webhook->>Sentry: mark span OK and return (skip poke/auto-credit)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • nfmelendez
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: adding multi-chain account creation support in the activity webhook, which aligns with the changes across multiple files.
Linked Issues check ✅ Passed The PR implements the objective from #960 to deploy accounts to any chain by introducing multi-chain support through NETWORKS mapping, runtime network validation, and chain-specific account creation logic.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing multi-chain account deployment support, including network validation, chain-specific client creation, test updates, and configuration changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch create

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

sentry[bot]

This comment was marked as resolved.

gemini-code-assist[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@sentry
Copy link
Copy Markdown

sentry Bot commented Apr 16, 2026

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
621 1 620 1
View the full list of 1 ❄️ flaky test(s)
local::local

Flake rate in main: 100.00% (Passed 0 times, Failed 1 times)

Stack Traces | 352s run time
Element not found: Text matching regex: Spending limit

To view more test analytics, go to the Prevent Tests Dashboard

chatgpt-codex-connector[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 10 additional findings in Devin Review.

Open in Devin Review

coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@cruzdanilo cruzdanilo force-pushed the create branch 2 times, most recently from 079754c to 4e162a5 Compare April 16, 2026 23:57
chatgpt-codex-connector[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/hooks/activity.ts (1)

162-174: 🧹 Nitpick | 🔵 Trivial

Hoist transport/client out of the per-account loop.

Both only depend on chain which is fixed per payload, yet they're rebuilt for every account in pokes (including a fresh onFetchRequest closure and a new traced public client). For payloads with multiple recipients (see the pokes multiple accounts test) this is wasted work.

♻️ Proposed fix
     const { "sentry-trace": sentryTrace, baggage } = getTraceData();
+    const transport = http(`${chain.rpcUrls.alchemy.http[0]}/${alchemyAPIKey}`, {
+      async onFetchRequest(request) {
+        captureRequests([v.parse(Request, await request.json())]);
+      },
+    });
+    const client = createPublicClient({ chain, transport, rpcSchema: rpcSchema<Tracer>() }).extend(trace);
     Promise.allSettled(
       [...pokes].map(([account, { publicKey, factory, source, assets }]) =>
         continueTrace({ sentryTrace, baggage }, () =>
           withScope((scope) =>
             startSpan(
               { name: "account activity", op: "exa.activity", attributes: { account }, forceTransaction: true },
               async (span) => {
                 scope.setUser({ id: account });
-                const transport = http(`${chain.rpcUrls.alchemy.http[0]}/${alchemyAPIKey}`, {
-                  async onFetchRequest(request) {
-                    captureRequests([v.parse(Request, await request.json())]);
-                  },
-                });
-                const client = createPublicClient({ chain, transport, rpcSchema: rpcSchema<Tracer>() }).extend(trace);
                 const isDeployed = !!(await client.getCode({ address: account }));

Note: the deploys on the event network… test mocks viem.createPublicClient with mockReturnValueOnce, which would still match (single account → single call).


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6cf4e34e-3b60-4872-b1a9-aa72d5decf0e

📥 Commits

Reviewing files that changed from the base of the PR and between 4e162a5 and c1ef521.

📒 Files selected for processing (6)
  • .changeset/new-koi-curl.md
  • server/hooks/activity.ts
  • server/test/hooks/activity.test.ts
  • server/utils/alchemy.ts
  • server/utils/keeper.ts
  • server/utils/traceClient.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e76f03477e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread server/hooks/activity.ts
@cruzdanilo cruzdanilo merged commit e76f034 into main Apr 17, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

server: deploy account to any chain

1 participant