Skip to content

M5.4: Build funding operation record and selected-route adapter #49

Description

@Hazyshades

Parent: M5: Embedded USDC Funding Pilot release gate

Outcome

Integrate the route approved in #48 behind a backend boundary with a shared operation record, verified provider events, idempotent updates, and reconciled wallet delivery.

Gate from #48

Do not start implementation until #48 records a go with:

  • definitive final-status source;
  • authenticity verification method;
  • join identifiers;
  • a test event or sandbox payload.

Circle Onramp Kit is the primary candidate, but the adapter is for the approved route only.

Shared operation record

Define one Sendly funding operation that stores at least:

  • Sendly operation ID;
  • provider name and provider operation or session ID;
  • authenticated Sendly user ID;
  • destination wallet address and wallet model;
  • destination chain;
  • provider environment;
  • amount and asset fields the server is allowed to persist per M5.3: Select one embedded funding route and corridor #48 (do not invent quote or fee fields the provider never sends);
  • USDC amount expected or delivered when known;
  • event history;
  • current status;
  • terminal outcome when reached.

Separate current status from terminal outcomes. Do not list pending as a terminal status.

Status core

created
  -> session_ready
  -> submitted
  -> settlement_pending
  -> completed

submitted / settlement_pending
  -> failed
  -> refund_pending -> refunded

session_expired is a session state. It is not an automatic terminal outcome for a payment that may already have been submitted. A widget or session expiry can still be followed by a late webhook that completes, fails, or refunds the operation.

Exact transition names may map to the selected provider's events, but the separation above is required.

Transition table to implement

Situation Required behavior
Late webhook after browser return Update from the verified event; browser return alone never sets completed
Replayed webhook or duplicate event Idempotent against Sendly operation ID and provider ID; no second operation; no flip from a terminal failure into completed without an explicit verified refund or reopen rule from #48
Return or refresh after completed Show the stored terminal outcome; do not create a new session for the same idempotency key
session_expired with no submit evidence Stay non-terminal or mark session expired; wait for timeout policy from #48 before failing
session_expired after submitted Keep settlement path open until definitive provider status arrives or an approved timeout fails the operation

Required funding path (M5)

Sendly UI
 -> backend creates funding session for the authenticated user
 -> approved hosted or widget flow from #48
 -> browser return (UI only)
 -> verified provider final-status event
 -> backend verifies authenticity and updates operation
 -> reconcile destination wallet delivery
 -> terminal outcome

Provider secrets stay backend-only.

Binding and idempotency rules

  • Bind the destination wallet address to the authenticated user before session creation.
  • Closing the browser tab must not mark the operation completed.
  • A replayed event must not create a second operation or flip a terminal failure into success.
  • Redirect or widget callback is not proof of settlement by itself.

Acceptance criteria

  • Implementation starts only after the M5.3: Select one embedded funding route and corridor #48 go and final-status contract above.
  • Backend creates a funding session only for the approved corridor, wallet model, destination chain, and provider environment from M5.3: Select one embedded funding route and corridor #48.
  • Destination address is bound to the authenticated user; callers cannot substitute an arbitrary address.
  • Provider event authenticity is verified before state changes, using the method named in M5.3: Select one embedded funding route and corridor #48.
  • Replayed events are idempotent against the Sendly operation ID and provider ID.
  • Provider and Sendly identifiers reconcile to one operation record.
  • Current status and terminal outcomes follow the status core; session_expired is not treated as automatic payment failure after submit.
  • A failed or refunded operation cannot appear as completed.
  • Quote and fee are stored only when M5.3: Select one embedded funding route and corridor #48 says the server receives them; otherwise the UI may rely on the widget for those values.
  • Frontend code contains no provider secret.
  • Provider and upstream failures expose an operator correlation ID and a recoverable state.
  • Shared abstractions for Instant cash-out or P2P escrow are deferred until those pilots are approved.

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

    area:fiatFiat on-ramp and off-ramp workpriority:p1Required for the planned milestonerisk:fundsCan move, lock, lose, or misdirect fundstype:featureUser-visible or operator-visible capability

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions