灵符lingfu
L

ling-wallet

↓ 0 downloads

Ling Wallet: a post-quantum privacy-coin wallet, full node and HyperTorus miner for LNG

Windows · x86-64 ✕Linux · x86-64 ✕LingOS · x86-64LingOS · Pi 5 ARM64 ✕
Keywords wallet, cryptocurrency, lng, node, miner, ling
lingfu install ling-wallet
LicenseMIT
Authorsling-lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (116)

ling/escrowtest.ling
# escrowtest.ling — end-to-end LNG escrow against a running ling-market.
#
# Plays the buyer (and, via the API, the vendor): mine until coins mature,
# set the vendor's payout address, place an order, pay it with the order
# memo, wait for the market to mark it funded, ship, confirm, and check the
# vendor payout arrives. Start the market first (see ../../ling-market):
#
#   ling run market_server.ling --port 7795 --db T/market.db --lng-dir T/lng
#       --lng-listen 127.0.0.1:18891 --lng-peer 127.0.0.1:18890
#       --lng-test-difficulty 1 --lng-test-target 2
#   ling run --interp escrowtest.ling --data-dir T/buyer --fast-kdf 1
#       --listen 127.0.0.1:18890 --peer 127.0.0.1:18891
#       --market-port 7795 --market-log T/server.log

use "api.ling"
use "real_backend.ling"

fn check(name, cond) {
    if cond {
        print("PASS ", name)
        st_add("pass", 1)
    } else {
        print("FAIL ", name)
        st_add("fail", 1)
    }
    return cond
}

fn pump(secs) {
    bind deadline = epoch_now() + secs
    while epoch_now() < deadline {
        real_tick()
        sleep(50)
    }
    return 0
}

fn json_str(json, key) {
    bind marker = format("\"{}\":\"", key)
    bind start = str_find(json, marker)
    if start < 0 {
        return ""
    }
    bind rest = substr(json, start + len(marker))
    return substr(rest, 0, str_find(rest, "\""))
}

fn json_num(json, key) {
    bind marker = format("\"{}\":", key)
    bind start = str_find(json, marker)
    if start < 0 {
        return -1
    }
    bind rest = substr(json, start + len(marker))
    bind end = str_find(rest, ",")
    if end < 0 {
        bind end = str_find(rest, "}")
    }
    return to_number(substr(rest, 0, end))
}

fn market(path) {
    return lingtp_get("127.0.0.1", to_number(cli_arg("market-port", "7795")), path)
}

fn market_post(path, body) {
    return lingtp_post("127.0.0.1", to_number(cli_arg("market-port", "7795")), path, body)
}

# The seeded vendor's TOTP secret, from the market's startup log.
fn vendor_secret() {
    bind log = read_file(cli_arg("market-log", "server.log"))
    bind at = str_find(log, "sweettooth/")
    bind rest = substr(log, at)
    bind s = str_find(rest, "totp secret=")
    return trim(substr(rest, s + 12, 32))
}

fn order_status(id) {
    return json_str(market(format("/api/order/get?order_id={}", id)), "status")
}

fn wait_status(id, want, secs) {
    bind deadline = epoch_now() + secs
    while epoch_now() < deadline && order_status(id) != want {
        pump(2)
    }
    return order_status(id) == want
}

bind start = do {
    shared_put("test_genesis_difficulty", "1")
    shared_put("test_target_secs", "2")
    real_init()
    pump(2)
    check("buyer wallet created", match real_create("buyer password 1") { ok(w) => true, bad(e) => false, })
    pump(2)
    bind me = real_summary().x.short_address

    # Mine until some coinbases mature (60 blocks).
    real_set_mining(true, 2, 100, false)
    bind t0 = epoch_now()
    bind deadline = epoch_now() + 900
    while epoch_now() < deadline && real_summary().x.unlocked < 10 * COIN {
        pump(2)
    }
    print("mined to height ", st_get("n_height", 0), " in ", floor(epoch_now() - t0), " s")
    check("buyer has spendable LNG", real_summary().x.unlocked >= 10 * COIN)

    # Vendor: log in with 2FA, point the shop's payouts at our address.
    bind login = market_post("/api/vendor/login", format("username=sweettooth&password=NebulaGummyBears99!&code={}", totp_now(vendor_secret())))
    bind vtoken = json_str(login, "token")
    check("vendor logs in with 2FA", vtoken != "")
    bind upd = market_post("/api/shop/update", format("token={}&shop_id=1&payout_address={}", vtoken, me))
    check("vendor sets an LNG payout address", str_find(upd, "\"ok\":true") >= 0)
    check("invalid payout address rejected", str_find(market_post("/api/shop/update", format("token={}&shop_id=1&payout_address=lng1nope", vtoken)), "\"ok\":false") >= 0)

    # Buyer: place an order.
    check("order without refund address rejected", str_find(market_post("/api/order/create", "product_id=1&quantity=1"), "refund_address") >= 0)
    bind order = market_post("/api/order/create", format("product_id=1&quantity=2&refund_address={}", me))
    bind oid = json_num(order, "order_id")
    bind btoken = json_str(order, "buyer_token")
    bind pay_to = json_str(order, "escrow_address")
    bind memo = json_str(order, "payment_memo")
    bind total = floor(to_number(json_str(order, "total_amount")) * COIN + 0.5)
    check("order placed with escrow address and memo", oid > 0 && starts_with(pay_to, "lng1") && starts_with(memo, "order:"))

    # Pay it.
    bind lk = ["pending"]
    bind deadline = epoch_now() + 90
    while list_get(lk, 0) == "pending" && epoch_now() < deadline {
        bind lk = real_lookup(pay_to)
        pump(0.5)
    }
    check("market escrow address verified over the network", list_get(lk, 0) == "verified")
    bind prep = real_prepare(pay_to, total, memo)
    check("payment prepared", match prep { ok(p) => true, bad(e) => false, })
    check("payment authorized", match real_confirm(prep.x.id, "buyer password 1") { ok(v) => true, bad(e) => false, })
    bind deadline = epoch_now() + 60
    while list_get(real_progress(prep.x.id), 0) == "signing" && epoch_now() < deadline {
        pump(0.5)
    }
    check("payment sent", list_get(real_progress(prep.x.id), 0) == "sent")

    check("market marks the order funded", wait_status(oid, "funded", 300))

    # Vendor ships, buyer confirms → vendor payout.
    check("vendor ships", str_find(market_post("/api/order/ship", format("token={}&order_id={}&note=on its way", vtoken, oid)), "\"ok\":true") >= 0)
    check("buyer confirms receipt", str_find(market_post("/api/order/confirm", format("order_id={}&buyer_token={}", oid, btoken)), "\"ok\":true") >= 0)

    # The payout (memo order:<id>) reaches the vendor's address — ours.
    bind want = format("order:{}", oid)
    bind got = 0
    bind deadline = epoch_now() + 600
    while got == 0 && epoch_now() < deadline {
        pump(2)
        bind h = real_history(100)
        bind i = 0
        while i < len(h) {
            bind r = list_get(h, i)
            if r.direction == "in" && r.memo == want {
                bind got = r.amount
            }
            bind i = i + 1
        }
    }
    print("payout received: ", got / COIN, " LNG of ", total / COIN, " LNG escrowed")
    check("vendor payout arrived", got > 0)
    check("payout is the total minus a small network fee", got <= total && got > total - COIN / 10)

    real_set_mining(false, 1, 100, false)
    print("")
    print(format("{} passed, {} failed", st_get("pass", 0), st_get("fail", 0)))
    quit()
}

← Back to index