feat(wallet): store Cardano address in Matrix account data for discovery

Implements public Cardano address directory using Matrix account data:

Publishing (write side):
- After wallet creation, import, or SSSS restore, the Cardano address
  is written to the user Matrix account data
- Key: com.sulkta.cardano.address
- Content: { "address": "addr1..." }
- This is public/unencrypted for discovery by other users

Lookup (read side):
- When entering a Matrix user in /pay, their account data is checked
- If they have a linked Cardano address, it auto-fills the recipient
- UI shows "Address loaded from @username profile ✓" when found
- Shows "@username has not linked a wallet" if not found
- Graceful fallback to manual address entry

New files:
- CardanoAddressService interface (wallet:api)
- DefaultCardanoAddressService implementation (wallet:impl)

Updated:
- WalletSetupPresenter: calls publishAddress after all wallet setup paths
- PaymentEntryPresenter: looks up recipient address from Matrix
- PaymentEntryState: added Resolving and Found states
- PaymentEntryView: shows lookup progress and result cards
This commit is contained in:
Kayos 2026-03-29 07:08:09 -07:00
parent 699807e1bd
commit c35289a3bd
6 changed files with 390 additions and 16 deletions

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2026 Sulkta Coop.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
package io.element.android.features.wallet.api.address
import io.element.android.libraries.matrix.api.core.UserId
/**
* Service for managing Cardano addresses in Matrix account data.
*
* This allows users to publish their Cardano address so other users can
* look it up for payments - like a public address directory baked into Matrix.
*
* Account data key: `com.sulkta.cardano.address`
* Content format: `{ "address": "addr1..." }`
*/
interface CardanoAddressService {
/**
* Publish the user's Cardano address to their Matrix account data.
* This is public data, not encrypted.
*
* @param address The Cardano address to publish
* @return Result indicating success or failure
*/
suspend fun publishAddress(address: String): Result<Unit>
/**
* Look up another user's Cardano address from their Matrix account data.
*
* @param userId The Matrix user ID to look up
* @return The user's Cardano address if published, null if not found
*/
suspend fun lookupAddress(userId: UserId): Result<String?>
companion object {
const val ACCOUNT_DATA_TYPE = "com.sulkta.cardano.address"
}
}
/**
* Result of a Cardano address lookup.
*/
sealed interface AddressLookupResult {
/** Address was found and retrieved successfully */
data class Found(val address: String, val userId: UserId) : AddressLookupResult
/** User has no Cardano address linked */
data class NotLinked(val userId: UserId) : AddressLookupResult
/** Lookup failed due to an error */
data class Error(val userId: UserId, val message: String) : AddressLookupResult
}