Skip to content

feat: email OTP for signup verification and withdrawal confirmation - #207

Merged
Emmyt24 merged 1 commit into
mainfrom
feat/email-otp-signup-withdrawal
Aug 7, 2026
Merged

feat: email OTP for signup verification and withdrawal confirmation#207
Emmyt24 merged 1 commit into
mainfrom
feat/email-otp-signup-withdrawal

Conversation

@Emmyt24

@Emmyt24 Emmyt24 commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Adds a new octo-email crate (Resend HTTP client, OTP generation/hashing, branded HTML templates) and wires it through signup/login (OTP-gated email verification before a session token is issued) and a new withdraw/request-otp + withdraw/confirm pair that binds a one-time code to the exact signed transaction hash before it's relayed to Horizon.

Adds a new octo-email crate (Resend HTTP client, OTP generation/hashing,
branded HTML templates) and wires it through signup/login (OTP-gated
email verification before a session token is issued) and a new
withdraw/request-otp + withdraw/confirm pair that binds a one-time code
to the exact signed transaction hash before it's relayed to Horizon.
@Emmyt24
Emmyt24 merged commit be10ea7 into main Aug 7, 2026
1 check passed
phalap1 added a commit to phalap1/Octo-Protocol that referenced this pull request Aug 7, 2026
Picks up the email OTP work (Octo-Protocol-org#207, Octo-Protocol-org#208, Octo-Protocol-org#209). One real conflict, plus
six call sites the automatic merge left compiling against the old
signatures.

Conflict:
- withdraw_refuses_to_sign_for_a_client_custody_wallet called
  auth_token(&app); main changed the helper to auth_token(&app, &state)
  because signup now issues its token only after the emailed code is
  consumed. Took main's form.

Fixed while merging, all of it mechanical:
- five more auth_token(&app) call sites in the withdraw idempotency tests
  merged without markers, since main never saw those tests. Two of them
  moved state into build_router, so they now clone it like every other
  test in the file.
- withdraw_preflight_tests built AppState with five arguments; main added
  the EmailSender parameter. Uses EmailSender::new_captured(), same as the
  other test fixtures.
- withdraw_preflight_tests signed up by hand and read data.token off the
  response. That field is gone: signup returns data.user_id and the token
  comes from /v1/auth/verify-email. Now goes through
  common::signup_and_verify_full.

The withdrawal OTP main added sits on its own routes, /withdraw/request-otp
and /withdraw/confirm, and gates the already-signed XDR path in submit.rs.
It does not touch POST /v1/wallets/:id/withdraw, so the pre-flight balance
and minimum-reserve checks are unchanged.

cargo clippy --workspace --all-targets and cargo fmt --all are clean.
cargo test -p octo-api runs 153 tests against Postgres with no failures and
no skips, including the three pre-flight tests from Octo-Protocol-org#108.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant