@@ -9,18 +9,14 @@ import android.util.Log
9
9
import kotlinx.coroutines.runBlocking
10
10
import org.bitcoindevkit.Address
11
11
import org.bitcoindevkit.AddressInfo
12
- import org.rustbitcoin.bitcoin.Amount
13
12
import org.bitcoindevkit.CanonicalTx
14
13
import org.bitcoindevkit.ChainPosition
15
14
import org.bitcoindevkit.Connection
16
15
import org.bitcoindevkit.Descriptor
17
16
import org.bitcoindevkit.DescriptorSecretKey
18
- import org.rustbitcoin.bitcoin.FeeRate
19
17
import org.bitcoindevkit.KeychainKind
20
18
import org.bitcoindevkit.Mnemonic
21
- import org.rustbitcoin.bitcoin.Network
22
19
import org.bitcoindevkit.Psbt
23
- import org.rustbitcoin.bitcoin.Script
24
20
import org.bitcoindevkit.TxBuilder
25
21
import org.bitcoindevkit.Update
26
22
import org.bitcoindevkit.WordCount
@@ -34,8 +30,12 @@ import org.bitcoindevkit.devkitwallet.data.TxDetails
34
30
import org.bitcoindevkit.devkitwallet.domain.utils.intoDomain
35
31
import org.bitcoindevkit.devkitwallet.domain.utils.intoProto
36
32
import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.Recipient
37
- import org.bitcoindevkit.Wallet as BdkWallet
33
+ import org.rustbitcoin.bitcoin.Amount
34
+ import org.rustbitcoin.bitcoin.FeeRate
35
+ import org.rustbitcoin.bitcoin.Network
36
+ import org.rustbitcoin.bitcoin.Script
38
37
import java.util.UUID
38
+ import org.bitcoindevkit.Wallet as BdkWallet
39
39
40
40
private const val TAG = " Wallet"
41
41
@@ -46,19 +46,15 @@ class Wallet private constructor(
46
46
private var fullScanCompleted : Boolean ,
47
47
private val walletId : String ,
48
48
private val userPreferencesRepository : UserPreferencesRepository ,
49
- blockchainClientsConfig : BlockchainClientsConfig
49
+ blockchainClientsConfig : BlockchainClientsConfig ,
50
50
) {
51
51
private var currentBlockchainClient: BlockchainClient ? = blockchainClientsConfig.getClient()
52
52
53
53
fun getRecoveryPhrase (): List <String > {
54
54
return recoveryPhrase.split(" " )
55
55
}
56
56
57
- fun createTransaction (
58
- recipientList : List <Recipient >,
59
- feeRate : FeeRate ,
60
- opReturnMsg : String?
61
- ): Psbt {
57
+ fun createTransaction (recipientList : List <Recipient >, feeRate : FeeRate , opReturnMsg : String? ): Psbt {
62
58
// technique 1 for adding a list of recipients to the TxBuilder
63
59
// var txBuilder = TxBuilder()
64
60
// for (recipient in recipientList) {
@@ -67,11 +63,12 @@ class Wallet private constructor(
67
63
// txBuilder = txBuilder.feeRate(satPerVbyte = fee_rate)
68
64
69
65
// technique 2 for adding a list of recipients to the TxBuilder
70
- var txBuilder = recipientList.fold(TxBuilder ()) { builder, recipient ->
71
- // val address = Address(recipient.address)
72
- val scriptPubKey: Script = Address (recipient.address, Network .TESTNET ).scriptPubkey()
73
- builder.addRecipient(scriptPubKey, Amount .fromSat(recipient.amount))
74
- }
66
+ var txBuilder =
67
+ recipientList.fold(TxBuilder ()) { builder, recipient ->
68
+ // val address = Address(recipient.address)
69
+ val scriptPubKey: Script = Address (recipient.address, Network .TESTNET ).scriptPubkey()
70
+ builder.addRecipient(scriptPubKey, Amount .fromSat(recipient.amount))
71
+ }
75
72
// if (!opReturnMsg.isNullOrEmpty()) {
76
73
// txBuilder = txBuilder.addData(opReturnMsg.toByteArray(charset = Charsets.UTF_8).asUByteArray().toList())
77
74
// }
@@ -111,11 +108,13 @@ class Wallet private constructor(
111
108
}
112
109
113
110
fun broadcast (signedPsbt : Psbt ): String {
114
- currentBlockchainClient?.broadcast(signedPsbt.extractTx()) ? : throw IllegalStateException (" Blockchain client not initialized" )
111
+ currentBlockchainClient?.broadcast(signedPsbt.extractTx()) ? : throw IllegalStateException (
112
+ " Blockchain client not initialized"
113
+ )
115
114
return signedPsbt.extractTx().computeTxid()
116
115
}
117
116
118
- private fun getAllTransactions (): List <CanonicalTx > = wallet.transactions()
117
+ private fun getAllTransactions (): List <CanonicalTx > = wallet.transactions()
119
118
120
119
fun getAllTxDetails (): List <TxDetails > {
121
120
val transactions = getAllTransactions()
@@ -136,11 +135,27 @@ class Wallet private constructor(
136
135
Log .e(TAG , " Error calculating fee for tx $txid : $e " )
137
136
}
138
137
139
- val (confirmationBlock, confirmationTimestamp, pending) = when (val position = tx.chainPosition) {
140
- is ChainPosition .Unconfirmed -> Triple (null , null , true )
141
- is ChainPosition .Confirmed -> Triple (ConfirmationBlock (position.confirmationBlockTime.blockId.height), Timestamp (position.confirmationBlockTime.confirmationTime), false )
142
- }
143
- TxDetails (tx.transaction, txid, sent.toSat(), received.toSat(), fee?.toSat() ? : 0uL , feeRate, pending, confirmationBlock, confirmationTimestamp)
138
+ val (confirmationBlock, confirmationTimestamp, pending) =
139
+ when (val position = tx.chainPosition) {
140
+ is ChainPosition .Unconfirmed -> Triple (null , null , true )
141
+ is ChainPosition .Confirmed ->
142
+ Triple (
143
+ ConfirmationBlock (position.confirmationBlockTime.blockId.height),
144
+ Timestamp (position.confirmationBlockTime.confirmationTime),
145
+ false
146
+ )
147
+ }
148
+ TxDetails (
149
+ tx.transaction,
150
+ txid,
151
+ sent.toSat(),
152
+ received.toSat(),
153
+ fee?.toSat() ? : 0uL ,
154
+ feeRate,
155
+ pending,
156
+ confirmationBlock,
157
+ confirmationTimestamp
158
+ )
144
159
}
145
160
}
146
161
@@ -156,10 +171,11 @@ class Wallet private constructor(
156
171
157
172
private fun fullScan () {
158
173
val fullScanRequest = wallet.startFullScan().build()
159
- val update: Update = currentBlockchainClient?.fullScan(
160
- fullScanRequest = fullScanRequest,
161
- stopGap = 20u ,
162
- ) ? : throw IllegalStateException (" Blockchain client not initialized" )
174
+ val update: Update =
175
+ currentBlockchainClient?.fullScan(
176
+ fullScanRequest = fullScanRequest,
177
+ stopGap = 20u ,
178
+ ) ? : throw IllegalStateException (" Blockchain client not initialized" )
163
179
wallet.applyUpdate(update)
164
180
wallet.persist(connection)
165
181
}
@@ -175,9 +191,10 @@ class Wallet private constructor(
175
191
} else {
176
192
Log .i(TAG , " Just a normal sync!" )
177
193
val syncRequest = wallet.startSyncWithRevealedSpks().build()
178
- val update = currentBlockchainClient?.sync(
179
- syncRequest = syncRequest,
180
- ) ? : throw IllegalStateException (" Blockchain client not initialized" )
194
+ val update =
195
+ currentBlockchainClient?.sync(
196
+ syncRequest = syncRequest,
197
+ ) ? : throw IllegalStateException (" Blockchain client not initialized" )
181
198
wallet.applyUpdate(update)
182
199
wallet.persist(connection)
183
200
}
@@ -188,7 +205,7 @@ class Wallet private constructor(
188
205
fun getNewAddress (): AddressInfo = wallet.revealNextAddress(KeychainKind .EXTERNAL )
189
206
190
207
fun getClientEndpoint (): String = currentBlockchainClient?.endpoint() ? : " No active client"
191
-
208
+
192
209
// fun setElectrumSettings(electrumSettings: ElectrumSettings) {
193
210
// when (electrumSettings) {
194
211
// ElectrumSettings.DEFAULT -> electrumServer.useDefaultElectrum()
@@ -204,42 +221,46 @@ class Wallet private constructor(
204
221
): Wallet {
205
222
val mnemonic = Mnemonic (WordCount .WORDS12 )
206
223
val bip32ExtendedRootKey = DescriptorSecretKey (newWalletConfig.network, mnemonic, null )
207
- val descriptor: Descriptor = createScriptAppropriateDescriptor(
208
- newWalletConfig.scriptType,
209
- bip32ExtendedRootKey,
210
- newWalletConfig.network,
211
- KeychainKind .EXTERNAL
212
- )
213
- val changeDescriptor: Descriptor = createScriptAppropriateDescriptor(
214
- newWalletConfig.scriptType,
215
- bip32ExtendedRootKey,
216
- newWalletConfig.network,
217
- KeychainKind .INTERNAL
218
- )
224
+ val descriptor: Descriptor =
225
+ createScriptAppropriateDescriptor(
226
+ newWalletConfig.scriptType,
227
+ bip32ExtendedRootKey,
228
+ newWalletConfig.network,
229
+ KeychainKind .EXTERNAL
230
+ )
231
+ val changeDescriptor: Descriptor =
232
+ createScriptAppropriateDescriptor(
233
+ newWalletConfig.scriptType,
234
+ bip32ExtendedRootKey,
235
+ newWalletConfig.network,
236
+ KeychainKind .INTERNAL
237
+ )
219
238
val walletId = UUID .randomUUID().toString()
220
239
val connection = Connection (" $internalAppFilesPath /wallet-${walletId.take(8 )} .sqlite3" ,)
221
240
222
241
// Create SingleWallet object for saving to datastore
223
- val newWalletForDatastore: SingleWallet = SingleWallet .newBuilder()
224
- .setId(walletId)
225
- .setName(newWalletConfig.name)
226
- .setNetwork(newWalletConfig.network.intoProto())
227
- .setScriptType(newWalletConfig.scriptType)
228
- .setDescriptor(descriptor.toStringWithSecret())
229
- .setChangeDescriptor(changeDescriptor.toStringWithSecret())
230
- .setRecoveryPhrase(mnemonic.toString())
231
- .build()
242
+ val newWalletForDatastore: SingleWallet =
243
+ SingleWallet .newBuilder()
244
+ .setId(walletId)
245
+ .setName(newWalletConfig.name)
246
+ .setNetwork(newWalletConfig.network.intoProto())
247
+ .setScriptType(newWalletConfig.scriptType)
248
+ .setDescriptor(descriptor.toStringWithSecret())
249
+ .setChangeDescriptor(changeDescriptor.toStringWithSecret())
250
+ .setRecoveryPhrase(mnemonic.toString())
251
+ .build()
232
252
233
253
// TODO: launch this correctly, not on the main thread
234
254
// Save the new wallet to the datastore
235
255
runBlocking { userPreferencesRepository.updateActiveWallets(newWalletForDatastore) }
236
256
237
- val bdkWallet = BdkWallet (
238
- descriptor = descriptor,
239
- changeDescriptor = changeDescriptor,
240
- network = newWalletConfig.network,
241
- connection = connection,
242
- )
257
+ val bdkWallet =
258
+ BdkWallet (
259
+ descriptor = descriptor,
260
+ changeDescriptor = changeDescriptor,
261
+ network = newWalletConfig.network,
262
+ connection = connection,
263
+ )
243
264
244
265
return Wallet (
245
266
wallet = bdkWallet,
@@ -260,11 +281,12 @@ class Wallet private constructor(
260
281
val descriptor = Descriptor (activeWallet.descriptor, activeWallet.network.intoDomain())
261
282
val changeDescriptor = Descriptor (activeWallet.changeDescriptor, activeWallet.network.intoDomain())
262
283
val connection = Connection (" $internalAppFilesPath /wallet-${activeWallet.id.take(8 )} .sqlite3" )
263
- val bdkWallet = BdkWallet .load(
264
- descriptor = descriptor,
265
- changeDescriptor = changeDescriptor,
266
- connection = connection,
267
- )
284
+ val bdkWallet =
285
+ BdkWallet .load(
286
+ descriptor = descriptor,
287
+ changeDescriptor = changeDescriptor,
288
+ connection = connection,
289
+ )
268
290
269
291
return Wallet (
270
292
wallet = bdkWallet,
@@ -284,42 +306,46 @@ class Wallet private constructor(
284
306
): Wallet {
285
307
val mnemonic = Mnemonic .fromString(recoverWalletConfig.recoveryPhrase)
286
308
val bip32ExtendedRootKey = DescriptorSecretKey (recoverWalletConfig.network, mnemonic, null )
287
- val descriptor: Descriptor = createScriptAppropriateDescriptor(
288
- recoverWalletConfig.scriptType,
289
- bip32ExtendedRootKey,
290
- recoverWalletConfig.network,
291
- KeychainKind .EXTERNAL
292
- )
293
- val changeDescriptor: Descriptor = createScriptAppropriateDescriptor(
294
- recoverWalletConfig.scriptType,
295
- bip32ExtendedRootKey,
296
- recoverWalletConfig.network,
297
- KeychainKind .INTERNAL
298
- )
309
+ val descriptor: Descriptor =
310
+ createScriptAppropriateDescriptor(
311
+ recoverWalletConfig.scriptType,
312
+ bip32ExtendedRootKey,
313
+ recoverWalletConfig.network,
314
+ KeychainKind .EXTERNAL
315
+ )
316
+ val changeDescriptor: Descriptor =
317
+ createScriptAppropriateDescriptor(
318
+ recoverWalletConfig.scriptType,
319
+ bip32ExtendedRootKey,
320
+ recoverWalletConfig.network,
321
+ KeychainKind .INTERNAL
322
+ )
299
323
val walletId = UUID .randomUUID().toString()
300
324
val connection = Connection (" $internalAppFilesPath /wallet-${walletId.take(8 )} .sqlite3" ,)
301
325
302
326
// Create SingleWallet object for saving to datastore
303
- val newWalletForDatastore: SingleWallet = SingleWallet .newBuilder()
304
- .setId(walletId)
305
- .setName(recoverWalletConfig.name)
306
- .setNetwork(recoverWalletConfig.network.intoProto())
307
- .setScriptType(recoverWalletConfig.scriptType)
308
- .setDescriptor(descriptor.toStringWithSecret())
309
- .setChangeDescriptor(changeDescriptor.toStringWithSecret())
310
- .setRecoveryPhrase(mnemonic.toString())
311
- .build()
327
+ val newWalletForDatastore: SingleWallet =
328
+ SingleWallet .newBuilder()
329
+ .setId(walletId)
330
+ .setName(recoverWalletConfig.name)
331
+ .setNetwork(recoverWalletConfig.network.intoProto())
332
+ .setScriptType(recoverWalletConfig.scriptType)
333
+ .setDescriptor(descriptor.toStringWithSecret())
334
+ .setChangeDescriptor(changeDescriptor.toStringWithSecret())
335
+ .setRecoveryPhrase(mnemonic.toString())
336
+ .build()
312
337
313
338
// TODO: launch this correctly, not on the main thread
314
339
// Save the new wallet to the datastore
315
340
runBlocking { userPreferencesRepository.updateActiveWallets(newWalletForDatastore) }
316
341
317
- val bdkWallet = BdkWallet (
318
- descriptor = descriptor,
319
- changeDescriptor = changeDescriptor,
320
- connection = connection,
321
- network = recoverWalletConfig.network,
322
- )
342
+ val bdkWallet =
343
+ BdkWallet (
344
+ descriptor = descriptor,
345
+ changeDescriptor = changeDescriptor,
346
+ connection = connection,
347
+ network = recoverWalletConfig.network,
348
+ )
323
349
324
350
return Wallet (
325
351
wallet = bdkWallet,
@@ -338,7 +364,7 @@ fun createScriptAppropriateDescriptor(
338
364
scriptType : ActiveWalletScriptType ,
339
365
bip32ExtendedRootKey : DescriptorSecretKey ,
340
366
network : Network ,
341
- keychain : KeychainKind
367
+ keychain : KeychainKind ,
342
368
): Descriptor {
343
369
return if (keychain == KeychainKind .EXTERNAL ) {
344
370
when (scriptType) {
0 commit comments