@1sat/sweep-ui 0.0.95 → 0.0.96
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/components/SweepApp.d.ts.map +1 -1
- package/dist/components/asset-preview.d.ts +6 -7
- package/dist/components/asset-preview.d.ts.map +1 -1
- package/dist/components/opns-section.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +284 -178
- package/dist/lib/scanner.d.ts +1 -2
- package/dist/lib/scanner.d.ts.map +1 -1
- package/dist/lib/sweeper.d.ts +29 -13
- package/dist/lib/sweeper.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/SweepApp.tsx +109 -61
- package/src/components/asset-preview.tsx +67 -62
- package/src/components/opns-section.tsx +6 -0
- package/src/index.ts +1 -1
- package/src/lib/scanner.ts +1 -3
- package/src/lib/sweeper.ts +143 -57
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/components/SweepApp.tsx
|
|
2
|
+
import { groupBsv20Tokens as groupBsv20Tokens2 } from "@1sat/actions";
|
|
2
3
|
import { PrivateKey as PrivateKey3 } from "@bsv/sdk";
|
|
3
4
|
import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useState as useState5 } from "react";
|
|
4
5
|
import { Toaster, toast } from "sonner";
|
|
@@ -84,7 +85,6 @@ function toScannedAssets(result) {
|
|
|
84
85
|
funding: result.funding,
|
|
85
86
|
ordinals: result.ordinals.map(enrichOrdinal),
|
|
86
87
|
opnsNames: result.opnsNames.map(enrichOrdinal),
|
|
87
|
-
listings: result.listings.map(enrichOrdinal),
|
|
88
88
|
bsv21Tokens: enrichTokenBalances(result.bsv21Tokens),
|
|
89
89
|
bsv20Tokens: result.bsv20Tokens,
|
|
90
90
|
locked: result.locked,
|
|
@@ -276,13 +276,16 @@ async function legacyBurnOrdinals(params) {
|
|
|
276
276
|
|
|
277
277
|
// src/lib/sweeper.ts
|
|
278
278
|
import {
|
|
279
|
+
SWEEP_BATCH_SIZE,
|
|
280
|
+
bsv21SweepBatches,
|
|
279
281
|
createContext,
|
|
282
|
+
groupBsv20Tokens,
|
|
280
283
|
prepareSweepInputs,
|
|
281
284
|
sweepBsv,
|
|
285
|
+
sweepBsv20,
|
|
282
286
|
sweepBsv21,
|
|
283
287
|
sweepOrdinals
|
|
284
288
|
} from "@1sat/actions";
|
|
285
|
-
var SWEEP_BATCH_SIZE = 25;
|
|
286
289
|
function getOwner(output) {
|
|
287
290
|
return output.events?.find((e) => e.startsWith("own:"))?.slice(4);
|
|
288
291
|
}
|
|
@@ -304,49 +307,15 @@ function chunk(items, size) {
|
|
|
304
307
|
return batches;
|
|
305
308
|
}
|
|
306
309
|
async function executeSweep(params) {
|
|
307
|
-
const {
|
|
308
|
-
wallet,
|
|
309
|
-
keys,
|
|
310
|
-
funding,
|
|
311
|
-
ordinals,
|
|
312
|
-
listings = [],
|
|
313
|
-
amount,
|
|
314
|
-
onProgress
|
|
315
|
-
} = params;
|
|
310
|
+
const { wallet, keys, funding, ordinals, amount, onProgress } = params;
|
|
316
311
|
const ctx = createContext(wallet, { services: getServices(), chain: "main" });
|
|
317
312
|
const result = {
|
|
318
313
|
ordinalTxids: [],
|
|
319
|
-
|
|
314
|
+
bsv20Txids: [],
|
|
320
315
|
bsv21Txids: [],
|
|
321
316
|
errors: [],
|
|
322
|
-
sweptOutpoints: []
|
|
323
|
-
cancelledListings: []
|
|
317
|
+
sweptOutpoints: []
|
|
324
318
|
};
|
|
325
|
-
if (listings.length > 0) {
|
|
326
|
-
const batches = chunk(listings, SWEEP_BATCH_SIZE);
|
|
327
|
-
for (let b = 0;b < batches.length; b++) {
|
|
328
|
-
const batch = batches[b];
|
|
329
|
-
onProgress(`Cancelling ${batch.length} OrdLock listing${batch.length !== 1 ? "s" : ""} into wallet...`);
|
|
330
|
-
try {
|
|
331
|
-
const inputs = await prepareSweepInputs(ctx, batch);
|
|
332
|
-
const cancelResult = await sweepOrdinals.execute(ctx, {
|
|
333
|
-
inputs,
|
|
334
|
-
keys: buildKeys(batch, keys, inputs)
|
|
335
|
-
});
|
|
336
|
-
if (cancelResult.error)
|
|
337
|
-
throw new Error(cancelResult.error);
|
|
338
|
-
const txid = cancelResult.txid?.trim();
|
|
339
|
-
if (!txid)
|
|
340
|
-
throw new Error("Cancellation returned no transaction ID");
|
|
341
|
-
result.listingTxids.push(txid);
|
|
342
|
-
result.cancelledListings.push(...batch.map((o) => o.outpoint));
|
|
343
|
-
} catch (e) {
|
|
344
|
-
result.errors.push(`Listings batch ${b + 1}: ${e instanceof Error ? e.message : String(e)}`);
|
|
345
|
-
onProgress("Sweep stopped with errors");
|
|
346
|
-
return result;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
319
|
if (funding.length > 0) {
|
|
351
320
|
onProgress(`Sweeping ${funding.length} BSV UTXOs...`);
|
|
352
321
|
try {
|
|
@@ -398,7 +367,46 @@ async function executeSweep(params) {
|
|
|
398
367
|
async function sweepBsv21Token(params) {
|
|
399
368
|
const { wallet, keys, token, onProgress } = params;
|
|
400
369
|
const ctx = createContext(wallet, { services: getServices(), chain: "main" });
|
|
401
|
-
|
|
370
|
+
const txids = [];
|
|
371
|
+
const errors = [];
|
|
372
|
+
const name = token.symbol ?? token.tokenId.slice(0, 8);
|
|
373
|
+
for (const batch of bsv21SweepBatches(token.outputs)) {
|
|
374
|
+
onProgress(`Sweeping ${name}...`);
|
|
375
|
+
try {
|
|
376
|
+
const sweepInputs = await prepareSweepInputs(ctx, batch);
|
|
377
|
+
const sweepInputMap = new Map(sweepInputs.map((s) => [s.outpoint, s]));
|
|
378
|
+
const inputs = batch.map((out) => {
|
|
379
|
+
const base = sweepInputMap.get(out.outpoint);
|
|
380
|
+
if (!base)
|
|
381
|
+
throw new Error(`Missing sweep input for ${out.outpoint}`);
|
|
382
|
+
return {
|
|
383
|
+
...base,
|
|
384
|
+
tokenId: token.tokenId,
|
|
385
|
+
amount: token.amounts.get(out.outpoint) ?? "0"
|
|
386
|
+
};
|
|
387
|
+
});
|
|
388
|
+
const result = await sweepBsv21.execute(ctx, {
|
|
389
|
+
inputs,
|
|
390
|
+
keys: buildKeys(batch, keys)
|
|
391
|
+
});
|
|
392
|
+
if (result.error)
|
|
393
|
+
errors.push(result.error);
|
|
394
|
+
else if (result.txid)
|
|
395
|
+
txids.push(result.txid);
|
|
396
|
+
} catch (e) {
|
|
397
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
txid: txids.at(-1),
|
|
402
|
+
txids,
|
|
403
|
+
error: errors[0]
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
async function sweepBsv20Token(params) {
|
|
407
|
+
const { wallet, keys, token, onProgress } = params;
|
|
408
|
+
const ctx = createContext(wallet, { services: getServices(), chain: "main" });
|
|
409
|
+
onProgress(`Sweeping ${token.tick}...`);
|
|
402
410
|
try {
|
|
403
411
|
const sweepInputs = await prepareSweepInputs(ctx, token.outputs);
|
|
404
412
|
const sweepInputMap = new Map(sweepInputs.map((s) => [s.outpoint, s]));
|
|
@@ -408,12 +416,14 @@ async function sweepBsv21Token(params) {
|
|
|
408
416
|
throw new Error(`Missing sweep input for ${out.outpoint}`);
|
|
409
417
|
return {
|
|
410
418
|
...base,
|
|
411
|
-
|
|
419
|
+
tick: token.tick,
|
|
412
420
|
amount: token.amounts.get(out.outpoint) ?? "0"
|
|
413
421
|
};
|
|
414
422
|
});
|
|
415
|
-
const
|
|
416
|
-
|
|
423
|
+
const result = await sweepBsv20.execute(ctx, {
|
|
424
|
+
inputs,
|
|
425
|
+
keys: buildKeys(token.outputs, keys)
|
|
426
|
+
});
|
|
417
427
|
if (result.error)
|
|
418
428
|
return { error: result.error };
|
|
419
429
|
return { txid: result.txid };
|
|
@@ -421,6 +431,68 @@ async function sweepBsv21Token(params) {
|
|
|
421
431
|
return { error: e instanceof Error ? e.message : String(e) };
|
|
422
432
|
}
|
|
423
433
|
}
|
|
434
|
+
async function sweepAllClasses(params) {
|
|
435
|
+
const { wallet, keys, assets, amount, onProgress } = params;
|
|
436
|
+
const result = {
|
|
437
|
+
ordinalTxids: [],
|
|
438
|
+
bsv20Txids: [],
|
|
439
|
+
bsv21Txids: [],
|
|
440
|
+
errors: [],
|
|
441
|
+
sweptOutpoints: []
|
|
442
|
+
};
|
|
443
|
+
const first = await executeSweep({
|
|
444
|
+
wallet,
|
|
445
|
+
keys,
|
|
446
|
+
funding: assets.funding,
|
|
447
|
+
ordinals: assets.ordinals,
|
|
448
|
+
amount,
|
|
449
|
+
onProgress
|
|
450
|
+
});
|
|
451
|
+
result.bsvTxid = first.bsvTxid;
|
|
452
|
+
result.ordinalTxids.push(...first.ordinalTxids);
|
|
453
|
+
result.sweptOutpoints.push(...first.sweptOutpoints);
|
|
454
|
+
result.errors.push(...first.errors);
|
|
455
|
+
if (assets.opnsNames.length > 0) {
|
|
456
|
+
const opns = await executeSweep({
|
|
457
|
+
wallet,
|
|
458
|
+
keys,
|
|
459
|
+
funding: [],
|
|
460
|
+
ordinals: assets.opnsNames,
|
|
461
|
+
onProgress
|
|
462
|
+
});
|
|
463
|
+
result.ordinalTxids.push(...opns.ordinalTxids);
|
|
464
|
+
result.sweptOutpoints.push(...opns.sweptOutpoints);
|
|
465
|
+
result.errors.push(...opns.errors);
|
|
466
|
+
}
|
|
467
|
+
for (const token of groupBsv20Tokens(assets.bsv20Tokens)) {
|
|
468
|
+
const swept = await sweepBsv20Token({
|
|
469
|
+
wallet,
|
|
470
|
+
keys,
|
|
471
|
+
token,
|
|
472
|
+
onProgress
|
|
473
|
+
});
|
|
474
|
+
if (swept.error)
|
|
475
|
+
result.errors.push(`BSV-20 ${token.tick}: ${swept.error}`);
|
|
476
|
+
else if (swept.txid)
|
|
477
|
+
result.bsv20Txids.push(swept.txid);
|
|
478
|
+
}
|
|
479
|
+
for (const token of assets.bsv21Tokens) {
|
|
480
|
+
if (token.outputs.length === 0)
|
|
481
|
+
continue;
|
|
482
|
+
const swept = await sweepBsv21Token({
|
|
483
|
+
wallet,
|
|
484
|
+
keys,
|
|
485
|
+
token,
|
|
486
|
+
onProgress
|
|
487
|
+
});
|
|
488
|
+
result.bsv21Txids.push(...swept.txids);
|
|
489
|
+
if (swept.error) {
|
|
490
|
+
result.errors.push(`BSV-21 ${token.symbol ?? token.tokenId.slice(0, 8)}: ${swept.error}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
onProgress(result.errors.length > 0 ? "Sweep stopped with errors" : "Sweep complete");
|
|
494
|
+
return result;
|
|
495
|
+
}
|
|
424
496
|
|
|
425
497
|
// src/lib/wallet.ts
|
|
426
498
|
import {
|
|
@@ -452,6 +524,7 @@ function isConnected() {
|
|
|
452
524
|
}
|
|
453
525
|
|
|
454
526
|
// src/components/asset-preview.tsx
|
|
527
|
+
import { isListedOutput } from "@1sat/actions";
|
|
455
528
|
import { useState } from "react";
|
|
456
529
|
|
|
457
530
|
// src/lib/utils.ts
|
|
@@ -608,6 +681,13 @@ function OrdinalCard({
|
|
|
608
681
|
/* @__PURE__ */ jsxs("div", {
|
|
609
682
|
className: "min-h-[2rem] flex flex-col justify-end",
|
|
610
683
|
children: [
|
|
684
|
+
isListedOutput(ordinal) && /* @__PURE__ */ jsx4("div", {
|
|
685
|
+
className: "mb-1",
|
|
686
|
+
children: /* @__PURE__ */ jsx4("span", {
|
|
687
|
+
className: "inline-block px-1 py-0.5 text-[9px] rounded bg-amber-500/20 text-amber-400",
|
|
688
|
+
children: "listed"
|
|
689
|
+
})
|
|
690
|
+
}),
|
|
611
691
|
subtype && /* @__PURE__ */ jsx4("div", {
|
|
612
692
|
className: "mb-1",
|
|
613
693
|
children: /* @__PURE__ */ jsx4("span", {
|
|
@@ -966,6 +1046,7 @@ function TokenRow({
|
|
|
966
1046
|
onSweep,
|
|
967
1047
|
walletConnected
|
|
968
1048
|
}) {
|
|
1049
|
+
const listed = tb.outputs.filter(isListedOutput).length;
|
|
969
1050
|
return /* @__PURE__ */ jsxs("div", {
|
|
970
1051
|
className: `flex items-center justify-between p-3 rounded-lg border ${tb.isActive ? "bg-muted/30 border-purple-500/10" : "bg-muted/20 border-muted/20 opacity-60"}`,
|
|
971
1052
|
children: [
|
|
@@ -987,7 +1068,7 @@ function TokenRow({
|
|
|
987
1068
|
children: [
|
|
988
1069
|
/* @__PURE__ */ jsx4("span", {
|
|
989
1070
|
className: "font-medium text-foreground",
|
|
990
|
-
children: tb.symbol || tb.tokenId.slice(0, 8)
|
|
1071
|
+
children: tb.symbol || `${tb.tokenId.slice(0, 8)}...`
|
|
991
1072
|
}),
|
|
992
1073
|
tb.isActive ? /* @__PURE__ */ jsx4("span", {
|
|
993
1074
|
className: "px-1.5 py-0.5 text-[9px] rounded bg-green-600/20 text-green-700 dark:text-green-400",
|
|
@@ -1011,6 +1092,7 @@ function TokenRow({
|
|
|
1011
1092
|
tb.outputs.length,
|
|
1012
1093
|
" output",
|
|
1013
1094
|
tb.outputs.length !== 1 ? "s" : "",
|
|
1095
|
+
listed ? `, ${listed} listed` : "",
|
|
1014
1096
|
")"
|
|
1015
1097
|
]
|
|
1016
1098
|
})
|
|
@@ -1020,7 +1102,7 @@ function TokenRow({
|
|
|
1020
1102
|
})
|
|
1021
1103
|
]
|
|
1022
1104
|
}),
|
|
1023
|
-
|
|
1105
|
+
onSweep && /* @__PURE__ */ jsx4(Button, {
|
|
1024
1106
|
size: "sm",
|
|
1025
1107
|
onClick: () => onSweep(tb.tokenId),
|
|
1026
1108
|
disabled: !walletConnected,
|
|
@@ -1082,89 +1164,80 @@ function Bsv21Section({
|
|
|
1082
1164
|
]
|
|
1083
1165
|
});
|
|
1084
1166
|
}
|
|
1085
|
-
function Bsv20Section({
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
children: [
|
|
1091
|
-
/* @__PURE__ */ jsxs("div", {
|
|
1092
|
-
className: "flex items-center gap-2 mb-2",
|
|
1093
|
-
children: [
|
|
1094
|
-
/* @__PURE__ */ jsx4("span", {
|
|
1095
|
-
className: "h-2 w-2 rounded-full bg-muted-foreground"
|
|
1096
|
-
}),
|
|
1097
|
-
/* @__PURE__ */ jsx4("span", {
|
|
1098
|
-
className: "text-sm font-semibold text-muted-foreground",
|
|
1099
|
-
children: "BSV-20 Tokens"
|
|
1100
|
-
})
|
|
1101
|
-
]
|
|
1102
|
-
}),
|
|
1103
|
-
/* @__PURE__ */ jsx4("p", {
|
|
1104
|
-
className: "text-xs text-muted-foreground mb-2",
|
|
1105
|
-
children: "Cannot be swept automatically."
|
|
1106
|
-
}),
|
|
1107
|
-
/* @__PURE__ */ jsxs("div", {
|
|
1108
|
-
className: "flex flex-wrap gap-2",
|
|
1109
|
-
children: [
|
|
1110
|
-
tokens.slice(0, 10).map((o) => {
|
|
1111
|
-
const tickEvent = o.events?.find((e) => e.startsWith("tick:"));
|
|
1112
|
-
const tick = tickEvent ? tickEvent.slice(5) : "Token";
|
|
1113
|
-
return /* @__PURE__ */ jsx4("span", {
|
|
1114
|
-
className: "px-2 py-1 text-xs rounded bg-muted/30 text-muted-foreground",
|
|
1115
|
-
children: tick
|
|
1116
|
-
}, o.outpoint);
|
|
1117
|
-
}),
|
|
1118
|
-
tokens.length > 10 && /* @__PURE__ */ jsxs("span", {
|
|
1119
|
-
className: "text-xs text-muted-foreground",
|
|
1120
|
-
children: [
|
|
1121
|
-
"+",
|
|
1122
|
-
tokens.length - 10,
|
|
1123
|
-
" more"
|
|
1124
|
-
]
|
|
1125
|
-
})
|
|
1126
|
-
]
|
|
1127
|
-
})
|
|
1128
|
-
]
|
|
1129
|
-
});
|
|
1130
|
-
}
|
|
1131
|
-
function ListingsSection({
|
|
1132
|
-
listings,
|
|
1133
|
-
walletConnected,
|
|
1134
|
-
onCancel
|
|
1167
|
+
function Bsv20Section({
|
|
1168
|
+
tokens,
|
|
1169
|
+
unparsedCount = 0,
|
|
1170
|
+
onSweep,
|
|
1171
|
+
walletConnected
|
|
1135
1172
|
}) {
|
|
1136
|
-
if (
|
|
1173
|
+
if (tokens.length === 0 && unparsedCount === 0)
|
|
1137
1174
|
return null;
|
|
1138
1175
|
return /* @__PURE__ */ jsxs("div", {
|
|
1139
|
-
className: "border border-
|
|
1176
|
+
className: "border border-teal-500/20 bg-teal-500/5 p-4 rounded-lg",
|
|
1140
1177
|
children: [
|
|
1141
1178
|
/* @__PURE__ */ jsxs("div", {
|
|
1142
|
-
className: "flex items-center gap-2",
|
|
1179
|
+
className: "flex items-center gap-2 mb-3",
|
|
1143
1180
|
children: [
|
|
1144
1181
|
/* @__PURE__ */ jsx4("span", {
|
|
1145
|
-
className: "h-2 w-2 rounded-full bg-
|
|
1182
|
+
className: "h-2 w-2 rounded-full bg-teal-500"
|
|
1146
1183
|
}),
|
|
1147
1184
|
/* @__PURE__ */ jsx4("span", {
|
|
1148
|
-
className: "text-sm font-semibold text-
|
|
1149
|
-
children: "
|
|
1185
|
+
className: "text-sm font-semibold text-teal-500",
|
|
1186
|
+
children: "BSV-20 Tokens"
|
|
1150
1187
|
})
|
|
1151
1188
|
]
|
|
1152
1189
|
}),
|
|
1153
|
-
/* @__PURE__ */ jsxs("p", {
|
|
1154
|
-
className: "text-xs text-muted-foreground",
|
|
1190
|
+
unparsedCount > 0 && /* @__PURE__ */ jsxs("p", {
|
|
1191
|
+
className: "text-xs text-muted-foreground mb-3",
|
|
1155
1192
|
children: [
|
|
1156
|
-
|
|
1157
|
-
"
|
|
1158
|
-
|
|
1159
|
-
"
|
|
1193
|
+
unparsedCount,
|
|
1194
|
+
" UTXO",
|
|
1195
|
+
unparsedCount !== 1 ? "s" : "",
|
|
1196
|
+
" with no parseable tick/amt — leftover, not swept."
|
|
1160
1197
|
]
|
|
1161
1198
|
}),
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1199
|
+
/* @__PURE__ */ jsx4("div", {
|
|
1200
|
+
className: "space-y-3",
|
|
1201
|
+
children: tokens.map((tb) => {
|
|
1202
|
+
const listed = tb.outputs.filter(isListedOutput).length;
|
|
1203
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1204
|
+
className: "flex items-center justify-between p-3 rounded-lg border bg-muted/30 border-teal-500/10",
|
|
1205
|
+
children: [
|
|
1206
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1207
|
+
children: [
|
|
1208
|
+
/* @__PURE__ */ jsx4("div", {
|
|
1209
|
+
className: "font-medium text-foreground",
|
|
1210
|
+
children: tb.tick
|
|
1211
|
+
}),
|
|
1212
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1213
|
+
className: "text-xs text-muted-foreground",
|
|
1214
|
+
children: [
|
|
1215
|
+
tb.totalAmount.toString(),
|
|
1216
|
+
/* @__PURE__ */ jsxs("span", {
|
|
1217
|
+
className: "ml-2",
|
|
1218
|
+
children: [
|
|
1219
|
+
"(",
|
|
1220
|
+
tb.outputs.length,
|
|
1221
|
+
" output",
|
|
1222
|
+
tb.outputs.length !== 1 ? "s" : "",
|
|
1223
|
+
listed ? `, ${listed} listed` : "",
|
|
1224
|
+
")"
|
|
1225
|
+
]
|
|
1226
|
+
})
|
|
1227
|
+
]
|
|
1228
|
+
})
|
|
1229
|
+
]
|
|
1230
|
+
}),
|
|
1231
|
+
onSweep && /* @__PURE__ */ jsx4(Button, {
|
|
1232
|
+
size: "sm",
|
|
1233
|
+
onClick: () => onSweep(tb.tick),
|
|
1234
|
+
disabled: !walletConnected,
|
|
1235
|
+
title: walletConnected ? undefined : "Connect BRC-100 wallet to sweep",
|
|
1236
|
+
children: "Sweep to Wallet"
|
|
1237
|
+
})
|
|
1238
|
+
]
|
|
1239
|
+
}, tb.tick);
|
|
1240
|
+
})
|
|
1168
1241
|
})
|
|
1169
1242
|
]
|
|
1170
1243
|
});
|
|
@@ -1321,6 +1394,7 @@ function ConnectWallet({
|
|
|
1321
1394
|
}
|
|
1322
1395
|
|
|
1323
1396
|
// src/components/opns-section.tsx
|
|
1397
|
+
import { isListedOutput as isListedOutput2 } from "@1sat/actions";
|
|
1324
1398
|
import { useEffect, useState as useState3 } from "react";
|
|
1325
1399
|
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1326
1400
|
function OpnsSection({
|
|
@@ -1482,6 +1556,10 @@ function OpnsSection({
|
|
|
1482
1556
|
className: "text-sm text-foreground truncate",
|
|
1483
1557
|
children: displayName
|
|
1484
1558
|
}),
|
|
1559
|
+
isListedOutput2(item) && /* @__PURE__ */ jsx6("span", {
|
|
1560
|
+
className: "shrink-0 text-[10px] font-medium px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-400",
|
|
1561
|
+
children: "listed"
|
|
1562
|
+
}),
|
|
1485
1563
|
!validating && overlayValid.has(item.outpoint) && (overlayValid.get(item.outpoint) ? /* @__PURE__ */ jsx6("span", {
|
|
1486
1564
|
className: "shrink-0 text-[10px] font-medium px-1.5 py-0.5 rounded bg-green-500/20 text-green-400",
|
|
1487
1565
|
children: "valid"
|
|
@@ -2317,6 +2395,8 @@ function SweepApp({
|
|
|
2317
2395
|
{ label, txid, timestamp: new Date, error }
|
|
2318
2396
|
]);
|
|
2319
2397
|
}, []);
|
|
2398
|
+
const groupedBsv20 = useMemo(() => assets ? groupBsv20Tokens2(assets.bsv20Tokens) : [], [assets]);
|
|
2399
|
+
const unparsedBsv20 = assets ? assets.bsv20Tokens.length - groupedBsv20.reduce((n, t) => n + t.outputs.length, 0) : 0;
|
|
2320
2400
|
const tabs = useMemo(() => {
|
|
2321
2401
|
if (!assets)
|
|
2322
2402
|
return [];
|
|
@@ -2329,16 +2409,24 @@ function SweepApp({
|
|
|
2329
2409
|
});
|
|
2330
2410
|
if (assets.opnsNames.length > 0)
|
|
2331
2411
|
t.push({ id: "opns", label: "OpNS", count: assets.opnsNames.length });
|
|
2412
|
+
if (groupedBsv20.length > 0 || unparsedBsv20 > 0)
|
|
2413
|
+
t.push({
|
|
2414
|
+
id: "bsv20",
|
|
2415
|
+
label: "BSV-20",
|
|
2416
|
+
count: groupedBsv20.reduce((n, tok) => n + tok.outputs.length, 0)
|
|
2417
|
+
});
|
|
2332
2418
|
if (assets.bsv21Tokens.length > 0)
|
|
2333
|
-
t.push({
|
|
2334
|
-
|
|
2335
|
-
|
|
2419
|
+
t.push({
|
|
2420
|
+
id: "bsv21",
|
|
2421
|
+
label: "BSV-21",
|
|
2422
|
+
count: assets.bsv21Tokens.reduce((n, tok) => n + tok.outputs.length, 0)
|
|
2423
|
+
});
|
|
2336
2424
|
if (assets.locked.length > 0)
|
|
2337
2425
|
t.push({ id: "locks", label: "Locks", count: assets.locked.length });
|
|
2338
2426
|
if (assets.run.length > 0)
|
|
2339
2427
|
t.push({ id: "run", label: "RUN", count: assets.run.length });
|
|
2340
2428
|
return t;
|
|
2341
|
-
}, [assets]);
|
|
2429
|
+
}, [assets, groupedBsv20, unparsedBsv20]);
|
|
2342
2430
|
const handleToggleOrdinal = useCallback2((outpoint) => {
|
|
2343
2431
|
setSelectedOrdinals((prev) => {
|
|
2344
2432
|
const next = new Set(prev);
|
|
@@ -2400,17 +2488,18 @@ function SweepApp({
|
|
|
2400
2488
|
];
|
|
2401
2489
|
const result = await scanAddresses(addresses, (p) => setScanProgress(p.detail ?? p.phase));
|
|
2402
2490
|
setAssets(result);
|
|
2403
|
-
const
|
|
2491
|
+
const grouped = groupBsv20Tokens2(result.bsv20Tokens);
|
|
2492
|
+
const total = result.funding.length + result.ordinals.length + result.opnsNames.length + result.bsv21Tokens.reduce((n, t) => n + t.outputs.length, 0) + grouped.reduce((n, t) => n + t.outputs.length, 0) + result.locked.length + result.run.length;
|
|
2404
2493
|
if (total === 0)
|
|
2405
2494
|
toast.info("No assets found at legacy addresses");
|
|
2406
2495
|
if (result.ordinals.length > 0)
|
|
2407
2496
|
setActiveTab("ordinals");
|
|
2408
2497
|
else if (result.opnsNames.length > 0)
|
|
2409
2498
|
setActiveTab("opns");
|
|
2499
|
+
else if (grouped.length > 0)
|
|
2500
|
+
setActiveTab("bsv20");
|
|
2410
2501
|
else if (result.bsv21Tokens.length > 0)
|
|
2411
2502
|
setActiveTab("bsv21");
|
|
2412
|
-
else if (result.bsv20Tokens.length > 0)
|
|
2413
|
-
setActiveTab("bsv20");
|
|
2414
2503
|
else if (result.locked.length > 0)
|
|
2415
2504
|
setActiveTab("locks");
|
|
2416
2505
|
} catch (e) {
|
|
@@ -2426,7 +2515,7 @@ function SweepApp({
|
|
|
2426
2515
|
}, [initialKeys, handleScan]);
|
|
2427
2516
|
const runOperation = useCallback2(async (label, op) => {
|
|
2428
2517
|
setSweeping(true);
|
|
2429
|
-
setSweepProgress(label
|
|
2518
|
+
setSweepProgress(`${label}...`);
|
|
2430
2519
|
try {
|
|
2431
2520
|
const txid = await op();
|
|
2432
2521
|
if (txid)
|
|
@@ -2466,17 +2555,11 @@ function SweepApp({
|
|
|
2466
2555
|
keys: keyMap,
|
|
2467
2556
|
funding: getSelectedFunding(),
|
|
2468
2557
|
ordinals: [],
|
|
2469
|
-
listings: assets.listings,
|
|
2470
2558
|
amount: sweepAmount ?? undefined,
|
|
2471
2559
|
onProgress: setSweepProgress
|
|
2472
2560
|
});
|
|
2473
|
-
|
|
2474
|
-
addTx("Cancel listings", txid);
|
|
2475
|
-
if (result.errors.length > 0) {
|
|
2476
|
-
if (result.cancelledListings.length > 0)
|
|
2477
|
-
await refreshAssets();
|
|
2561
|
+
if (result.errors.length > 0)
|
|
2478
2562
|
throw new Error(result.errors[0]);
|
|
2479
|
-
}
|
|
2480
2563
|
return result.bsvTxid ?? "";
|
|
2481
2564
|
});
|
|
2482
2565
|
}, [
|
|
@@ -2486,43 +2569,7 @@ function SweepApp({
|
|
|
2486
2569
|
sweepAmount,
|
|
2487
2570
|
getSelectedFunding,
|
|
2488
2571
|
runOperation,
|
|
2489
|
-
keyMap
|
|
2490
|
-
addTx,
|
|
2491
|
-
refreshAssets
|
|
2492
|
-
]);
|
|
2493
|
-
const handleCancelListings = useCallback2(async () => {
|
|
2494
|
-
const wallet = resolveWallet();
|
|
2495
|
-
if (!wallet || !legacyKeys || !assets || assets.listings.length === 0)
|
|
2496
|
-
return;
|
|
2497
|
-
await runOperation("Cancel listings", async () => {
|
|
2498
|
-
const result = await executeSweep({
|
|
2499
|
-
wallet,
|
|
2500
|
-
keys: keyMap,
|
|
2501
|
-
funding: [],
|
|
2502
|
-
ordinals: [],
|
|
2503
|
-
listings: assets.listings,
|
|
2504
|
-
onProgress: setSweepProgress
|
|
2505
|
-
});
|
|
2506
|
-
if (result.errors.length > 0) {
|
|
2507
|
-
for (const txid of result.listingTxids)
|
|
2508
|
-
addTx("Cancel listings", txid);
|
|
2509
|
-
if (result.cancelledListings.length > 0)
|
|
2510
|
-
await refreshAssets();
|
|
2511
|
-
throw new Error(result.errors[0]);
|
|
2512
|
-
}
|
|
2513
|
-
for (let i = 0;i < result.listingTxids.length - 1; i++) {
|
|
2514
|
-
addTx("Cancel listings", result.listingTxids[i]);
|
|
2515
|
-
}
|
|
2516
|
-
return result.listingTxids[result.listingTxids.length - 1] ?? "";
|
|
2517
|
-
});
|
|
2518
|
-
}, [
|
|
2519
|
-
resolveWallet,
|
|
2520
|
-
legacyKeys,
|
|
2521
|
-
assets,
|
|
2522
|
-
keyMap,
|
|
2523
|
-
runOperation,
|
|
2524
|
-
addTx,
|
|
2525
|
-
refreshAssets
|
|
2572
|
+
keyMap
|
|
2526
2573
|
]);
|
|
2527
2574
|
const handleSendBsv = useCallback2(async (destination) => {
|
|
2528
2575
|
if (!legacyKeys || !assets)
|
|
@@ -2705,11 +2752,65 @@ function SweepApp({
|
|
|
2705
2752
|
token,
|
|
2706
2753
|
onProgress: setSweepProgress
|
|
2707
2754
|
});
|
|
2755
|
+
for (const txid of result.txids.slice(0, -1))
|
|
2756
|
+
addTx("BSV-21", txid);
|
|
2708
2757
|
if (result.error)
|
|
2709
2758
|
throw new Error(result.error);
|
|
2710
2759
|
return result.txid ?? "";
|
|
2711
2760
|
});
|
|
2712
|
-
}, [resolveWallet, assets, keyMap, runOperation]);
|
|
2761
|
+
}, [resolveWallet, assets, keyMap, runOperation, addTx]);
|
|
2762
|
+
const handleSweepBsv20Token = useCallback2(async (tick) => {
|
|
2763
|
+
const wallet = resolveWallet();
|
|
2764
|
+
if (!wallet || !assets)
|
|
2765
|
+
return;
|
|
2766
|
+
const token = groupedBsv20.find((t) => t.tick === tick);
|
|
2767
|
+
if (!token)
|
|
2768
|
+
return;
|
|
2769
|
+
await runOperation(`Sweep ${token.tick}`, async () => {
|
|
2770
|
+
const result = await sweepBsv20Token({
|
|
2771
|
+
wallet,
|
|
2772
|
+
keys: keyMap,
|
|
2773
|
+
token,
|
|
2774
|
+
onProgress: setSweepProgress
|
|
2775
|
+
});
|
|
2776
|
+
if (result.error)
|
|
2777
|
+
throw new Error(result.error);
|
|
2778
|
+
return result.txid ?? "";
|
|
2779
|
+
});
|
|
2780
|
+
}, [resolveWallet, assets, groupedBsv20, keyMap, runOperation]);
|
|
2781
|
+
const handleSweepAll = useCallback2(async () => {
|
|
2782
|
+
const wallet = resolveWallet();
|
|
2783
|
+
if (!wallet || !legacyKeys || !assets)
|
|
2784
|
+
return;
|
|
2785
|
+
await runOperation("Sweep all", async () => {
|
|
2786
|
+
const result = await sweepAllClasses({
|
|
2787
|
+
wallet,
|
|
2788
|
+
keys: keyMap,
|
|
2789
|
+
assets,
|
|
2790
|
+
amount: sweepAmount ?? undefined,
|
|
2791
|
+
onProgress: setSweepProgress
|
|
2792
|
+
});
|
|
2793
|
+
if (result.bsvTxid)
|
|
2794
|
+
addTx("BSV", result.bsvTxid);
|
|
2795
|
+
for (const txid of result.ordinalTxids)
|
|
2796
|
+
addTx("Ordinals", txid);
|
|
2797
|
+
for (const txid of result.bsv20Txids)
|
|
2798
|
+
addTx("BSV-20", txid);
|
|
2799
|
+
for (const txid of result.bsv21Txids)
|
|
2800
|
+
addTx("BSV-21", txid);
|
|
2801
|
+
if (result.errors.length > 0)
|
|
2802
|
+
throw new Error(result.errors[0]);
|
|
2803
|
+
return result.bsvTxid ?? result.ordinalTxids.at(-1) ?? result.bsv20Txids.at(-1) ?? result.bsv21Txids.at(-1) ?? "";
|
|
2804
|
+
});
|
|
2805
|
+
}, [
|
|
2806
|
+
resolveWallet,
|
|
2807
|
+
legacyKeys,
|
|
2808
|
+
assets,
|
|
2809
|
+
keyMap,
|
|
2810
|
+
sweepAmount,
|
|
2811
|
+
runOperation,
|
|
2812
|
+
addTx
|
|
2813
|
+
]);
|
|
2713
2814
|
return /* @__PURE__ */ jsxs6("div", {
|
|
2714
2815
|
className: "min-h-screen bg-background text-foreground",
|
|
2715
2816
|
children: [
|
|
@@ -2749,6 +2850,13 @@ function SweepApp({
|
|
|
2749
2850
|
assets && !sweeping && /* @__PURE__ */ jsxs6("div", {
|
|
2750
2851
|
className: "space-y-3",
|
|
2751
2852
|
children: [
|
|
2853
|
+
/* @__PURE__ */ jsx11(Button, {
|
|
2854
|
+
className: "w-full",
|
|
2855
|
+
disabled: !walletConnected,
|
|
2856
|
+
onClick: handleSweepAll,
|
|
2857
|
+
title: walletConnected ? undefined : "Connect BRC-100 wallet to sweep",
|
|
2858
|
+
children: "Sweep all to wallet"
|
|
2859
|
+
}),
|
|
2752
2860
|
/* @__PURE__ */ jsx11(FundingSection, {
|
|
2753
2861
|
funding: assets.funding,
|
|
2754
2862
|
totalBsv: assets.totalBsv,
|
|
@@ -2758,11 +2866,6 @@ function SweepApp({
|
|
|
2758
2866
|
onSend: sweepOnly ? undefined : handleSendBsv,
|
|
2759
2867
|
walletConnected
|
|
2760
2868
|
}),
|
|
2761
|
-
/* @__PURE__ */ jsx11(ListingsSection, {
|
|
2762
|
-
listings: assets.listings,
|
|
2763
|
-
walletConnected,
|
|
2764
|
-
onCancel: handleCancelListings
|
|
2765
|
-
}),
|
|
2766
2869
|
tabs.length > 0 && /* @__PURE__ */ jsxs6(Tabs, {
|
|
2767
2870
|
value: activeTab,
|
|
2768
2871
|
onValueChange: (v) => setActiveTab(v),
|
|
@@ -2812,6 +2915,15 @@ function SweepApp({
|
|
|
2812
2915
|
walletConnected
|
|
2813
2916
|
})
|
|
2814
2917
|
}),
|
|
2918
|
+
/* @__PURE__ */ jsx11(TabsContent, {
|
|
2919
|
+
value: "bsv20",
|
|
2920
|
+
children: /* @__PURE__ */ jsx11(Bsv20Section, {
|
|
2921
|
+
tokens: groupedBsv20,
|
|
2922
|
+
unparsedCount: unparsedBsv20,
|
|
2923
|
+
onSweep: handleSweepBsv20Token,
|
|
2924
|
+
walletConnected
|
|
2925
|
+
})
|
|
2926
|
+
}),
|
|
2815
2927
|
/* @__PURE__ */ jsx11(TabsContent, {
|
|
2816
2928
|
value: "bsv21",
|
|
2817
2929
|
children: /* @__PURE__ */ jsx11(Bsv21Section, {
|
|
@@ -2820,12 +2932,6 @@ function SweepApp({
|
|
|
2820
2932
|
walletConnected
|
|
2821
2933
|
})
|
|
2822
2934
|
}),
|
|
2823
|
-
/* @__PURE__ */ jsx11(TabsContent, {
|
|
2824
|
-
value: "bsv20",
|
|
2825
|
-
children: /* @__PURE__ */ jsx11(Bsv20Section, {
|
|
2826
|
-
tokens: assets.bsv20Tokens
|
|
2827
|
-
})
|
|
2828
|
-
}),
|
|
2829
2935
|
/* @__PURE__ */ jsx11(TabsContent, {
|
|
2830
2936
|
value: "locks",
|
|
2831
2937
|
children: /* @__PURE__ */ jsx11(LockedSection, {
|
|
@@ -2970,7 +3076,6 @@ export {
|
|
|
2970
3076
|
ConnectWallet,
|
|
2971
3077
|
FundingSection,
|
|
2972
3078
|
Input,
|
|
2973
|
-
ListingsSection,
|
|
2974
3079
|
LockedSection,
|
|
2975
3080
|
OpnsSection,
|
|
2976
3081
|
OrdinalsSection,
|
|
@@ -3004,5 +3109,6 @@ export {
|
|
|
3004
3109
|
legacySendOrdinals,
|
|
3005
3110
|
scanAddress,
|
|
3006
3111
|
scanAddresses,
|
|
3112
|
+
sweepAllClasses,
|
|
3007
3113
|
truncate
|
|
3008
3114
|
};
|