Skip to content

Portfolio & history

Balances, chain distribution and a per-product transaction record.

Routes: /defi/overview, /defi/swap-history, /defi/bridge-history, /defi/perpetual-transaction, /defi/liquidity-history

Portfolio overview

Source: defi-dex/src/pages/defi/overview.tsx · Data: Zerion

Portfolio data comes from Zerion's wallet API, not from Blazpay's own indexing:

GET https://api.zerion.io/v1/wallets/{wallet}/positions/
      ?filter[positions]=only_simple
      &currency={currency}
      &filter[trash]=only_non_trash
      &sort=value

filter[trash]=only_non_trash matters — without it a wallet's view is dominated by airdropped spam tokens.

bz-backend/services/portfolio.js exposes two shapes:

FunctionReturns
getSummary(wallet)Total value, chain distribution, headline numbers
getPortfolio(wallet)Full position list

Both are consumed by the wallet reputation card as well as the portfolio page, and by the PORTFOLIO AI intent.

In BlazAI

The PORTFOLIO intent renders portfolio/UserPortfolio (action portfolio) with charts and distribution inline in chat. CHECK_BALANCE is a narrower intent for a specific token or chain, and is also used for follow-up questions about the worth or price of tokens already discussed.

Transaction history

Blazpay keeps its own record of every trade it originated, in bz-backend/models/defiTransactions.js. This is separate from the chain — it exists so that a user can see a bridge that is still in flight, a trade whose hash has not been mined yet, and a human-readable route description.

The UUID-first pattern

A transaction record is created before the on-chain hash exists:

  1. sendTransactionRaw generates a UUID and writes a record with txHash = <uuid>.
  2. It pushes ?hash=<uuid> into the browser URL, so a reload recovers the in-flight trade.
  3. Once the wallet returns the real hash, it PATCHes /defi/transaction/hash/<uuid> to replace it.

If you find records whose txHash looks like a UUID rather than 0x…, those are trades that never got a hash — the user rejected the wallet prompt, or the tab closed.

Endpoints

PurposeEndpoint
List a wallet's transactionsGET /defi/transaction/:walletAddress
One transaction by idGET /defi/transaction/:walletAddress/:id
By hashGET /defi/tx/:hash, GET /defi/txHash/:txHash
Most recent for a walletGET /defi/tx/wallet/:address
Refresh pending statusesGET /defi/txn/:walletAddress
CreatePOST /defi/transaction
Update by uuid or hashPATCH /defi/transaction/hash/:hash
Bridge status updatePATCH /defi/transaction/update

Full detail: trading API reference.

Status refresh

GET /defi/txn/:walletAddress walks that wallet's pending records and asks each provider's status endpoint (getTxStatus(chainId, hash) on the relevant aggregator, using the routers map in swap-sdk/src/utils/constants.ts). bridgeStatusCron.js does the same in the background so a user who closes the tab still gets a resolved record.

Per-product history surfaces

RouteRecords
/defi/swap-historySame-chain swaps
/defi/bridge-historyCross-chain transfers, including in-flight
/defi/perpetual-transactionOrderly orders and fills
/defi/liquidity-historyReserved; liquidity is not shipped
/defi/transactiondetailsSingle-transaction detail view

CSIP fills are separate — models/DcaFill.js, surfaced in the CSIP position detail rather than the generic history. Autopilot activity is separate again — models/autopilotTradeModel.js and autopilotEventModel.js, surfaced via GET /defi/autopilot/:chainId/:agentId/activity.

Other data sources

DataSource
Balances (portfolio)Zerion
Wallet token balances (init)GET /defi/init/:addresscontrollers/defi/init.js
Price chartsgetGraphPrice in defi-dex/src/apis/defi.api.ts
Token prices for automationCoinMarketCap, batched into a Redis rolling series (services/autopilotPrices.js)
Fee treasury totalsCoinGecko, via GET /defi/fees/summary
Per-chain first/last activityEtherscan v2 txlist

Three different price sources, deliberately

CoinMarketCap feeds automation (it needs a consistent series for dip-buy and take-profit triggers). CoinGecko feeds the fee summary (one-off, batch, free tier is fine). Zerion feeds portfolio display (it already prices positions, so re-pricing would be duplicated work). Do not consolidate them without checking that the replacement supports rolling series.

Known limits

  • Portfolio totals exclude anything not in a wallet. Perp collateral inside Orderly, CSIP vault balances and Autopilot vault balances do not appear. A user with most of their capital in automation sees a misleadingly small portfolio.
  • Zerion coverage defines chain coverage. A chain Blazpay supports for swaps but Zerion does not index shows a zero balance.
  • "Oldest hold" on the wallet card defaults to wallet age, not to per-token entry time — that would need an ERC-20 Transfer log index per chain.
  • No unified cross-product PnL. Each surface reports its own.
  • UUID-hash records can accumulate. There is no cleanup job for records whose hash never resolved.

Internal + developer documentation. Usage figures are point-in-time snapshots — re-verify before publishing them.