Skip to content

Add live-verified Revolut, Swapter and NYM reporting plugins, and fix the broken test suite - #228

Open
j0ntz wants to merge 5 commits into
masterfrom
jon/reports-server-umbrella
Open

Add live-verified Revolut, Swapter and NYM reporting plugins, and fix the broken test suite#228
j0ntz wants to merge 5 commits into
masterfrom
jon/reports-server-umbrella

Conversation

@j0ntz

@j0ntz j0ntz commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Description

The working half of the umbrella task
reports-server: Umbrella.

This PR carries only the providers whose keys are known to work, and every one of
them was driven against the live partner API before this was opened. The
providers that are still blocked on a credential or a partner API change are
split out to #231 so
they cannot hold this up.

Ordering matters: the test suite was broken on master, so nothing else could be
trusted until that was fixed. It goes first, then one commit per provider.

Commits

  1. Fix broken mocha test suite - test/util.test.ts imported from
    ../lib/util, a gitignored build artifact that only exists after a build, so
    a clean checkout could not run a single test. Repointed at
    ../src/demo/clientUtil, and renamed 4 stale pluginId keys to partnerId
    in the analytics fixtures, which the current cleaner rejects.
  2. Add CI job to run the test suite - no test job existed, which is how the
    suite stayed broken. Generates the gitignored clientConfig.json then runs
    mocha on every PR.
  3. Add Swapter partner plugin - recreated under Edge credentials from partner
    PR #219.
  4. Add NYM Swap (nymswap) reporting plugin - new, reconciled against the live
    NYM partner reporting API.
  5. Add Revolut fiat payment provider - rewritten against the real API, see
    below.

Revolut was not credential-blocked, it was pointed at the wrong API

The previous version of this plugin queried
api.revolut.com/partner/v1/transactions with an Authorization: Bearer header
and got a 404, which had been read as an unprovisioned key. That endpoint does
not exist. The Revolut Ramp reporting API is:

GET https://ramp-partners.revolut.com/partners/api/2.0/orders
X-API-KEY: <key>

and it answers with the key Edge already ships in the GUI
(env.json RAMP_PLUGIN_INITS.revolut, which also carries that exact host as
apiUrl). No new credential is needed. The plugin is rewritten accordingly, and
three things about that API are worth calling out because each one silently
breaks a naive port:

  • start and end are date-only (YYYY-MM-DD). An ISO date-time, epoch
    seconds and epoch millis all return 400 Invalid field 'start'.
  • The response is a bare JSON array, not an envelope. Paging is skip/limit
    walked until a short page, with no cursor and no total.
  • Order ids are not unique. Revolut returns one row per payment attempt, so
    the same id arrives as both COMPLETED and FAILED with different amounts and
    updated_at. Since orderId keys the StandardTx document, attempts are
    collapsed to one winner per id (settled beats unsettled, then latest
    updated_at) before anything is emitted. On the live run this collapsed 1,359
    rows to 1,162 orders; without it, 197 orders would have been written twice with
    an arbitrary attempt winning.

Native assets resolve to their Edge chain with tokenId: null. Tokens resolve
their chain but leave tokenId undefined on purpose: Revolut reports no contract
address, and minting a tokenId from a guessed contract would mis-price the asset,
so the currency code carries the rates lookup instead.

nexchange was dropped as a duplicate

