@1sat/actions 0.0.197 → 0.0.199
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/apply/applyIntent.d.ts +7 -15
- package/dist/apply/applyIntent.d.ts.map +1 -1
- package/dist/apply/applyIntent.js +76 -25
- package/dist/apply/applyIntent.js.map +1 -1
- package/dist/apply/index.d.ts +1 -1
- package/dist/apply/index.d.ts.map +1 -1
- package/dist/apply/index.js +1 -1
- package/dist/apply/index.js.map +1 -1
- package/dist/apply/inscribeSigma.d.ts +1 -1
- package/dist/apply/inscribeSigma.d.ts.map +1 -1
- package/dist/apply/inscribeSigma.js +20 -13
- package/dist/apply/inscribeSigma.js.map +1 -1
- package/dist/apply/prepare.d.ts +12 -7
- package/dist/apply/prepare.d.ts.map +1 -1
- package/dist/apply/prepare.js +3 -21
- package/dist/apply/prepare.js.map +1 -1
- package/dist/apply/registry.d.ts +3 -2
- package/dist/apply/registry.d.ts.map +1 -1
- package/dist/apply/registry.js +7 -26
- package/dist/apply/registry.js.map +1 -1
- package/dist/apply/stampScriptTags.d.ts.map +1 -1
- package/dist/apply/stampScriptTags.js +8 -1
- package/dist/apply/stampScriptTags.js.map +1 -1
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/collections/index.js +77 -51
- package/dist/collections/index.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/cosign/finalize.js +1 -2
- package/dist/cosign/finalize.js.map +1 -1
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/inscriptions/index.d.ts.map +1 -1
- package/dist/inscriptions/index.js +34 -39
- package/dist/inscriptions/index.js.map +1 -1
- package/dist/locks/index.d.ts +1 -1
- package/dist/locks/index.d.ts.map +1 -1
- package/dist/locks/index.js +28 -13
- package/dist/locks/index.js.map +1 -1
- package/dist/opns/index.d.ts.map +1 -1
- package/dist/opns/index.js +60 -50
- package/dist/opns/index.js.map +1 -1
- package/dist/ordinals/index.d.ts +1 -2
- package/dist/ordinals/index.d.ts.map +1 -1
- package/dist/ordinals/index.js +84 -93
- package/dist/ordinals/index.js.map +1 -1
- package/dist/pipeline/index.d.ts +4 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +4 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/runPipeline.d.ts +30 -0
- package/dist/pipeline/runPipeline.d.ts.map +1 -0
- package/dist/pipeline/runPipeline.js +82 -0
- package/dist/pipeline/runPipeline.js.map +1 -0
- package/dist/pipeline/spendTargets.d.ts +52 -0
- package/dist/pipeline/spendTargets.d.ts.map +1 -0
- package/dist/pipeline/spendTargets.js +87 -0
- package/dist/pipeline/spendTargets.js.map +1 -0
- package/dist/pipeline/unlockInput.d.ts +49 -0
- package/dist/pipeline/unlockInput.d.ts.map +1 -0
- package/dist/pipeline/unlockInput.js +316 -0
- package/dist/pipeline/unlockInput.js.map +1 -0
- package/dist/signing/index.d.ts +1 -1
- package/dist/signing/index.d.ts.map +1 -1
- package/dist/signing/index.js +1 -1
- package/dist/signing/index.js.map +1 -1
- package/dist/signing/sigma.d.ts +13 -17
- package/dist/signing/sigma.d.ts.map +1 -1
- package/dist/signing/sigma.js +37 -40
- package/dist/signing/sigma.js.map +1 -1
- package/dist/sweep/index.d.ts.map +1 -1
- package/dist/sweep/index.js +20 -17
- package/dist/sweep/index.js.map +1 -1
- package/dist/sync/syncCosignDeliveries.d.ts.map +1 -1
- package/dist/sync/syncCosignDeliveries.js +30 -20
- package/dist/sync/syncCosignDeliveries.js.map +1 -1
- package/dist/tokens/index.d.ts +8 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +246 -174
- package/dist/tokens/index.js.map +1 -1
- package/dist/types.d.ts +16 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/bsv21Remittance.d.ts +63 -0
- package/dist/utils/bsv21Remittance.d.ts.map +1 -0
- package/dist/utils/bsv21Remittance.js +146 -0
- package/dist/utils/bsv21Remittance.js.map +1 -0
- package/dist/utils/bsv21Remittance.test.d.ts +2 -0
- package/dist/utils/bsv21Remittance.test.d.ts.map +1 -0
- package/dist/utils/bsv21Remittance.test.js +115 -0
- package/dist/utils/bsv21Remittance.test.js.map +1 -0
- package/dist/utils/createTrackedAction.d.ts +42 -38
- package/dist/utils/createTrackedAction.d.ts.map +1 -1
- package/dist/utils/createTrackedAction.js +147 -79
- package/dist/utils/createTrackedAction.js.map +1 -1
- package/dist/utils/hasOneSatModule.d.ts +14 -0
- package/dist/utils/hasOneSatModule.d.ts.map +1 -0
- package/dist/utils/hasOneSatModule.js +31 -0
- package/dist/utils/hasOneSatModule.js.map +1 -0
- package/dist/utils/internalizeBeef.d.ts.map +1 -1
- package/dist/utils/internalizeBeef.js +37 -12
- package/dist/utils/internalizeBeef.js.map +1 -1
- package/dist/utils/loadBasketOutput.d.ts +1 -1
- package/dist/utils/loadBasketOutput.d.ts.map +1 -1
- package/dist/utils/loadBasketOutput.js +11 -3
- package/dist/utils/loadBasketOutput.js.map +1 -1
- package/dist/utils/moveBasket.d.ts +37 -0
- package/dist/utils/moveBasket.d.ts.map +1 -0
- package/dist/utils/moveBasket.js +115 -0
- package/dist/utils/moveBasket.js.map +1 -0
- package/dist/utils/ordinalRemittance.d.ts +33 -0
- package/dist/utils/ordinalRemittance.d.ts.map +1 -0
- package/dist/utils/ordinalRemittance.js +70 -0
- package/dist/utils/ordinalRemittance.js.map +1 -0
- package/dist/utils/ordinalSeedTags.d.ts +5 -3
- package/dist/utils/ordinalSeedTags.d.ts.map +1 -1
- package/dist/utils/ordinalSeedTags.js +34 -7
- package/dist/utils/ordinalSeedTags.js.map +1 -1
- package/dist/utils/resolveDestination.d.ts +3 -6
- package/dist/utils/resolveDestination.d.ts.map +1 -1
- package/dist/utils/resolveDestination.js +5 -1
- package/dist/utils/resolveDestination.js.map +1 -1
- package/dist/utils/signOrdinalInput.d.ts +3 -2
- package/dist/utils/signOrdinalInput.d.ts.map +1 -1
- package/dist/utils/signOrdinalInput.js +18 -13
- package/dist/utils/signOrdinalInput.js.map +1 -1
- package/dist/utils/stampBsv21OutputCi.d.ts +16 -0
- package/dist/utils/stampBsv21OutputCi.d.ts.map +1 -0
- package/dist/utils/stampBsv21OutputCi.js +90 -0
- package/dist/utils/stampBsv21OutputCi.js.map +1 -0
- package/dist/utils/stampOrdinalOutputCi.d.ts +15 -0
- package/dist/utils/stampOrdinalOutputCi.d.ts.map +1 -0
- package/dist/utils/stampOrdinalOutputCi.js +103 -0
- package/dist/utils/stampOrdinalOutputCi.js.map +1 -0
- package/dist/utils/walletMetadataCi.d.ts +23 -0
- package/dist/utils/walletMetadataCi.d.ts.map +1 -0
- package/dist/utils/walletMetadataCi.js +70 -0
- package/dist/utils/walletMetadataCi.js.map +1 -0
- package/package.json +7 -7
package/dist/tokens/index.js
CHANGED
|
@@ -4,27 +4,63 @@
|
|
|
4
4
|
* Actions for managing BSV21 tokens.
|
|
5
5
|
*/
|
|
6
6
|
import { BSV21, OrdLock, P2MS } from '@1sat/templates';
|
|
7
|
-
import { BSV21_DEPLOY_TAG,
|
|
7
|
+
import { BSV21_DEPLOY_TAG, buildInputAssetLabel, buildTokenLabel, readAssetIdTag, } from '@1sat/types';
|
|
8
8
|
import { parseOutpoint } from '@1sat/utils';
|
|
9
9
|
import { BigNumber, LockingScript, OP, P2PKH, PublicKey, TransactionSignature, UnlockingScript, Utils, } from '@bsv/sdk';
|
|
10
10
|
import { prepareP1SatArgs } from '../apply';
|
|
11
|
-
import {
|
|
11
|
+
import { BSV21_AUTH_TAG, BSV21_BASKET, P1SAT_PROTOCOL, } from '../constants';
|
|
12
12
|
import { executeTrackedAction } from '../utils/createTrackedAction';
|
|
13
13
|
import { getDisplayValue } from '../utils/displayValue';
|
|
14
|
+
import { bsv21FieldsFromOutput, bsv21FilterTags, buildBsv21CustomInstructions, normalizeBsv21TokenId, } from '../utils/bsv21Remittance';
|
|
14
15
|
import { resolveDestination } from '../utils/resolveDestination';
|
|
15
16
|
import { signP2PKHInput } from '../utils/signP2PKH';
|
|
16
|
-
/** tokenId
|
|
17
|
+
/** tokenId: CI `id` → tag `bsv21:<id>` → deploy outpoint. */
|
|
17
18
|
function tokenIdFromOutput(o) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
return undefined;
|
|
19
|
+
return bsv21FieldsFromOutput({
|
|
20
|
+
tags: o.tags,
|
|
21
|
+
customInstructions: o.customInstructions,
|
|
22
|
+
outpoint: o.outpoint,
|
|
23
|
+
}).tokenId;
|
|
25
24
|
}
|
|
26
25
|
function matchesTokenId(o, tokenId) {
|
|
27
|
-
|
|
26
|
+
const id = tokenIdFromOutput(o);
|
|
27
|
+
if (!id)
|
|
28
|
+
return false;
|
|
29
|
+
return normalizeBsv21TokenId(id) === normalizeBsv21TokenId(tokenId);
|
|
30
|
+
}
|
|
31
|
+
function amtFromOutput(o) {
|
|
32
|
+
return bsv21FieldsFromOutput({
|
|
33
|
+
tags: o.tags,
|
|
34
|
+
customInstructions: o.customInstructions,
|
|
35
|
+
outpoint: o.outpoint,
|
|
36
|
+
}).amt;
|
|
37
|
+
}
|
|
38
|
+
/** Value tips only — skip pure auth rows in balances. */
|
|
39
|
+
function isBalanceableBsv21Output(o) {
|
|
40
|
+
const f = bsv21FieldsFromOutput({
|
|
41
|
+
tags: o.tags,
|
|
42
|
+
customInstructions: o.customInstructions,
|
|
43
|
+
outpoint: o.outpoint,
|
|
44
|
+
});
|
|
45
|
+
// Auth-only UTXOs (not deploy+mint value)
|
|
46
|
+
if (f.isAuth && !f.isDeploy)
|
|
47
|
+
return false;
|
|
48
|
+
const op = parseBsv21Op(o);
|
|
49
|
+
if (op === 'auth' || op === 'deploy+auth')
|
|
50
|
+
return false;
|
|
51
|
+
return !!f.amt && f.amt !== '0';
|
|
52
|
+
}
|
|
53
|
+
function parseBsv21Op(o) {
|
|
54
|
+
const ci = o.customInstructions;
|
|
55
|
+
if (!ci)
|
|
56
|
+
return undefined;
|
|
57
|
+
try {
|
|
58
|
+
const op = JSON.parse(ci).op;
|
|
59
|
+
return typeof op === 'string' ? op : undefined;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
28
64
|
}
|
|
29
65
|
// ============================================================================
|
|
30
66
|
// Internal helpers
|
|
@@ -121,14 +157,21 @@ export const getBsv21Balances = {
|
|
|
121
157
|
const outputs = await listTokensInternal(ctx);
|
|
122
158
|
const balanceMap = new Map();
|
|
123
159
|
for (const o of outputs) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
160
|
+
if (!isBalanceableBsv21Output(o))
|
|
161
|
+
continue;
|
|
162
|
+
const fields = bsv21FieldsFromOutput({
|
|
163
|
+
tags: o.tags,
|
|
164
|
+
customInstructions: o.customInstructions,
|
|
165
|
+
outpoint: o.outpoint,
|
|
166
|
+
});
|
|
167
|
+
const tokenId = fields.tokenId;
|
|
168
|
+
const amtStr = fields.amt;
|
|
169
|
+
if (!tokenId || !amtStr)
|
|
127
170
|
continue;
|
|
128
|
-
const amt = BigInt(
|
|
129
|
-
const dec = Number.parseInt(
|
|
130
|
-
const symTag = getDisplayValue(o, 'sym', 'sym');
|
|
131
|
-
const rawIcon =
|
|
171
|
+
const amt = BigInt(amtStr);
|
|
172
|
+
const dec = Number.parseInt(fields.dec || '0', 10);
|
|
173
|
+
const symTag = fields.sym ?? getDisplayValue(o, 'sym', 'sym');
|
|
174
|
+
const rawIcon = fields.icon;
|
|
132
175
|
const icon = rawIcon?.startsWith('_')
|
|
133
176
|
? `${tokenId.split('_')[0]}${rawIcon}`
|
|
134
177
|
: rawIcon;
|
|
@@ -189,6 +232,10 @@ export const sendBsv21 = {
|
|
|
189
232
|
required: ['amount', 'destination'],
|
|
190
233
|
},
|
|
191
234
|
},
|
|
235
|
+
validateOverlay: {
|
|
236
|
+
type: 'boolean',
|
|
237
|
+
description: 'Default true. When true, require active token + per-input overlay unspent check (hard fail). When false, spend wallet tips only.',
|
|
238
|
+
},
|
|
192
239
|
},
|
|
193
240
|
required: ['tokenId', 'recipients'],
|
|
194
241
|
},
|
|
@@ -211,14 +258,32 @@ export const sendBsv21 = {
|
|
|
211
258
|
resolved.push({ amount, destination: r.destination });
|
|
212
259
|
}
|
|
213
260
|
const totalAmount = resolved.reduce((sum, r) => sum + r.amount, 0n);
|
|
214
|
-
|
|
215
|
-
|
|
261
|
+
const validateOverlay = input.validateOverlay !== false;
|
|
262
|
+
let tokenDetails;
|
|
263
|
+
if (validateOverlay) {
|
|
264
|
+
if (!ctx.services?.bsv21) {
|
|
265
|
+
return { error: 'services-required' };
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
tokenDetails = await ctx.services.bsv21.getTokenDetails(tokenId);
|
|
269
|
+
}
|
|
270
|
+
catch (e) {
|
|
271
|
+
console.error('[sendBsv21] getTokenDetails failed:', e);
|
|
272
|
+
return { error: 'token-not-found' };
|
|
273
|
+
}
|
|
274
|
+
if (!tokenDetails.status.is_active) {
|
|
275
|
+
return { error: 'token-not-active' };
|
|
276
|
+
}
|
|
216
277
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
278
|
+
else if (ctx.services?.bsv21) {
|
|
279
|
+
// Best-effort meta/fees only — never gate the send.
|
|
280
|
+
try {
|
|
281
|
+
tokenDetails = await ctx.services.bsv21.getTokenDetails(tokenId);
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
tokenDetails = undefined;
|
|
285
|
+
}
|
|
220
286
|
}
|
|
221
|
-
const { fee_address, fee_per_output } = tokenDetails.status;
|
|
222
287
|
const listResult = await ctx.wallet.listOutputs({
|
|
223
288
|
basket: BSV21_BASKET,
|
|
224
289
|
includeTags: true,
|
|
@@ -227,17 +292,14 @@ export const sendBsv21 = {
|
|
|
227
292
|
limit: 10000,
|
|
228
293
|
});
|
|
229
294
|
const tokenUtxos = listResult.outputs.filter((o) => matchesTokenId(o, tokenId));
|
|
230
|
-
//
|
|
295
|
+
// When validateOverlay: only spend tips the overlay still lists unspent.
|
|
231
296
|
const validOutpoints = new Set();
|
|
232
|
-
|
|
233
|
-
if (ctx.services?.bsv21) {
|
|
297
|
+
if (validateOverlay) {
|
|
234
298
|
const candidateOutpoints = tokenUtxos.map((o) => o.outpoint);
|
|
235
299
|
try {
|
|
236
300
|
const validated = await ctx.services.bsv21.validateOutputs(tokenId, candidateOutpoints, { unspent: true });
|
|
237
|
-
overlayValidated = true;
|
|
238
301
|
for (const v of validated) {
|
|
239
|
-
|
|
240
|
-
validOutpoints.add(normalizedOutpoint);
|
|
302
|
+
validOutpoints.add(v.outpoint.replace('_', '.'));
|
|
241
303
|
}
|
|
242
304
|
}
|
|
243
305
|
catch (e) {
|
|
@@ -250,29 +312,42 @@ export const sendBsv21 = {
|
|
|
250
312
|
for (const utxo of tokenUtxos) {
|
|
251
313
|
if (totalIn >= totalAmount)
|
|
252
314
|
break;
|
|
253
|
-
const
|
|
254
|
-
if (!
|
|
315
|
+
const amtStr = amtFromOutput(utxo);
|
|
316
|
+
if (!amtStr)
|
|
255
317
|
continue;
|
|
256
|
-
const utxoAmount = BigInt(
|
|
257
|
-
if (
|
|
318
|
+
const utxoAmount = BigInt(amtStr);
|
|
319
|
+
if (validateOverlay && !validOutpoints.has(utxo.outpoint)) {
|
|
258
320
|
continue;
|
|
259
321
|
}
|
|
260
322
|
selected.push(utxo);
|
|
261
323
|
totalIn += utxoAmount;
|
|
262
324
|
}
|
|
263
325
|
if (totalIn < totalAmount) {
|
|
264
|
-
return {
|
|
326
|
+
return {
|
|
327
|
+
error: validateOverlay
|
|
328
|
+
? 'insufficient-valid-tokens'
|
|
329
|
+
: 'insufficient-tokens',
|
|
330
|
+
};
|
|
265
331
|
}
|
|
266
332
|
const outputs = [];
|
|
267
333
|
const p2pkh = new P2PKH();
|
|
268
334
|
const recipientKeyIDs = [];
|
|
269
|
-
//
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
335
|
+
// Meta: overlay when present, else first selected tip CI.
|
|
336
|
+
const fromTip = selected[0]
|
|
337
|
+
? bsv21FieldsFromOutput({
|
|
338
|
+
tags: selected[0].tags,
|
|
339
|
+
customInstructions: selected[0].customInstructions,
|
|
340
|
+
outpoint: selected[0].outpoint,
|
|
341
|
+
})
|
|
342
|
+
: {};
|
|
343
|
+
const tokenTags = bsv21FilterTags({ tokenId });
|
|
344
|
+
const tokenMeta = {
|
|
345
|
+
id: tokenId,
|
|
346
|
+
op: 'transfer',
|
|
347
|
+
sym: tokenDetails?.token.sym ?? fromTip.sym,
|
|
348
|
+
dec: tokenDetails?.token.dec ?? fromTip.dec ?? 0,
|
|
349
|
+
icon: tokenDetails?.token.icon ?? fromTip.icon,
|
|
350
|
+
};
|
|
276
351
|
for (const r of resolved) {
|
|
277
352
|
const recipientResolved = await resolveDestination(ctx, r.destination, {
|
|
278
353
|
protocolID: P1SAT_PROTOCOL,
|
|
@@ -280,7 +355,7 @@ export const sendBsv21 = {
|
|
|
280
355
|
});
|
|
281
356
|
recipientKeyIDs.push(recipientResolved.customInstructions?.keyID);
|
|
282
357
|
const transferScript = BSV21.transfer(tokenId, r.amount).lock(recipientResolved.lockingScript);
|
|
283
|
-
// Self destinations stay in the BSV21 basket with
|
|
358
|
+
// Self destinations stay in the BSV21 basket with filter tags + CI.
|
|
284
359
|
const isSelf = r.destination.counterparty === 'self' ||
|
|
285
360
|
recipientResolved.customInstructions?.counterparty === 'self';
|
|
286
361
|
outputs.push({
|
|
@@ -289,20 +364,18 @@ export const sendBsv21 = {
|
|
|
289
364
|
outputDescription: `Send ${r.amount} tokens`,
|
|
290
365
|
...(isSelf && {
|
|
291
366
|
basket: BSV21_BASKET,
|
|
292
|
-
tags:
|
|
367
|
+
tags: tokenTags,
|
|
293
368
|
// Only when the wallet actually derived the key. A literal
|
|
294
369
|
// address or lockingScript destination has no derivation, and
|
|
295
370
|
// inventing a keyID here would record a triple that was never
|
|
296
371
|
// used to lock this output — leaving it unspendable from its
|
|
297
372
|
// own record.
|
|
298
373
|
...(recipientResolved.customInstructions?.keyID && {
|
|
299
|
-
customInstructions:
|
|
374
|
+
customInstructions: buildBsv21CustomInstructions({
|
|
375
|
+
token: { ...tokenMeta, amt: String(r.amount) },
|
|
300
376
|
protocolID: P1SAT_PROTOCOL,
|
|
301
377
|
keyID: recipientResolved.customInstructions.keyID,
|
|
302
378
|
counterparty: 'self',
|
|
303
|
-
...(tokenDetails.token.sym && {
|
|
304
|
-
sym: tokenDetails.token.sym,
|
|
305
|
-
}),
|
|
306
379
|
}),
|
|
307
380
|
}),
|
|
308
381
|
}),
|
|
@@ -329,34 +402,30 @@ export const sendBsv21 = {
|
|
|
329
402
|
satoshis: 1,
|
|
330
403
|
outputDescription: 'Token change',
|
|
331
404
|
basket: BSV21_BASKET,
|
|
332
|
-
tags:
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
`dec:${tokenDetails.token.dec ?? 0}`,
|
|
336
|
-
...(tokenDetails.token.sym
|
|
337
|
-
? [`sym:${tokenDetails.token.sym}`]
|
|
338
|
-
: []),
|
|
339
|
-
...(tokenDetails.token.icon
|
|
340
|
-
? [`icon:${tokenDetails.token.icon}`]
|
|
341
|
-
: []),
|
|
342
|
-
],
|
|
343
|
-
customInstructions: JSON.stringify({
|
|
405
|
+
tags: tokenTags,
|
|
406
|
+
customInstructions: buildBsv21CustomInstructions({
|
|
407
|
+
token: { ...tokenMeta, amt: String(change) },
|
|
344
408
|
protocolID: P1SAT_PROTOCOL,
|
|
345
409
|
keyID: changeKeyID,
|
|
346
|
-
|
|
347
|
-
sym: tokenDetails.token.sym,
|
|
348
|
-
}),
|
|
410
|
+
counterparty: 'self',
|
|
349
411
|
}),
|
|
350
412
|
});
|
|
351
413
|
}
|
|
352
|
-
// Fee
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
414
|
+
// Fee out when we have fund params (required path always has details).
|
|
415
|
+
const fee_address = tokenDetails?.status?.fee_address;
|
|
416
|
+
const fee_per_output = tokenDetails?.status?.fee_per_output;
|
|
417
|
+
if (typeof fee_address === 'string' &&
|
|
418
|
+
fee_address &&
|
|
419
|
+
typeof fee_per_output === 'number' &&
|
|
420
|
+
fee_per_output > 0) {
|
|
421
|
+
outputs.push({
|
|
422
|
+
lockingScript: p2pkh.lock(fee_address).toHex(),
|
|
423
|
+
satoshis: fee_per_output * tokenOutputCount,
|
|
424
|
+
outputDescription: 'Overlay processing fee',
|
|
425
|
+
tags: ['fee:overlay'],
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
const symbol = tokenMeta.sym || tokenId.slice(0, 8);
|
|
360
429
|
let inputBEEF = listResult.BEEF;
|
|
361
430
|
if (!inputBEEF || inputBEEF.length === 0) {
|
|
362
431
|
if (!ctx.services)
|
|
@@ -386,20 +455,19 @@ export const sendBsv21 = {
|
|
|
386
455
|
})),
|
|
387
456
|
outputs,
|
|
388
457
|
options: { randomizeOutputs: false },
|
|
389
|
-
}
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
return spends;
|
|
458
|
+
});
|
|
459
|
+
const spends = selected
|
|
460
|
+
.map((o) => {
|
|
461
|
+
const id = readAssetIdTag(o.tags);
|
|
462
|
+
return id
|
|
463
|
+
? ({ basket: BSV21_BASKET, id })
|
|
464
|
+
: null;
|
|
465
|
+
})
|
|
466
|
+
.filter((t) => !!t);
|
|
467
|
+
const result = await executeTrackedAction(ctx.wallet, sendArgs, input.fundingProvider, inputBEEF, undefined, {
|
|
468
|
+
spends,
|
|
469
|
+
usePermissionModule: input.usePermissionModule ?? input.useOneSatModule ?? input.useModule,
|
|
470
|
+
permissionScheme: 'bsv21',
|
|
403
471
|
});
|
|
404
472
|
// Submit to overlay service for indexing
|
|
405
473
|
if (result.tx && ctx.services) {
|
|
@@ -540,21 +608,19 @@ export const buyBsv21 = {
|
|
|
540
608
|
satoshis: 1,
|
|
541
609
|
outputDescription: 'Purchased tokens',
|
|
542
610
|
basket: BSV21_BASKET,
|
|
543
|
-
tags:
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
:
|
|
551
|
-
|
|
552
|
-
|
|
611
|
+
tags: bsv21FilterTags({ tokenId }),
|
|
612
|
+
customInstructions: buildBsv21CustomInstructions({
|
|
613
|
+
token: {
|
|
614
|
+
id: tokenId,
|
|
615
|
+
amt: String(tokenAmount),
|
|
616
|
+
op: 'transfer',
|
|
617
|
+
sym: tokenDetails.token.sym,
|
|
618
|
+
dec: tokenDetails.token.dec ?? 0,
|
|
619
|
+
icon: tokenDetails.token.icon,
|
|
620
|
+
},
|
|
553
621
|
protocolID: P1SAT_PROTOCOL,
|
|
554
622
|
keyID: bsv21KeyID,
|
|
555
|
-
|
|
556
|
-
sym: tokenDetails.token.sym,
|
|
557
|
-
}),
|
|
623
|
+
counterparty: 'self',
|
|
558
624
|
}),
|
|
559
625
|
});
|
|
560
626
|
const payoutReader = new Utils.Reader(ordLockData.payout);
|
|
@@ -602,10 +668,11 @@ export const buyBsv21 = {
|
|
|
602
668
|
],
|
|
603
669
|
outputs,
|
|
604
670
|
options: { randomizeOutputs: false },
|
|
605
|
-
}
|
|
606
|
-
const result = await executeTrackedAction(ctx.wallet, buyArgs, input.fundingProvider, beefBinary,
|
|
607
|
-
|
|
608
|
-
|
|
671
|
+
});
|
|
672
|
+
const result = await executeTrackedAction(ctx.wallet, buyArgs, input.fundingProvider, beefBinary, undefined, {
|
|
673
|
+
spends: [{ outpoint, scheme: 'bsv21' }],
|
|
674
|
+
usePermissionModule: input.usePermissionModule ?? input.useOneSatModule ?? input.useModule,
|
|
675
|
+
permissionScheme: 'bsv21',
|
|
609
676
|
});
|
|
610
677
|
// Submit to overlay service for indexing
|
|
611
678
|
if (result.tx && ctx.services) {
|
|
@@ -658,25 +725,32 @@ export const buyBsv21 = {
|
|
|
658
725
|
},
|
|
659
726
|
};
|
|
660
727
|
/**
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
*
|
|
728
|
+
* Deploy via createAction. Tags: `bsv21:deploy` (+ auth). No `bsv21:<tokenId>`
|
|
729
|
+
* (id = this outpoint, known only after the tx). Balance/selection resolve id
|
|
730
|
+
* from outpoint when that tag is present.
|
|
664
731
|
*/
|
|
665
732
|
async function executeBsv21Deploy(args) {
|
|
666
733
|
const { ctx, symbol, deployScript, basket } = args;
|
|
734
|
+
// Deploy filing: `bsv21:deploy` (+ optional auth). No `bsv21:<tokenId>`
|
|
735
|
+
// (id = outpoint after mine). Never amt/sym/dec/icon tags.
|
|
736
|
+
const tags = args.buildTags().filter((t) => t === BSV21_DEPLOY_TAG || t === BSV21_AUTH_TAG);
|
|
737
|
+
if (!tags.includes(BSV21_DEPLOY_TAG))
|
|
738
|
+
tags.push(BSV21_DEPLOY_TAG);
|
|
667
739
|
const customInstructions = args.destinationCustomInstructions
|
|
668
|
-
?
|
|
740
|
+
? buildBsv21CustomInstructions({
|
|
741
|
+
token: {
|
|
742
|
+
// No `id` — readers use deploy outpoint as token id.
|
|
743
|
+
amt: args.token.amt,
|
|
744
|
+
op: args.token.op,
|
|
745
|
+
sym: symbol,
|
|
746
|
+
dec: args.token.dec,
|
|
747
|
+
icon: args.token.icon,
|
|
748
|
+
},
|
|
669
749
|
protocolID: args.destinationCustomInstructions.protocolID,
|
|
670
750
|
keyID: args.destinationCustomInstructions.keyID,
|
|
671
|
-
|
|
672
|
-
counterparty: args.destinationCustomInstructions.counterparty,
|
|
673
|
-
}),
|
|
674
|
-
sym: symbol,
|
|
751
|
+
counterparty: args.destinationCustomInstructions.counterparty,
|
|
675
752
|
})
|
|
676
753
|
: undefined;
|
|
677
|
-
const tags = args.buildTags();
|
|
678
|
-
if (!tags.includes(BSV21_DEPLOY_TAG))
|
|
679
|
-
tags.push(BSV21_DEPLOY_TAG);
|
|
680
754
|
const caArgs = {
|
|
681
755
|
description: args.description,
|
|
682
756
|
outputs: [
|
|
@@ -691,7 +765,7 @@ async function executeBsv21Deploy(args) {
|
|
|
691
765
|
],
|
|
692
766
|
options: { randomizeOutputs: false },
|
|
693
767
|
};
|
|
694
|
-
const prepared = await prepareP1SatArgs(ctx, caArgs
|
|
768
|
+
const prepared = await prepareP1SatArgs(ctx, caArgs);
|
|
695
769
|
const result = await executeTrackedAction(ctx.wallet, prepared, args.fundingProvider);
|
|
696
770
|
if (!result.txid) {
|
|
697
771
|
return { error: 'deploy-no-txid' };
|
|
@@ -754,17 +828,13 @@ export const deployBsv21Mint = {
|
|
|
754
828
|
basket: BSV21_BASKET,
|
|
755
829
|
description: `Deploy ${symbol} (${amount} fixed supply)`,
|
|
756
830
|
outputDescription: `Deploy ${symbol}`,
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
`sym:${symbol}`,
|
|
763
|
-
];
|
|
764
|
-
if (icon)
|
|
765
|
-
tags.push(`icon:${icon}`);
|
|
766
|
-
return tags;
|
|
831
|
+
token: {
|
|
832
|
+
amt: String(amount),
|
|
833
|
+
op: 'deploy+mint',
|
|
834
|
+
dec: decimals,
|
|
835
|
+
icon,
|
|
767
836
|
},
|
|
837
|
+
buildTags: () => [BSV21_DEPLOY_TAG],
|
|
768
838
|
});
|
|
769
839
|
if (result.error)
|
|
770
840
|
return { error: result.error };
|
|
@@ -861,15 +931,16 @@ export const deployBsv21Auth = {
|
|
|
861
931
|
symbol,
|
|
862
932
|
deployScript,
|
|
863
933
|
destinationCustomInstructions: resolved.customInstructions,
|
|
864
|
-
basket:
|
|
934
|
+
basket: BSV21_BASKET,
|
|
865
935
|
description: `Deploy ${symbol} (mintable)`,
|
|
866
936
|
outputDescription: `Deploy ${symbol} auth`,
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
937
|
+
token: {
|
|
938
|
+
amt: '0',
|
|
939
|
+
op: 'deploy+auth',
|
|
940
|
+
dec: decimals,
|
|
941
|
+
icon,
|
|
872
942
|
},
|
|
943
|
+
buildTags: () => [BSV21_DEPLOY_TAG, BSV21_AUTH_TAG],
|
|
873
944
|
});
|
|
874
945
|
if (result.error)
|
|
875
946
|
return { error: result.error };
|
|
@@ -893,7 +964,7 @@ export const deployBsv21Auth = {
|
|
|
893
964
|
index: 0,
|
|
894
965
|
protocolID: P1SAT_PROTOCOL,
|
|
895
966
|
keyID: resolved.customInstructions?.keyID,
|
|
896
|
-
basket:
|
|
967
|
+
basket: BSV21_BASKET,
|
|
897
968
|
satoshis: 1,
|
|
898
969
|
},
|
|
899
970
|
],
|
|
@@ -976,15 +1047,17 @@ export const mintBsv21 = {
|
|
|
976
1047
|
}
|
|
977
1048
|
// Look up the token's metadata for tag enrichment.
|
|
978
1049
|
const tokenDetails = await ctx.services.bsv21.getTokenDetails(tokenId);
|
|
979
|
-
// Find a spendable auth UTXO for this token.
|
|
1050
|
+
// Find a spendable auth UTXO for this token (same basket as balance).
|
|
980
1051
|
const authList = await ctx.wallet.listOutputs({
|
|
981
|
-
basket:
|
|
1052
|
+
basket: BSV21_BASKET,
|
|
1053
|
+
tags: [BSV21_AUTH_TAG, `bsv21:${tokenId}`],
|
|
1054
|
+
tagQueryMode: 'all',
|
|
982
1055
|
includeTags: true,
|
|
983
1056
|
includeCustomInstructions: true,
|
|
984
1057
|
include: 'entire transactions',
|
|
985
1058
|
limit: 1000,
|
|
986
1059
|
});
|
|
987
|
-
const authUtxo = authList.outputs
|
|
1060
|
+
const authUtxo = authList.outputs[0];
|
|
988
1061
|
if (!authUtxo) {
|
|
989
1062
|
return { error: 'no-auth-utxo-for-token' };
|
|
990
1063
|
}
|
|
@@ -1001,30 +1074,29 @@ export const mintBsv21 = {
|
|
|
1001
1074
|
keyIDPrefix: `bsv21-mint-${tokenId}`,
|
|
1002
1075
|
});
|
|
1003
1076
|
const mintScript = BSV21.mint(tokenId, mintAmount).lock(mintResolved.lockingScript);
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
];
|
|
1013
|
-
const mintCI = mintResolved.customInstructions
|
|
1014
|
-
? JSON.stringify({
|
|
1015
|
-
...mintResolved.customInstructions,
|
|
1016
|
-
...(tokenDetails.token.sym && { sym: tokenDetails.token.sym }),
|
|
1017
|
-
})
|
|
1018
|
-
: tokenDetails.token.sym
|
|
1019
|
-
? JSON.stringify({ sym: tokenDetails.token.sym })
|
|
1020
|
-
: undefined;
|
|
1077
|
+
const mintMeta = {
|
|
1078
|
+
id: tokenId,
|
|
1079
|
+
amt: String(mintAmount),
|
|
1080
|
+
op: 'mint',
|
|
1081
|
+
sym: tokenDetails.token.sym,
|
|
1082
|
+
dec: tokenDetails.token.dec ?? 0,
|
|
1083
|
+
icon: tokenDetails.token.icon,
|
|
1084
|
+
};
|
|
1021
1085
|
outputs.push({
|
|
1022
1086
|
lockingScript: mintScript.toHex(),
|
|
1023
1087
|
satoshis: 1,
|
|
1024
1088
|
outputDescription: `Mint ${mintAmount} tokens`,
|
|
1025
1089
|
basket: BSV21_BASKET,
|
|
1026
|
-
tags:
|
|
1027
|
-
customInstructions:
|
|
1090
|
+
tags: bsv21FilterTags({ tokenId }),
|
|
1091
|
+
customInstructions: mintResolved.customInstructions
|
|
1092
|
+
? buildBsv21CustomInstructions({
|
|
1093
|
+
token: mintMeta,
|
|
1094
|
+
protocolID: mintResolved.customInstructions.protocolID,
|
|
1095
|
+
keyID: mintResolved.customInstructions.keyID,
|
|
1096
|
+
counterparty: mintResolved.customInstructions
|
|
1097
|
+
.counterparty,
|
|
1098
|
+
})
|
|
1099
|
+
: buildBsv21CustomInstructions({ token: mintMeta }),
|
|
1028
1100
|
});
|
|
1029
1101
|
}
|
|
1030
1102
|
if (!endMinting) {
|
|
@@ -1033,30 +1105,30 @@ export const mintBsv21 = {
|
|
|
1033
1105
|
keyIDPrefix: `bsv21-auth-${tokenId}`,
|
|
1034
1106
|
});
|
|
1035
1107
|
const authScript = BSV21.auth(tokenId).lock(authResolved.lockingScript);
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
const authCustomInstructions = authResolved.customInstructions
|
|
1045
|
-
? JSON.stringify({
|
|
1046
|
-
...authResolved.customInstructions,
|
|
1047
|
-
...(tokenDetails.token.sym && { sym: tokenDetails.token.sym }),
|
|
1048
|
-
})
|
|
1049
|
-
: tokenDetails.token.sym
|
|
1050
|
-
? JSON.stringify({ sym: tokenDetails.token.sym })
|
|
1051
|
-
: undefined;
|
|
1108
|
+
const authMeta = {
|
|
1109
|
+
id: tokenId,
|
|
1110
|
+
amt: '0',
|
|
1111
|
+
op: 'auth',
|
|
1112
|
+
sym: tokenDetails.token.sym,
|
|
1113
|
+
dec: tokenDetails.token.dec ?? 0,
|
|
1114
|
+
icon: tokenDetails.token.icon,
|
|
1115
|
+
};
|
|
1052
1116
|
authOutputIndex = outputs.length;
|
|
1053
1117
|
outputs.push({
|
|
1054
1118
|
lockingScript: authScript.toHex(),
|
|
1055
1119
|
satoshis: 1,
|
|
1056
1120
|
outputDescription: 'Continuing mint authority',
|
|
1057
|
-
basket:
|
|
1058
|
-
tags:
|
|
1059
|
-
customInstructions:
|
|
1121
|
+
basket: BSV21_BASKET,
|
|
1122
|
+
tags: bsv21FilterTags({ tokenId, auth: true }),
|
|
1123
|
+
customInstructions: authResolved.customInstructions
|
|
1124
|
+
? buildBsv21CustomInstructions({
|
|
1125
|
+
token: authMeta,
|
|
1126
|
+
protocolID: authResolved.customInstructions.protocolID,
|
|
1127
|
+
keyID: authResolved.customInstructions.keyID,
|
|
1128
|
+
counterparty: authResolved.customInstructions
|
|
1129
|
+
.counterparty,
|
|
1130
|
+
})
|
|
1131
|
+
: buildBsv21CustomInstructions({ token: authMeta }),
|
|
1060
1132
|
});
|
|
1061
1133
|
}
|
|
1062
1134
|
// Optional fee output to overlay fund address (per token output).
|
|
@@ -1086,7 +1158,7 @@ export const mintBsv21 = {
|
|
|
1086
1158
|
labels: [
|
|
1087
1159
|
buildTokenLabel(tokenId),
|
|
1088
1160
|
...(authInputId
|
|
1089
|
-
? [buildInputAssetLabel(
|
|
1161
|
+
? [buildInputAssetLabel(BSV21_BASKET, authInputId)]
|
|
1090
1162
|
: []),
|
|
1091
1163
|
],
|
|
1092
1164
|
inputBEEF,
|
|
@@ -1099,7 +1171,7 @@ export const mintBsv21 = {
|
|
|
1099
1171
|
],
|
|
1100
1172
|
outputs,
|
|
1101
1173
|
options: { randomizeOutputs: false },
|
|
1102
|
-
}
|
|
1174
|
+
});
|
|
1103
1175
|
const result = await executeTrackedAction(ctx.wallet, mintArgs, input.fundingProvider, inputBEEF, async (tx) => {
|
|
1104
1176
|
if (authCI.multiSig === true) {
|
|
1105
1177
|
// 1-of-N P2MS auth: this wallet contributes its single
|