Skip to content

Add Xgram#216

Open
paullinator wants to merge 1 commit into
masterfrom
pr-206-xgram
Open

Add Xgram#216
paullinator wants to merge 1 commit into
masterfrom
pr-206-xgram

Conversation

@paullinator

@paullinator paullinator commented Jun 4, 2026

Copy link
Copy Markdown
Member

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Description

none

Note

Medium Risk
New third-party API ingestion and large asset/network mapping tables affect reporting accuracy; watermark logic is carefully designed but incorrect mapping could mis-attribute swaps until caught by tests or ops.

Overview
Adds Xgram as a new swap partner so the reports query engine can ingest exchange history into StandardTx records.

The new plugin calls Xgram’s list-currency-options and paginated exchange-history APIs (with retries), maps Xgram statuses and networks to Edge chain/plugin and token IDs (including a static fallback for currencies missing from the API), and normalizes each order via processXgramTx. Pagination is newest-first with a 5-day lookback; latestIsoDate only advances when a full sync completes, so failed runs do not skip orders. xgram is wired into queryEngine and the demo partner list; unit tests cover mapping for completed, pending, and fallback native assets.

Reviewed by Cursor Bugbot for commit 38f6598. Bugbot is set up for automated code reviews on this repo. Configure here.

Co-authored-by: Cursor <cursoragent@cursor.com>

@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 and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: processXgramTx non-standard signature
    • Updated processXgramTx to accept pluginParams, load the Xgram currency cache internally, and await it from queryXgram.

Create PR

Or push these changes by commenting:

@cursor push 856754591b
Preview (856754591b)
diff --git a/src/partners/xgram.ts b/src/partners/xgram.ts
--- a/src/partners/xgram.ts
+++ b/src/partners/xgram.ts
@@ -375,8 +375,6 @@
   if (previousTimestamp < 0) previousTimestamp = 0
   const targetIsoDate = new Date(previousTimestamp).toISOString()
 
-  const currencies = await fetchCurrencyCache(apiKey, log)
-
   // Because Xgram pages from newest to oldest, the watermark can only be
   // advanced once the entire newer-than-target range has been fetched and
   // processed without error. Track the candidate watermark separately and only
@@ -427,7 +425,7 @@
     }
     let oldestIsoDate = '999999999999999999999999999999999999'
     for (const rawTx of txs) {
-      const standardTx = processXgramTx(rawTx, currencies)
+      const standardTx = await processXgramTx(rawTx, pluginParams)
       if (standardTx.isoDate < oldestIsoDate) {
         oldestIsoDate = standardTx.isoDate
       }
@@ -462,8 +460,21 @@
   pluginId: 'xgram'
 }
 
-export function processXgramTx(
+export async function processXgramTx(
   rawTx: unknown,
+  pluginParams: PluginParams
+): Promise<StandardTx> {
+  const { log } = pluginParams
+  const { apiKeys } = asStandardPluginParams(pluginParams)
+  const { apiKey } = apiKeys
+  if (apiKey == null) throw new Error('Missing Xgram apiKey')
+  const currencies = await fetchCurrencyCache(apiKey, log)
+
+  return processXgramTxWithCurrencies(rawTx, currencies)
+}
+
+export function processXgramTxWithCurrencies(
+  rawTx: unknown,
   currencies: XgramCurrencies
 ): StandardTx {
   const tx: XgramTxTx = asXgramTx(rawTx)

diff --git a/test/xgram.test.ts b/test/xgram.test.ts
--- a/test/xgram.test.ts
+++ b/test/xgram.test.ts
@@ -1,7 +1,10 @@
 import { expect } from 'chai'
 import { describe, it } from 'mocha'
 
-import { processXgramTx, XgramCurrencies } from '../src/partners/xgram'
+import {
+  processXgramTxWithCurrencies,
+  XgramCurrencies
+} from '../src/partners/xgram'
 
 const currencies: XgramCurrencies = {
   BTC: {
@@ -33,7 +36,7 @@
 
 describe('processXgramTx', () => {
   it('maps source and destination asset IDs', () => {
-    const tx = processXgramTx(
+    const tx = processXgramTxWithCurrencies(
       {
         id: 'dyv3a2tdbgipvh0',
         'x-status': 'x-completed',
@@ -67,7 +70,7 @@
   })
 
   it('uses expected amounts and chain-specific token IDs for pending rows', () => {
-    const tx = processXgramTx(
+    const tx = processXgramTxWithCurrencies(
       {
         id: 'tmah3a2td9cp20q0',
         'x-status': 'x-new',
@@ -98,7 +101,7 @@
   })
 
   it('maps historical native currencies missing from the currency API', () => {
-    const tx = processXgramTx(
+    const tx = processXgramTxWithCurrencies(
       {
         id: 'talr3a0e49fplpog',
         'x-status': 'x-timeout',

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 38f6598. Configure here.

Comment thread src/partners/xgram.ts
export function processXgramTx(
rawTx: unknown,
currencies: XgramCurrencies
): StandardTx {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

processXgramTx non-standard signature

Medium Severity

processXgramTx takes a currencies map as its second argument instead of pluginParams, unlike other swap partners’ process*Tx helpers. Uniform backfill callers can only pass (rawTx, pluginParams), so they cannot load the currency cache or map Xgram rows the way this plugin does today.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by learned rule: process*Tx must have uniform signature for backfill scripts

Reviewed by Cursor Bugbot for commit 38f6598. Configure here.

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