@1sat/cli 0.0.90 → 0.0.92

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.
@@ -1,23 +1,23 @@
1
1
  /**
2
- * OpNS commands - register, deregister, lookup, sell, buy, cancel-listing.
3
- *
4
- * Manage OpNS names: payment identity bindings and market listings. Paid
5
- * mining is product code on 1sat.name.
2
+ * OpNS commands — id-first wallet spends; external buy with outpoint/BEEF.
6
3
  */
7
4
 
8
5
  import {
9
- cancelListing,
10
- deriveDepositAddresses,
6
+ buyOpns,
7
+ cancelOpnsListing,
8
+ deregisterOpns,
11
9
  getDisplayValue,
12
- getOpnsNames,
13
- listOrdinal,
14
- opnsDeregister as opnsDeregisterAction,
15
- opnsRegister as opnsRegisterAction,
16
- purchaseOrdinal,
10
+ internalizeOpns,
11
+ listOpns,
12
+ registerOpns,
13
+ sellOpns,
14
+ sendOpns,
17
15
  } from '@1sat/actions'
16
+ import { P1SAT_PROTOCOL } from '@1sat/types'
18
17
  import { confirm, isCancel } from '@clack/prompts'
19
18
  import type { GlobalFlags } from '../args'
20
19
  import { extractFlag } from '../args'
20
+ import { idFromTags, parseBeefFlag, parseToFlag } from '../beef'
21
21
  import { loadContext } from '../context'
22
22
  import { printCommandHelp } from '../help'
23
23
  import { loadKey } from '../keys'
@@ -41,7 +41,11 @@ export async function handleOpnsCommand(
41
41
  case 'buy':
42
42
  return opnsBuy(rest, opts)
43
43
  case 'cancel-listing':
44
- return opnsCancelListing(rest, opts)
44
+ return opnsCancelListingCmd(rest, opts)
45
+ case 'send':
46
+ return opnsSend(rest, opts)
47
+ case 'internalize':
48
+ return opnsInternalize(rest, opts)
45
49
  default:
46
50
  printCommandHelp('opns', opts.json)
47
51
  if (subcommand && subcommand !== 'help') {
@@ -50,42 +54,28 @@ export async function handleOpnsCommand(
50
54
  }
51
55
  }
52
56
 
53
- async function opnsRegister(args: string[], opts: GlobalFlags): Promise<void> {
54
- const outpoint = extractFlag(args, '--outpoint')
57
+ function requireId(args: string[]): string {
58
+ const id = extractFlag(args, '--id')
59
+ if (!id) fatal('Missing --id <tracking-id>')
60
+ return id
61
+ }
55
62
 
56
- if (!outpoint) fatal('Missing --outpoint <txid.vout>')
63
+ async function opnsRegister(args: string[], opts: GlobalFlags): Promise<void> {
64
+ const id = requireId(args)
57
65
 
58
66
  if (!opts.yes) {
59
67
  const ok = await confirm({
60
- message: `Register identity on OpNS name ${outpoint}?`,
68
+ message: `Register identity on OpNS id ${id}?`,
61
69
  })
62
- if (isCancel(ok) || !ok) {
63
- fatal('Registration cancelled.')
64
- }
70
+ if (isCancel(ok) || !ok) fatal('Registration cancelled.')
65
71
  }
66
72
 
67
73
  const privateKey = await loadKey()
68
- const { ctx, destroy } = await loadContext(privateKey, {
69
- chain: opts.chain,
70
- })
74
+ const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
71
75
 
72
76
  try {
73
- // Look up the OpNS ordinal from the wallet
74
- const namesResult = await getOpnsNames.execute(ctx, { limit: 10000 })
75
- const ordinal = namesResult.outputs.find((o) => o.outpoint === outpoint)
76
- if (!ordinal) {
77
- fatal(`OpNS name not found in wallet: ${outpoint}`)
78
- }
79
-
80
- const result = await opnsRegisterAction.execute(ctx, {
81
- ordinal,
82
- inputBEEF: namesResult.BEEF as number[] | undefined,
83
- })
84
-
85
- if (result.error) {
86
- fatal(result.error)
87
- }
88
-
77
+ const result = await registerOpns.execute(ctx, { id })
78
+ if (result.error) fatal(result.error)
89
79
  output(opts.json ? result : { txid: result.txid }, opts)
90
80
  } finally {
91
81
  await destroy()
@@ -96,55 +86,55 @@ async function opnsDeregister(
96
86
  args: string[],
97
87
  opts: GlobalFlags,
98
88
  ): Promise<void> {
99
- const outpoint = extractFlag(args, '--outpoint')
100
-
101
- if (!outpoint) fatal('Missing --outpoint <txid.vout>')
89
+ const id = requireId(args)
102
90
 
103
91
  if (!opts.yes) {
104
92
  const ok = await confirm({
105
- message: `Deregister identity from OpNS name ${outpoint}?`,
93
+ message: `Deregister identity from OpNS id ${id}?`,
106
94
  })
107
- if (isCancel(ok) || !ok) {
108
- fatal('Deregistration cancelled.')
109
- }
95
+ if (isCancel(ok) || !ok) fatal('Deregistration cancelled.')
110
96
  }
111
97
 
112
98
  const privateKey = await loadKey()
113
- const { ctx, destroy } = await loadContext(privateKey, {
114
- chain: opts.chain,
115
- })
99
+ const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
116
100
 
117
101
  try {
118
- // Look up the OpNS ordinal from the wallet
119
- const namesResult = await getOpnsNames.execute(ctx, { limit: 10000 })
120
- const ordinal = namesResult.outputs.find((o) => o.outpoint === outpoint)
121
- if (!ordinal) {
122
- fatal(`OpNS name not found in wallet: ${outpoint}`)
123
- }
124
-
125
- const result = await opnsDeregisterAction.execute(ctx, {
126
- ordinal,
127
- inputBEEF: namesResult.BEEF as number[] | undefined,
128
- })
129
-
130
- if (result.error) {
131
- fatal(result.error)
132
- }
133
-
102
+ const result = await deregisterOpns.execute(ctx, { id })
103
+ if (result.error) fatal(result.error)
134
104
  output(opts.json ? result : { txid: result.txid }, opts)
135
105
  } finally {
136
106
  await destroy()
137
107
  }
138
108
  }
139
109
 
140
- async function opnsLookup(_args: string[], opts: GlobalFlags): Promise<void> {
110
+ async function opnsLookup(args: string[], opts: GlobalFlags): Promise<void> {
111
+ const limit = Number(extractFlag(args, '--limit') ?? '100')
112
+ const offset = Number(extractFlag(args, '--offset') ?? '0')
113
+ const names = extractFlag(args, '--names')?.split(',').filter(Boolean)
114
+ const ids = extractFlag(args, '--ids')?.split(',').filter(Boolean)
115
+ const tags = extractFlag(args, '--tags')?.split(',').filter(Boolean)
116
+ const tagQueryMode = extractFlag(args, '--tag-query-mode') as
117
+ | 'all'
118
+ | 'any'
119
+ | undefined
120
+ const include = extractFlag(args, '--include') as
121
+ | 'locking scripts'
122
+ | 'entire transactions'
123
+ | undefined
124
+
141
125
  const privateKey = await loadKey()
142
- const { ctx, destroy } = await loadContext(privateKey, {
143
- chain: opts.chain,
144
- })
126
+ const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
145
127
 
146
128
  try {
147
- const result = await getOpnsNames.execute(ctx, { limit: 100 })
129
+ const result = await listOpns.execute(ctx, {
130
+ limit,
131
+ offset,
132
+ names,
133
+ ids,
134
+ tags,
135
+ tagQueryMode,
136
+ include,
137
+ })
148
138
 
149
139
  if (opts.json) {
150
140
  output(result.outputs, opts)
@@ -157,6 +147,7 @@ async function opnsLookup(_args: string[], opts: GlobalFlags): Promise<void> {
157
147
  }
158
148
 
159
149
  for (const o of result.outputs) {
150
+ const id = idFromTags(o.tags) ?? ''
160
151
  const nameTag = getDisplayValue(o, 'name', 'name') ?? ''
161
152
  const publishedTag = o.tags?.find((t) => t === 'opns:published')
162
153
  const status = publishedTag ? 'registered' : 'unregistered'
@@ -168,7 +159,7 @@ async function opnsLookup(_args: string[], opts: GlobalFlags): Promise<void> {
168
159
  const listed = price ? ` ${formatLabel(`listed @ ${price}`)}` : ''
169
160
 
170
161
  console.log(
171
- ` ${formatValue(o.outpoint)} ${nameTag ? formatValue(nameTag) : ''} ${formatLabel(status)}${listed}`,
162
+ ` ${formatValue(id)} ${formatValue(o.outpoint)} ${nameTag ? formatValue(nameTag) : ''} ${formatLabel(status)}${listed}`,
172
163
  )
173
164
  }
174
165
 
@@ -178,44 +169,25 @@ async function opnsLookup(_args: string[], opts: GlobalFlags): Promise<void> {
178
169
  }
179
170
  }
180
171
 
181
- async function opnsCancelListing(
172
+ async function opnsCancelListingCmd(
182
173
  args: string[],
183
174
  opts: GlobalFlags,
184
175
  ): Promise<void> {
185
- const outpoint = extractFlag(args, '--outpoint')
186
-
187
- if (!outpoint) fatal('Missing --outpoint <txid.vout>')
176
+ const id = requireId(args)
188
177
 
189
178
  if (!opts.yes) {
190
179
  const ok = await confirm({
191
- message: `Cancel listing for OpNS name ${outpoint}?`,
180
+ message: `Cancel listing for OpNS id ${id}?`,
192
181
  })
193
- if (isCancel(ok) || !ok) {
194
- fatal('Cancellation cancelled.')
195
- }
182
+ if (isCancel(ok) || !ok) fatal('Cancellation cancelled.')
196
183
  }
197
184
 
198
185
  const privateKey = await loadKey()
199
- const { ctx, destroy } = await loadContext(privateKey, {
200
- chain: opts.chain,
201
- })
186
+ const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
202
187
 
203
188
  try {
204
- const namesResult = await getOpnsNames.execute(ctx, { limit: 10000 })
205
- const listing = namesResult.outputs.find((o) => o.outpoint === outpoint)
206
- if (!listing) {
207
- fatal(`Listing not found in wallet OpNS basket: ${outpoint}`)
208
- }
209
-
210
- const result = await cancelListing.execute(ctx, {
211
- listing,
212
- inputBEEF: namesResult.BEEF as number[] | undefined,
213
- })
214
-
215
- if (result.error) {
216
- fatal(result.error)
217
- }
218
-
189
+ const result = await cancelOpnsListing.execute(ctx, { id })
190
+ if (result.error) fatal(result.error)
219
191
  output(opts.json ? result : { txid: result.txid }, opts)
220
192
  } finally {
221
193
  await destroy()
@@ -223,13 +195,11 @@ async function opnsCancelListing(
223
195
  }
224
196
 
225
197
  async function opnsSell(args: string[], opts: GlobalFlags): Promise<void> {
226
- const outpoint = extractFlag(args, '--outpoint')
198
+ const id = requireId(args)
227
199
  const priceStr = extractFlag(args, '--price')
228
- const payAddressFlag = extractFlag(args, '--pay-address')
200
+ const payAddress = extractFlag(args, '--pay-address')
229
201
 
230
- if (!outpoint) fatal('Missing --outpoint <txid.vout>')
231
202
  if (!priceStr) fatal('Missing --price <satoshis>')
232
-
233
203
  const price = Number(priceStr)
234
204
  if (!Number.isFinite(price) || price <= 0) {
235
205
  fatal('--price must be a positive number')
@@ -237,48 +207,47 @@ async function opnsSell(args: string[], opts: GlobalFlags): Promise<void> {
237
207
 
238
208
  if (!opts.yes) {
239
209
  const ok = await confirm({
240
- message: `List OpNS name ${outpoint} for sale at ${price} satoshis?`,
210
+ message: `List OpNS id ${id} for sale at ${price} satoshis?`,
241
211
  })
242
- if (isCancel(ok) || !ok) {
243
- fatal('Listing cancelled.')
244
- }
212
+ if (isCancel(ok) || !ok) fatal('Listing cancelled.')
245
213
  }
246
214
 
247
215
  const privateKey = await loadKey()
248
- const { ctx, destroy } = await loadContext(privateKey, {
249
- chain: opts.chain,
250
- })
216
+ const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
251
217
 
252
218
  try {
253
- const namesResult = await getOpnsNames.execute(ctx, { limit: 10000 })
254
- const ordinal = namesResult.outputs.find((o) => o.outpoint === outpoint)
255
- if (!ordinal) {
256
- fatal(`OpNS name not found in wallet: ${outpoint}`)
257
- }
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
+ }
229
+ }
258
230
 
259
- let payAddress = payAddressFlag
260
- if (!payAddress) {
261
- const addressResult = await deriveDepositAddresses.execute(ctx, {
262
- prefix: '1sat',
263
- count: 1,
264
- })
265
- payAddress = addressResult.derivations[0]?.address
266
- if (!payAddress) {
267
- fatal('Failed to derive pay address')
268
- }
269
- }
231
+ async function opnsSend(args: string[], opts: GlobalFlags): Promise<void> {
232
+ const id = requireId(args)
233
+ const to = extractFlag(args, '--to')
234
+ if (!to) fatal('Missing --to <address|identityKey>')
270
235
 
271
- const result = await listOrdinal.execute(ctx, {
272
- ordinal,
273
- price,
274
- payAddress,
275
- inputBEEF: namesResult.BEEF as number[] | undefined,
236
+ const dest = parseToFlag(to)
237
+
238
+ if (!opts.yes) {
239
+ const ok = await confirm({
240
+ message: `Send OpNS id ${id} to ${to}?`,
276
241
  })
242
+ if (isCancel(ok) || !ok) fatal('Send cancelled.')
243
+ }
277
244
 
278
- if (result.error) {
279
- fatal(result.error)
280
- }
245
+ const privateKey = await loadKey()
246
+ const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
281
247
 
248
+ try {
249
+ const result = await sendOpns.execute(ctx, { id, ...dest })
250
+ if (result.error) fatal(result.error)
282
251
  output(opts.json ? result : { txid: result.txid }, opts)
283
252
  } finally {
284
253
  await destroy()
@@ -287,31 +256,63 @@ async function opnsSell(args: string[], opts: GlobalFlags): Promise<void> {
287
256
 
288
257
  async function opnsBuy(args: string[], opts: GlobalFlags): Promise<void> {
289
258
  const outpoint = extractFlag(args, '--outpoint')
259
+ const beef = parseBeefFlag(extractFlag(args, '--beef'))
260
+ const name = extractFlag(args, '--name')
261
+ const origin = extractFlag(args, '--origin')
290
262
 
291
263
  if (!outpoint) fatal('Missing --outpoint <txid.vout>')
292
264
 
293
265
  if (!opts.yes) {
294
266
  const ok = await confirm({
295
- message: `Purchase OpNS name listing ${outpoint}?`,
267
+ message: `Purchase OpNS listing ${outpoint}?`,
296
268
  })
297
- if (isCancel(ok) || !ok) {
298
- fatal('Purchase cancelled.')
299
- }
269
+ if (isCancel(ok) || !ok) fatal('Purchase cancelled.')
300
270
  }
301
271
 
302
272
  const privateKey = await loadKey()
303
- const { ctx, destroy } = await loadContext(privateKey, {
304
- chain: opts.chain,
305
- })
273
+ const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
306
274
 
307
275
  try {
308
- const result = await purchaseOrdinal.execute(ctx, { outpoint })
276
+ const result = await buyOpns.execute(ctx, {
277
+ outpoint,
278
+ ...(beef && { inputBEEF: beef }),
279
+ ...(name && { name }),
280
+ ...(origin && { origin }),
281
+ })
282
+ if (result.error) fatal(result.error)
283
+ output(opts.json ? result : { txid: result.txid }, opts)
284
+ } finally {
285
+ await destroy()
286
+ }
287
+ }
309
288
 
310
- if (result.error) {
311
- fatal(result.error)
312
- }
289
+ async function opnsInternalize(
290
+ args: string[],
291
+ opts: GlobalFlags,
292
+ ): Promise<void> {
293
+ const beef = parseBeefFlag(extractFlag(args, '--beef'))
294
+ const keyID = extractFlag(args, '--key-id') ?? '1sat 0'
313
295
 
314
- output(opts.json ? result : { txid: result.txid }, opts)
296
+ if (!beef) fatal('Missing --beef <file|hex|base64>')
297
+
298
+ if (!opts.yes) {
299
+ const ok = await confirm({
300
+ message: 'Internalize OpNS mint AtomicBEEF into wallet?',
301
+ })
302
+ if (isCancel(ok) || !ok) fatal('Internalize cancelled.')
303
+ }
304
+
305
+ const privateKey = await loadKey()
306
+ const { ctx, destroy } = await loadContext(privateKey, { chain: opts.chain })
307
+
308
+ try {
309
+ const result = await internalizeOpns.execute(ctx, {
310
+ tx: beef,
311
+ protocolID: P1SAT_PROTOCOL,
312
+ keyID,
313
+ })
314
+ if (result.error) fatal(result.error)
315
+ output(opts.json ? result : result, opts)
315
316
  } finally {
316
317
  await destroy()
317
318
  }