Explorer node: add asset_swaps and asset_swaps_totals endpoints#2054
Merged
Conversation
Expose live Asset-Swap (DEX) offers from the explorer node, mirroring the
existing swap_offers / swap_totals atomic-swap endpoints.
The adapter builds a read-only DexBoard over the broadcast router and wallet
DB it already creates. A no-op IRawCommGateway is passed, since the explorer
only lists offers and never accepts/processes trades. Two routes are added:
/asset_swaps live offers, reported in maker terms (send = offered,
receive = wanted), absolute first/second rather than
DexOrder's isMine-relative helpers; expired filtered.
/asset_swaps_totals per-asset offered/wanted totals plus offer count.
Amounts are serialized as strings to avoid JSON precision loss. The new code
is gated by BEAM_ASSET_SWAP_SUPPORT, matching how the atomic-swap path is
gated by BEAM_ATOMIC_SWAP_SUPPORT.
Closes #2053
Recent clang versions flag the whitespace-before-suffix spelling of the user-defined literal operators in 3rdparty/nlohmann/json.hpp (operator "" _json / _json_pointer). With the project's unconditional -Werror this breaks the build of any target that includes that header, e.g. explorer-node. Add -Wno-deprecated-literal-operator to the AppleClang flag block, next to the existing -Wno-enum-constexpr-conversion handling.
Add an "Asset Swaps" menu link, a dispatcher branch for type=asset_swaps, and DisplayAssetSwaps / DisplayAssetSwapTotals render functions, mirroring the existing Atomic Swaps frontend. Lists /asset_swaps offers and fetches /asset_swaps_totals into the totals panel.
get_asset_swaps / get_asset_swaps_totals returned raw groth integers plus an is_mine flag. Wrap the amounts in wallet::PrintableAmount (as the adjacent atomic-swap handlers already do) so the API returns decimal strings, and drop is_mine: the explorer runs a FAKE_SEED wallet, so offers are never "mine".
DisplayAssetSwaps / DisplayAssetSwapTotals dumped the JSON via Obj2Html (nested bullet lists). Render the offers and per-asset totals as dataTables instead, formatting amounts with MakeAmountClr and dropping the is_mine column.
The "Total offers: N" line used the aboutText class (light-colored text), which was invisible on the light totals panel. Remove it; the offer count is already shown in the "Offers (N)" collapsible header.
Render the currency as "NAME (id)" (e.g. BEAM (0), bUSDT (37)) in both the offers and totals tables, so the underlying confidential-asset id is visible.
DisplayAtomicSwaps dumped offers via Obj2Html. Use the same dataTable layout as asset swaps (Sends / For / Created / Expires / Order ID), mapping the atomic fields: beam_amount/swap_amount by is_beam_side -> Sends/For, time_created, height_expired, txId.
…mestamps get_Timestamp_s() and the hdrs Age/duration deltas read SystemState::get_Timestamp_ms(), which is PBFT/PoS-only: on PoW it reinterprets the PoW solution as PBFT header data and returns 0, so every PoW block timestamp (and the Age / d.Time columns) rendered as 0 (1970-01-01). Regression from 221cc7d. Choose the source by the chain consensus type (Rules::m_Consensus) via a single get_Timestamp_ms_safe() helper - the ms timestamp for Pbft, the seconds field m_TimeStamp otherwise - and use it at every site the regression touched (block timestamp, genesis, Age and duration deltas). Also return asset-swap create_time/expire_time as raw unix seconds so the web UI can format them like the block-headers page.
…lper Render asset-swap created/expires via formatTimestamp(..., 'local') - the same helper the hdrs page uses - now that the node returns raw seconds.
Maxnflaxl
added a commit
to BeamMW/docs-gitbook
that referenced
this pull request
Jun 18, 2026
…ndpoints Reflects BeamMW/beam#2054: two read-only DEX endpoints gated by BEAM_ASSET_SWAP_SUPPORT. Adds them to the endpoint list and documents request/response shapes (maker-terms send_*/receive_*, PrintableAmount strings, numeric asset IDs, raw unix create/expire times, 32-hex order id).
valdok
approved these changes
Jun 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements #2053. The explorer node already exposes atomic-swap offers via
swap_offers/swap_totals, but had no equivalent for Asset Swaps (DEX). This adds two read-only endpoints:/asset_swaps— live asset-swap (DEX) offers/asset_swaps_totals— per-asset aggregate totals + offer countThe node already receives this data over SBBS broadcast, so no wallet / wallet-API is required.
Both endpoints are documented in the Beam Node Explorer API reference.
How it works
The adapter builds a read-only
DexBoardover the broadcast router and wallet DB it already creates for the atomic-swap board. It subscribes to the DEX offers broadcast channel and accumulates offers (foreign offers are kept withisMine=false, not rejected). A no-opIRawCommGatewayis passed because the explorer only lists offers — it never accepts or processes trades.Plumbing mirrors the existing
swap_offers/swap_totalspath exactly: an entry in theExplorerNodeDirsmacro,OnRequesthandlers, and backend methods. The new code is gated byBEAM_ASSET_SWAP_SUPPORT, matching how atomic swaps are gated byBEAM_ATOMIC_SWAP_SUPPORT(required, since the wallet DB's DEX methods are themselves behind that flag)./asset_swapsReported in maker terms (
send_*= what the maker offers,receive_*= what the maker wants), using the absolute first/second sides rather thanDexOrder'sisMine-relativesend/receivehelpers (which are perspective-dependent and meaningless on a neutral node). Amounts are formatted withPrintableAmount, timestamps returned as raw unix seconds (formatted client-side, as on the block-headers page).{ "id": "<order-uuid>", "send_asset_id": 0, "send_currency": "BEAM", "send_amount": "4,862.63068319", "receive_asset_id": 7, "receive_currency": "USDT", "receive_amount": "500", "create_time": 1781784005, "expire_time": 1781785805 }/asset_swaps_totals{ "total_offers_count": 12, "assets": [ { "asset_id": 0, "currency": "BEAM", "amount_offered": "5,000", "amount_wanted": "0" }, { "asset_id": 7, "currency": "USDT", "amount_offered": "0", "amount_wanted": "2,500" } ] }Bugfixes
Fixes the explorer needed alongside the feature:
PoW block timestamps rendered as
1970-01-01.get_Timestamp_s()and the hdrs Age / block-duration deltas readSystemState::get_Timestamp_ms(), which carries a value only for PBFT/PoS consensus — on a PoW chain it reinterprets the PoW solution as PBFT header data and returns 0, so every block / header / status timestamp (and the Age andd.Timecolumns) collapsed to the epoch. Regression from221cc7da2("explorer: showing time in ms where applicable (for PoS networks)"). Fixed by choosing the source from the chain's consensus type (Rules::m_Consensus) via a singleget_Timestamp_ms_safe()helper used at every affected site: the ms timestamp forPbft, the seconds fieldm_TimeStampforPoW/FakePoW.-Wdeprecated-literal-operatorbuild break. Recent clang flags the whitespace-before-suffix user-defined-literal spelling in the bundled3rdparty/nlohmann/json.hpp; with the project's unconditional-Werrorthis breaks the build of any target that includes it (e.g.explorer-node). Added-Wno-deprecated-literal-operatorto the AppleClang flag block, next to the existing-Wno-enum-constexpr-conversionhandling.