Skip to content

feat(api): Multi-chain API surface, OpenAPI, and webhooks #227

Description

@Emmyt24

Depends on: #215, #216, #220, #225. Blocks: nothing (terminal).

Description

The public API assumes one chain. Responses carry Stellar-shaped fields (stellar_account_g,
muxed_address, memo_id, stellar_tx_hash), amounts are numbers, and there is no way for a
client to say which chain it wants. Payment links
(crates/api/src/routes/payment_links.rs) resolve a
single hard-coded asset. Webhook payloads (octo-webhooks) carry
no chain identity, so a consumer receiving deposit.confirmed cannot tell which chain it came from.

Expose multi-chain support coherently across the API, the OpenAPI spec, and webhooks, without
breaking existing Stellar integrations.

Requirements and context

  • Existing Stellar clients must keep working. Choose and document a compatibility strategy:
    default chain_id to Stellar when the field is absent, and/or version the API. Amount-as-string
    (feat(store): Arbitrary-precision amounts — replace i64 stroops with NUMERIC(78,0) #215) is already breaking — bundle the breaks into one clearly-communicated version rather than
    dribbling them out.
  • Every resource that is chain-scoped must expose chain_id in responses, and accept it on creation.
  • Chain-specific fields must be nested, not flattened. A flat response with memo_id: null on
    EVM and derivation_index: null on Stellar teaches clients to guess. Nest under a chain_details
    discriminated union keyed on chain kind.
  • Payment links gain chain selection: a link should support one or more chains, with the payer
    choosing at checkout and each choice yielding a chain-appropriate deposit address (feat(store): EVM per-customer deposit addresses via HD derivation #220).
  • Webhooks must carry chain_id in every event, and new events from this epic
    (deposit.confirmed, deposit.orphaned from feat(ingest): Confirmation depth and reorg handling for EVM deposits #222) need documented payloads. Webhook signing
    (crates/webhooks/src/sign.rs) is unchanged.
  • drift_tests.rs enforces spec/implementation agreement — every change here needs a matching
    docs/openapi.yaml change or CI fails.
  • Security: authorisation is per wallet and must remain per wallet. Adding a chain_id
    parameter must not create a path where a client passes a chain id to reach another tenant's
    resources. Extend
    crates/api/tests/authz_matrix_tests.rs
    with chain-scoped cases.

Suggested execution

Branch: feat/multi-chain-api-surface

Implement changes

  • Add chain_id to wallet/address/transaction/payment-link request and response schemas, with the
    documented default for absent values, and nest chain-specific fields under a discriminated union.
  • Add GET /v1/chains — supported chains, their tokens (feat(store): ERC-20 token registry #223), confirmation depths, and enabled
    status, so clients can discover capability rather than hard-code it.
  • Extend payment links to multi-chain: chain selection at creation, per-chain deposit address at
    checkout, chain_id recorded on payment rows.
  • Add chain_id to every webhook payload and document the new deposit lifecycle events.
  • Update docs/openapi.yaml, docs/api.md, and the Bruno collection
    in api-tests/ added in 4cd1bd2.

Test and commit

  • Extend crates/api/tests/drift_tests.rs to cover the new
    and modified endpoints. Note: this file currently has a compile error on main
    (statusN at line 47) — fix it as part of this PR.
  • Backward-compatibility tests: a request with no chain_id behaves exactly as it does today,
    asserted against the current response shapes.
  • Authorization tests: a client cannot reach another tenant's wallet by varying chain_id.
  • Webhook tests: every event carries a correct chain_id; existing signature verification is
    unchanged.
  • Multi-chain payment-link end-to-end test covering creation, chain selection, and per-chain address
    issuance.
  • Write a migration guide for API consumers documenting every breaking change and how to adapt.

Example commit message

feat(api): multi-chain API surface, OpenAPI, and webhooks

Adds chain_id across chain-scoped resources with Stellar as the default
for absent values, nests chain-specific fields under a discriminated
union so clients stop guessing at null columns, and adds GET /v1/chains
for capability discovery.

Payment links gain chain selection with per-chain deposit addresses,
and every webhook payload now carries chain_id.

Also fixes a pre-existing compile error in drift_tests.rs.

BREAKING CHANGE: amount fields are strings; chain-specific fields moved
under chain_details.

Refs #227

Guidelines

Last issue in the epic and the one users actually see. Write the migration guide as if you were the
integrator receiving it.


Metadata

Metadata

Assignees

No one assigned

    Labels

    area/backendBackend crates: api, store, ingest, webhooks, bin/servercompat/breaking-changeChanges a public API or on-disk contractdifficulty/hardHard, complex, cross-cuttingdocumentationImprovements or additions to documentationtype/epicTracking issue for a multi-issue epic

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions