@1sat/sweep-ui 0.0.96 → 0.0.98
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/tx-history.d.ts +3 -1
- package/dist/components/tx-history.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +447 -123
- package/dist/lib/sweeper.d.ts +73 -2
- package/dist/lib/sweeper.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/components/SweepApp.tsx +150 -7
- package/src/components/tx-history.tsx +15 -1
- package/src/index.ts +8 -0
- package/src/lib/sweeper.ts +457 -107
package/dist/lib/sweeper.d.ts
CHANGED
|
@@ -3,6 +3,40 @@ import type { IndexedOutput } from '@1sat/types';
|
|
|
3
3
|
import type { PrivateKey, WalletInterface } from '@bsv/sdk';
|
|
4
4
|
import type { ScannedAssets, TokenBalance } from './scanner';
|
|
5
5
|
export { SWEEP_BATCH_SIZE };
|
|
6
|
+
/** Transferable sweep classes, same order and names as `1sat sweep import`. */
|
|
7
|
+
export type SweepClass = 'bsv' | 'ordinals' | 'opns' | 'bsv20' | 'bsv21';
|
|
8
|
+
/**
|
|
9
|
+
* Per-class sweep selection. Empty sets sweep nothing in that class;
|
|
10
|
+
* omit `selection` entirely to sweep every class (previous behavior).
|
|
11
|
+
*/
|
|
12
|
+
export interface SweepClassSelection {
|
|
13
|
+
sweepBsv: boolean;
|
|
14
|
+
/** Ordinals-class outpoints (`ordinals`, listed OrdLocks included). */
|
|
15
|
+
ordinalOutpoints: Set<string>;
|
|
16
|
+
/** OpNS-class outpoints. */
|
|
17
|
+
opnsOutpoints: Set<string>;
|
|
18
|
+
/** BSV-20 ticks. */
|
|
19
|
+
bsv20Ticks: Set<string>;
|
|
20
|
+
/** BSV-21 tokenIds. */
|
|
21
|
+
bsv21TokenIds: Set<string>;
|
|
22
|
+
}
|
|
23
|
+
/** Select every scanned asset, the default when no selection is passed. */
|
|
24
|
+
export declare function selectAllSweepClasses(assets: ScannedAssets): SweepClassSelection;
|
|
25
|
+
/**
|
|
26
|
+
* Sweep-all is disabled only when every *currently available* class is
|
|
27
|
+
* skipped. Comparing counts instead strands the button on stale skip ids
|
|
28
|
+
* after a refresh drops a class.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isSweepAllDisabled(available: SweepClass[], skipped: Set<SweepClass>): boolean;
|
|
31
|
+
/** Show class skip chips when there is a choice, or a skip to clear. */
|
|
32
|
+
export declare function showClassSkips(available: SweepClass[], skipped: Set<SweepClass>): boolean;
|
|
33
|
+
/** Per-step receipt, emitted via `onResult` as each class/batch completes. */
|
|
34
|
+
export interface SweepStepResult {
|
|
35
|
+
sweepClass: SweepClass;
|
|
36
|
+
label: string;
|
|
37
|
+
txid?: string;
|
|
38
|
+
error?: string;
|
|
39
|
+
}
|
|
6
40
|
export interface SweepResult {
|
|
7
41
|
bsvTxid?: string;
|
|
8
42
|
ordinalTxids: string[];
|
|
@@ -11,6 +45,8 @@ export interface SweepResult {
|
|
|
11
45
|
errors: string[];
|
|
12
46
|
/** Outpoints successfully swept (ordinals/OpNS, including listed OrdLocks). */
|
|
13
47
|
sweptOutpoints: string[];
|
|
48
|
+
/** Swept outpoints that were marketplace listings canceled into the wallet. */
|
|
49
|
+
cancelledListings: string[];
|
|
14
50
|
}
|
|
15
51
|
/**
|
|
16
52
|
* Sweep BSV funding then ordinals into the connected wallet.
|
|
@@ -24,6 +60,10 @@ export declare function executeSweep(params: {
|
|
|
24
60
|
ordinals: IndexedOutput[];
|
|
25
61
|
amount?: number;
|
|
26
62
|
onProgress: (stage: string) => void;
|
|
63
|
+
/** Outpoints to skip; successes are added (canonical `txid.vout` form). */
|
|
64
|
+
completed?: Set<string>;
|
|
65
|
+
signal?: AbortSignal;
|
|
66
|
+
onResult?: (result: SweepStepResult) => void;
|
|
27
67
|
}): Promise<SweepResult>;
|
|
28
68
|
/**
|
|
29
69
|
* Sweep one BSV-21 token. Listed OrdLocks are each their own tx so one
|
|
@@ -34,27 +74,58 @@ export declare function sweepBsv21Token(params: {
|
|
|
34
74
|
keys: Map<string, PrivateKey>;
|
|
35
75
|
token: TokenBalance;
|
|
36
76
|
onProgress: (stage: string) => void;
|
|
77
|
+
signal?: AbortSignal;
|
|
78
|
+
/** Outpoints to skip; successes are added (canonical `txid.vout` form). */
|
|
79
|
+
completed?: Set<string>;
|
|
80
|
+
onResult?: (result: SweepStepResult) => void;
|
|
37
81
|
}): Promise<{
|
|
38
82
|
txid?: string;
|
|
39
83
|
txids: string[];
|
|
84
|
+
sweptOutpoints: string[];
|
|
85
|
+
cancelledListings: string[];
|
|
40
86
|
error?: string;
|
|
41
87
|
}>;
|
|
42
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Sweep one BSV-20 ticker into the connected wallet. BSV-20 needs no per-tx
|
|
90
|
+
* overlay funding, so splitting listed outputs 1-per-tx is cheap — pass
|
|
91
|
+
* `splitListed` so one invalid listing cannot sink the rest of the tick.
|
|
92
|
+
*/
|
|
43
93
|
export declare function sweepBsv20Token(params: {
|
|
44
94
|
wallet: WalletInterface;
|
|
45
95
|
keys: Map<string, PrivateKey>;
|
|
46
96
|
token: Bsv20Balance;
|
|
47
97
|
onProgress: (stage: string) => void;
|
|
98
|
+
signal?: AbortSignal;
|
|
99
|
+
splitListed?: boolean;
|
|
100
|
+
/** Outpoints to skip; successes are added (canonical `txid.vout` form). */
|
|
101
|
+
completed?: Set<string>;
|
|
102
|
+
onResult?: (result: SweepStepResult) => void;
|
|
48
103
|
}): Promise<{
|
|
49
104
|
txid?: string;
|
|
105
|
+
txids: string[];
|
|
106
|
+
sweptOutpoints: string[];
|
|
107
|
+
cancelledListings: string[];
|
|
50
108
|
error?: string;
|
|
51
109
|
}>;
|
|
52
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Same class order as `1sat sweep import`: BSV, ordinals, OpNS, BSV-20,
|
|
112
|
+
* BSV-21. Continues later classes if one fails. Pass `selection` to sweep
|
|
113
|
+
* only chosen classes/items (like `1sat sweep --only/--skip`); pass
|
|
114
|
+
* `completed` to skip already-swept outpoints and record new successes for
|
|
115
|
+
* retry; pass `signal` to abort between steps. Listed OrdLocks stay in their
|
|
116
|
+
* class and cancel in that spend.
|
|
117
|
+
*/
|
|
53
118
|
export declare function sweepAllClasses(params: {
|
|
54
119
|
wallet: WalletInterface;
|
|
55
120
|
keys: Map<string, PrivateKey>;
|
|
56
121
|
assets: ScannedAssets;
|
|
57
122
|
amount?: number;
|
|
58
123
|
onProgress: (stage: string) => void;
|
|
124
|
+
selection?: SweepClassSelection;
|
|
125
|
+
completed?: Set<string>;
|
|
126
|
+
signal?: AbortSignal;
|
|
127
|
+
onResult?: (result: SweepStepResult) => void;
|
|
128
|
+
/** Split listed BSV-20 outputs 1-per-tx so one bad listing cannot sink the tick. */
|
|
129
|
+
splitListedBsv20?: boolean;
|
|
59
130
|
}): Promise<SweepResult>;
|
|
60
131
|
//# sourceMappingURL=sweeper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sweeper.d.ts","sourceRoot":"","sources":["../../src/lib/sweeper.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,YAAY,EACjB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"sweeper.d.ts","sourceRoot":"","sources":["../../src/lib/sweeper.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1sat/sweep-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.98",
|
|
4
4
|
"description": "Sweep UI components for migrating legacy BSV assets",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
],
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@1sat/actions": "0.0.
|
|
33
|
-
"@1sat/client": "0.0.
|
|
34
|
-
"@1sat/connect": "0.0.
|
|
35
|
-
"@1sat/types": "0.0.
|
|
36
|
-
"@1sat/utils": "0.0.
|
|
32
|
+
"@1sat/actions": "0.0.220",
|
|
33
|
+
"@1sat/client": "0.0.54",
|
|
34
|
+
"@1sat/connect": "0.0.94",
|
|
35
|
+
"@1sat/types": "0.0.47",
|
|
36
|
+
"@1sat/utils": "0.0.37",
|
|
37
37
|
"bitcoin-backup": "^0.0.11",
|
|
38
38
|
"class-variance-authority": "^0.7.1",
|
|
39
39
|
"clsx": "^2.1.1",
|
|
@@ -14,7 +14,11 @@ import {
|
|
|
14
14
|
scanAddresses,
|
|
15
15
|
} from '../lib/scanner'
|
|
16
16
|
import {
|
|
17
|
+
type SweepClass,
|
|
17
18
|
executeSweep,
|
|
19
|
+
isSweepAllDisabled,
|
|
20
|
+
selectAllSweepClasses,
|
|
21
|
+
showClassSkips,
|
|
18
22
|
sweepAllClasses,
|
|
19
23
|
sweepBsv20Token,
|
|
20
24
|
sweepBsv21Token,
|
|
@@ -58,12 +62,17 @@ export function SweepApp({
|
|
|
58
62
|
const [sweeping, setSweeping] = useState(false)
|
|
59
63
|
const [sweepProgress, setSweepProgress] = useState('')
|
|
60
64
|
const [txHistory, setTxHistory] = useState<TxRecord[]>([])
|
|
65
|
+
const [cancelledListings, setCancelledListings] = useState(0)
|
|
61
66
|
const [selectedOrdinals, setSelectedOrdinals] = useState<Set<string>>(
|
|
62
67
|
new Set(),
|
|
63
68
|
)
|
|
64
69
|
const [selectedOpns, setSelectedOpns] = useState<Set<string>>(new Set())
|
|
65
70
|
const [sweepAmount, setSweepAmount] = useState<number | null>(null)
|
|
66
71
|
const [activeTab, setActiveTab] = useState<TabId>('ordinals')
|
|
72
|
+
/** Classes excluded from Sweep-all (CLI `--skip` equivalent). Empty = all. */
|
|
73
|
+
const [skippedClasses, setSkippedClasses] = useState<Set<SweepClass>>(
|
|
74
|
+
new Set(),
|
|
75
|
+
)
|
|
67
76
|
|
|
68
77
|
useEffect(() => {
|
|
69
78
|
setWalletConnected(!!externalWallet)
|
|
@@ -100,6 +109,10 @@ export function SweepApp({
|
|
|
100
109
|
])
|
|
101
110
|
}, [])
|
|
102
111
|
|
|
112
|
+
const addCancelled = useCallback((count: number) => {
|
|
113
|
+
if (count > 0) setCancelledListings((prev) => prev + count)
|
|
114
|
+
}, [])
|
|
115
|
+
|
|
103
116
|
const groupedBsv20 = useMemo(
|
|
104
117
|
() => (assets ? groupBsv20Tokens(assets.bsv20Tokens) : []),
|
|
105
118
|
[assets],
|
|
@@ -194,6 +207,7 @@ export function SweepApp({
|
|
|
194
207
|
setAssets(null)
|
|
195
208
|
setSelectedOrdinals(new Set())
|
|
196
209
|
setSelectedOpns(new Set())
|
|
210
|
+
setSkippedClasses(new Set())
|
|
197
211
|
setSweepAmount(null)
|
|
198
212
|
setLegacyKeys(keys)
|
|
199
213
|
|
|
@@ -284,6 +298,7 @@ export function SweepApp({
|
|
|
284
298
|
onProgress: setSweepProgress,
|
|
285
299
|
})
|
|
286
300
|
if (result.errors.length > 0) throw new Error(result.errors[0])
|
|
301
|
+
addCancelled(result.cancelledListings.length)
|
|
287
302
|
return result.bsvTxid ?? ''
|
|
288
303
|
})
|
|
289
304
|
}, [
|
|
@@ -294,6 +309,7 @@ export function SweepApp({
|
|
|
294
309
|
getSelectedFunding,
|
|
295
310
|
runOperation,
|
|
296
311
|
keyMap,
|
|
312
|
+
addCancelled,
|
|
297
313
|
])
|
|
298
314
|
|
|
299
315
|
const handleSendBsv = useCallback(
|
|
@@ -336,13 +352,22 @@ export function SweepApp({
|
|
|
336
352
|
if (result.sweptOutpoints.length > 0) await refreshAssets()
|
|
337
353
|
throw new Error(result.errors[0])
|
|
338
354
|
}
|
|
355
|
+
addCancelled(result.cancelledListings.length)
|
|
339
356
|
for (let i = 0; i < result.ordinalTxids.length - 1; i++) {
|
|
340
357
|
addTx(label, result.ordinalTxids[i])
|
|
341
358
|
}
|
|
342
359
|
return result.ordinalTxids[result.ordinalTxids.length - 1] ?? ''
|
|
343
360
|
})
|
|
344
361
|
},
|
|
345
|
-
[
|
|
362
|
+
[
|
|
363
|
+
resolveWallet,
|
|
364
|
+
legacyKeys,
|
|
365
|
+
keyMap,
|
|
366
|
+
runOperation,
|
|
367
|
+
addTx,
|
|
368
|
+
addCancelled,
|
|
369
|
+
refreshAssets,
|
|
370
|
+
],
|
|
346
371
|
)
|
|
347
372
|
|
|
348
373
|
const handleSweepOrdinals = useCallback(async () => {
|
|
@@ -431,13 +456,22 @@ export function SweepApp({
|
|
|
431
456
|
if (result.sweptOutpoints.length > 0) await refreshAssets()
|
|
432
457
|
throw new Error(result.errors[0])
|
|
433
458
|
}
|
|
459
|
+
addCancelled(result.cancelledListings.length)
|
|
434
460
|
for (let i = 0; i < result.ordinalTxids.length - 1; i++) {
|
|
435
461
|
addTx(label, result.ordinalTxids[i])
|
|
436
462
|
}
|
|
437
463
|
return result.ordinalTxids[result.ordinalTxids.length - 1] ?? ''
|
|
438
464
|
})
|
|
439
465
|
},
|
|
440
|
-
[
|
|
466
|
+
[
|
|
467
|
+
resolveWallet,
|
|
468
|
+
legacyKeys,
|
|
469
|
+
keyMap,
|
|
470
|
+
runOperation,
|
|
471
|
+
addTx,
|
|
472
|
+
addCancelled,
|
|
473
|
+
refreshAssets,
|
|
474
|
+
],
|
|
441
475
|
)
|
|
442
476
|
|
|
443
477
|
const handleSweepOpns = useCallback(async () => {
|
|
@@ -519,11 +553,12 @@ export function SweepApp({
|
|
|
519
553
|
})
|
|
520
554
|
for (const txid of result.txids.slice(0, -1)) addTx('BSV-21', txid)
|
|
521
555
|
if (result.error) throw new Error(result.error)
|
|
556
|
+
addCancelled(result.cancelledListings.length)
|
|
522
557
|
return result.txid ?? ''
|
|
523
558
|
},
|
|
524
559
|
)
|
|
525
560
|
},
|
|
526
|
-
[resolveWallet, assets, keyMap, runOperation, addTx],
|
|
561
|
+
[resolveWallet, assets, keyMap, runOperation, addTx, addCancelled],
|
|
527
562
|
)
|
|
528
563
|
|
|
529
564
|
const handleSweepBsv20Token = useCallback(
|
|
@@ -540,27 +575,90 @@ export function SweepApp({
|
|
|
540
575
|
onProgress: setSweepProgress,
|
|
541
576
|
})
|
|
542
577
|
if (result.error) throw new Error(result.error)
|
|
578
|
+
addCancelled(result.cancelledListings.length)
|
|
543
579
|
return result.txid ?? ''
|
|
544
580
|
})
|
|
545
581
|
},
|
|
546
|
-
[resolveWallet, assets, groupedBsv20, keyMap, runOperation],
|
|
582
|
+
[resolveWallet, assets, groupedBsv20, keyMap, runOperation, addCancelled],
|
|
547
583
|
)
|
|
548
584
|
|
|
585
|
+
const toggleSweepClass = useCallback((sweepClass: SweepClass) => {
|
|
586
|
+
setSkippedClasses((prev) => {
|
|
587
|
+
const next = new Set(prev)
|
|
588
|
+
if (next.has(sweepClass)) next.delete(sweepClass)
|
|
589
|
+
else next.add(sweepClass)
|
|
590
|
+
return next
|
|
591
|
+
})
|
|
592
|
+
}, [])
|
|
593
|
+
|
|
594
|
+
const sweepClasses = useMemo(() => {
|
|
595
|
+
if (!assets) return []
|
|
596
|
+
const classes: { id: SweepClass; label: string; count: number }[] = []
|
|
597
|
+
if (assets.funding.length > 0)
|
|
598
|
+
classes.push({ id: 'bsv', label: 'BSV', count: assets.funding.length })
|
|
599
|
+
if (assets.ordinals.length > 0)
|
|
600
|
+
classes.push({
|
|
601
|
+
id: 'ordinals',
|
|
602
|
+
label: 'Ordinals',
|
|
603
|
+
count: assets.ordinals.length,
|
|
604
|
+
})
|
|
605
|
+
if (assets.opnsNames.length > 0)
|
|
606
|
+
classes.push({
|
|
607
|
+
id: 'opns',
|
|
608
|
+
label: 'OpNS',
|
|
609
|
+
count: assets.opnsNames.length,
|
|
610
|
+
})
|
|
611
|
+
if (groupedBsv20.length > 0)
|
|
612
|
+
classes.push({
|
|
613
|
+
id: 'bsv20',
|
|
614
|
+
label: 'BSV-20',
|
|
615
|
+
count: groupedBsv20.reduce((n, t) => n + t.outputs.length, 0),
|
|
616
|
+
})
|
|
617
|
+
if (assets.bsv21Tokens.some((t) => t.outputs.length > 0))
|
|
618
|
+
classes.push({
|
|
619
|
+
id: 'bsv21',
|
|
620
|
+
label: 'BSV-21',
|
|
621
|
+
count: assets.bsv21Tokens.reduce((n, t) => n + t.outputs.length, 0),
|
|
622
|
+
})
|
|
623
|
+
return classes
|
|
624
|
+
}, [assets, groupedBsv20])
|
|
625
|
+
|
|
549
626
|
const handleSweepAll = useCallback(async () => {
|
|
550
627
|
const wallet = resolveWallet()
|
|
551
628
|
if (!wallet || !legacyKeys || !assets) return
|
|
552
|
-
await runOperation('Sweep
|
|
629
|
+
await runOperation('Sweep selected', async () => {
|
|
630
|
+
const all = selectAllSweepClasses(assets)
|
|
553
631
|
const result = await sweepAllClasses({
|
|
554
632
|
wallet,
|
|
555
633
|
keys: keyMap,
|
|
556
634
|
assets,
|
|
557
635
|
amount: sweepAmount ?? undefined,
|
|
558
636
|
onProgress: setSweepProgress,
|
|
637
|
+
selection: {
|
|
638
|
+
sweepBsv: !skippedClasses.has('bsv') && all.sweepBsv,
|
|
639
|
+
ordinalOutpoints: skippedClasses.has('ordinals')
|
|
640
|
+
? new Set<string>()
|
|
641
|
+
: selectedOrdinals.size > 0
|
|
642
|
+
? selectedOrdinals
|
|
643
|
+
: all.ordinalOutpoints,
|
|
644
|
+
opnsOutpoints: skippedClasses.has('opns')
|
|
645
|
+
? new Set<string>()
|
|
646
|
+
: selectedOpns.size > 0
|
|
647
|
+
? selectedOpns
|
|
648
|
+
: all.opnsOutpoints,
|
|
649
|
+
bsv20Ticks: skippedClasses.has('bsv20')
|
|
650
|
+
? new Set<string>()
|
|
651
|
+
: all.bsv20Ticks,
|
|
652
|
+
bsv21TokenIds: skippedClasses.has('bsv21')
|
|
653
|
+
? new Set<string>()
|
|
654
|
+
: all.bsv21TokenIds,
|
|
655
|
+
},
|
|
559
656
|
})
|
|
560
657
|
if (result.bsvTxid) addTx('BSV', result.bsvTxid)
|
|
561
658
|
for (const txid of result.ordinalTxids) addTx('Ordinals', txid)
|
|
562
659
|
for (const txid of result.bsv20Txids) addTx('BSV-20', txid)
|
|
563
660
|
for (const txid of result.bsv21Txids) addTx('BSV-21', txid)
|
|
661
|
+
addCancelled(result.cancelledListings.length)
|
|
564
662
|
if (result.errors.length > 0) throw new Error(result.errors[0])
|
|
565
663
|
return (
|
|
566
664
|
result.bsvTxid ??
|
|
@@ -578,6 +676,10 @@ export function SweepApp({
|
|
|
578
676
|
sweepAmount,
|
|
579
677
|
runOperation,
|
|
580
678
|
addTx,
|
|
679
|
+
addCancelled,
|
|
680
|
+
skippedClasses,
|
|
681
|
+
selectedOrdinals,
|
|
682
|
+
selectedOpns,
|
|
581
683
|
])
|
|
582
684
|
|
|
583
685
|
return (
|
|
@@ -615,15 +717,55 @@ export function SweepApp({
|
|
|
615
717
|
|
|
616
718
|
{assets && !sweeping && (
|
|
617
719
|
<div className="space-y-3">
|
|
720
|
+
{showClassSkips(
|
|
721
|
+
sweepClasses.map((c) => c.id),
|
|
722
|
+
skippedClasses,
|
|
723
|
+
) && (
|
|
724
|
+
<div className="flex flex-wrap gap-1.5">
|
|
725
|
+
{sweepClasses.map((sweepClass) => {
|
|
726
|
+
const skipped = skippedClasses.has(sweepClass.id)
|
|
727
|
+
return (
|
|
728
|
+
<Button
|
|
729
|
+
key={sweepClass.id}
|
|
730
|
+
variant={skipped ? 'outline' : 'secondary'}
|
|
731
|
+
size="sm"
|
|
732
|
+
className="gap-1.5"
|
|
733
|
+
onClick={() => toggleSweepClass(sweepClass.id)}
|
|
734
|
+
title={
|
|
735
|
+
skipped
|
|
736
|
+
? `Include ${sweepClass.label} in Sweep-selected`
|
|
737
|
+
: `Skip ${sweepClass.label} in Sweep-selected`
|
|
738
|
+
}
|
|
739
|
+
>
|
|
740
|
+
{sweepClass.label}
|
|
741
|
+
<Badge
|
|
742
|
+
variant="secondary"
|
|
743
|
+
className="text-[10px] px-1.5 py-0"
|
|
744
|
+
>
|
|
745
|
+
{sweepClass.count}
|
|
746
|
+
</Badge>
|
|
747
|
+
</Button>
|
|
748
|
+
)
|
|
749
|
+
})}
|
|
750
|
+
</div>
|
|
751
|
+
)}
|
|
618
752
|
<Button
|
|
619
753
|
className="w-full"
|
|
620
|
-
disabled={
|
|
754
|
+
disabled={
|
|
755
|
+
!walletConnected ||
|
|
756
|
+
isSweepAllDisabled(
|
|
757
|
+
sweepClasses.map((c) => c.id),
|
|
758
|
+
skippedClasses,
|
|
759
|
+
)
|
|
760
|
+
}
|
|
621
761
|
onClick={handleSweepAll}
|
|
622
762
|
title={
|
|
623
763
|
walletConnected ? undefined : 'Connect BRC-100 wallet to sweep'
|
|
624
764
|
}
|
|
625
765
|
>
|
|
626
|
-
|
|
766
|
+
{skippedClasses.size > 0
|
|
767
|
+
? 'Sweep selected to wallet'
|
|
768
|
+
: 'Sweep all to wallet'}
|
|
627
769
|
</Button>
|
|
628
770
|
<FundingSection
|
|
629
771
|
funding={assets.funding}
|
|
@@ -715,6 +857,7 @@ export function SweepApp({
|
|
|
715
857
|
sweeping={sweeping}
|
|
716
858
|
progress={sweepProgress}
|
|
717
859
|
history={txHistory}
|
|
860
|
+
cancelledListings={cancelledListings}
|
|
718
861
|
/>
|
|
719
862
|
</div>
|
|
720
863
|
</div>
|
|
@@ -13,9 +13,16 @@ interface Props {
|
|
|
13
13
|
sweeping: boolean
|
|
14
14
|
progress: string
|
|
15
15
|
history: TxRecord[]
|
|
16
|
+
/** Marketplace listings canceled into the wallet across this session. */
|
|
17
|
+
cancelledListings?: number
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
export function TxHistory({
|
|
20
|
+
export function TxHistory({
|
|
21
|
+
sweeping,
|
|
22
|
+
progress,
|
|
23
|
+
history,
|
|
24
|
+
cancelledListings = 0,
|
|
25
|
+
}: Props) {
|
|
19
26
|
return (
|
|
20
27
|
<>
|
|
21
28
|
{sweeping && (
|
|
@@ -32,6 +39,13 @@ export function TxHistory({ sweeping, progress, history }: Props) {
|
|
|
32
39
|
<div className="border border-border/50 rounded-lg p-3 space-y-2">
|
|
33
40
|
<div className="text-xs font-medium text-muted-foreground">
|
|
34
41
|
Transactions ({history.length})
|
|
42
|
+
{cancelledListings > 0 && (
|
|
43
|
+
<span>
|
|
44
|
+
{' '}
|
|
45
|
+
· {cancelledListings} listing
|
|
46
|
+
{cancelledListings !== 1 ? 's' : ''} canceled
|
|
47
|
+
</span>
|
|
48
|
+
)}
|
|
35
49
|
</div>
|
|
36
50
|
<div className="space-y-2 max-h-48 overflow-y-auto">
|
|
37
51
|
{[...history].reverse().map((tx, i) => (
|
package/src/index.ts
CHANGED
|
@@ -53,8 +53,16 @@ export {
|
|
|
53
53
|
export {
|
|
54
54
|
executeSweep,
|
|
55
55
|
sweepAllClasses,
|
|
56
|
+
sweepBsv20Token,
|
|
57
|
+
sweepBsv21Token,
|
|
58
|
+
selectAllSweepClasses,
|
|
59
|
+
isSweepAllDisabled,
|
|
60
|
+
showClassSkips,
|
|
56
61
|
SWEEP_BATCH_SIZE,
|
|
62
|
+
type SweepClass,
|
|
63
|
+
type SweepClassSelection,
|
|
57
64
|
type SweepResult,
|
|
65
|
+
type SweepStepResult,
|
|
58
66
|
} from './lib/sweeper'
|
|
59
67
|
export {
|
|
60
68
|
legacySendBsv,
|