Skip to content

feat: add activity service - #66

Merged
Seranged merged 11 commits into
mainfrom
feature/activity-service
Jul 20, 2026
Merged

Seranged merged 11 commits into
mainfrom
feature/activity-service

Conversation

@Seranged

@Seranged Seranged commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a typed activityService for normalized account and vault event timelines.
  • Keep transport, schema validation, capability discovery, cache keys, and fallback behavior in the SDK so Lite does not duplicate backend contract logic.
  • Expose an adapter boundary that can support another activity source later without changing consumer-facing event/feed models.
  • Preserve opt-in V3 behavior for direct SDK consumers: constructing EulerSDK without Activity configuration does not start making new backend requests.

Public API

Account activity

sdk.activityService.fetchAccountActivityEvents({
  owner,
  chainId,
  categories,
  eventTypes,
  cursor,
  from,
  to,
  limit,
})

Calls:

GET /v3/activity/accounts/{owner}/events

Vault activity

sdk.activityService.fetchVaultActivityEvents({
  chainId,
  vault,
  vaultType,
  categories,
  eventTypes,
  cursor,
  from,
  to,
  limit,
})

Calls:

GET /v3/activity/vaults/{chainId}/{vault}/events

The service serializes CSV filters and chain sets canonically, validates limits, inclusive Unix-second time bounds, and addresses, and keeps cache keys stable across equivalent caller input.

Normalized contract

Categories:

  • lending
  • borrowing
  • swaps
  • liquidations
  • account
  • rewards
  • governance

Every event requires:

  • id, chainId, timestamp
  • blockNumber as a decimal string, numeric logIndex, and txHash
  • normalized type, category, and source

Optional fields retain source truth without inventing context:

  • owner/account/subaccount
  • vault/vault type
  • actor/counterparty
  • asset amount/change/valuation
  • source type, group ID, and payload

Responses are validated at runtime, including RFC 3339 timestamps, EVM addresses/hashes, coverage states, cursor shape, and discriminated event data. A successful HTTP response with an incompatible schema is an error, not an empty page.

Capability and coverage model

The SDK exposes three distinct signals:

  1. Static adapter capability — which categories and scopes an adapter can represent.
  2. Scoped support — whether a chain, vault type, or account scope is configured for that adapter.
  3. Runtime coverage — complete, partial, unsupported, or syncing from the source response.

Consumers should combine all three. In particular, unsupported is not the same as a successful empty timeline, while partial can still contain useful events.

Coverage describes event-family availability. Missing optional enrichment such as historical USD valuation does not make an otherwise indexed family partial.

Adapter and fallback boundary

ActivityService consumes an activity adapter rather than hard-coding UI behavior to V3.

Included adapters:

  • V3 adapter for the normalized backend routes.
  • Custom adapter support for another source or host application.
  • Unavailable adapter with explicit unsupported capability/coverage behavior.

No subgraph adapter is implemented in this PR. The interface allows one to be added later without changing Lite feed components or normalized event types.

The SDK never converts transport, authentication, timeout, or schema failures into data: []. The caller can retain last-known data, offer retry, or hide an authoritatively unsupported scope without presenting a false empty state.

Transport hardening

  • V3 Activity requests use one 10-second AbortController deadline across both the header fetch and streamed body consumption, and always clear the timer after completion or failure.
  • Response bodies are capped at 2 MiB using both Content-Length and actual streamed-byte checks.
  • A blank resolved endpoint produces an unavailable service with source-not-configured capability rather than failing SDK construction or issuing a request.
  • Response cursors are subject to the same 2,048-character bound as request cursors, so a successful page cannot hand the consumer an unusable continuation cursor.

Account-family compatibility

Activity response validation reuses the SDK's exported getSubAccountId() and SUB_ACCOUNT_MAX_ID boundary. EVC account-family IDs are limited to 0–255 (256 addresses total, including primary ID 0), and ID 256 is rejected before it can cross into another 19-byte prefix.

Configuration

Activity can use the shared V3 connection or a dedicated Activity URL/key. Configuration and environment precedence cover:

  • explicit SDK config
  • dedicated Activity URL/API key
  • shared V3 URL/API key
  • explicit V3 disablement

Direct new EulerSDK(...) consumers do not receive an unexpected network dependency. When V3/Activity is unavailable, the public service remains well typed and reports unsupported capability instead of issuing requests.

Backend dependencies

This SDK contract targets the normalized V3 Activity API:

#273 prevents mixed-schema Ponder unions from returning false empty timelines. #274 adds the account/vault routes, normalization, deterministic cursors, and coverage metadata consumed here.

Dependency and merge order

  1. V3 indexed-event repair: https://github.com/euler-xyz/euler-data-v3/pull/273
  2. V3 normalized Activity API: https://github.com/euler-xyz/euler-data-v3/pull/274
  3. This SDK PR
  4. Publish @eulerxyz/euler-v2-sdk and bump the Lite Activity stack.
  5. Deploy the normalized V3 Activity API on supported chains.
  6. Lite vault Activity: feat: add vault and portfolio activity timelines euler-lite#736
  7. Lite portfolio Activity: feat: add portfolio activity timeline euler-lite#737 — rebase after the vault PR merges.

This PR can merge once the #274 contract is accepted, but consumers must not enable the V3 adapter until #274 is deployed. Publishing the SDK remains a separate release action.

Suggested review focus

  • Confirm request paths/query serialization exactly match #274.
  • Confirm strict runtime validation does not silently drop malformed events or coverage.
  • Confirm equivalent filter/chain ordering produces the same cache key.
  • Confirm cursor reuse cannot accidentally cross scopes.
  • Confirm direct SDK construction remains network-neutral without Activity/V3 configuration.
  • Confirm custom/unavailable adapters preserve the same normalized contract.
  • Confirm unsupported, partial, syncing, transport error, and real empty states remain distinguishable.

Test plan

  • Full SDK test suite: 32 files; 446 tests passed
  • Activity request construction and canonical query serialization
  • Runtime schema validation, including timestamps and response coverage
  • Cursor, owner, chain, category, event-type, time-bound, and limit validation
  • Static capabilities and scoped support
  • Custom and unavailable adapters
  • Blank endpoint degradation without network access
  • Header/body timeout, response-size cap, cleanup, and oversized response cursor rejection
  • Shared subaccount-family boundary, including maximum ID 255 and rejection of ID 256
  • Config/env precedence and explicit V3 disablement
  • Canonical query/cache keys
  • Typecheck passed
  • Package build passed
  • Activity changed-file Biome checks passed
  • git diff --check passed

Summary by CodeRabbit

  • New Features

    • Added Activity service support for account and vault event timelines, including capabilities, filtering, pagination, and event normalization.
    • Introduced a built-in Activity service with activityService and activityServiceConfig overrides, and exposed it on the SDK instance.
    • Added activityV3ApiUrl / activityV3ApiKey configuration with environment variable support; Activity defaults to shared V3 settings unless overridden.
    • When V3 is disabled, Activity correctly reports as unavailable.
  • Documentation

    • Documented the new Activity configuration section, defaults, and key options.
  • Tests

    • Added end-to-end Activity request/response validation and configuration/preference and robustness coverage.

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard review: Changes requested

Reviewed PR #66 at head 8bf86aa473cdd39ba131313f87449d9501b651a5.

The new V3-backed activity service is generally clean: endpoint wiring, API-key propagation, public root exports, query decoration, and event normalization all line up with the existing SDK service patterns. I found one SDK API-compatibility blocker before this should merge.

Blocking finding

  • EulerSDKOptions now requires activityService. That makes the exported new EulerSDK({...}) constructor/options shape source-breaking for any integrator or test harness that constructs the exported class directly instead of going through buildEulerSDK().

Validation performed

  • Diff/context review across all 10 changed files.
  • V3 OpenAPI contract check for /v3/evc/accounts/{address}/events and /v3/evk/vaults/{chainId}/{address}/events.
  • Live API smoke with ActivityService against mainnet USDC vault 0xD8b27CF359b7D15710a5BE299AF6e7Bf904984C2; response normalized and target contract helper returned the checksummed vault.
  • pnpm install --frozen-lockfile
  • pnpm --filter @eulerxyz/euler-v2-sdk test -- activityService.test.ts — passed; Vitest ran the full SDK suite, 27 files / 350 tests.
  • pnpm --filter @eulerxyz/euler-v2-sdk typecheck — passed.
  • pnpm --filter @eulerxyz/euler-v2-sdk build — passed; generated declarations include the new service exports.
  • pnpm --filter @eulerxyz/euler-v2-sdk lint — exit 0 with existing unrelated Biome warnings in src/utils/*.
  • git diff --check origin/main...HEAD — passed.
  • Security/supply-chain sweep over the diff — no dependency, workflow, script, secret, or suspicious execution changes found.

Scalability / maintainability hygiene pass

Checked sibling V3-backed services, config/env precedence, buildQuery decoration, root/package exports, generated declarations, and service override wiring. The activity service follows the existing V3 service abstraction; no missed sibling flow or duplicated old behavior found beyond the constructor API break noted inline.

Bot/reviewer feedback

No active CodeRabbit/other bot comments or prior Leonard comments were present when reviewed.

Screenshots: not applicable; SDK-only change with no user-visible UI surface.

comment lifecycle: none found

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Changes requested

Reviewed PR #66 at head b2380af2d1624709ccc60325554fbca8b8078d54.

The latest push adds useful coverage for activity-specific V3 config precedence, and the activity service itself continues to look coherent: default/export wiring, buildEulerSDK() integration, API-key propagation, query decoration, response normalization, and the live V3 account/vault event shape all line up.

The existing SDK API-compatibility blocker is still present, so I am keeping this as Changes requested.

Blocking finding

  • EulerSDKOptions still requires activityService (packages/euler-v2-sdk/src/sdk/sdk.ts). Because EulerSDKOptions and EulerSDK are exported public API, this is source-breaking for direct new EulerSDK({...}) users who were previously passing the complete valid service set. The generated declaration also exposes activityService: IActivityService as required. The existing Leonard inline comment on the current head remains relevant.

A low-noise fix would be to keep buildEulerSDK() constructing the new service, but avoid making existing direct-constructor callers immediately fail TypeScript: for example, make the constructor option optional with a safe default/lazy fallback, or otherwise introduce the new member in a backwards-compatible way consistent with the package's semver expectations.

Validation performed

  • Re-reviewed all 10 changed files and the delta from prior reviewed head 8bf86aa473cdd39ba131313f87449d9501b651a5 to current head b2380af2d1624709ccc60325554fbca8b8078d54 (test/activityService.test.ts only).
  • pnpm install --frozen-lockfile — passed.
  • pnpm --filter @eulerxyz/euler-v2-sdk test -- activityService.test.ts — passed; Vitest ran 27 files / 351 tests.
  • pnpm --filter @eulerxyz/euler-v2-sdk typecheck — passed.
  • pnpm --filter @eulerxyz/euler-v2-sdk build — passed; generated declarations include the new activity exports, and also confirm EulerSDKOptions.activityService is required.
  • pnpm --filter @eulerxyz/euler-v2-sdk lint — exit 0, with pre-existing unrelated Biome warnings in src/utils/*.
  • git diff --check origin/main...HEAD — passed.
  • Live V3 smoke via built ActivityService against:
    • account 0xee5b5c82a365d75e9f8a1e982687fb5b6ceb606c
    • mainnet USDC vault 0xD8b27CF359b7D15710a5BE299AF6e7Bf904984C2
      Both endpoints returned 200 application/json; normalized categories/labels and target-contract extraction matched the fixture.
  • Security/supply-chain sweep over the diff — no dependency, workflow, script, secret, package-export, transaction-construction, BigNumber/decimal, or suspicious execution changes found.

Scalability / maintainability hygiene pass

Started from the PR intent — a reusable activity timeline service — and checked sibling V3-backed service patterns, config/env precedence, buildQuery decoration, service override wiring, root/package exports, generated declarations, and tests. The activity service is the right reusable abstraction for account/vault timeline reads, and the new config precedence test covers the latest push. I did not find missed sibling flows or duplicated old behavior beyond the public constructor compatibility issue above.

Bot/reviewer feedback

No active CodeRabbit/other bot comments were present. The prior Leonard inline comment is still relevant on the current head.

Screenshots: not applicable; SDK-only change with no user-visible UI surface.

comment lifecycle: no Leonard top-level issue comment found to edit; kept the still-relevant Leonard inline comment on sdk.ts; no stale Leonard comments deleted.

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Approved

Reviewed PR #66 at head 2f51bba94e726bce999630c35657a27ce826c638.

The latest push fixes the prior SDK API-compatibility blocker by keeping EulerSDKOptions.activityService optional and defaulting the constructor to a built-in ActivityService. That preserves direct new EulerSDK({...}) callers while still exposing sdk.activityService for normal buildEulerSDK() users. The activity service wiring, exports, env/config precedence, query decoration, API-key propagation, and event normalization all look coherent.

Validation performed

  • Full diff/context review across all 10 changed files.
  • Rechecked current GitHub PR metadata, prior Leonard reviews, prior Leonard inline comments, and active reviewer/bot feedback. No active CodeRabbit/other-bot findings were present; the stale Leonard inline blocker was deleted after verifying the fix.
  • pnpm install --frozen-lockfile — passed.
  • pnpm --filter @eulerxyz/euler-v2-sdk test -- activityService.test.ts — passed; Vitest ran 27 files / 352 tests.
  • pnpm --filter @eulerxyz/euler-v2-sdk typecheck — passed.
  • pnpm --filter @eulerxyz/euler-v2-sdk build — passed; generated declarations expose EulerSDKOptions.activityService?: IActivityService and sdk.activityService: IActivityService.
  • pnpm --filter @eulerxyz/euler-v2-sdk lint — exit 0, with existing unrelated Biome warnings in src/utils/*.
  • git diff --check origin/main...HEAD — passed.
  • Live V3 API fixture checks against:
    • account events: /v3/evc/accounts/0xee5b5c82a365d75e9f8a1e982687fb5b6ceb606c/events?chainId=1&from=1725148800&to=1726358400&limit=2
    • vault events: /v3/evk/vaults/1/0xD8b27CF359b7D15710a5BE299AF6e7Bf904984C2/events?chainId=1&from=1725148800&to=1726358400&limit=2
      Both returned the expected { data, meta } shape with event fields consumed by the service.
  • Security/supply-chain sweep over the diff: no dependency, workflow, script, secret, transaction-construction, shell-execution, or suspicious network-surface changes beyond the intended V3 activity fetches.

Scalability / maintainability hygiene pass

Started from the PR intent: add a reusable V3 activity read service to the SDK. I searched sibling services, config/env patterns, buildQuery decoration, root/package exports, generated declaration output, and similar V3-backed service wiring. The implementation follows the existing service abstraction rather than duplicating a one-off consumer path, adds focused tests for URL construction/normalization/config precedence/backwards-compatible constructor wiring, and does not leave a comparable sibling flow using an old behavior.

Screenshot evidence

Not applicable: this SDK PR has no user-visible UI surface to capture.

Verdict: approve.

@Seranged
Seranged force-pushed the feature/activity-service branch from 2f51bba to b5f6846 Compare July 13, 2026 11:57
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a typed Activity service to the Euler v2 SDK, including V3 API fetching, strict response validation, capability handling, configuration overrides, SDK exposure, query integration, documentation, and comprehensive tests.

Changes

Activity service

Layer / File(s) Summary
Activity contracts and configuration
packages/euler-v2-sdk/src/services/activityService/activityServiceTypes.ts, packages/euler-v2-sdk/src/sdk/config.ts, packages/euler-v2-sdk/src/sdk/defaultConfig.ts, packages/euler-v2-sdk/docs/*, packages/euler-v2-sdk/test/sdkConfig.test.ts
Defines activity event, coverage, query, adapter, and service contracts; adds activity-specific API configuration, defaults, environment parsing, and documentation.
Activity response normalization and validation
packages/euler-v2-sdk/src/services/activityService/activityEvent.ts, packages/euler-v2-sdk/test/activityService.test.ts
Validates and normalizes activity events, metadata, coverage, filters, scoping, timestamps, enrichment fields, and payload-derived addresses.
V3 adapter and activity service
packages/euler-v2-sdk/src/services/activityService/activityService.ts, packages/euler-v2-sdk/src/services/activityService/adapters/activityV3Adapter.ts, packages/euler-v2-sdk/test/activityService.test.ts
Adds V3 HTTP requests, API-key headers, capability reporting, unavailable adapters, service delegation, query-key normalization, endpoint joining, request bounds, timeout handling, response-size limits, and redirect safety.
SDK exposure and construction
packages/euler-v2-sdk/src/index.ts, packages/euler-v2-sdk/src/sdk/buildSDK.ts, packages/euler-v2-sdk/src/sdk/sdk.ts, packages/euler-v2-sdk/src/utils/queryNames.ts, packages/euler-v2-sdk/test/activityService.test.ts
Exports the activity module, constructs or overrides the service, handles disabled V3 behavior, exposes it on EulerSDK, and includes its query methods in SDK query names.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SDKClient
  participant EulerSDK
  participant ActivityService
  participant ActivityV3Adapter
  participant ActivityAPI
  SDKClient->>EulerSDK: access activityService
  EulerSDK->>ActivityService: construct configured service
  SDKClient->>ActivityService: fetch activity events
  ActivityService->>ActivityV3Adapter: delegate request
  ActivityV3Adapter->>ActivityAPI: GET events with filters
  ActivityAPI-->>ActivityV3Adapter: response page
  ActivityV3Adapter-->>ActivityService: normalized page
  ActivityService-->>SDKClient: ActivityEventsPage
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding the activity service.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/activity-service

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
packages/euler-v2-sdk/src/services/activityService/activityService.ts (1)

99-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract duplicated categories/eventTypes normalization into a shared helper.

The categories/eventTypes normalization block is duplicated identically in getQueryKeyAccountActivityEvents and getQueryKeyVaultActivityEvents. A future edit to one (e.g., changing how eventTypes are normalized) could easily be missed in the other, producing inconsistent query-key/cache behavior between account and vault activity queries.

♻️ Proposed refactor to share normalization logic
+function normalizeActivityFilters(args: {
+	categories?: readonly string[];
+	eventTypes?: readonly string[];
+}): { categories: unknown[] | undefined; eventTypes: unknown[] | undefined } {
+	return {
+		categories:
+			args.categories === undefined
+				? undefined
+				: normalizeQueryKeySet([...args.categories]),
+		eventTypes:
+			args.eventTypes === undefined
+				? undefined
+				: normalizeQueryKeySet(
+						args.eventTypes.map((eventType) => eventType.trim().toLowerCase()),
+					),
+	};
+}

 	getQueryKeyAccountActivityEvents(
 		args: FetchAccountActivityEventsArgs,
 	): string | null {
 		const chainIds = Array.isArray(args.chainId)
 			? [...args.chainId]
 			: [args.chainId];
 		return serializeQueryArgs([
 			{
 				...args,
 				owner: getAddress(args.owner),
 				chainId: normalizeQueryKeySet(chainIds),
-				categories:
-					args.categories === undefined
-						? undefined
-						: normalizeQueryKeySet([...args.categories]),
-				eventTypes:
-					args.eventTypes === undefined
-						? undefined
-						: normalizeQueryKeySet(
-								args.eventTypes.map((eventType) =>
-									eventType.trim().toLowerCase(),
-								),
-							),
+				...normalizeActivityFilters(args),
 			},
 		]);
 	}

Apply the same substitution in getQueryKeyVaultActivityEvents.

Also applies to: 130-151

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/euler-v2-sdk/src/services/activityService/activityService.ts` around
lines 99 - 124, Extract the shared categories and eventTypes normalization logic
from getQueryKeyAccountActivityEvents and getQueryKeyVaultActivityEvents into a
helper, then call that helper from both query-key methods. Preserve the existing
undefined handling, category normalization, and trimmed lowercased eventType
normalization so account and vault queries remain consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/euler-v2-sdk/src/sdk/buildSDK.ts`:
- Around line 1547-1567: Add a canBuildActivityV3 guard around ActivityV3Adapter
construction in the activityService setup, using the resolved activity
configuration’s endpoint validation. When disableV3 is true or the endpoint is
empty/misconfigured after trimming, select UnavailableActivityAdapter instead;
only construct ActivityV3Adapter when the configuration is buildable, matching
the existing accountV3, eVaultV3, eulerEarnV3, vaultType, and rewards patterns.

In `@packages/euler-v2-sdk/src/services/activityService/activityEvent.ts`:
- Around line 517-526: Update the cursor validation in the activity event
response parsing flow to reject any non-null nextCursor longer than 2,048
characters immediately, before pagination returns it for a subsequent request.
Preserve the existing hasMore/null consistency checks and use the parsed
nextCursor value from this block.

In
`@packages/euler-v2-sdk/src/services/activityService/adapters/activityV3Adapter.ts`:
- Around line 191-196: Add an AbortController-based timeout to the request in
fetchEvents, following the repository’s established timeout pattern. Pass the
controller’s signal to fetch, ensure the timeout is cleared after the request
completes, and preserve the existing response-text handling.

---

Nitpick comments:
In `@packages/euler-v2-sdk/src/services/activityService/activityService.ts`:
- Around line 99-124: Extract the shared categories and eventTypes normalization
logic from getQueryKeyAccountActivityEvents and getQueryKeyVaultActivityEvents
into a helper, then call that helper from both query-key methods. Preserve the
existing undefined handling, category normalization, and trimmed lowercased
eventType normalization so account and vault queries remain consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: euler-xyz/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 04225dad-3bdb-4111-bb3c-2e3dd8bc68f1

📥 Commits

Reviewing files that changed from the base of the PR and between 36868c8 and b5f6846.

📒 Files selected for processing (15)
  • packages/euler-v2-sdk/docs/config-through-env.md
  • packages/euler-v2-sdk/docs/configuration.md
  • packages/euler-v2-sdk/src/index.ts
  • packages/euler-v2-sdk/src/sdk/buildSDK.ts
  • packages/euler-v2-sdk/src/sdk/config.ts
  • packages/euler-v2-sdk/src/sdk/defaultConfig.ts
  • packages/euler-v2-sdk/src/sdk/sdk.ts
  • packages/euler-v2-sdk/src/services/activityService/activityEvent.ts
  • packages/euler-v2-sdk/src/services/activityService/activityService.ts
  • packages/euler-v2-sdk/src/services/activityService/activityServiceTypes.ts
  • packages/euler-v2-sdk/src/services/activityService/adapters/activityV3Adapter.ts
  • packages/euler-v2-sdk/src/services/activityService/index.ts
  • packages/euler-v2-sdk/src/utils/queryNames.ts
  • packages/euler-v2-sdk/test/activityService.test.ts
  • packages/euler-v2-sdk/test/sdkConfig.test.ts

Comment thread packages/euler-v2-sdk/src/sdk/buildSDK.ts
Comment thread packages/euler-v2-sdk/src/services/activityService/activityEvent.ts
Comment thread packages/euler-v2-sdk/src/services/activityService/adapters/activityV3Adapter.ts Outdated

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Changes requested

Reviewed PR #66 at head 53dcee31d68653950afb4a9b87042eac29e63637.

The normalized account/vault route paths, query names, response coverage model, config precedence, cache-key canonicalization, root exports, and optional EulerSDKOptions.activityService wiring are coherent. The latest commit also resolves CodeRabbit’s blank-endpoint and oversized-cursor findings. I found two blocking edge cases in the new response path, detailed inline.

Blocking findings

  • The ten-second timeout ends when response headers arrive, before response.text() consumes the body. A headers-first/stalled body can therefore hang forever; the focused review fixture confirms the timer count is already zero while body parsing remains pending after ten seconds.
  • Activity validation rejects subaccount ID 256, although this package publicly defines SUB_ACCOUNT_MAX_ID = 256 and getSubAccountAddress(owner, 256) produces that canonical SDK value. The focused fixture confirms such an account response is rejected.

Backend / integration evidence

  • Compared against stacked euler-data-v3 PRs #273 (231e3e5) and #274 (451408f): account/vault paths, wire query names, coverage states, cursor bound, and normalized response fields align.
  • #273 and #274 remain open, and #274 is stacked on #273. Their merge/deploy order remains a release gate; local SDK validation does not prove the normalized routes are deployed.
  • CodeRabbit’s timeout thread is only partially resolved: the header wait is bounded, but body consumption is not. Its other two actionable threads are fixed on this head.

Validation

  • pnpm install --frozen-lockfile — passed.
  • Full SDK suite — 32 files / 440 tests passed.
  • pnpm --filter @eulerxyz/euler-v2-sdk typecheck — passed.
  • pnpm --filter @eulerxyz/euler-v2-sdk build — passed.
  • Activity changed-file Biome check — passed.
  • Built-package runtime export smoke — passed for the new activity symbols.
  • git diff --check origin/main...HEAD — passed.
  • Focused local discriminating checks — 3/3 passed, reproducing the stalled-body timeout gap, subaccount-256 rejection, and relative-endpoint search/hash behavior. The temporary test was removed; worktree is clean.
  • Whole-diff security/supply-chain sweep — no dependency, workflow, secret, transaction-construction, or suspicious execution changes found.

Scalability / maintainability hygiene

The service is the correct reusable boundary and sibling config/query/export flows are covered. Two maintainability gaps remain: request normalization is duplicated between cache-key construction and V3 serialization, creating drift risk; and bounded request cardinality is undermined by unbounded response-body time/size. The latter is blocking here. Focused regression tests should cover headers followed by a stalled body and the shared subaccount boundary.

Screenshots: not applicable; SDK-only change with no UI surface.

comment lifecycle: no Leonard top-level issue comment exists to edit; no current Leonard inline comments exist to clean up; prior formal review history was preserved.

Comment thread packages/euler-v2-sdk/src/services/activityService/activityEvent.ts Outdated
Comment thread packages/euler-v2-sdk/src/services/activityService/activityEvent.ts Outdated
@Seranged
Seranged requested a review from LeonardEulerXYZ July 13, 2026 12:45

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Changes requested

Reviewed PR #66 at head afa4d0360779a153a55b94ec72d7e261299de40a.

The latest commit fixes both prior blockers: the ten-second deadline now remains active through streamed body consumption, and account-family validation reuses the package's exported subaccount helper/boundary so ID 256 is accepted and invalid relatives are rejected. I found one remaining transport cleanup blocker in the new response-size path, detailed inline.

Blocking finding

  • When Content-Length advertises more than 2 MiB, the SDK rejects before acquiring or cancelling the response body, then clears the request timeout without aborting the controller. The focused fixture confirms the promise rejects while both signal.aborted and the stream's cancellation flag remain false. An oversized response can therefore continue consuming connection/network resources after the caller has received the error. Abort the request or cancel the body on this path, and cover the cleanup invariant in a regression test.

Validation performed

  • Full diff and surrounding-code review across all 15 changed files, plus focused inspection of the latest afa4d03 delta.
  • pnpm exec vitest run test/activityService.test.ts — 40/40 passed.
  • pnpm test — 32 files / 443 tests passed.
  • pnpm typecheck — passed.
  • pnpm build — passed.
  • git diff --check origin/main...HEAD — passed.
  • Focused built-package transport fixture — reproduced the oversized-Content-Length cleanup gap: { signalAborted: false, bodyCancelled: false }.
  • Rechecked the prior regressions: headers-first stalled-body timeout passes; exported subaccount ID 256 passes and 257 is rejected.
  • Whole-diff security/supply-chain sweep — no dependency, workflow, secret, transaction-construction, shell-execution, or suspicious network changes beyond the intended Activity V3 HTTP adapter.

Integration boundary

The normalized Activity backend dependencies, euler-data-v3 #273 and #274, are still open; #274 remains stacked on #273. Their merge/deploy order and the subsequent SDK publish/consumer bump remain release gates. The SDK remains network-neutral when Activity/V3 is not configured.

Screenshots: not applicable; SDK-only change with no UI surface.

Comment lifecycle: deleted the two stale Leonard inline blocker comments after verifying their fixes; preserved prior formal review history.

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Changes requested

Reviewed PR #66 at head a630d50e4fed317e542453587a1187752b4ad6c8.

The latest commit correctly fixes the prior oversized-response cleanup blocker: both header-declared and streamed oversize failures now cancel the body, abort the request, and clear the deadline. The public exports, optional constructor wiring, normalized route/query shape, cache-key ordering, strict response parsing, and config precedence remain coherent. Two blockers remain: one credential-boundary issue in the new transport and one producer/consumer mismatch with the linked normalized Activity API.

Blocking findings

  • The V3 fetch follows redirects while attaching X-API-Key. Node 22 forwards that custom header across a cross-origin 302, so an open redirect or compromised configured endpoint can disclose a dedicated/shared V3 key. Disable redirects or enforce same-origin redirects.
  • The SDK accepts and tests the exported XOR sub-account ID 256, but linked euler-data-v3 PR #274 at 2e6249ba590c374285701ad804536969365933ee still enumerates only final-byte variants 0..255, rejects indices above 255, and derives the index from the final byte. Account Activity therefore omits canonical ID 256 while potentially reporting complete coverage. The producer and SDK contract must agree before this integration is safe to ship.

Concrete findings are inline.

Validation performed

  • Full diff/context review across all 15 changed files and focused review of latest commit a630d50.
  • pnpm install --frozen-lockfile — passed.
  • Full SDK suite — 32 files / 444 tests passed.
  • SDK typecheck and package build — passed.
  • Package lint — exit 0 with existing unrelated warnings/information in src/utils/*.
  • git diff --check origin/main...HEAD — passed; worktree restored clean after Corepack's local packageManager mutation.
  • Focused Node 22 redirect fixture — cross-origin 302 received X-API-Key: secret; Authorization was stripped.
  • Cross-repo contract pass against euler-data-v3 #273 (231e3e5) and #274 (2e6249b): route names, query serialization, response envelope, coverage aggregation, cursor bounds, and filter bounds otherwise align. Relevant backend Activity tests passed in the independent contract pass.
  • Live default V3 OpenAPI currently has no normalized /v3/activity/* paths; backend deploy, SDK publish, and consumer dependency bumps remain sequencing gates.
  • Whole-diff security/supply-chain sweep found no dependency, workflow, transaction-construction, generated-package, secret literal, or suspicious execution changes beyond the redirect credential issue above.

Scalability / maintainability hygiene pass

Starting from the reusable Activity-service intent, I checked sibling SDK V3 adapters, config/env resolution, service overrides, package exports, query-key construction, and linked Lite consumers (#736/#737). The abstraction is correctly SDK-owned, but request canonicalization is duplicated between ActivityService cache keys and ActivityV3Adapter URL serialization, and the new adapter adds another bespoke V3 transport beside EVault/intrinsic-APY transports with already-different path/timeout semantics. These are non-blocking follow-up candidates for shared canonical-argument and V3 HTTP helpers with focused contract tests. The linked Lite PRs also still pin published SDK 1.1.4, and portfolio Activity lacks an account-branch composable regression; those are downstream sequencing/test gates rather than additional defects in this SDK diff.

Bot/reviewer feedback

CodeRabbit's three actionable threads (blank endpoint, oversized response cursor, and body timeout) are resolved on this head. I did not promote any stale bot suggestion into a Leonard finding.

Screenshots: not applicable; this is an SDK/API change with no UI surface.

comment lifecycle: no Leonard issue walkthrough exists to edit; deleted 1 stale Leonard inline blocker after verifying the latest fix; prior formal review history preserved.

Comment thread packages/euler-v2-sdk/test/activityService.test.ts
Comment thread packages/euler-v2-sdk/test/activityService.test.ts
@Seranged
Seranged requested a review from LeonardEulerXYZ July 13, 2026 15:03
@Seranged

Copy link
Copy Markdown
Contributor Author

Follow-up fixes are live on current head b0c9ed5. Commit a630d50 cancels/aborts oversized or failed response bodies before timeout cleanup; b0c9ed5 rejects redirects at the credentialed fetch boundary with a real two-origin regression. The XOR-256 producer contract is aligned in euler-data-v3 PR 274 at 675e624. Full SDK suite: 445 passed; typecheck, build, Biome, diff-check, and review-last pass.

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Approved

Reviewed PR #66 at head b0c9ed5e51a24a83a055dda02e2dc4d5bde3264b.

The latest commit fixes the credential-boundary blocker by rejecting redirects before the Activity request can forward X-API-Key to another origin. The two-origin regression confirms the configured origin receives the key while the redirect target receives no request. The earlier subaccount-family integration blocker is also now resolved in the linked producer: current euler-data-v3 PR #274 head 675e6249f3bbe8b762aa65dc7f56c20fb94352aa enumerates and validates the full XOR family through ID 256, matching this SDK's exported SUB_ACCOUNT_MAX_ID contract.

The normalized account/vault routes, query serialization, response validation and coverage model, cache-key canonicalization, optional constructor wiring, config/env precedence, root exports, timeout/body-size cleanup, and unavailable-service behavior are coherent.

Validation performed

  • Full diff and surrounding-code review across all 15 changed files.
  • pnpm install --frozen-lockfile — passed.
  • Full SDK suite — 32 files / 445 tests passed, including 42 Activity tests.
  • pnpm --filter @eulerxyz/euler-v2-sdk typecheck — passed.
  • pnpm --filter @eulerxyz/euler-v2-sdk build — passed.
  • Built-package runtime export smoke — passed for the new Activity exports.
  • pnpm --filter @eulerxyz/euler-v2-sdk lint — exit 0 with existing unrelated warnings/information under src/utils/*.
  • git diff --check origin/main...HEAD — passed.
  • Two-origin redirect fixture — passed; redirect target received no request/API key.
  • Cross-repo contract pass against current euler-data-v3 #273 (afc9ffd) and #274 (675e624): route/query/response contracts and XOR subaccount IDs 0..256 align. Both backend PRs remain open and stacked; merge/deploy order remains a release gate.
  • Package/dependency pass against Lite #736/#737: consumers still need the post-merge SDK publish/version-lock update and backend deployment before enabling Activity.
  • Whole-diff security/supply-chain sweep — no dependency, workflow, secret literal, transaction-construction, shell-execution, or suspicious network behavior found beyond the intended Activity V3 fetch.

Scalability / maintainability hygiene pass

Started from the reusable Activity-read intent and checked sibling V3 adapters, config/env resolution, query decoration, cache keys, package exports, response filtering, and linked Lite account/vault consumers. The SDK-owned adapter/service boundary is the correct reusable abstraction and focused tests cover account/vault parity, canonical filters, cursor scoping, unavailable/partial/syncing states, transport deadlines, response caps, redirect isolation, and constructor compatibility. Request/cache normalization is duplicated between the service and adapter, and the generic query cache retains expired entries; these are reasonable shared-helper/cache follow-ups, not blockers specific to this integration.

Bot/reviewer feedback

CodeRabbit's actionable findings for blank endpoints, oversized cursors, and request timeouts are resolved on this head. Its remaining duplicated-filter-normalization note is a non-blocking maintainability suggestion. No material active bot finding remains.

Screenshots: not applicable; SDK/API change with no UI surface.

comment lifecycle: deleted 2 stale Leonard inline blockers after verifying the redirect and producer-contract fixes; no Leonard top-level walkthrough existed to edit.

@Seranged Seranged mentioned this pull request Jul 13, 2026
4 tasks
@Seranged

Copy link
Copy Markdown
Contributor Author

Dependency update: the shared EVC account-family boundary correction is open in #76.

Valid IDs are 0–255 (256 addresses total, including primary ID 0). This Activity branch imports SUB_ACCOUNT_MAX_ID, so it should rebase onto main after #76 merges before PR #66 is merged or published. Its existing boundary regression will then exercise max ID 255 and reject 256.

Seranged added 8 commits July 14, 2026 09:31
Adds a V3-backed activity service with account and vault event fetchers, normalized activity labels/categories, SDK config wiring, and coverage for local proxy usage.
Adds coverage showing activity-specific V3 endpoint and API key config override the shared V3 config, matching the SDK service convention.
Makes activityService optional for direct EulerSDK construction and falls back to the default V3 activity service when omitted.
Align the SDK adapter, validation, capability reporting, and configuration with the normalized V3 Activity contract.
@Seranged
Seranged force-pushed the feature/activity-service branch from b0c9ed5 to fafc100 Compare July 14, 2026 08:32
@Seranged

Copy link
Copy Markdown
Contributor Author

Rebased onto current main after the EVC boundary correction merged.

Current head: fafc100

  • Activity validation now inherits SUB_ACCOUNT_MAX_ID = 255.
  • Account-family ID 255 is accepted and ID 256 is rejected.
  • git range-diff confirms all eight Activity commits are patch-identical to the pre-rebase series.
  • Focused Activity suite: 42 passed.
  • Full SDK suite: 32 files / 446 passed.
  • Typecheck and package build passed.
  • Repository lint exits cleanly with existing unrelated diagnostics.
  • PR description now reflects the 0–255 contract.

Ready for re-review.

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Changes requested

Reviewed PR #66 at head fafc100412af0fee482bc79604423a566e91fb9d.

The Activity service is structurally sound: account/vault route construction, coverage/cursor handling, opt-in configuration, constructor compatibility, response-size/deadline controls, redirect rejection, public exports, and the corrected EVC subaccount boundary all held up. The full SDK suite, typecheck, build, changed-file Biome lint, and diff hygiene passed.

Blocking finding

The V3 adapter accepts arbitrary non-empty eventTypes, while the linked normalized API in euler-data-v3#274 accepts only its closed ACTIVITY_EVENT_TYPES enum and returns HTTP 400 for unknown values. This makes an invalid backend request valid in the SDK's typed public surface. See the inline comment.

Cross-repo / rollout evidence

  • SDK route paths, parameter names, coverage model, cursor contract, chain/category/time/limit bounds, and vault types otherwise match euler-data-v3#274 at current head cdfb630.
  • The production Activity routes currently return 404, and the published SDK/Lite consumers have not yet been bumped. Those are documented rollout gates, not additional defects in this branch.
  • The old unresolved 0–256 discussion is stale: current SDK/backend heads agree on valid subaccount IDs 0–255, with 256 rejected.

Scalability / maintainability hygiene

Account and vault flows, config precedence, unavailable/custom adapters, exports, and cache integration are covered. One non-blocking consolidation remains: category/event-type canonicalization is repeated in cache-key generation, V3 URL serialization, and response scoping. A shared internal canonical-query helper would prevent those three definitions drifting. The remaining CodeRabbit duplication nit is therefore valid; its earlier endpoint, cursor, timeout, and transport findings are fixed on this head.

Validation

  • pnpm --filter @eulerxyz/euler-v2-sdk test — 32 files, 446 tests passed
  • pnpm --filter @eulerxyz/euler-v2-sdk typecheck — passed
  • pnpm --filter @eulerxyz/euler-v2-sdk build — passed
  • changed-file biome lint — passed
  • git diff --check origin/main...HEAD — passed
  • full 15-file security/supply-chain sweep — no suspicious dependency, workflow, script, secret, generated-artifact, or transaction-construction changes

No screenshots: this is an SDK/API change with no directly rendered UI in this PR.

Comment thread packages/euler-v2-sdk/src/services/activityService/adapters/activityV3Adapter.ts Outdated
Expose the normalized V3 event type union and reject unsupported request or response values before they reach consumers.
Comment thread packages/euler-v2-sdk/src/services/activityService/adapters/activityV3Adapter.ts Outdated

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Changes requested

Reviewed PR #66 at head 7f955a88a5d6a3022ba5f469efb78daae458c246. The latest commit fixes the prior SDK/backend event-type mismatch: the exported 78-value union now has exact parity with merged euler-data-v3#274, and both request and response paths reject unknown types. The earlier blank-endpoint, oversized-cursor, timeout/body-cap, redirect, constructor-compatibility, and EVC-family findings also remain fixed.

Two issues remain, detailed inline:

  1. Response scope validation omits from, to, and limit. A successful response can contain events outside the caller's requested inclusive time window or more rows than requested, yet still pass the SDK's otherwise fail-closed request-bound validation and enter the query cache. A focused built-artifact smoke confirmed both accepted_out_of_window=true and accepted_over_limit=true.
  2. Activity pagination makes the default cache's unbounded retention material. Every cursor produces a one-use cache key, while expired entries are never evicted unless that exact key is requested again. Long-lived integrators can therefore retain every fetched page indefinitely.

Validation

  • pnpm install --frozen-lockfile
  • full SDK suite: 32 files / 448 tests passed
  • pnpm --filter @eulerxyz/euler-v2-sdk typecheck passed
  • pnpm --filter @eulerxyz/euler-v2-sdk build passed
  • changed-file Biome lint passed
  • git diff --check origin/main...HEAD passed
  • focused built-artifact response-scope smoke reproduced both acceptance gaps
  • live production account and vault Activity routes returned HTTP 200 with the expected {data, meta} envelope
  • whole-diff dependency, secret, executable, network, and supply-chain sweep found no malicious-code indicators; no dependency/lockfile/workflow changes

Scalability / maintainability hygiene

The producer/SDK boundary is sensibly centralized, and Lite's vault and portfolio work share one activity feed/display stack. Remaining hygiene: consolidate duplicated category/event-type canonicalization across query keys, URL serialization, and response scoping; consider a generated/parity invariant for the manually duplicated 78-value event enum. Downstream, Lite#736/#737 still lock published SDK 1.1.4, so publishing and lockfile bumping remain sequencing gates; #737 also needs direct account-branch feed coverage. Those downstream items do not independently block this SDK diff.

Bot feedback

CodeRabbit's blank-endpoint, oversized-cursor, and timeout concerns are fixed on this head and should be treated as stale. Its duplicated filter-normalization nit remains valid but non-blocking.

No screenshots: this is an SDK/API change with no user-visible surface in this repository.

Comment thread packages/euler-v2-sdk/src/services/activityService/activityEvent.ts
Comment thread packages/euler-v2-sdk/src/sdk/buildSDK.ts
- reject rows outside requested time and page limits
- bypass default caching for cursor-based activity pages
Comment thread packages/euler-v2-sdk/src/sdk/buildSDK.ts
Comment thread packages/euler-v2-sdk/src/services/activityService/activityEvent.ts

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Changes requested

Reviewed PR #66 at head 02db958bb3ae78d00410e298ad73aef2aa661a48.

The latest commit resolves the two prior blockers in the built-in SDK path: account and vault responses now enforce from, to, and limit, and cursor pages bypass createQueryCacheBuildQuery. The focused regressions cover both scopes, exact/inclusive boundaries, over-limit responses, first-page deduplication, and repeated cursor calls.

One downstream cache-contract issue remains, detailed inline. ActivityService now uses null from getQueryKey* as an explicit “do not cache” signal, but the repository’s documented/custom React Query builder replaces that null with serializeQueryArgs(args) via ?? and caches the cursor page anyway. The SDK’s own React example is wired globally through this builder. Thus custom buildQuery consumers following the repository guidance silently miss the fix and retain cursor pages. Please make the null-key bypass contract explicit, update the example/docs to call the underlying fetcher directly for null, and add a focused regression.

Validation

  • pnpm install --frozen-lockfile — passed
  • full SDK suite — 32 files / 451 tests passed
  • SDK typecheck — passed
  • SDK package build — passed
  • changed-source Biome lint — passed
  • built-package Activity root-export smoke — passed
  • React SDK example production build — passed
  • git diff --check origin/main...HEAD — passed
  • cross-repo contract check against merged euler-data-v3 Activity implementation — route/query bounds and whole-second timestamp semantics align
  • whole-diff security/supply-chain sweep — no dependency, lockfile, workflow, secret literal, transaction-construction, or suspicious execution changes

Scalability / maintainability hygiene

Starting from the reusable Activity-read intent, I checked the built-in cache, custom BuildQueryFn contract, React Query example, caching documentation, account/vault parity, linked Lite consumers, and producer contract. The SDK-owned Activity service is the right abstraction, but cache-bypass semantics must compose through custom builders; otherwise the same pagination leak survives in the canonical sibling flow. Non-blocking follow-up: category/event-type canonicalization remains duplicated across cache keys, URL serialization, and response scoping.

Bot feedback

CodeRabbit’s blank-endpoint, oversized-cursor, and timeout findings are fixed on this head. Its remaining normalization-duplication concern is valid maintainability hygiene, not a blocker. No stale bot claim was promoted into this verdict.

Screenshots: not applicable; this PR changes an SDK/API surface and has no rendered UI.

comment lifecycle: no Leonard issue walkthrough exists to edit; the two prior Leonard inline blockers were verified fixed and removed before this review.

@LeonardEulerXYZ LeonardEulerXYZ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leonard re-review: Approved

Reviewed PR #66 at head 9889988265d25018bcb729c5cb95fc81ff60f432.

The latest commit resolves the remaining custom-cache blocker. BuildQueryContext.getCacheKey(args) === null is now a documented no-cache signal, the canonical React Query builder invokes the intercepted fetcher directly for cursor pages, and the focused regression proves account and vault cursor calls bypass the custom cache while first-page calls still deduplicate.

No remaining blocking correctness, SDK compatibility, transport/security, generated-export, or downstream contract issue was found.

Contract and integration evidence

  • Request paths, filters, limits, cursor bounds, coverage semantics, response envelope, EVC subaccount range, and the 78-value event-type union match current euler-data-v3 main (9026bbb); the event enums have exact 78/78 order parity.
  • A live built-artifact smoke against https://v3.euler.finance/v3/activity returned HTTP 200 and passed the SDK's strict response normalization for a chain-1 account fixture.
  • Root package exports and built declarations include ActivityService, ActivityV3Adapter, unavailable-adapter support, event types, and Activity constants.
  • Lite #736/#737 consume the same public service/types through shared vault/account feed primitives. Publishing the SDK and updating Lite's package/lockfile remain explicit rollout gates, not defects in this PR.

Validation

  • pnpm install --frozen-lockfile — passed
  • full SDK suite — 32 files / 452 tests passed
  • pnpm --filter @eulerxyz/euler-v2-sdk typecheck — passed
  • pnpm --filter @eulerxyz/euler-v2-sdk build — passed
  • SDK package lint and focused changed-source Biome check — passed
  • React SDK example production build — passed
  • changed React query wrapper ESLint — passed
  • git diff --check origin/main...HEAD — passed
  • whole-diff and per-commit security/supply-chain sweep — no dependency, lockfile, workflow, executable-script, secret, transaction-construction, or suspicious execution changes

The example package's full eslint . still reports unrelated pre-existing errors in untouched files; the changed query wrapper itself is clean.

Scalability / maintainability hygiene

Starting from the reusable Activity-read intent, I checked sibling account/vault flows, config precedence, public exports, built-in and custom query caches, response scoping, producer parity, and linked Lite consumers. The adapter/service boundary is the correct shared abstraction, and account/vault behavior is covered symmetrically. Non-blocking follow-up: category/event-type canonicalization is still repeated across cache-key generation, URL serialization, and response scoping; a shared internal canonical-query helper plus an automated backend/SDK enum-parity check would reduce future drift.

Bot/reviewer feedback

The earlier CodeRabbit endpoint, cursor, and timeout findings are fixed. The prior Leonard cursor-cache thread is fixed and already resolved; no stale active bot finding remains.

Screenshots: not applicable; this PR changes an SDK/API surface and has no rendered UI in this repository.

comment lifecycle: no Leonard top-level walkthrough existed; the prior Leonard inline thread is resolved, so no deletion or duplicate comment was needed.

@Seranged
Seranged merged commit a994012 into main Jul 20, 2026
1 check 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.

3 participants