@1sat/cli 0.0.111 → 0.0.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +55 -96
- package/package.json +9 -9
- package/src/commands/action.ts +10 -0
- package/src/commands/opns.ts +3 -34
- package/src/commands/ordinals.ts +6 -33
- package/src/commands/serve.ts +15 -4
- package/src/config.ts +11 -0
- package/src/help.ts +6 -0
- package/src/repricer/buildPriceUpdateTask.ts +12 -2
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
res = fn(fn = 0);
|
|
6
|
-
} catch (e) {
|
|
7
|
-
err = [e];
|
|
8
|
-
}
|
|
9
|
-
if (err)
|
|
10
|
-
throw err[0];
|
|
11
|
-
return res;
|
|
12
|
-
};
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
4
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
13
5
|
|
|
14
6
|
// src/args.ts
|
|
15
7
|
function parseGlobalFlags(args) {
|
|
@@ -513,11 +505,11 @@ async function handleActionCommand(args, opts) {
|
|
|
513
505
|
Registered actions:
|
|
514
506
|
`);
|
|
515
507
|
const grouped = new Map;
|
|
516
|
-
for (const
|
|
517
|
-
const cat =
|
|
508
|
+
for (const action2 of actions) {
|
|
509
|
+
const cat = action2.meta.category;
|
|
518
510
|
if (!grouped.has(cat))
|
|
519
511
|
grouped.set(cat, []);
|
|
520
|
-
grouped.get(cat).push(
|
|
512
|
+
grouped.get(cat).push(action2);
|
|
521
513
|
}
|
|
522
514
|
for (const [category, categoryActions] of grouped) {
|
|
523
515
|
console.log(` ${category}:`);
|
|
@@ -549,6 +541,9 @@ Run '1sat action' to list available actions.`);
|
|
|
549
541
|
try {
|
|
550
542
|
const result = await action.execute(ctx, input);
|
|
551
543
|
output(result, opts);
|
|
544
|
+
if (actionName === "cancelOwnedListings" && result !== null && typeof result === "object" && "errors" in result && Array.isArray(result.errors) && result.errors.length > 0) {
|
|
545
|
+
process.exitCode = 1;
|
|
546
|
+
}
|
|
552
547
|
} finally {
|
|
553
548
|
await destroy();
|
|
554
549
|
}
|
|
@@ -1048,6 +1043,8 @@ var init_help = __esm(() => {
|
|
|
1048
1043
|
{
|
|
1049
1044
|
name: "sell",
|
|
1050
1045
|
description: "List an ordinal for sale (OrdLock)",
|
|
1046
|
+
unavailable: true,
|
|
1047
|
+
notes: "OrdLock listing create is disabled. Buy and cancel of existing listings remain available.",
|
|
1051
1048
|
args: [
|
|
1052
1049
|
{ flag: "--id", values: "<tracking-id>", required: true },
|
|
1053
1050
|
{ flag: "--price", values: "<sats>", required: true },
|
|
@@ -1260,6 +1257,8 @@ var init_help = __esm(() => {
|
|
|
1260
1257
|
{
|
|
1261
1258
|
name: "sell",
|
|
1262
1259
|
description: "List an OpNS name for sale",
|
|
1260
|
+
unavailable: true,
|
|
1261
|
+
notes: "OrdLock listing create is disabled. Buy and cancel of existing listings remain available.",
|
|
1263
1262
|
args: [
|
|
1264
1263
|
{ flag: "--id", values: "<tracking-id>", required: true },
|
|
1265
1264
|
{ flag: "--price", values: "<satoshis>", required: true },
|
|
@@ -1441,7 +1440,7 @@ function createApprovalAuth(wallet) {
|
|
|
1441
1440
|
get(target, property) {
|
|
1442
1441
|
if (property === "createAction")
|
|
1443
1442
|
return async (...args) => {
|
|
1444
|
-
const satoshis = args[0].outputs?.reduce((sum,
|
|
1443
|
+
const satoshis = args[0].outputs?.reduce((sum, output2) => sum + output2.satoshis, 0) ?? 0;
|
|
1445
1444
|
if (!Number.isSafeInteger(satoshis) || satoshis <= 0)
|
|
1446
1445
|
throw new Error("Invalid HTTP payment amount");
|
|
1447
1446
|
if (approved === false)
|
|
@@ -1965,15 +1964,15 @@ async function handleInitCommand(_args, opts) {
|
|
|
1965
1964
|
}
|
|
1966
1965
|
let wif;
|
|
1967
1966
|
if (keySource === "generate") {
|
|
1968
|
-
const
|
|
1969
|
-
wif =
|
|
1970
|
-
const
|
|
1967
|
+
const pk2 = PrivateKey2.fromRandom();
|
|
1968
|
+
wif = pk2.toWif();
|
|
1969
|
+
const address2 = pk2.toPublicKey().toAddress();
|
|
1971
1970
|
console.log();
|
|
1972
1971
|
console.log(formatWarning(" IMPORTANT: Back up your private key!"));
|
|
1973
1972
|
console.log(formatWarning(" If you lose it, your funds are gone forever."));
|
|
1974
1973
|
console.log();
|
|
1975
1974
|
console.log(` ${formatValue("WIF:")} ${wif}`);
|
|
1976
|
-
console.log(` ${formatValue("Address:")} ${
|
|
1975
|
+
console.log(` ${formatValue("Address:")} ${address2}`);
|
|
1977
1976
|
console.log();
|
|
1978
1977
|
const confirmed = await confirm2({
|
|
1979
1978
|
message: "Have you saved your private key somewhere safe?"
|
|
@@ -2442,10 +2441,9 @@ import {
|
|
|
2442
2441
|
internalizeOpns,
|
|
2443
2442
|
listOpns,
|
|
2444
2443
|
registerOpns,
|
|
2445
|
-
sellOpns,
|
|
2446
2444
|
sendOpns
|
|
2447
2445
|
} from "@1sat/actions";
|
|
2448
|
-
import { P1SAT_PROTOCOL } from "@1sat/types";
|
|
2446
|
+
import { ORDLOCK_LISTING_CREATE_DISABLED, P1SAT_PROTOCOL } from "@1sat/types";
|
|
2449
2447
|
import { confirm as confirm4, isCancel as isCancel5 } from "@clack/prompts";
|
|
2450
2448
|
async function handleOpnsCommand(args, opts) {
|
|
2451
2449
|
const [subcommand, ...rest] = args;
|
|
@@ -2582,37 +2580,8 @@ async function opnsCancelListingCmd(args, opts) {
|
|
|
2582
2580
|
await destroy();
|
|
2583
2581
|
}
|
|
2584
2582
|
}
|
|
2585
|
-
async function opnsSell(
|
|
2586
|
-
|
|
2587
|
-
const priceStr = extractFlag(args, "--price");
|
|
2588
|
-
const payAddress = extractFlag(args, "--pay-address");
|
|
2589
|
-
if (!priceStr)
|
|
2590
|
-
fatal("Missing --price <satoshis>");
|
|
2591
|
-
const price = Number(priceStr);
|
|
2592
|
-
if (!Number.isFinite(price) || price <= 0) {
|
|
2593
|
-
fatal("--price must be a positive number");
|
|
2594
|
-
}
|
|
2595
|
-
if (!opts.yes) {
|
|
2596
|
-
const ok = await confirm4({
|
|
2597
|
-
message: `List OpNS id ${id} for sale at ${price} satoshis?`
|
|
2598
|
-
});
|
|
2599
|
-
if (isCancel5(ok) || !ok)
|
|
2600
|
-
fatal("Listing cancelled.");
|
|
2601
|
-
}
|
|
2602
|
-
const privateKey = await loadKey();
|
|
2603
|
-
const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain });
|
|
2604
|
-
try {
|
|
2605
|
-
const result = await sellOpns.execute(ctx, {
|
|
2606
|
-
id,
|
|
2607
|
-
price,
|
|
2608
|
-
...payAddress && { payAddress }
|
|
2609
|
-
});
|
|
2610
|
-
if (result.error)
|
|
2611
|
-
fatal(result.error);
|
|
2612
|
-
output(opts.json ? result : { txid: result.txid }, opts);
|
|
2613
|
-
} finally {
|
|
2614
|
-
await destroy();
|
|
2615
|
-
}
|
|
2583
|
+
async function opnsSell(_args, _opts) {
|
|
2584
|
+
fatal(ORDLOCK_LISTING_CREATE_DISABLED);
|
|
2616
2585
|
}
|
|
2617
2586
|
async function opnsSend(args, opts) {
|
|
2618
2587
|
const id = requireId(args);
|
|
@@ -2713,9 +2682,9 @@ import {
|
|
|
2713
2682
|
getDisplayValue as getDisplayValue2,
|
|
2714
2683
|
inscribe,
|
|
2715
2684
|
listOrdinals,
|
|
2716
|
-
sellOrdinal,
|
|
2717
2685
|
sendOrdinals
|
|
2718
2686
|
} from "@1sat/actions";
|
|
2687
|
+
import { ORDLOCK_LISTING_CREATE_DISABLED as ORDLOCK_LISTING_CREATE_DISABLED2 } from "@1sat/types";
|
|
2719
2688
|
import { Utils as Utils3 } from "@bsv/sdk";
|
|
2720
2689
|
import { confirm as confirm5, isCancel as isCancel6 } from "@clack/prompts";
|
|
2721
2690
|
async function handleOrdinalsCommand(args, opts) {
|
|
@@ -2878,37 +2847,8 @@ async function ordinalsSend(args, opts) {
|
|
|
2878
2847
|
await destroy();
|
|
2879
2848
|
}
|
|
2880
2849
|
}
|
|
2881
|
-
async function ordinalsSell(
|
|
2882
|
-
|
|
2883
|
-
const priceStr = extractFlag(args, "--price");
|
|
2884
|
-
const payAddress = extractFlag(args, "--pay-address");
|
|
2885
|
-
if (!priceStr)
|
|
2886
|
-
fatal("Missing --price <satoshis>");
|
|
2887
|
-
const price = Number(priceStr);
|
|
2888
|
-
if (!Number.isFinite(price) || price <= 0) {
|
|
2889
|
-
fatal("--price must be a positive number");
|
|
2890
|
-
}
|
|
2891
|
-
if (!opts.yes) {
|
|
2892
|
-
const ok = await confirm5({
|
|
2893
|
-
message: `List ordinal id ${id} for sale at ${price} satoshis?`
|
|
2894
|
-
});
|
|
2895
|
-
if (isCancel6(ok) || !ok)
|
|
2896
|
-
fatal("Listing cancelled.");
|
|
2897
|
-
}
|
|
2898
|
-
const privateKey = await loadKey();
|
|
2899
|
-
const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain });
|
|
2900
|
-
try {
|
|
2901
|
-
const result = await sellOrdinal.execute(ctx, {
|
|
2902
|
-
id,
|
|
2903
|
-
price,
|
|
2904
|
-
...payAddress && { payAddress }
|
|
2905
|
-
});
|
|
2906
|
-
if (result.error)
|
|
2907
|
-
fatal(result.error);
|
|
2908
|
-
output(opts.json ? result : { txid: result.txid }, opts);
|
|
2909
|
-
} finally {
|
|
2910
|
-
await destroy();
|
|
2911
|
-
}
|
|
2850
|
+
async function ordinalsSell(_args, _opts) {
|
|
2851
|
+
fatal(ORDLOCK_LISTING_CREATE_DISABLED2);
|
|
2912
2852
|
}
|
|
2913
2853
|
async function ordinalsCancel(args, opts) {
|
|
2914
2854
|
const id = requireId2(args);
|
|
@@ -3389,7 +3329,7 @@ function buildPriceUpdateTask(options) {
|
|
|
3389
3329
|
lastRunMsecsSinceEpoch: 0,
|
|
3390
3330
|
async asyncSetup() {},
|
|
3391
3331
|
trigger(now) {
|
|
3392
|
-
if (targets.length === 0)
|
|
3332
|
+
if (targets.length === 0 && !options.onQuote)
|
|
3393
3333
|
return { run: false };
|
|
3394
3334
|
if (now - this.lastRunMsecsSinceEpoch < intervalMs)
|
|
3395
3335
|
return { run: false };
|
|
@@ -3402,6 +3342,13 @@ function buildPriceUpdateTask(options) {
|
|
|
3402
3342
|
} catch (err) {
|
|
3403
3343
|
return `rate fetch failed: ${err.message}`;
|
|
3404
3344
|
}
|
|
3345
|
+
if (options.onQuote) {
|
|
3346
|
+
try {
|
|
3347
|
+
await options.onQuote(quote);
|
|
3348
|
+
} catch (err) {
|
|
3349
|
+
return `quote persist failed: ${err.message}`;
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3405
3352
|
const parts = [];
|
|
3406
3353
|
for (const target of targets) {
|
|
3407
3354
|
const currentSats = target.readCurrentSats();
|
|
@@ -3498,6 +3445,7 @@ import {
|
|
|
3498
3445
|
} from "@1sat/wallet-node";
|
|
3499
3446
|
import {
|
|
3500
3447
|
KnexAccountStore,
|
|
3448
|
+
KnexHandleCertStore,
|
|
3501
3449
|
KnexPendingStore,
|
|
3502
3450
|
createHostServer,
|
|
3503
3451
|
createWalletServer
|
|
@@ -3644,7 +3592,7 @@ async function runWithStorage(resolved, mode) {
|
|
|
3644
3592
|
}
|
|
3645
3593
|
});
|
|
3646
3594
|
}
|
|
3647
|
-
if (r?.enabled
|
|
3595
|
+
if (r?.enabled) {
|
|
3648
3596
|
walletResult.monitor.addTask(buildPriceUpdateTask({
|
|
3649
3597
|
monitor: walletResult.monitor,
|
|
3650
3598
|
rateProvider: resolveRateProvider(r.provider ?? "whatsonchain", {
|
|
@@ -3655,9 +3603,13 @@ async function runWithStorage(resolved, mode) {
|
|
|
3655
3603
|
maxMovePct: r.maxMovePct ?? 25,
|
|
3656
3604
|
minSats: r.minSats ?? 1
|
|
3657
3605
|
},
|
|
3658
|
-
targets
|
|
3606
|
+
targets,
|
|
3607
|
+
onQuote: async (quote) => {
|
|
3608
|
+
setConfigPath("server.exchangeRate", quote);
|
|
3609
|
+
}
|
|
3659
3610
|
}));
|
|
3660
|
-
|
|
3611
|
+
const targetNote = targets.map((t) => `${t.name} $${t.targetUsd}`).join(", ") || "quote only";
|
|
3612
|
+
console.log(`[repricer] enabled — ${targetNote} every ${Math.round((r.intervalMs ?? 900000) / 1000)}s via ${r.provider ?? "whatsonchain"}`);
|
|
3661
3613
|
}
|
|
3662
3614
|
}
|
|
3663
3615
|
if (runMonitor) {
|
|
@@ -3687,7 +3639,7 @@ async function startWalletServer(resolved, walletResult, accounts, mode) {
|
|
|
3687
3639
|
ttlSeconds: sessionStoreCfg.ttlSeconds
|
|
3688
3640
|
} : undefined;
|
|
3689
3641
|
if (mode === "wallet") {
|
|
3690
|
-
const
|
|
3642
|
+
const handle2 = createWalletServer({
|
|
3691
3643
|
wallet: walletResult.wallet,
|
|
3692
3644
|
storage: walletResult.getActiveStorage(),
|
|
3693
3645
|
serverIdentityKey: walletResult.wallet.identityKey,
|
|
@@ -3697,10 +3649,10 @@ async function startWalletServer(resolved, walletResult, accounts, mode) {
|
|
|
3697
3649
|
accounts: accounts?.walletServerAccounts,
|
|
3698
3650
|
sessionStore
|
|
3699
3651
|
});
|
|
3700
|
-
const
|
|
3701
|
-
const
|
|
3702
|
-
console.log(`[wallet] listening on ${resolved.host}:${
|
|
3703
|
-
return { stop: () =>
|
|
3652
|
+
const port2 = await handle2.start();
|
|
3653
|
+
const notes2 = [resolved.accounts.enabled ? "accounts: on" : ""].filter(Boolean).join(", ");
|
|
3654
|
+
console.log(`[wallet] listening on ${resolved.host}:${port2}${notes2 ? ` (${notes2})` : ""}`);
|
|
3655
|
+
return { stop: () => handle2.stop() };
|
|
3704
3656
|
}
|
|
3705
3657
|
const serverCfg = config.server ?? {};
|
|
3706
3658
|
const paymailCfg = serverCfg.paymail;
|
|
@@ -3710,6 +3662,8 @@ async function startWalletServer(resolved, walletResult, accounts, mode) {
|
|
|
3710
3662
|
await pendingStore.init();
|
|
3711
3663
|
const accountStore = new KnexAccountStore(knex);
|
|
3712
3664
|
await accountStore.init();
|
|
3665
|
+
const handleCertStore = new KnexHandleCertStore(knex);
|
|
3666
|
+
await handleCertStore.init();
|
|
3713
3667
|
const handle = await createHostServer({
|
|
3714
3668
|
wallet: walletResult.wallet,
|
|
3715
3669
|
sessionStore,
|
|
@@ -3718,12 +3672,16 @@ async function startWalletServer(resolved, walletResult, accounts, mode) {
|
|
|
3718
3672
|
listen: { port: resolved.port, host: resolved.host },
|
|
3719
3673
|
accounts: accounts?.walletServerAccounts,
|
|
3720
3674
|
accountStore,
|
|
3675
|
+
handleCertStore,
|
|
3676
|
+
getExchangeRate: () => loadConfig().server?.exchangeRate ?? null,
|
|
3721
3677
|
paymail: {
|
|
3722
3678
|
baseUrl: paymailCfg?.baseUrl ?? `http://${resolved.host}:${resolved.port}`,
|
|
3723
3679
|
stackUrl: paymailCfg?.stackUrl ?? resolved.stackUrl,
|
|
3724
3680
|
pendingStore,
|
|
3725
3681
|
accountStore,
|
|
3682
|
+
certStore: handleCertStore,
|
|
3726
3683
|
...paymailCfg?.userDomain && { userDomain: paymailCfg.userDomain },
|
|
3684
|
+
...paymailCfg?.verifySignature && { verifySignature: true },
|
|
3727
3685
|
messageboxUrl: `http://127.0.0.1:${resolved.port}/messagebox`,
|
|
3728
3686
|
hostPrivateKey: resolved.privateKey
|
|
3729
3687
|
},
|
|
@@ -4867,8 +4825,8 @@ async function walletListOutputs(args, opts) {
|
|
|
4867
4825
|
${result.totalOutputs} total outputs in basket '${basket}':
|
|
4868
4826
|
`);
|
|
4869
4827
|
for (const out of result.outputs) {
|
|
4870
|
-
const
|
|
4871
|
-
console.log(` ${out.outpoint} | ${out.satoshis} sats | tags: ${
|
|
4828
|
+
const tags2 = out.tags?.join(", ") || "none";
|
|
4829
|
+
console.log(` ${out.outpoint} | ${out.satoshis} sats | tags: ${tags2}`);
|
|
4872
4830
|
}
|
|
4873
4831
|
console.log();
|
|
4874
4832
|
}
|
|
@@ -5126,6 +5084,7 @@ var init_wallet = __esm(() => {
|
|
|
5126
5084
|
});
|
|
5127
5085
|
|
|
5128
5086
|
// src/main.ts
|
|
5087
|
+
var exports_main = {};
|
|
5129
5088
|
import { existsSync as existsSync4 } from "node:fs";
|
|
5130
5089
|
import { resolve } from "node:path";
|
|
5131
5090
|
import { config as loadEnv } from "dotenv";
|
|
@@ -5265,4 +5224,4 @@ var init_main = __esm(() => {
|
|
|
5265
5224
|
|
|
5266
5225
|
// src/cli.ts
|
|
5267
5226
|
process.env.DOTENV_CONFIG_QUIET = "true";
|
|
5268
|
-
await Promise.resolve().then(() => (init_main(),
|
|
5227
|
+
await Promise.resolve().then(() => (init_main(), exports_main));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1sat/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.113",
|
|
4
4
|
"description": "CLI for 1Sat Ordinals SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli.js",
|
|
@@ -27,20 +27,20 @@
|
|
|
27
27
|
],
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@1sat/actions": "0.0.
|
|
31
|
-
"@1sat/client": "0.0.
|
|
32
|
-
"@1sat/types": "0.0.
|
|
33
|
-
"@1sat/wallet-node": "0.0.
|
|
34
|
-
"@1sat/wallet-server": "0.0.
|
|
35
|
-
"@
|
|
30
|
+
"@1sat/actions": "0.0.214",
|
|
31
|
+
"@1sat/client": "0.0.52",
|
|
32
|
+
"@1sat/types": "0.0.44",
|
|
33
|
+
"@1sat/wallet-node": "0.0.74",
|
|
34
|
+
"@1sat/wallet-server": "0.0.50",
|
|
35
|
+
"@bopen-io/messagebox-server": "^1.3.2",
|
|
36
|
+
"@bsv/sdk": "^2.5.0",
|
|
36
37
|
"@bsv/wallet-toolbox": "npm:@bopen-io/wallet-toolbox@2.6.2-brc153.5",
|
|
37
|
-
"chalk": "^5.0.0",
|
|
38
38
|
"@clack/prompts": "^0.8.0",
|
|
39
39
|
"bitcoin-backup": "^0.0.11",
|
|
40
|
+
"chalk": "^5.0.0",
|
|
40
41
|
"dotenv": "^17.0.0",
|
|
41
42
|
"evlog": "^2.10.0",
|
|
42
43
|
"knex": "^3.1.0",
|
|
43
|
-
"@bopen-io/messagebox-server": "^1.3.2",
|
|
44
44
|
"pg": "^8.11.3",
|
|
45
45
|
"sqlite3": "^6.0.1"
|
|
46
46
|
},
|
package/src/commands/action.ts
CHANGED
|
@@ -73,6 +73,16 @@ export async function handleActionCommand(
|
|
|
73
73
|
try {
|
|
74
74
|
const result = await action.execute(ctx, input)
|
|
75
75
|
output(result, opts)
|
|
76
|
+
if (
|
|
77
|
+
actionName === 'cancelOwnedListings' &&
|
|
78
|
+
result !== null &&
|
|
79
|
+
typeof result === 'object' &&
|
|
80
|
+
'errors' in result &&
|
|
81
|
+
Array.isArray(result.errors) &&
|
|
82
|
+
result.errors.length > 0
|
|
83
|
+
) {
|
|
84
|
+
process.exitCode = 1
|
|
85
|
+
}
|
|
76
86
|
} finally {
|
|
77
87
|
await destroy()
|
|
78
88
|
}
|
package/src/commands/opns.ts
CHANGED
|
@@ -10,10 +10,9 @@ import {
|
|
|
10
10
|
internalizeOpns,
|
|
11
11
|
listOpns,
|
|
12
12
|
registerOpns,
|
|
13
|
-
sellOpns,
|
|
14
13
|
sendOpns,
|
|
15
14
|
} from '@1sat/actions'
|
|
16
|
-
import { P1SAT_PROTOCOL } from '@1sat/types'
|
|
15
|
+
import { ORDLOCK_LISTING_CREATE_DISABLED, P1SAT_PROTOCOL } from '@1sat/types'
|
|
17
16
|
import { confirm, isCancel } from '@clack/prompts'
|
|
18
17
|
import type { GlobalFlags } from '../args.js'
|
|
19
18
|
import { extractFlag } from '../args.js'
|
|
@@ -194,38 +193,8 @@ async function opnsCancelListingCmd(
|
|
|
194
193
|
}
|
|
195
194
|
}
|
|
196
195
|
|
|
197
|
-
async function opnsSell(
|
|
198
|
-
|
|
199
|
-
const priceStr = extractFlag(args, '--price')
|
|
200
|
-
const payAddress = extractFlag(args, '--pay-address')
|
|
201
|
-
|
|
202
|
-
if (!priceStr) fatal('Missing --price <satoshis>')
|
|
203
|
-
const price = Number(priceStr)
|
|
204
|
-
if (!Number.isFinite(price) || price <= 0) {
|
|
205
|
-
fatal('--price must be a positive number')
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (!opts.yes) {
|
|
209
|
-
const ok = await confirm({
|
|
210
|
-
message: `List OpNS id ${id} for sale at ${price} satoshis?`,
|
|
211
|
-
})
|
|
212
|
-
if (isCancel(ok) || !ok) fatal('Listing cancelled.')
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const privateKey = await loadKey()
|
|
216
|
-
const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
const result = await sellOpns.execute(ctx, {
|
|
220
|
-
id,
|
|
221
|
-
price,
|
|
222
|
-
...(payAddress && { payAddress }),
|
|
223
|
-
})
|
|
224
|
-
if (result.error) fatal(result.error)
|
|
225
|
-
output(opts.json ? result : { txid: result.txid }, opts)
|
|
226
|
-
} finally {
|
|
227
|
-
await destroy()
|
|
228
|
-
}
|
|
196
|
+
async function opnsSell(_args: string[], _opts: GlobalFlags): Promise<void> {
|
|
197
|
+
fatal(ORDLOCK_LISTING_CREATE_DISABLED)
|
|
229
198
|
}
|
|
230
199
|
|
|
231
200
|
async function opnsSend(args: string[], opts: GlobalFlags): Promise<void> {
|
package/src/commands/ordinals.ts
CHANGED
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
getDisplayValue,
|
|
12
12
|
inscribe,
|
|
13
13
|
listOrdinals,
|
|
14
|
-
sellOrdinal,
|
|
15
14
|
sendOrdinals,
|
|
16
15
|
} from '@1sat/actions'
|
|
16
|
+
import { ORDLOCK_LISTING_CREATE_DISABLED } from '@1sat/types'
|
|
17
17
|
import { Utils } from '@bsv/sdk'
|
|
18
18
|
import { confirm, isCancel } from '@clack/prompts'
|
|
19
19
|
import type { GlobalFlags } from '../args.js'
|
|
@@ -245,38 +245,11 @@ async function ordinalsSend(args: string[], opts: GlobalFlags): Promise<void> {
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
async function ordinalsSell(
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (!priceStr) fatal('Missing --price <satoshis>')
|
|
254
|
-
const price = Number(priceStr)
|
|
255
|
-
if (!Number.isFinite(price) || price <= 0) {
|
|
256
|
-
fatal('--price must be a positive number')
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (!opts.yes) {
|
|
260
|
-
const ok = await confirm({
|
|
261
|
-
message: `List ordinal id ${id} for sale at ${price} satoshis?`,
|
|
262
|
-
})
|
|
263
|
-
if (isCancel(ok) || !ok) fatal('Listing cancelled.')
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const privateKey = await loadKey()
|
|
267
|
-
const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
|
|
268
|
-
|
|
269
|
-
try {
|
|
270
|
-
const result = await sellOrdinal.execute(ctx, {
|
|
271
|
-
id,
|
|
272
|
-
price,
|
|
273
|
-
...(payAddress && { payAddress }),
|
|
274
|
-
})
|
|
275
|
-
if (result.error) fatal(result.error)
|
|
276
|
-
output(opts.json ? result : { txid: result.txid }, opts)
|
|
277
|
-
} finally {
|
|
278
|
-
await destroy()
|
|
279
|
-
}
|
|
248
|
+
async function ordinalsSell(
|
|
249
|
+
_args: string[],
|
|
250
|
+
_opts: GlobalFlags,
|
|
251
|
+
): Promise<void> {
|
|
252
|
+
fatal(ORDLOCK_LISTING_CREATE_DISABLED)
|
|
280
253
|
}
|
|
281
254
|
|
|
282
255
|
async function ordinalsCancel(
|
package/src/commands/serve.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from '@1sat/wallet-node'
|
|
27
27
|
import {
|
|
28
28
|
KnexAccountStore,
|
|
29
|
+
KnexHandleCertStore,
|
|
29
30
|
KnexPendingStore,
|
|
30
31
|
createHostServer,
|
|
31
32
|
createWalletServer,
|
|
@@ -298,7 +299,7 @@ async function runWithStorage(
|
|
|
298
299
|
},
|
|
299
300
|
})
|
|
300
301
|
}
|
|
301
|
-
if (r?.enabled
|
|
302
|
+
if (r?.enabled) {
|
|
302
303
|
walletResult.monitor.addTask(
|
|
303
304
|
buildPriceUpdateTask({
|
|
304
305
|
monitor: walletResult.monitor,
|
|
@@ -311,12 +312,16 @@ async function runWithStorage(
|
|
|
311
312
|
minSats: r.minSats ?? 1,
|
|
312
313
|
},
|
|
313
314
|
targets,
|
|
315
|
+
onQuote: async (quote) => {
|
|
316
|
+
setConfigPath('server.exchangeRate', quote)
|
|
317
|
+
},
|
|
314
318
|
}),
|
|
315
319
|
)
|
|
320
|
+
const targetNote =
|
|
321
|
+
targets.map((t) => `${t.name} $${t.targetUsd}`).join(', ') ||
|
|
322
|
+
'quote only'
|
|
316
323
|
console.log(
|
|
317
|
-
`[repricer] enabled — ${
|
|
318
|
-
.map((t) => `${t.name} $${t.targetUsd}`)
|
|
319
|
-
.join(', ')} every ${Math.round(
|
|
324
|
+
`[repricer] enabled — ${targetNote} every ${Math.round(
|
|
320
325
|
(r.intervalMs ?? 900_000) / 1000,
|
|
321
326
|
)}s via ${r.provider ?? 'whatsonchain'}`,
|
|
322
327
|
)
|
|
@@ -401,6 +406,8 @@ async function startWalletServer(
|
|
|
401
406
|
await pendingStore.init()
|
|
402
407
|
const accountStore = new KnexAccountStore(knex)
|
|
403
408
|
await accountStore.init()
|
|
409
|
+
const handleCertStore = new KnexHandleCertStore(knex)
|
|
410
|
+
await handleCertStore.init()
|
|
404
411
|
|
|
405
412
|
const handle = await createHostServer({
|
|
406
413
|
wallet: walletResult.wallet,
|
|
@@ -410,13 +417,17 @@ async function startWalletServer(
|
|
|
410
417
|
listen: { port: resolved.port, host: resolved.host },
|
|
411
418
|
accounts: accounts?.walletServerAccounts,
|
|
412
419
|
accountStore,
|
|
420
|
+
handleCertStore,
|
|
421
|
+
getExchangeRate: () => loadConfig().server?.exchangeRate ?? null,
|
|
413
422
|
paymail: {
|
|
414
423
|
baseUrl:
|
|
415
424
|
paymailCfg?.baseUrl ?? `http://${resolved.host}:${resolved.port}`,
|
|
416
425
|
stackUrl: paymailCfg?.stackUrl ?? resolved.stackUrl,
|
|
417
426
|
pendingStore,
|
|
418
427
|
accountStore,
|
|
428
|
+
certStore: handleCertStore,
|
|
419
429
|
...(paymailCfg?.userDomain && { userDomain: paymailCfg.userDomain }),
|
|
430
|
+
...(paymailCfg?.verifySignature && { verifySignature: true }),
|
|
420
431
|
messageboxUrl: `http://127.0.0.1:${resolved.port}/messagebox`,
|
|
421
432
|
hostPrivateKey: resolved.privateKey,
|
|
422
433
|
},
|
package/src/config.ts
CHANGED
|
@@ -118,6 +118,11 @@ export interface ServerPaymailConfig {
|
|
|
118
118
|
* only resolves when its identity holds an account on this host.
|
|
119
119
|
*/
|
|
120
120
|
userDomain?: string
|
|
121
|
+
/**
|
|
122
|
+
* Require signed P2P metadata on receive-beef / receive-transaction.
|
|
123
|
+
* Advertised as Request Sender Validation on well-known. Default false.
|
|
124
|
+
*/
|
|
125
|
+
verifySignature?: boolean
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
export interface ServerSessionStoreConfig {
|
|
@@ -153,6 +158,12 @@ export interface ServerConfig {
|
|
|
153
158
|
paymail?: ServerPaymailConfig
|
|
154
159
|
/** Shared BSV/USD repricer engine for the accounts storage price. */
|
|
155
160
|
repricer?: RepricerConfig
|
|
161
|
+
/** Last successful BSV/USD quote from the repricer. Served at GET /exchange-rate. */
|
|
162
|
+
exchangeRate?: {
|
|
163
|
+
bsvUsd: number
|
|
164
|
+
timestamp: number
|
|
165
|
+
source: string
|
|
166
|
+
}
|
|
156
167
|
/**
|
|
157
168
|
* Redis-shared BRC-104 sessions. Required when multiple serve instances
|
|
158
169
|
* run behind one load balancer; unset keeps sessions in-memory.
|
package/src/help.ts
CHANGED
|
@@ -393,6 +393,9 @@ export const COMMANDS: CommandSpec[] = [
|
|
|
393
393
|
{
|
|
394
394
|
name: 'sell',
|
|
395
395
|
description: 'List an ordinal for sale (OrdLock)',
|
|
396
|
+
unavailable: true,
|
|
397
|
+
notes:
|
|
398
|
+
'OrdLock listing create is disabled. Buy and cancel of existing listings remain available.',
|
|
396
399
|
args: [
|
|
397
400
|
{ flag: '--id', values: '<tracking-id>', required: true },
|
|
398
401
|
{ flag: '--price', values: '<sats>', required: true },
|
|
@@ -617,6 +620,9 @@ export const COMMANDS: CommandSpec[] = [
|
|
|
617
620
|
{
|
|
618
621
|
name: 'sell',
|
|
619
622
|
description: 'List an OpNS name for sale',
|
|
623
|
+
unavailable: true,
|
|
624
|
+
notes:
|
|
625
|
+
'OrdLock listing create is disabled. Buy and cancel of existing listings remain available.',
|
|
620
626
|
args: [
|
|
621
627
|
{ flag: '--id', values: '<tracking-id>', required: true },
|
|
622
628
|
{ flag: '--price', values: '<satoshis>', required: true },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { computeReprice } from './computeReprice.js'
|
|
2
|
-
import type { RateProvider, RepricerBounds } from './types.js'
|
|
2
|
+
import type { BsvUsdQuote, RateProvider, RepricerBounds } from './types.js'
|
|
3
3
|
|
|
4
4
|
/** One price the repricer maintains from the shared BSV/USD quote. */
|
|
5
5
|
export interface RepriceTarget {
|
|
@@ -20,6 +20,8 @@ export interface PriceUpdateTaskOptions {
|
|
|
20
20
|
intervalMs: number
|
|
21
21
|
bounds: RepricerBounds
|
|
22
22
|
targets: RepriceTarget[]
|
|
23
|
+
/** Called after a successful rate fetch, even when every target is skipped. */
|
|
24
|
+
onQuote?: (quote: BsvUsdQuote) => Promise<void>
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export interface PriceUpdateTask {
|
|
@@ -47,7 +49,7 @@ export function buildPriceUpdateTask(
|
|
|
47
49
|
lastRunMsecsSinceEpoch: 0,
|
|
48
50
|
async asyncSetup() {},
|
|
49
51
|
trigger(now: number): { run: boolean } {
|
|
50
|
-
if (targets.length === 0) return { run: false }
|
|
52
|
+
if (targets.length === 0 && !options.onQuote) return { run: false }
|
|
51
53
|
if (now - this.lastRunMsecsSinceEpoch < intervalMs) return { run: false }
|
|
52
54
|
return { run: true }
|
|
53
55
|
},
|
|
@@ -59,6 +61,14 @@ export function buildPriceUpdateTask(
|
|
|
59
61
|
return `rate fetch failed: ${(err as Error).message}`
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
if (options.onQuote) {
|
|
65
|
+
try {
|
|
66
|
+
await options.onQuote(quote)
|
|
67
|
+
} catch (err) {
|
|
68
|
+
return `quote persist failed: ${(err as Error).message}`
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
62
72
|
const parts: string[] = []
|
|
63
73
|
for (const target of targets) {
|
|
64
74
|
const currentSats = target.readCurrentSats()
|