3.5 KiB
3.5 KiB
/pay Fallback UX Implementation
Date: 2026-03-29
Commit: 2b93236229 on phase1-dev
APK: http://192.168.0.5:8888/
What Was Implemented
Flow B — Fallback When Recipient Has No Linked Wallet
When a user types /pay 10 to a recipient who hasn't linked a Cardano wallet:
- Address lookup happens in background -
CardanoAddressService.lookupAddress(@recipient)is called - Not found → Show banner card with:
- Warning icon: "⚠️ @recipient hasn't linked a Cardano wallet"
- Instructional text: "Enter their Cardano address manually:"
- Embedded editable text field with placeholder "addr1... or addr_test1..."
- Live validation on manual address input:
- Must start with
addr_test1(preprod) oraddr1(mainnet) - Length between 58-108 characters
- Shows inline error if invalid
- Shows green checkmark "Valid address" when valid
- Must start with
- Continue button enables when:
- Amount is valid (≥1 ADA)
- Manual address passes validation
- Resolved address is passed to confirmation screen - The
PaymentEntryNodenow passesstate.resolvedAddress(which comes from either the lookup or manual entry) instead of the rawrecipientInput
Files Changed
| File | Changes |
|---|---|
PaymentFlowEvents.kt |
Added ManualAddressChanged(address: String) event |
PaymentEntryState.kt |
Added manualAddressInput, manualAddressError, resolvedAddress fields; added needsManualAddressEntry computed property |
PaymentEntryPresenter.kt |
Handle ManualAddressChanged event; validateManualAddress() function; updated canContinue logic to work with manual entry |
PaymentEntryView.kt |
Added ManualAddressEntryCard composable with embedded OutlinedTextField; updated preview states |
PaymentEntryNode.kt |
Changed to pass state.resolvedAddress instead of state.recipientInput to confirmation callback |
Flow A — Happy Path (Already Working)
When recipient HAS a linked wallet:
- User types
/pay 10 - Payment form opens with recipient pre-selected from DM context
CardanoAddressService.lookupAddress(@recipient)returns the address- Green card shows: "✓ Address loaded from @recipient's profile" with truncated address
- Recipient field shows Matrix user ID (read-only context)
- Amount field pre-filled with "10"
- Continue button enabled immediately
- Confirmation screen shows full transaction details with fee estimate
Amount Pre-fill
When user types /pay 10, the 10 is parsed by PayCommandParser and passed via ParsedPayCommand.AmountOnly or ParsedPayCommand.WithMatrixRecipient. The PaymentEntryPresenter.extractPrefills() function extracts this and pre-fills the amount field.
Address Validation Rules
private fun validateManualAddress(input: String): String? {
// Must start with addr_test1 (preprod) or addr1 (mainnet)
val isTestnet = input.startsWith("addr_test1")
val isMainnet = input.startsWith("addr1") && !input.startsWith("addr_test1")
if (!isTestnet && !isMainnet) return "Address must start with addr1 or addr_test1"
if (input.length < 58) return "Address too short"
if (input.length > 108) return "Address too long"
if (!CARDANO_ADDRESS_REGEX.matches(input)) return "Invalid Cardano address format"
return null
}
Testing Notes
- Build passes with warnings only (no errors)
- All existing tests pass
- Preview states updated to include manual entry scenarios
- APK served on port 8888 for install testing