Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds screen to list usable channels #29

Merged
merged 3 commits into from Nov 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -45,6 +45,8 @@ class DispatchActivity : AppCompatActivity() {

serializedChannelMonitors = monitors.joinToString(separator = ",")

Log.i(TAG, "Successfully created/restored wallet with mnemonic ${OnchainWallet.recoveryPhrase()}")

start(
OnchainWallet.getLdkEntropy(),
latestBlockHeight.toInt(),
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/com/example/umlandowallet/Global.kt
Expand Up @@ -13,9 +13,9 @@ object Global {
val prefixScorer = "scorer"


val feerateFast = 5000 // estimate fee rate in BTC/kB
val feerateMedium = 5000 // estimate fee rate in BTC/kB
val feerateSlow = 5000 // estimate fee rate in BTC/kB
val feerateFast = 2000 // estimate fee rate in BTC/kB
val feerateMedium = 2000 // estimate fee rate in BTC/kB
val feerateSlow = 2000 // estimate fee rate in BTC/kB

var eventsTxBroadcast: Array<String> = arrayOf<String>()
var eventsPaymentSent: Array<String> = arrayOf<String>()
Expand Down
18 changes: 4 additions & 14 deletions app/src/main/java/com/example/umlandowallet/Start.kt
Expand Up @@ -71,12 +71,6 @@ fun start(
channelMonitorList.add(channelMonitorBytes)
}
channelMonitors = channelMonitorList.toTypedArray()

// val list = Global.chainMonitor!!.list_monitors()
// list.iterator().forEach { outPoint ->
// val monitor = // Retrieve channel monitor saved in step 4
// Global.chainMonitor!!.as_Watch().watch_channel(outPoint, monitor)
// }
}

// This is going to be the fee policy for __incoming__ channels. they are set upfront globally:
Expand Down Expand Up @@ -117,10 +111,6 @@ fun start(
)

Global.channelManager = Global.channelManagerConstructor!!.channel_manager
Global.channelManagerConstructor!!.chain_sync_completed(
ChannelManagerEventHandler,
scorer
)
Global.peerManager = Global.channelManagerConstructor!!.peer_manager
Global.nioPeerHandler = Global.channelManagerConstructor!!.nio_peer_handler
Global.router = Global.channelManagerConstructor!!.net_graph
Expand All @@ -139,13 +129,13 @@ fun start(
logger
)
Global.channelManager = Global.channelManagerConstructor!!.channel_manager
Global.peerManager = Global.channelManagerConstructor!!.peer_manager
Global.nioPeerHandler = Global.channelManagerConstructor!!.nio_peer_handler
Global.router = Global.channelManagerConstructor!!.net_graph
Global.channelManagerConstructor!!.chain_sync_completed(
ChannelManagerEventHandler,
scorer
)
Global.peerManager = Global.channelManagerConstructor!!.peer_manager
Global.nioPeerHandler = Global.channelManagerConstructor!!.nio_peer_handler
Global.router = Global.channelManagerConstructor!!.net_graph
}

// If you want to communicate from your computer to your emulator,
Expand Down Expand Up @@ -181,7 +171,7 @@ object LDKBroadcaster : BroadcasterInterface.BroadcasterInterfaceInterface {
val service = Service.create()

tx?.let {
GlobalScope.launch {
CoroutineScope(Dispatchers.IO).launch {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that's the better way to do it for sure.

val txid = service.broadcastTx(tx)
Log.i(LDKTAG, "We've broadcast a transaction with txid $txid")
}
Expand Down
Expand Up @@ -76,8 +76,8 @@ object OnchainWallet {
fun buildFundingTx(value: Long, script: ByteArray): ByteArray {
sync()
val scriptListUByte: List<UByte> = script.toUByteArray().asList()
val outputScript: Script = Script(scriptListUByte)
val (psbt, txDetails) = TxBuilder()
val outputScript = Script(scriptListUByte)
val (psbt, _) = TxBuilder()
.addRecipient(outputScript, value.toULong())
.feeRate(4.0F)
.finish(onchainWallet)
Expand Down
Expand Up @@ -29,14 +29,7 @@ interface Access {

companion object {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might be able to do without the create() method in the interface, and simply create an AccessImpl object directly at the call-site.

For example if you remove the companion object entirely, the one call to the AccessImpl is in WalletScreen and would become

onClick = {
    CoroutineScope(Dispatchers.IO).launch {
        // Access.create().sync()
        AccessImpl().sync()
    }
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or you could create the object above and simply reuse it every time you sync instead of creating a new one every time.

@Composable
fun WalletScreen() {
    val accessImpl = AccessImpl()
// ...
onClick = {
    CoroutineScope(Dispatchers.IO).launch {
        accessImpl.sync()
    }
}

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in c446025

fun create(): Access {
// Setup BDK Esplora client
val esploraURL: String = "http://10.0.2.2:3002"
val blockchainConfig =
BlockchainConfig.Esplora(EsploraConfig(esploraURL, null, 5u, 20u, null))

return AccessImpl(
blockchain = Blockchain(blockchainConfig),
)
return AccessImpl()
}
}
}
@@ -1,5 +1,7 @@
package com.example.umlandowallet.data.remote

import com.example.umlandowallet.ChannelManagerEventHandler
import com.example.umlandowallet.Global
import com.example.umlandowallet.data.*
import com.example.umlandowallet.toByteArray
import com.example.umlandowallet.toHex
Expand All @@ -9,10 +11,29 @@ import org.ldk.structs.ChannelManager
import org.ldk.structs.TwoTuple_usizeTransactionZ

class AccessImpl(
private val blockchain: Blockchain,
) : Access {
override suspend fun sync() {
val currentHeight = blockchain.getHeight()
this.syncWallet(OnchainWallet)

val relevantTxIdsFromChannelManager: Array<ByteArray> =
Global.channelManager!!.as_Confirm()._relevant_txids
val relevantTxIdsFromChainMonitor: Array<ByteArray> =
Global.chainMonitor!!.as_Confirm()._relevant_txids

val relevantTxIds: Array<ByteArray> =
relevantTxIdsFromChannelManager + relevantTxIdsFromChainMonitor

this.syncTransactionConfirmed(relevantTxIds, Global.channelManager!!, Global.chainMonitor!!)
this.syncTransactionsUnconfirmed(
relevantTxIds,
Global.channelManager!!,
Global.chainMonitor!!
)
this.syncBestBlockConnected(Global.channelManager!!, Global.chainMonitor!!)

Global.channelManagerConstructor!!.chain_sync_completed(
ChannelManagerEventHandler, Global.scorer!!
)
}

override suspend fun syncWallet(onchainWallet: OnchainWallet) {
Expand Down Expand Up @@ -48,18 +69,17 @@ class AccessImpl(
if (txStatus.confirmed) {
val txHex = service.getTxHex(txId)
val tx = service.getTx(txId)
if (tx.status.block_height != null) {
val blockHeader = service.getHeader(tx.status.block_hash)
val merkleProof = service.getMerkleProof(txId)
if (tx.status.block_height == merkleProof.block_height) {
confirmedTxs.add(ConfirmedTx(
tx = txHex.toByteArray(),
block_height = tx.status.block_height,
block_header = blockHeader,
merkle_proof_pos = merkleProof.pos
)
val blockHeader = service.getHeader(tx.status.block_hash)
val merkleProof = service.getMerkleProof(txId)
if (tx.status.block_height == merkleProof.block_height) {
confirmedTxs.add(
ConfirmedTx(
tx = txHex.toByteArray(),
block_height = tx.status.block_height,
block_header = blockHeader,
merkle_proof_pos = merkleProof.pos
)
}
)
}
}
}
Expand All @@ -68,13 +88,23 @@ class AccessImpl(
for (cTx in confirmedTxs) {
channelManager.as_Confirm().transactions_confirmed(
cTx.block_header.toByteArray(),
arrayOf<TwoTuple_usizeTransactionZ>(TwoTuple_usizeTransactionZ.of(cTx.block_height.toLong(), cTx.tx)),
arrayOf<TwoTuple_usizeTransactionZ>(
TwoTuple_usizeTransactionZ.of(
cTx.block_height.toLong(),
cTx.tx
)
),
cTx.block_height
)

chainMonitor.as_Confirm().transactions_confirmed(
cTx.block_header.toByteArray(),
arrayOf<TwoTuple_usizeTransactionZ>(TwoTuple_usizeTransactionZ.of(cTx.block_height.toLong(), cTx.tx)),
arrayOf<TwoTuple_usizeTransactionZ>(
TwoTuple_usizeTransactionZ.of(
cTx.block_height.toLong(),
cTx.tx
)
),
cTx.block_height
)
}
Expand Down
Expand Up @@ -29,7 +29,7 @@ interface Service {

suspend fun getMerkleProof(txid: String) : MerkleProof

suspend fun connectPeer(pubkeyHex: String, hostname: String, port: Int) : Boolean
suspend fun connectPeer(pubkeyHex: String, hostname: String, port: Int)

companion object {
fun create() : Service {
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/com/example/umlandowallet/ui/Navigation.kt
Expand Up @@ -137,6 +137,23 @@ fun Navigation(
}
) { OpenChannelScreen() }

// List a channel
composable(
route = Screen.ListChannelsScreen.route,
enterTransition = {
slideIntoContainer(AnimatedContentScope.SlideDirection.Up, animationSpec = tween(animationDuration))
},
popEnterTransition = {
slideIntoContainer(AnimatedContentScope.SlideDirection.Up, animationSpec = tween(animationDuration))
},
exitTransition = {
slideOutOfContainer(AnimatedContentScope.SlideDirection.Down, animationSpec = tween(animationDuration))
},
popExitTransition = {
slideOutOfContainer(AnimatedContentScope.SlideDirection.Down, animationSpec = tween(animationDuration))
}
) { ListChannelsScreen() }

// Recovery phrase
composable(
route = Screen.RecoveryPhraseScreen.route,
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/com/example/umlandowallet/ui/Screen.kt
Expand Up @@ -7,5 +7,6 @@ sealed class Screen(val route: String) {
object ListPeersScreen : Screen("list_peers")
object ConnectPeerScreen : Screen("connect_peer")
object OpenChannelScreen : Screen("open_channel")
object ListChannelsScreen : Screen("list_channels")
object RecoveryPhraseScreen : Screen("recovery_phrase")
}
13 changes: 13 additions & 0 deletions app/src/main/java/com/example/umlandowallet/ui/SettingsScreen.kt
Expand Up @@ -101,6 +101,19 @@ fun SettingsScreen(navController: NavController) {
}
}
)

// List channels
SettingButton(
label = "List channels",
onClick = {
navController.navigate(Screen.ListChannelsScreen.route) {
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route)
}
launchSingleTop = true
}
}
)
Text(
text = "Onchain Wallet",
fontSize = 18.sp,
Expand Down
20 changes: 3 additions & 17 deletions app/src/main/java/com/example/umlandowallet/ui/WalletScreen.kt
Expand Up @@ -21,6 +21,8 @@ import kotlinx.coroutines.launch

@Composable
fun WalletScreen() {
val accessImpl = AccessImpl()

Column(
modifier = Modifier
.padding(top = 48.dp)
Expand All @@ -47,24 +49,8 @@ fun WalletScreen() {
)
Button(
onClick = {
val relevantTxIdsFromChannelManager: Array<ByteArray> = Global.channelManager!!.as_Confirm()._relevant_txids
val relevantTxIdsFromChainMonitor: Array<ByteArray> = Global.chainMonitor!!.as_Confirm()._relevant_txids

val relevantTxIds: Array<ByteArray> = relevantTxIdsFromChannelManager + relevantTxIdsFromChainMonitor

CoroutineScope(Dispatchers.IO).launch {
val access = Access.create()

// Sync BDK wallet
access.syncWallet(OnchainWallet)

// Sync LDK/Lightning
access.syncTransactionsUnconfirmed(relevantTxIds, Global.channelManager!!, Global.chainMonitor!!)
access.syncTransactionConfirmed(relevantTxIds, Global.channelManager!!, Global.chainMonitor!!)
access.syncBestBlockConnected(Global.channelManager!!, Global.chainMonitor!!)

Global.channelManagerConstructor!!.chain_sync_completed(
ChannelManagerEventHandler, Global.scorer!!)
accessImpl.sync()
}

Log.i(LDKTAG, "Wallet synced")
Expand Down
Expand Up @@ -8,7 +8,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.umlandowallet.data.remote.Access
import com.example.umlandowallet.data.remote.Service
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

Expand Down Expand Up @@ -62,17 +65,10 @@ fun ConnectPeerScreen() {
)
Button(
onClick = {
// val pubKey = pubKey
val host = "10.0.2.2"
// val port = port

GlobalScope.launch {
val hasConnected = service.connectPeer(pubKey, host, port.toInt())
if(hasConnected) {
setConnectPeerStatus("Successfully connected to peer")
} else {
setConnectPeerStatus("Failed to connect")
}
CoroutineScope(Dispatchers.IO).launch {
service.connectPeer(pubKey, host, port.toInt())
}
},
modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp),
Expand Down