Skip to content

Add GET /api/history?address= endpoint for wallet transaction history #153

Description

@TaprootFreak

Problem

Wallet integrations (the in-tree zk-coins/app, and external integrators like Cake Wallet and Layerz Wallet) need a per-address transaction history endpoint. Today the public API surface (/api/balance, /api/info, /api/mint, /api/send, /api/commit, /api/receive, /api/proof/:id, /api/username/*) has no way to list past coin movements for a given account address.

The web app currently sidesteps this by tracking its own state locally, but that breaks the documented thin-client invariant (feedback_zkcoins_thin_client: app only holds keys + UI; before every signed request, the app calls api.balance for authoritative server state). Mobile wallets cannot follow the same shortcut — they need server-authoritative history to render a transaction list.

This is the gating endpoint for everything downstream:

  • Pure-JS @zkcoins/sdk cannot expose getTransactions() without it.
  • OpenAPI 3.x spec cannot be published as complete without it.
  • cw_zkcoins (Cake Wallet) and zkcoins-wallet.ts (Layerz Wallet) adapters need it for getCommonTransactions() / fetchTransactions().

Proposed shape

GET /api/history?address=<hex>&limit=<n>&offset=<n>
  • address (required): the account address (hex, same encoding as /api/balance).
  • limit (optional, default 50, max 200).
  • offset (optional, default 0).

Response

{
  "items": [
    {
      "txid": "<hex>",
      "timestamp": 1717081234,
      "direction": "send" | "receive" | "mint",
      "amount": 10000,
      "counterparty": "<hex>",
      "status": "pending" | "confirmed" | "failed",
      "block_height": 871234,
      "memo": null
    }
  ],
  "total": 137,
  "limit": 50,
  "offset": 0
}
  • txid is the on-chain commit txid where this coin movement was inscribed. For pending mints/sends not yet broadcast or not yet confirmed, the proof_id can be exposed in the same slot (TBD on the canonical identifier — see Open Questions).
  • direction is from the queried address's perspective.
  • counterparty is optional — sends include the recipient address, receives include the sender. Mints have no counterparty.
  • status: pending until the inscription confirms in a block, then confirmed. failed for the broadcast-rejected case the publisher already surfaces (503 SERVICE_UNAVAILABLE path).
  • block_height is set once status === "confirmed".

Acceptance criteria

  • Endpoint registered in router.rs, behind always status (no feature gate).
  • Postgres query joins the existing coin/send tables; no new schema work expected.
  • 100% line + function coverage on the activated MVP surface (router + handler).
  • Unit tests: happy path, empty result, pagination boundaries (limit=0 / limit=max+1 → 400; offset beyond total → empty items with correct total), missing address → 400, invalid hex → 400.
  • Live contract test in node/tests/api_remote.rs adds a /api/history round-trip on a freshly-minted address.
  • Zod schema (zk-coins/app/src/lib/api/schemas.ts) + typed client method (zk-coins/app/src/lib/api/client.ts) added — keeps the app in sync as the in-tree consumer. App's behaviour stays unchanged until a later PR wires the UI to it.
  • README §Features table entry added.

Out of scope

  • App UI changes that consume the new endpoint — separate PR once the server side is stable.
  • OpenAPI 3.x export (depends on this PR landing first).
  • WebSocket push of new history rows (post-MVP).

Open questions for the PR author

  1. Canonical identifier for an unconfirmed rowtxid won't exist until the publisher broadcasts. Options: (a) use the proof_id (server-internal monotonic ID, already exposed via /api/proof/:id); (b) use a synthetic id field separate from txid. Recommendation: separate fields, id always set, txid only once broadcast.
  2. Sort order — newest first (ORDER BY timestamp DESC) is the wallet-UI default; pin this in the docs.
  3. Address normalization — match whatever /api/balance accepts (case sensitivity, length checks). Reuse the existing helper.

References

  • Memory feedback_zkcoins_thin_client — thin-client invariant.
  • Memory project_zkcoins_server_heavy_architecture — server-heavy design rationale.
  • Memory project_zkcoins_api_info_normalization — sibling deferred enhancement, to be picked up alongside the SDK work.
  • PR feat(config): require explicit chain config — no silent Mutinynet defaults #149 (require explicit chain config) — pattern for adding new env-driven behaviour without silent defaults.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions