Skip to content

feat: Multi-asset donations via Stellar path payments — donate any asset, treasury receives USDC #1056

Description

@Anuoluwapo25

Summary

Build multi-asset donations via Stellar path payments — a donor contributes in XLM, EURC, or any asset with DEX liquidity, and the treasury receives USDC, atomically, in a single transaction. New feature; donations today assume the donor already holds the treasury asset (server/src/services/horizon-verify.service.ts verifies a plain payment).

Background

Every donor turned away for holding "the wrong asset" is funding LearnVault never received. A European sponsor holds EURC; a Stellar-native holds XLM; a regional donor holds an anchored local-currency token. Asking each of them to go swap first loses most of them at that step.

Stellar's path_payment_strict_receive does the conversion inside the payment itself through the built-in DEX and AMM liquidity pools — no external swap, no bridge, no second transaction that can half-fail. The treasury's accounting stays denominated in one asset while donors pay in whatever they hold.

What to build

1. Path discovery

  • GET /api/donate/paths?from=XLM&amount=100 → call Horizon's /paths/strict-send and /paths/strict-receive, return viable payment paths with the estimated destination amount.
  • Show the donor the real rate and the price impact before they sign. A donor who discovers slippage after the fact does not donate twice.

2. Donation transaction builder

  • POST /api/donate/build constructs a path_payment_strict_receive where:
    • destAsset = treasury USDC, destAmount = the exact amount the treasury should receive
    • sendMax = quoted amount plus a donor-selected slippage tolerance (default 0.5%)
    • path = the discovered intermediate assets
    • destination = the treasury account
  • Return XDR for wallet signing. The server never holds donor keys.

3. Trustline preflight

  • Check whether the donor holds a trustline for the asset they are sending, and whether the treasury has one for USDC.
  • If the treasury lacks a trustline for an incoming path, that path must be excluded from the results rather than offered and then failing at submission.

4. Verification and accounting

  • Extend horizon-verify.service.ts to recognize path payments: verify the destination amount and asset actually credited to the treasury, not the source amount. Crediting a donor for sendMax rather than what arrived is the bug this feature invites — guard it with a test.
  • Record both legs (sent_asset/sent_amount and received_usdc) so impact reporting stays denominated in USDC.
  • Migration server/src/db/migrations/029_multi_asset_donations.sql plus its .undo.sql adding the source-asset columns to the existing donation table.

5. Frontend

  • Asset picker on the donate flow, defaulting to assets the donor actually holds (read their balances).
  • Live quote: "You send ~102.3 XLM → Treasury receives 10.00 USDC", refreshing on a timer, with the slippage control visible.
  • Clear failure message when no path exists, naming the asset rather than showing a generic error.

6. Tests

  • Path lookup with a mocked Horizon.
  • sendMax correctly reflects slippage tolerance.
  • Verification credits the received USDC amount, not the sent amount.
  • No-path-available and missing-trustline cases are handled and surfaced.

Acceptance criteria

  • Donor can contribute in XLM or EURC and the treasury receives USDC in one transaction
  • Quote with price impact is shown before signing, and slippage is configurable
  • Paths requiring a trustline the treasury lacks are never offered
  • Verification credits the destination amount actually received
  • Donation records retain both the source asset and the received USDC
  • Tests cover the slippage and verification math

Notes for contributors

Activity

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

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26Third CampaignCampaign: Third CampaignbackendAPI/database/infrastructureenhancementNew feature or requestfeatureNew feature implementationfrontendReact/TypeScript UI work

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions