@cogcoin/client 0.5.14 → 1.0.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/README.md +80 -25
- package/dist/app-paths.d.ts +5 -6
- package/dist/app-paths.js +8 -16
- package/dist/art/balance.txt +10 -0
- package/dist/art/welcome.txt +16 -0
- package/dist/bitcoind/bootstrap/controller.d.ts +1 -0
- package/dist/bitcoind/bootstrap/controller.js +53 -1
- package/dist/bitcoind/client/follow-block-times.d.ts +1 -0
- package/dist/bitcoind/client/follow-block-times.js +1 -1
- package/dist/bitcoind/client/internal-types.d.ts +7 -3
- package/dist/bitcoind/client/managed-client.d.ts +4 -2
- package/dist/bitcoind/client/managed-client.js +14 -0
- package/dist/bitcoind/client/sync-engine.js +72 -11
- package/dist/bitcoind/hash-order.d.ts +4 -0
- package/dist/bitcoind/hash-order.js +13 -0
- package/dist/bitcoind/indexer-daemon-main.js +11 -3
- package/dist/bitcoind/normalize.js +3 -2
- package/dist/bitcoind/processing-start-height.d.ts +5 -0
- package/dist/bitcoind/processing-start-height.js +7 -0
- package/dist/bitcoind/progress/constants.d.ts +4 -0
- package/dist/bitcoind/progress/constants.js +4 -0
- package/dist/bitcoind/progress/controller.d.ts +2 -1
- package/dist/bitcoind/progress/controller.js +3 -3
- package/dist/bitcoind/progress/follow-scene.d.ts +6 -2
- package/dist/bitcoind/progress/follow-scene.js +29 -6
- package/dist/bitcoind/progress/formatting.d.ts +1 -0
- package/dist/bitcoind/progress/formatting.js +6 -0
- package/dist/bitcoind/progress/train-scene.js +37 -18
- package/dist/bitcoind/progress/tty-renderer.d.ts +6 -1
- package/dist/bitcoind/progress/tty-renderer.js +8 -4
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +3 -0
- package/dist/bitcoind/types.d.ts +16 -0
- package/dist/bytes.d.ts +1 -0
- package/dist/bytes.js +3 -0
- package/dist/cli/art.d.ts +2 -0
- package/dist/cli/art.js +37 -0
- package/dist/cli/commands/client-admin.d.ts +2 -0
- package/dist/cli/commands/client-admin.js +91 -0
- package/dist/cli/commands/follow.js +0 -2
- package/dist/cli/commands/mining-admin.js +6 -47
- package/dist/cli/commands/mining-read.js +11 -50
- package/dist/cli/commands/mining-runtime.js +38 -3
- package/dist/cli/commands/service-runtime.js +0 -2
- package/dist/cli/commands/status.js +8 -2
- package/dist/cli/commands/sync.js +51 -4
- package/dist/cli/commands/wallet-admin.js +142 -136
- package/dist/cli/commands/wallet-mutation.js +91 -79
- package/dist/cli/commands/wallet-read.js +15 -18
- package/dist/cli/context.js +4 -14
- package/dist/cli/mining-format.d.ts +0 -1
- package/dist/cli/mining-format.js +5 -37
- package/dist/cli/mining-json.d.ts +0 -18
- package/dist/cli/mining-json.js +0 -35
- package/dist/cli/mutation-command-groups.d.ts +1 -2
- package/dist/cli/mutation-command-groups.js +0 -5
- package/dist/cli/mutation-json.d.ts +24 -145
- package/dist/cli/mutation-json.js +30 -136
- package/dist/cli/mutation-resolved-json.d.ts +0 -7
- package/dist/cli/mutation-resolved-json.js +4 -10
- package/dist/cli/mutation-success.d.ts +2 -0
- package/dist/cli/mutation-success.js +11 -1
- package/dist/cli/mutation-text-format.js +1 -3
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js +254 -231
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +93 -122
- package/dist/cli/preview-json.d.ts +17 -120
- package/dist/cli/preview-json.js +14 -97
- package/dist/cli/prompt.js +8 -13
- package/dist/cli/read-json.d.ts +15 -37
- package/dist/cli/read-json.js +44 -140
- package/dist/cli/runner.js +10 -13
- package/dist/cli/types.d.ts +8 -17
- package/dist/cli/types.js +0 -2
- package/dist/cli/wallet-format.d.ts +1 -0
- package/dist/cli/wallet-format.js +205 -144
- package/dist/cli/workflow-hints.d.ts +3 -3
- package/dist/cli/workflow-hints.js +11 -8
- package/dist/client/default-client.d.ts +3 -1
- package/dist/client/default-client.js +45 -2
- package/dist/client/factory.js +1 -1
- package/dist/client/initialization.js +23 -0
- package/dist/client/persistence.js +5 -5
- package/dist/client/store-adapter.js +1 -0
- package/dist/sqlite/checkpoints.d.ts +1 -0
- package/dist/sqlite/checkpoints.js +7 -0
- package/dist/sqlite/store.js +14 -1
- package/dist/types.d.ts +1 -0
- package/dist/wallet/coin-control.d.ts +41 -11
- package/dist/wallet/coin-control.js +100 -357
- package/dist/wallet/descriptor-normalization.d.ts +1 -3
- package/dist/wallet/descriptor-normalization.js +0 -16
- package/dist/wallet/lifecycle.d.ts +7 -99
- package/dist/wallet/lifecycle.js +513 -968
- package/dist/wallet/managed-core-wallet.d.ts +13 -0
- package/dist/wallet/managed-core-wallet.js +20 -0
- package/dist/wallet/mining/constants.d.ts +5 -12
- package/dist/wallet/mining/constants.js +5 -12
- package/dist/wallet/mining/control.d.ts +1 -13
- package/dist/wallet/mining/control.js +45 -349
- package/dist/wallet/mining/index.d.ts +3 -4
- package/dist/wallet/mining/index.js +1 -2
- package/dist/wallet/mining/runner.d.ts +179 -6
- package/dist/wallet/mining/runner.js +891 -501
- package/dist/wallet/mining/runtime-artifacts.js +23 -3
- package/dist/wallet/mining/sentence-protocol.d.ts +44 -0
- package/dist/wallet/mining/sentence-protocol.js +123 -0
- package/dist/wallet/mining/sentences.d.ts +4 -8
- package/dist/wallet/mining/sentences.js +3 -52
- package/dist/wallet/mining/state.d.ts +11 -6
- package/dist/wallet/mining/state.js +7 -6
- package/dist/wallet/mining/types.d.ts +2 -30
- package/dist/wallet/mining/visualizer.d.ts +31 -3
- package/dist/wallet/mining/visualizer.js +135 -13
- package/dist/wallet/read/context.d.ts +0 -2
- package/dist/wallet/read/context.js +119 -140
- package/dist/wallet/read/filter.js +2 -11
- package/dist/wallet/read/index.d.ts +1 -1
- package/dist/wallet/read/project.js +24 -77
- package/dist/wallet/read/types.d.ts +10 -25
- package/dist/wallet/reset.d.ts +0 -1
- package/dist/wallet/reset.js +60 -138
- package/dist/wallet/root-resolution.d.ts +1 -5
- package/dist/wallet/root-resolution.js +0 -18
- package/dist/wallet/runtime.d.ts +0 -6
- package/dist/wallet/runtime.js +0 -8
- package/dist/wallet/state/client-password-agent.js +208 -0
- package/dist/wallet/state/client-password.d.ts +65 -0
- package/dist/wallet/state/client-password.js +952 -0
- package/dist/wallet/state/crypto.d.ts +1 -20
- package/dist/wallet/state/crypto.js +0 -63
- package/dist/wallet/state/provider.d.ts +23 -11
- package/dist/wallet/state/provider.js +248 -290
- package/dist/wallet/state/storage.d.ts +2 -2
- package/dist/wallet/state/storage.js +48 -16
- package/dist/wallet/tx/anchor.d.ts +3 -28
- package/dist/wallet/tx/anchor.js +349 -1240
- package/dist/wallet/tx/bitcoin-transfer.d.ts +35 -0
- package/dist/wallet/tx/bitcoin-transfer.js +200 -0
- package/dist/wallet/tx/cog.d.ts +5 -1
- package/dist/wallet/tx/cog.js +149 -185
- package/dist/wallet/tx/common.d.ts +74 -10
- package/dist/wallet/tx/common.js +315 -138
- package/dist/wallet/tx/domain-admin.d.ts +3 -1
- package/dist/wallet/tx/domain-admin.js +61 -99
- package/dist/wallet/tx/domain-market.d.ts +5 -1
- package/dist/wallet/tx/domain-market.js +221 -228
- package/dist/wallet/tx/field.d.ts +4 -10
- package/dist/wallet/tx/field.js +84 -914
- package/dist/wallet/tx/identity-selector.d.ts +9 -3
- package/dist/wallet/tx/identity-selector.js +17 -35
- package/dist/wallet/tx/index.d.ts +3 -1
- package/dist/wallet/tx/index.js +2 -1
- package/dist/wallet/tx/register.d.ts +3 -1
- package/dist/wallet/tx/register.js +62 -220
- package/dist/wallet/tx/reputation.d.ts +3 -1
- package/dist/wallet/tx/reputation.js +58 -95
- package/dist/wallet/types.d.ts +8 -122
- package/package.json +5 -5
- package/dist/wallet/archive.d.ts +0 -4
- package/dist/wallet/archive.js +0 -41
- package/dist/wallet/mining/hook-protocol.d.ts +0 -47
- package/dist/wallet/mining/hook-protocol.js +0 -161
- package/dist/wallet/mining/hook-runner.js +0 -52
- package/dist/wallet/mining/hooks.d.ts +0 -38
- package/dist/wallet/mining/hooks.js +0 -520
- package/dist/wallet/state/explicit-lock.d.ts +0 -4
- package/dist/wallet/state/explicit-lock.js +0 -19
- package/dist/wallet/state/session.d.ts +0 -12
- package/dist/wallet/state/session.js +0 -23
- /package/dist/wallet/{mining/hook-runner.d.ts → state/client-password-agent.d.ts} +0 -0
|
@@ -1,367 +1,126 @@
|
|
|
1
|
-
import { saveUnlockSession } from "./state/session.js";
|
|
2
1
|
import { persistWalletStateUpdate } from "./descriptor-normalization.js";
|
|
3
|
-
import {
|
|
4
|
-
export const DEFAULT_PROACTIVE_RESERVE_SATS =
|
|
5
|
-
function btcNumberToSats(value) {
|
|
6
|
-
return BigInt(Math.round(value * 100_000_000));
|
|
7
|
-
}
|
|
2
|
+
import { normalizeMiningStateRecord } from "./mining/state.js";
|
|
3
|
+
export const DEFAULT_PROACTIVE_RESERVE_SATS = 0;
|
|
8
4
|
export function outpointKey(outpoint) {
|
|
9
5
|
return `${outpoint.txid}:${outpoint.vout}`;
|
|
10
6
|
}
|
|
11
|
-
function
|
|
12
|
-
|
|
7
|
+
function uniqueStrings(values) {
|
|
8
|
+
return values.filter((value, index, entries) => typeof value === "string" && value.length > 0 && entries.indexOf(value) === index);
|
|
9
|
+
}
|
|
10
|
+
function uniqueOutpoints(values) {
|
|
13
11
|
const seen = new Set();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
||
|
|
18
|
-
||
|
|
19
|
-
||
|
|
20
|
-
||
|
|
12
|
+
const normalized = [];
|
|
13
|
+
for (const value of values ?? []) {
|
|
14
|
+
if (value == null
|
|
15
|
+
|| typeof value.txid !== "string"
|
|
16
|
+
|| value.txid.length === 0
|
|
17
|
+
|| typeof value.vout !== "number"
|
|
18
|
+
|| !Number.isInteger(value.vout)
|
|
19
|
+
|| value.vout < 0) {
|
|
21
20
|
continue;
|
|
22
21
|
}
|
|
23
|
-
const key = outpointKey(
|
|
22
|
+
const key = outpointKey(value);
|
|
24
23
|
if (seen.has(key)) {
|
|
25
24
|
continue;
|
|
26
25
|
}
|
|
27
26
|
seen.add(key);
|
|
28
|
-
normalized.push({ txid:
|
|
27
|
+
normalized.push({ txid: value.txid, vout: value.vout });
|
|
29
28
|
}
|
|
30
29
|
return normalized;
|
|
31
30
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return 0;
|
|
39
|
-
}
|
|
40
|
-
return DEFAULT_PROACTIVE_RESERVE_SATS;
|
|
41
|
-
}
|
|
42
|
-
function sameOutpointList(left, right) {
|
|
43
|
-
if (left.length !== (right?.length ?? 0)) {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
return left.every((outpoint, index) => outpoint.txid === right?.[index]?.txid && outpoint.vout === right?.[index]?.vout);
|
|
47
|
-
}
|
|
48
|
-
export function normalizeWalletStateRecord(state) {
|
|
49
|
-
const rawProactiveReserveSats = state.proactiveReserveSats;
|
|
50
|
-
const proactiveReserveSats = normalizeReserveSats(rawProactiveReserveSats);
|
|
51
|
-
const reserveValueChanged = proactiveReserveSats !== rawProactiveReserveSats;
|
|
52
|
-
const proactiveReserveOutpoints = normalizeOutpointRecordList(proactiveReserveSats <= 0 || reserveValueChanged
|
|
53
|
-
? []
|
|
54
|
-
: state.proactiveReserveOutpoints);
|
|
55
|
-
const pendingMutations = state.pendingMutations ?? [];
|
|
56
|
-
if (proactiveReserveSats === state.proactiveReserveSats
|
|
57
|
-
&& sameOutpointList(proactiveReserveOutpoints, state.proactiveReserveOutpoints)
|
|
58
|
-
&& pendingMutations === state.pendingMutations) {
|
|
59
|
-
return state;
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
...state,
|
|
63
|
-
proactiveReserveSats,
|
|
64
|
-
proactiveReserveOutpoints,
|
|
65
|
-
pendingMutations,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
export function normalizePortableWalletArchivePayload(payload) {
|
|
69
|
-
const rawProactiveReserveSats = payload.proactiveReserveSats;
|
|
70
|
-
const proactiveReserveSats = normalizeReserveSats(rawProactiveReserveSats);
|
|
71
|
-
const reserveValueChanged = proactiveReserveSats !== rawProactiveReserveSats;
|
|
72
|
-
const proactiveReserveOutpoints = normalizeOutpointRecordList(proactiveReserveSats <= 0 || reserveValueChanged
|
|
73
|
-
? []
|
|
74
|
-
: payload.proactiveReserveOutpoints);
|
|
75
|
-
if (proactiveReserveSats === payload.proactiveReserveSats
|
|
76
|
-
&& sameOutpointList(proactiveReserveOutpoints, payload.proactiveReserveOutpoints)) {
|
|
77
|
-
return payload;
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
...payload,
|
|
81
|
-
proactiveReserveSats,
|
|
82
|
-
proactiveReserveOutpoints,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
function isSpendableUtxo(entry) {
|
|
86
|
-
return entry.spendable !== false && entry.safe !== false;
|
|
87
|
-
}
|
|
88
|
-
function isConfirmedFundingUtxo(state, entry) {
|
|
89
|
-
return entry.scriptPubKey === state.funding.scriptPubKeyHex
|
|
90
|
-
&& entry.confirmations >= 1
|
|
91
|
-
&& isSpendableUtxo(entry);
|
|
92
|
-
}
|
|
93
|
-
function sortFundingEntriesForReserve(entries) {
|
|
94
|
-
return entries.slice().sort((left, right) => {
|
|
95
|
-
const amount = btcNumberToSats(right.amount) - btcNumberToSats(left.amount);
|
|
96
|
-
if (amount !== 0n) {
|
|
97
|
-
return amount > 0n ? 1 : -1;
|
|
98
|
-
}
|
|
99
|
-
const txid = left.txid.localeCompare(right.txid);
|
|
100
|
-
if (txid !== 0) {
|
|
101
|
-
return txid;
|
|
102
|
-
}
|
|
103
|
-
return left.vout - right.vout;
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
function isActiveTrackedTransaction(record) {
|
|
107
|
-
if (record == null) {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
return record.status === "broadcasting"
|
|
111
|
-
|| record.status === "broadcast-unknown"
|
|
112
|
-
|| record.status === "live";
|
|
113
|
-
}
|
|
114
|
-
function isActiveTrackedStatus(status) {
|
|
115
|
-
return status === "broadcasting"
|
|
116
|
-
|| status === "broadcast-unknown"
|
|
117
|
-
|| status === "live";
|
|
118
|
-
}
|
|
119
|
-
function deriveLiveProvisionalOutpointKeys(state) {
|
|
120
|
-
const keys = new Set();
|
|
121
|
-
for (const family of state.proactiveFamilies) {
|
|
122
|
-
if ((family.type !== "anchor" && family.type !== "field") || family.tx1?.attemptedTxid == null) {
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
if (isActiveTrackedStatus(family.status)) {
|
|
126
|
-
keys.add(outpointKey({ txid: family.tx1.attemptedTxid, vout: 1 }));
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return keys;
|
|
130
|
-
}
|
|
131
|
-
function deriveAuxiliaryDedicatedOutpoints(state, spendableUtxos) {
|
|
132
|
-
const canonicalAnchorKeys = new Set(state.domains
|
|
133
|
-
.map((domain) => domain.currentCanonicalAnchorOutpoint)
|
|
134
|
-
.filter((outpoint) => outpoint !== null)
|
|
135
|
-
.map((outpoint) => outpointKey(outpoint)));
|
|
136
|
-
const dedicatedScriptSet = new Set(state.identities
|
|
137
|
-
.filter((identity) => identity.status === "dedicated")
|
|
138
|
-
.map((identity) => identity.scriptPubKeyHex));
|
|
139
|
-
const liveProvisionalKeys = deriveLiveProvisionalOutpointKeys(state);
|
|
140
|
-
const auxiliary = [];
|
|
141
|
-
const seen = new Set();
|
|
142
|
-
for (const entry of spendableUtxos) {
|
|
143
|
-
if (!isSpendableUtxo(entry) || !dedicatedScriptSet.has(entry.scriptPubKey)) {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
const outpoint = { txid: entry.txid, vout: entry.vout };
|
|
147
|
-
const key = outpointKey(outpoint);
|
|
148
|
-
if (canonicalAnchorKeys.has(key) || liveProvisionalKeys.has(key) || seen.has(key)) {
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
seen.add(key);
|
|
152
|
-
auxiliary.push(outpoint);
|
|
153
|
-
}
|
|
154
|
-
return auxiliary;
|
|
155
|
-
}
|
|
156
|
-
export function computeDesignatedProactiveReserveOutpoints(state, spendableUtxos) {
|
|
157
|
-
const normalizedState = normalizeWalletStateRecord(state);
|
|
158
|
-
if (normalizedState.proactiveReserveSats <= 0) {
|
|
159
|
-
return [];
|
|
160
|
-
}
|
|
161
|
-
const conflictKey = normalizedState.miningState.sharedMiningConflictOutpoint === null
|
|
162
|
-
? null
|
|
163
|
-
: outpointKey(normalizedState.miningState.sharedMiningConflictOutpoint);
|
|
164
|
-
const eligible = sortFundingEntriesForReserve(spendableUtxos.filter((entry) => isConfirmedFundingUtxo(normalizedState, entry)
|
|
165
|
-
&& outpointKey({ txid: entry.txid, vout: entry.vout }) !== conflictKey));
|
|
166
|
-
const selected = [];
|
|
167
|
-
let total = 0n;
|
|
168
|
-
const target = BigInt(normalizedState.proactiveReserveSats);
|
|
169
|
-
for (const entry of eligible) {
|
|
170
|
-
selected.push({ txid: entry.txid, vout: entry.vout });
|
|
171
|
-
total += btcNumberToSats(entry.amount);
|
|
172
|
-
if (total >= target) {
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (total < target) {
|
|
177
|
-
return [];
|
|
178
|
-
}
|
|
179
|
-
return selected;
|
|
31
|
+
function uniqueLocalScriptPubKeyHexes(state) {
|
|
32
|
+
return uniqueStrings([
|
|
33
|
+
state.funding?.scriptPubKeyHex ?? "",
|
|
34
|
+
...(state.localScriptPubKeyHexes ?? []),
|
|
35
|
+
...((state.identities ?? []).map((identity) => identity?.scriptPubKeyHex ?? "")),
|
|
36
|
+
]);
|
|
180
37
|
}
|
|
181
|
-
function
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
38
|
+
function normalizeDomains(rawDomains) {
|
|
39
|
+
return (rawDomains ?? [])
|
|
40
|
+
.filter((domain) => typeof domain?.name === "string" && domain.name.trim().length > 0)
|
|
41
|
+
.map((domain) => ({
|
|
42
|
+
name: domain.name.trim().toLowerCase(),
|
|
43
|
+
domainId: domain.domainId ?? null,
|
|
44
|
+
currentOwnerScriptPubKeyHex: domain.currentOwnerScriptPubKeyHex ?? null,
|
|
45
|
+
canonicalChainStatus: domain.canonicalChainStatus ?? "unknown",
|
|
46
|
+
foundingMessageText: domain.foundingMessageText ?? null,
|
|
47
|
+
birthTime: domain.birthTime ?? null,
|
|
48
|
+
}))
|
|
49
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
50
|
+
}
|
|
51
|
+
export function normalizeWalletStateRecord(rawState) {
|
|
52
|
+
const fundingAddress = rawState.funding?.address
|
|
53
|
+
?? rawState.managedCoreWallet?.walletAddress
|
|
54
|
+
?? rawState.managedCoreWallet?.fundingAddress0
|
|
55
|
+
?? "";
|
|
56
|
+
const fundingScriptPubKeyHex = rawState.funding?.scriptPubKeyHex
|
|
57
|
+
?? rawState.managedCoreWallet?.walletScriptPubKeyHex
|
|
58
|
+
?? rawState.managedCoreWallet?.fundingScriptPubKeyHex0
|
|
59
|
+
?? "";
|
|
60
|
+
const localScriptPubKeyHexes = uniqueLocalScriptPubKeyHexes(rawState);
|
|
61
|
+
const pendingMutations = (rawState.pendingMutations ?? [])
|
|
62
|
+
.filter((mutation) => mutation.status === "confirmed" || mutation.status === "canceled")
|
|
63
|
+
.map((mutation) => ({
|
|
64
|
+
...mutation,
|
|
65
|
+
senderLocalIndex: mutation.senderScriptPubKeyHex === fundingScriptPubKeyHex ? 0 : null,
|
|
66
|
+
senderScriptPubKeyHex: mutation.senderScriptPubKeyHex === ""
|
|
67
|
+
? fundingScriptPubKeyHex
|
|
68
|
+
: mutation.senderScriptPubKeyHex,
|
|
69
|
+
temporaryBuilderLockedOutpoints: [],
|
|
70
|
+
}));
|
|
198
71
|
return {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
72
|
+
schemaVersion: 5,
|
|
73
|
+
stateRevision: rawState.stateRevision ?? 1,
|
|
74
|
+
lastWrittenAtUnixMs: rawState.lastWrittenAtUnixMs ?? 0,
|
|
75
|
+
walletRootId: rawState.walletRootId ?? "",
|
|
76
|
+
network: rawState.network ?? "mainnet",
|
|
77
|
+
localScriptPubKeyHexes,
|
|
78
|
+
mnemonic: {
|
|
79
|
+
phrase: rawState.mnemonic?.phrase ?? "",
|
|
80
|
+
language: rawState.mnemonic?.language ?? "english",
|
|
202
81
|
},
|
|
203
|
-
|
|
82
|
+
keys: {
|
|
83
|
+
masterFingerprintHex: rawState.keys?.masterFingerprintHex ?? "",
|
|
84
|
+
accountPath: rawState.keys?.accountPath ?? "",
|
|
85
|
+
accountXprv: rawState.keys?.accountXprv ?? "",
|
|
86
|
+
accountXpub: rawState.keys?.accountXpub ?? "",
|
|
87
|
+
},
|
|
88
|
+
descriptor: {
|
|
89
|
+
privateExternal: rawState.descriptor?.privateExternal ?? "",
|
|
90
|
+
publicExternal: rawState.descriptor?.publicExternal ?? "",
|
|
91
|
+
checksum: rawState.descriptor?.checksum ?? null,
|
|
92
|
+
rangeEnd: rawState.descriptor?.rangeEnd ?? 0,
|
|
93
|
+
safetyMargin: rawState.descriptor?.safetyMargin ?? 0,
|
|
94
|
+
},
|
|
95
|
+
funding: {
|
|
96
|
+
address: fundingAddress,
|
|
97
|
+
scriptPubKeyHex: fundingScriptPubKeyHex,
|
|
98
|
+
},
|
|
99
|
+
walletBirthTime: rawState.walletBirthTime ?? 0,
|
|
100
|
+
managedCoreWallet: {
|
|
101
|
+
walletName: rawState.managedCoreWallet?.walletName ?? "",
|
|
102
|
+
internalPassphrase: rawState.managedCoreWallet?.internalPassphrase ?? "",
|
|
103
|
+
descriptorChecksum: rawState.managedCoreWallet?.descriptorChecksum ?? null,
|
|
104
|
+
walletAddress: rawState.managedCoreWallet?.walletAddress ?? fundingAddress,
|
|
105
|
+
walletScriptPubKeyHex: rawState.managedCoreWallet?.walletScriptPubKeyHex ?? fundingScriptPubKeyHex,
|
|
106
|
+
proofStatus: rawState.managedCoreWallet?.proofStatus ?? "not-proven",
|
|
107
|
+
lastImportedAtUnixMs: rawState.managedCoreWallet?.lastImportedAtUnixMs ?? null,
|
|
108
|
+
lastVerifiedAtUnixMs: rawState.managedCoreWallet?.lastVerifiedAtUnixMs ?? null,
|
|
109
|
+
},
|
|
110
|
+
domains: normalizeDomains(rawState.domains),
|
|
111
|
+
miningState: normalizeMiningStateRecord(rawState.miningState),
|
|
112
|
+
pendingMutations,
|
|
204
113
|
};
|
|
205
114
|
}
|
|
206
|
-
function
|
|
207
|
-
|
|
208
|
-
const stale = new Map();
|
|
209
|
-
let familiesChanged = false;
|
|
210
|
-
let mutationsChanged = false;
|
|
211
|
-
const proactiveFamilies = normalizedState.proactiveFamilies.map((family) => {
|
|
212
|
-
let nextFamily = family;
|
|
213
|
-
for (const key of ["tx1", "tx2"]) {
|
|
214
|
-
const record = nextFamily[key];
|
|
215
|
-
if (record == null || isActiveTrackedTransaction(record) || record.temporaryBuilderLockedOutpoints.length === 0) {
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
for (const outpoint of record.temporaryBuilderLockedOutpoints) {
|
|
219
|
-
stale.set(outpointKey(outpoint), outpoint);
|
|
220
|
-
}
|
|
221
|
-
nextFamily = {
|
|
222
|
-
...nextFamily,
|
|
223
|
-
[key]: {
|
|
224
|
-
...record,
|
|
225
|
-
temporaryBuilderLockedOutpoints: [],
|
|
226
|
-
},
|
|
227
|
-
};
|
|
228
|
-
familiesChanged = true;
|
|
229
|
-
}
|
|
230
|
-
return nextFamily;
|
|
231
|
-
});
|
|
232
|
-
const pendingMutations = (normalizedState.pendingMutations ?? []).map((mutation) => {
|
|
233
|
-
if (isActiveTrackedStatus(mutation.status) || mutation.temporaryBuilderLockedOutpoints.length === 0) {
|
|
234
|
-
return mutation;
|
|
235
|
-
}
|
|
236
|
-
for (const outpoint of mutation.temporaryBuilderLockedOutpoints) {
|
|
237
|
-
stale.set(outpointKey(outpoint), outpoint);
|
|
238
|
-
}
|
|
239
|
-
mutationsChanged = true;
|
|
240
|
-
return {
|
|
241
|
-
...mutation,
|
|
242
|
-
temporaryBuilderLockedOutpoints: [],
|
|
243
|
-
};
|
|
244
|
-
});
|
|
245
|
-
if (!familiesChanged && !mutationsChanged && normalizedState === state) {
|
|
246
|
-
return {
|
|
247
|
-
state,
|
|
248
|
-
staleOutpoints: [],
|
|
249
|
-
changed: false,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
return {
|
|
253
|
-
state: familiesChanged || mutationsChanged
|
|
254
|
-
? {
|
|
255
|
-
...normalizedState,
|
|
256
|
-
proactiveFamilies,
|
|
257
|
-
pendingMutations,
|
|
258
|
-
}
|
|
259
|
-
: normalizedState,
|
|
260
|
-
staleOutpoints: [...stale.values()],
|
|
261
|
-
changed: familiesChanged || mutationsChanged || normalizedState !== state,
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
function collectPersistentPolicyLockedOutpoints(state, spendableUtxos) {
|
|
265
|
-
const outpoints = [];
|
|
266
|
-
const seen = new Set();
|
|
267
|
-
const pushUnique = (outpoint) => {
|
|
268
|
-
if (outpoint === null) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
const key = outpointKey(outpoint);
|
|
272
|
-
if (seen.has(key)) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
seen.add(key);
|
|
276
|
-
outpoints.push(outpoint);
|
|
277
|
-
};
|
|
278
|
-
for (const domain of state.domains) {
|
|
279
|
-
pushUnique(domain.currentCanonicalAnchorOutpoint);
|
|
280
|
-
}
|
|
281
|
-
for (const outpoint of deriveAuxiliaryDedicatedOutpoints(state, spendableUtxos)) {
|
|
282
|
-
pushUnique(outpoint);
|
|
283
|
-
}
|
|
284
|
-
for (const outpoint of state.proactiveReserveOutpoints) {
|
|
285
|
-
pushUnique(outpoint);
|
|
286
|
-
}
|
|
287
|
-
if (!miningFamilyMayStillExist(state.miningState)) {
|
|
288
|
-
pushUnique(state.miningState.sharedMiningConflictOutpoint);
|
|
289
|
-
}
|
|
290
|
-
return outpoints;
|
|
115
|
+
export function computeDesignatedProactiveReserveOutpoints(_state, _spendableUtxos) {
|
|
116
|
+
return [];
|
|
291
117
|
}
|
|
292
118
|
export async function reconcilePersistentPolicyLocks(options) {
|
|
293
|
-
const
|
|
294
|
-
let state = normalizeWalletStateRecord(options.state);
|
|
295
|
-
let changed = state !== options.state;
|
|
296
|
-
const fixedInputKeys = new Set((options.fixedInputs ?? []).map((outpoint) => outpointKey(outpoint)));
|
|
297
|
-
const temporarilyUnlockedKeys = new Set((options.temporarilyUnlockedOutpoints ?? []).map((outpoint) => outpointKey(outpoint)));
|
|
298
|
-
if (options.cleanupInactiveTemporaryBuilderLocks === true) {
|
|
299
|
-
const cleaned = collectInactiveTemporaryBuilderLockCleanup(state);
|
|
300
|
-
state = cleaned.state;
|
|
301
|
-
changed ||= cleaned.changed;
|
|
302
|
-
if (cleaned.staleOutpoints.length > 0) {
|
|
303
|
-
await options.rpc.lockUnspent(options.walletName, true, cleaned.staleOutpoints).catch(() => undefined);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
const lockedBeforeReserveInspection = await options.rpc.listLockUnspent(options.walletName).catch(() => []);
|
|
307
|
-
const lockedBeforeReserveInspectionKeys = new Set(lockedBeforeReserveInspection.map((outpoint) => outpointKey(outpoint)));
|
|
308
|
-
const reserveInspectionUnlocks = rawReserveOutpoints.filter((outpoint) => {
|
|
309
|
-
const key = outpointKey(outpoint);
|
|
310
|
-
return lockedBeforeReserveInspectionKeys.has(key) && !fixedInputKeys.has(key);
|
|
311
|
-
});
|
|
312
|
-
if (reserveInspectionUnlocks.length > 0) {
|
|
313
|
-
await options.rpc.lockUnspent(options.walletName, true, reserveInspectionUnlocks).catch(() => undefined);
|
|
314
|
-
}
|
|
315
|
-
const spendableUtxos = reserveInspectionUnlocks.length > 0 || options.spendableUtxos === undefined
|
|
316
|
-
? await options.rpc.listUnspent(options.walletName, 0).catch(() => [])
|
|
317
|
-
: options.spendableUtxos;
|
|
318
|
-
const previouslyProtectedUniverse = collectPersistentPolicyLockedOutpoints(state, spendableUtxos);
|
|
319
|
-
const reserveSynced = syncStateWithComputedReserve(state, spendableUtxos);
|
|
320
|
-
state = reserveSynced.state;
|
|
321
|
-
changed ||= reserveSynced.changed;
|
|
322
|
-
const protectedUniverse = collectPersistentPolicyLockedOutpoints(state, spendableUtxos);
|
|
323
|
-
if (protectedUniverse.length === 0 && previouslyProtectedUniverse.length === 0) {
|
|
324
|
-
return {
|
|
325
|
-
state,
|
|
326
|
-
changed,
|
|
327
|
-
spendableUtxos,
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
const protectedUniverseKeys = new Set(protectedUniverse.map((outpoint) => outpointKey(outpoint)));
|
|
331
|
-
const previouslyProtectedUniverseKeys = new Set(previouslyProtectedUniverse.map((outpoint) => outpointKey(outpoint)));
|
|
332
|
-
const managedProtectedKeys = new Set([
|
|
333
|
-
...protectedUniverseKeys,
|
|
334
|
-
...previouslyProtectedUniverseKeys,
|
|
335
|
-
]);
|
|
336
|
-
const locked = await options.rpc.listLockUnspent(options.walletName).catch(() => []);
|
|
337
|
-
const spendableKeys = new Set(spendableUtxos.map((entry) => outpointKey(entry)));
|
|
338
|
-
const lockedKeys = new Set(locked.map((outpoint) => outpointKey(outpoint)));
|
|
339
|
-
const expectedLocked = protectedUniverse.filter((outpoint) => {
|
|
340
|
-
const key = outpointKey(outpoint);
|
|
341
|
-
return (spendableKeys.has(key) || lockedKeys.has(key))
|
|
342
|
-
&& !fixedInputKeys.has(key)
|
|
343
|
-
&& !temporarilyUnlockedKeys.has(key);
|
|
344
|
-
});
|
|
345
|
-
const expectedLockedKeys = new Set(expectedLocked.map((outpoint) => outpointKey(outpoint)));
|
|
346
|
-
const lockedManaged = locked.filter((outpoint) => managedProtectedKeys.has(outpointKey(outpoint)));
|
|
347
|
-
const staleLocked = lockedManaged.filter((outpoint) => !expectedLockedKeys.has(outpointKey(outpoint)));
|
|
348
|
-
const missingLocked = protectedUniverse.filter((outpoint) => {
|
|
349
|
-
const key = outpointKey(outpoint);
|
|
350
|
-
return spendableKeys.has(key)
|
|
351
|
-
&& !fixedInputKeys.has(key)
|
|
352
|
-
&& !temporarilyUnlockedKeys.has(key)
|
|
353
|
-
&& !lockedKeys.has(key);
|
|
354
|
-
});
|
|
355
|
-
if (staleLocked.length > 0) {
|
|
356
|
-
await options.rpc.lockUnspent(options.walletName, true, staleLocked).catch(() => undefined);
|
|
357
|
-
}
|
|
358
|
-
if (missingLocked.length > 0) {
|
|
359
|
-
await options.rpc.lockUnspent(options.walletName, false, missingLocked).catch(() => undefined);
|
|
360
|
-
}
|
|
119
|
+
const state = normalizeWalletStateRecord(options.state);
|
|
361
120
|
return {
|
|
362
121
|
state,
|
|
363
|
-
changed,
|
|
364
|
-
spendableUtxos,
|
|
122
|
+
changed: state !== options.state,
|
|
123
|
+
spendableUtxos: options.spendableUtxos ?? await options.rpc.listUnspent(options.walletName, 0).catch(() => []),
|
|
365
124
|
};
|
|
366
125
|
}
|
|
367
126
|
export async function persistWalletCoinControlStateIfNeeded(options) {
|
|
@@ -369,12 +128,10 @@ export async function persistWalletCoinControlStateIfNeeded(options) {
|
|
|
369
128
|
rpc: options.rpc,
|
|
370
129
|
walletName: options.state.managedCoreWallet.walletName,
|
|
371
130
|
state: options.state,
|
|
372
|
-
cleanupInactiveTemporaryBuilderLocks: options.cleanupInactiveTemporaryBuilderLocks ?? true,
|
|
373
131
|
});
|
|
374
132
|
if (!reconciled.changed) {
|
|
375
133
|
return {
|
|
376
134
|
changed: false,
|
|
377
|
-
session: options.session ?? null,
|
|
378
135
|
state: reconciled.state,
|
|
379
136
|
};
|
|
380
137
|
}
|
|
@@ -385,22 +142,8 @@ export async function persistWalletCoinControlStateIfNeeded(options) {
|
|
|
385
142
|
nowUnixMs: options.nowUnixMs,
|
|
386
143
|
replacePrimary: options.replacePrimary,
|
|
387
144
|
});
|
|
388
|
-
if (options.session == null) {
|
|
389
|
-
return {
|
|
390
|
-
changed: true,
|
|
391
|
-
session: null,
|
|
392
|
-
state: nextState,
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
const nextSession = {
|
|
396
|
-
...options.session,
|
|
397
|
-
walletRootId: nextState.walletRootId,
|
|
398
|
-
sourceStateRevision: nextState.stateRevision,
|
|
399
|
-
};
|
|
400
|
-
await saveUnlockSession(options.paths.walletUnlockSessionPath, nextSession, options.access);
|
|
401
145
|
return {
|
|
402
146
|
changed: true,
|
|
403
|
-
session: nextSession,
|
|
404
147
|
state: nextState,
|
|
405
148
|
};
|
|
406
149
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type WalletStateSaveAccess } from "./state/storage.js";
|
|
2
2
|
import type { WalletRuntimePaths } from "./runtime.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { WalletStateV1 } from "./types.js";
|
|
4
4
|
export interface WalletDescriptorInfoRpc {
|
|
5
5
|
getDescriptorInfo(descriptor: string): Promise<{
|
|
6
6
|
descriptor: string;
|
|
@@ -30,13 +30,11 @@ export declare function persistWalletStateUpdate(options: {
|
|
|
30
30
|
export declare function persistNormalizedWalletDescriptorStateIfNeeded(options: {
|
|
31
31
|
state: WalletStateV1;
|
|
32
32
|
access: WalletStateSaveAccess;
|
|
33
|
-
session?: UnlockSessionStateV1 | null;
|
|
34
33
|
paths: WalletRuntimePaths;
|
|
35
34
|
nowUnixMs: number;
|
|
36
35
|
replacePrimary?: boolean;
|
|
37
36
|
rpc: WalletDescriptorInfoRpc;
|
|
38
37
|
}): Promise<{
|
|
39
38
|
changed: boolean;
|
|
40
|
-
session: UnlockSessionStateV1 | null;
|
|
41
39
|
state: WalletStateV1;
|
|
42
40
|
}>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { rm } from "node:fs/promises";
|
|
2
2
|
import { deriveWalletMaterialFromMnemonic } from "./material.js";
|
|
3
|
-
import { saveUnlockSession } from "./state/session.js";
|
|
4
3
|
import { saveWalletState } from "./state/storage.js";
|
|
5
4
|
export function stripDescriptorChecksum(descriptor) {
|
|
6
5
|
return descriptor.replace(/#[A-Za-z0-9]+$/, "");
|
|
@@ -76,7 +75,6 @@ export async function persistNormalizedWalletDescriptorStateIfNeeded(options) {
|
|
|
76
75
|
if (!normalized.changed) {
|
|
77
76
|
return {
|
|
78
77
|
changed: false,
|
|
79
|
-
session: options.session ?? null,
|
|
80
78
|
state: options.state,
|
|
81
79
|
};
|
|
82
80
|
}
|
|
@@ -87,22 +85,8 @@ export async function persistNormalizedWalletDescriptorStateIfNeeded(options) {
|
|
|
87
85
|
nowUnixMs: options.nowUnixMs,
|
|
88
86
|
replacePrimary: options.replacePrimary,
|
|
89
87
|
});
|
|
90
|
-
if (options.session === undefined || options.session === null) {
|
|
91
|
-
return {
|
|
92
|
-
changed: true,
|
|
93
|
-
session: options.session ?? null,
|
|
94
|
-
state: nextState,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
const nextSession = {
|
|
98
|
-
...options.session,
|
|
99
|
-
walletRootId: nextState.walletRootId,
|
|
100
|
-
sourceStateRevision: nextState.stateRevision,
|
|
101
|
-
};
|
|
102
|
-
await saveUnlockSession(options.paths.walletUnlockSessionPath, nextSession, options.access);
|
|
103
88
|
return {
|
|
104
89
|
changed: true,
|
|
105
|
-
session: nextSession,
|
|
106
90
|
state: nextState,
|
|
107
91
|
};
|
|
108
92
|
}
|