Skip to content

feat(affiliate): use verified actuals for swap fee amounts and expose partnerBps#12311

Merged
kaladinlight merged 5 commits intodevelopfrom
feat/affiliate-dashboard-verified-actuals
May 1, 2026
Merged

feat(affiliate): use verified actuals for swap fee amounts and expose partnerBps#12311
kaladinlight merged 5 commits intodevelopfrom
feat/affiliate-dashboard-verified-actuals

Conversation

@kaladinlight
Copy link
Copy Markdown
Contributor

@kaladinlight kaladinlight commented May 1, 2026

Description

Reworks the affiliate swaps endpoint to derive USD fee amounts using a tiered priority — actual on-chain amounts first, then inferred from volume × bps — and exposes partnerBps directly in the public API so clients no longer compute it.

  • New calculateAffiliateFeeAmountUsd helper with three-tier priority: (1) actual fee amount × affiliate asset USD, (2) volume × bps inferred from buy/sell side based on affiliateFeeAssetId, (3) null. Prefers verified amounts from affiliateVerificationDetails when present.
  • getAffiliateSwaps now derives affiliateBps and partnerBps server-side, returns buyAmountCryptoPrecision / buyAmountUsd, and renames affiliateFeeUsdaffiliateFeeAmountUsd.
  • Upstream SwapServiceAffiliateSwapSchema extended with sellAssetUsd, actualAffiliateFeeAmountCryptoBaseUnit, affiliateAssetUsd, affiliateFeeAssetId, and affiliateVerificationDetails.
  • Renamed AffiliateSwapItemSchemaAffiliateSwapSchema and exported SwapServiceAffiliateSwap type.
  • affiliate-dashboard updated to consume new fields directly; removed local partnerBps computation. USD format now allows up to 4 fractional digits to surface sub-cent fee amounts.
  • Adds unit test coverage for calculateAffiliateFeeAmountUsd across all priority tiers and edge cases.

Issue (if applicable)

closes #

Risk

Low — read-only API change scoped to the affiliate swaps endpoint and its dashboard consumer. No on-chain transactions affected. The response shape changes (renamed/added fields), but the only consumer in this repo is the affiliate-dashboard, which is updated in lockstep.

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

None.

Testing

Engineering

  • Run pnpm --filter @shapeshiftoss/public-api test — new calculateAffiliateFeeAmountUsd.test.ts covers all three priority paths plus fallbacks.
  • Hit /v1/affiliate/swaps against a swap-service that returns the new upstream fields and confirm affiliateFeeAmountUsd, partnerBps, buyAmountCryptoPrecision, and buyAmountUsd are populated.
  • Load the affiliate-dashboard swaps table and verify volume, fee, partner BPS, and ShapeShift BPS columns render correctly for verified, unverified, and null-bps swaps.

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added partner fee amount calculation in USD for improved earnings transparency.
  • Bug Fixes

    • Partner BPS now displays actual values directly instead of derived calculations.
    • Period date calculations now use local timezone.
    • USD amounts format with up to 4 decimal places for greater precision.
    • Swaps table layout refinements for improved readability.

kaladinlight and others added 2 commits April 30, 2026 16:36
Reshape the affiliate swaps endpoint around verified on-chain values:
fee USD is derived from the actual paid amount when recorded, falling
back to volume × bps (buy-side when feeAssetId matches buyAsset, else
sell-side). Sell/buy amounts now prefer verified/actual over expected.

Drops the verbose `affiliateVerificationDetails`, `affiliateFeeAsset`,
and `affiliateFeeAmountCryptoPrecision` from the response — the
dashboard only needs the resolved USD value and bps. Bumps dashboard
fee precision to 4 decimals so small actual fees aren't rounded to
zero.

Calculation extracted to `calculateAffiliateFeeAmountUsd` with unit
tests covering each priority tier.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Compute partnerBps server-side as max(0, affiliateBps - shapeshiftBps)
so consumers don't have to derive it. affiliateBps defaults to 0 when
no source value exists, making both bps fields non-nullable. The
inferred fee USD calc now scales by partnerBps so the value reflects
the partner's share.

Tightens swaps table column layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kaladinlight kaladinlight requested a review from a team as a code owner May 1, 2026 00:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 1, 2026

Warning

Rate limit exceeded

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

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

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

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

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

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

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5eebbc5a-3e19-45e5-9e86-60a61ac8b690

📥 Commits

Reviewing files that changed from the base of the PR and between 9b85529 and af9f130.

📒 Files selected for processing (2)
  • packages/affiliate-dashboard/src/hooks/useAffiliateConfig.ts
  • packages/public-api/src/routes/affiliate/types.ts
📝 Walkthrough

Walkthrough

Affiliate swap data handling is refactored with field restructuring (expectedBuyAmountCryptoPrecision/actualBuyAmountCryptoPrecision → buyAmountCryptoPrecision/buyAmountUsd, affiliateBps → partnerBps), a new partner fee USD calculation function, stricter schema validation (removed passthrough), and timezone handling shifted from UTC to local time.

Changes

