@bsv/wallet-toolbox 2.6.4 → 2.7.0
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/CHANGELOG.md +68 -3
- package/README.md +68 -12
- package/docs/action-batch-planning.md +80 -37
- package/docs/managed-change-liquidity.md +251 -0
- package/out/src/Setup.d.ts +9 -0
- package/out/src/Setup.d.ts.map +1 -1
- package/out/src/Setup.js +2 -0
- package/out/src/Setup.js.map +1 -1
- package/out/src/SetupClient.d.ts +3 -0
- package/out/src/SetupClient.d.ts.map +1 -1
- package/out/src/SetupClient.js +1 -0
- package/out/src/SetupClient.js.map +1 -1
- package/out/src/SetupWallet.d.ts +3 -0
- package/out/src/SetupWallet.d.ts.map +1 -1
- package/out/src/Wallet.d.ts +4 -3
- package/out/src/Wallet.d.ts.map +1 -1
- package/out/src/Wallet.js +4 -3
- package/out/src/Wallet.js.map +1 -1
- package/out/src/WalletPermissionsManager.d.ts.map +1 -1
- package/out/src/WalletPermissionsManager.js +5 -8
- package/out/src/WalletPermissionsManager.js.map +1 -1
- package/out/src/mockchain/MockServices.d.ts.map +1 -1
- package/out/src/mockchain/MockServices.js +2 -6
- package/out/src/mockchain/MockServices.js.map +1 -1
- package/out/src/monitor/Monitor.d.ts.map +1 -1
- package/out/src/monitor/Monitor.js +5 -4
- package/out/src/monitor/Monitor.js.map +1 -1
- package/out/src/monitor/tasks/TaskArcSSE.d.ts +4 -1
- package/out/src/monitor/tasks/TaskArcSSE.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskArcSSE.js +92 -65
- package/out/src/monitor/tasks/TaskArcSSE.js.map +1 -1
- package/out/src/monitor/tasks/TaskReconcilePendingTransactions.d.ts +25 -0
- package/out/src/monitor/tasks/TaskReconcilePendingTransactions.d.ts.map +1 -0
- package/out/src/monitor/tasks/TaskReconcilePendingTransactions.js +181 -0
- package/out/src/monitor/tasks/TaskReconcilePendingTransactions.js.map +1 -0
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.js +15 -3
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.js.map +1 -1
- package/out/src/monitor/tasks/TaskReviewUtxos.d.ts +29 -2
- package/out/src/monitor/tasks/TaskReviewUtxos.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskReviewUtxos.js +155 -7
- package/out/src/monitor/tasks/TaskReviewUtxos.js.map +1 -1
- package/out/src/monitor/tasks/index.all.d.ts +1 -0
- package/out/src/monitor/tasks/index.all.d.ts.map +1 -1
- package/out/src/monitor/tasks/index.all.js +1 -0
- package/out/src/monitor/tasks/index.all.js.map +1 -1
- package/out/src/sdk/ActionBatch.interfaces.d.ts +19 -0
- package/out/src/sdk/ActionBatch.interfaces.d.ts.map +1 -1
- package/out/src/sdk/WERR_errors.d.ts +23 -0
- package/out/src/sdk/WERR_errors.d.ts.map +1 -1
- package/out/src/sdk/WERR_errors.js +44 -1
- package/out/src/sdk/WERR_errors.js.map +1 -1
- package/out/src/sdk/WalletError.d.ts.map +1 -1
- package/out/src/sdk/WalletError.js +7 -21
- package/out/src/sdk/WalletError.js.map +1 -1
- package/out/src/sdk/WalletErrorFromJson.d.ts.map +1 -1
- package/out/src/sdk/WalletErrorFromJson.js +9 -1
- package/out/src/sdk/WalletErrorFromJson.js.map +1 -1
- package/out/src/sdk/WalletServices.interfaces.d.ts +14 -1
- package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
- package/out/src/sdk/WalletStorage.interfaces.d.ts +3 -1
- package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/out/src/sdk/types.d.ts +3 -2
- package/out/src/sdk/types.d.ts.map +1 -1
- package/out/src/sdk/types.js +3 -2
- package/out/src/sdk/types.js.map +1 -1
- package/out/src/services/Services.d.ts.map +1 -1
- package/out/src/services/Services.js +73 -15
- package/out/src/services/Services.js.map +1 -1
- package/out/src/services/classifyOutputUtxo.d.ts +25 -0
- package/out/src/services/classifyOutputUtxo.d.ts.map +1 -0
- package/out/src/services/classifyOutputUtxo.js +87 -0
- package/out/src/services/classifyOutputUtxo.js.map +1 -0
- package/out/src/services/createDefaultWalletServicesOptions.d.ts +16 -3
- package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js +38 -8
- package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/out/src/services/providers/ArcSSEClient.d.ts +13 -4
- package/out/src/services/providers/ArcSSEClient.d.ts.map +1 -1
- package/out/src/services/providers/ArcSSEClient.js +30 -7
- package/out/src/services/providers/ArcSSEClient.js.map +1 -1
- package/out/src/services/providers/Arcade.d.ts +10 -1
- package/out/src/services/providers/Arcade.d.ts.map +1 -1
- package/out/src/services/providers/Arcade.js +63 -0
- package/out/src/services/providers/Arcade.js.map +1 -1
- package/out/src/services/providers/arcadeStatus.d.ts +18 -0
- package/out/src/services/providers/arcadeStatus.d.ts.map +1 -0
- package/out/src/services/providers/arcadeStatus.js +56 -0
- package/out/src/services/providers/arcadeStatus.js.map +1 -0
- package/out/src/signer/actionBatch/ActionBatchPlanner.d.ts.map +1 -1
- package/out/src/signer/actionBatch/ActionBatchPlanner.js +25 -3
- package/out/src/signer/actionBatch/ActionBatchPlanner.js.map +1 -1
- package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts +2 -0
- package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts.map +1 -1
- package/out/src/signer/actionBatch/ActionBatchWorkspace.js +135 -16
- package/out/src/signer/actionBatch/ActionBatchWorkspace.js.map +1 -1
- package/out/src/storage/StorageIdb.d.ts +2 -0
- package/out/src/storage/StorageIdb.d.ts.map +1 -1
- package/out/src/storage/StorageIdb.js +24 -1
- package/out/src/storage/StorageIdb.js.map +1 -1
- package/out/src/storage/StorageKnex.d.ts +1 -1
- package/out/src/storage/StorageKnex.d.ts.map +1 -1
- package/out/src/storage/StorageKnex.js +4 -4
- package/out/src/storage/StorageKnex.js.map +1 -1
- package/out/src/storage/StorageProvider.d.ts +18 -2
- package/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/out/src/storage/StorageProvider.js +45 -14
- package/out/src/storage/StorageProvider.js.map +1 -1
- package/out/src/storage/StorageReaderWriter.d.ts.map +1 -1
- package/out/src/storage/StorageReaderWriter.js +3 -2
- package/out/src/storage/StorageReaderWriter.js.map +1 -1
- package/out/src/storage/WalletStorageManager.d.ts +12 -0
- package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
- package/out/src/storage/WalletStorageManager.js +22 -2
- package/out/src/storage/WalletStorageManager.js.map +1 -1
- package/out/src/storage/adminServer/adminServer.d.ts +2 -0
- package/out/src/storage/adminServer/adminServer.d.ts.map +1 -1
- package/out/src/storage/adminServer/adminServer.js +25 -8
- package/out/src/storage/adminServer/adminServer.js.map +1 -1
- package/out/src/storage/adminServer/adminUi.d.ts.map +1 -1
- package/out/src/storage/adminServer/adminUi.js +32 -9
- package/out/src/storage/adminServer/adminUi.js.map +1 -1
- package/out/src/storage/adminServer/reviewUtxos.d.ts +27 -0
- package/out/src/storage/adminServer/reviewUtxos.d.ts.map +1 -0
- package/out/src/storage/adminServer/reviewUtxos.js +62 -0
- package/out/src/storage/adminServer/reviewUtxos.js.map +1 -0
- package/out/src/storage/index.all.d.ts +1 -0
- package/out/src/storage/index.all.d.ts.map +1 -1
- package/out/src/storage/index.all.js +1 -0
- package/out/src/storage/index.all.js.map +1 -1
- package/out/src/storage/index.client.d.ts +1 -0
- package/out/src/storage/index.client.d.ts.map +1 -1
- package/out/src/storage/index.client.js +1 -0
- package/out/src/storage/index.client.js.map +1 -1
- package/out/src/storage/index.mobile.d.ts +1 -0
- package/out/src/storage/index.mobile.d.ts.map +1 -1
- package/out/src/storage/index.mobile.js +1 -0
- package/out/src/storage/index.mobile.js.map +1 -1
- package/out/src/storage/methods/ListOutputsSpecOp.d.ts.map +1 -1
- package/out/src/storage/methods/ListOutputsSpecOp.js +4 -44
- package/out/src/storage/methods/ListOutputsSpecOp.js.map +1 -1
- package/out/src/storage/methods/actionBatch.d.ts +9 -2
- package/out/src/storage/methods/actionBatch.d.ts.map +1 -1
- package/out/src/storage/methods/actionBatch.js +258 -66
- package/out/src/storage/methods/actionBatch.js.map +1 -1
- package/out/src/storage/methods/actionBatchBlobs.js +7 -4
- package/out/src/storage/methods/actionBatchBlobs.js.map +1 -1
- package/out/src/storage/methods/attemptToPostReqsToNetwork.d.ts.map +1 -1
- package/out/src/storage/methods/attemptToPostReqsToNetwork.js +2 -66
- package/out/src/storage/methods/attemptToPostReqsToNetwork.js.map +1 -1
- package/out/src/storage/methods/availableManagedChange.d.ts +8 -1
- package/out/src/storage/methods/availableManagedChange.d.ts.map +1 -1
- package/out/src/storage/methods/availableManagedChange.js.map +1 -1
- package/out/src/storage/methods/createAction.d.ts.map +1 -1
- package/out/src/storage/methods/createAction.js +183 -51
- package/out/src/storage/methods/createAction.js.map +1 -1
- package/out/src/storage/methods/generateChange.d.ts +13 -1
- package/out/src/storage/methods/generateChange.d.ts.map +1 -1
- package/out/src/storage/methods/generateChange.js +169 -12
- package/out/src/storage/methods/generateChange.js.map +1 -1
- package/out/src/storage/methods/listActionsIdb.d.ts.map +1 -1
- package/out/src/storage/methods/listActionsIdb.js +4 -0
- package/out/src/storage/methods/listActionsIdb.js.map +1 -1
- package/out/src/storage/methods/listActionsKnex.d.ts.map +1 -1
- package/out/src/storage/methods/listActionsKnex.js +4 -0
- package/out/src/storage/methods/listActionsKnex.js.map +1 -1
- package/out/src/storage/methods/listOutputsIdb.d.ts.map +1 -1
- package/out/src/storage/methods/listOutputsIdb.js +2 -1
- package/out/src/storage/methods/listOutputsIdb.js.map +1 -1
- package/out/src/storage/methods/managedChangePolicy.d.ts +44 -0
- package/out/src/storage/methods/managedChangePolicy.d.ts.map +1 -0
- package/out/src/storage/methods/managedChangePolicy.js +58 -0
- package/out/src/storage/methods/managedChangePolicy.js.map +1 -0
- package/out/src/storage/methods/reconcileFailedTransactionInputs.d.ts +26 -0
- package/out/src/storage/methods/reconcileFailedTransactionInputs.d.ts.map +1 -0
- package/out/src/storage/methods/reconcileFailedTransactionInputs.js +124 -0
- package/out/src/storage/methods/reconcileFailedTransactionInputs.js.map +1 -0
- package/out/src/storage/methods/reviewUtxoOutputs.d.ts +37 -0
- package/out/src/storage/methods/reviewUtxoOutputs.d.ts.map +1 -0
- package/out/src/storage/methods/reviewUtxoOutputs.js +150 -0
- package/out/src/storage/methods/reviewUtxoOutputs.js.map +1 -0
- package/out/src/storage/portable/index.d.ts.map +1 -1
- package/out/src/storage/portable/index.js +4 -2
- package/out/src/storage/portable/index.js.map +1 -1
- package/out/src/storage/remoting/StorageClientBase.d.ts +2 -1
- package/out/src/storage/remoting/StorageClientBase.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageClientBase.js +3 -0
- package/out/src/storage/remoting/StorageClientBase.js.map +1 -1
- package/out/src/storage/remoting/StorageServer.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageServer.js +4 -1
- package/out/src/storage/remoting/StorageServer.js.map +1 -1
- package/out/src/storage/schema/KnexMigrations.d.ts +1 -0
- package/out/src/storage/schema/KnexMigrations.d.ts.map +1 -1
- package/out/src/storage/schema/KnexMigrations.js +29 -3
- package/out/src/storage/schema/KnexMigrations.js.map +1 -1
- package/out/src/storage/schema/entities/EntityOutputBasket.d.ts.map +1 -1
- package/out/src/storage/schema/entities/EntityOutputBasket.js +5 -2
- package/out/src/storage/schema/entities/EntityOutputBasket.js.map +1 -1
- package/out/src/utility/brc153ReferenceLabels.d.ts +21 -0
- package/out/src/utility/brc153ReferenceLabels.d.ts.map +1 -0
- package/out/src/utility/brc153ReferenceLabels.js +45 -0
- package/out/src/utility/brc153ReferenceLabels.js.map +1 -0
- package/out/src/utility/index.all.d.ts +1 -0
- package/out/src/utility/index.all.d.ts.map +1 -1
- package/out/src/utility/index.all.js +1 -0
- package/out/src/utility/index.all.js.map +1 -1
- package/out/src/utility/index.client.d.ts +1 -0
- package/out/src/utility/index.client.d.ts.map +1 -1
- package/out/src/utility/index.client.js +1 -0
- package/out/src/utility/index.client.js.map +1 -1
- package/out/src/utility/utilityHelpers.d.ts +1 -1
- package/out/src/utility/utilityHelpers.d.ts.map +1 -1
- package/out/src/utility/utilityHelpers.js +2 -1
- package/out/src/utility/utilityHelpers.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,9 +6,74 @@ attention to changes that materially alter behavior or extend functionality.
|
|
|
6
6
|
|
|
7
7
|
## wallet-toolbox (unreleased)
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
- Keep mainnet and testnet ChainTracks usable from browser and webview wallets:
|
|
10
|
+
browser runtimes temporarily select the CORS-enabled legacy service while
|
|
11
|
+
Node runtimes retain Arcade/go-chaintracks v2. `Services.getHeight` now falls
|
|
12
|
+
back to WhatsOnChain if ChainTracks is unavailable and preserves the original
|
|
13
|
+
ChainTracks error when both providers fail.
|
|
14
|
+
- Route `ttn` wallets through the isolated `teratestnet` overlay preset and
|
|
15
|
+
enable the public TTN Arcade broadcaster/proof provider by default. TTN does
|
|
16
|
+
not register the incompatible legacy ARC BEEF fallback. Other chain defaults
|
|
17
|
+
are unchanged, and an empty Arcade URL explicitly disables Arcade.
|
|
18
|
+
- Reconcile Arcade broadcast outcomes as durable wallet state. Retryable
|
|
19
|
+
locktime and parent conditions remain pending, while validator failures fail
|
|
20
|
+
the request and explicit missing-input or conflict evidence atomically fails
|
|
21
|
+
every local transaction copy and quarantines its wallet-owned inputs without
|
|
22
|
+
depending on WhatsOnChain. Cached accepted/seen labels can no longer revive a
|
|
23
|
+
terminal conflict; only a mined event whose Merkle proof validates through
|
|
24
|
+
the configured chain tracker may repair it. Arcade also participates in the
|
|
25
|
+
shared transaction-status service so double-spend review remains conservative
|
|
26
|
+
on networks with no explorer. A scheduled paged pass also reconciles aged
|
|
27
|
+
pending requests from durable Arcade lifecycle state, including orphan-mempool
|
|
28
|
+
losers whose SSE event was missed; mined/known evidence wins over rejection.
|
|
29
|
+
Inconclusive or absent UTXO providers no longer
|
|
30
|
+
masquerade as a spent-output verdict in invalid-change release, stale-input
|
|
31
|
+
reconciliation, proof recovery, or storage diagnostics. Invalid-change review
|
|
32
|
+
returns conclusive read-only findings plus unknown diagnostics. Direct release
|
|
33
|
+
blocks atomically with machine-readable `WERR_UTXO_REVIEW_INCONCLUSIVE` when
|
|
34
|
+
any result is unknown. Monitor Admin uses bounded, five-second-deadline pages
|
|
35
|
+
and can explicitly release the confirmed-spent subset while retaining unknowns;
|
|
36
|
+
every mutation rechecks ownership/allocation under lock and records audit
|
|
37
|
+
evidence. Monitor Admin scans by default and requires explicit confirmation.
|
|
38
|
+
The
|
|
39
|
+
Arcade SSE cursor advances only after both event storage work and cursor
|
|
40
|
+
persistence succeed; either failure leaves the event queued for ordered retry.
|
|
41
|
+
- Replace 32-satoshi default-basket fragments with a progressive liquidity
|
|
42
|
+
policy targeting 144 useful 5,000-satoshi outputs. New actions create at most
|
|
43
|
+
eight outputs from real surplus and migrate at most four fee-positive legacy
|
|
44
|
+
fragments, while a same-tier compatibility plan guarantees that optional
|
|
45
|
+
shaping cannot refuse an action the former planner could fund. Explicitly
|
|
46
|
+
funded actions materialize change from their existing surplus without
|
|
47
|
+
gathering pool inputs, and SQLite policy migrations use sync-compatible UTC
|
|
48
|
+
ISO timestamps.
|
|
49
|
+
- Prefer completed, then unproven, then sending parents. Plans above 16 inputs
|
|
50
|
+
compare exact transaction-plus-BEEF bytes before accepting pending ancestry;
|
|
51
|
+
pending change remains an unconditional last-resort funding source. Align
|
|
52
|
+
action-batch reservation/planning and add a read-only Monitor liquidity
|
|
53
|
+
report. All work limits are configurable and accept `-1` for explicit
|
|
54
|
+
operator-selected unlimited behavior.
|
|
55
|
+
- Restore delayed broadcast for durable permission-token persistence. Permission
|
|
56
|
+
grants no longer inherit network-broadcast latency; the managed-change policy
|
|
57
|
+
handles queued ancestry without hiding it or preferring it over settled funds.
|
|
58
|
+
- Isolate each in-memory action batch by explicit staged-output or `sendWith`
|
|
59
|
+
membership, so unrelated immediate actions and `noSend` roots cannot be
|
|
60
|
+
captured by or commit a workspace. Add an exact-input resume protocol for
|
|
61
|
+
expired leases, structured lifecycle errors, and a provider-enforced
|
|
62
|
+
cumulative reservation limit that defaults to 256 outputs and can be
|
|
63
|
+
configured, including `-1` for operator-selected unlimited operation.
|
|
64
|
+
- Keep the combined action-batch, managed-liquidity, browser-fallback, and
|
|
65
|
+
fail-safe reconciliation browser/mobile cost bounded by exact packed-artifact
|
|
66
|
+
contracts. Local verification measures 1,557,683 raw / 366,927 gzip / 287,337
|
|
67
|
+
Brotli bytes with Vite, 1,215,983 raw / 333,466 gzip / 268,497 Brotli bytes
|
|
68
|
+
with esbuild, 1,617,544 raw Metro bytes, and 3,271,146 raw / 1,302,110 gzip /
|
|
69
|
+
1,025,812 Brotli Hermes bytes. Reviewed raw ceilings are 1,561,000 Vite bytes,
|
|
70
|
+
1,220,000 esbuild bytes, 1,710,000 Metro bytes, and 3,275,000 Hermes bytes;
|
|
71
|
+
compressed ceilings remain independently governed.
|
|
72
|
+
- Fix `WalletStorageManager.getStoreEndpointURL` / `getStores().endpointURL` to
|
|
73
|
+
duck-type provider `endpointUrl` instead of matching
|
|
74
|
+
`constructor.name === 'StorageClient'`. Production minifiers rename classes,
|
|
75
|
+
so the name check left remote stores with `endpointURL: undefined` while
|
|
76
|
+
sync still worked; clients that select a backup by URL (make primary) failed.
|
|
12
77
|
- Let Storage Server operators select an explicit listener host while retaining
|
|
13
78
|
the historical omitted-host behavior for existing callers. The official
|
|
14
79
|
Wallet Infrastructure image uses this to bind direct-mode traffic on IPv4
|
package/README.md
CHANGED
|
@@ -26,12 +26,16 @@ BSV Desktop and BSV Browser are the BSV Association reference wallet application
|
|
|
26
26
|
| **MockChain** | In-memory blockchain for testing — mock mining, UTXO tracking, and merkle proof generation without a network |
|
|
27
27
|
| **Entropy** | `EntropyCollector` gathers mouse/touch entropy for high-quality randomness in browser environments |
|
|
28
28
|
|
|
29
|
-
Durable permission grants
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
Durable permission grants queue their internal token transaction for delayed
|
|
30
|
+
broadcast, so permission approval does not inherit network-broadcast latency.
|
|
31
|
+
The funding planner prefers settled change and uses queued permission ancestry
|
|
32
|
+
only as a last resort, keeping the application path fast without hiding funds.
|
|
33
|
+
|
|
34
|
+
Immediate actions prefer completed, then unproven, then sending change. A
|
|
35
|
+
pathological settled plan is compared with pending alternatives by exact
|
|
36
|
+
serialized BEEF plus transaction bytes; queued ancestry is used only when it is
|
|
37
|
+
necessary or smaller. Pending change is never withheld, so queued
|
|
38
|
+
work cannot strand the balance behind a large reserved input.
|
|
35
39
|
|
|
36
40
|
### Packages
|
|
37
41
|
|
|
@@ -43,9 +47,13 @@ The toolbox publishes three npm packages from this repo:
|
|
|
43
47
|
|
|
44
48
|
### ChainTracks sources and networks
|
|
45
49
|
|
|
46
|
-
Wallet services do not require a WhatsOnChain key for ChainTracks.
|
|
47
|
-
testnet, and TerraTestNet use the public
|
|
48
|
-
|
|
50
|
+
Wallet services do not require a WhatsOnChain key for ChainTracks. Node
|
|
51
|
+
runtimes on mainnet, testnet, and TerraTestNet use the public
|
|
52
|
+
Arcade/go-chaintracks v2 HTTP and SSE surfaces by default. Browser and webview
|
|
53
|
+
runtimes on mainnet/testnet temporarily select the legacy CORS-enabled service
|
|
54
|
+
until the v2 edge serves CORS and OPTIONS; `Services.getHeight` also falls back
|
|
55
|
+
to WhatsOnChain on those networks if ChainTracks is unavailable. Bulk batches
|
|
56
|
+
still pass through local serialization, hash,
|
|
49
57
|
continuity, and genesis checks; providers are tried in priority order; and a
|
|
50
58
|
synchronized tracker can continue serving its last-good checked data during a
|
|
51
59
|
provider outage. WhatsOnChain remains a mainnet/testnet fallback and anonymous
|
|
@@ -60,8 +68,51 @@ go-chaintracks client; existing legacy v1 URLs and explicit clients remain
|
|
|
60
68
|
compatible. Browser and mobile distributions expose the same fetch/SSE client
|
|
61
69
|
without Node `Buffer` or filesystem dependencies.
|
|
62
70
|
|
|
63
|
-
Arcade is the
|
|
64
|
-
|
|
71
|
+
Arcade is the HTTPS/SSE gateway for Teranode-backed header data. Its v2 edge
|
|
72
|
+
must allow browser origins and OPTIONS before browser defaults can use it;
|
|
73
|
+
direct Teranode P2P is not included in browser/mobile artifacts.
|
|
74
|
+
|
|
75
|
+
TTN wallets also register
|
|
76
|
+
`https://arcade-v2-ttn-us-1.bsvblockchain.tech` as their first broadcast and
|
|
77
|
+
Merkle-proof provider. Mainnet and testnet Arcade broadcasting remains opt-in.
|
|
78
|
+
Pass an explicit `arcadeUrl` to override the TTN endpoint or an empty string to
|
|
79
|
+
disable it. TTN overlay lookups use the separate `teratestnet` resolver preset
|
|
80
|
+
and never fall back to testnet discovery.
|
|
81
|
+
|
|
82
|
+
### Broadcast rejection and monitor reconciliation
|
|
83
|
+
|
|
84
|
+
When Arcade is configured, Wallet Toolbox consumes Arcade's status code and
|
|
85
|
+
validator detail instead of treating every `REJECTED` event alike. Retryable
|
|
86
|
+
parent and locktime conditions stay pending. Terminal validator failures fail
|
|
87
|
+
the request, and explicit missing-input or conflict evidence also quarantines
|
|
88
|
+
every wallet-owned copy of the consumed input in the same storage transaction.
|
|
89
|
+
That quarantine uses Arcade's positive rejection evidence and does not require
|
|
90
|
+
WhatsOnChain or another UTXO explorer.
|
|
91
|
+
|
|
92
|
+
Arcade is also registered as a transaction-status provider, so monitor review
|
|
93
|
+
continues on networks without WhatsOnChain. A scheduled bounded pass revisits
|
|
94
|
+
aged pending requests and applies durable Arcade lifecycle verdicts that may
|
|
95
|
+
have arrived while SSE was disconnected, including `SEEN_IN_ORPHAN_MEMPOOL`.
|
|
96
|
+
Mined/known evidence takes precedence over a stale rejection. Provider absence
|
|
97
|
+
and provider errors are treated as inconclusive, never as proof that an output
|
|
98
|
+
was spent.
|
|
99
|
+
After an input conflict has been recorded, a later cached accepted/seen label
|
|
100
|
+
cannot restore the failed transaction; recovery requires a mined status and a
|
|
101
|
+
Merkle proof validated by the configured chain tracker. Arcade SSE events are
|
|
102
|
+
acknowledged in order only after their storage update and cursor persistence
|
|
103
|
+
succeed, so a transient storage failure is retried instead of skipped.
|
|
104
|
+
|
|
105
|
+
Invalid-change review applies the same positive-evidence rule. Only an
|
|
106
|
+
explicit successful `isUtxo: false` result is considered spent; a provider
|
|
107
|
+
error, rate limit, timeout, missing provider, missing script, or malformed
|
|
108
|
+
response is unknown. Read-only scans return the conclusive picture plus the
|
|
109
|
+
unknown count. Direct destructive release remains all-or-nothing: any unknown
|
|
110
|
+
throws `WERR_UTXO_REVIEW_INCONCLUSIVE` before mutation. The authenticated
|
|
111
|
+
Monitor Admin tool instead uses 20-output pages (four provider calls in flight,
|
|
112
|
+
five-second per-output review deadline) and may explicitly release the
|
|
113
|
+
positively spent subset while retaining and reporting unknowns. Each confirmed
|
|
114
|
+
spent output is rechecked for ownership and allocation state under the write
|
|
115
|
+
lock, and every release or blocked release records bounded audit evidence.
|
|
65
116
|
|
|
66
117
|
Core ChainTracks factories accept a final source-options argument when an
|
|
67
118
|
application must override the defaults. Set `disableChaintracks`, `disableCdn`,
|
|
@@ -122,6 +173,11 @@ See [Managed change, sweeping, and recovery](./docs/managed-change-policy.md)
|
|
|
122
173
|
for the default-basket invariant, automatic funding policy, and supported
|
|
123
174
|
`internalizeAction` repair paths.
|
|
124
175
|
|
|
176
|
+
See [Managed-change liquidity policy](./docs/managed-change-liquidity.md) for
|
|
177
|
+
the 144-output / 5,000-satoshi defaults, gradual legacy-wallet migration,
|
|
178
|
+
pending-parent policy, exact BEEF comparison, operator tuning, action-batch
|
|
179
|
+
alignment, monitoring, and rollout guidance.
|
|
180
|
+
|
|
125
181
|
See [In-memory action batch planning](./docs/action-batch-planning.md) for
|
|
126
182
|
capability-negotiated `noSend` planning, compact manifests, compressed binary
|
|
127
183
|
pack transport, atomic commit, compatibility behavior, and retained benchmarks.
|
|
@@ -139,7 +195,7 @@ The planner uses the same exact / least-over / largest-under selection policy
|
|
|
139
195
|
as the historical allocator, but proves economic sufficiency before writing a
|
|
140
196
|
transaction and claims every selected input in one database transaction. Knex
|
|
141
197
|
storage automatically adds a composite funding-selection index on migration;
|
|
142
|
-
IndexedDB schema version
|
|
198
|
+
IndexedDB schema version 4 adds corresponding user/basket and outpoint indexes
|
|
143
199
|
and resolves transaction-status eligibility in one indexed pass.
|
|
144
200
|
|
|
145
201
|
The retained fragmented-funding benchmark is runnable with:
|
|
@@ -17,12 +17,34 @@ Large first actions use compact bootstrap only when the provider also advertises
|
|
|
17
17
|
`compactBegin: true`; this keeps new clients compatible with older version-1
|
|
18
18
|
servers during a rolling deployment.
|
|
19
19
|
|
|
20
|
+
One `Wallet` instance owns at most one in-memory action-batch workspace. An
|
|
21
|
+
independent `noSend` graph created while that workspace is open uses the ordinary
|
|
22
|
+
persistent path; it is not captured merely because the calls overlap. Storage
|
|
23
|
+
providers may host many concurrent batches for different wallets or sessions,
|
|
24
|
+
and their output reservations remain disjoint. A future client-side multi-workspace
|
|
25
|
+
router would also need defined semantics for a `sendWith` request or child action
|
|
26
|
+
that joins more than one graph; this version deliberately does not imply those
|
|
27
|
+
semantics.
|
|
28
|
+
|
|
20
29
|
The original manifest and one-blob-per-request transport remain version 1. A
|
|
21
30
|
provider can independently advertise the additive `manifestVersion: 2`,
|
|
22
|
-
`commitByDigest`, and `packedUploads`
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
`commitByDigest`, `resume`, `maxReservedOutputs`, and `packedUploads`
|
|
32
|
+
capabilities. A new client uses each optimization only when its provider
|
|
33
|
+
advertises it. Old clients ignore the extra fields, new clients retain the
|
|
34
|
+
version-1 path against old providers, and additive storage methods remain
|
|
35
|
+
optional for third-party `WalletStorage` implementations. The exported capability
|
|
36
|
+
helper does not advertise `resume` by default; built-in providers opt in because
|
|
37
|
+
they implement the optional `resumeActionBatch` method.
|
|
38
|
+
|
|
39
|
+
The retained browser platform contract measures the resumable implementation at
|
|
40
|
+
1,548,179 raw / 364,550 gzip / 285,697 Brotli bytes with Vite and 1,209,217 raw /
|
|
41
|
+
331,318 gzip / 267,001 Brotli bytes with esbuild. Every browser size ceiling
|
|
42
|
+
remains unchanged.
|
|
43
|
+
|
|
44
|
+
The mobile contract measures 1,609,633 raw / 405,646 gzip / 315,527 Brotli
|
|
45
|
+
Metro bytes and 3,253,366 raw / 1,293,591 gzip / 1,018,837 Brotli Hermes bytes.
|
|
46
|
+
Only the Hermes raw ceiling advances, by less than 0.15%; every compressed and
|
|
47
|
+
Metro ceiling remains unchanged.
|
|
26
48
|
|
|
27
49
|
The capability and its methods are Wallet Toolbox storage extensions. They do not
|
|
28
50
|
extend `WalletInterface`, `CreateActionArgs`, `SignActionArgs`, `noSend`,
|
|
@@ -36,17 +58,26 @@ extend `WalletInterface`, `CreateActionArgs`, `SignActionArgs`, `noSend`,
|
|
|
36
58
|
output-script lengths at bootstrap. Signed transactions and the external
|
|
37
59
|
proof frontier follow through the binary commit path, so a hexadecimal
|
|
38
60
|
script is not duplicated into a large JSON request.
|
|
39
|
-
2. The wallet plans, signs, validates, and indexes subsequent
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
61
|
+
2. The wallet plans, signs, validates, and indexes a subsequent action locally
|
|
62
|
+
only when it belongs to the same transaction graph: an input or
|
|
63
|
+
`noSendChange` outpoint references a staged output, or `sendWith` references
|
|
64
|
+
a transaction owned by the workspace. Time adjacency, a shared wallet or
|
|
65
|
+
originator, and merely being another `noSend` action do not establish
|
|
66
|
+
membership. Unrelated work continues through the ordinary persistence path.
|
|
67
|
+
A shared BEEF graph avoids retaining repeated ancestry. The signed
|
|
68
|
+
transaction is the canonical source for output scripts; format 2 carries
|
|
69
|
+
script digests for validation rather than duplicating scripts.
|
|
44
70
|
3. If confirmed funding runs low, the wallet extends its reservation pool using
|
|
45
71
|
an EWMA estimate and geometrically increasing runway. Forwarded staged change
|
|
46
72
|
needs no reservation or extension.
|
|
47
|
-
4. `sendWith
|
|
48
|
-
|
|
49
|
-
|
|
73
|
+
4. `sendWith` that names a workspace transaction, or a normal action that
|
|
74
|
+
explicitly depends on a staged output, validates and atomically persists
|
|
75
|
+
every member action. An unrelated normal action neither joins nor commits
|
|
76
|
+
the workspace. Only the requested transactions are sent; earlier actions
|
|
77
|
+
retain their `nosend` status. If a workspace-owned `noSend` action also
|
|
78
|
+
requests only unrelated persisted transactions through `sendWith`, the new
|
|
79
|
+
action remains staged and the explicit broadcasts run through the ordinary
|
|
80
|
+
persistence path; neither request is silently dropped.
|
|
50
81
|
5. Broadcast occurs after the storage transaction. Delayed mode returns after the
|
|
51
82
|
batch is durably queued; immediate mode uses the existing aggregate broadcaster
|
|
52
83
|
and review results.
|
|
@@ -62,17 +93,24 @@ can use unreserved outputs normally. A uniqueness constraint prevents one output
|
|
|
62
93
|
from belonging to two active batches.
|
|
63
94
|
|
|
64
95
|
The initial reservation includes at most three extra candidates and never more
|
|
65
|
-
than eight outputs
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
deficit but cost too
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
96
|
+
than eight outputs or the operator's lower cumulative reservation cap. Its
|
|
97
|
+
canonical funding target includes the marginal P2PKH input fee and enough value
|
|
98
|
+
to recover an economically viable first change output, so a low basket minimum
|
|
99
|
+
cannot repeatedly select inputs that satisfy the nominal deficit but cost too
|
|
100
|
+
much to use.
|
|
101
|
+
|
|
102
|
+
Extensions add at most 64 outputs per storage call. Built-in providers also
|
|
103
|
+
enforce and advertise a cumulative maximum of 256 persisted output reservations
|
|
104
|
+
per workspace, including caller-selected persisted inputs and confirmed inputs
|
|
105
|
+
already consumed by uncommitted member transactions. This is a provider resource
|
|
106
|
+
bound, not a transaction or consensus input limit; staged outputs do not consume
|
|
107
|
+
additional persisted reservations. Set `StorageProviderOptions.actionBatchMaxReservedOutputs`
|
|
108
|
+
(or the matching `SetupWalletKnexArgs` option when using
|
|
109
|
+
`Setup.createStorageKnex`) to another positive integer, or to `-1` for
|
|
110
|
+
operator-selected unlimited operation. The provider advertises the effective value. Extensions use the same
|
|
111
|
+
exact, least-over, then largest-under selection policy as normal funding. Retry
|
|
112
|
+
targets are incremental shortfalls: the planner credits the value and count of
|
|
113
|
+
every unconsumed reserved output before asking for more.
|
|
76
114
|
Confirmed inputs already used by staged transactions remain reserved until
|
|
77
115
|
commit but are not credited as available funding. Proactive EWMA requests
|
|
78
116
|
likewise subtract the unconsumed pool, initialize from the first complete
|
|
@@ -80,9 +118,14 @@ sample, and increase geometric runway only when the provider fulfills both the
|
|
|
80
118
|
requested count and value. Empty or partial extensions therefore cannot
|
|
81
119
|
compound a target against unchanged wallet state.
|
|
82
120
|
Leases last 15 minutes with a 60-minute hard lifetime. Long-running workspaces
|
|
83
|
-
renew near 80% of the lease
|
|
84
|
-
|
|
85
|
-
|
|
121
|
+
renew near 80% of the lease. A client and provider advertising `resume` can
|
|
122
|
+
atomically reacquire only the exact persisted outpoints already held by that
|
|
123
|
+
workspace after soft expiry; a conflicting spend or reservation fails that
|
|
124
|
+
connected workflow without capturing unrelated actions. Lifecycle failures use
|
|
125
|
+
`WERR_ACTION_BATCH_STATE` with a machine-readable state rather than message-text
|
|
126
|
+
matching. Version-1 commit retains its compatible expired-input reacquisition
|
|
127
|
+
path. Commit, abort, wallet destruction, expiry cleanup, and the one-minute
|
|
128
|
+
monitor task release unused state.
|
|
86
129
|
|
|
87
130
|
## Atomic commit and payload transport
|
|
88
131
|
|
|
@@ -193,15 +236,15 @@ pnpm --filter @bsv/wallet-toolbox bench:action-batch
|
|
|
193
236
|
On the same Apple Silicon host with Node.js v25.9.0, a representative cold
|
|
194
237
|
250-action, 1 KiB-script run reduced planning/signing/validation from
|
|
195
238
|
19,117.03 ms in legacy mode to 10,907.93 ms in batch mode (42.9%, or 1.75x).
|
|
196
|
-
Including atomic commit, total local time was
|
|
197
|
-
(
|
|
198
|
-
from
|
|
199
|
-
200 ms of control-path latency, a 99.
|
|
200
|
-
|
|
201
|
-
A generic single 4 MiB zero-filled script took 1,
|
|
202
|
-
path and
|
|
203
|
-
less local time. Its instrumented requests fell from 13,982,465 bytes to 8,
|
|
204
|
-
bytes. The one 4,195,234-byte logical pack compressed to 5,
|
|
239
|
+
Including atomic commit, total local time was 11,131.49 ms versus 5,795.95 ms
|
|
240
|
+
(47.9% lower), while storage calls and database transactions fell from 750 to
|
|
241
|
+
2 and from 750 to 3, respectively. At 100 ms storage RTT those calls represent
|
|
242
|
+
75,000 ms versus 200 ms of control-path latency, a 99.7% reduction.
|
|
243
|
+
|
|
244
|
+
A generic single 4 MiB zero-filled script took 1,160.86 ms through the legacy
|
|
245
|
+
path and 288.20 ms through format 2, including upload and atomic commit: 75.2%
|
|
246
|
+
less local time. Its instrumented requests fell from 13,982,465 bytes to 8,067
|
|
247
|
+
bytes. The one 4,195,234-byte logical pack compressed to 5,236 bytes and was
|
|
205
248
|
uploaded in one call. This synthetic compression ratio represents highly
|
|
206
249
|
repetitive data; incompressible data falls back to identity encoding without
|
|
207
250
|
expansion. Absolute times remain host- and database-dependent.
|
|
@@ -210,8 +253,8 @@ It records planning, signing and validation, storage RPCs, database transactions
|
|
|
210
253
|
request bytes, commit and broadcast time, CPU, and incremental peak heap. Physical
|
|
211
254
|
SQLite runs compare 1, 10, 50, and 250 action chains at 1 KiB and exercise each
|
|
212
255
|
larger script size with a real action, including the 4 MiB upload path. Its
|
|
213
|
-
complete model covers dependent,
|
|
214
|
-
signing workloads at every action count; 1 KiB, 64 KiB, 1 MiB, and 4 MiB
|
|
256
|
+
complete model covers dependent, isolated-root fallback, explicit-input, and
|
|
257
|
+
two-step signing workloads at every action count; 1 KiB, 64 KiB, 1 MiB, and 4 MiB
|
|
215
258
|
scripts; and 25, 100, and 250 ms storage RTT. The measured cases deliberately
|
|
216
259
|
include both many-small-action and few-large-action shapes so transport tuning
|
|
217
260
|
is not fitted to one contract or graph. Production rollout should additionally
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Managed-change liquidity policy
|
|
2
|
+
|
|
3
|
+
Wallet-managed change is both the wallet's balance and its concurrency pool.
|
|
4
|
+
An output that is technically spendable but too small to carry a useful action
|
|
5
|
+
at the current fee rate does not provide useful liquidity. Conversely, creating
|
|
6
|
+
the entire pool in one transaction makes every child carry a large common BEEF
|
|
7
|
+
ancestor and creates unnecessary linkage.
|
|
8
|
+
|
|
9
|
+
This policy keeps `createAction` available to existing callers while gradually
|
|
10
|
+
moving new and existing wallets toward useful, parallel funding units.
|
|
11
|
+
|
|
12
|
+
## Invariants
|
|
13
|
+
|
|
14
|
+
The implementation treats these as non-negotiable:
|
|
15
|
+
|
|
16
|
+
1. A policy preference cannot make an action fail if the former planner could
|
|
17
|
+
fund it. Each parent-status tier retries the compatibility funding shape
|
|
18
|
+
before the planner widens to less-preferred ancestry.
|
|
19
|
+
2. `completed` parents are preferred, then `unproven`, then `sending`.
|
|
20
|
+
Pending outputs are never withheld: they remain a last-resort source and
|
|
21
|
+
are selected when settled liquidity cannot fund the action.
|
|
22
|
+
3. A large settled-input plan may be compared with pending alternatives, but
|
|
23
|
+
only after the configurable comparison threshold. The comparison uses the
|
|
24
|
+
actual serialized BEEF bytes plus the planned transaction bytes; input
|
|
25
|
+
count and satoshi value are not used as BEEF-size proxies.
|
|
26
|
+
4. Pool growth consumes only surplus already present after the requested
|
|
27
|
+
action and its exact incremental fee are funded. The wallet does not gather
|
|
28
|
+
another input merely to manufacture change outputs.
|
|
29
|
+
5. An output below the preferred value is permitted when it is the only
|
|
30
|
+
fundable remainder. The preferred value is not a dust rule and cannot turn
|
|
31
|
+
a valid payment into `WERR_INSUFFICIENT_FUNDS`.
|
|
32
|
+
6. Legacy fragments migrate only on a caller-authorized `createAction`, only
|
|
33
|
+
when their value exceeds their marginal input fee, and only within the
|
|
34
|
+
configured per-action budget.
|
|
35
|
+
7. Action-batch workspaces reserve disjoint outputs and use the same change
|
|
36
|
+
values and per-action shaping limits as the legacy `createAction` path.
|
|
37
|
+
8. Permission-token persistence retains delayed broadcast so a permission
|
|
38
|
+
grant does not inherit network-broadcast latency. The funding policy makes
|
|
39
|
+
queued change available only after preferred alternatives are exhausted.
|
|
40
|
+
|
|
41
|
+
## Defaults
|
|
42
|
+
|
|
43
|
+
| Setting | Default | Purpose |
|
|
44
|
+
| ---------------------------------- | -------------: | ---------------------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| Default-basket target | 144 outputs | Supports many independently planned actions without requiring one large fanout transaction. |
|
|
46
|
+
| Preferred output value | 5,000 satoshis | Keeps a liquidity unit useful at fee rates materially above the historical 32-satoshi era. |
|
|
47
|
+
| New outputs per action | 8 | Builds the pool progressively and bounds any one transaction's fanout and descendant BEEF footprint. |
|
|
48
|
+
| Legacy migration inputs per action | 4 | Retires old fragments progressively without recreating 178-input permission transactions. |
|
|
49
|
+
| Pending-comparison threshold | 16 inputs | Keeps the common settled path fast; above this point the planner measures alternatives by exact serialized cost. |
|
|
50
|
+
|
|
51
|
+
At the Wallet Toolbox default of 100 satoshis/kB, a 148-byte managed input adds
|
|
52
|
+
about 15 satoshis of fee and a minimal one-input/one-output transaction costs
|
|
53
|
+
about 20 satoshis. A 5,000-satoshi preferred unit is therefore roughly 250
|
|
54
|
+
minimal-spend fees at that rate. Even at 1,000 satoshis/kB it remains roughly
|
|
55
|
+
26 minimal-spend fees. The value is intentionally a liquidity target, not a
|
|
56
|
+
consensus or economic-dust boundary.
|
|
57
|
+
|
|
58
|
+
A completely filled default pool represents 720,000 satoshis. Wallets with a
|
|
59
|
+
smaller balance do not attempt to manufacture that reserve. They retain fewer
|
|
60
|
+
outputs, and a remainder below 5,000 satoshis is kept when that is the only
|
|
61
|
+
available shape.
|
|
62
|
+
|
|
63
|
+
## Funding and ancestry selection
|
|
64
|
+
|
|
65
|
+
For each action, storage loads unreserved managed change once and plans in this
|
|
66
|
+
order:
|
|
67
|
+
|
|
68
|
+
1. completed parents;
|
|
69
|
+
2. completed plus unproven parents;
|
|
70
|
+
3. completed, unproven, and sending parents.
|
|
71
|
+
|
|
72
|
+
Within each tier, the new surplus-only shape runs first. If that shape reports
|
|
73
|
+
insufficient funds, the same tier is immediately retried with the former
|
|
74
|
+
funding algorithm and the allocator's economic floor for its first remainder.
|
|
75
|
+
This is deliberately at least as permissive as the historical 32-satoshi
|
|
76
|
+
basket. An inability to create a preferred 5,000-satoshi change output is not
|
|
77
|
+
evidence that settled funds cannot pay the requested output.
|
|
78
|
+
|
|
79
|
+
The first successful plan is accepted immediately when it uses no more than 16
|
|
80
|
+
managed inputs. Above that threshold, later status tiers are also planned and
|
|
81
|
+
the wallet compares:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
serialized cost = planned transaction bytes + exact input BEEF bytes
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The smallest measured plan wins. If proof retrieval needed only for comparison
|
|
88
|
+
is unavailable, that alternative receives an infinite comparison cost; the
|
|
89
|
+
already fundable baseline remains available. This optimization can therefore
|
|
90
|
+
improve latency and BEEF size but cannot become a new availability dependency.
|
|
91
|
+
|
|
92
|
+
Using a `sending` parent necessarily extends the unconfirmed BEEF chain and a
|
|
93
|
+
failed ancestor can invalidate its descendants. That is why it is last in the
|
|
94
|
+
normal order. It remains supported because refusing a fundable user action is
|
|
95
|
+
worse than reluctantly extending the chain after all safer liquidity is
|
|
96
|
+
exhausted.
|
|
97
|
+
|
|
98
|
+
## Progressive pool shaping
|
|
99
|
+
|
|
100
|
+
Explicit or fixed inputs can already cover the requested outputs and fee. In
|
|
101
|
+
that case the planner materializes the first change output directly from that
|
|
102
|
+
existing surplus before considering optional fragment migration. It does not
|
|
103
|
+
call the managed-change allocator merely to create pool outputs. This keeps
|
|
104
|
+
consolidations and externally funded actions on the same shaping policy while
|
|
105
|
+
preserving the invariant that pool growth never gathers compulsory inputs.
|
|
106
|
+
When the surplus cannot pay both the marginal output fee and the economic dust
|
|
107
|
+
floor, the bounded remainder stays in the transaction fee instead of causing a
|
|
108
|
+
compatibility retry to gather another input solely to manufacture change.
|
|
109
|
+
|
|
110
|
+
After compulsory funding succeeds, the planner may consume up to four
|
|
111
|
+
undersized outputs. A fragment is skipped when spending it would cost at least
|
|
112
|
+
its value. Optional migration never supplies a missing satoshi for the caller's
|
|
113
|
+
requested outputs and never runs when the basket is already at its target.
|
|
114
|
+
|
|
115
|
+
The resulting surplus is split into at most eight outputs and only when every
|
|
116
|
+
new output can meet the preferred value after paying the exact added output
|
|
117
|
+
fee. Otherwise the wallet keeps one output. Excess is distributed through the
|
|
118
|
+
existing randomized change algorithm, and ordinary output randomization still
|
|
119
|
+
applies. The policy therefore preserves the existing privacy intent and
|
|
120
|
+
non-uniform values whenever surplus exists instead of replacing it with a
|
|
121
|
+
fixed deterministic denomination scheme. When the available value is exactly
|
|
122
|
+
the sum of the preferred minima, equal minima are unavoidable; the wallet does
|
|
123
|
+
not create a smaller output merely to force cosmetic variance.
|
|
124
|
+
|
|
125
|
+
The target is based on healthy outputs (those at or above the basket's
|
|
126
|
+
preferred value), not raw output count. Consuming a legacy fragment and
|
|
127
|
+
creating a useful output moves the pool forward; merely retaining another
|
|
128
|
+
32-satoshi fragment does not make the pool appear healthy.
|
|
129
|
+
|
|
130
|
+
## Existing-wallet migration
|
|
131
|
+
|
|
132
|
+
The SQL and IndexedDB providers recognize only the exact historical untouched
|
|
133
|
+
default:
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
basket name = default
|
|
137
|
+
target count = 144
|
|
138
|
+
minimum value = 32
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Those baskets advance to a 5,000-satoshi preferred value during the normal
|
|
142
|
+
provider migration. Other basket names, custom target counts, and custom
|
|
143
|
+
minimum values are unchanged. The migration does not consolidate, sign, or
|
|
144
|
+
broadcast a transaction. Future `createAction` calls progressively consume at
|
|
145
|
+
most the configured number of fee-positive fragments and create useful change
|
|
146
|
+
only from real surplus.
|
|
147
|
+
|
|
148
|
+
The SQL data migration is intentionally one-way. Rolling code back does not
|
|
149
|
+
rewrite a migrated preference to 32 or fragment funds. Older code can still
|
|
150
|
+
read and honor the 5,000-satoshi basket value. SQLite writes the migrated
|
|
151
|
+
row's timestamp in UTC ISO form, matching incremental-sync query values and
|
|
152
|
+
keeping that metadata immediately sync-visible. MySQL retains its native
|
|
153
|
+
millisecond timestamp expression.
|
|
154
|
+
|
|
155
|
+
## Operator configuration
|
|
156
|
+
|
|
157
|
+
The defaults are suitable for a general wallet. Local Knex and IndexedDB
|
|
158
|
+
operators can tune the work budgets without rebuilding the package:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const setup = await Setup.createWalletKnex({
|
|
162
|
+
...args,
|
|
163
|
+
managedChangePolicy: {
|
|
164
|
+
maxOutputsPerAction: 8,
|
|
165
|
+
migrationInputsPerAction: 4,
|
|
166
|
+
pendingComparisonInputs: 16
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The same `managedChangePolicy` option is accepted by `StorageKnex`,
|
|
172
|
+
`StorageIdb`, `Setup.createStorageKnex`, and `SetupClient.createStorageIdb`.
|
|
173
|
+
The basket target and preferred value remain user-wallet settings and can be
|
|
174
|
+
changed through `wallet.setWalletChangeParams(count, satoshis)`.
|
|
175
|
+
|
|
176
|
+
Each policy limit accepts `-1`, with deliberately different meanings:
|
|
177
|
+
|
|
178
|
+
- `maxOutputsPerAction: -1` makes the basket target the only fanout bound;
|
|
179
|
+
- `migrationInputsPerAction: -1` permits all fee-positive legacy fragments in
|
|
180
|
+
one authorized action;
|
|
181
|
+
- `pendingComparisonInputs: -1` disables optional pending-plan comparison, but
|
|
182
|
+
pending funds remain available when earlier tiers are insufficient.
|
|
183
|
+
|
|
184
|
+
Unlimited modes can create large transactions or BEEF payloads and should be
|
|
185
|
+
used only by operators that have measured their workload. They do not remove
|
|
186
|
+
the wallet's economic-dust check, transaction validity checks, action-batch
|
|
187
|
+
reservation limit, or available-funding bound.
|
|
188
|
+
|
|
189
|
+
The official `wallet-infra` image exposes the same settings as validated
|
|
190
|
+
environment values:
|
|
191
|
+
|
|
192
|
+
```dotenv
|
|
193
|
+
WALLET_STORAGE_MANAGED_CHANGE_MAX_OUTPUTS_PER_ACTION=8
|
|
194
|
+
WALLET_STORAGE_MANAGED_CHANGE_MIGRATION_INPUTS_PER_ACTION=4
|
|
195
|
+
WALLET_STORAGE_MANAGED_CHANGE_PENDING_COMPARISON_INPUTS=16
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
This lets a hosted Wallet Storage provider choose the policy without rebuilding
|
|
199
|
+
the image. Invalid, unsafe-integer, or out-of-range values fail startup instead
|
|
200
|
+
of silently falling back. The API and singleton Monitor roles must use the same
|
|
201
|
+
values so planning, reservation, and operator reporting describe one policy.
|
|
202
|
+
|
|
203
|
+
## Action batches and concurrent workspaces
|
|
204
|
+
|
|
205
|
+
An action-batch begin response carries the effective output and migration
|
|
206
|
+
limits when the provider supports them. Older and third-party providers can
|
|
207
|
+
omit the optional policy; clients then use the same defaults. Initial and
|
|
208
|
+
extended reservation selection prefers completed parents, then unproven, then
|
|
209
|
+
sending, while still reserving enough last-resort liquidity to avoid wedging a
|
|
210
|
+
workspace.
|
|
211
|
+
|
|
212
|
+
Workspaces remain isolated by explicit transaction-graph membership and their
|
|
213
|
+
reservations remain disjoint. Pool-shaping state is local to each plan; there
|
|
214
|
+
is no global in-memory "current batch" whose change can be consumed by an
|
|
215
|
+
unrelated action.
|
|
216
|
+
|
|
217
|
+
## Monitoring and rollout
|
|
218
|
+
|
|
219
|
+
`TaskReviewUtxos.reviewManagedChangeByIdentityKey(identityKey)` is a read-only
|
|
220
|
+
operator report. It returns:
|
|
221
|
+
|
|
222
|
+
- total and target managed-change counts;
|
|
223
|
+
- healthy and undersized counts;
|
|
224
|
+
- active action-batch reservations;
|
|
225
|
+
- completed, unproven, and sending parent counts;
|
|
226
|
+
- total satoshis and the preferred minimum.
|
|
227
|
+
|
|
228
|
+
Monitor has no signing authority and does not perform consolidation. This
|
|
229
|
+
keeps migration tied to normal user-authorized actions and makes rollout
|
|
230
|
+
observable without creating surprise transactions. The official Monitor admin
|
|
231
|
+
UI exposes the same report as the **managed-change liquidity (read only)** UTXO
|
|
232
|
+
review mode.
|
|
233
|
+
|
|
234
|
+
Recommended rollout checks are:
|
|
235
|
+
|
|
236
|
+
1. record the report before upgrade;
|
|
237
|
+
2. migrate the storage provider and confirm only exact legacy defaults changed;
|
|
238
|
+
3. exercise a small immediate action, a delayed permission action, and two
|
|
239
|
+
concurrent action-batch workspaces;
|
|
240
|
+
4. confirm undersized count declines gradually and sending-parent use remains
|
|
241
|
+
exceptional;
|
|
242
|
+
5. watch action input count, serialized BEEF bytes, fee, and broadcast failure
|
|
243
|
+
rates before changing defaults or selecting an unlimited mode.
|
|
244
|
+
|
|
245
|
+
## Compatibility surface
|
|
246
|
+
|
|
247
|
+
No BRC-100 method, Wallet Wire method, Storage Server RPC method, or persisted
|
|
248
|
+
transaction format changes. The action-batch policy field is optional. Existing
|
|
249
|
+
custom basket settings remain authoritative. A same-tier compatibility plan,
|
|
250
|
+
followed by the retained pending-parent fallback, ensures the new preferences
|
|
251
|
+
do not add a refusal where the previous wallet could create an action.
|
package/out/src/Setup.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { Monitor } from './monitor/Monitor';
|
|
|
9
9
|
import { Wallet } from './Wallet';
|
|
10
10
|
import { StorageKnex } from './storage/StorageKnex';
|
|
11
11
|
import { WalletStorageProvider } from './sdk/WalletStorage.interfaces';
|
|
12
|
+
import type { ManagedChangePolicyOptions } from './storage/methods/managedChangePolicy';
|
|
12
13
|
/**
|
|
13
14
|
* The 'Setup` class provides static setup functions to construct BRC-100 compatible
|
|
14
15
|
* wallets in a variety of configurations.
|
|
@@ -190,6 +191,8 @@ export interface SetupWalletArgs {
|
|
|
190
191
|
* storage validation. This does not alter the BRC-100 interface.
|
|
191
192
|
*/
|
|
192
193
|
scriptVerifier?: SpendVerifierInterface;
|
|
194
|
+
/** Optional operator tuning for wallet-managed liquidity shaping. */
|
|
195
|
+
managedChangePolicy?: ManagedChangePolicyOptions;
|
|
193
196
|
}
|
|
194
197
|
/**
|
|
195
198
|
*
|
|
@@ -197,6 +200,12 @@ export interface SetupWalletArgs {
|
|
|
197
200
|
export interface SetupWalletKnexArgs extends SetupWalletArgs {
|
|
198
201
|
knex: Knex<any, any[]>;
|
|
199
202
|
databaseName: string;
|
|
203
|
+
/**
|
|
204
|
+
* Maximum persisted outputs one action-batch workspace may reserve.
|
|
205
|
+
* Defaults to 256. Set to -1 only when the storage operator deliberately
|
|
206
|
+
* accepts unbounded reservations.
|
|
207
|
+
*/
|
|
208
|
+
actionBatchMaxReservedOutputs?: number;
|
|
200
209
|
}
|
|
201
210
|
/**
|
|
202
211
|
*
|