Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
f05ef22
initial commit for GUI
joemphilips Sep 18, 2020
79c5996
include ResultUtils and TaskUtils to the solution
joemphilips Sep 19, 2020
cde85c2
Refactor Oracle to handle async op
joemphilips Sep 19, 2020
afa79f5
Update Oracle view
joemphilips Sep 20, 2020
23c3325
add event view
joemphilips Sep 20, 2020
4149565
nit: update event
joemphilips Sep 21, 2020
0b216e0
Seperate EventInEdit into another module
joemphilips Sep 22, 2020
340f077
nit: update formatting
joemphilips Sep 23, 2020
5046c27
Fix miner bug in getOracle
joemphilips Sep 23, 2020
080f4cb
Add Hot reloading feature
joemphilips Sep 27, 2020
17dcfad
remove change of moving some classes into seperate files
joemphilips Sep 29, 2020
d56c560
Use TabControl instead of button for event button
joemphilips Sep 29, 2020
a07dc1e
bubbleup new dlc message from event module to Oracle
joemphilips Sep 30, 2020
6136ad5
Pass NewOfferMetadata into DLC module
joemphilips Sep 30, 2020
a810f8d
update GUI
joemphilips Sep 30, 2020
4fdb12f
update
joemphilips Oct 3, 2020
4447ece
cli: add DiscretePayoffs.TryParse
joemphilips Oct 3, 2020
f87ac15
update GUI
joemphilips Oct 3, 2020
296e547
Update GUI
joemphilips Oct 4, 2020
0235483
update GUI
joemphilips Oct 5, 2020
9c0c7fe
refactor oracle import/generation
joemphilips Oct 5, 2020
eb3a7be
udpate event import
joemphilips Oct 5, 2020
078f1e3
update
joemphilips Oct 5, 2020
aa60caf
Confim Offer is working correctly in GUI
joemphilips Oct 6, 2020
160e84c
nit: move dlc valiation into separate file
joemphilips Oct 6, 2020
95e3d97
WIP: trying to create DLCOffer module
joemphilips Oct 6, 2020
ee8554e
move some primitives from NDLC.CLI to NDLC
joemphilips Oct 7, 2020
c8c95e1
update gui
joemphilips Oct 7, 2020
d1535e6
Refactor DLCAccept.State to have discrete view
joemphilips Oct 7, 2020
daac6dd
update DLCAccept module
joemphilips Oct 7, 2020
ce8f636
Refactor DLCAccept.State to have discrete view
joemphilips Oct 8, 2020
0605e66
Finish DLCSign module
joemphilips Oct 8, 2020
ce95ccb
Cli: Add ListDLCCommand
joemphilips Oct 9, 2020
b8414bd
add DLCList module
joemphilips Oct 9, 2020
89fb6f0
Refactor ListDLCCommand to show more pretty output
joemphilips Oct 9, 2020
989df42
Update GUI
joemphilips Oct 9, 2020
1273f95
update GUI
joemphilips Oct 9, 2020
e462765
update GUI a bit
joemphilips Oct 10, 2020
e3abe06
GUI: enable to copy intermediate messages from GUI
joemphilips Oct 10, 2020
fd160e9
add feature for attesting Event
joemphilips Oct 10, 2020
35db1dc
update ListDLCCommand
joemphilips Oct 10, 2020
f88186e
GUI: include DLCState into DLCList.GotoInfo
joemphilips Oct 11, 2020
dad0f04
GUI: Separate Start And CheckSig module
joemphilips Oct 11, 2020
b5c7aca
add feature to add attestation
joemphilips Oct 11, 2020
7422afd
Show CET execution result for DLC
joemphilips Oct 12, 2020
fe07603
Remove DLCListCommand
joemphilips Oct 30, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions NDLC.CLI/DLC/OfferDLCCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ protected override async Task InvokeAsyncBase(InvocationContext context)
var payoffsStr = context.ParseResult.CommandResult.GetArgumentValueOrDefault<List<string>>("payoff");
if (payoffsStr is null || payoffsStr.Count == 0)
throw new CommandOptionRequiredException("payoff");
var payoffs = CreatePayoffs(payoffsStr);
if (!DiscretePayoffs.TryParse(payoffsStr, out var payoffs) || payoffs is null)
{
throw new CommandException("payoff", "The payoff can't be parsed");
}
FixCasing(evt, payoffs);
var builder = new DLCTransactionBuilder(true, null, null, null, Network);

Expand All @@ -75,18 +78,6 @@ protected override async Task InvokeAsyncBase(InvocationContext context)
context.Console.Out.Write($"Offer created, you now need to setup the DLC sending {collateral} BTC to yourself. For more information, run `dlc show \"{name}\"`.");
}

