Feat/middleware foundation#55
Open
117l11 wants to merge 20 commits into
Open
Conversation
Captures approved design for splitting the stack into four components (ussdclient, middleware, broadcaster, smsclient) with Base Sepolia as the demo chain, Pretium for fiat off-ramp, and Termii for SMS. Covers middleware cleanup scope (real Keccak, FUNCTION_MAP removal, typed UserIntent), new tables (withdrawal_request, sms_notification, balance_query, user_preferences), eth_tx schema migration, broadcaster worker patterns (lazy 7702 auth, row-lease double-submission guard), and phased ordering through to architecture refinement. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
13 tasks covering: real Keccak selectors, bounded nick_auth_7702, PhoneWallet deletion, eth_tx schema migration, new tables (withdrawal_request, sms_notification, balance_query, user_preferences), UserIntent typed parser, FUNCTION_MAP removal, handler refactors (register, validate, cancel), broadcaster writeback reducers, commented-code cleanup, and a register-flow smoke test. 69 TDD steps. Produces compiling middleware with new schema ready for Plan 2 (broadcaster + E2E send ETH). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces keccak256_simple (a byte-XOR accumulator, not a hash) with sha3::Keccak256::digest()[..4] in a new pure selector module. Verified against known vectors for transfer, balanceOf, and swapExactTokensForTokens. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tighten `pub use selector::*` to `pub use selector::keccak_selector` so future additions to selector.rs don't silently escape to the crate's public surface. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Caps Nick's Method derivation at 1M attempts and returns Result<_, AuthGenError> so callers handle failure explicitly instead of risking an infinite loop. Also fixes the placeholder chain_id = 0 in register/validate to 84532 (Base Sepolia). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…rors Drops the `pub use hashing::*` wildcard in favor of explicit symbol re-exports so future additions to hashing.rs do not silently leak to the crate's public surface. Replaces the raw `AuthGenError` Display text that was bubbling up to the USSD screen with a user-appropriate "Service temporarily unavailable" message, and logs the internal error detail via log::error! for operators. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Superseded by EsimProfile. No callers used phone_wallet. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
eth_tx now uses auto-inc id as PK (was session_id), supporting multiple txs per session (Withdraw needs escrow + refund tied to one session). Adds: tx_type, block_number, gas_used, error_reason, processing_by, processing_since lease fields used by the broadcaster (Plan 2). TxType reduced to SendEth | WithdrawEscrow | WithdrawRefund. All three move native ETH via Burner7702.execute(to, value, 0x) — no ABI selector needed until Swap ships. Deletes obsolete tests referencing removed Swap* types. BREAKING: requires spacetime delete + republish. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…uery, user_preferences tables These are consumed by Plan 2 (broadcaster) and later plans (SMS service, balance worker, Pretium worker). Tables land first with no callers so migrations can settle before we wire flows. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces scattered split('*') indexing in function handlers with a
single parse_intent(screen, data) returning a typed enum. Covered
by 8 unit tests (happy path + arity + unknown screen + invalid values).
Handlers migrate to consume UserIntent in Task 8 onward.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…spatch The lazy_static Mutex<HashMap<String, fn>> was cleared and rebuilt on every USSD step — wasteful and race-prone. Replaced with a single match statement in functions::dispatch::dispatch(fn_name, ctx, session). USSDService::execute_fn now calls dispatch directly; load_function and register_functions are removed. Drops the lazy_static crate dependency. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
register_pin and confirm_register_pin now call parse_intent and pattern-
match on the typed variant instead of indexing session.data.split('*').
Uses BASE_SEPOLIA_CHAIN_ID = 84532 constant for 7702 derivation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…osition bug validate_pin/phone/amount/token all consume typed UserIntent variants from parse_intent instead of indexing parts[N]. This removes the phone_position=3 branch that addressed the wrong index when the cumulative input had only 2 segments. validate_token becomes a no-op until Swap is in scope. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ConfirmDecision::Confirm → TxStatus::Submitted (broadcaster picks up) ConfirmDecision::Cancel → TxStatus::Cancelled Previously only logged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- set_gateway_identity (module-owner only) registers the broadcaster's SpacetimeDB identity in app_config - mark_eth_tx_processing (with 5-min row lease), mark_eth_tx_broadcast, confirm_eth_tx, fail_eth_tx handle the eth_tx state machine - mark_auth7702_active flips auth_7702.status once the SetCode tx confirms on-chain All reducers require ctx.sender == gateway_identity from app_config. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Deletes commented-out Swap struct, SwapStatus/SwapType enums, claim_swap reducer stub, and unused SwapTable/USSDSessionTable aliases. Inlines _check_profile_exists and _check_session_exists (one call each). Git history preserves the deleted code for reference. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Exercises process_ussd_step through the full registration path (initial dial → pick Register → enter PIN → confirm PIN) and asserts that esim_profile, user_pin, and auth_7702 rows are created. Runs against a live SpacetimeDB instance — not part of cargo test. Prereq: middleware published via 'spacetime publish'. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- esim_profile/user_pin store phone without the leading '+' (normalize_phone_number strips it before insert) - SpacetimeDB SQL rejects 'WHERE 1=1' and 'ORDER BY … LIMIT 1'; use bare DELETE and drop the LIMIT clause - row assertions now count PHONE_NORM hits across multi-line output instead of relying on tail -1 Verified: register_pin + confirm_register_pin produces one esim_profile, user_pin, and auth_7702 row each. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…writes Each of mark_eth_tx_processing, mark_eth_tx_broadcast, confirm_eth_tx, and fail_eth_tx now bail out if the row's status is already Confirmed, Failed, or Cancelled. Previously a stale lease after the 5-min window could have let a late worker rewrite a terminal row. Also tightens the smoke test: - DELETE FROM auth_7702 is now scoped to the test phone's derived wallet (was unconditional) - row-count greps anchor on quoted values so header rows cannot satisfy the assertion Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eight pytest cases that POST to ussdclient's /ussdeth endpoint and verify both the USSD response text and the resulting SpacetimeDB rows. Each test provisions a fresh phone via UUID so cases can run in any order. Covered flows: - initial dial (new user sees RegisterScreen) - register -> confirm_register creates esim_profile + user_pin - registered user sees MainScreen on next dial - send-eth menu chain creates eth_tx(Pending) - confirm flips status to Submitted; cancel flips to Cancelled - bad PIN returns 'Invalid PIN' - malformed phone returns 'Invalid phone number format' Prereqs documented in module docstring; tests call `spacetime sql` for assertions and cleanup, so the CLI must be authed against the local DB. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Foundation rewrite of the SpacetimeDB middleware module. 18 commits implementing Plan 1 of
docs/superpowers/plans/2026-04-17-middleware-foundation.md.Fixes
cancel_txnow writeseth_tx.status(was log-only)validate_pinuses typedUserIntent, removing thephone_position=3indexing bugRefactors
UserIntenttyped parser replaces ad-hocsplit('*')indexingmatchdispatch replacesMutex<HashMap<String, fn>>(dropslazy_staticdep)eth_txschema:auto_inc id, indexedsession_id, lease fieldsauth::listandeth::tx::selectorre-exportsAdditions
set_gateway_identity,mark_eth_tx_processing(5-min row lease),mark_eth_tx_broadcast,confirm_eth_tx,fail_eth_tx,mark_auth7702_activewithdrawal_request,sms_notification,balance_query,user_preferencestests/smoke/test_register_pin_flow.shagainst a live SpacetimeDBtests/e2e/test_ussdclient_flows.py— 8 pytest cases driving the live HTTP bridgeCleanup
PhoneWallettableSwapTable/USSDSessionTablealiases_check_profile_exists/_check_session_existsTest plan
cargo build --releasecleancargo test --lib→ 36 passedspacetime publish --project-path middleware gateway2succeeds./tests/smoke/test_register_pin_flow.shpasses end-to-endpytest tests/e2e/test_ussdclient_flows.py→ 8/8 passed against liveussdclient_v2.py+ SpacetimeDBDeferred to Plan 2 (tracked in memory)
set_gateway_identity's owner check (ctx.sender != ctx.identity()) is unreachable for CLI callers — broadcaster reducers still deny-by-default, so no security regression, but the reducer is currently uncallable. Replace with one-time admin-claim or compile-timetrusted identity.
Timestamp::to_string()— replace withrand::Rng(helper already exists infunctions/pin.rs).validate_pindoesn't increment/check them. Wire up.TxParams::encode()/TxType::signature()are empty stubs — real ABI encoding happens when the broadcaster lands.🤖 Generated with Claude Code