Skip to content

Add Bridgeless reporting from a chain scan - #240

Merged
j0ntz merged 2 commits into
deployfrom
jon/reports-bridgeless
Oct 21, 2026
Merged

j0ntz merged 2 commits into
deployfrom
jon/reports-bridgeless

Conversation

@j0ntz

@j0ntz j0ntz commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Description

Asana task

Bridgeless has no partner reporting API. The new bridgeless plugin reads the Bridgeless chain directly; Edge is referral 2 on the bridge.

How a run works:

  • Find. It walks Tendermint tx_search height windows for /core.bridge.MsgSubmitTransactions from the last saved height (the first run starts at 6,400,000, before Edge's referral existed). The referral id is only in the message body. Each tx's protobuf is decoded locally and orders with referral_id == 2 are kept. Every validator submits the same deposit, and orders are keyed chainId/txHash/txIndex, the orderId edge-exchange-plugins assigns.
  • Date. Each new order takes the block time of its Submit tx.
  • Status. The LCD bridge record gives the payout: a withdrawal hash is complete, a signature without one is withdrawing (approved, not yet claimed), anything else is processing. Unfinished orders are kept in the plugin settings and re-read every run. After 90 days without a payout they stop being re-read, with a warning in the log.
  • Limits. Windows shrink when the node times out or a window is dense, and a window that keeps failing holds progress there. The scan stops after 3 minutes and dating and re-reads after 3.5, which keeps a run inside the query engine's 5 minute timeout. An undecodable tx is logged and skipped, and a token-list outage keeps every pending order for the next run.

Amounts are scaled by the bridge's own token list. usdValue is left at -1 for the rates engine, which prices these orders through rates v3 by pluginId and tokenId.

Registration: bridgeless joins the query engine and the demo partner registry as a swap provider. The registry now carries it, and the extraProviderTypes stopgap in /v2/config is removed. The v2 dashboard also gains a TON network name, and docs/blocked-partner-reporting.md describes the chain scan instead of listing Bridgeless as blocked.

Deploy steps (ops, not in this PR):

  • Add bridgeless to each app's partnerIds in reports_apps with empty apiKeys. The plugin needs no key, but the query engine only runs partners listed there.
  • Revenue is not reported per order (the bridge commission is in payout-token units). Est. revenue stays $0 until the app doc's revShareRate covers Bridgeless.

Testing

  • Unit tests: 15 new tests in test/bridgeless.test.ts against a real mainnet Submit tx and bridge record (dedupe across validators, status mapping, re-reads, window splitting, held progress, the 90 day cutoff, a bad tx, a token-list outage, the run budget). The full suite passes, and verify-repo passes against deploy.
  • Live chain: a full scan of the bridge state on 2026-10-21 found 49 records with referral 2. The plugin's first run from an empty cursor reported the same 49, none missing and none extra, in about 100 seconds.
  • Local CouchDB end to end: the query engine wrote 49 orders (47 complete, 2 withdrawing) in 98 s; a second run took 2.2 s with no new orders. The rates engine priced the 47 complete orders ($30,382 total) and the cache engine wrote month buckets with chained pairs such as BTC@zano>BTC@bitcoin. /v2/config reports bridgeless: swap.
  • The screenshots below are the local v2 dashboard filtered to Bridgeless (provider, networks, pairs), the full provider table, and the v1 Bridgeless chart.

Test evidence

8cda48d
Register the Bridgeless partner plugin
2026-10-21

1. v2 bridgeless provider

2. v2 bridgeless networks

3. v2 bridgeless pairs

4. v2 all providers

5. v1 bridgeless chart

j0ntz added 2 commits October 21, 2026 14:45
Bridgeless has no reporting API. The plugin scans the chain for the
validators' deposit submissions, keeps Edge's referral, and reads each
order's bridge record for its status, re-reading unfinished orders on
later runs.
Adds bridgeless to the query engine and the demo partner list, drops the
v2 config stopgap now that the registry carries it, names TON on the v2
dashboard, and moves Bridgeless out of the blocked-partner doc.

@j0ntz j0ntz left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Self-review at 8cda48d (code-review-sonnet, medium): 8 findings, 3 fixed before the PR opened, 5 rejected.

Fixed before review (3)
  • src/partners/bridgeless.ts:417: one undecodable Submit tx threw out of the window and froze the scan at that height on every run. Fixed in "Add the Bridgeless partner plugin": the tx is logged and skipped.
  • src/partners/bridgeless.ts:260: a token-list outage threw after the scan and discarded its progress and the pending orders. Fixed in "Add the Bridgeless partner plugin": every pending order is kept for the next run.
  • src/partners/bridgeless.ts:77: dating and re-reads had no time limit, and a slow node could push a run past the query engine's 5 minute timeout. Fixed in "Add the Bridgeless partner plugin": after 3.5 minutes the remaining orders wait for the next run.
Rejected in curation (5)
  • src/partners/bridgeless.ts:597: an unknown token makes an order retry every run and never report. Rejected: the bridge only accepts registered tokens, and the order stays pending with a log line each run until the 90 day cutoff, by design.
  • src/partners/bridgeless.ts:85: the zero-address native check is EVM-only and misses natives on other chains. Rejected: the bridge stores every native coin under the zero address; live records for bitcoin, ton, solana, bitcoincash and ethereum natives all resolved to a null tokenId.
  • src/partners/bridgeless.ts:248: rewinding scannedTo re-emits orders already reported. Rejected: insertTransactions upserts by the ${pluginId}:${orderId} doc id: a re-emitted order overwrites itself.
  • src/partners/bridgeless.ts:293: a malformed isoDate gives a NaN age and the order is never dropped. Rejected: isoDate only comes from a Tendermint block header time, which always parses.
  • src/queryEngine.ts:70: the plugin does nothing until bridgeless is in an app's partnerIds. Rejected: that is the ops deploy step for every partner, and the PR description lists it.

@j0ntz
j0ntz merged commit 8cda48d into deploy Oct 21, 2026
5 checks 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.

1 participant