Cohort / File(s) Summary
API Schema & Type Definitions
packages/public-api/src/routes/affiliate/types.ts
Renamed AffiliateSwapItem to AffiliateSwap schema; replaced buy amount and fee fields with new USD/precision variants; expanded upstream SwapServiceAffiliateSwapSchema with additional USD and affiliate fee breakdown fields; added affiliateVerificationDetails object.
Partner Fee Calculation Logic
packages/public-api/src/routes/affiliate/calculatePartnerFeeAmountUsd.ts, packages/public-api/src/routes/affiliate/calculatePartnerFeeAmountUsd.test.ts
New function computes partner fee USD using on-chain calculation (when available) or fallback inferred calculation; comprehensive test suite with fixtures and multiple priority flows.
API Response Mapping
packages/public-api/src/routes/affiliate/getAffiliateSwaps.ts
Updates swap response to use new field names (buyAmountCryptoPrecision, buyAmountUsd, affiliateFeeAmountUsd, partnerBps); derives partnerBps from affiliateVerificationDetails; calculates partner fee USD via calculatePartnerFeeAmountUsd; removes passthrough validation.
Dashboard Hook & Validation
packages/affiliate-dashboard/src/hooks/useAffiliateSwaps.ts
Client-side Zod schema updated to match API field structure; removed passthrough() for stricter validation; AffiliateSwap type infers new field set.
Dashboard Display
packages/affiliate-dashboard/src/components/swaps/SwapsTable.tsx
Displays swap.partnerBps directly instead of derived calculation; USD cells refactored to use formatUsdOrDash; numeric columns centered with adjusted spacing constraints.
Utilities
packages/affiliate-dashboard/src/lib/format.ts, packages/affiliate-dashboard/src/lib/periods.ts
formatUsd now allows up to 4 fraction digits; month/period computations switched from UTC to local timezone date parts for month key generation and boundaries.

Poem

🐰 Fields reshape and flow anew,
Partner fees calculated true,
Local time instead of UTC's way,
Swaps display in brighter day,
With stricter schemas, cleaner sight,
The dashboard dances in the light! ✨

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and concisely describes the two main changes: using verified actuals for swap fee amounts and exposing partnerBps, which align with the PR's core objectives.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/affiliate-dashboard-verified-actuals

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

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 52 minutes and 3 seconds.

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

…liateBps

Renames the helper to calculatePartnerFeeAmountUsd and scales the on-chain
captured fee by partnerBps / affiliateBps so path 1 (verified actuals) and
path 2 (volume × bps) both report the partner's share rather than the total
captured. Drops affiliateBps from the response — it's redundant once
shapeshiftBps and partnerBps are exposed. Makes partnerBps nullable end-to-end
so "no fee data" is distinguishable from "0 bps", and the dashboard renders
nullable bps and fee values as an em dash. Replaces .toString() with .toFixed()
on USD amounts to avoid scientific-notation strings, and broadens test coverage
to cover priority ordering, partner-share scaling, and direct sell/buy-side
selection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kaladinlight kaladinlight enabled auto-merge (squash) May 1, 2026 00:48
@kaladinlight kaladinlight disabled auto-merge May 1, 2026 00:49
The dropdown was showing UTC months, so users in negative-UTC zones saw next
month appear (and the current month disappear) hours before their local
calendar rolled over. Compute month boundaries from local time and rely on
.toISOString() for the UTC conversion when querying — the API still receives
absolute timestamps, but they line up with the user's calendar month.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/affiliate-dashboard/src/lib/periods.ts`:
- Around line 34-37: Update the AffiliateConfigResponseSchema and the hook
schema to enforce ISO datetime strings: change
AffiliateConfigResponseSchema.createdAt to use z.string().datetime() (and add
the openapi example '2024-01-01T00:00:00.000Z' as suggested) so the API boundary
validates datetime format before it reaches generatePeriods, and update the
schema used in useAffiliateConfig (createdAt in that hook) to
z.string().datetime() as well so both the API response type and the client-side
hook match the upstream SwapServiceAffiliateSwapSchema and avoid Date parsing
timezone misalignment in generatePeriods.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8d8a246f-ec7a-4701-a26d-796872935158

📥 Commits

Reviewing files that changed from the base of the PR and between 07714b1 and 9b85529.

📒 Files selected for processing (8)
  • packages/affiliate-dashboard/src/components/swaps/SwapsTable.tsx
  • packages/affiliate-dashboard/src/hooks/useAffiliateSwaps.ts
  • packages/affiliate-dashboard/src/lib/format.ts
  • packages/affiliate-dashboard/src/lib/periods.ts
  • packages/public-api/src/routes/affiliate/calculatePartnerFeeAmountUsd.test.ts
  • packages/public-api/src/routes/affiliate/calculatePartnerFeeAmountUsd.ts
  • packages/public-api/src/routes/affiliate/getAffiliateSwaps.ts
  • packages/public-api/src/routes/affiliate/types.ts

Comment thread packages/affiliate-dashboard/src/lib/periods.ts
A bare date string like "2024-01-01" parses as UTC midnight, which when
truncated via local-time getMonth() in negative-UTC offsets shifts the
oldestMonth back a month and pads the dropdown with an empty trailing entry.
Validating at the API boundary (and matching the dashboard schema) ensures
generatePeriods only sees full ISO timestamps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kaladinlight kaladinlight enabled auto-merge (squash) May 1, 2026 01:07
@kaladinlight kaladinlight merged commit 5cb7ba2 into develop May 1, 2026
4 checks passed
@kaladinlight kaladinlight deleted the feat/affiliate-dashboard-verified-actuals branch May 1, 2026 01:15
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.

1 participant