Skip to content

Commit f42599e

Browse files
JOHNJOHN
authored andcommitted
docs: Add Paykit integration discovery document (Phase 1)
- Document LightningRepo and WalletRepo integration points - Map Paykit executor methods to Bitkit APIs - Document suspend/sync bridging patterns - Document error handling with Result<T> pattern - Document network configuration mapping - Outline payment completion polling strategy - Document dependency injection setup
1 parent d7ca7ad commit f42599e

File tree

1 file changed

+314
-0
lines changed

1 file changed

+314
-0
lines changed

INTEGRATION_DISCOVERY.md

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# Paykit Integration Discovery - Android
2+
3+
This document outlines the integration points for connecting Paykit-rs with Bitkit Android.
4+
5+
## Repository Structure
6+
7+
### Key Repositories
8+
9+
#### LightningRepo
10+
- **Location**: `app/src/main/java/to/bitkit/repositories/LightningRepo.kt`
11+
- **Type**: Singleton (via Dagger/Hilt: `@Singleton`)
12+
- **Purpose**: Manages Lightning Network operations via LightningService
13+
- **Dependencies**: `LightningService`, `CoreService`, `LdkNodeEventBus`
14+
15+
**Key Methods for Paykit Integration**:
16+
17+
1. **Lightning Payment**:
18+
```kotlin
19+
suspend fun payInvoice(bolt11: String, sats: ULong? = null): Result<PaymentId>
20+
```
21+
- **Location**: Line 521
22+
- **Returns**: `Result<PaymentId>` (from LDKNode)
23+
- **Usage**: Pay Lightning invoices
24+
- **Error Handling**: Returns `Result.failure(Exception)` on error
25+
26+
2. **Onchain Payment**:
27+
```kotlin
28+
suspend fun sendOnChain(
29+
address: Address,
30+
sats: ULong,
31+
speed: TransactionSpeed? = null,
32+
utxosToSpend: List<SpendableUtxo>? = null,
33+
feeRates: FeeRates? = null,
34+
isTransfer: Boolean = false,
35+
channelId: String? = null,
36+
isMaxAmount: Boolean = false
37+
): Result<Txid>
38+
```
39+
- **Location**: Line 529
40+
- **Returns**: `Result<Txid>` (from LDKNode)
41+
- **Usage**: Send Bitcoin on-chain
42+
- **Error Handling**: Returns `Result.failure(Exception)` on error
43+
44+
3. **Payment Access**:
45+
```kotlin
46+
suspend fun getPayments(): Result<List<PaymentDetails>>
47+
```
48+
- **Location**: Line 608
49+
- **Returns**: List of payment details
50+
- **Usage**: Get payment status and preimage
51+
52+
4. **Fee Estimation**:
53+
```kotlin
54+
suspend fun estimateRoutingFees(bolt11: String): Result<ULong>
55+
```
56+
- **Location**: Line 843
57+
- **Returns**: Routing fee in millisatoshis
58+
59+
5. **Onchain Fee Calculation**:
60+
```kotlin
61+
suspend fun calculateTotalFee(
62+
amountSats: ULong,
63+
address: Address? = null,
64+
speed: TransactionSpeed? = null,
65+
utxosToSpend: List<SpendableUtxo>? = null,
66+
feeRates: FeeRates? = null
67+
): Result<ULong>
68+
```
69+
- **Location**: Line 618
70+
- **Returns**: Total fee in satoshis
71+
72+
#### WalletRepo
73+
- **Location**: `app/src/main/java/to/bitkit/repositories/WalletRepo.kt`
74+
- **Type**: Singleton (via Dagger/Hilt: `@Singleton`)
75+
- **Purpose**: Manages wallet state and balance operations
76+
- **Dependencies**: `CoreService`, `LightningRepo`
77+
78+
**Key Methods for Paykit Integration**:
79+
80+
1. **Transaction Lookup**: Use `ActivityRepo` or `CoreService` for transaction queries
81+
2. **Balance Management**: Access via `balanceState` Flow
82+
83+
#### CoreService
84+
- **Location**: `app/src/main/java/to/bitkit/services/CoreService.kt`
85+
- **Type**: Singleton (via Dagger/Hilt)
86+
- **Purpose**: Core wallet operations and activity management
87+
88+
## API Mappings for Paykit Executors
89+
90+
### BitcoinExecutorFfi Implementation
91+
92+
#### sendToAddress
93+
- **Bitkit API**: `LightningRepo.sendOnChain(address:sats:speed:utxosToSpend:feeRates:isTransfer:channelId:isMaxAmount:)`
94+
- **Suspend Pattern**: `suspend -> Result<Txid>`
95+
- **Bridging**: Use `runBlocking` with `withTimeout`
96+
- **Return Mapping**:
97+
- `Result<Txid>` → Extract `.hex` on success
98+
- Need to query transaction for fee, vout, confirmations
99+
100+
#### estimateFee
101+
- **Bitkit API**: `LightningRepo.calculateTotalFee(amountSats:address:speed:utxosToSpend:feeRates:)`
102+
- **Return**: Fee in satoshis for target blocks
103+
- **Mapping**: Convert `TransactionSpeed` to target blocks
104+
105+
#### getTransaction
106+
- **Bitkit API**: Use `ActivityRepo` or `CoreService` to lookup transaction
107+
- **Query**: By `txid` (String)
108+
- **Return**: `BitcoinTxResultFfi` or `null`
109+
110+
#### verifyTransaction
111+
- **Bitkit API**: Get transaction via `getTransaction`, verify outputs
112+
- **Return**: Boolean
113+
114+
### LightningExecutorFfi Implementation
115+
116+
#### payInvoice
117+
- **Bitkit API**: `LightningRepo.payInvoice(bolt11:sats:)`
118+
- **Suspend Pattern**: `suspend -> Result<PaymentId>`
119+
- **Bridging**: Use `runBlocking` with `withTimeout`
120+
- **Payment Completion**:
121+
- Poll `LightningRepo.getPayments()` every 100-500ms
122+
- Find payment by `PaymentId` or `paymentHash`
123+
- Extract preimage from `PaymentDetails.preimage`
124+
- **Return Mapping**:
125+
- `PaymentId` → Extract for payment lookup
126+
- Extract preimage from payment details
127+
128+
#### decodeInvoice
129+
- **Bitkit API**: `com.synonym.bitkitcore.decode(invoice: String)``LightningInvoice`
130+
- **Mapping**:
131+
- `LightningInvoice.paymentHash``DecodedInvoiceFfi.paymentHash`
132+
- `LightningInvoice.amountMsat``DecodedInvoiceFfi.amountMsat`
133+
- `LightningInvoice.description``DecodedInvoiceFfi.description`
134+
- `LightningInvoice.payeePubkey``DecodedInvoiceFfi.payee`
135+
- `LightningInvoice.expiry``DecodedInvoiceFfi.expiry`
136+
- `LightningInvoice.timestamp``DecodedInvoiceFfi.timestamp`
137+
138+
#### estimateFee
139+
- **Bitkit API**: `LightningRepo.estimateRoutingFees(bolt11:)`
140+
- **Return**: Fee in millisatoshis
141+
142+
#### getPayment
143+
- **Bitkit API**: `LightningRepo.getPayments()``Result<List<PaymentDetails>>`
144+
- **Find by**: `paymentHash` (compare hex strings)
145+
- **Extract**: `PaymentDetails.preimage`, `amountMsat`, `feePaidMsat`, `status`
146+
147+
#### verifyPreimage
148+
- **Implementation**: Use `java.security.MessageDigest.getInstance("SHA-256")`
149+
- **Compute**: SHA256 of preimage bytes
150+
- **Compare**: With payment hash (case-insensitive)
151+
152+
## Error Types
153+
154+
### Result<T> Pattern
155+
- **Pattern**: Kotlin `Result<T>` type
156+
- **Success**: `Result.success(value)`
157+
- **Failure**: `Result.failure(exception)`
158+
- **Mapping to PaykitMobileException**:
159+
```kotlin
160+
result.fold(
161+
onSuccess = { value -> /* handle success */ },
162+
onFailure = { error ->
163+
throw PaykitMobileException.Transport(
164+
"Operation failed: ${error.message ?: error.toString()}"
165+
)
166+
}
167+
)
168+
```
169+
170+
## Network Configuration
171+
172+
### Current Network Setup
173+
- **Location**: `app/src/main/java/to/bitkit/env/Env.kt`
174+
- **Property**: `Env.network: Network` (from LDKNode)
175+
- **Values**: `Network.BITCOIN`, `Network.TESTNET`, `Network.REGTEST`, `Network.SIGNET`
176+
- **Mapping to Paykit**:
177+
- `Network.BITCOIN``BitcoinNetworkFfi.MAINNET` / `LightningNetworkFfi.MAINNET`
178+
- `Network.TESTNET``BitcoinNetworkFfi.TESTNET` / `LightningNetworkFfi.TESTNET`
179+
- `Network.REGTEST``BitcoinNetworkFfi.REGTEST` / `LightningNetworkFfi.REGTEST`
180+
- `Network.SIGNET``BitcoinNetworkFfi.TESTNET` / `LightningNetworkFfi.TESTNET` (fallback)
181+
182+
## Async/Sync Patterns
183+
184+
### Current Pattern
185+
- **Bitkit Repositories**: All use `suspend` functions (Kotlin coroutines)
186+
- **Paykit FFI**: Synchronous methods
187+
- **Bridging Strategy**: Use `runBlocking` with `withTimeout`
188+
189+
### Example Bridge Pattern
190+
```kotlin
191+
fun syncMethod(): Result {
192+
return runBlocking {
193+
withTimeout(30.seconds) {
194+
try {
195+
val result = suspendMethod()
196+
Result.success(result)
197+
} catch (e: Exception) {
198+
Result.failure(e)
199+
}
200+
}
201+
}
202+
}
203+
```
204+
205+
## Thread Safety
206+
207+
- **LightningRepo**: Singleton via Hilt, thread-safe
208+
- **CoreService**: Singleton via Hilt, thread-safe
209+
- **FFI Methods**: May be called from any thread
210+
- **Strategy**: `runBlocking` handles thread safety for suspend functions
211+
212+
## Payment Completion Handling
213+
214+
### Polling Approach (Required)
215+
```kotlin
216+
val paymentIdResult = lightningRepo.payInvoice(bolt11 = invoice, sats = sats)
217+
val paymentId = paymentIdResult.getOrThrow()
218+
219+
// Poll for completion
220+
var attempts = 0
221+
while (attempts < 60) {
222+
val paymentsResult = lightningRepo.getPayments()
223+
paymentsResult.onSuccess { payments ->
224+
val payment = payments.find { it.paymentId == paymentId }
225+
if (payment != null && payment.status == PaymentStatus.Succeeded) {
226+
val preimage = payment.preimage
227+
// Payment completed
228+
return@runBlocking preimage
229+
}
230+
}
231+
delay(1000) // 1 second
232+
attempts++
233+
}
234+
throw PaykitMobileException.NetworkTimeout("Payment timeout")
235+
```
236+
237+
## Transaction Details Extraction
238+
239+
### Challenge
240+
- `LightningRepo.sendOnChain()` returns only `Txid`
241+
- `BitcoinTxResultFfi` needs: fee, vout, confirmations, blockHeight
242+
243+
### Solution
244+
1. Return initial result with `confirmations: 0`, `blockHeight: null`
245+
2. Query transaction details after broadcast:
246+
```kotlin
247+
val txidResult = lightningRepo.sendOnChain(...)
248+
val txid = txidResult.getOrThrow()
249+
delay(2000) // Wait for propagation
250+
val txDetails = activityRepo.getTransaction(txid)
251+
// Extract fee, vout, confirmations
252+
```
253+
254+
## Dependency Injection
255+
256+
### Current Setup
257+
- **Framework**: Hilt (Dagger)
258+
- **Pattern**: Constructor injection with `@Inject`
259+
- **Example**:
260+
```kotlin
261+
@Singleton
262+
class BitkitBitcoinExecutor @Inject constructor(
263+
private val lightningRepo: LightningRepo,
264+
private val coreService: CoreService
265+
) : BitcoinExecutorFfi {
266+
// Implementation
267+
}
268+
```
269+
270+
## File Structure for Integration
271+
272+
### Proposed Structure
273+
```
274+
app/src/main/java/to/bitkit/paykit/
275+
├── PaykitManager.kt
276+
├── PaykitIntegrationHelper.kt
277+
├── executors/
278+
│ ├── BitkitBitcoinExecutor.kt
279+
│ └── BitkitLightningExecutor.kt
280+
└── services/
281+
└── PaykitPaymentService.kt
282+
```
283+
284+
## Dependencies
285+
286+
### Current Dependencies
287+
- `org.lightningdevkit.ldknode`: Lightning Network node implementation
288+
- `com.synonym.bitkitcore`: Core wallet functionality
289+
- `kotlinx.coroutines`: Coroutine support
290+
291+
### New Dependencies
292+
- `com.paykit.mobile`: Generated UniFFI bindings (to be added)
293+
294+
## Build Configuration
295+
296+
### Gradle Setup
297+
- **Location**: `app/build.gradle.kts`
298+
- **NDK**: May need NDK configuration for Rust libraries
299+
- **jniLibs**: Place `.so` files in `app/src/main/jniLibs/<arch>/`
300+
301+
### Build Targets
302+
- `aarch64-linux-android` (arm64-v8a)
303+
- `armv7-linux-androideabi` (armeabi-v7a)
304+
- `x86_64-linux-android` (x86_64) - for emulator
305+
306+
## Next Steps
307+
308+
1. ✅ Discovery complete (this document)
309+
2. ⏳ Set up Paykit-rs dependency
310+
3. ⏳ Generate UniFFI bindings
311+
4. ⏳ Configure Gradle build settings
312+
5. ⏳ Implement executors
313+
6. ⏳ Register executors with PaykitClient
314+
7. ⏳ Integration testing

0 commit comments

Comments
 (0)