feat: add activity service - #66
Conversation
LeonardEulerXYZ
left a comment
There was a problem hiding this comment.
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
EulerSDKOptionsnow requiresactivityService. That makes the exportednew EulerSDK({...})constructor/options shape source-breaking for any integrator or test harness that constructs the exported class directly instead of going throughbuildEulerSDK().
Validation performed
- Diff/context review across all 10 changed files.
- V3 OpenAPI contract check for
/v3/evc/accounts/{address}/eventsand/v3/evk/vaults/{chainId}/{address}/events. - Live API smoke with
ActivityServiceagainst mainnet USDC vault0xD8b27CF359b7D15710a5BE299AF6e7Bf904984C2; response normalized and target contract helper returned the checksummed vault. pnpm install --frozen-lockfilepnpm --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 insrc/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
left a comment
There was a problem hiding this comment.
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
EulerSDKOptionsstill requiresactivityService(packages/euler-v2-sdk/src/sdk/sdk.ts). BecauseEulerSDKOptionsandEulerSDKare exported public API, this is source-breaking for directnew EulerSDK({...})users who were previously passing the complete valid service set. The generated declaration also exposesactivityService: IActivityServiceas 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
8bf86aa473cdd39ba131313f87449d9501b651a5to current headb2380af2d1624709ccc60325554fbca8b8078d54(test/activityService.test.tsonly). 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 confirmEulerSDKOptions.activityServiceis required.pnpm --filter @eulerxyz/euler-v2-sdk lint— exit 0, with pre-existing unrelated Biome warnings insrc/utils/*.git diff --check origin/main...HEAD— passed.- Live V3 smoke via built
ActivityServiceagainst:- account
0xee5b5c82a365d75e9f8a1e982687fb5b6ceb606c - mainnet USDC vault
0xD8b27CF359b7D15710a5BE299AF6e7Bf904984C2
Both endpoints returned200 application/json; normalized categories/labels and target-contract extraction matched the fixture.
- account
- 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
left a comment
There was a problem hiding this comment.
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 exposeEulerSDKOptions.activityService?: IActivityServiceandsdk.activityService: IActivityService.pnpm --filter @eulerxyz/euler-v2-sdk lint— exit 0, with existing unrelated Biome warnings insrc/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.
- account events:
- 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.
2f51bba to
b5f6846
Compare
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds 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. ChangesActivity service
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
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/euler-v2-sdk/src/services/activityService/activityService.ts (1)
99-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract duplicated categories/eventTypes normalization into a shared helper.
The categories/eventTypes normalization block is duplicated identically in
getQueryKeyAccountActivityEventsandgetQueryKeyVaultActivityEvents. 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
📒 Files selected for processing (15)
packages/euler-v2-sdk/docs/config-through-env.mdpackages/euler-v2-sdk/docs/configuration.mdpackages/euler-v2-sdk/src/index.tspackages/euler-v2-sdk/src/sdk/buildSDK.tspackages/euler-v2-sdk/src/sdk/config.tspackages/euler-v2-sdk/src/sdk/defaultConfig.tspackages/euler-v2-sdk/src/sdk/sdk.tspackages/euler-v2-sdk/src/services/activityService/activityEvent.tspackages/euler-v2-sdk/src/services/activityService/activityService.tspackages/euler-v2-sdk/src/services/activityService/activityServiceTypes.tspackages/euler-v2-sdk/src/services/activityService/adapters/activityV3Adapter.tspackages/euler-v2-sdk/src/services/activityService/index.tspackages/euler-v2-sdk/src/utils/queryNames.tspackages/euler-v2-sdk/test/activityService.test.tspackages/euler-v2-sdk/test/sdkConfig.test.ts
LeonardEulerXYZ
left a comment
There was a problem hiding this comment.
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 definesSUB_ACCOUNT_MAX_ID = 256andgetSubAccountAddress(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.
LeonardEulerXYZ
left a comment
There was a problem hiding this comment.
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-Lengthadvertises 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 bothsignal.abortedand 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
afa4d03delta. 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-Lengthcleanup 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
left a comment
There was a problem hiding this comment.
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 at2e6249ba590c374285701ad804536969365933eestill enumerates only final-byte variants0..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 localpackageManagermutation.- Focused Node 22 redirect fixture — cross-origin 302 received
X-API-Key: secret;Authorizationwas 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.
|
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
left a comment
There was a problem hiding this comment.
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 undersrc/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.
|
Dependency update: the shared EVC account-family boundary correction is open in #76. Valid IDs are |
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.
b0c9ed5 to
fafc100
Compare
|
Rebased onto current Current head:
Ready for re-review. |
LeonardEulerXYZ
left a comment
There was a problem hiding this comment.
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–256discussion is stale: current SDK/backend heads agree on valid subaccount IDs0–255, with256rejected.
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 passedpnpm --filter @eulerxyz/euler-v2-sdk typecheck— passedpnpm --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.
Expose the normalized V3 event type union and reject unsupported request or response values before they reach consumers.
LeonardEulerXYZ
left a comment
There was a problem hiding this comment.
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:
- Response scope validation omits
from,to, andlimit. 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 bothaccepted_out_of_window=trueandaccepted_over_limit=true. - 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 typecheckpassedpnpm --filter @eulerxyz/euler-v2-sdk buildpassed- changed-file Biome lint passed
git diff --check origin/main...HEADpassed- 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.
- reject rows outside requested time and page limits - bypass default caching for cursor-based activity pages
LeonardEulerXYZ
left a comment
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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-v3main (9026bbb); the event enums have exact 78/78 order parity. - A live built-artifact smoke against
https://v3.euler.finance/v3/activityreturned 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— passedpnpm --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.
Summary
activityServicefor normalized account and vault event timelines.EulerSDKwithout Activity configuration does not start making new backend requests.Public API
Account activity
Calls:
Vault activity
Calls:
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:
lendingborrowingswapsliquidationsaccountrewardsgovernanceEvery event requires:
id,chainId,timestampblockNumberas a decimal string, numericlogIndex, andtxHashtype,category, and sourceOptional fields retain source truth without inventing context:
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:
complete,partial,unsupported, orsyncingfrom the source response.Consumers should combine all three. In particular,
unsupportedis not the same as a successful empty timeline, whilepartialcan 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
ActivityServiceconsumes an activity adapter rather than hard-coding UI behavior to V3.Included adapters:
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
AbortControllerdeadline across both the header fetch and streamed body consumption, and always clear the timer after completion or failure.Content-Lengthand actual streamed-byte checks.source-not-configuredcapability rather than failing SDK construction or issuing a request.Account-family compatibility
Activity response validation reuses the SDK's exported
getSubAccountId()andSUB_ACCOUNT_MAX_IDboundary. EVC account-family IDs are limited to0–255(256 addresses total, including primary ID0), and ID256is 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:
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
@eulerxyz/euler-v2-sdkand bump the Lite Activity stack.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
Test plan
255and rejection of ID256git diff --checkpassedSummary by CodeRabbit
New Features
activityServiceandactivityServiceConfigoverrides, and exposed it on the SDK instance.activityV3ApiUrl/activityV3ApiKeyconfiguration with environment variable support; Activity defaults to shared V3 settings unless overridden.Documentation
Tests