private DiscretePayoffs CreatePayoffs(List<string> payoffs)
{
var result = new DiscretePayoffs();
foreach (var payoff in payoffs)
{
if (!DiscretePayoff.TryParse(payoff, out var o) || o is null)
throw new CommandException("payoff", "The payoff can't be parsed");
result.Add(o);
}
return result;
}

/// <summary>
/// Fix case mistakes
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions NDLC.CLI/DLC/ReviewDLCCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static Command CreateCommand()
protected override async Task InvokeAsyncBase(InvocationContext context)
{
var offer = context.GetOffer(Repository.JsonSettings);
Console.WriteLine($" Offer is {offer}");
if (offer.OracleInfo is null)
throw new CommandException("offer", "Missing oracleInfo");
if (offer.Timeouts is null)
Expand Down
3 changes: 3 additions & 0 deletions NDLC.CLI/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ public static PSBT ParsePSBT(this InvocationContext ctx, string argName, Network
throw new CommandException(argName, "Invalid PSBT");
return psbt;
}

public static string ToString(ECXOnlyPubKey pubKey)
{
var buf = new byte[32];
pubKey.WriteToSpan(buf);
return Encoders.Hex.EncodeData(buf);
}

public static string ToBase58(ECXOnlyPubKey pubKey)
{
var buf = new byte[32];
Expand All @@ -35,3 +37,4 @@ public static string ToBase58(ECXOnlyPubKey pubKey)
}
}
}

120 changes: 120 additions & 0 deletions NDLC.GUI/About.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
namespace NDLC.GUI

open System
open System.Diagnostics
open System.Runtime.InteropServices

open Avalonia.Layout
open Avalonia.Controls
open Avalonia.Controls.Presenters
open Avalonia.Media
open Avalonia.Styling

open Elmish
open Avalonia.FuncUI
open Avalonia.FuncUI.DSL
open Avalonia.FuncUI.Components
open Avalonia.FuncUI.Elmish


module About =
type State = { noop: bool }

type Links =
| NDLC
| DLCSpecs
| AvaloniaFuncUI
with
member this.Text =
match this with
| NDLC -> "About NDLC"
| DLCSpecs -> "Spec for the DLC protocol itself"
| AvaloniaFuncUI -> "About the framework we used to create this GUI"

type Msg = OpenUrl of Links

let init = { noop = false }


let update (msg: Msg) (state: State) =
match msg with
| OpenUrl link ->
let url =
match link with
| NDLC -> "https://github.com/dgarage/NDLC"
| DLCSpecs -> "https://github.com/discreetlogcontracts/dlcspecs"
| AvaloniaFuncUI -> "https://github.com/AvaloniaCommunity/Avalonia.FuncUI"

ignore <|
if RuntimeInformation.IsOSPlatform OSPlatform.Windows then
let start = sprintf "/c start %s" url
Process.Start(ProcessStartInfo("cmd", start))
else if RuntimeInformation.IsOSPlatform OSPlatform.Linux then
Process.Start ("xdg-open", url)
else if RuntimeInformation.IsOSPlatform OSPlatform.OSX then
Process.Start ("open", url)
else
raise <| NotSupportedException("Unknown OS platform")
state


let view (state: State) (dispatch: Msg -> unit) =
let linkView (l: Links) =
TextBlock.create [
TextBlock.classes ["link"]
TextBlock.text l.Text
TextBlock.foreground "#009bd2"
TextBlock.fontSize 16.
TextBlock.fontWeight FontWeight.SemiBold
TextBlock.fontStyle FontStyle.Oblique
TextBlock.onTapped (fun _ -> dispatch (OpenUrl l))
]
DockPanel.create [
DockPanel.margin (0., 20.)
DockPanel.horizontalAlignment HorizontalAlignment.Center
DockPanel.verticalAlignment VerticalAlignment.Top
DockPanel.children [
StackPanel.create [
StackPanel.dock Dock.Top
StackPanel.verticalAlignment VerticalAlignment.Top
StackPanel.children [
TextBlock.create [
TextBlock.classes ["title"]
TextBlock.fontSize 24.
TextBlock.fontWeight FontWeight.Thin
TextBlock.text "GUI application for managing DLC (Experimental)"
]
TextBlock.create [
TextBlock.classes [ "subtitle" ]
TextBlock.fontSize 16.
TextBlock.fontWeight FontWeight.Thin
TextBlock.text
("DLC is an exciting new mechanism to create an anonymous prediction market\n" +
"with just a bitcoin. And this is a wrapper GUI to manage your position and more.")
]
]
]
StackPanel.create [
StackPanel.dock Dock.Left
StackPanel.horizontalAlignment HorizontalAlignment.Left
StackPanel.children [
linkView NDLC
linkView Links.DLCSpecs
linkView Links.AvaloniaFuncUI
]
]
StackPanel.create [
StackPanel.dock Dock.Right
]
]
]

type Host() as this =
inherit Hosts.HostControl()
do
this.Styles.Load "avares://NDLC.GUI/Styles.xaml"
Elmish.Program.mkSimple (fun () -> init) update view
|> Program.withHost this
|> Program.run


