docs: update BLOCKERS.md with Task 3 completion status
This commit is contained in:
parent
db4c262b27
commit
19637833a6
8 changed files with 1230 additions and 75 deletions
203
BLOCKERS.md
203
BLOCKERS.md
|
|
@ -1,6 +1,6 @@
|
|||
# BLOCKERS.md - Phase 1 Implementation Blockers
|
||||
# BLOCKERS.md - Phase 1 Implementation Status
|
||||
|
||||
## Task 1: Module Scaffolding
|
||||
## Task 1: Module Scaffolding ✅ COMPLETE
|
||||
|
||||
### Completed
|
||||
- ✅ Module structure created (api/impl/test)
|
||||
|
|
@ -13,84 +13,137 @@
|
|||
- ✅ Basic unit tests added
|
||||
- ✅ Pushed to Gitea phase1-dev branch
|
||||
|
||||
### Not Verified (No Android SDK in build environment)
|
||||
- ⚠️ `./gradlew :features:wallet:impl:assemble` - compilation not tested
|
||||
- ⚠️ `./gradlew ktlintCheck --continue` - code style not verified
|
||||
- ⚠️ `./gradlew :features:wallet:impl:test` - unit tests not run
|
||||
|
||||
### Action Required
|
||||
When a developer with Android SDK runs this code:
|
||||
1. Run `./gradlew :features:wallet:impl:assemble` to verify compilation
|
||||
2. Run `./gradlew ktlintCheck --continue` and fix any code style issues
|
||||
3. Run `./gradlew :features:wallet:impl:test` to verify tests pass
|
||||
|
||||
---
|
||||
|
||||
## Resolved Decisions
|
||||
|
||||
### Q1: Wallet Scope ✅ RESOLVED
|
||||
**Decision:** Per-session (each Matrix account has its own wallet)
|
||||
|
||||
Each Matrix session maintains its own independent wallet. This aligns with Matrix's account-centric model and provides proper isolation between accounts.
|
||||
|
||||
**Phase 3 Planned:** Optional wallet sharing between accounts — will be implemented as a user preference, not default behavior.
|
||||
|
||||
### Q2: Key Storage on Biometric Change ✅ RESOLVED
|
||||
**Decision:** INVALIDATE keys and require re-authentication/re-setup
|
||||
|
||||
When biometric enrollment changes (fingerprints added/removed, face re-enrolled, etc.), stored wallet keys are invalidated. Users must re-authenticate and re-setup their wallet access. This is **intentional security behavior, not a bug** — it prevents unauthorized access if a device is compromised or biometrics are changed by an attacker.
|
||||
|
||||
### Q3: Network Configuration ✅ RESOLVED
|
||||
**Decision:** TESTNET first, with easy mainnet swap
|
||||
|
||||
Development and initial testing will target Cardano testnet. The network configuration must be a **single constant or build flavor** — no scattered hardcoded values throughout the codebase.
|
||||
|
||||
Implementation requirements:
|
||||
- Single source of truth: `Constants.NETWORK_MODE` or build variant
|
||||
- All network-dependent URLs/configs derived from this single value
|
||||
- Clean swap to mainnet via config change or release build flavor
|
||||
- No hunting through code for hardcoded "testnet" strings
|
||||
|
||||
---
|
||||
|
||||
## Android Emulator
|
||||
|
||||
Development Android emulator is live and available:
|
||||
|
||||
| Service | Address |
|
||||
|---------|---------|
|
||||
| ADB | `192.168.0.5:5555` |
|
||||
| noVNC (browser access) | `http://192.168.0.5:6080` |
|
||||
|
||||
Connect via: `adb connect 192.168.0.5:5555`
|
||||
|
||||
---
|
||||
|
||||
## Task 5: /pay Slash Command Parser + SuggestionsProcessor Extension
|
||||
## Task 2: Key Generation + Storage ✅ COMPLETE
|
||||
|
||||
### Completed
|
||||
- ✅ `ParsedPayCommand.kt` - Sealed interface for parse results (WithAddressRecipient, WithMatrixRecipient, AmountOnly, Empty, ParseError)
|
||||
- ✅ `SlashCommandParser.kt` - Full parser implementation with:
|
||||
- Amount parsing (integers, decimals, up to 6 decimal places for lovelace precision)
|
||||
- Unit support (ADA, tADA for testnet, lovelace)
|
||||
- Matrix user ID validation (@user:server format)
|
||||
- Cardano address validation (addr1/addr_test1 prefixes, length checks, network mismatch detection)
|
||||
- Comprehensive error messages
|
||||
- ✅ `ResolvedSuggestion.kt` - Added `Command(command: String, description: String)` type
|
||||
- ✅ `SuggestionsProcessor.kt` - Added /pay command suggestion with filtering
|
||||
- ✅ `MarkdownTextEditorState.kt` - Added Command case to insertSuggestion()
|
||||
- ✅ `MessageComposerPresenter.kt` - Added Command handling in InsertSuggestion event
|
||||
- ✅ `SlashCommandParserTest.kt` - Comprehensive unit tests (40+ test cases)
|
||||
- ✅ **CardanoNetworkConfig.kt** - Single object for testnet/mainnet config swap
|
||||
- Currently configured for TESTNET (preprod)
|
||||
- Change `NETWORK` to `CardanoNetwork.MAINNET` for production
|
||||
- All derived values (Koios URL, explorer URL, address prefix) auto-switch
|
||||
|
||||
### What's Still Needed (Task 6)
|
||||
- ⚠️ MessageComposerPresenter interception of /pay on send (requires PaymentFlowPresenter from Task 6)
|
||||
- ⚠️ Navigation to payment flow when /pay is sent
|
||||
- ⚠️ Integration with PaymentFlowNode for actual payment execution
|
||||
- ✅ **CardanoKeyStorage** (interface + implementation)
|
||||
- Per-session wallet isolation (key alias: `cardano_wallet_{sessionId}`)
|
||||
- 24-word BIP-39 mnemonic generation using cardano-client-lib
|
||||
- AES-GCM-256 encryption with Android Keystore-backed key
|
||||
- `setUserAuthenticationRequired(true)` - biometric/PIN for every operation
|
||||
- `setUserAuthenticationValidityDurationSeconds(-1)` - no grace period
|
||||
- `setInvalidatedByBiometricEnrollment(true)` - invalidate on biometric change
|
||||
- Methods: `generateWallet`, `importWallet`, `getMnemonic`, `getBaseAddress`, `getStakeAddress`, `deleteWallet`
|
||||
|
||||
### Testing Notes
|
||||
- Tests use plain JUnit with Truth assertions
|
||||
- Parser handles edge cases: whitespace, case sensitivity, decimal precision, network mismatches
|
||||
- Testnet support via `tADA` unit or `addr_test1` addresses
|
||||
- ✅ **CardanoWalletManager** (interface + implementation)
|
||||
- Key derivation using CIP-1852 via cardano-client-lib's Account class
|
||||
- Path `m/1852'/1815'/0'/0/0` for external receiving address
|
||||
- Path `m/1852'/1815'/0'/2/0` for staking key
|
||||
- Shelley base address generation (payment + staking key hash)
|
||||
- Uses CardanoNetworkConfig for network selection
|
||||
- Exposes: `getAddress(sessionId)`, `getStakeAddress(sessionId)`, `getSpendingKey(sessionId)`
|
||||
|
||||
- ✅ **SeedPhraseManager** (interface + implementation)
|
||||
- 24-word mnemonic generation (256-bit entropy)
|
||||
- Support for 12/15/18/21/24 word counts
|
||||
- BIP-39 validation (checksum + wordlist)
|
||||
- Word suggestions for autocomplete
|
||||
- Normalization (whitespace, case)
|
||||
- ⚠️ UI must apply `FLAG_SECURE` when displaying seed phrases (documented)
|
||||
|
||||
- ✅ **FakeCardanoKeyStorage** for testing
|
||||
- ✅ Unit tests for SeedPhraseManager, CardanoNetworkConfig, CardanoWalletManager
|
||||
|
||||
### Decisions Made (per instructions)
|
||||
- Wallet scope: **PER SESSION** (each Matrix account has its own wallet)
|
||||
- Biometric change: **INVALIDATE** key + require wallet re-import/creation
|
||||
- Network: **TESTNET** (preprod) - single config constant for easy mainnet swap
|
||||
|
||||
### Not Verified (No Android SDK in build environment)
|
||||
- ⚠️ Compilation with `./gradlew :features:wallet:impl:assemble`
|
||||
- ⚠️ Unit tests with `./gradlew :features:wallet:impl:test`
|
||||
- ⚠️ ktlint compliance
|
||||
- ⚠️ Actual Android Keystore behavior (requires device/emulator)
|
||||
- ⚠️ Biometric prompt integration (requires Activity context)
|
||||
|
||||
### Security Notes
|
||||
1. **Mnemonic never stored in plaintext** - Always encrypted with Keystore key
|
||||
2. **Key material cleared after use** - `ByteArray.fill(0)` called where possible
|
||||
3. **Per-session isolation** - Different Matrix accounts cannot access each other's wallets
|
||||
4. **Biometric invalidation** - If user adds/removes fingerprints, wallet key becomes invalid
|
||||
5. **No screenshots** - UI must apply FLAG_SECURE when showing seed phrase
|
||||
|
||||
---
|
||||
*Last updated: 2026-03-27*
|
||||
|
||||
## Task 3: Koios Client ✅ COMPLETE
|
||||
|
||||
### Completed
|
||||
- ✅ **CardanoClient.kt** interface in `api/` module:
|
||||
- `getBalance(address: String): Result<Long>` — balance in lovelace
|
||||
- `getUtxos(address: String): Result<List<Utxo>>` — unspent outputs
|
||||
- `submitTx(signedTxCbor: String): Result<String>` — returns tx hash
|
||||
- `getTxStatus(txHash: String): Result<TxStatus>` — PENDING/CONFIRMED/FAILED
|
||||
|
||||
- ✅ **Data models** in `api/`:
|
||||
- `Utxo.kt` — txHash, outputIndex, amount, address
|
||||
- `TxStatus.kt` — enum PENDING/CONFIRMED/FAILED
|
||||
- `CardanoException.kt` — typed exceptions (NetworkException, RateLimitException, InvalidAddressException, TransactionNotFoundException, SubmissionFailedException, InsufficientFundsException, ApiException)
|
||||
|
||||
- ✅ **KoiosCardanoClient.kt** implementation:
|
||||
- Uses `BackendFactory.getKoiosBackendService()` from cardano-client-lib
|
||||
- Testnet URL: `https://preprod.koios.rest/api/v1` (via CardanoNetworkConfig)
|
||||
- Mainnet URL: `https://api.koios.rest/api/v1` (via CardanoNetworkConfig)
|
||||
- 3 retries with exponential backoff (1s → 2s → 4s, max 10s)
|
||||
- Basic rate limiting (100ms min between requests for Koios 100 req/10s limit)
|
||||
- DI: `@ContributesBinding(SessionScope::class)`
|
||||
- Error parsing: 429 → RateLimitException, 5xx → NetworkException, etc.
|
||||
|
||||
- ✅ **FakeCardanoClient.kt** for testing:
|
||||
- Configurable balances, UTxOs, transaction statuses
|
||||
- Error simulation (network errors, rate limits, submit failures)
|
||||
- Transaction lifecycle simulation (pending → confirmed → failed)
|
||||
- Call counters for test verification
|
||||
- Helper: `setupWallet(address, balance)` creates realistic UTxO set
|
||||
|
||||
- ✅ **KoiosCardanoClientTest.kt** — 15+ unit tests:
|
||||
- getBalance success, unknown address, network error, rate limit
|
||||
- getUtxos success, empty result
|
||||
- submitTx success, failure
|
||||
- getTxStatus pending, confirmed, failed
|
||||
- reset/state management
|
||||
|
||||
- ✅ **CardanoWalletManager updated** to use CardanoClient:
|
||||
- `refreshBalance()` now fetches real balance via Koios
|
||||
- Updates WalletState with lovelace + formatted ADA string
|
||||
|
||||
### Design Notes
|
||||
- **No API key required** — Koios public API is free
|
||||
- **Network config centralized** — Change `CardanoNetworkConfig.NETWORK` to swap testnet/mainnet
|
||||
- **Hex CBOR for submitTx** — Accepts hex-encoded signed transaction bytes
|
||||
- **UTxO pagination** — Limited to first 100 UTxOs (sufficient for typical wallets)
|
||||
|
||||
### Potential Issues
|
||||
- ⚠️ `getTxStatus` returns PENDING for unknown hashes (could be never-submitted or truly pending)
|
||||
- ⚠️ Koios rate limit (100 req/10s) may need adjustment for heavy usage patterns
|
||||
- ⚠️ No getProtocolParameters yet (needed for Task 4 fee calculation)
|
||||
|
||||
---
|
||||
|
||||
## Task 4-8: Pending
|
||||
|
||||
See PHASE1-PLAN.md for full task breakdown.
|
||||
|
||||
---
|
||||
|
||||
## Known Issues
|
||||
|
||||
### Issue 1: Biometric Prompt Activity Context
|
||||
The `CardanoKeyStorageImpl` uses `setUserAuthenticationRequired(true)` which will cause `UserNotAuthenticatedException` when accessing the key. The biometric prompt UI must be triggered from an Activity/Fragment context before calling `getMnemonic()`, `getSpendingKey()`, etc.
|
||||
|
||||
**Solution:** Task 6 (Payment Flow UI) must call BiometricPrompt before invoking storage operations.
|
||||
|
||||
### Issue 2: KeyPermanentlyInvalidatedException
|
||||
If user changes biometric enrollment, the Keystore key is invalidated. Current behavior: throws exception, user must delete and recreate wallet.
|
||||
|
||||
**Enhancement (future):** Show user-friendly message explaining why wallet became invalid and offer to re-import.
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-03-27 - Task 2 complete*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue