mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-19 05:43:51 +01:00
Added DLC GUI stuff to a new package in the existing GUI and made a new tab for DLCs (#1590)
Co-authored-by: Ben Carman <benthecarman@live.com>
This commit is contained in:
parent
9237074510
commit
a1d17ab662
@ -2,6 +2,7 @@ package org.bitcoins.gui
|
||||
|
||||
import javafx.event.{ActionEvent, EventHandler}
|
||||
import javafx.scene.image.Image
|
||||
import org.bitcoins.gui.dlc.DLCPane
|
||||
import org.bitcoins.gui.settings.SettingsPane
|
||||
import scalafx.application.{JFXApp, Platform}
|
||||
import scalafx.beans.property.StringProperty
|
||||
@ -80,6 +81,8 @@ object WalletGUI extends JFXApp {
|
||||
bottom = statusLabel
|
||||
}
|
||||
|
||||
private val dlcPane = new DLCPane(glassPane)
|
||||
|
||||
private val settingsPane = new SettingsPane
|
||||
|
||||
private val tabPane: TabPane = new TabPane {
|
||||
@ -89,12 +92,17 @@ object WalletGUI extends JFXApp {
|
||||
content = borderPane
|
||||
}
|
||||
|
||||
val dlcTab: Tab = new Tab {
|
||||
text = "DLC"
|
||||
content = dlcPane.borderPane
|
||||
}
|
||||
|
||||
val settingsTab: Tab = new Tab {
|
||||
text = "Settings"
|
||||
content = settingsPane.view
|
||||
}
|
||||
|
||||
tabs = Seq(walletTab, settingsTab)
|
||||
tabs = Seq(walletTab, dlcTab, settingsTab)
|
||||
|
||||
tabClosingPolicy = TabClosingPolicy.Unavailable
|
||||
}
|
||||
|
178
app/gui/src/main/scala/org/bitcoins/gui/dlc/DLCPane.scala
Normal file
178
app/gui/src/main/scala/org/bitcoins/gui/dlc/DLCPane.scala
Normal file
@ -0,0 +1,178 @@
|
||||
package org.bitcoins.gui.dlc
|
||||
|
||||
import javafx.event.{ActionEvent, EventHandler}
|
||||
import org.bitcoins.gui.{GlobalData, TaskRunner}
|
||||
import scalafx.geometry.{Insets, Pos}
|
||||
import scalafx.scene.control._
|
||||
import scalafx.scene.layout._
|
||||
|
||||
class DLCPane(glassPane: VBox) {
|
||||
|
||||
private val statusLabel = new Label {
|
||||
maxWidth = Double.MaxValue
|
||||
padding = Insets(0, 10, 10, 10)
|
||||
text <== GlobalData.statusText
|
||||
}
|
||||
|
||||
private val resultArea = new TextArea {
|
||||
prefHeight = 750
|
||||
prefWidth = 800
|
||||
editable = false
|
||||
text = "Click on Offer or Accept to begin."
|
||||
wrapText = true
|
||||
}
|
||||
|
||||
private val demoOracleArea = new TextArea {
|
||||
prefHeight = 700
|
||||
prefWidth = 400
|
||||
editable = false
|
||||
text =
|
||||
"Click on Init Demo Oracle to generate example oracle and contract information"
|
||||
wrapText = true
|
||||
}
|
||||
|
||||
private val numOutcomesTF = new TextField {
|
||||
promptText = "Number of Outcomes"
|
||||
}
|
||||
|
||||
private val model =
|
||||
new DLCPaneModel(resultArea, demoOracleArea, numOutcomesTF)
|
||||
|
||||
private val demoOracleButton = new Button {
|
||||
text = "Init Demo Oracle"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onInitOracle()
|
||||
}
|
||||
}
|
||||
|
||||
private val oracleButtonHBox = new HBox {
|
||||
children = Seq(numOutcomesTF, demoOracleButton)
|
||||
spacing = 15
|
||||
}
|
||||
|
||||
private val demoOracleVBox = new VBox {
|
||||
children = Seq(demoOracleArea, oracleButtonHBox)
|
||||
spacing = 15
|
||||
}
|
||||
|
||||
private val offerButton = new Button {
|
||||
text = "Offer"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onOffer()
|
||||
}
|
||||
}
|
||||
|
||||
private val acceptButton = new Button {
|
||||
text = "Accept"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onAccept()
|
||||
}
|
||||
}
|
||||
|
||||
private val signButton = new Button {
|
||||
text = "Sign"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onSign()
|
||||
}
|
||||
}
|
||||
|
||||
private val addSigsButton = new Button {
|
||||
text = "Add Sigs"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onAddSigs()
|
||||
}
|
||||
}
|
||||
|
||||
private val getFundingButton = new Button {
|
||||
text = "Get Funding Tx"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onGetFunding()
|
||||
}
|
||||
}
|
||||
|
||||
private val initCloseButton = new Button {
|
||||
text = "Init Close"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onInitClose()
|
||||
}
|
||||
}
|
||||
|
||||
private val acceptCloseButton = new Button {
|
||||
text = "Accept Close"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onAcceptClose()
|
||||
}
|
||||
}
|
||||
|
||||
private val refundButton = new Button {
|
||||
text = "Refund"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onRefund()
|
||||
}
|
||||
}
|
||||
|
||||
private val forceCloseButton = new Button {
|
||||
text = "Force Close"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onForceClose()
|
||||
}
|
||||
}
|
||||
|
||||
private val punishButton = new Button {
|
||||
text = "Punish"
|
||||
onAction = new EventHandler[ActionEvent] {
|
||||
override def handle(event: ActionEvent): Unit = model.onPunish()
|
||||
}
|
||||
}
|
||||
|
||||
private val initButtonBar = new ButtonBar {
|
||||
buttons = Seq(offerButton, signButton)
|
||||
}
|
||||
|
||||
private val acceptButtonBar = new ButtonBar {
|
||||
buttons = Seq(acceptButton, addSigsButton, getFundingButton)
|
||||
}
|
||||
|
||||
private val execButtonBar = new ButtonBar {
|
||||
buttons = Seq(initCloseButton,
|
||||
acceptCloseButton,
|
||||
refundButton,
|
||||
forceCloseButton,
|
||||
punishButton)
|
||||
}
|
||||
|
||||
private val spaceRegion = new Region()
|
||||
private val spaceRegion2 = new Region()
|
||||
|
||||
private val buttonSpacer = new GridPane {
|
||||
hgap = 10
|
||||
prefHeight = 50
|
||||
alignment = Pos.Center
|
||||
|
||||
add(initButtonBar, 0, 0)
|
||||
add(spaceRegion, 1, 0)
|
||||
add(acceptButtonBar, 2, 0)
|
||||
add(spaceRegion2, 3, 0)
|
||||
add(execButtonBar, 4, 0)
|
||||
}
|
||||
|
||||
private val textAreaHBox = new HBox {
|
||||
children = Seq(resultArea, demoOracleVBox)
|
||||
spacing = 10
|
||||
}
|
||||
|
||||
val borderPane: BorderPane = new BorderPane {
|
||||
top = buttonSpacer
|
||||
center = textAreaHBox
|
||||
bottom = statusLabel
|
||||
}
|
||||
|
||||
resultArea.prefWidth <== (borderPane.width * 2) / 3
|
||||
demoOracleVBox.prefWidth <== (borderPane.width / 3)
|
||||
|
||||
spaceRegion.prefWidth <== (borderPane.width - initButtonBar.width - acceptButtonBar.width - execButtonBar.width - 100) / 2
|
||||
spaceRegion2.prefWidth <== spaceRegion.prefWidth
|
||||
|
||||
private val taskRunner = new TaskRunner(buttonSpacer, glassPane)
|
||||
model.taskRunner = taskRunner
|
||||
}
|
127
app/gui/src/main/scala/org/bitcoins/gui/dlc/DLCPaneModel.scala
Normal file
127
app/gui/src/main/scala/org/bitcoins/gui/dlc/DLCPaneModel.scala
Normal file
@ -0,0 +1,127 @@
|
||||
package org.bitcoins.gui.dlc
|
||||
|
||||
import org.bitcoins.cli.{CliCommand, Config, ConsoleCli}
|
||||
import org.bitcoins.commons.jsonmodels.dlc.DLCMessage.OracleInfo
|
||||
import org.bitcoins.crypto.ECPrivateKey
|
||||
import org.bitcoins.gui.TaskRunner
|
||||
import org.bitcoins.gui.dlc.dialog._
|
||||
import scalafx.beans.property.ObjectProperty
|
||||
import scalafx.scene.control.{TextArea, TextField}
|
||||
import scalafx.stage.Window
|
||||
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
class DLCPaneModel(
|
||||
resultArea: TextArea,
|
||||
oracleInfoArea: TextArea,
|
||||
numOutcomesTF: TextField) {
|
||||
var taskRunner: TaskRunner = _
|
||||
|
||||
// Sadly, it is a Java "pattern" to pass null into
|
||||
// constructors to signal that you want some default
|
||||
val parentWindow: ObjectProperty[Window] =
|
||||
ObjectProperty[Window](null.asInstanceOf[Window])
|
||||
|
||||
def printDLCDialogResult[T <: CliCommand](
|
||||
caption: String,
|
||||
dialog: DLCDialog[T]): Unit = {
|
||||
val result = dialog.showAndWait(parentWindow.value)
|
||||
|
||||
result match {
|
||||
case Some(command) =>
|
||||
taskRunner.run(
|
||||
caption = caption,
|
||||
op = {
|
||||
ConsoleCli.exec(command, Config.empty) match {
|
||||
case Success(commandReturn) => resultArea.text = commandReturn
|
||||
case Failure(err) =>
|
||||
err.printStackTrace()
|
||||
resultArea.text = s"Error executing command:\n${err.getMessage}"
|
||||
}
|
||||
}
|
||||
)
|
||||
case None => ()
|
||||
}
|
||||
}
|
||||
|
||||
def onInitOracle(): Unit = {
|
||||
val numOutcomes = BigInt(numOutcomesTF.text()).toInt
|
||||
require(numOutcomes <= 10, "More than 10 outcomes not supported.")
|
||||
|
||||
val result = InitOracleDialog.showAndWait(parentWindow.value, numOutcomes)
|
||||
|
||||
result match {
|
||||
case Some((outcomes, contractInfo)) =>
|
||||
val builder = new StringBuilder()
|
||||
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
val pubKey = privKey.schnorrPublicKey
|
||||
val kValue = ECPrivateKey.freshPrivateKey
|
||||
val rValue = kValue.schnorrNonce
|
||||
val oracleInfo = OracleInfo(pubKey, rValue)
|
||||
|
||||
builder.append(
|
||||
s"Oracle Public Key: ${pubKey.hex}\nEvent R value: ${rValue.hex}\n")
|
||||
builder.append(s"Serialized Oracle Info: ${oracleInfo.hex}\n\n")
|
||||
|
||||
builder.append("Outcome hashes and amounts in order of entry:\n")
|
||||
contractInfo.foreach {
|
||||
case (hash, amt) => builder.append(s"${hash.hex} - ${amt.toLong}\n")
|
||||
}
|
||||
builder.append(s"\nSerialized Contract Info:\n${contractInfo.hex}\n\n")
|
||||
|
||||
builder.append("Outcomes and oracle sigs in order of entry:\n")
|
||||
outcomes.zip(contractInfo.keys).foreach {
|
||||
case (outcome, hash) =>
|
||||
val sig = privKey.schnorrSignWithNonce(hash.bytes, kValue)
|
||||
builder.append(s"$outcome - ${sig.hex}\n")
|
||||
}
|
||||
|
||||
GlobalDLCData.lastOracleInfo = oracleInfo.hex
|
||||
GlobalDLCData.lastContractInfo = contractInfo.hex
|
||||
|
||||
oracleInfoArea.text = builder.result()
|
||||
case None => ()
|
||||
}
|
||||
}
|
||||
|
||||
def onOffer(): Unit = {
|
||||
printDLCDialogResult("CreateDLCOffer", OfferDLCDialog)
|
||||
}
|
||||
|
||||
def onAccept(): Unit = {
|
||||
printDLCDialogResult("AcceptDLCOffer", AcceptDLCDialog)
|
||||
}
|
||||
|
||||
def onSign(): Unit = {
|
||||
printDLCDialogResult("SignDLC", SignDLCDialog)
|
||||
}
|
||||
|
||||
def onAddSigs(): Unit = {
|
||||
printDLCDialogResult("AddDLCSigs", AddSigsDLCDialog)
|
||||
}
|
||||
|
||||
def onGetFunding(): Unit = {
|
||||
printDLCDialogResult("GetDLCFundingTx", GetFundingDLCDialog)
|
||||
}
|
||||
|
||||
def onInitClose(): Unit = {
|
||||
printDLCDialogResult("InitDLCMutualClose", InitCloseDLCDialog)
|
||||
}
|
||||
|
||||
def onAcceptClose(): Unit = {
|
||||
printDLCDialogResult("AcceptDLCMutualClose", AcceptCloseDLCDialog)
|
||||
}
|
||||
|
||||
def onForceClose(): Unit = {
|
||||
printDLCDialogResult("ExecuteUnilateralDLC", ForceCloseDLCDialog)
|
||||
}
|
||||
|
||||
def onPunish(): Unit = {
|
||||
printDLCDialogResult("ExecuteDLCPunishment", PunishDLCDialog)
|
||||
}
|
||||
|
||||
def onRefund(): Unit = {
|
||||
printDLCDialogResult("ExecuteDLCRefund", RefundDLCDialog)
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package org.bitcoins.gui.dlc
|
||||
|
||||
object GlobalDLCData {
|
||||
var lastEventId: String = ""
|
||||
var lastOracleSig: String = ""
|
||||
var lastOracleInfo: String = ""
|
||||
var lastContractInfo: String = ""
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.cli.CliCommand.AcceptDLCOffer
|
||||
import org.bitcoins.commons.jsonmodels.dlc.DLCMessage.DLCOffer
|
||||
|
||||
object AcceptDLCDialog
|
||||
extends DLCDialog[AcceptDLCOffer](
|
||||
"Accept DLC Offer",
|
||||
"Enter DLC offer to accept",
|
||||
Vector(DLCDialog.dlcOfferStr -> DLCDialog.textArea())) {
|
||||
import DLCDialog._
|
||||
|
||||
override def constructFromInput(
|
||||
inputs: Map[String, String]): AcceptDLCOffer = {
|
||||
val offer = DLCOffer.fromJson(ujson.read(inputs(dlcOfferStr)))
|
||||
AcceptDLCOffer(offer, escaped = false)
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.cli.CliCommand.AddDLCSigs
|
||||
import org.bitcoins.commons.jsonmodels.dlc.DLCMessage.DLCSign
|
||||
|
||||
object AddSigsDLCDialog
|
||||
extends DLCDialog[AddDLCSigs](
|
||||
"Sign DLC",
|
||||
"Enter DLC signatures message",
|
||||
Vector(DLCDialog.dlcSigStr -> DLCDialog.textArea())) {
|
||||
|
||||
import DLCDialog._
|
||||
|
||||
override def constructFromInput(inputs: Map[String, String]): AddDLCSigs = {
|
||||
val sign = DLCSign.fromJson(ujson.read(inputs(dlcSigStr)))
|
||||
AddDLCSigs(sign)
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.cli.CliCommand
|
||||
import org.bitcoins.gui.dlc.GlobalDLCData
|
||||
import scalafx.Includes._
|
||||
import scalafx.application.Platform
|
||||
import scalafx.geometry.Insets
|
||||
import scalafx.scene.control._
|
||||
import scalafx.scene.layout.GridPane
|
||||
import scalafx.stage.Window
|
||||
|
||||
abstract class DLCDialog[T <: CliCommand](
|
||||
dialogTitle: String,
|
||||
header: String,
|
||||
fields: Vector[(String, TextInputControl)], // Vector instead of Map to keep order
|
||||
optionalFields: Vector[String] = Vector.empty) {
|
||||
private def readCachedValue(key: String, value: String): Unit = {
|
||||
fields
|
||||
.find(_._1 == key)
|
||||
.foreach(_._2.text = value)
|
||||
}
|
||||
|
||||
readCachedValue(DLCDialog.dlcEventIdStr, GlobalDLCData.lastEventId)
|
||||
readCachedValue(DLCDialog.dlcOracleSigStr, GlobalDLCData.lastOracleSig)
|
||||
readCachedValue(DLCDialog.oracleInfoStr, GlobalDLCData.lastOracleInfo)
|
||||
readCachedValue(DLCDialog.contractInfoStr, GlobalDLCData.lastContractInfo)
|
||||
|
||||
private def writeCachedValue(
|
||||
key: String,
|
||||
inputs: Vector[(String, String)],
|
||||
setter: String => Unit): Unit = {
|
||||
inputs
|
||||
.find(_._1 == key)
|
||||
.foreach(pair => setter(pair._2))
|
||||
}
|
||||
|
||||
def constructFromInput(inputs: Map[String, String]): T
|
||||
|
||||
def showAndWait(parentWindow: Window): Option[T] = {
|
||||
val dialog = new Dialog[Option[T]]() {
|
||||
initOwner(parentWindow)
|
||||
title = dialogTitle
|
||||
headerText = header
|
||||
}
|
||||
|
||||
dialog.dialogPane().buttonTypes = Seq(ButtonType.OK, ButtonType.Cancel)
|
||||
|
||||
dialog.dialogPane().content = new GridPane {
|
||||
hgap = 10
|
||||
vgap = 10
|
||||
padding = Insets(20, 100, 10, 10)
|
||||
|
||||
var nextRow: Int = 0
|
||||
def addRow(label: String, textField: TextInputControl): Unit = {
|
||||
add(new Label(label), 0, nextRow)
|
||||
add(textField, 1, nextRow)
|
||||
nextRow += 1
|
||||
}
|
||||
|
||||
fields.foreach {
|
||||
case (fieldStr, filedInput) => addRow(fieldStr, filedInput)
|
||||
}
|
||||
}
|
||||
|
||||
// Enable/Disable OK button depending on whether all data was entered.
|
||||
val okButton = dialog.dialogPane().lookupButton(ButtonType.OK)
|
||||
val requiredFields =
|
||||
fields.filterNot(field => optionalFields.contains(field._1))
|
||||
// Simple validation that sufficient data was entered
|
||||
okButton.disable <== requiredFields
|
||||
.map(_._2.text.isEmpty)
|
||||
.reduce(_ || _)
|
||||
|
||||
// Request focus on the first field by default.
|
||||
Platform.runLater(fields.head._2.requestFocus())
|
||||
|
||||
// When the OK button is clicked, convert the result to a T.
|
||||
dialog.resultConverter = dialogButton =>
|
||||
if (dialogButton == ButtonType.OK) {
|
||||
val inputs = fields.map { case (key, input) => (key, input.text()) }
|
||||
|
||||
writeCachedValue(DLCDialog.dlcEventIdStr,
|
||||
inputs,
|
||||
GlobalDLCData.lastEventId = _)
|
||||
writeCachedValue(DLCDialog.dlcOracleSigStr,
|
||||
inputs,
|
||||
GlobalDLCData.lastOracleSig = _)
|
||||
writeCachedValue(DLCDialog.oracleInfoStr,
|
||||
inputs,
|
||||
GlobalDLCData.lastOracleInfo = _)
|
||||
writeCachedValue(DLCDialog.contractInfoStr,
|
||||
inputs,
|
||||
GlobalDLCData.lastContractInfo = _)
|
||||
|
||||
Some(constructFromInput(inputs.toMap))
|
||||
} else None
|
||||
|
||||
val result = dialog.showAndWait()
|
||||
|
||||
result match {
|
||||
case Some(someT: Some[T]) => someT
|
||||
case Some(_) | None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DLCDialog {
|
||||
|
||||
def textArea(): TextArea = {
|
||||
new TextArea {
|
||||
wrapText = true
|
||||
}
|
||||
}
|
||||
|
||||
val oracleInfoStr = "Oracle Info"
|
||||
val contractInfoStr = "Contract Info"
|
||||
val collateralStr = "Collateral"
|
||||
val feeRateStr = "Fee Rate"
|
||||
val locktimeStr = "Locktime"
|
||||
val refundLocktimeStr = "Refund Locktime"
|
||||
|
||||
val allOfferFields: Map[String, String] = Map[String, String](
|
||||
oracleInfoStr -> "",
|
||||
contractInfoStr -> "",
|
||||
collateralStr -> "Satoshis",
|
||||
feeRateStr -> "sats/vbyte (optional)",
|
||||
locktimeStr -> "Block or unix time",
|
||||
refundLocktimeStr -> "Block or unix time"
|
||||
)
|
||||
|
||||
def constructOfferFields(): Vector[(String, TextField)] =
|
||||
allOfferFields.map {
|
||||
case (label, hint) =>
|
||||
(label, new TextField() {
|
||||
promptText = hint
|
||||
})
|
||||
}.toVector
|
||||
|
||||
val dlcOfferStr = "DLC Offer"
|
||||
|
||||
val dlcAcceptStr = "DLC Accept Message"
|
||||
|
||||
val dlcSigStr = "DLC Signatures"
|
||||
|
||||
val dlcEventIdStr = "Event ID"
|
||||
|
||||
val dlcOracleSigStr = "Oracle Signature"
|
||||
|
||||
val dlcMutualCloseOfferStr = "Mutual Close Offer"
|
||||
|
||||
val dlcForceCloseTxStr = "Force Close Transaction"
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.cli.CliCommand.GetDLCFundingTx
|
||||
import org.bitcoins.crypto.Sha256DigestBE
|
||||
import scalafx.scene.control.TextField
|
||||
|
||||
object GetFundingDLCDialog
|
||||
extends DLCDialog[GetDLCFundingTx](
|
||||
"DLC Funding Transaction",
|
||||
"Enter DLC event ID",
|
||||
Vector(DLCDialog.dlcEventIdStr -> new TextField())) {
|
||||
import DLCDialog._
|
||||
|
||||
override def constructFromInput(
|
||||
inputs: Map[String, String]): GetDLCFundingTx = {
|
||||
val eventId = Sha256DigestBE(inputs(dlcEventIdStr))
|
||||
GetDLCFundingTx(eventId)
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.cli.CliCommand.CreateDLCOffer
|
||||
import org.bitcoins.commons.jsonmodels.dlc.DLCMessage
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
|
||||
object OfferDLCDialog
|
||||
extends DLCDialog[CreateDLCOffer]("Create DLC Offer",
|
||||
"Enter DLC details",
|
||||
DLCDialog.constructOfferFields(),
|
||||
Vector(DLCDialog.feeRateStr)) {
|
||||
import DLCDialog._
|
||||
|
||||
override def constructFromInput(
|
||||
inputs: Map[String, String]): CreateDLCOffer = {
|
||||
val feeRate = if (inputs(feeRateStr).isEmpty) {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
SatoshisPerVirtualByte(
|
||||
Satoshis(BigInt(inputs(feeRateStr)))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
CreateDLCOffer(
|
||||
oracleInfo = DLCMessage.OracleInfo.fromHex(inputs(oracleInfoStr)),
|
||||
contractInfo = DLCMessage.ContractInfo.fromHex(inputs(contractInfoStr)),
|
||||
collateral = Satoshis(BigInt(inputs(collateralStr))),
|
||||
feeRateOpt = feeRate,
|
||||
locktime = UInt32(BigInt(inputs(locktimeStr))),
|
||||
refundLT = UInt32(BigInt(inputs(refundLocktimeStr))),
|
||||
escaped = false
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.cli.CliCommand.ExecuteDLCRefund
|
||||
import org.bitcoins.crypto.Sha256DigestBE
|
||||
import scalafx.scene.control.TextField
|
||||
|
||||
object RefundDLCDialog
|
||||
extends DLCDialog[ExecuteDLCRefund](
|
||||
"DLC Refund",
|
||||
"Enter DLC event ID",
|
||||
Vector(DLCDialog.dlcEventIdStr -> new TextField())) {
|
||||
import DLCDialog._
|
||||
|
||||
override def constructFromInput(
|
||||
inputs: Map[String, String]): ExecuteDLCRefund = {
|
||||
val eventId = Sha256DigestBE(inputs(dlcEventIdStr))
|
||||
ExecuteDLCRefund(eventId, noBroadcast = false)
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.cli.CliCommand.SignDLC
|
||||
import org.bitcoins.commons.jsonmodels.dlc.DLCMessage.DLCAccept
|
||||
import org.bitcoins.gui.dlc.GlobalDLCData
|
||||
|
||||
object SignDLCDialog
|
||||
extends DLCDialog[SignDLC](
|
||||
"Sign DLC",
|
||||
"Enter DLC accept message",
|
||||
Vector(DLCDialog.dlcAcceptStr -> DLCDialog.textArea())) {
|
||||
import DLCDialog._
|
||||
|
||||
override def constructFromInput(inputs: Map[String, String]): SignDLC = {
|
||||
val accept = DLCAccept.fromJson(ujson.read(inputs(dlcAcceptStr)))
|
||||
GlobalDLCData.lastEventId = accept.eventId.hex
|
||||
SignDLC(accept, escaped = false)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user