Skip to content

fix: add POST /api/donations/submit endpoint#87

Merged
ayshadogo merged 1 commit into
Dfunder:mainfrom
snowrugar-beep:fix/issue-69-donation-submission-endpoint
Jun 24, 2026
Merged

fix: add POST /api/donations/submit endpoint#87
ayshadogo merged 1 commit into
Dfunder:mainfrom
snowrugar-beep:fix/issue-69-donation-submission-endpoint

Conversation

@snowrugar-beep

Copy link
Copy Markdown
Contributor

Summary

Implements POST /api/donations/submit, a new HTTP endpoint that accepts a signed Soroban donation transaction, submits it to the Soroban RPC, polls for terminal status, and persists a confirmed donation record in SQLite.

Closes #69.

Changes

  • src/api/{mod,error,server,handlers}.rs (new) – Handler, router, and JSON error mapping. Validates the request body (XDR non-empty, positive campaign_id, numeric amount, valid Stellar strkey via stellar-strkey), submits via SorobanRpc::send_transaction, short-circuits on synchronous Failed, polls up to 10 attempts at 1-second intervals, persists a confirmed row on Success, and returns 200 / 202 / 400 / 500 with a structured JSON body.
  • src/soroban/{mod,rpc_client}.rs – Adds an abstract SorobanRpc async trait and implements it for SorobanRpcClient so handlers can be unit-tested with a mock.
  • src/db/donations_repo.rs – Wraps the rusqlite Connection in a std::sync::Mutex (rusqlite’s StatementCache makes the raw connection !Sync, blocking axum’s Send + Sync requirement). Adds #[derive(Clone)] to NewDonation. Public API unchanged. Adds a Send + Sync test.
  • src/errors.rs – Adds a DatabaseError variant and From<RpcError> / From<DbError> impls so the API layer has a uniform error model.
  • src/main.rs – Bootstraps the axum server on HTTP_BIND_ADDR (default 0.0.0.0:8080) with DATABASE_PATH (default ./stellar-aid.db) and the production AppState. Keeps the original config-validation path so missing env vars fail fast at startup.
  • Cargo.toml – Adds axum = "0.7", async-trait = "0.1", and dev-deps tower = "0.5" / http-body-util = "0.1"; switches tokio features to full so the new server can bind TCP.

Testing

  • 17 new tests in src/api/handlers.rs cover the happy-path persist + 200 response, synchronous Failed short-circuit (asserts get_transaction_status is never called), polling-budget exhaustion → 202 pending, every validation rule (empty XDR / zero campaign id / non-numeric or zero amount / invalid donor address), and a real Stellar ed25519 public-key round-trip via stellar-strkey.
  • cargo fmt --all, cargo clippy --all-targets, cargo build --all-features, and cargo test --all-features all pass on the root crate (94/94 tests).
  • Manual verification: serialized body shape for confirmed / failed / pending matches Issue Build Donation Submission Endpoint (Rust HTTP) #69’s spec.

Notes

  • The unsigned donor_user_id field remains None; the existing DonationsRepo.get_campaign_donations already renders such records as Anonymous Donor. A follow-up PR can wire auth + donor_user_id linking.
  • services::donation_verifier is intentionally not called in this PR (out of scope per Issue Build Donation Submission Endpoint (Rust HTTP) #69); a TODO(post-merge) comment in src/api/handlers.rs flags where it would slot in.

Resolves Dfunder#69.

- Adds src/api/{mod,error,server,handlers}.rs implementing the endpoint that accepts a signed Soroban TransactionEnvelope XDR, submits it via the RPC client, polls for terminal status, and persists confirmed donations.

- Introduces a SorobanRpc async trait in src/soroban/rpc_client.rs so handlers can be unit-tested with a mock implementation.

- Wraps DonationsRepo.connection in std::sync::Mutex<Connection> (rusqlite::Connection is !Sync) so AppState is Send+Sync for axum.

- Wires main.rs to bootstrap the axum server over HTTP_BIND_ADDR (default 0.0.0.0:8080) using DATABASE_PATH (default ./stellar-aid.db).

- Extends StellarAidError with a DatabaseError variant and From impls for RpcError / DbError so API-layer error mapping is uniform.

- 17 new tests cover the happy path, short-circuit on send.status==Failed, polling timeout, every validation rule, and the test-public-key round trip.

@ayshadogo ayshadogo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Looks Good

Job Well Done '🤝

@ayshadogo ayshadogo merged commit 3c44619 into Dfunder:main Jun 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build Donation Submission Endpoint (Rust HTTP)

2 participants