@1sat/sweep-ui 0.0.75 → 0.0.77
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 +3 -2
- package/dist/components/asset-preview.d.ts.map +1 -1
- package/dist/components/opns-section.d.ts +3 -2
- package/dist/components/opns-section.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +252 -93
- package/dist/lib/sweeper.d.ts +5 -0
- package/dist/lib/sweeper.d.ts.map +1 -1
- package/package.json +52 -52
- package/src/components/SweepApp.tsx +101 -40
- package/src/components/asset-preview.tsx +82 -59
- package/src/components/opns-section.tsx +105 -50
- package/src/index.ts +5 -1
- package/src/lib/sweeper.ts +47 -13
package/dist/index.js
CHANGED
|
@@ -281,6 +281,7 @@ import {
|
|
|
281
281
|
sweepBsv21,
|
|
282
282
|
sweepOrdinals
|
|
283
283
|
} from "@1sat/actions";
|
|
284
|
+
var SWEEP_BATCH_SIZE = 25;
|
|
284
285
|
function getOwner(output) {
|
|
285
286
|
return output.events?.find((e) => e.startsWith("own:"))?.slice(4);
|
|
286
287
|
}
|
|
@@ -293,13 +294,21 @@ function buildKeys(outputs, keyMap) {
|
|
|
293
294
|
return key;
|
|
294
295
|
});
|
|
295
296
|
}
|
|
297
|
+
function chunk(items, size) {
|
|
298
|
+
const batches = [];
|
|
299
|
+
for (let i = 0;i < items.length; i += size) {
|
|
300
|
+
batches.push(items.slice(i, i + size));
|
|
301
|
+
}
|
|
302
|
+
return batches;
|
|
303
|
+
}
|
|
296
304
|
async function executeSweep(params) {
|
|
297
305
|
const { wallet, keys, funding, ordinals, amount, onProgress } = params;
|
|
298
306
|
const ctx = createContext(wallet, { services: getServices(), chain: "main" });
|
|
299
307
|
const result = {
|
|
300
308
|
ordinalTxids: [],
|
|
301
309
|
bsv21Txids: [],
|
|
302
|
-
errors: []
|
|
310
|
+
errors: [],
|
|
311
|
+
sweptOutpoints: []
|
|
303
312
|
};
|
|
304
313
|
if (funding.length > 0) {
|
|
305
314
|
onProgress(`Sweeping ${funding.length} BSV UTXOs...`);
|
|
@@ -319,22 +328,32 @@ async function executeSweep(params) {
|
|
|
319
328
|
}
|
|
320
329
|
}
|
|
321
330
|
if (ordinals.length > 0) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
331
|
+
const batches = chunk(ordinals, SWEEP_BATCH_SIZE);
|
|
332
|
+
for (let b = 0;b < batches.length; b++) {
|
|
333
|
+
const batch = batches[b];
|
|
334
|
+
const from = b * SWEEP_BATCH_SIZE + 1;
|
|
335
|
+
const to = b * SWEEP_BATCH_SIZE + batch.length;
|
|
336
|
+
onProgress(batches.length === 1 ? `Sweeping ${batch.length} ordinal${batch.length !== 1 ? "s" : ""}...` : `Sweeping ordinals ${from}–${to} of ${ordinals.length} (batch ${b + 1}/${batches.length})...`);
|
|
337
|
+
try {
|
|
338
|
+
const inputs = await prepareSweepInputs(ctx, batch);
|
|
339
|
+
const ordResult = await sweepOrdinals.execute(ctx, {
|
|
340
|
+
inputs,
|
|
341
|
+
keys: buildKeys(batch, keys)
|
|
342
|
+
});
|
|
343
|
+
if (ordResult.error) {
|
|
344
|
+
result.errors.push(`Ordinals batch ${b + 1}/${batches.length}: ${ordResult.error}`);
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
if (ordResult.txid)
|
|
348
|
+
result.ordinalTxids.push(ordResult.txid);
|
|
349
|
+
result.sweptOutpoints.push(...batch.map((o) => o.outpoint));
|
|
350
|
+
} catch (e) {
|
|
351
|
+
result.errors.push(`Ordinals batch ${b + 1}/${batches.length}: ${e instanceof Error ? e.message : String(e)}`);
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
335
354
|
}
|
|
336
355
|
}
|
|
337
|
-
onProgress("Sweep complete");
|
|
356
|
+
onProgress(result.errors.length > 0 ? "Sweep stopped with errors" : "Sweep complete");
|
|
338
357
|
return result;
|
|
339
358
|
}
|
|
340
359
|
async function sweepBsv21Token(params) {
|
|
@@ -507,7 +526,6 @@ function Input({ className, type, ...props }) {
|
|
|
507
526
|
|
|
508
527
|
// src/components/asset-preview.tsx
|
|
509
528
|
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
510
|
-
var ORDINALS_PER_PAGE = 20;
|
|
511
529
|
function isImageType(ct) {
|
|
512
530
|
return ct.startsWith("image/") && ct !== "image/svg+xml";
|
|
513
531
|
}
|
|
@@ -715,9 +733,10 @@ function OrdinalsSection({
|
|
|
715
733
|
ordinals,
|
|
716
734
|
selectedOrdinals,
|
|
717
735
|
onToggle,
|
|
718
|
-
|
|
736
|
+
onSelectPage,
|
|
719
737
|
onDeselectAll,
|
|
720
738
|
onSweep,
|
|
739
|
+
onSweepAll,
|
|
721
740
|
onSend,
|
|
722
741
|
onBurn,
|
|
723
742
|
walletConnected
|
|
@@ -726,9 +745,13 @@ function OrdinalsSection({
|
|
|
726
745
|
const [address, setAddress] = useState("");
|
|
727
746
|
if (ordinals.length === 0)
|
|
728
747
|
return null;
|
|
729
|
-
const totalPages = Math.ceil(ordinals.length /
|
|
730
|
-
const
|
|
731
|
-
const
|
|
748
|
+
const totalPages = Math.ceil(ordinals.length / SWEEP_BATCH_SIZE);
|
|
749
|
+
const safePage = Math.min(page, totalPages - 1);
|
|
750
|
+
const start = safePage * SWEEP_BATCH_SIZE;
|
|
751
|
+
const pageItems = ordinals.slice(start, start + SWEEP_BATCH_SIZE);
|
|
752
|
+
const pageOutpoints = pageItems.map((o) => o.outpoint);
|
|
753
|
+
const selectedCount = selectedOrdinals.size;
|
|
754
|
+
const batchCount = Math.ceil(ordinals.length / SWEEP_BATCH_SIZE);
|
|
732
755
|
return /* @__PURE__ */ jsxs("div", {
|
|
733
756
|
className: "border border-blue-500/20 bg-blue-500/5 p-4 rounded-lg",
|
|
734
757
|
children: [
|
|
@@ -755,13 +778,21 @@ function OrdinalsSection({
|
|
|
755
778
|
ordinals.length,
|
|
756
779
|
" inscription",
|
|
757
780
|
ordinals.length !== 1 ? "s" : "",
|
|
758
|
-
|
|
781
|
+
selectedCount > 0 && /* @__PURE__ */ jsxs("span", {
|
|
759
782
|
className: "text-blue-400 ml-1",
|
|
760
783
|
children: [
|
|
761
784
|
"(",
|
|
762
|
-
|
|
785
|
+
selectedCount,
|
|
763
786
|
" selected)"
|
|
764
787
|
]
|
|
788
|
+
}),
|
|
789
|
+
/* @__PURE__ */ jsxs("span", {
|
|
790
|
+
className: "ml-1 text-muted-foreground/80",
|
|
791
|
+
children: [
|
|
792
|
+
"· ",
|
|
793
|
+
SWEEP_BATCH_SIZE,
|
|
794
|
+
"/page"
|
|
795
|
+
]
|
|
765
796
|
})
|
|
766
797
|
]
|
|
767
798
|
})
|
|
@@ -774,15 +805,15 @@ function OrdinalsSection({
|
|
|
774
805
|
variant: "outline",
|
|
775
806
|
size: "sm",
|
|
776
807
|
className: "h-7 text-[11px]",
|
|
777
|
-
onClick:
|
|
778
|
-
children: "Select
|
|
808
|
+
onClick: () => onSelectPage(pageOutpoints),
|
|
809
|
+
children: "Select page"
|
|
779
810
|
}),
|
|
780
811
|
/* @__PURE__ */ jsx4(Button, {
|
|
781
812
|
variant: "outline",
|
|
782
813
|
size: "sm",
|
|
783
814
|
className: "h-7 text-[11px]",
|
|
784
815
|
onClick: onDeselectAll,
|
|
785
|
-
disabled:
|
|
816
|
+
disabled: selectedCount === 0,
|
|
786
817
|
children: "Deselect"
|
|
787
818
|
})
|
|
788
819
|
]
|
|
@@ -804,15 +835,15 @@ function OrdinalsSection({
|
|
|
804
835
|
variant: "ghost",
|
|
805
836
|
size: "sm",
|
|
806
837
|
className: "text-xs",
|
|
807
|
-
onClick: () => setPage(
|
|
808
|
-
disabled:
|
|
838
|
+
onClick: () => setPage(safePage - 1),
|
|
839
|
+
disabled: safePage === 0,
|
|
809
840
|
children: "Prev"
|
|
810
841
|
}),
|
|
811
842
|
/* @__PURE__ */ jsxs("span", {
|
|
812
843
|
className: "text-xs text-muted-foreground",
|
|
813
844
|
children: [
|
|
814
845
|
"Page ",
|
|
815
|
-
|
|
846
|
+
safePage + 1,
|
|
816
847
|
" of ",
|
|
817
848
|
totalPages
|
|
818
849
|
]
|
|
@@ -821,16 +852,16 @@ function OrdinalsSection({
|
|
|
821
852
|
variant: "ghost",
|
|
822
853
|
size: "sm",
|
|
823
854
|
className: "text-xs",
|
|
824
|
-
onClick: () => setPage(
|
|
825
|
-
disabled:
|
|
855
|
+
onClick: () => setPage(safePage + 1),
|
|
856
|
+
disabled: safePage >= totalPages - 1,
|
|
826
857
|
children: "Next"
|
|
827
858
|
})
|
|
828
859
|
]
|
|
829
860
|
}),
|
|
830
|
-
|
|
861
|
+
/* @__PURE__ */ jsxs("div", {
|
|
831
862
|
className: "mt-3 space-y-2",
|
|
832
863
|
children: [
|
|
833
|
-
onSend && /* @__PURE__ */ jsx4(Input, {
|
|
864
|
+
selectedCount > 0 && onSend && /* @__PURE__ */ jsx4(Input, {
|
|
834
865
|
type: "text",
|
|
835
866
|
placeholder: "Destination address...",
|
|
836
867
|
value: address,
|
|
@@ -838,34 +869,48 @@ function OrdinalsSection({
|
|
|
838
869
|
className: "font-mono text-xs"
|
|
839
870
|
}),
|
|
840
871
|
/* @__PURE__ */ jsxs("div", {
|
|
841
|
-
className: "flex gap-2",
|
|
872
|
+
className: "flex flex-wrap gap-2",
|
|
842
873
|
children: [
|
|
843
|
-
onSend && /* @__PURE__ */ jsxs(Button, {
|
|
874
|
+
selectedCount > 0 && onSend && /* @__PURE__ */ jsxs(Button, {
|
|
844
875
|
variant: "outline",
|
|
845
876
|
size: "sm",
|
|
846
|
-
className: "flex-1",
|
|
877
|
+
className: "flex-1 min-w-[6rem]",
|
|
847
878
|
disabled: !address.trim(),
|
|
848
879
|
onClick: () => onSend(address.trim()),
|
|
849
880
|
children: [
|
|
850
881
|
"Send ",
|
|
851
|
-
|
|
852
|
-
" Ordinal",
|
|
853
|
-
selectedOrdinals.size !== 1 ? "s" : ""
|
|
882
|
+
selectedCount
|
|
854
883
|
]
|
|
855
884
|
}),
|
|
856
|
-
/* @__PURE__ */
|
|
885
|
+
selectedCount > 0 && /* @__PURE__ */ jsxs(Button, {
|
|
857
886
|
size: "sm",
|
|
858
|
-
className: "flex-1",
|
|
887
|
+
className: "flex-1 min-w-[6rem]",
|
|
859
888
|
onClick: onSweep,
|
|
860
889
|
disabled: !walletConnected,
|
|
861
890
|
title: walletConnected ? undefined : "Connect BRC-100 wallet to sweep",
|
|
862
|
-
children:
|
|
891
|
+
children: [
|
|
892
|
+
"Sweep ",
|
|
893
|
+
selectedCount,
|
|
894
|
+
selectedCount > SWEEP_BATCH_SIZE ? ` (${Math.ceil(selectedCount / SWEEP_BATCH_SIZE)} batches)` : ""
|
|
895
|
+
]
|
|
863
896
|
}),
|
|
864
|
-
|
|
897
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
898
|
+
variant: selectedCount > 0 ? "outline" : "default",
|
|
899
|
+
size: "sm",
|
|
900
|
+
className: "flex-1 min-w-[6rem]",
|
|
901
|
+
onClick: onSweepAll,
|
|
902
|
+
disabled: !walletConnected,
|
|
903
|
+
title: walletConnected ? undefined : "Connect BRC-100 wallet to sweep",
|
|
904
|
+
children: [
|
|
905
|
+
"Sweep all",
|
|
906
|
+
batchCount > 1 ? ` (${batchCount} batches)` : ""
|
|
907
|
+
]
|
|
908
|
+
}),
|
|
909
|
+
selectedCount > 0 && onBurn && /* @__PURE__ */ jsx4(Button, {
|
|
865
910
|
size: "sm",
|
|
866
911
|
className: "bg-red-600 hover:bg-red-700 text-white",
|
|
867
912
|
onClick: () => {
|
|
868
|
-
if (window.confirm(`Permanently burn ${
|
|
913
|
+
if (window.confirm(`Permanently burn ${selectedCount} ordinal${selectedCount !== 1 ? "s" : ""}? This cannot be undone.`))
|
|
869
914
|
onBurn();
|
|
870
915
|
},
|
|
871
916
|
children: "Burn"
|
|
@@ -1202,13 +1247,15 @@ function OpnsSection({
|
|
|
1202
1247
|
opnsNames,
|
|
1203
1248
|
selectedOpns,
|
|
1204
1249
|
onToggle,
|
|
1205
|
-
|
|
1250
|
+
onSelectPage,
|
|
1206
1251
|
onDeselectAll,
|
|
1207
1252
|
onSweep,
|
|
1253
|
+
onSweepAll,
|
|
1208
1254
|
onSend,
|
|
1209
1255
|
onBurn,
|
|
1210
1256
|
walletConnected
|
|
1211
1257
|
}) {
|
|
1258
|
+
const [page, setPage] = useState3(0);
|
|
1212
1259
|
const [address, setAddress] = useState3("");
|
|
1213
1260
|
const [resolvedNames, setResolvedNames] = useState3(new Map);
|
|
1214
1261
|
const [overlayValid, setOverlayValid] = useState3(new Map);
|
|
@@ -1263,6 +1310,13 @@ function OpnsSection({
|
|
|
1263
1310
|
}, [opnsNames]);
|
|
1264
1311
|
if (opnsNames.length === 0)
|
|
1265
1312
|
return null;
|
|
1313
|
+
const totalPages = Math.ceil(opnsNames.length / SWEEP_BATCH_SIZE);
|
|
1314
|
+
const safePage = Math.min(page, totalPages - 1);
|
|
1315
|
+
const start = safePage * SWEEP_BATCH_SIZE;
|
|
1316
|
+
const pageItems = opnsNames.slice(start, start + SWEEP_BATCH_SIZE);
|
|
1317
|
+
const pageOutpoints = pageItems.map((o) => o.outpoint);
|
|
1318
|
+
const selectedCount = selectedOpns.size;
|
|
1319
|
+
const batchCount = Math.ceil(opnsNames.length / SWEEP_BATCH_SIZE);
|
|
1266
1320
|
return /* @__PURE__ */ jsxs3("div", {
|
|
1267
1321
|
className: "border border-orange-500/20 bg-orange-500/5 p-4 rounded-lg",
|
|
1268
1322
|
children: [
|
|
@@ -1289,13 +1343,21 @@ function OpnsSection({
|
|
|
1289
1343
|
opnsNames.length,
|
|
1290
1344
|
" domain",
|
|
1291
1345
|
opnsNames.length !== 1 ? "s" : "",
|
|
1292
|
-
|
|
1346
|
+
selectedCount > 0 && /* @__PURE__ */ jsxs3("span", {
|
|
1293
1347
|
className: "text-orange-400 ml-1",
|
|
1294
1348
|
children: [
|
|
1295
1349
|
"(",
|
|
1296
|
-
|
|
1350
|
+
selectedCount,
|
|
1297
1351
|
" selected)"
|
|
1298
1352
|
]
|
|
1353
|
+
}),
|
|
1354
|
+
/* @__PURE__ */ jsxs3("span", {
|
|
1355
|
+
className: "ml-1 text-muted-foreground/80",
|
|
1356
|
+
children: [
|
|
1357
|
+
"· ",
|
|
1358
|
+
SWEEP_BATCH_SIZE,
|
|
1359
|
+
"/page"
|
|
1360
|
+
]
|
|
1299
1361
|
})
|
|
1300
1362
|
]
|
|
1301
1363
|
})
|
|
@@ -1308,15 +1370,15 @@ function OpnsSection({
|
|
|
1308
1370
|
variant: "outline",
|
|
1309
1371
|
size: "sm",
|
|
1310
1372
|
className: "h-7 text-[11px]",
|
|
1311
|
-
onClick:
|
|
1312
|
-
children: "Select
|
|
1373
|
+
onClick: () => onSelectPage(pageOutpoints),
|
|
1374
|
+
children: "Select page"
|
|
1313
1375
|
}),
|
|
1314
1376
|
/* @__PURE__ */ jsx6(Button, {
|
|
1315
1377
|
variant: "outline",
|
|
1316
1378
|
size: "sm",
|
|
1317
1379
|
className: "h-7 text-[11px]",
|
|
1318
1380
|
onClick: onDeselectAll,
|
|
1319
|
-
disabled:
|
|
1381
|
+
disabled: selectedCount === 0,
|
|
1320
1382
|
children: "Deselect"
|
|
1321
1383
|
})
|
|
1322
1384
|
]
|
|
@@ -1325,7 +1387,7 @@ function OpnsSection({
|
|
|
1325
1387
|
}),
|
|
1326
1388
|
/* @__PURE__ */ jsx6("div", {
|
|
1327
1389
|
className: "space-y-1",
|
|
1328
|
-
children:
|
|
1390
|
+
children: pageItems.map((item) => {
|
|
1329
1391
|
const isSelected = selectedOpns.has(item.outpoint);
|
|
1330
1392
|
const displayName = resolvedNames.get(item.outpoint) ?? item.outpoint.substring(0, 8) + "...";
|
|
1331
1393
|
return /* @__PURE__ */ jsxs3("div", {
|
|
@@ -1351,10 +1413,40 @@ function OpnsSection({
|
|
|
1351
1413
|
}, item.outpoint);
|
|
1352
1414
|
})
|
|
1353
1415
|
}),
|
|
1354
|
-
|
|
1416
|
+
totalPages > 1 && /* @__PURE__ */ jsxs3("div", {
|
|
1417
|
+
className: "flex items-center justify-center gap-4 mt-2",
|
|
1418
|
+
children: [
|
|
1419
|
+
/* @__PURE__ */ jsx6(Button, {
|
|
1420
|
+
variant: "ghost",
|
|
1421
|
+
size: "sm",
|
|
1422
|
+
className: "text-xs",
|
|
1423
|
+
onClick: () => setPage(safePage - 1),
|
|
1424
|
+
disabled: safePage === 0,
|
|
1425
|
+
children: "Prev"
|
|
1426
|
+
}),
|
|
1427
|
+
/* @__PURE__ */ jsxs3("span", {
|
|
1428
|
+
className: "text-xs text-muted-foreground",
|
|
1429
|
+
children: [
|
|
1430
|
+
"Page ",
|
|
1431
|
+
safePage + 1,
|
|
1432
|
+
" of ",
|
|
1433
|
+
totalPages
|
|
1434
|
+
]
|
|
1435
|
+
}),
|
|
1436
|
+
/* @__PURE__ */ jsx6(Button, {
|
|
1437
|
+
variant: "ghost",
|
|
1438
|
+
size: "sm",
|
|
1439
|
+
className: "text-xs",
|
|
1440
|
+
onClick: () => setPage(safePage + 1),
|
|
1441
|
+
disabled: safePage >= totalPages - 1,
|
|
1442
|
+
children: "Next"
|
|
1443
|
+
})
|
|
1444
|
+
]
|
|
1445
|
+
}),
|
|
1446
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
1355
1447
|
className: "mt-3 space-y-2",
|
|
1356
1448
|
children: [
|
|
1357
|
-
onSend && /* @__PURE__ */ jsx6(Input, {
|
|
1449
|
+
selectedCount > 0 && onSend && /* @__PURE__ */ jsx6(Input, {
|
|
1358
1450
|
type: "text",
|
|
1359
1451
|
placeholder: "Destination address...",
|
|
1360
1452
|
value: address,
|
|
@@ -1362,34 +1454,48 @@ function OpnsSection({
|
|
|
1362
1454
|
className: "font-mono text-xs"
|
|
1363
1455
|
}),
|
|
1364
1456
|
/* @__PURE__ */ jsxs3("div", {
|
|
1365
|
-
className: "flex gap-2",
|
|
1457
|
+
className: "flex flex-wrap gap-2",
|
|
1366
1458
|
children: [
|
|
1367
|
-
onSend && /* @__PURE__ */ jsxs3(Button, {
|
|
1459
|
+
selectedCount > 0 && onSend && /* @__PURE__ */ jsxs3(Button, {
|
|
1368
1460
|
variant: "outline",
|
|
1369
1461
|
size: "sm",
|
|
1370
|
-
className: "flex-1",
|
|
1462
|
+
className: "flex-1 min-w-[6rem]",
|
|
1371
1463
|
disabled: !address.trim(),
|
|
1372
1464
|
onClick: () => onSend(address.trim()),
|
|
1373
1465
|
children: [
|
|
1374
1466
|
"Send ",
|
|
1375
|
-
|
|
1376
|
-
" Domain",
|
|
1377
|
-
selectedOpns.size !== 1 ? "s" : ""
|
|
1467
|
+
selectedCount
|
|
1378
1468
|
]
|
|
1379
1469
|
}),
|
|
1380
|
-
/* @__PURE__ */
|
|
1470
|
+
selectedCount > 0 && /* @__PURE__ */ jsxs3(Button, {
|
|
1381
1471
|
size: "sm",
|
|
1382
|
-
className: "flex-1",
|
|
1472
|
+
className: "flex-1 min-w-[6rem]",
|
|
1383
1473
|
onClick: onSweep,
|
|
1384
1474
|
disabled: !walletConnected,
|
|
1385
1475
|
title: walletConnected ? undefined : "Connect BRC-100 wallet to sweep",
|
|
1386
|
-
children:
|
|
1476
|
+
children: [
|
|
1477
|
+
"Sweep ",
|
|
1478
|
+
selectedCount,
|
|
1479
|
+
selectedCount > SWEEP_BATCH_SIZE ? ` (${Math.ceil(selectedCount / SWEEP_BATCH_SIZE)} batches)` : ""
|
|
1480
|
+
]
|
|
1481
|
+
}),
|
|
1482
|
+
/* @__PURE__ */ jsxs3(Button, {
|
|
1483
|
+
variant: selectedCount > 0 ? "outline" : "default",
|
|
1484
|
+
size: "sm",
|
|
1485
|
+
className: "flex-1 min-w-[6rem]",
|
|
1486
|
+
onClick: onSweepAll,
|
|
1487
|
+
disabled: !walletConnected,
|
|
1488
|
+
title: walletConnected ? undefined : "Connect BRC-100 wallet to sweep",
|
|
1489
|
+
children: [
|
|
1490
|
+
"Sweep all",
|
|
1491
|
+
batchCount > 1 ? ` (${batchCount} batches)` : ""
|
|
1492
|
+
]
|
|
1387
1493
|
}),
|
|
1388
|
-
onBurn && /* @__PURE__ */ jsx6(Button, {
|
|
1494
|
+
selectedCount > 0 && onBurn && /* @__PURE__ */ jsx6(Button, {
|
|
1389
1495
|
size: "sm",
|
|
1390
1496
|
className: "bg-red-600 hover:bg-red-700 text-white",
|
|
1391
1497
|
onClick: () => {
|
|
1392
|
-
if (window.confirm(`Permanently burn ${
|
|
1498
|
+
if (window.confirm(`Permanently burn ${selectedCount} domain${selectedCount !== 1 ? "s" : ""}? This cannot be undone.`))
|
|
1393
1499
|
onBurn();
|
|
1394
1500
|
},
|
|
1395
1501
|
children: "Burn"
|
|
@@ -2163,10 +2269,9 @@ function SweepApp({
|
|
|
2163
2269
|
return next;
|
|
2164
2270
|
});
|
|
2165
2271
|
}, []);
|
|
2166
|
-
const
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
}, [assets]);
|
|
2272
|
+
const handleSelectOrdinalPage = useCallback2((outpoints) => {
|
|
2273
|
+
setSelectedOrdinals(new Set(outpoints));
|
|
2274
|
+
}, []);
|
|
2170
2275
|
const handleDeselectAllOrdinals = useCallback2(() => setSelectedOrdinals(new Set), []);
|
|
2171
2276
|
const handleToggleOpns = useCallback2((outpoint) => {
|
|
2172
2277
|
setSelectedOpns((prev) => {
|
|
@@ -2178,10 +2283,9 @@ function SweepApp({
|
|
|
2178
2283
|
return next;
|
|
2179
2284
|
});
|
|
2180
2285
|
}, []);
|
|
2181
|
-
const
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
}, [assets]);
|
|
2286
|
+
const handleSelectOpnsPage = useCallback2((outpoints) => {
|
|
2287
|
+
setSelectedOpns(new Set(outpoints));
|
|
2288
|
+
}, []);
|
|
2185
2289
|
const handleDeselectAllOpns = useCallback2(() => setSelectedOpns(new Set), []);
|
|
2186
2290
|
const refreshAssets = useCallback2(async () => {
|
|
2187
2291
|
if (!legacyKeys)
|
|
@@ -2309,26 +2413,52 @@ function SweepApp({
|
|
|
2309
2413
|
return result.txid;
|
|
2310
2414
|
});
|
|
2311
2415
|
}, [legacyKeys, assets, sweepAmount, getSelectedFunding, runOperation]);
|
|
2312
|
-
const
|
|
2416
|
+
const sweepOrdinalList = useCallback2(async (list, label) => {
|
|
2313
2417
|
const wallet = resolveWallet();
|
|
2314
|
-
if (!wallet || !legacyKeys ||
|
|
2418
|
+
if (!wallet || !legacyKeys || list.length === 0)
|
|
2315
2419
|
return;
|
|
2316
|
-
|
|
2317
|
-
if (selected.length === 0)
|
|
2318
|
-
return;
|
|
2319
|
-
await runOperation(`Sweep ${selected.length} ordinal${selected.length !== 1 ? "s" : ""}`, async () => {
|
|
2420
|
+
await runOperation(label, async () => {
|
|
2320
2421
|
const result = await executeSweep({
|
|
2321
2422
|
wallet,
|
|
2322
2423
|
keys: keyMap,
|
|
2323
2424
|
funding: [],
|
|
2324
|
-
ordinals:
|
|
2425
|
+
ordinals: list,
|
|
2325
2426
|
onProgress: setSweepProgress
|
|
2326
2427
|
});
|
|
2327
|
-
if (result.
|
|
2428
|
+
if (result.sweptOutpoints.length > 0) {
|
|
2429
|
+
setSelectedOrdinals((prev) => {
|
|
2430
|
+
const next = new Set(prev);
|
|
2431
|
+
for (const op of result.sweptOutpoints)
|
|
2432
|
+
next.delete(op);
|
|
2433
|
+
return next;
|
|
2434
|
+
});
|
|
2435
|
+
}
|
|
2436
|
+
if (result.errors.length > 0) {
|
|
2437
|
+
for (const txid of result.ordinalTxids)
|
|
2438
|
+
addTx(label, txid);
|
|
2439
|
+
if (result.sweptOutpoints.length > 0)
|
|
2440
|
+
await refreshAssets();
|
|
2328
2441
|
throw new Error(result.errors[0]);
|
|
2329
|
-
|
|
2442
|
+
}
|
|
2443
|
+
for (let i = 0;i < result.ordinalTxids.length - 1; i++) {
|
|
2444
|
+
addTx(label, result.ordinalTxids[i]);
|
|
2445
|
+
}
|
|
2446
|
+
return result.ordinalTxids[result.ordinalTxids.length - 1] ?? "";
|
|
2330
2447
|
});
|
|
2331
|
-
}, [resolveWallet, legacyKeys,
|
|
2448
|
+
}, [resolveWallet, legacyKeys, keyMap, runOperation, addTx, refreshAssets]);
|
|
2449
|
+
const handleSweepOrdinals = useCallback2(async () => {
|
|
2450
|
+
if (!assets)
|
|
2451
|
+
return;
|
|
2452
|
+
const selected = assets.ordinals.filter((o) => selectedOrdinals.has(o.outpoint));
|
|
2453
|
+
if (selected.length === 0)
|
|
2454
|
+
return;
|
|
2455
|
+
await sweepOrdinalList(selected, `Sweep ${selected.length} ordinal${selected.length !== 1 ? "s" : ""}`);
|
|
2456
|
+
}, [assets, selectedOrdinals, sweepOrdinalList]);
|
|
2457
|
+
const handleSweepAllOrdinals = useCallback2(async () => {
|
|
2458
|
+
if (!assets || assets.ordinals.length === 0)
|
|
2459
|
+
return;
|
|
2460
|
+
await sweepOrdinalList(assets.ordinals, `Sweep all ${assets.ordinals.length} ordinal${assets.ordinals.length !== 1 ? "s" : ""}`);
|
|
2461
|
+
}, [assets, sweepOrdinalList]);
|
|
2332
2462
|
const handleSendOrdinals = useCallback2(async (destination) => {
|
|
2333
2463
|
if (!legacyKeys || !assets)
|
|
2334
2464
|
return;
|
|
@@ -2360,26 +2490,52 @@ function SweepApp({
|
|
|
2360
2490
|
return result.txid;
|
|
2361
2491
|
});
|
|
2362
2492
|
}, [legacyKeys, assets, selectedOrdinals, runOperation]);
|
|
2363
|
-
const
|
|
2493
|
+
const sweepOpnsList = useCallback2(async (list, label) => {
|
|
2364
2494
|
const wallet = resolveWallet();
|
|
2365
|
-
if (!wallet || !legacyKeys ||
|
|
2366
|
-
return;
|
|
2367
|
-
const selected = assets.opnsNames.filter((o) => selectedOpns.has(o.outpoint));
|
|
2368
|
-
if (selected.length === 0)
|
|
2495
|
+
if (!wallet || !legacyKeys || list.length === 0)
|
|
2369
2496
|
return;
|
|
2370
|
-
await runOperation(
|
|
2497
|
+
await runOperation(label, async () => {
|
|
2371
2498
|
const result = await executeSweep({
|
|
2372
2499
|
wallet,
|
|
2373
2500
|
keys: keyMap,
|
|
2374
2501
|
funding: [],
|
|
2375
|
-
ordinals:
|
|
2502
|
+
ordinals: list,
|
|
2376
2503
|
onProgress: setSweepProgress
|
|
2377
2504
|
});
|
|
2378
|
-
if (result.
|
|
2505
|
+
if (result.sweptOutpoints.length > 0) {
|
|
2506
|
+
setSelectedOpns((prev) => {
|
|
2507
|
+
const next = new Set(prev);
|
|
2508
|
+
for (const op of result.sweptOutpoints)
|
|
2509
|
+
next.delete(op);
|
|
2510
|
+
return next;
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
if (result.errors.length > 0) {
|
|
2514
|
+
for (const txid of result.ordinalTxids)
|
|
2515
|
+
addTx(label, txid);
|
|
2516
|
+
if (result.sweptOutpoints.length > 0)
|
|
2517
|
+
await refreshAssets();
|
|
2379
2518
|
throw new Error(result.errors[0]);
|
|
2380
|
-
|
|
2519
|
+
}
|
|
2520
|
+
for (let i = 0;i < result.ordinalTxids.length - 1; i++) {
|
|
2521
|
+
addTx(label, result.ordinalTxids[i]);
|
|
2522
|
+
}
|
|
2523
|
+
return result.ordinalTxids[result.ordinalTxids.length - 1] ?? "";
|
|
2381
2524
|
});
|
|
2382
|
-
}, [resolveWallet, legacyKeys,
|
|
2525
|
+
}, [resolveWallet, legacyKeys, keyMap, runOperation, addTx, refreshAssets]);
|
|
2526
|
+
const handleSweepOpns = useCallback2(async () => {
|
|
2527
|
+
if (!assets)
|
|
2528
|
+
return;
|
|
2529
|
+
const selected = assets.opnsNames.filter((o) => selectedOpns.has(o.outpoint));
|
|
2530
|
+
if (selected.length === 0)
|
|
2531
|
+
return;
|
|
2532
|
+
await sweepOpnsList(selected, `Sweep ${selected.length} domain${selected.length !== 1 ? "s" : ""}`);
|
|
2533
|
+
}, [assets, selectedOpns, sweepOpnsList]);
|
|
2534
|
+
const handleSweepAllOpns = useCallback2(async () => {
|
|
2535
|
+
if (!assets || assets.opnsNames.length === 0)
|
|
2536
|
+
return;
|
|
2537
|
+
await sweepOpnsList(assets.opnsNames, `Sweep all ${assets.opnsNames.length} domain${assets.opnsNames.length !== 1 ? "s" : ""}`);
|
|
2538
|
+
}, [assets, sweepOpnsList]);
|
|
2383
2539
|
const handleSendOpns = useCallback2(async (destination) => {
|
|
2384
2540
|
if (!legacyKeys || !assets)
|
|
2385
2541
|
return;
|
|
@@ -2503,9 +2659,10 @@ function SweepApp({
|
|
|
2503
2659
|
ordinals: assets.ordinals,
|
|
2504
2660
|
selectedOrdinals,
|
|
2505
2661
|
onToggle: handleToggleOrdinal,
|
|
2506
|
-
|
|
2662
|
+
onSelectPage: handleSelectOrdinalPage,
|
|
2507
2663
|
onDeselectAll: handleDeselectAllOrdinals,
|
|
2508
2664
|
onSweep: handleSweepOrdinals,
|
|
2665
|
+
onSweepAll: handleSweepAllOrdinals,
|
|
2509
2666
|
onSend: sweepOnly ? undefined : handleSendOrdinals,
|
|
2510
2667
|
onBurn: sweepOnly ? undefined : handleBurnOrdinals,
|
|
2511
2668
|
walletConnected
|
|
@@ -2517,9 +2674,10 @@ function SweepApp({
|
|
|
2517
2674
|
opnsNames: assets.opnsNames,
|
|
2518
2675
|
selectedOpns,
|
|
2519
2676
|
onToggle: handleToggleOpns,
|
|
2520
|
-
|
|
2677
|
+
onSelectPage: handleSelectOpnsPage,
|
|
2521
2678
|
onDeselectAll: handleDeselectAllOpns,
|
|
2522
2679
|
onSweep: handleSweepOpns,
|
|
2680
|
+
onSweepAll: handleSweepAllOpns,
|
|
2523
2681
|
onSend: sweepOnly ? undefined : handleSendOpns,
|
|
2524
2682
|
onBurn: sweepOnly ? undefined : handleBurnOpns,
|
|
2525
2683
|
walletConnected
|
|
@@ -2698,6 +2856,7 @@ export {
|
|
|
2698
2856
|
Tabs,
|
|
2699
2857
|
SweepProgress,
|
|
2700
2858
|
SweepApp,
|
|
2859
|
+
SWEEP_BATCH_SIZE,
|
|
2701
2860
|
RunSection,
|
|
2702
2861
|
OrdinalsSection,
|
|
2703
2862
|
OpnsSection,
|
package/dist/lib/sweeper.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import type { IndexedOutput } from '@1sat/types';
|
|
2
2
|
import type { PrivateKey, WalletInterface } from '@bsv/sdk';
|
|
3
3
|
import type { TokenBalance } from './scanner';
|
|
4
|
+
/** Page size, select-page size, and createAction batch size for ordinal/OpNS sweeps. */
|
|
5
|
+
export declare const SWEEP_BATCH_SIZE = 25;
|
|
4
6
|
export interface SweepResult {
|
|
5
7
|
bsvTxid?: string;
|
|
6
8
|
ordinalTxids: string[];
|
|
7
9
|
bsv21Txids: string[];
|
|
8
10
|
errors: string[];
|
|
11
|
+
/** Outpoints successfully swept (ordinals/OpNS). */
|
|
12
|
+
sweptOutpoints: string[];
|
|
9
13
|
}
|
|
10
14
|
/**
|
|
11
15
|
* Sweep BSV funding and ordinals into the connected wallet.
|
|
16
|
+
* Ordinals are processed in batches of {@link SWEEP_BATCH_SIZE}; stops on first batch error.
|
|
12
17
|
*/
|
|
13
18
|
export declare function executeSweep(params: {
|
|
14
19
|
wallet: WalletInterface;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sweeper.d.ts","sourceRoot":"","sources":["../../src/lib/sweeper.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAG7C,MAAM,WAAW,WAAW;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"sweeper.d.ts","sourceRoot":"","sources":["../../src/lib/sweeper.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAG7C,wFAAwF;AACxF,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,MAAM,WAAW,WAAW;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,oDAAoD;IACpD,cAAc,EAAE,MAAM,EAAE,CAAA;CACxB;AA2BD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE;IAC1C,MAAM,EAAE,eAAe,CAAA;IACvB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IAC7B,OAAO,EAAE,aAAa,EAAE,CAAA;IACxB,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC,GAAG,OAAO,CAAC,WAAW,CAAC,CAiEvB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC7C,MAAM,EAAE,eAAe,CAAA;IACvB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IAC7B,KAAK,EAAE,YAAY,CAAA;IACnB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC,GAAG,OAAO,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA4B7C"}
|