L
ling-wallet
↓ 0 downloadsLing Wallet: a post-quantum privacy-coin wallet, full node and HyperTorus miner for LNG
Keywords wallet, cryptocurrency, lng, node, miner, ling
lingfu install ling-walletCode / Files (116)
ling/main.ling
# Ling Wallet — desktop UI.
# Run: lingfu run (from the repo root; live node, on the JIT)
# lingfu run --mock (simulated backend)
# ling run --interp main.ling (the tree-walking interpreter)
# Shots: lingfu run --mock --screenshot out.png --screen wallet [--frames N] [--prof]
use "backend.ling"
use "ui/theme.ling"
use "ui/gfx.ling"
use "ui/input.ling"
use "ui/widgets.ling"
use "ui/icons.ling"
use "ui/qr.ling"
use "ui/torus.ling"
use "ui/shell.ling"
use "ui/onboard.ling"
use "ui/wallet.ling"
use "ui/send.ling"
use "ui/receive.ling"
use "ui/mining.ling"
use "ui/network.ling"
use "ui/security.ling"
use "ui/about.ling"
bind SHOT_PW = "correct-horse-42"
fn set_rate(fps) {
if st_get("fps", 0) != fps {
set_fps(fps)
st_set("fps", fps)
}
}
# Screenshot mode: put the app into the named state.
fn shot_setup(name) {
st_set("shot", 1)
st_set("shot_done", 0)
bind needs_wallet = name != "onboarding" && name != "create" && name != "restore"
if needs_wallet && name != "words" && name != "verify" { be_create(SHOT_PW) }
if name == "create" {
st_set("ob_step", "password")
tf_set("ob_pw", "correct horse battery 42")
}
if name == "words" || name == "verify" {
bind r = be_create(SHOT_PW)
match r {
ok(ws) => ob_created(ws),
bad(e) => println(e),
}
st_set("ob_ask", [2, 11, 19])
}
if name == "verify" {
st_set("ob_step", "verify")
tf_set("ob_a0", "lattice")
}
if name == "restore" {
st_set("ob_step", "restore")
tf_set("rs0", "orbit")
tf_set("rs1", "candy")
}
if name == "unlock" {
be_lock()
tf_set("unlock_pw", "wrongpass")
st_set("unlock_err", "Wrong password.")
}
bind sec = index_of(["wallet", "send", "receive", "mining", "network", "security", "about"], name)
if sec >= 0 { st_set("section", sec) }
if str_starts_with(name, "send") {
st_set("section", 1)
tf_set("send_to", "lng1q8w3x5ffm2kzv7d4hn3j9t0yqe6c2rplx4sa8gu")
tf_set("send_amt", "12.5")
tf_set("send_memo", "invoice 2291")
}
if str_starts_with(name, "security") { st_set("section", 5) }
if name == "security-revealed" {
bind r2 = be_reveal(SHOT_PW)
match r2 {
ok(ws) => sec_revealed(ws),
bad(e) => println(e),
}
}
}
# Steps that need time to pass first (lookups, signing).
fn shot_step(name, el) {
if st_get("shot_step", 0) > 0 { return () }
if str_starts_with(name, "send-") && el > 1.4 {
st_set("shot_step", 1)
bind to = tf_get("send_to")
bind r = be_prepare(to, parse_lng("12.5"), "invoice 2291")
match r {
ok(p) => send_prepared(p),
bad(e) => println(e),
}
if name == "send-authorize" {
send_go("authorize")
tf_set("send_pw", "correct-horse")
}
if name == "send-sent" {
bind p2 = st_get("send_p", ())
be_confirm(p2.id, SHOT_PW)
send_signed()
}
}
}
fn shot_min_time(name) {
if name == "send-sent" { return 3.6 }
if str_starts_with(name, "send") { return 2.0 }
if name == "mining" || name == "onboarding" { return 2.0 }
return 0.6
}
bind start = do {
# screenshot mode types a published password and renders the seed words: it only ever runs on the mock backend
if cli_arg("screenshot", "") != "" { st_set("be_mock", 1) }
be_init()
open_window(1200, 780, "Ling Wallet", 1)
px_flat()
if !fonts_load() { println("fonts missing; run from the ling/ folder") }
st_set("autolock", 2)
st_set("section", 0)
st_set("autofocus", 1)
st_set("activity_t", 0)
send_reset()
sec_wipe()
tz_clear("tz")
tz_clear("deco")
bind shot_out = cli_arg("screenshot", "")
bind shot_name = cli_arg("screen", "wallet")
bind shot_frames = to_number(cli_arg("frames", "20"))
bind prof = index_of(get_args(), "--prof") >= 0
bind t0 = time_now()
if shot_out != "" { shot_setup(shot_name) }
bind frame = 0
bind last_draw = 0 - 10
bind running = true
set_rate(60)
while window_is_open() && running {
bind t = time_now()
bind input = u_begin(t)
be_tick()
if shot_out != "" { shot_step(shot_name, t - t0) }
bind idle_for = t - st_get("activity_t", 0)
bind redraw = input || animating() || toast_live() || t - last_draw > 0.5 || shot_out != ""
if focus_get() != "" && t - last_draw > 0.3 { bind redraw = true }
if redraw {
app_frame()
u_end()
bind last_draw = t
if prof {
st_add("prof_ms", (time_now() - t) * 1000)
st_add("prof_n", 1)
if st_get("prof_n", 0) >= 60 {
println("draw ms avg: ", round(st_get("prof_ms", 0) / st_get("prof_n", 1) * 10) / 10)
st_set("prof_ms", 0)
st_set("prof_n", 0)
}
}
}
if shot_out != "" {
set_rate(60)
} else if idle_for < 1.5 || focus_get() != "" {
# a focused field keeps the loop polling keys at full rate; idle
# frames skip drawing, so this costs little
set_rate(60)
} else if animating() {
set_rate(30)
} else {
set_rate(10)
}
present()
bind frame = frame + 1
if shot_out != "" && frame >= shot_frames && t - t0 >= shot_min_time(shot_name) {
bind path = screenshot(shot_name)
if file_exists(shot_out) { remove_file(shot_out) }
rename_file(path, shot_out)
println("saved ", shot_out)
bind running = false
}
}
}