feat(wallet): token send support with asset picker
- Add UtxoAsset model for native assets in UTXOs - Update KoiosCardanoClient.getUtxos() to parse asset_list - Add asset fields to PaymentRequest (policyId, name, quantity) - DefaultTransactionBuilder: multi-asset tx with Amount.asset() - Min UTXO: always include 1.5 ADA with token sends (protocol req) - PaymentEntryPresenter: load available assets, handle selection - PaymentEntryView: asset picker dropdown when tokens available - PaymentConfirmation: show token name/quantity instead of ADA - PaymentProgress: displayAmount field for token sends - Wire asset data through entire nav flow (FlowNode/Nodes) - Updated NativeAsset with metadata fields for NFT prep
This commit is contained in:
parent
af05e51916
commit
a57fd79098
20 changed files with 648 additions and 100 deletions
|
|
@ -14,6 +14,11 @@ package io.element.android.features.wallet.api
|
|||
* @property quantity The amount of this asset
|
||||
* @property displayName Human-readable name if available
|
||||
* @property fingerprint The asset fingerprint (CIP-14)
|
||||
* @property imageUrl Resolved image URL (IPFS gateway or HTTPS) for NFTs
|
||||
* @property decimals Decimal places for fungible tokens (null for NFTs)
|
||||
* @property ticker Token ticker symbol (e.g., "HOSKY")
|
||||
* @property description Token/NFT description
|
||||
* @property isNft True if this is likely an NFT (quantity == 1 with image metadata)
|
||||
*/
|
||||
data class NativeAsset(
|
||||
val policyId: String,
|
||||
|
|
@ -21,6 +26,11 @@ data class NativeAsset(
|
|||
val quantity: Long,
|
||||
val displayName: String?,
|
||||
val fingerprint: String?,
|
||||
val imageUrl: String? = null,
|
||||
val decimals: Int? = null,
|
||||
val ticker: String? = null,
|
||||
val description: String? = null,
|
||||
val isNft: Boolean = false,
|
||||
) {
|
||||
/**
|
||||
* Truncated policy ID for display.
|
||||
|
|
@ -36,7 +46,7 @@ data class NativeAsset(
|
|||
* Display name, falling back to truncated asset name.
|
||||
*/
|
||||
val name: String
|
||||
get() = displayName ?: assetName.takeIf { it.isNotEmpty() }?.let {
|
||||
get() = displayName ?: ticker ?: assetName.takeIf { it.isNotEmpty() }?.let {
|
||||
// Try to decode hex to ASCII if it looks printable
|
||||
try {
|
||||
val decoded = it.chunked(2).map { hex -> hex.toInt(16).toChar() }.joinToString("")
|
||||
|
|
@ -45,4 +55,22 @@ data class NativeAsset(
|
|||
it
|
||||
}
|
||||
} ?: "Unknown"
|
||||
|
||||
/**
|
||||
* Unit string for this asset (concatenated policyId + assetName).
|
||||
*/
|
||||
val unit: String
|
||||
get() = "$policyId$assetName"
|
||||
|
||||
/**
|
||||
* Format quantity with decimals for display.
|
||||
*/
|
||||
fun formatQuantity(): String {
|
||||
return if (decimals != null && decimals > 0) {
|
||||
val divisor = Math.pow(10.0, decimals.toDouble())
|
||||
String.format("%.${decimals}f", quantity / divisor).trimEnd('0').trimEnd('.')
|
||||
} else {
|
||||
quantity.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,25 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
|||
*
|
||||
* @property fromAddress The sender's Cardano address (Bech32)
|
||||
* @property toAddress The recipient's Cardano address (Bech32)
|
||||
* @property amountLovelace The amount to send in lovelace (1 ADA = 1,000,000 lovelace)
|
||||
* @property amountLovelace The amount of ADA to send in lovelace (1 ADA = 1,000,000 lovelace).
|
||||
* For token-only sends, this should be the minimum UTXO (~1.5 ADA).
|
||||
* @property sessionId The Matrix session ID for key retrieval
|
||||
* @property assetPolicyId Policy ID of the native asset to send (null for ADA-only)
|
||||
* @property assetName Asset name in hex (null for ADA-only)
|
||||
* @property assetQuantity Quantity of the native asset to send (null for ADA-only)
|
||||
*/
|
||||
data class PaymentRequest(
|
||||
val fromAddress: String,
|
||||
val toAddress: String,
|
||||
val amountLovelace: Long,
|
||||
val sessionId: SessionId,
|
||||
)
|
||||
val assetPolicyId: String? = null,
|
||||
val assetName: String? = null,
|
||||
val assetQuantity: Long? = null,
|
||||
) {
|
||||
/**
|
||||
* True if this request includes a native asset (token) send.
|
||||
*/
|
||||
val hasAsset: Boolean
|
||||
get() = assetPolicyId != null && assetName != null && assetQuantity != null && assetQuantity > 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,25 @@ package io.element.android.features.wallet.api
|
|||
* @property outputIndex The index of this output within the transaction.
|
||||
* @property amount The amount in lovelace (1 ADA = 1,000,000 lovelace).
|
||||
* @property address The address holding this UTxO.
|
||||
* @property assets Native assets (tokens) contained in this UTxO.
|
||||
*/
|
||||
data class Utxo(
|
||||
val txHash: String,
|
||||
val outputIndex: Int,
|
||||
val amount: Long,
|
||||
val address: String,
|
||||
val assets: List<UtxoAsset> = emptyList(),
|
||||
)
|
||||
|
||||
/**
|
||||
* Represents a native asset within a UTxO.
|
||||
*
|
||||
* @property policyId The minting policy ID (56 hex chars).
|
||||
* @property assetName The asset name (hex-encoded).
|
||||
* @property quantity The amount of this asset in the UTxO.
|
||||
*/
|
||||
data class UtxoAsset(
|
||||
val policyId: String,
|
||||
val assetName: String,
|
||||
val quantity: Long,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue