Skip to content

fetchTransactionsFromHorizon sets counterparty to the user's own address for sent transactions (distinct from the hardcoded-amount bug in #6) #17

Description

@abayomicornelius

Problem

src/lib/api.ts's fetchTransactionsFromHorizon maps raw Horizon transaction records into the app's Transaction type. Setting aside the hardcoded amount/assetCode values already tracked in #6, there is a separate, distinct bug in the same mapping in how counterparty is derived:

counterparty:
  r.source_account === publicKey ? publicKey : r.source_account,

When r.source_account === publicKey (i.e. direction: 'sent'), the ternary evaluates to publicKey — the connected wallet's own address — instead of the actual recipient. The Horizon /transactions endpoint used here doesn't even carry a destination account at the transaction level (that lives on the nested operations, which this endpoint doesn't return), so there's no correct value available to plug in here without a further request — but returning the user's own address as their transaction's "counterparty" is actively misleading rather than merely incomplete, and is worth tracking as its own defect since fixing #6's amount/endpoint issue alone would not fix this.

Why it matters

Any UI that renders counterparty for a sent transaction (transaction history lists, receipts, exports) will display the user's own address as who they paid — actively wrong information, not just a missing feature. A user reviewing their sent-payments history would see their own public key listed as the recipient of every outgoing payment, which is confusing at best and could mask a genuine misdirected payment at worst (if the real destination were ever wrong, this bug would hide that fact by showing the user's own address instead of surfacing anything to double-check against).

Reproduction

  1. Call useRecentTransactions() (which calls this function) for any account with at least one outgoing payment.
  2. Inspect the returned transactions[i].counterparty for a direction: 'sent' entry — it will equal publicKey, the account's own address, not the recipient.

Suggested fix

This should be fixed as part of the same endpoint migration tracked in #6 (moving from /transactions to /accounts/{id}/payments, which returns per-operation from/to fields) — once that migration lands, counterparty can be derived correctly as "whichever of from/to isn't the current account" instead of needing a same-endpoint workaround. Until that migration happens, at minimum this specific ternary should be fixed to return null/undefined for the unknown-destination case rather than a plausible-looking but wrong value (the user's own address), so consuming UI can render "recipient unavailable" instead of confidently wrong data.

Edge cases

Multi-operation transactions (this app's own batch-send and escrow features produce these, e.g. buildBatchPaymentTransaction) have no single "counterparty" at all — the fix needs a defined behavior for that case (e.g. counterparty: null or a list) rather than picking one arbitrary value, which is also relevant to #6's endpoint-migration work.

Testing strategy

Unit test fetchTransactionsFromHorizon (or its post-migration replacement) against a fixture Horizon response with a known outgoing payment and assert counterparty equals the actual destination, never publicKey.

Related issues in this batch

Directly complements #6, which tracks the hardcoded amount/assetCode bug in this same mapping function — both stem from the same root cause (the /transactions endpoint lacking operation-level data) and should likely be fixed together as part of the endpoint migration #6 describes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26bugSomething isn't workingvery hardVery difficult / senior-level bounty issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions