Covers: - CIP-1852 key derivation with code examples - Transaction building (cardano-client-lib + CSL) - Android library comparison (cardano-client-lib recommended) - CIP-0013 payment URI parsing - CIP-0030/CIP-0045 dApp connectivity - Koios vs Blockfrost API analysis - MVP architecture recommendations
26 KiB
Cardano Technical Specifications Review for Element X ADA Wallet
Date: 2026-03-26
Purpose: Deep technical review for building a native Cardano wallet inside an Android app (Element X fork)
Table of Contents
- Key Derivation (CIP-1852)
- Transaction Building & Signing
- Android Library Options
- Minimum Viable TX Flow
- CIP-0013: Payment URI Format
- CIP-0030: dApp-Wallet Bridge
- CIP-0045: WebRTC dApp-Wallet Communication
- WalletConnect v2 on Cardano
- Backend APIs: Koios vs Blockfrost
- Recommendations
1. Key Derivation (CIP-1852)
Standard Derivation Path
CIP-1852 defines the HD wallet derivation for Cardano Shelley-era wallets, based on BIP-44/BIP-32-Ed25519.
Standard path:
m / purpose' / coin_type' / account' / role / index
Concrete values:
purpose: 1852' (hardened) - Shelley wallets (or 44' for Byron)coin_type: 1815' (hardened) - Cardano's registered coin typeaccount: 0' (hardened) - First accountrole:- 0 = External chain (receiving addresses)
- 1 = Internal chain (change addresses)
- 2 = Staking key
index: Sequential address index
Example derivation paths:
m/1852'/1815'/0'/0/0 → First external/receiving address
m/1852'/1815'/0'/1/0 → First internal/change address
m/1852'/1815'/0'/2/0 → Staking key
Code Example (cardano-serialization-lib / JavaScript)
function harden(num) {
return 0x80000000 + num;
}
// From mnemonic to root key
import { mnemonicToEntropy } from 'bip39';
const entropy = mnemonicToEntropy(
"test walk nut penalty hip pave soap entry language right filter choice"
);
const rootKey = CardanoWasm.Bip32PrivateKey.from_bip39_entropy(
Buffer.from(entropy, 'hex'),
Buffer.from(''), // empty password
);
// Derive account key
const accountKey = rootKey
.derive(harden(1852)) // purpose
.derive(harden(1815)) // coin type
.derive(harden(0)); // account #0
// Derive payment key (external, index 0)
const utxoPubKey = accountKey
.derive(0) // external chain
.derive(0) // index 0
.to_public();
// Derive staking key
const stakeKey = accountKey
.derive(2) // staking role
.derive(0)
.to_public();
// Create base address (payment + staking)
const baseAddr = CardanoWasm.BaseAddress.new(
CardanoWasm.NetworkInfo.mainnet().network_id(),
CardanoWasm.StakeCredential.from_keyhash(utxoPubKey.to_raw_key().hash()),
CardanoWasm.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash()),
);
console.log(baseAddr.to_address().to_bech32());
// Output: addr1q...
Code Example (cardano-client-lib / Java/Kotlin)
import com.bloxbean.cardano.client.account.Account
import com.bloxbean.cardano.client.common.model.Networks
// Create new wallet from mnemonic
val mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
val account = Account(Networks.mainnet(), mnemonic)
// Get addresses
val baseAddress = account.baseAddress() // addr1q...
val enterpriseAddress = account.enterpriseAddress()
val stakeAddress = account.stakeAddress() // stake1u...
// For derivation at specific index
val account5 = Account(Networks.mainnet(), mnemonic, 5) // account index 5
2. Transaction Building & Signing
Simple ADA Transfer with cardano-client-lib (Java/Kotlin)
This is the recommended approach for Android as it's pure Java/Kotlin.
import com.bloxbean.cardano.client.account.Account
import com.bloxbean.cardano.client.backend.blockfrost.service.BFBackendService
import com.bloxbean.cardano.client.common.model.Networks
import com.bloxbean.cardano.client.quicktx.QuickTxBuilder
import com.bloxbean.cardano.client.quicktx.Tx
import com.bloxbean.cardano.client.function.helper.SignerProviders
// Setup
val backendService = BFBackendService(
"https://cardano-mainnet.blockfrost.io/api/v0",
"<PROJECT_ID>"
)
val sender = Account(Networks.mainnet(), "<mnemonic>")
val senderAddress = sender.baseAddress()
val receiverAddress = "addr1q..."
// Build and submit transaction
val tx = Tx()
.payToAddress(receiverAddress, Amount.ada(5.0))
.from(senderAddress)
val quickTxBuilder = QuickTxBuilder(backendService)
val result = quickTxBuilder
.compose(tx)
.withSigner(SignerProviders.signerFrom(sender))
.completeAndWait { txHash -> println("Submitted: $txHash") }
if (result.isSuccessful) {
println("Transaction hash: ${result.value}")
}
Low-level Transaction Building (cardano-client-lib)
import com.bloxbean.cardano.client.function.TxBuilder
import com.bloxbean.cardano.client.function.TxBuilderContext
import com.bloxbean.cardano.client.function.Output
import com.bloxbean.cardano.client.function.helper.*
import com.bloxbean.cardano.client.backend.api.DefaultUtxoSupplier
import com.bloxbean.cardano.client.backend.api.DefaultProtocolParamsSupplier
// Define outputs
val output = Output.builder()
.address(receiverAddress)
.assetName("lovelace")
.qty(5_000_000) // 5 ADA in lovelace
.build()
// Build transaction
val txBuilder = output.outputBuilder()
.buildInputs(InputBuilders.createFromSender(senderAddress, senderAddress))
.andThen(BalanceTxBuilders.balanceTx(senderAddress, 1))
val utxoSupplier = DefaultUtxoSupplier(backendService.utxoService)
val protocolParamsSupplier = DefaultProtocolParamsSupplier(backendService.epochService)
// Build and sign
val signedTx = TxBuilderContext.init(utxoSupplier, protocolParamsSupplier)
.buildAndSign(txBuilder, SignerProviders.signerFrom(sender))
// Submit
val result = backendService.transactionService.submitTransaction(signedTx.serialize())
Transaction Building with cardano-serialization-lib (JavaScript/WASM)
// Protocol parameters (these change - fetch from backend)
const linearFee = CardanoWasm.LinearFee.new(
CardanoWasm.BigNum.from_str('44'),
CardanoWasm.BigNum.from_str('155381')
);
const txBuilderCfg = CardanoWasm.TransactionBuilderConfigBuilder.new()
.fee_algo(linearFee)
.pool_deposit(CardanoWasm.BigNum.from_str('500000000'))
.key_deposit(CardanoWasm.BigNum.from_str('2000000'))
.max_value_size(4000)
.max_tx_size(8000)
.coins_per_utxo_word(CardanoWasm.BigNum.from_str('34482'))
.build();
const txBuilder = CardanoWasm.TransactionBuilder.new(txBuilderCfg);
// Add input (must provide UTxO details from backend)
txBuilder.add_key_input(
prvKey.to_public().hash(),
CardanoWasm.TransactionInput.new(
CardanoWasm.TransactionHash.from_bytes(
Buffer.from("8561258e210352fba2ac0488afed67b3427a27ccf1d41ec030c98a8199bc22ec", "hex")
),
0 // index
),
CardanoWasm.Value.new(CardanoWasm.BigNum.from_str('10000000'))
);
// Add output
const outputAddr = CardanoWasm.Address.from_bech32("addr_test1qpu...");
txBuilder.add_output(
CardanoWasm.TransactionOutput.new(
outputAddr,
CardanoWasm.Value.new(CardanoWasm.BigNum.from_str('5000000'))
)
);
// Set TTL (time-to-live)
txBuilder.set_ttl(410021);
// Add change output (calculates fee automatically)
const changeAddr = CardanoWasm.Address.from_bech32("addr_test1...");
txBuilder.add_change_if_needed(changeAddr);
// Build transaction body
const txBody = txBuilder.build();
const txHash = CardanoWasm.hash_transaction(txBody);
// Sign
const witnesses = CardanoWasm.TransactionWitnessSet.new();
const vkeyWitnesses = CardanoWasm.Vkeywitnesses.new();
const vkeyWitness = CardanoWasm.make_vkey_witness(txHash, prvKey);
vkeyWitnesses.add(vkeyWitness);
witnesses.set_vkeys(vkeyWitnesses);
// Assemble final transaction
const transaction = CardanoWasm.Transaction.new(txBody, witnesses, undefined);
const signedTxCbor = transaction.to_bytes();
3. Android Library Options
Option A: cardano-client-lib (RECOMMENDED)
Repository: https://github.com/bloxbean/cardano-client-lib
Why it's the best choice for Android:
- Pure Java - No JNI/native dependencies
- Works on Android out of the box - Min SDK 21+
- Active development - Regular releases, good documentation
- Modular design - Include only what you need
- Backend-agnostic - Supports Blockfrost, Koios, Ogmios/Kupo
- CIP implementations - CIP-8 (message signing), CIP-20, CIP-25, CIP-30, CIP-67, CIP-68
Gradle dependencies:
dependencies {
// Core library
implementation 'com.bloxbean.cardano:cardano-client-lib:0.7.1'
// Pick ONE backend:
implementation 'com.bloxbean.cardano:cardano-client-backend-blockfrost:0.7.1'
// OR
implementation 'com.bloxbean.cardano:cardano-client-backend-koios:0.7.1'
}
Key modules:
| Module | Purpose |
|---|---|
cardano-client-crypto |
BIP32, BIP39, CIP1852 key derivation |
cardano-client-address |
Address generation (Base, Enterprise, Stake) |
cardano-client-transaction-spec |
Transaction serialization (CBOR) |
cardano-client-quicktx |
High-level transaction builder |
cardano-client-cip30 |
dApp-Wallet bridge implementation |
Option B: cardano-serialization-lib (CSL)
Repository: https://github.com/Emurgo/cardano-serialization-lib
Android challenges:
- Written in Rust, compiled to WebAssembly
- For Android, requires JNI bindings via Rust FFI
- React Native wrapper exists (
react-native-haskell-shelley) but adds complexity - No official AAR published
- Would need to compile Rust to Android NDK targets (arm64-v8a, armeabi-v7a, x86, x86_64)
When to consider:
- If you need exact byte-level compatibility with other CSL implementations
- If building a complex dApp that needs Plutus script support
- If your team already has Rust/JNI expertise
Build requirements for Android:
# Would need to set up:
rustup target add aarch64-linux-android
rustup target add armv7-linux-androideabi
rustup target add i686-linux-android
rustup target add x86_64-linux-android
# Then build with cargo-ndk or similar
Option C: Blockfrost Kotlin SDK
Repository: https://github.com/blockfrost/blockfrost-kotlin
Purpose: API client only - does NOT handle key management or transaction building
Use for: Querying blockchain data, submitting pre-built transactions
import io.blockfrost.sdk_kotlin.api.CardanoAddressesApi
import io.blockfrost.sdk_kotlin.infrastructure.ApiClient
ApiClient.apiKey["project_id"] = "<PROJECT_ID>"
val addressApi = CardanoAddressesApi("https://cardano-mainnet.blockfrost.io/api/v0")
val utxos = addressApi.getAddressUtxos("addr1q...")
Recommendation Matrix
| Use Case | Recommended Library |
|---|---|
| Simple wallet (send/receive ADA) | cardano-client-lib |
| NFT minting | cardano-client-lib |
| Staking delegation | cardano-client-lib |
| Complex smart contracts | cardano-serialization-lib (with significant integration effort) |
| Just querying data | Blockfrost Kotlin SDK |
4. Minimum Viable TX Flow
High-Level Flow
1. USER INITIATES PAYMENT
└─> Parse recipient address, amount
2. FETCH UTXOs
└─> Query backend for sender's unspent outputs
└─> Select UTxOs covering amount + fees
3. BUILD TRANSACTION
├─> Inputs: Selected UTxOs
├─> Outputs: Payment output + change output
├─> Calculate fees based on tx size
└─> Set TTL (current slot + ~7200 slots = ~2 hours)
4. SIGN TRANSACTION
└─> Use payment private key to create witness
5. SUBMIT TRANSACTION
└─> POST serialized CBOR to backend
6. CONFIRM
└─> Poll for confirmation or use websocket
Kotlin Implementation
class CardanoWallet(
private val backendService: BackendService,
private val account: Account
) {
suspend fun sendAda(
recipientAddress: String,
amountAda: Double
): Result<String> = withContext(Dispatchers.IO) {
try {
val tx = Tx()
.payToAddress(recipientAddress, Amount.ada(amountAda))
.from(account.baseAddress())
val result = QuickTxBuilder(backendService)
.compose(tx)
.withSigner(SignerProviders.signerFrom(account))
.complete()
if (result.isSuccessful) {
// Submit
val submitResult = backendService.transactionService
.submitTransaction(result.value.serialize())
if (submitResult.isSuccessful) {
Result.success(submitResult.value)
} else {
Result.failure(Exception(submitResult.response))
}
} else {
Result.failure(Exception("Failed to build transaction"))
}
} catch (e: Exception) {
Result.failure(e)
}
}
}
Fee Calculation
Cardano fees are calculated as:
fee = a * tx_size_bytes + b
Current mainnet parameters (as of March 2026):
a= 44 lovelace/byteb= 155,381 lovelace (base fee)
Typical simple transaction: ~250-350 bytes → ~165,000-175,000 lovelace (~0.17 ADA)
5. CIP-0013: Payment URI Format
URI Format
web+cardano:<address>[?amount=<amount>][&message=<message>]
Parameters
| Parameter | Required | Description |
|---|---|---|
address |
Yes | Bech32 address (addr1...) or $handle |
amount |
No | Amount in lovelace (1 ADA = 1,000,000 lovelace) |
message |
No | URL-encoded message (for tx metadata) |
Examples
# Simple payment request
web+cardano:addr1qxck...
# With amount (5 ADA = 5,000,000 lovelace)
web+cardano:addr1qxck...?amount=5000000
# With amount and message
web+cardano:addr1qxck...?amount=5000000&message=Coffee%20payment
# Using ADA handle
web+cardano:$kayos
Kotlin Parser
data class CardanoPaymentRequest(
val address: String,
val amount: Long? = null, // in lovelace
val message: String? = null
)
fun parseCardanoUri(uri: String): CardanoPaymentRequest? {
val prefix = "web+cardano:"
if (!uri.startsWith(prefix)) return null
val withoutPrefix = uri.removePrefix(prefix)
val parts = withoutPrefix.split("?", limit = 2)
val address = parts[0]
val params = if (parts.size > 1) {
parts[1].split("&").associate { param ->
val kv = param.split("=", limit = 2)
kv[0] to (if (kv.size > 1) URLDecoder.decode(kv[1], "UTF-8") else "")
}
} else emptyMap()
return CardanoPaymentRequest(
address = address,
amount = params["amount"]?.toLongOrNull(),
message = params["message"]
)
}
// Usage
val request = parseCardanoUri("web+cardano:addr1q...?amount=5000000&message=Test")
// CardanoPaymentRequest(address="addr1q...", amount=5000000, message="Test")
Android Intent Filter
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="web+cardano" />
</intent-filter>
6. CIP-0030: dApp-Wallet Bridge
Overview
CIP-0030 defines a JavaScript API for web dApps to communicate with browser extension wallets. For a mobile wallet, this is relevant when:
- Implementing WalletConnect-style connectivity
- Building an in-app dApp browser
- Providing SDK for dApps to integrate
API Methods
Initialization:
// dApp requests connection
const api = await window.cardano.nami.enable();
Key Methods:
| Method | Returns | Description |
|---|---|---|
getNetworkId() |
Promise<number> |
0 = testnet, 1 = mainnet |
getUtxos() |
Promise<TransactionUnspentOutput[]> |
Wallet's UTxOs in CBOR |
getBalance() |
Promise<Value> |
Total balance (CBOR) |
getUsedAddresses() |
Promise<Address[]> |
Used addresses |
getUnusedAddresses() |
Promise<Address[]> |
Fresh addresses |
getChangeAddress() |
Promise<Address> |
Address for change |
getRewardAddresses() |
Promise<Address[]> |
Staking addresses |
signTx(tx, partialSign) |
Promise<TransactionWitnessSet> |
Sign transaction |
signData(addr, payload) |
Promise<DataSignature> |
CIP-8 message signing |
submitTx(tx) |
Promise<TransactionHash> |
Submit to network |
cardano-client-lib CIP-30 Support
import com.bloxbean.cardano.client.cip.cip30.CIP30DataSigner
// Sign arbitrary data (CIP-8)
val signature = CIP30DataSigner.sign(
account.hdKeyPair().privateKey,
"Hello Cardano!".toByteArray()
)
// Returns: { signature: "...", key: "..." }
7. CIP-0045: WebRTC dApp-Wallet Communication
Overview
CIP-0045 enables P2P communication between dApps and mobile wallets using WebRTC/WebTorrent, eliminating the need for browser extensions.
How It Works
┌─────────────┐ WebRTC/WebTorrent ┌──────────────┐
│ dApp │ <─────────────────────────────────>│ Mobile Wallet│
│ (Browser) │ P2P via BitTorrent trackers │ (App) │
└─────────────┘ └──────────────┘
1. dApp displays QR code
2. Wallet scans, establishes P2P
3. CIP-30 API over the channel
Reference Implementation
Library: @fabianbormann/cardano-peer-connect
Repository: https://github.com/fabianbormann/cardano-peer-connect
Wallet Implementation (TypeScript/React Native)
import { CardanoPeerConnect } from '@fabianbormann/cardano-peer-connect';
class MyWalletPeerConnect extends CardanoPeerConnect {
constructor() {
super({
name: 'Element X ADA',
version: '1.0.0',
icon: '<base64-icon>'
});
}
// Implement CIP-30 methods
async getRewardAddresses(): Promise<string[]> {
return [this.wallet.stakeAddress];
}
async getUsedAddresses(): Promise<string[]> {
return [this.wallet.baseAddress];
}
async signTx(tx: string, partialSign: boolean): Promise<string> {
// Show UI for user approval
const approved = await this.showSigningDialog(tx);
if (!approved) throw new Error('User rejected');
return this.wallet.sign(tx);
}
}
// Connect to dApp
const peerConnect = new MyWalletPeerConnect();
peerConnect.setOnConnect((message) => {
console.log('Connected to dApp:', message.dApp.name);
});
// Scan QR code to get dApp identifier
const dAppId = 'bYUh6Bn6A...388LR1JCrED';
peerConnect.connect(dAppId, [
'wss://tracker.openwebtorrent.com:443/announce',
'wss://tracker.btorrent.xyz'
]);
Android Wallets Supporting CIP-0045
| Wallet | CIP-0045 Support | Notes |
|---|---|---|
| Eternl | ✅ | Full support |
| Typhon | ✅ | Full support |
| Vespr | ⚠️ | WalletConnect preferred |
| Nami | ❌ | Browser extension only |
| Lace | ❌ | Browser extension only |
Recommendation
CIP-0045 is powerful but complex. For MVP:
- Start without CIP-0045 - focus on send/receive
- Phase 2: Add CIP-0013 URI handling
- Phase 3: Consider CIP-0045 for dApp integration
8. WalletConnect v2 on Cardano
Current State
WalletConnect v2 on Cardano is fragmented:
- No official Cardano namespace in WC2 registry
- Different wallets use different approaches:
- VESPR: Uses custom implementation
- Flint: Has WC2 support
- Most wallets: Prefer CIP-0045
VESPR Wallet
VESPR (https://vespr.xyz/) is a popular mobile wallet:
- Android: Yes (Play Store)
- iOS: Yes (App Store)
- Supports both CIP-0045 and a custom WC-style protocol
- Closed source
For Element X ADA
Recommendation: Implement CIP-0045 rather than WalletConnect v2:
- Better Cardano ecosystem adoption
- Open standard with reference implementation
- Works with more dApps
9. Backend APIs: Koios vs Blockfrost
Feature Comparison
| Feature | Blockfrost | Koios |
|---|---|---|
| Pricing | Freemium (50k req/day free) | Free (community) |
| Rate Limits | 10 req/sec, 500 burst | 100 req/10s |
| Decentralization | Centralized | Decentralized nodes |
| Kotlin SDK | ✅ Official | ❌ (REST only) |
| Java SDK | ✅ Official | Via cardano-client-lib |
| Self-hosting | ❌ | ✅ |
| IPFS | ✅ | ❌ |
| Reliability | Very high | Good (varies by node) |
API Comparison
Get UTxOs:
# Blockfrost
curl -H "project_id: <ID>" \
"https://cardano-mainnet.blockfrost.io/api/v0/addresses/addr1.../utxos"
# Koios
curl "https://api.koios.rest/api/v1/address_utxos?_address=addr1..."
Submit Transaction:
# Blockfrost
curl -X POST -H "project_id: <ID>" \
-H "Content-Type: application/cbor" \
--data-binary @tx.signed \
"https://cardano-mainnet.blockfrost.io/api/v0/tx/submit"
# Koios
curl -X POST \
-H "Content-Type: application/cbor" \
--data-binary @tx.signed \
"https://api.koios.rest/api/v1/submittx"
Kotlin/Android Usage
Blockfrost with cardano-client-lib:
val backendService = BFBackendService(
Constants.BLOCKFROST_MAINNET_URL,
"<PROJECT_ID>"
)
val utxos = backendService.utxoService.getUtxos(address, 100, 1)
Koios with cardano-client-lib:
val backendService = KoiosBackendService(
Constants.KOIOS_MAINNET_URL
)
val utxos = backendService.utxoService.getUtxos(address, 100, 1)
Recommendation for Element X ADA
Use Blockfrost for MVP:
- Official Kotlin SDK
- Higher reliability guarantees
- Free tier sufficient for development/testing
- Easy to switch to Koios later (same cardano-client-lib interface)
Consider Koios for production if:
- Need to minimize costs at scale
- Want decentralization
- Plan to self-host infrastructure
10. Recommendations
Architecture Summary
┌─────────────────────────────────────────────────────────┐
│ Element X ADA │
├─────────────────────────────────────────────────────────┤
│ UI Layer (Compose) │
│ ├─ WalletScreen (balance, history) │
│ ├─ SendScreen (CIP-0013 URI parsing) │
│ └─ ReceiveScreen (QR generation) │
├─────────────────────────────────────────────────────────┤
│ Wallet Core │
│ ├─ KeyManager (encrypted mnemonic storage) │
│ ├─ TransactionBuilder (QuickTx API) │
│ └─ AddressGenerator (CIP-1852) │
├─────────────────────────────────────────────────────────┤
│ cardano-client-lib (0.7.1) │
│ ├─ cardano-client-lib │
│ ├─ cardano-client-backend-blockfrost │
│ └─ cardano-client-cip30 (for future dApp support) │
├─────────────────────────────────────────────────────────┤
│ Backend │
│ └─ Blockfrost API (mainnet/testnet) │
└─────────────────────────────────────────────────────────┘
MVP Feature Set
-
Wallet Management
- Generate new wallet (24-word mnemonic)
- Import existing wallet
- Secure storage (Android Keystore)
-
Basic Operations
- View ADA balance
- View transaction history
- Send ADA (manual entry)
- Receive ADA (QR code + address)
-
CIP Support (Phase 1)
- CIP-1852: Key derivation ✅
- CIP-0013: Payment URIs ✅
-
Future Enhancements (Phase 2+)
- Native tokens display
- Staking delegation
- CIP-0045: dApp connectivity
- NFT gallery
Dependencies (build.gradle)
dependencies {
// Cardano core
implementation 'com.bloxbean.cardano:cardano-client-lib:0.7.1'
implementation 'com.bloxbean.cardano:cardano-client-backend-blockfrost:0.7.1'
// For CIP-30 support (Phase 2)
implementation 'com.bloxbean.cardano:cardano-client-cip30:0.7.1'
// Security
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
// QR codes
implementation 'com.google.zxing:core:3.5.2'
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
}
Security Considerations
-
Mnemonic Storage:
- Use Android Keystore + EncryptedSharedPreferences
- Never store plaintext
- Consider hardware-backed keys on supported devices
-
Transaction Signing:
- Derive keys in memory only
- Clear sensitive data after use
- Require biometric/PIN for signing
-
Network:
- Use certificate pinning for API calls
- Validate all addresses before sending
Appendix: Quick Reference
Address Prefixes
| Type | Mainnet Prefix | Testnet Prefix |
|---|---|---|
| Base | addr1 | addr_test1 |
| Enterprise | addr1 | addr_test1 |
| Stake | stake1 | stake_test1 |
| Script | addr1 | addr_test1 |
Lovelace Conversions
1 ADA = 1,000,000 lovelace
1 lovelace = 0.000001 ADA
// Kotlin helper
fun adaToLovelace(ada: Double): Long = (ada * 1_000_000).toLong()
fun lovelaceToAda(lovelace: Long): Double = lovelace / 1_000_000.0
Testnet Faucet
https://docs.cardano.org/cardano-testnets/tools/faucet/
Document prepared for Element X ADA project. Last updated: 2026-03-26