28 changes: 28 additions & 0 deletions NDLC.GUI/Components.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace NDLC.GUI

open Avalonia
open Avalonia.Controls
open Avalonia.Controls.Presenters
open Avalonia.FuncUI.DSL
open Avalonia.Layout
open Avalonia.Styling

module Components =
let spinner =
StackPanel.create [
StackPanel.children [
StackPanel.create [
StackPanel.horizontalAlignment HorizontalAlignment.Center
StackPanel.verticalAlignment VerticalAlignment.Center
StackPanel.children [
TextBox.create [
TextBox.text "Now loading..."
]
]
]
]
]


let inputTextBox (name) (watermark) =
TextBox.create []
31 changes: 31 additions & 0 deletions NDLC.GUI/Controls.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace NDLC.GUI
open System

open Avalonia.Controls
open Avalonia.FuncUI.DSL
open Avalonia.Input
open Avalonia.Interactivity

module TextBox =
let onTextInput handler =
let handler' (args: RoutedEventArgs) =
let tx = (args.Source :?> TextBox).Text
if String.IsNullOrEmpty tx then () else
handler tx
[
TextBox.onKeyDown(handler')
TextBox.onKeyUp(handler')
]

let onTextInputFinished handler =
let handler' =
fun (args: KeyEventArgs) ->
if args.Key = Key.Enter || args.Key = Key.Tab then
let tx = (args.Source :?> TextBox).Text
if String.IsNullOrEmpty tx then () else
handler tx
[
TextBox.onKeyDown(handler')
TextBox.onKeyUp(handler')
]

75 changes: 75 additions & 0 deletions NDLC.GUI/DLC/CheckSig.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module internal NDLC.GUI.DLC.CheckSig

open System.Text
open System.Threading.Tasks
open FSharp.Control.Tasks
open NBitcoin
open NBitcoin.DataEncoders
open NDLC.GUI.DLC
open NDLC.GUI.Utils
open NDLC.Infrastructure
open NDLC.Messages
open NDLC.Messages
open Newtonsoft.Json
open Newtonsoft.Json.Linq

let private parse<'T when 'T : null and 'T : not struct> (g, base64: string): 'T option =
let repo = ConfigUtils.repository g
let json = UTF8Encoding.UTF8.GetString(Encoders.Base64.DecodeData(base64));
JsonConvert.DeserializeObject<'T>(json, repo.JsonSettings) |> Option.ofObj

let private tryGetDLCFromID (repo: Repository) (contractId: uint256) = task {
if (contractId |> isNull) then
// TODO: Allow to pass a hint via command line
return Error("This accept message does not match any of our DLC");
else
let! dlc = repo.GetDLC(contractId);
if (dlc |> isNull) then
return Error("This accept message does not match any of our DLC")
else
return Ok(dlc)
}

let private handleAccept g (accept: Accept): Task<PSBT> = task {
let repo = ConfigUtils.repository g
let! dlcResult = tryGetDLCFromID (repo) (accept.OffererContractId)
match dlcResult with
| Error e -> return failwith e
| Ok dlc ->
match DLCUtils.assertState (dlc, true, Repository.DLCState.DLCNextStep.CheckSigs, g.Network) with
| Error e -> return failwith e
| Ok _ ->
let builder = DLCTransactionBuilder(dlc.BuilderState.ToString(), g.Network);
builder.Sign1(accept);
dlc.BuilderState <- builder.ExportStateJObject();
dlc.Accept <- JObject.FromObject(accept, JsonSerializer.Create(repo.JsonSettings));
do! repo.SaveDLC(dlc);
return (builder.GetFundingPSBT());
}

let private handleSign g (s: Sign) = task {
let repo = ConfigUtils.repository g
let! dlcResult = tryGetDLCFromID (repo) (s.AcceptorContractId)
match dlcResult with
| Error e -> return failwith e
| Ok dlc ->
match DLCUtils.assertState (dlc, false, Repository.DLCState.DLCNextStep.CheckSigs, g.Network) with
| Error e -> return failwith e
| Ok _ ->
let builder = DLCTransactionBuilder(dlc.BuilderState.ToString(), g.Network)
builder.Finalize1(s)
dlc.Sign <- JObject.FromObject(sign, JsonSerializer.Create(repo.JsonSettings));
dlc.BuilderState <- builder.ExportStateJObject();
do! repo.SaveDLC(dlc);
return (builder.GetFundingPSBT())
}
let checksig globalConfig (base64: string) = task {
match parse<Accept>(globalConfig, base64),parse<Sign> (globalConfig, base64) with
| Some a, None ->
return! handleAccept (globalConfig) (a)
| _, Some s ->
return! handleSign (globalConfig) (s)
| None, None ->
return failwith "Failed to parse Accept/Sign message"
}

Loading