@1sat/actions 0.0.190 → 0.0.191
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/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/inscriptions/index.d.ts +2 -2
- package/dist/inscriptions/index.d.ts.map +1 -1
- package/dist/inscriptions/index.js +3 -6
- package/dist/inscriptions/index.js.map +1 -1
- package/dist/locks/index.d.ts +32 -3
- package/dist/locks/index.d.ts.map +1 -1
- package/dist/locks/index.js +76 -5
- package/dist/locks/index.js.map +1 -1
- package/dist/opns/index.d.ts +69 -76
- package/dist/opns/index.d.ts.map +1 -1
- package/dist/opns/index.js +432 -234
- package/dist/opns/index.js.map +1 -1
- package/dist/ordinals/index.d.ts +76 -42
- package/dist/ordinals/index.d.ts.map +1 -1
- package/dist/ordinals/index.js +219 -180
- package/dist/ordinals/index.js.map +1 -1
- package/dist/tokens/index.d.ts +5 -1
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +36 -18
- package/dist/tokens/index.js.map +1 -1
- package/dist/utils/createTrackedAction.js +1 -1
- package/dist/utils/internalizeBeef.d.ts.map +1 -1
- package/dist/utils/internalizeBeef.js +1 -25
- package/dist/utils/internalizeBeef.js.map +1 -1
- package/dist/utils/loadBasketOutput.d.ts +25 -0
- package/dist/utils/loadBasketOutput.d.ts.map +1 -0
- package/dist/utils/loadBasketOutput.js +50 -0
- package/dist/utils/loadBasketOutput.js.map +1 -0
- package/dist/utils/ordinalSeedTags.d.ts +8 -0
- package/dist/utils/ordinalSeedTags.d.ts.map +1 -0
- package/dist/utils/ordinalSeedTags.js +24 -0
- package/dist/utils/ordinalSeedTags.js.map +1 -0
- package/package.json +9 -9
- package/dist/utils/resolveBeef.d.ts +0 -20
- package/dist/utils/resolveBeef.d.ts.map +0 -1
- package/dist/utils/resolveBeef.js +0 -36
- package/dist/utils/resolveBeef.js.map +0 -1
package/dist/opns/index.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpNS Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Wallet-owned names live in OPNS_BASKET with id: tags.
|
|
5
|
+
* Self-moves: id → one loadBasketOutputBeef → ordinalSeedTags + domain tags.
|
|
6
|
+
* Ingress (internalizeOpns / buyOpns) stamps full tags including id:.
|
|
7
7
|
*/
|
|
8
|
-
import { OpNS } from '@1sat/templates';
|
|
9
|
-
import { OPNS_BASKET, OPNS_PUBLISHED_TAG, OPNS_PUSHDROP_TEMPLATE, OPNS_REGISTER_COUNTERPARTY, P1SAT_PROTOCOL, opnsRegisterKeyId, } from '@1sat/types';
|
|
10
|
-
import { PushDrop, Transaction, Utils, } from '@bsv/sdk';
|
|
11
|
-
import {
|
|
8
|
+
import { OpNS, OrdLock } from '@1sat/templates';
|
|
9
|
+
import { OPNS_BASKET, OPNS_PUBLISHED_TAG, OPNS_PUSHDROP_TEMPLATE, OPNS_REGISTER_COUNTERPARTY, P1SAT_PROTOCOL, buildInputAssetLabel, opnsRegisterKeyId, readAssetIdTag, } from '@1sat/types';
|
|
10
|
+
import { P2PKH, PublicKey, PushDrop, Transaction, Utils, } from '@bsv/sdk';
|
|
11
|
+
import { buildOrdLockScript, buyOrdinal, defaultPayAddress, deriveCancelAddressInternal, } from '../ordinals';
|
|
12
12
|
import { executeTrackedAction, randomActionId, } from '../utils/createTrackedAction';
|
|
13
|
-
import {
|
|
13
|
+
import { loadBasketOutputBeef } from '../utils/loadBasketOutput';
|
|
14
|
+
import { ordinalSeedTags } from '../utils/ordinalSeedTags';
|
|
14
15
|
import { signOrdinalInput, unlockingScriptLengthForInstructions, } from '../utils/signOrdinalInput';
|
|
16
|
+
const OPNS_CONTENT_TYPE = 'application/op-ns';
|
|
15
17
|
export { opnsRegisterKeyId } from '@1sat/types';
|
|
16
|
-
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Helpers
|
|
20
|
+
// ============================================================================
|
|
17
21
|
function findMintNameDelivery(tx) {
|
|
18
22
|
for (let i = 0; i + 2 < tx.outputs.length; i++) {
|
|
19
23
|
const parent = OpNS.decode(tx.outputs[i].lockingScript);
|
|
@@ -27,79 +31,59 @@ function findMintNameDelivery(tx) {
|
|
|
27
31
|
}
|
|
28
32
|
return null;
|
|
29
33
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
function nameFromOutput(out) {
|
|
35
|
+
const fromTag = out.tags?.find((t) => t.startsWith('name:'))?.slice(5);
|
|
36
|
+
if (fromTag)
|
|
37
|
+
return fromTag.slice(0, 64);
|
|
38
|
+
if (!out.customInstructions)
|
|
39
|
+
return undefined;
|
|
40
|
+
try {
|
|
41
|
+
const n = JSON.parse(out.customInstructions).name;
|
|
42
|
+
return typeof n === 'string' && n ? n.slice(0, 64) : undefined;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
41
46
|
}
|
|
42
|
-
return ordinal.tags?.find((t) => t.startsWith('name:'))?.slice(5);
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
/** Load OPNS row + BEEF from wallet storage by id. */
|
|
49
|
+
async function loadOpnsSpend(ctx, input) {
|
|
50
|
+
return loadBasketOutputBeef(ctx.wallet, OPNS_BASKET, input.id);
|
|
51
|
+
}
|
|
52
|
+
/** Ordinal seed + opns domain tag; optional extras (ordlock, published, …). */
|
|
53
|
+
function opnsFileTags(output, extra = []) {
|
|
54
|
+
const tags = ordinalSeedTags(output);
|
|
55
|
+
if (!tags.includes('opns'))
|
|
56
|
+
tags.unshift('opns');
|
|
57
|
+
for (const e of extra) {
|
|
58
|
+
if (e && !tags.includes(e))
|
|
59
|
+
tags.push(e);
|
|
47
60
|
}
|
|
48
|
-
return
|
|
49
|
-
sign: async (tx) => {
|
|
50
|
-
const unlocking = await signOrdinalInput(ctx, tx, 0, ordinal.customInstructions);
|
|
51
|
-
if (typeof unlocking !== 'string')
|
|
52
|
-
throw new Error(unlocking.error);
|
|
53
|
-
return { 0: { unlockingScript: unlocking } };
|
|
54
|
-
},
|
|
55
|
-
};
|
|
61
|
+
return tags;
|
|
56
62
|
}
|
|
57
63
|
// ============================================================================
|
|
58
|
-
//
|
|
64
|
+
// listOpns
|
|
59
65
|
// ============================================================================
|
|
60
|
-
|
|
61
|
-
* List OpNS names in the wallet. Mirrors listOutputs (fixed OPNS basket).
|
|
62
|
-
* Metadata-only by default; pass include: 'entire transactions' for batch BEEF.
|
|
63
|
-
*/
|
|
64
|
-
export const getOpnsNames = {
|
|
66
|
+
export const listOpns = {
|
|
65
67
|
meta: {
|
|
66
|
-
name: '
|
|
68
|
+
name: 'listOpns',
|
|
67
69
|
description: 'List OpNS names from the wallet (metadata by default; optional BEEF)',
|
|
68
70
|
category: 'opns',
|
|
69
71
|
inputSchema: {
|
|
70
72
|
type: 'object',
|
|
71
73
|
properties: {
|
|
72
|
-
tags: {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
tagQueryMode: {
|
|
78
|
-
type: 'string',
|
|
79
|
-
enum: ['all', 'any'],
|
|
80
|
-
description: 'How tags combine (default any when filtering)',
|
|
81
|
-
},
|
|
82
|
-
names: {
|
|
83
|
-
type: 'array',
|
|
84
|
-
description: 'Appended as name:${n} tags',
|
|
85
|
-
items: { type: 'string' },
|
|
86
|
-
},
|
|
74
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
75
|
+
tagQueryMode: { type: 'string', enum: ['all', 'any'] },
|
|
76
|
+
names: { type: 'array', items: { type: 'string' } },
|
|
77
|
+
ids: { type: 'array', items: { type: 'string' } },
|
|
87
78
|
include: {
|
|
88
79
|
type: 'string',
|
|
89
80
|
enum: ['locking scripts', 'entire transactions'],
|
|
90
|
-
description: 'Omit for metadata-only (no BEEF)',
|
|
91
81
|
},
|
|
92
82
|
includeCustomInstructions: { type: 'boolean' },
|
|
93
83
|
includeTags: { type: 'boolean' },
|
|
94
84
|
includeLabels: { type: 'boolean' },
|
|
95
|
-
limit: {
|
|
96
|
-
|
|
97
|
-
description: 'Max names to return (default: 100)',
|
|
98
|
-
},
|
|
99
|
-
offset: {
|
|
100
|
-
type: 'integer',
|
|
101
|
-
description: 'Offset for pagination (default: 0)',
|
|
102
|
-
},
|
|
85
|
+
limit: { type: 'integer' },
|
|
86
|
+
offset: { type: 'integer' },
|
|
103
87
|
},
|
|
104
88
|
},
|
|
105
89
|
},
|
|
@@ -109,6 +93,10 @@ export const getOpnsNames = {
|
|
|
109
93
|
if (n)
|
|
110
94
|
tags.push(`name:${n}`);
|
|
111
95
|
}
|
|
96
|
+
for (const id of input.ids ?? []) {
|
|
97
|
+
if (id)
|
|
98
|
+
tags.push(id.startsWith('id:') ? id : `id:${id}`);
|
|
99
|
+
}
|
|
112
100
|
const filtering = tags.length > 0;
|
|
113
101
|
const result = await ctx.wallet.listOutputs({
|
|
114
102
|
basket: OPNS_BASKET,
|
|
@@ -132,51 +120,40 @@ export const getOpnsNames = {
|
|
|
132
120
|
};
|
|
133
121
|
},
|
|
134
122
|
};
|
|
135
|
-
/**
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
123
|
+
/** @deprecated Use listOpns */
|
|
124
|
+
export const getOpnsNames = listOpns;
|
|
125
|
+
// ============================================================================
|
|
126
|
+
// internalizeOpns (ingress)
|
|
127
|
+
// ============================================================================
|
|
139
128
|
export const internalizeOpns = {
|
|
140
129
|
meta: {
|
|
141
130
|
name: 'internalizeOpns',
|
|
142
|
-
description: 'Internalize a foreign-created OpNS mint into the
|
|
131
|
+
description: 'Internalize a foreign-created OpNS mint (AtomicBEEF) into the OPNS basket',
|
|
143
132
|
category: 'opns',
|
|
144
133
|
inputSchema: {
|
|
145
134
|
type: 'object',
|
|
146
135
|
properties: {
|
|
147
|
-
tx: {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
},
|
|
152
|
-
protocolID: {
|
|
153
|
-
type: 'array',
|
|
154
|
-
description: 'Wallet protocol for spend derivation',
|
|
155
|
-
},
|
|
156
|
-
keyID: {
|
|
157
|
-
type: 'string',
|
|
158
|
-
description: 'Key ID for spend derivation',
|
|
159
|
-
},
|
|
160
|
-
counterparty: {
|
|
161
|
-
type: 'string',
|
|
162
|
-
description: 'Counterparty for spend derivation (default self)',
|
|
163
|
-
},
|
|
136
|
+
tx: { type: 'array', items: { type: 'integer' } },
|
|
137
|
+
protocolID: { type: 'array' },
|
|
138
|
+
keyID: { type: 'string' },
|
|
139
|
+
counterparty: { type: 'string' },
|
|
164
140
|
},
|
|
165
141
|
required: ['tx', 'protocolID', 'keyID'],
|
|
166
142
|
},
|
|
167
143
|
},
|
|
168
|
-
async execute(
|
|
144
|
+
async execute(ctx, input) {
|
|
169
145
|
try {
|
|
170
146
|
const parsed = Transaction.fromAtomicBEEF(input.tx);
|
|
171
147
|
const txid = parsed.id('hex');
|
|
172
148
|
const delivery = findMintNameDelivery(parsed);
|
|
173
|
-
if (!delivery)
|
|
149
|
+
if (!delivery)
|
|
174
150
|
return { error: 'not-an-opns-mint' };
|
|
175
|
-
}
|
|
176
151
|
const { vout, name } = delivery;
|
|
152
|
+
const outpoint = `${txid}.${vout}`;
|
|
177
153
|
const actionId = randomActionId();
|
|
154
|
+
const idTag = `id:${actionId}_${vout}`;
|
|
178
155
|
const counterparty = input.counterparty ?? 'self';
|
|
179
|
-
await
|
|
156
|
+
await ctx.wallet.internalizeAction({
|
|
180
157
|
tx: input.tx,
|
|
181
158
|
outputs: [
|
|
182
159
|
{
|
|
@@ -184,7 +161,13 @@ export const internalizeOpns = {
|
|
|
184
161
|
protocol: 'basket insertion',
|
|
185
162
|
insertionRemittance: {
|
|
186
163
|
basket: OPNS_BASKET,
|
|
187
|
-
tags: [
|
|
164
|
+
tags: [
|
|
165
|
+
'opns',
|
|
166
|
+
`type:${OPNS_CONTENT_TYPE}`,
|
|
167
|
+
`origin:${outpoint}`,
|
|
168
|
+
`name:${name}`,
|
|
169
|
+
idTag,
|
|
170
|
+
],
|
|
188
171
|
customInstructions: JSON.stringify({
|
|
189
172
|
protocolID: input.protocolID,
|
|
190
173
|
keyID: input.keyID,
|
|
@@ -198,8 +181,9 @@ export const internalizeOpns = {
|
|
|
198
181
|
});
|
|
199
182
|
return {
|
|
200
183
|
txid,
|
|
201
|
-
outpoint
|
|
184
|
+
outpoint,
|
|
202
185
|
name,
|
|
186
|
+
id: `${actionId}_${vout}`,
|
|
203
187
|
};
|
|
204
188
|
}
|
|
205
189
|
catch (err) {
|
|
@@ -209,58 +193,50 @@ export const internalizeOpns = {
|
|
|
209
193
|
}
|
|
210
194
|
},
|
|
211
195
|
};
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
* fields[0] = identity pubkey bytes; field-sig included (same derivation).
|
|
217
|
-
*/
|
|
218
|
-
export const opnsRegister = {
|
|
196
|
+
// ============================================================================
|
|
197
|
+
// register / deregister
|
|
198
|
+
// ============================================================================
|
|
199
|
+
export const registerOpns = {
|
|
219
200
|
meta: {
|
|
220
|
-
name: '
|
|
201
|
+
name: 'registerOpns',
|
|
221
202
|
description: 'Bind BRC-100 identity key to an OpNS name via signed PushDrop',
|
|
222
203
|
category: 'opns',
|
|
223
204
|
inputSchema: {
|
|
224
205
|
type: 'object',
|
|
225
206
|
properties: {
|
|
226
|
-
|
|
227
|
-
type: 'object',
|
|
228
|
-
description: 'WalletOutput of the OpNS ordinal from listOutputs',
|
|
229
|
-
},
|
|
230
|
-
inputBEEF: {
|
|
231
|
-
type: 'array',
|
|
232
|
-
description: "BEEF from listOutputs with include: 'entire transactions'",
|
|
233
|
-
},
|
|
207
|
+
id: { type: 'string', description: 'OPNS basket tracking id' },
|
|
234
208
|
},
|
|
235
|
-
required: ['
|
|
209
|
+
required: ['id'],
|
|
236
210
|
},
|
|
237
211
|
},
|
|
238
212
|
async execute(ctx, input) {
|
|
239
213
|
try {
|
|
240
|
-
const
|
|
241
|
-
if (
|
|
214
|
+
const loaded = await loadOpnsSpend(ctx, input);
|
|
215
|
+
if ('error' in loaded)
|
|
216
|
+
return loaded;
|
|
217
|
+
const { output, beef } = loaded;
|
|
218
|
+
if (!output.customInstructions) {
|
|
242
219
|
return { error: 'missing-custom-instructions' };
|
|
243
220
|
}
|
|
244
|
-
const inputBEEF = input.inputBEEF ??
|
|
245
|
-
(await resolveBeef(ctx.wallet, OPNS_BASKET, ordinal));
|
|
246
221
|
const { publicKey: identityPubKey } = await ctx.wallet.getPublicKey({
|
|
247
222
|
identityKey: true,
|
|
248
223
|
});
|
|
249
|
-
const keyID = opnsRegisterKeyId(
|
|
224
|
+
const keyID = opnsRegisterKeyId(output.outpoint);
|
|
250
225
|
const lockingScript = await new PushDrop(ctx.wallet).lock([Utils.toArray(identityPubKey, 'hex')], P1SAT_PROTOCOL, keyID, OPNS_REGISTER_COUNTERPARTY, true, true);
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const name = sourceNameFromOrdinal(ordinal);
|
|
256
|
-
const result = await executeTrackedAction(ctx.wallet, {
|
|
226
|
+
const name = nameFromOutput(output);
|
|
227
|
+
const tags = opnsFileTags(output, [OPNS_PUBLISHED_TAG]);
|
|
228
|
+
const inputId = readAssetIdTag(output.tags);
|
|
229
|
+
return await executeTrackedAction(ctx.wallet, {
|
|
257
230
|
description: 'Register OpNS identity bind',
|
|
258
|
-
inputBEEF,
|
|
231
|
+
inputBEEF: beef,
|
|
232
|
+
...(inputId && {
|
|
233
|
+
labels: [buildInputAssetLabel(OPNS_BASKET, inputId)],
|
|
234
|
+
}),
|
|
259
235
|
inputs: [
|
|
260
236
|
{
|
|
261
|
-
outpoint:
|
|
237
|
+
outpoint: output.outpoint,
|
|
262
238
|
inputDescription: 'OpNS name to register',
|
|
263
|
-
unlockingScriptLength: unlockingScriptLengthForInstructions(
|
|
239
|
+
unlockingScriptLength: unlockingScriptLengthForInstructions(output.customInstructions),
|
|
264
240
|
},
|
|
265
241
|
],
|
|
266
242
|
outputs: [
|
|
@@ -280,186 +256,408 @@ export const opnsRegister = {
|
|
|
280
256
|
},
|
|
281
257
|
],
|
|
282
258
|
options: { randomizeOutputs: false },
|
|
283
|
-
}, input.fundingProvider,
|
|
284
|
-
const unlocking = await signOrdinalInput(ctx, tx, 0,
|
|
259
|
+
}, input.fundingProvider, beef, async (tx) => {
|
|
260
|
+
const unlocking = await signOrdinalInput(ctx, tx, 0, output.customInstructions);
|
|
285
261
|
if (typeof unlocking !== 'string')
|
|
286
262
|
throw new Error(unlocking.error);
|
|
287
263
|
return { 0: { unlockingScript: unlocking } };
|
|
288
264
|
});
|
|
289
|
-
return result;
|
|
290
265
|
}
|
|
291
266
|
catch (error) {
|
|
292
|
-
console.error('[
|
|
293
|
-
if (ctx.debug && ctx.log) {
|
|
294
|
-
ctx.log({
|
|
295
|
-
timestamp: new Date().toISOString(),
|
|
296
|
-
action: 'opnsRegister',
|
|
297
|
-
input: { outpoint: input.ordinal.outpoint },
|
|
298
|
-
error: error instanceof Error ? error.message : 'unknown-error',
|
|
299
|
-
});
|
|
300
|
-
}
|
|
267
|
+
console.error('[registerOpns]', error);
|
|
301
268
|
return {
|
|
302
269
|
error: error instanceof Error ? error.message : 'unknown-error',
|
|
303
270
|
};
|
|
304
271
|
}
|
|
305
272
|
},
|
|
306
273
|
};
|
|
307
|
-
/**
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
*/
|
|
311
|
-
export const opnsDeregister = {
|
|
274
|
+
/** @deprecated Use registerOpns */
|
|
275
|
+
export const opnsRegister = registerOpns;
|
|
276
|
+
export const deregisterOpns = {
|
|
312
277
|
meta: {
|
|
313
|
-
name: '
|
|
278
|
+
name: 'deregisterOpns',
|
|
314
279
|
description: 'Remove identity bind from an OpNS name (self-transfer to P2PKH)',
|
|
315
280
|
category: 'opns',
|
|
316
281
|
inputSchema: {
|
|
317
282
|
type: 'object',
|
|
318
283
|
properties: {
|
|
319
|
-
|
|
320
|
-
type: 'object',
|
|
321
|
-
description: 'WalletOutput of the OpNS ordinal from listOutputs',
|
|
322
|
-
},
|
|
323
|
-
inputBEEF: {
|
|
324
|
-
type: 'array',
|
|
325
|
-
description: "BEEF from listOutputs with include: 'entire transactions'",
|
|
326
|
-
},
|
|
284
|
+
id: { type: 'string' },
|
|
327
285
|
},
|
|
328
|
-
required: ['
|
|
286
|
+
required: ['id'],
|
|
329
287
|
},
|
|
330
288
|
},
|
|
331
289
|
async execute(ctx, input) {
|
|
332
290
|
try {
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
291
|
+
const loaded = await loadOpnsSpend(ctx, input);
|
|
292
|
+
if ('error' in loaded)
|
|
293
|
+
return loaded;
|
|
294
|
+
const { output, beef } = loaded;
|
|
295
|
+
if (!output.customInstructions) {
|
|
296
|
+
return { error: 'missing-custom-instructions' };
|
|
297
|
+
}
|
|
298
|
+
const outpoint = output.outpoint;
|
|
299
|
+
const { publicKey } = await ctx.wallet.getPublicKey({
|
|
300
|
+
protocolID: P1SAT_PROTOCOL,
|
|
301
|
+
keyID: outpoint,
|
|
302
|
+
counterparty: 'self',
|
|
303
|
+
forSelf: true,
|
|
304
|
+
});
|
|
305
|
+
const address = PublicKey.fromString(publicKey).toAddress();
|
|
306
|
+
const tags = opnsFileTags(output);
|
|
307
|
+
const name = nameFromOutput(output);
|
|
308
|
+
const inputId = readAssetIdTag(output.tags);
|
|
309
|
+
return await executeTrackedAction(ctx.wallet, {
|
|
310
|
+
description: 'Deregister OpNS identity bind',
|
|
311
|
+
inputBEEF: beef,
|
|
312
|
+
...(inputId && {
|
|
313
|
+
labels: [buildInputAssetLabel(OPNS_BASKET, inputId)],
|
|
314
|
+
}),
|
|
315
|
+
inputs: [
|
|
337
316
|
{
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
317
|
+
outpoint,
|
|
318
|
+
inputDescription: 'OpNS name to deregister',
|
|
319
|
+
unlockingScriptLength: unlockingScriptLengthForInstructions(output.customInstructions),
|
|
341
320
|
},
|
|
342
321
|
],
|
|
343
|
-
|
|
322
|
+
outputs: [
|
|
323
|
+
{
|
|
324
|
+
lockingScript: new P2PKH().lock(address).toHex(),
|
|
325
|
+
satoshis: 1,
|
|
326
|
+
outputDescription: 'OpNS name (unbound)',
|
|
327
|
+
basket: OPNS_BASKET,
|
|
328
|
+
tags,
|
|
329
|
+
customInstructions: JSON.stringify({
|
|
330
|
+
protocolID: P1SAT_PROTOCOL,
|
|
331
|
+
keyID: outpoint,
|
|
332
|
+
...(name && { name }),
|
|
333
|
+
}),
|
|
334
|
+
},
|
|
335
|
+
],
|
|
336
|
+
options: { randomizeOutputs: false },
|
|
337
|
+
}, input.fundingProvider, beef, async (tx) => {
|
|
338
|
+
const unlocking = await signOrdinalInput(ctx, tx, 0, output.customInstructions);
|
|
339
|
+
if (typeof unlocking !== 'string')
|
|
340
|
+
throw new Error(unlocking.error);
|
|
341
|
+
return { 0: { unlockingScript: unlocking } };
|
|
344
342
|
});
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
console.error('[deregisterOpns]', error);
|
|
346
|
+
return {
|
|
347
|
+
error: error instanceof Error ? error.message : 'unknown-error',
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
/** @deprecated Use deregisterOpns */
|
|
353
|
+
export const opnsDeregister = deregisterOpns;
|
|
354
|
+
// ============================================================================
|
|
355
|
+
// sell / send / cancel
|
|
356
|
+
// ============================================================================
|
|
357
|
+
export const sellOpns = {
|
|
358
|
+
meta: {
|
|
359
|
+
name: 'sellOpns',
|
|
360
|
+
description: 'List an OpNS name for sale',
|
|
361
|
+
category: 'opns',
|
|
362
|
+
inputSchema: {
|
|
363
|
+
type: 'object',
|
|
364
|
+
properties: {
|
|
365
|
+
id: { type: 'string' },
|
|
366
|
+
price: { type: 'integer' },
|
|
367
|
+
payAddress: {
|
|
368
|
+
type: 'string',
|
|
369
|
+
description: 'Payment address (default: P1SAT keyID 1sat 0)',
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
required: ['id', 'price'],
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
async execute(ctx, input) {
|
|
376
|
+
try {
|
|
377
|
+
if (input.price <= 0)
|
|
378
|
+
return { error: 'invalid-price' };
|
|
379
|
+
const loaded = await loadOpnsSpend(ctx, input);
|
|
380
|
+
if ('error' in loaded)
|
|
381
|
+
return loaded;
|
|
382
|
+
const { output, beef } = loaded;
|
|
383
|
+
if (!output.customInstructions) {
|
|
384
|
+
return { error: 'missing-custom-instructions' };
|
|
351
385
|
}
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
386
|
+
const outpoint = output.outpoint;
|
|
387
|
+
const payAddress = input.payAddress ?? (await defaultPayAddress(ctx));
|
|
388
|
+
const cancelAddress = await deriveCancelAddressInternal(ctx, outpoint);
|
|
389
|
+
const lockingScript = buildOrdLockScript(cancelAddress, payAddress, input.price).toHex();
|
|
390
|
+
const tags = opnsFileTags(output, ['ordlock', `price:${input.price}`]);
|
|
391
|
+
const name = nameFromOutput(output);
|
|
392
|
+
const inputId = readAssetIdTag(output.tags);
|
|
355
393
|
return await executeTrackedAction(ctx.wallet, {
|
|
356
|
-
|
|
357
|
-
|
|
394
|
+
description: `List OpNS for ${input.price} sats`,
|
|
395
|
+
inputBEEF: beef,
|
|
396
|
+
...(inputId && {
|
|
397
|
+
labels: [buildInputAssetLabel(OPNS_BASKET, inputId)],
|
|
398
|
+
}),
|
|
399
|
+
inputs: [
|
|
400
|
+
{
|
|
401
|
+
outpoint,
|
|
402
|
+
inputDescription: 'OpNS name to list',
|
|
403
|
+
unlockingScriptLength: unlockingScriptLengthForInstructions(output.customInstructions),
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
outputs: [
|
|
407
|
+
{
|
|
408
|
+
lockingScript,
|
|
409
|
+
satoshis: 1,
|
|
410
|
+
outputDescription: `List OpNS for ${input.price} sats`,
|
|
411
|
+
basket: OPNS_BASKET,
|
|
412
|
+
tags,
|
|
413
|
+
customInstructions: JSON.stringify({
|
|
414
|
+
protocolID: P1SAT_PROTOCOL,
|
|
415
|
+
keyID: outpoint,
|
|
416
|
+
...(name && { name }),
|
|
417
|
+
}),
|
|
418
|
+
},
|
|
419
|
+
],
|
|
358
420
|
options: { randomizeOutputs: false },
|
|
359
|
-
}, input.fundingProvider,
|
|
421
|
+
}, input.fundingProvider, beef, async (tx) => {
|
|
422
|
+
const unlocking = await signOrdinalInput(ctx, tx, 0, output.customInstructions);
|
|
423
|
+
if (typeof unlocking !== 'string')
|
|
424
|
+
throw new Error(unlocking.error);
|
|
425
|
+
return { 0: { unlockingScript: unlocking } };
|
|
426
|
+
});
|
|
360
427
|
}
|
|
361
428
|
catch (error) {
|
|
362
|
-
console.error('[
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
429
|
+
console.error('[sellOpns]', error);
|
|
430
|
+
return {
|
|
431
|
+
error: error instanceof Error ? error.message : 'unknown-error',
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
};
|
|
436
|
+
/** @deprecated Use sellOpns */
|
|
437
|
+
export const opnsList = sellOpns;
|
|
438
|
+
export const sendOpns = {
|
|
439
|
+
meta: {
|
|
440
|
+
name: 'sendOpns',
|
|
441
|
+
description: 'Transfer an OpNS name to a new owner',
|
|
442
|
+
category: 'opns',
|
|
443
|
+
inputSchema: {
|
|
444
|
+
type: 'object',
|
|
445
|
+
properties: {
|
|
446
|
+
id: { type: 'string' },
|
|
447
|
+
counterparty: { type: 'string' },
|
|
448
|
+
address: { type: 'string' },
|
|
449
|
+
},
|
|
450
|
+
required: ['id'],
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
async execute(ctx, input) {
|
|
454
|
+
try {
|
|
455
|
+
if (!input.counterparty && !input.address) {
|
|
456
|
+
return { error: 'must-provide-counterparty-or-address' };
|
|
457
|
+
}
|
|
458
|
+
const loaded = await loadOpnsSpend(ctx, input);
|
|
459
|
+
if ('error' in loaded)
|
|
460
|
+
return loaded;
|
|
461
|
+
const { output, beef } = loaded;
|
|
462
|
+
if (!output.customInstructions) {
|
|
463
|
+
return { error: 'missing-custom-instructions' };
|
|
464
|
+
}
|
|
465
|
+
const outpoint = output.outpoint;
|
|
466
|
+
const isSelf = input.counterparty === 'self';
|
|
467
|
+
let recipientAddress;
|
|
468
|
+
if (input.counterparty) {
|
|
469
|
+
const { publicKey } = await ctx.wallet.getPublicKey({
|
|
470
|
+
protocolID: P1SAT_PROTOCOL,
|
|
471
|
+
keyID: outpoint,
|
|
472
|
+
counterparty: input.counterparty,
|
|
473
|
+
forSelf: isSelf,
|
|
369
474
|
});
|
|
475
|
+
recipientAddress = PublicKey.fromString(publicKey).toAddress();
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
recipientAddress = input.address;
|
|
370
479
|
}
|
|
480
|
+
const inputId = readAssetIdTag(output.tags);
|
|
481
|
+
const name = nameFromOutput(output);
|
|
482
|
+
const tags = opnsFileTags(output);
|
|
483
|
+
return await executeTrackedAction(ctx.wallet, {
|
|
484
|
+
description: 'Transfer OpNS name',
|
|
485
|
+
inputBEEF: beef,
|
|
486
|
+
...(inputId && {
|
|
487
|
+
labels: [buildInputAssetLabel(OPNS_BASKET, inputId)],
|
|
488
|
+
}),
|
|
489
|
+
inputs: [
|
|
490
|
+
{
|
|
491
|
+
outpoint,
|
|
492
|
+
inputDescription: 'OpNS name to transfer',
|
|
493
|
+
unlockingScriptLength: unlockingScriptLengthForInstructions(output.customInstructions),
|
|
494
|
+
},
|
|
495
|
+
],
|
|
496
|
+
outputs: [
|
|
497
|
+
isSelf
|
|
498
|
+
? {
|
|
499
|
+
lockingScript: new P2PKH().lock(recipientAddress).toHex(),
|
|
500
|
+
satoshis: 1,
|
|
501
|
+
outputDescription: 'OpNS self-transfer',
|
|
502
|
+
basket: OPNS_BASKET,
|
|
503
|
+
tags,
|
|
504
|
+
customInstructions: JSON.stringify({
|
|
505
|
+
protocolID: P1SAT_PROTOCOL,
|
|
506
|
+
keyID: outpoint,
|
|
507
|
+
...(name && { name }),
|
|
508
|
+
}),
|
|
509
|
+
}
|
|
510
|
+
: {
|
|
511
|
+
lockingScript: new P2PKH().lock(recipientAddress).toHex(),
|
|
512
|
+
satoshis: 1,
|
|
513
|
+
outputDescription: 'OpNS transfer',
|
|
514
|
+
tags: [],
|
|
515
|
+
},
|
|
516
|
+
],
|
|
517
|
+
options: { randomizeOutputs: false },
|
|
518
|
+
}, input.fundingProvider, beef, async (tx) => {
|
|
519
|
+
const unlocking = await signOrdinalInput(ctx, tx, 0, output.customInstructions);
|
|
520
|
+
if (typeof unlocking !== 'string')
|
|
521
|
+
throw new Error(unlocking.error);
|
|
522
|
+
return { 0: { unlockingScript: unlocking } };
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
catch (error) {
|
|
526
|
+
console.error('[sendOpns]', error);
|
|
371
527
|
return {
|
|
372
528
|
error: error instanceof Error ? error.message : 'unknown-error',
|
|
373
529
|
};
|
|
374
530
|
}
|
|
375
531
|
},
|
|
376
532
|
};
|
|
377
|
-
/**
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
*/
|
|
381
|
-
export const opnsList = {
|
|
533
|
+
/** @deprecated Use sendOpns */
|
|
534
|
+
export const opnsTransfer = sendOpns;
|
|
535
|
+
export const cancelOpnsListing = {
|
|
382
536
|
meta: {
|
|
383
|
-
name: '
|
|
384
|
-
description: '
|
|
537
|
+
name: 'cancelOpnsListing',
|
|
538
|
+
description: 'Cancel an OpNS name listing back into the OPNS basket',
|
|
385
539
|
category: 'opns',
|
|
386
540
|
inputSchema: {
|
|
387
541
|
type: 'object',
|
|
388
542
|
properties: {
|
|
389
|
-
|
|
390
|
-
type: 'object',
|
|
391
|
-
description: 'WalletOutput of the OpNS ordinal from listOutputs',
|
|
392
|
-
},
|
|
393
|
-
inputBEEF: {
|
|
394
|
-
type: 'array',
|
|
395
|
-
description: "BEEF from listOutputs with include: 'entire transactions'",
|
|
396
|
-
},
|
|
397
|
-
price: { type: 'integer', description: 'Price in satoshis' },
|
|
398
|
-
payAddress: {
|
|
399
|
-
type: 'string',
|
|
400
|
-
description: 'Address to receive payment on purchase',
|
|
401
|
-
},
|
|
543
|
+
id: { type: 'string' },
|
|
402
544
|
},
|
|
403
|
-
required: ['
|
|
545
|
+
required: ['id'],
|
|
404
546
|
},
|
|
405
547
|
},
|
|
406
548
|
async execute(ctx, input) {
|
|
407
|
-
|
|
549
|
+
try {
|
|
550
|
+
const loaded = await loadOpnsSpend(ctx, input);
|
|
551
|
+
if ('error' in loaded)
|
|
552
|
+
return loaded;
|
|
553
|
+
const { output: listing, beef: inputBEEF } = loaded;
|
|
554
|
+
const outpoint = listing.outpoint;
|
|
555
|
+
if (!listing.customInstructions) {
|
|
556
|
+
return { error: 'missing-custom-instructions' };
|
|
557
|
+
}
|
|
558
|
+
const { protocolID: signProtocolID, keyID: signKeyID, counterparty: signCounterparty, } = JSON.parse(listing.customInstructions);
|
|
559
|
+
const newKeyID = outpoint;
|
|
560
|
+
const cancelAddress = await deriveCancelAddressInternal(ctx, newKeyID);
|
|
561
|
+
const tags = opnsFileTags(listing);
|
|
562
|
+
const name = nameFromOutput(listing);
|
|
563
|
+
const inputId = readAssetIdTag(listing.tags);
|
|
564
|
+
const cancelUnlock = OrdLock.cancelWithWallet(ctx.wallet, signProtocolID, signKeyID, signCounterparty);
|
|
565
|
+
return await executeTrackedAction(ctx.wallet, {
|
|
566
|
+
description: 'Cancel OpNS listing',
|
|
567
|
+
inputBEEF,
|
|
568
|
+
...(inputId && {
|
|
569
|
+
labels: [buildInputAssetLabel(OPNS_BASKET, inputId)],
|
|
570
|
+
}),
|
|
571
|
+
inputs: [
|
|
572
|
+
{
|
|
573
|
+
outpoint,
|
|
574
|
+
inputDescription: 'Listed OpNS name',
|
|
575
|
+
unlockingScriptLength: 108,
|
|
576
|
+
},
|
|
577
|
+
],
|
|
578
|
+
outputs: [
|
|
579
|
+
{
|
|
580
|
+
lockingScript: new P2PKH().lock(cancelAddress).toHex(),
|
|
581
|
+
satoshis: 1,
|
|
582
|
+
outputDescription: 'Cancelled OpNS listing',
|
|
583
|
+
basket: OPNS_BASKET,
|
|
584
|
+
tags,
|
|
585
|
+
customInstructions: JSON.stringify({
|
|
586
|
+
protocolID: P1SAT_PROTOCOL,
|
|
587
|
+
keyID: newKeyID,
|
|
588
|
+
...(name && { name }),
|
|
589
|
+
}),
|
|
590
|
+
},
|
|
591
|
+
],
|
|
592
|
+
options: { randomizeOutputs: false },
|
|
593
|
+
}, input.fundingProvider, inputBEEF, async (tx) => {
|
|
594
|
+
const unlockingScript = await cancelUnlock.sign(tx, 0);
|
|
595
|
+
return { 0: { unlockingScript: unlockingScript.toHex() } };
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
catch (error) {
|
|
599
|
+
console.error('[cancelOpnsListing]', error);
|
|
600
|
+
return {
|
|
601
|
+
error: error instanceof Error ? error.message : 'unknown-error',
|
|
602
|
+
};
|
|
603
|
+
}
|
|
408
604
|
},
|
|
409
605
|
};
|
|
606
|
+
/** @deprecated Use cancelOpnsListing */
|
|
607
|
+
export const opnsCancelListing = cancelOpnsListing;
|
|
410
608
|
/**
|
|
411
|
-
*
|
|
412
|
-
* Spends the current lock; recipient gets plain P2PKH (bind does not carry forward).
|
|
609
|
+
* Buy an OpNS listing and file into the OPNS basket with full tags.
|
|
413
610
|
*/
|
|
414
|
-
export const
|
|
611
|
+
export const buyOpns = {
|
|
415
612
|
meta: {
|
|
416
|
-
name: '
|
|
417
|
-
description: '
|
|
613
|
+
name: 'buyOpns',
|
|
614
|
+
description: 'Purchase an OpNS name listing into the OPNS basket',
|
|
418
615
|
category: 'opns',
|
|
616
|
+
requiresServices: true,
|
|
419
617
|
inputSchema: {
|
|
420
618
|
type: 'object',
|
|
421
619
|
properties: {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
},
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
description: 'Recipient identity public key (hex)',
|
|
429
|
-
},
|
|
430
|
-
address: {
|
|
431
|
-
type: 'string',
|
|
432
|
-
description: 'Recipient P2PKH address',
|
|
433
|
-
},
|
|
434
|
-
inputBEEF: {
|
|
435
|
-
type: 'array',
|
|
436
|
-
description: "BEEF from listOutputs with include: 'entire transactions'",
|
|
437
|
-
},
|
|
620
|
+
outpoint: { type: 'string' },
|
|
621
|
+
inputBEEF: { type: 'array', items: { type: 'integer' } },
|
|
622
|
+
name: { type: 'string' },
|
|
623
|
+
origin: { type: 'string' },
|
|
624
|
+
marketplaceAddress: { type: 'string' },
|
|
625
|
+
marketplaceRate: { type: 'number' },
|
|
438
626
|
},
|
|
439
|
-
required: ['
|
|
627
|
+
required: ['outpoint'],
|
|
440
628
|
},
|
|
441
629
|
},
|
|
442
630
|
async execute(ctx, input) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
631
|
+
const name = input.name?.slice(0, 64);
|
|
632
|
+
const origin = input.origin ?? input.outpoint;
|
|
633
|
+
const tags = [
|
|
634
|
+
'opns',
|
|
635
|
+
`type:${OPNS_CONTENT_TYPE}`,
|
|
636
|
+
`origin:${origin}`,
|
|
637
|
+
...(name ? [`name:${name}`] : []),
|
|
638
|
+
];
|
|
639
|
+
return buyOrdinal.execute(ctx, {
|
|
640
|
+
outpoint: input.outpoint,
|
|
451
641
|
inputBEEF: input.inputBEEF,
|
|
642
|
+
marketplaceAddress: input.marketplaceAddress,
|
|
643
|
+
marketplaceRate: input.marketplaceRate,
|
|
644
|
+
name,
|
|
645
|
+
origin,
|
|
646
|
+
contentType: OPNS_CONTENT_TYPE,
|
|
452
647
|
fundingProvider: input.fundingProvider,
|
|
648
|
+
basket: OPNS_BASKET,
|
|
649
|
+
tags,
|
|
453
650
|
});
|
|
454
651
|
},
|
|
455
652
|
};
|
|
456
|
-
/** All OpNS actions for registry (paid mine lives on 1sat.name / orchestrator). */
|
|
457
653
|
export const opnsActions = [
|
|
458
|
-
|
|
654
|
+
listOpns,
|
|
459
655
|
internalizeOpns,
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
656
|
+
registerOpns,
|
|
657
|
+
deregisterOpns,
|
|
658
|
+
sellOpns,
|
|
659
|
+
sendOpns,
|
|
660
|
+
cancelOpnsListing,
|
|
661
|
+
buyOpns,
|
|
464
662
|
];
|
|
465
663
|
//# sourceMappingURL=index.js.map
|