Evaluating paul/partnerFixes
(#229) showed it
already carries a nexchange plugin descended from the same origin as ours
(#217): the test files
are byte-identical and the plugins differ by 96 diff lines. #229 is the newer and
broader branch, by the port's original author, so shipping a second copy would
only conflict with it.

Two fixes from our port that #229 does not have are written up in
#231 and posted on
#229 itself, so neither is lost. nexchange's real blocker is a reporting-scoped
key and is independent of whose code lands.

Testing

Every provider here was driven end to end against the live partner API, read
only, using the GUI's existing env.json credentials. Production CouchDB was
never touched.

Provider Result
Revolut 1,162 StandardTx (866 complete, 295 failed, 1 pending), 1,359 raw rows collapsed, 0 duplicate orderIds
NYM 47 StandardTx (11 complete, 36 expired)
Swapter 14 StandardTx (2 complete, 12 expired)

Every emitted row was validated against the repo's own asStandardTx cleaner:
0 failures and 0 malformed rows across all three.

Static: npm run build.types clean, npm test 64 passing 1 pending, eslint
clean, verify-repo.sh --base origin/master passed.

Superseded PRs (close on merge)

Edge-owned, safe to close with a pointer here and delete the branches:
#225 (test suite + CI),
#227 (Revolut),
#224 (Swapter),
#226 (NYM).

Partner-owned fork PRs are lineage only, do not delete their branches:
#211 (Revolut),
#219 (Swapter).

Post-merge setup

Each plugin returns [] silently when its apiKey is absent, so "no rows" after
deploy looks identical to "not wired". Write the key into
reports_apps.partnerIds.<pluginId>.apiKeys.apiKey in production CouchDB, restart
reportsQuery, then confirm rows are arriving rather than assuming they are.

pluginId Key source
revolut Already held: env.json RAMP_PLUGIN_INITS.revolut.apiKey
swapter Already held: env.json SWAPTER_INIT.apiKey
nymswap Already held: env.json NYM_SWAP_INIT.apiKey

All three are human ops steps. No agent writes to production CouchDB.

Comment thread test/nym.test.ts Outdated
Comment thread src/demo/partners.ts
Comment thread src/partners/swapter.ts
Comment thread src/partners/swapter.ts
Comment thread src/partners/nexchange.ts Outdated
Comment thread src/partners/swapter.ts
Comment thread src/partners/nym.ts
Comment thread src/partners/revolut.ts Outdated
Comment thread src/partners/nexchange.ts Outdated
Comment thread src/partners/swapter.ts Outdated
Comment thread src/partners/revolut.ts
Comment thread src/partners/swapter.ts
@j0ntz
j0ntz force-pushed the jon/reports-server-umbrella branch from b26a08c to e522418 Compare July 30, 2026 20:59

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e522418. Configure here.

Comment thread src/partners/nexchange.ts Outdated
Comment thread src/partners/nym.ts
Comment thread src/partners/nym.ts Outdated
j0ntz added 5 commits July 31, 2026 14:18
The suite imported from ../lib/util, a gitignored build artifact that only
exists after a build, so a clean checkout could not run any test. Point it at
the source module instead. The analytics fixtures also still used the old
pluginId key, which the current cleaner rejects.
The suite was not run by CI, which is how it stayed broken. The job installs
with --ignore-scripts and generates the gitignored clientConfig.json before
running mocha.
Queries Swapter's tool-history reporting endpoint and maps each order to a
StandardTx. Pages are buffered so a mid-page failure retries idempotently, and
progress only advances once the full walk completes.
Queries NYM's partner reporting endpoint and converts its native-unit amounts
to major units using the live currencies list. The report timestamp keys off
createdDate because completedDate is null even on settled orders.

processNymTx follows the uniform (rawTx, pluginParams) processor contract, and
an unparseable order fails its page rather than being skipped: skipping would
let the walk complete and advance progress past an order the next run's
lookback can no longer reach.
Queries Revolut Ramp's orders endpoint, authenticated with the X-API-KEY header
that the GUI's existing ramp key uses. Two shapes of that API are easy to get
wrong and are handled explicitly: the start/end bounds are date-only, and the
response is a bare array paged by skip/limit rather than a cursor envelope.

An order id is not unique in the response. Revolut returns one row per payment
attempt, so the same id arrives both COMPLETED and FAILED. Since orderId keys
the StandardTx document, attempts are collapsed to one winner per id, settled
beating unsettled, before anything is emitted.

Native assets resolve to their Edge chain with a null tokenId. Tokens resolve
their chain but leave tokenId undefined: Revolut reports no contract address,
and a guessed one would mis-price the asset.
@j0ntz
j0ntz force-pushed the jon/reports-server-umbrella branch from e522418 to 74cfeee Compare July 31, 2026 21:19
@j0ntz j0ntz changed the title Batch reports-server umbrella: fix test suite + CI and add Revolut, Swapter, NYM, nexchange plugins Add live-verified Revolut, Swapter and NYM reporting plugins, and fix the broken test suite Jul 31, 2026
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