Populate Sign GUI when choosing a file (#3243)

* Populate Sign GUI when choosing a file

* Add error messages, add for numeric
This commit is contained in:
benthecarman 2021-06-11 13:14:18 -07:00 committed by GitHub
parent 5caf7ee38b
commit 65f096f65a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 178 additions and 51 deletions

View File

@ -260,7 +260,7 @@ class CreateDLCOfferDialog extends Logging {
descriptor.numDigits,
descriptor.outcomeValueFunc,
totalCollateral,
RoundingIntervals.noRounding)
descriptor.roundingIntervals)
()
}
}

View File

@ -1,9 +1,11 @@
package org.bitcoins.gui.dlc.dialog
import grizzled.slf4j.Logging
import org.bitcoins.cli.CliCommand._
import org.bitcoins.core.protocol.dlc.models.{DLCStatus, EnumContractDescriptor}
import org.bitcoins.core.protocol.dlc.models._
import org.bitcoins.core.protocol.tlv._
import org.bitcoins.gui.GlobalData
import org.bitcoins.gui.dlc.DLCPlotUtil
import org.bitcoins.gui.dlc.GlobalDLCData.dlcs
import org.bitcoins.gui.util.GUIUtil
import scalafx.Includes._
@ -12,10 +14,12 @@ import scalafx.scene.control._
import scalafx.scene.layout._
import scalafx.stage.Window
import java.io.File
import java.nio.file.Files
import scala.collection._
import scala.util.{Failure, Success, Try}
object SignDLCDialog {
object SignDLCDialog extends Logging {
def showAndWait(parentWindow: Window): Option[SignDLCCliCommand] = {
val dialog = new Dialog[Option[SignDLCCliCommand]]() {
@ -33,26 +37,62 @@ object SignDLCDialog {
minWidth = 300
}
val acceptTFHBox = new HBox() {
spacing = 5
children = Vector(new Label("DLC Accept"), acceptTLVTF)
}
val separatorHBox = new HBox() {
alignment = Pos.Center
alignmentInParent = Pos.Center
spacing = 5
minWidth <== acceptTFHBox.width
children = Vector(new Separator(), new Label("or"), new Separator())
}
val errorLabel = new Label("") {
style = "-fx-text-fill: red"
}
val fromFileHBox = new HBox() {
spacing = 5
children = Vector(new Label("DLC Accept File"))
}
val vbox = new VBox() {
margin = Insets(10)
spacing = 10
children = Vector(acceptTFHBox, separatorHBox, fromFileHBox)
}
var nextRow: Int = 2
val gridPane = new GridPane {
alignment = Pos.Center
padding = Insets(top = 10, right = 10, bottom = 10, left = 10)
hgap = 5
vgap = 5
add(new Label("DLC Accept"), 0, 0)
add(acceptTLVTF, 1, 0)
}
def showDLCTerms(status: DLCStatus): Unit = {
val descriptor = status.contractInfo.contractDescriptor.toTLV match {
case v0: ContractDescriptorV0TLV =>
EnumContractDescriptor
.fromTLV(v0)
.flip(status.totalCollateral.satoshis)
case _: ContractDescriptorV1TLV =>
throw new RuntimeException("This is impossible.")
val destinationChooser = DLCDialog.fileChooserButton(
open = false,
{ file =>
DLCDialog.signDestDLCFile = Some(file)
DLCDialog.signDestFileChosenLabel.text = file.toString
})
val destChooserHBox = new HBox() {
spacing = 5
children = Vector(destinationChooser, DLCDialog.signDestFileChosenLabel)
}
def showDLCTerms(status: DLCStatus, isFromFile: Boolean): Unit = {
vbox.children.clear()
if (isFromFile) {
vbox.children.add(fromFileHBox)
} else {
vbox.children.addAll(acceptTFHBox)
}
vbox.children.add(gridPane)
val (oracleKey, eventId) = status.contractInfo.oracleInfo.toTLV match {
case OracleInfoV0TLV(announcement) =>
@ -66,6 +106,7 @@ object SignDLCDialog {
new TextField() {
text = eventId
editable = false
minWidth = 300
},
1,
nextRow
@ -101,24 +142,54 @@ object SignDLCDialog {
nextRow)
nextRow += 1
gridPane.add(new Label("Potential Outcome"), 0, nextRow)
gridPane.add(new Label("Payouts"), 1, nextRow)
nextRow += 1
status.contractInfo.contractDescriptor.toTLV match {
case v0: ContractDescriptorV0TLV =>
gridPane.add(new Label("Potential Outcome"), 0, nextRow)
gridPane.add(new Label("Payouts"), 1, nextRow)
nextRow += 1
descriptor.foreach { case (str, satoshis) =>
gridPane.add(new TextField() {
text = str.outcome
editable = false
},
0,
nextRow)
gridPane.add(new TextField() {
text = satoshis.toString
editable = false
},
1,
nextRow)
nextRow += 1
val descriptor = EnumContractDescriptor.fromTLV(v0)
descriptor.foreach { case (str, satoshis) =>
gridPane.add(new TextField() {
text = str.outcome
editable = false
},
0,
nextRow)
gridPane.add(new TextField() {
text = satoshis.toString
editable = false
},
1,
nextRow)
nextRow += 1
}
case v1: ContractDescriptorV1TLV =>
val previewGraphButton: Button = new Button("Preview Graph") {
onAction = _ => {
val descriptor = NumericContractDescriptor.fromTLV(v1)
val payoutCurve = if (status.isInitiator) {
descriptor.outcomeValueFunc
} else {
descriptor
.flip(status.totalCollateral.satoshis)
.outcomeValueFunc
}
DLCPlotUtil.plotCETs(base = 2,
descriptor.numDigits,
payoutCurve,
status.contractInfo.totalCollateral,
descriptor.roundingIntervals,
None)
()
}
}
gridPane.add(new Label("Payout Function"), 0, nextRow)
gridPane.add(previewGraphButton, 1, nextRow)
nextRow += 1
}
gridPane.add(new Label("Fee Rate"), 0, nextRow)
@ -139,6 +210,12 @@ object SignDLCDialog {
1,
nextRow)
nextRow += 1
if (isFromFile) {
gridPane.add(new Label(DLCDialog.dlcSignFileDestStr), 0, nextRow)
gridPane.add(destChooserHBox, 1, nextRow)
nextRow += 1
}
}
acceptTLVTF.onKeyTyped = _ => {
@ -148,37 +225,87 @@ object SignDLCDialog {
acceptTLVTF.text.value)) match {
case Failure(_) => ()
case Success(lnMessage) =>
val tempId = lnMessage.tlv.tempContractId
dlcs.find(_.tempContractId == tempId) match {
case Some(dlc) =>
dlc.contractInfo.contractDescriptor.toTLV match {
case _: ContractDescriptorV0TLV =>
dlcDetailsShown = true
showDLCTerms(dlc)
dialog.dialogPane().getScene.getWindow.sizeToScene()
case _: ContractDescriptorV1TLV =>
() // todo not supported
}
case None => ()
}
showDetails(lnMessage, isFromFile = false)
}
}
}
def showDetails(
lnMessage: LnMessage[DLCAcceptTLV],
isFromFile: Boolean): Unit = {
val tempId = lnMessage.tlv.tempContractId
dlcs.find(_.tempContractId == tempId) match {
case Some(dlc) =>
dlcDetailsShown = true
showDLCTerms(dlc, isFromFile)
case None =>
val errMsg =
s"DLCAccept is not associated with a DLC in our DLC Table View"
logger.error(errMsg)
errorLabel.text = errMsg
vbox.children.add(errorLabel)
}
dialog.dialogPane().getScene.getWindow.sizeToScene()
}
def handleFileChosen(file: File): Unit = {
val acceptMessageT = Try {
val hex = Files.readAllLines(file.toPath).get(0)
LnMessageFactory(DLCAcceptTLV).fromHex(hex)
}
acceptMessageT match {
case Failure(_) =>
val errMsg = "Error, file chosen as not a valid DLCAccept message"
logger.error(errMsg)
errorLabel.text = errMsg
vbox.children.add(errorLabel)
dialog.dialogPane().getScene.getWindow.sizeToScene()
case Success(acceptMessage) =>
showDetails(acceptMessage, isFromFile = true)
}
()
}
val fileChooser = DLCDialog.fileChooserButton(
open = true,
{ file =>
DLCDialog.acceptDLCFile = Some(file)
DLCDialog.acceptFileChosenLabel.text = file.toString
handleFileChosen(file)
})
fromFileHBox.children.addAll(fileChooser, DLCDialog.acceptFileChosenLabel)
dialog.dialogPane().content = new ScrollPane {
content = new VBox(gridPane)
margin = Insets(10)
content = vbox
}
// When the OK button is clicked, convert the result to a SignDLC.
dialog.resultConverter = dialogButton =>
if (dialogButton == ButtonType.OK) {
dialog.resultConverter = dialogButton => {
val res = if (dialogButton == ButtonType.OK) {
DLCDialog.acceptDLCFile match {
case Some(file) =>
val destOpt = DLCDialog.signDestDLCFile.map(_.toPath)
Some(SignDLCFromFile(file.toPath, destOpt))
case None =>
val acceptHex = acceptTLVTF.text.value
val accept = LnMessageFactory(DLCAcceptTLV).fromHex(acceptHex)
val acceptHex = acceptTLVTF.text.value
val accept = LnMessageFactory(DLCAcceptTLV).fromHex(acceptHex)
Some(SignDLC(accept))
Some(SignDLC(accept))
}
} else None
// reset
DLCDialog.acceptDLCFile = None
DLCDialog.acceptFileChosenLabel.text = ""
DLCDialog.signDestDLCFile = None
DLCDialog.signDestFileChosenLabel.text = ""
res
}
val result = dialog.showAndWait()
result match {