@1sat/cli 0.0.110 → 0.0.112
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 +49 -24
- package/package.json +4 -4
- package/src/commands/serve.ts +15 -4
- package/src/config.ts +11 -0
- package/src/repricer/buildPriceUpdateTask.ts +12 -2
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __esm = (fn, res, err) => () => {
|
|
3
|
+
if (fn)
|
|
4
|
+
try {
|
|
5
|
+
res = fn(fn = 0);
|
|
6
|
+
} catch (e) {
|
|
7
|
+
err = [e];
|
|
8
|
+
}
|
|
9
|
+
if (err)
|
|
10
|
+
throw err[0];
|
|
11
|
+
return res;
|
|
12
|
+
};
|
|
5
13
|
|
|
6
14
|
// src/args.ts
|
|
7
15
|
function parseGlobalFlags(args) {
|
|
@@ -505,11 +513,11 @@ async function handleActionCommand(args, opts) {
|
|
|
505
513
|
Registered actions:
|
|
506
514
|
`);
|
|
507
515
|
const grouped = new Map;
|
|
508
|
-
for (const
|
|
509
|
-
const cat =
|
|
516
|
+
for (const action of actions) {
|
|
517
|
+
const cat = action.meta.category;
|
|
510
518
|
if (!grouped.has(cat))
|
|
511
519
|
grouped.set(cat, []);
|
|
512
|
-
grouped.get(cat).push(
|
|
520
|
+
grouped.get(cat).push(action);
|
|
513
521
|
}
|
|
514
522
|
for (const [category, categoryActions] of grouped) {
|
|
515
523
|
console.log(` ${category}:`);
|
|
@@ -1433,7 +1441,7 @@ function createApprovalAuth(wallet) {
|
|
|
1433
1441
|
get(target, property) {
|
|
1434
1442
|
if (property === "createAction")
|
|
1435
1443
|
return async (...args) => {
|
|
1436
|
-
const satoshis = args[0].outputs?.reduce((sum,
|
|
1444
|
+
const satoshis = args[0].outputs?.reduce((sum, output) => sum + output.satoshis, 0) ?? 0;
|
|
1437
1445
|
if (!Number.isSafeInteger(satoshis) || satoshis <= 0)
|
|
1438
1446
|
throw new Error("Invalid HTTP payment amount");
|
|
1439
1447
|
if (approved === false)
|
|
@@ -1957,15 +1965,15 @@ async function handleInitCommand(_args, opts) {
|
|
|
1957
1965
|
}
|
|
1958
1966
|
let wif;
|
|
1959
1967
|
if (keySource === "generate") {
|
|
1960
|
-
const
|
|
1961
|
-
wif =
|
|
1962
|
-
const
|
|
1968
|
+
const pk = PrivateKey2.fromRandom();
|
|
1969
|
+
wif = pk.toWif();
|
|
1970
|
+
const address = pk.toPublicKey().toAddress();
|
|
1963
1971
|
console.log();
|
|
1964
1972
|
console.log(formatWarning(" IMPORTANT: Back up your private key!"));
|
|
1965
1973
|
console.log(formatWarning(" If you lose it, your funds are gone forever."));
|
|
1966
1974
|
console.log();
|
|
1967
1975
|
console.log(` ${formatValue("WIF:")} ${wif}`);
|
|
1968
|
-
console.log(` ${formatValue("Address:")} ${
|
|
1976
|
+
console.log(` ${formatValue("Address:")} ${address}`);
|
|
1969
1977
|
console.log();
|
|
1970
1978
|
const confirmed = await confirm2({
|
|
1971
1979
|
message: "Have you saved your private key somewhere safe?"
|
|
@@ -3381,7 +3389,7 @@ function buildPriceUpdateTask(options) {
|
|
|
3381
3389
|
lastRunMsecsSinceEpoch: 0,
|
|
3382
3390
|
async asyncSetup() {},
|
|
3383
3391
|
trigger(now) {
|
|
3384
|
-
if (targets.length === 0)
|
|
3392
|
+
if (targets.length === 0 && !options.onQuote)
|
|
3385
3393
|
return { run: false };
|
|
3386
3394
|
if (now - this.lastRunMsecsSinceEpoch < intervalMs)
|
|
3387
3395
|
return { run: false };
|
|
@@ -3394,6 +3402,13 @@ function buildPriceUpdateTask(options) {
|
|
|
3394
3402
|
} catch (err) {
|
|
3395
3403
|
return `rate fetch failed: ${err.message}`;
|
|
3396
3404
|
}
|
|
3405
|
+
if (options.onQuote) {
|
|
3406
|
+
try {
|
|
3407
|
+
await options.onQuote(quote);
|
|
3408
|
+
} catch (err) {
|
|
3409
|
+
return `quote persist failed: ${err.message}`;
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3397
3412
|
const parts = [];
|
|
3398
3413
|
for (const target of targets) {
|
|
3399
3414
|
const currentSats = target.readCurrentSats();
|
|
@@ -3490,6 +3505,7 @@ import {
|
|
|
3490
3505
|
} from "@1sat/wallet-node";
|
|
3491
3506
|
import {
|
|
3492
3507
|
KnexAccountStore,
|
|
3508
|
+
KnexHandleCertStore,
|
|
3493
3509
|
KnexPendingStore,
|
|
3494
3510
|
createHostServer,
|
|
3495
3511
|
createWalletServer
|
|
@@ -3636,7 +3652,7 @@ async function runWithStorage(resolved, mode) {
|
|
|
3636
3652
|
}
|
|
3637
3653
|
});
|
|
3638
3654
|
}
|
|
3639
|
-
if (r?.enabled
|
|
3655
|
+
if (r?.enabled) {
|
|
3640
3656
|
walletResult.monitor.addTask(buildPriceUpdateTask({
|
|
3641
3657
|
monitor: walletResult.monitor,
|
|
3642
3658
|
rateProvider: resolveRateProvider(r.provider ?? "whatsonchain", {
|
|
@@ -3647,9 +3663,13 @@ async function runWithStorage(resolved, mode) {
|
|
|
3647
3663
|
maxMovePct: r.maxMovePct ?? 25,
|
|
3648
3664
|
minSats: r.minSats ?? 1
|
|
3649
3665
|
},
|
|
3650
|
-
targets
|
|
3666
|
+
targets,
|
|
3667
|
+
onQuote: async (quote) => {
|
|
3668
|
+
setConfigPath("server.exchangeRate", quote);
|
|
3669
|
+
}
|
|
3651
3670
|
}));
|
|
3652
|
-
|
|
3671
|
+
const targetNote = targets.map((t) => `${t.name} $${t.targetUsd}`).join(", ") || "quote only";
|
|
3672
|
+
console.log(`[repricer] enabled — ${targetNote} every ${Math.round((r.intervalMs ?? 900000) / 1000)}s via ${r.provider ?? "whatsonchain"}`);
|
|
3653
3673
|
}
|
|
3654
3674
|
}
|
|
3655
3675
|
if (runMonitor) {
|
|
@@ -3679,7 +3699,7 @@ async function startWalletServer(resolved, walletResult, accounts, mode) {
|
|
|
3679
3699
|
ttlSeconds: sessionStoreCfg.ttlSeconds
|
|
3680
3700
|
} : undefined;
|
|
3681
3701
|
if (mode === "wallet") {
|
|
3682
|
-
const
|
|
3702
|
+
const handle = createWalletServer({
|
|
3683
3703
|
wallet: walletResult.wallet,
|
|
3684
3704
|
storage: walletResult.getActiveStorage(),
|
|
3685
3705
|
serverIdentityKey: walletResult.wallet.identityKey,
|
|
@@ -3689,10 +3709,10 @@ async function startWalletServer(resolved, walletResult, accounts, mode) {
|
|
|
3689
3709
|
accounts: accounts?.walletServerAccounts,
|
|
3690
3710
|
sessionStore
|
|
3691
3711
|
});
|
|
3692
|
-
const
|
|
3693
|
-
const
|
|
3694
|
-
console.log(`[wallet] listening on ${resolved.host}:${
|
|
3695
|
-
return { stop: () =>
|
|
3712
|
+
const port = await handle.start();
|
|
3713
|
+
const notes = [resolved.accounts.enabled ? "accounts: on" : ""].filter(Boolean).join(", ");
|
|
3714
|
+
console.log(`[wallet] listening on ${resolved.host}:${port}${notes ? ` (${notes})` : ""}`);
|
|
3715
|
+
return { stop: () => handle.stop() };
|
|
3696
3716
|
}
|
|
3697
3717
|
const serverCfg = config.server ?? {};
|
|
3698
3718
|
const paymailCfg = serverCfg.paymail;
|
|
@@ -3702,6 +3722,8 @@ async function startWalletServer(resolved, walletResult, accounts, mode) {
|
|
|
3702
3722
|
await pendingStore.init();
|
|
3703
3723
|
const accountStore = new KnexAccountStore(knex);
|
|
3704
3724
|
await accountStore.init();
|
|
3725
|
+
const handleCertStore = new KnexHandleCertStore(knex);
|
|
3726
|
+
await handleCertStore.init();
|
|
3705
3727
|
const handle = await createHostServer({
|
|
3706
3728
|
wallet: walletResult.wallet,
|
|
3707
3729
|
sessionStore,
|
|
@@ -3710,12 +3732,16 @@ async function startWalletServer(resolved, walletResult, accounts, mode) {
|
|
|
3710
3732
|
listen: { port: resolved.port, host: resolved.host },
|
|
3711
3733
|
accounts: accounts?.walletServerAccounts,
|
|
3712
3734
|
accountStore,
|
|
3735
|
+
handleCertStore,
|
|
3736
|
+
getExchangeRate: () => loadConfig().server?.exchangeRate ?? null,
|
|
3713
3737
|
paymail: {
|
|
3714
3738
|
baseUrl: paymailCfg?.baseUrl ?? `http://${resolved.host}:${resolved.port}`,
|
|
3715
3739
|
stackUrl: paymailCfg?.stackUrl ?? resolved.stackUrl,
|
|
3716
3740
|
pendingStore,
|
|
3717
3741
|
accountStore,
|
|
3742
|
+
certStore: handleCertStore,
|
|
3718
3743
|
...paymailCfg?.userDomain && { userDomain: paymailCfg.userDomain },
|
|
3744
|
+
...paymailCfg?.verifySignature && { verifySignature: true },
|
|
3719
3745
|
messageboxUrl: `http://127.0.0.1:${resolved.port}/messagebox`,
|
|
3720
3746
|
hostPrivateKey: resolved.privateKey
|
|
3721
3747
|
},
|
|
@@ -4859,8 +4885,8 @@ async function walletListOutputs(args, opts) {
|
|
|
4859
4885
|
${result.totalOutputs} total outputs in basket '${basket}':
|
|
4860
4886
|
`);
|
|
4861
4887
|
for (const out of result.outputs) {
|
|
4862
|
-
const
|
|
4863
|
-
console.log(` ${out.outpoint} | ${out.satoshis} sats | tags: ${
|
|
4888
|
+
const tags = out.tags?.join(", ") || "none";
|
|
4889
|
+
console.log(` ${out.outpoint} | ${out.satoshis} sats | tags: ${tags}`);
|
|
4864
4890
|
}
|
|
4865
4891
|
console.log();
|
|
4866
4892
|
}
|
|
@@ -5118,7 +5144,6 @@ var init_wallet = __esm(() => {
|
|
|
5118
5144
|
});
|
|
5119
5145
|
|
|
5120
5146
|
// src/main.ts
|
|
5121
|
-
var exports_main = {};
|
|
5122
5147
|
import { existsSync as existsSync4 } from "node:fs";
|
|
5123
5148
|
import { resolve } from "node:path";
|
|
5124
5149
|
import { config as loadEnv } from "dotenv";
|
|
@@ -5258,4 +5283,4 @@ var init_main = __esm(() => {
|
|
|
5258
5283
|
|
|
5259
5284
|
// src/cli.ts
|
|
5260
5285
|
process.env.DOTENV_CONFIG_QUIET = "true";
|
|
5261
|
-
await Promise.resolve().then(() => (init_main(),
|
|
5286
|
+
await Promise.resolve().then(() => (init_main(), {}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1sat/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.112",
|
|
4
4
|
"description": "CLI for 1Sat Ordinals SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli.js",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
],
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@1sat/actions": "0.0.
|
|
30
|
+
"@1sat/actions": "0.0.211",
|
|
31
31
|
"@1sat/client": "0.0.51",
|
|
32
|
-
"@1sat/types": "0.0.
|
|
32
|
+
"@1sat/types": "0.0.43",
|
|
33
33
|
"@1sat/wallet-node": "0.0.73",
|
|
34
|
-
"@1sat/wallet-server": "0.0.
|
|
34
|
+
"@1sat/wallet-server": "0.0.49",
|
|
35
35
|
"@bsv/sdk": "^2.1.9",
|
|
36
36
|
"@bsv/wallet-toolbox": "npm:@bopen-io/wallet-toolbox@2.6.2-brc153.5",
|
|
37
37
|
"chalk": "^5.0.0",
|
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.
|
|
@@ -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()
|