@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
|
@@ -8,7 +8,7 @@ import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
|
8
8
|
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
9
9
|
import { serializeRepCommit, serializeRepRevoke, validateDomainName, } from "../cogop/index.js";
|
|
10
10
|
import { openWalletReadContext } from "../read/index.js";
|
|
11
|
-
import { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransactionWithReserveFallback, formatCogAmount, isAlreadyAcceptedError, isBroadcastUnknownError, outpointKey, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
11
|
+
import { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransactionWithReserveFallback, createBuiltWalletMutationFeeSummary, createFundingMutationSender, createWalletMutationFeeMetadata, formatCogAmount, getDecodedInputScriptPubKeyHex, isLocalWalletScript, isAlreadyAcceptedError, isBroadcastUnknownError, mergeFixedWalletInputs, outpointKey, pauseMiningForWalletMutation, resolvePendingMutationReuseDecision, resolveWalletMutationFeeSelection, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
12
12
|
import { confirmTypedAcknowledgement as confirmSharedTypedAcknowledgement, confirmYesNo as confirmSharedYesNo, } from "./confirm.js";
|
|
13
13
|
import { getCanonicalIdentitySelector } from "./identity-selector.js";
|
|
14
14
|
import { findPendingMutationByIntent, upsertPendingMutation } from "./journal.js";
|
|
@@ -93,17 +93,6 @@ function describeReputationReview(review) {
|
|
|
93
93
|
}
|
|
94
94
|
return `included (${review.byteLength} bytes)`;
|
|
95
95
|
}
|
|
96
|
-
function resolveAnchorOutpointForSender(state, sender, errorPrefix) {
|
|
97
|
-
const anchoredDomain = state.domains.find((domain) => domain.currentOwnerLocalIndex === sender.index
|
|
98
|
-
&& domain.canonicalChainStatus === "anchored") ?? null;
|
|
99
|
-
if (anchoredDomain?.currentCanonicalAnchorOutpoint === null || anchoredDomain === null) {
|
|
100
|
-
throw new Error(`${errorPrefix}_anchor_outpoint_unavailable`);
|
|
101
|
-
}
|
|
102
|
-
return {
|
|
103
|
-
txid: anchoredDomain.currentCanonicalAnchorOutpoint.txid,
|
|
104
|
-
vout: anchoredDomain.currentCanonicalAnchorOutpoint.vout,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
96
|
function resolveReputationOperation(context, sourceDomainName, targetDomainName, errorPrefix) {
|
|
108
97
|
assertWalletMutationContextReady(context, errorPrefix);
|
|
109
98
|
const sourceDomain = lookupDomain(context.snapshot.state, sourceDomainName);
|
|
@@ -121,24 +110,14 @@ function resolveReputationOperation(context, sourceDomainName, targetDomainName,
|
|
|
121
110
|
throw new Error(`${errorPrefix}_target_domain_not_anchored`);
|
|
122
111
|
}
|
|
123
112
|
const ownerHex = Buffer.from(sourceDomain.ownerScriptPubKey).toString("hex");
|
|
124
|
-
|
|
125
|
-
if (ownerIdentity === null || ownerIdentity.address === null) {
|
|
113
|
+
if (ownerHex !== context.localState.state.funding.scriptPubKeyHex || context.model.walletAddress == null) {
|
|
126
114
|
throw new Error(`${errorPrefix}_source_owner_not_locally_controlled`);
|
|
127
115
|
}
|
|
128
|
-
if (ownerIdentity.readOnly) {
|
|
129
|
-
throw new Error(`${errorPrefix}_source_owner_read_only`);
|
|
130
|
-
}
|
|
131
116
|
return {
|
|
132
117
|
readContext: context,
|
|
133
118
|
state: context.localState.state,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
localIndex: ownerIdentity.index,
|
|
137
|
-
scriptPubKeyHex: ownerIdentity.scriptPubKeyHex,
|
|
138
|
-
address: ownerIdentity.address,
|
|
139
|
-
},
|
|
140
|
-
senderSelector: getCanonicalIdentitySelector(ownerIdentity),
|
|
141
|
-
anchorOutpoint: resolveAnchorOutpointForSender(context.localState.state, ownerIdentity, errorPrefix),
|
|
119
|
+
sender: createFundingMutationSender(context.localState.state),
|
|
120
|
+
senderSelector: context.model.walletAddress,
|
|
142
121
|
sourceDomain,
|
|
143
122
|
targetDomain,
|
|
144
123
|
availableBalanceCogtoshi: getBalance(context.snapshot.state, sourceDomain.ownerScriptPubKey),
|
|
@@ -150,29 +129,13 @@ function buildPlanForReputationOperation(options) {
|
|
|
150
129
|
&& entry.confirmations >= 1
|
|
151
130
|
&& entry.spendable !== false
|
|
152
131
|
&& entry.safe !== false);
|
|
153
|
-
const anchorUtxo = options.allUtxos.find((entry) => entry.txid === options.anchorOutpoint.txid
|
|
154
|
-
&& entry.vout === options.anchorOutpoint.vout
|
|
155
|
-
&& entry.scriptPubKey === options.sender.scriptPubKeyHex
|
|
156
|
-
&& entry.confirmations >= 1
|
|
157
|
-
&& entry.spendable !== false
|
|
158
|
-
&& entry.safe !== false);
|
|
159
|
-
if (anchorUtxo === undefined) {
|
|
160
|
-
throw new Error(`${options.errorPrefix}_anchor_utxo_missing`);
|
|
161
|
-
}
|
|
162
132
|
return {
|
|
163
133
|
sender: options.sender,
|
|
164
134
|
changeAddress: options.state.funding.address,
|
|
165
|
-
fixedInputs: [
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
outputs: [
|
|
169
|
-
{ data: Buffer.from(options.opReturnData).toString("hex") },
|
|
170
|
-
{ [options.sender.address]: satsToBtcNumber(BigInt(options.state.anchorValueSats)) },
|
|
171
|
-
],
|
|
172
|
-
changePosition: 2,
|
|
135
|
+
fixedInputs: [],
|
|
136
|
+
outputs: [{ data: Buffer.from(options.opReturnData).toString("hex") }],
|
|
137
|
+
changePosition: 1,
|
|
173
138
|
expectedOpReturnScriptHex: encodeOpReturnScript(options.opReturnData),
|
|
174
|
-
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
175
|
-
expectedAnchorValueSats: BigInt(options.state.anchorValueSats),
|
|
176
139
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
177
140
|
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
178
141
|
errorPrefix: options.errorPrefix,
|
|
@@ -184,33 +147,16 @@ function validateFundedDraft(decoded, funded, plan) {
|
|
|
184
147
|
if (inputs.length === 0) {
|
|
185
148
|
throw new Error(`${plan.errorPrefix}_missing_sender_input`);
|
|
186
149
|
}
|
|
187
|
-
assertFixedInputPrefixMatches(inputs, plan.fixedInputs, `${plan.errorPrefix}_sender_input_mismatch`);
|
|
188
|
-
if (inputs[0]?.prevout?.scriptPubKey?.hex !== plan.sender.scriptPubKeyHex) {
|
|
189
|
-
throw new Error(`${plan.errorPrefix}_sender_input_mismatch`);
|
|
190
|
-
}
|
|
191
|
-
assertFundingInputsAfterFixedPrefix({
|
|
192
|
-
inputs,
|
|
193
|
-
fixedInputs: plan.fixedInputs,
|
|
194
|
-
allowedFundingScriptPubKeyHex: plan.allowedFundingScriptPubKeyHex,
|
|
195
|
-
eligibleFundingOutpointKeys: plan.eligibleFundingOutpointKeys,
|
|
196
|
-
errorCode: `${plan.errorPrefix}_unexpected_funding_input`,
|
|
197
|
-
});
|
|
198
150
|
if (outputs[0]?.scriptPubKey?.hex !== plan.expectedOpReturnScriptHex) {
|
|
199
151
|
throw new Error(`${plan.errorPrefix}_opreturn_mismatch`);
|
|
200
152
|
}
|
|
201
|
-
if (outputs[1]?.scriptPubKey?.hex !== plan.expectedAnchorScriptHex) {
|
|
202
|
-
throw new Error(`${plan.errorPrefix}_anchor_output_mismatch`);
|
|
203
|
-
}
|
|
204
|
-
if (valueToSats(outputs[1]?.value ?? 0) !== plan.expectedAnchorValueSats) {
|
|
205
|
-
throw new Error(`${plan.errorPrefix}_anchor_value_mismatch`);
|
|
206
|
-
}
|
|
207
153
|
if (funded.changepos === -1) {
|
|
208
|
-
if (outputs.length !==
|
|
154
|
+
if (outputs.length !== 1) {
|
|
209
155
|
throw new Error(`${plan.errorPrefix}_unexpected_output_count`);
|
|
210
156
|
}
|
|
211
157
|
return;
|
|
212
158
|
}
|
|
213
|
-
if (funded.changepos !== plan.changePosition || outputs.length !==
|
|
159
|
+
if (funded.changepos !== plan.changePosition || outputs.length !== 2) {
|
|
214
160
|
throw new Error(`${plan.errorPrefix}_change_position_mismatch`);
|
|
215
161
|
}
|
|
216
162
|
if (outputs[funded.changepos]?.scriptPubKey?.hex !== plan.allowedFundingScriptPubKeyHex) {
|
|
@@ -226,7 +172,7 @@ async function buildTransaction(options) {
|
|
|
226
172
|
validateFundedDraft,
|
|
227
173
|
finalizeErrorCode: `${options.plan.errorPrefix}_finalize_failed`,
|
|
228
174
|
mempoolRejectPrefix: `${options.plan.errorPrefix}_mempool_rejected`,
|
|
229
|
-
|
|
175
|
+
feeRate: options.feeRateSatVb,
|
|
230
176
|
});
|
|
231
177
|
}
|
|
232
178
|
function createDraftMutation(options) {
|
|
@@ -244,6 +190,7 @@ function createDraftMutation(options) {
|
|
|
244
190
|
lastUpdatedAtUnixMs: options.nowUnixMs,
|
|
245
191
|
attemptedTxid: null,
|
|
246
192
|
attemptedWtxid: null,
|
|
193
|
+
...createWalletMutationFeeMetadata(options.feeSelection),
|
|
247
194
|
temporaryBuilderLockedOutpoints: [],
|
|
248
195
|
};
|
|
249
196
|
}
|
|
@@ -263,6 +210,7 @@ function createDraftMutation(options) {
|
|
|
263
210
|
lastUpdatedAtUnixMs: options.nowUnixMs,
|
|
264
211
|
attemptedTxid: null,
|
|
265
212
|
attemptedWtxid: null,
|
|
213
|
+
...createWalletMutationFeeMetadata(options.feeSelection),
|
|
266
214
|
temporaryBuilderLockedOutpoints: [],
|
|
267
215
|
};
|
|
268
216
|
}
|
|
@@ -275,7 +223,6 @@ async function saveUpdatedMutationState(options) {
|
|
|
275
223
|
await saveWalletStatePreservingUnlock({
|
|
276
224
|
state: nextState,
|
|
277
225
|
provider: options.provider,
|
|
278
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
279
226
|
nowUnixMs: options.nowUnixMs,
|
|
280
227
|
paths: options.paths,
|
|
281
228
|
});
|
|
@@ -322,7 +269,6 @@ async function reconcilePendingReputationMutation(options) {
|
|
|
322
269
|
nextState = await saveUpdatedMutationState({
|
|
323
270
|
state: nextState,
|
|
324
271
|
provider: options.provider,
|
|
325
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
326
272
|
nowUnixMs: options.nowUnixMs,
|
|
327
273
|
paths: options.paths,
|
|
328
274
|
});
|
|
@@ -341,7 +287,6 @@ async function reconcilePendingReputationMutation(options) {
|
|
|
341
287
|
nextState = await saveUpdatedMutationState({
|
|
342
288
|
state: nextState,
|
|
343
289
|
provider: options.provider,
|
|
344
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
345
290
|
nowUnixMs: options.nowUnixMs,
|
|
346
291
|
paths: options.paths,
|
|
347
292
|
});
|
|
@@ -358,7 +303,6 @@ async function reconcilePendingReputationMutation(options) {
|
|
|
358
303
|
nextState = await saveUpdatedMutationState({
|
|
359
304
|
state: nextState,
|
|
360
305
|
provider: options.provider,
|
|
361
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
362
306
|
nowUnixMs: options.nowUnixMs,
|
|
363
307
|
paths: options.paths,
|
|
364
308
|
});
|
|
@@ -448,7 +392,6 @@ async function sendBuiltTransaction(options) {
|
|
|
448
392
|
nextState = await saveUpdatedMutationState({
|
|
449
393
|
state: nextState,
|
|
450
394
|
provider: options.provider,
|
|
451
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
452
395
|
nowUnixMs: options.nowUnixMs,
|
|
453
396
|
paths: options.paths,
|
|
454
397
|
});
|
|
@@ -471,7 +414,6 @@ async function sendBuiltTransaction(options) {
|
|
|
471
414
|
nextState = await saveUpdatedMutationState({
|
|
472
415
|
state: nextState,
|
|
473
416
|
provider: options.provider,
|
|
474
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
475
417
|
nowUnixMs: options.nowUnixMs,
|
|
476
418
|
paths: options.paths,
|
|
477
419
|
});
|
|
@@ -487,7 +429,6 @@ async function sendBuiltTransaction(options) {
|
|
|
487
429
|
nextState = await saveUpdatedMutationState({
|
|
488
430
|
state: nextState,
|
|
489
431
|
provider: options.provider,
|
|
490
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
491
432
|
nowUnixMs: options.nowUnixMs,
|
|
492
433
|
paths: options.paths,
|
|
493
434
|
});
|
|
@@ -504,7 +445,6 @@ async function sendBuiltTransaction(options) {
|
|
|
504
445
|
nextState = await saveUpdatedMutationState({
|
|
505
446
|
state: nextState,
|
|
506
447
|
provider: options.provider,
|
|
507
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
508
448
|
nowUnixMs: options.nowUnixMs,
|
|
509
449
|
paths: options.paths,
|
|
510
450
|
});
|
|
@@ -577,31 +517,47 @@ async function submitReputationMutation(options) {
|
|
|
577
517
|
});
|
|
578
518
|
const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
|
|
579
519
|
const walletName = operation.state.managedCoreWallet.walletName;
|
|
520
|
+
const feeSelection = await resolveWalletMutationFeeSelection({
|
|
521
|
+
rpc,
|
|
522
|
+
feeRateSatVb: options.feeRateSatVb ?? null,
|
|
523
|
+
});
|
|
580
524
|
const existingMutation = findPendingMutationByIntent(operation.state, intentFingerprintHex);
|
|
525
|
+
let workingState = operation.state;
|
|
526
|
+
let replacementFixedInputs = null;
|
|
581
527
|
if (existingMutation !== null) {
|
|
582
528
|
const reconciled = await reconcilePendingReputationMutation({
|
|
583
529
|
state: operation.state,
|
|
584
530
|
mutation: existingMutation,
|
|
585
531
|
provider,
|
|
586
|
-
unlockUntilUnixMs: operation.unlockUntilUnixMs,
|
|
587
532
|
nowUnixMs,
|
|
588
533
|
paths,
|
|
589
534
|
rpc,
|
|
590
535
|
walletName,
|
|
591
536
|
context: readContext,
|
|
592
537
|
});
|
|
538
|
+
workingState = reconciled.state;
|
|
593
539
|
if (reconciled.resolution === "confirmed" || reconciled.resolution === "live") {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
540
|
+
const reuse = await resolvePendingMutationReuseDecision({
|
|
541
|
+
rpc,
|
|
542
|
+
walletName,
|
|
543
|
+
mutation: reconciled.mutation,
|
|
544
|
+
nextFeeSelection: feeSelection,
|
|
545
|
+
});
|
|
546
|
+
if (reuse.reuseExisting) {
|
|
547
|
+
return {
|
|
548
|
+
kind: options.kind === "rep-give" ? "give" : "revoke",
|
|
549
|
+
sourceDomainName: normalizedSourceDomainName,
|
|
550
|
+
targetDomainName: normalizedTargetDomainName,
|
|
551
|
+
amountCogtoshi: options.amountCogtoshi,
|
|
552
|
+
txid: reconciled.mutation.attemptedTxid ?? "unknown",
|
|
553
|
+
status: reconciled.resolution,
|
|
554
|
+
reusedExisting: true,
|
|
555
|
+
reviewIncluded: review.payloadHex !== null,
|
|
556
|
+
resolved,
|
|
557
|
+
fees: reuse.fees,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
replacementFixedInputs = reuse.replacementFixedInputs;
|
|
605
561
|
}
|
|
606
562
|
if (reconciled.resolution === "repair-required") {
|
|
607
563
|
throw new Error(`${options.errorPrefix}_repair_required`);
|
|
@@ -616,7 +572,7 @@ async function submitReputationMutation(options) {
|
|
|
616
572
|
resolved,
|
|
617
573
|
assumeYes: options.assumeYes,
|
|
618
574
|
});
|
|
619
|
-
let nextState = upsertPendingMutation(
|
|
575
|
+
let nextState = upsertPendingMutation(workingState, createDraftMutation({
|
|
620
576
|
kind: options.kind,
|
|
621
577
|
sourceDomainName: normalizedSourceDomainName,
|
|
622
578
|
targetDomainName: normalizedTargetDomainName,
|
|
@@ -625,30 +581,34 @@ async function submitReputationMutation(options) {
|
|
|
625
581
|
intentFingerprintHex,
|
|
626
582
|
nowUnixMs,
|
|
627
583
|
reviewPayloadHex: review.payloadHex,
|
|
584
|
+
feeSelection,
|
|
628
585
|
existing: existingMutation,
|
|
629
586
|
}));
|
|
630
587
|
nextState = await saveUpdatedMutationState({
|
|
631
588
|
state: nextState,
|
|
632
589
|
provider,
|
|
633
|
-
unlockUntilUnixMs: operation.unlockUntilUnixMs,
|
|
634
590
|
nowUnixMs,
|
|
635
591
|
paths,
|
|
636
592
|
});
|
|
637
593
|
const opReturnData = options.kind === "rep-give"
|
|
638
594
|
? serializeRepCommit(operation.sourceDomain.domainId, operation.targetDomain.domainId, options.amountCogtoshi, review.payload).opReturnData
|
|
639
595
|
: serializeRepRevoke(operation.sourceDomain.domainId, operation.targetDomain.domainId, options.amountCogtoshi, review.payload).opReturnData;
|
|
596
|
+
const reputationPlan = buildPlanForReputationOperation({
|
|
597
|
+
state: nextState,
|
|
598
|
+
allUtxos: await rpc.listUnspent(walletName, 1),
|
|
599
|
+
sender: operation.sender,
|
|
600
|
+
opReturnData,
|
|
601
|
+
errorPrefix: options.errorPrefix,
|
|
602
|
+
});
|
|
640
603
|
const built = await buildTransaction({
|
|
641
604
|
rpc,
|
|
642
605
|
walletName,
|
|
643
606
|
state: nextState,
|
|
644
|
-
plan:
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
opReturnData,
|
|
650
|
-
errorPrefix: options.errorPrefix,
|
|
651
|
-
}),
|
|
607
|
+
plan: {
|
|
608
|
+
...reputationPlan,
|
|
609
|
+
fixedInputs: mergeFixedWalletInputs(reputationPlan.fixedInputs, replacementFixedInputs),
|
|
610
|
+
},
|
|
611
|
+
feeRateSatVb: feeSelection.feeRateSatVb,
|
|
652
612
|
});
|
|
653
613
|
const final = await sendBuiltTransaction({
|
|
654
614
|
rpc,
|
|
@@ -658,7 +618,6 @@ async function submitReputationMutation(options) {
|
|
|
658
618
|
mutation: nextState.pendingMutations.find((mutation) => mutation.intentFingerprintHex === intentFingerprintHex),
|
|
659
619
|
state: nextState,
|
|
660
620
|
provider,
|
|
661
|
-
unlockUntilUnixMs: operation.unlockUntilUnixMs,
|
|
662
621
|
nowUnixMs,
|
|
663
622
|
paths,
|
|
664
623
|
errorPrefix: options.errorPrefix,
|
|
@@ -673,6 +632,10 @@ async function submitReputationMutation(options) {
|
|
|
673
632
|
reusedExisting: false,
|
|
674
633
|
reviewIncluded: review.payloadHex !== null,
|
|
675
634
|
resolved,
|
|
635
|
+
fees: createBuiltWalletMutationFeeSummary({
|
|
636
|
+
selection: feeSelection,
|
|
637
|
+
built,
|
|
638
|
+
}),
|
|
676
639
|
};
|
|
677
640
|
}
|
|
678
641
|
finally {
|
package/dist/wallet/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface OutpointRecord {
|
|
|
8
8
|
export type PendingMutationStatus = "draft" | "broadcasting" | "broadcast-unknown" | "live" | "confirmed" | "canceled" | "repair-required";
|
|
9
9
|
export interface PendingMutationRecord {
|
|
10
10
|
mutationId: string;
|
|
11
|
-
kind: "register" | "transfer" | "sell" | "buy" | "rep-give" | "rep-revoke" | "send" | "lock" | "claim" | "field-create" | "field-set" | "field-clear" | "endpoint" | "delegate" | "miner" | "canonical";
|
|
11
|
+
kind: "anchor" | "register" | "transfer" | "sell" | "buy" | "rep-give" | "rep-revoke" | "send" | "lock" | "claim" | "field-create" | "field-set" | "field-clear" | "endpoint" | "delegate" | "miner" | "canonical";
|
|
12
12
|
registerKind?: "root" | "subdomain";
|
|
13
13
|
domainName: string;
|
|
14
14
|
parentDomainName: string | null;
|
|
@@ -35,6 +35,8 @@ export interface PendingMutationRecord {
|
|
|
35
35
|
lastUpdatedAtUnixMs: number;
|
|
36
36
|
attemptedTxid: string | null;
|
|
37
37
|
attemptedWtxid: string | null;
|
|
38
|
+
selectedFeeRateSatVb?: number | null;
|
|
39
|
+
feeSelectionSource?: "custom-satvb" | "estimated-next-block-plus-one" | "fallback-default" | null;
|
|
38
40
|
temporaryBuilderLockedOutpoints: OutpointRecord[];
|
|
39
41
|
}
|
|
40
42
|
export interface LocalIdentityRecord {
|
|
@@ -47,30 +49,11 @@ export interface LocalIdentityRecord {
|
|
|
47
49
|
export interface DomainRecord {
|
|
48
50
|
name: string;
|
|
49
51
|
domainId: number | null;
|
|
50
|
-
dedicatedIndex: number | null;
|
|
51
52
|
currentOwnerScriptPubKeyHex: ScriptPubKeyHex | null;
|
|
52
|
-
currentOwnerLocalIndex: number | null;
|
|
53
53
|
canonicalChainStatus: "unknown" | "registered-unanchored" | "anchored";
|
|
54
|
-
localAnchorIntent: "none" | "reserved" | "tx1-live" | "tx2-live" | "repair-required";
|
|
55
|
-
currentCanonicalAnchorOutpoint: {
|
|
56
|
-
txid: string;
|
|
57
|
-
vout: number;
|
|
58
|
-
valueSats: number;
|
|
59
|
-
} | null;
|
|
60
54
|
foundingMessageText: string | null;
|
|
61
55
|
birthTime: number | null;
|
|
62
56
|
}
|
|
63
|
-
export interface HookClientStateRecord {
|
|
64
|
-
mode: "builtin" | "custom" | "disabled";
|
|
65
|
-
validationState: "unknown" | "validated" | "stale" | "failed" | "never" | "current";
|
|
66
|
-
lastValidationAtUnixMs: number | null;
|
|
67
|
-
lastValidationError: string | null;
|
|
68
|
-
validatedLaunchFingerprint: string | null;
|
|
69
|
-
validatedFullFingerprint: string | null;
|
|
70
|
-
fullTrustWarningAcknowledgedAtUnixMs: number | null;
|
|
71
|
-
consecutiveFailureCount: number;
|
|
72
|
-
cooldownUntilUnixMs: number | null;
|
|
73
|
-
}
|
|
74
57
|
export interface MiningStateRecord {
|
|
75
58
|
runMode: "stopped" | "foreground" | "background";
|
|
76
59
|
state: "idle" | "live" | "paused" | "paused-stale" | "repair-required";
|
|
@@ -92,7 +75,7 @@ export interface MiningStateRecord {
|
|
|
92
75
|
currentBlockTargetHeight: number | null;
|
|
93
76
|
currentReferencedBlockHashDisplay: string | null;
|
|
94
77
|
currentIntentFingerprintHex: string | null;
|
|
95
|
-
|
|
78
|
+
livePublishInMempool: boolean | null;
|
|
96
79
|
currentPublishDecision: string | null;
|
|
97
80
|
replacementCount: number;
|
|
98
81
|
currentBlockFeeSpentSats: string;
|
|
@@ -103,49 +86,13 @@ export interface MiningStateRecord {
|
|
|
103
86
|
vout: number;
|
|
104
87
|
} | null;
|
|
105
88
|
}
|
|
106
|
-
export interface ProactiveFamilyTransactionRecord {
|
|
107
|
-
status: "draft" | "broadcasting" | "broadcast-unknown" | "live" | "confirmed" | "canceled" | "repair-required";
|
|
108
|
-
attemptedTxid: string | null;
|
|
109
|
-
attemptedWtxid: string | null;
|
|
110
|
-
temporaryBuilderLockedOutpoints: OutpointRecord[];
|
|
111
|
-
rawHex: string | null;
|
|
112
|
-
}
|
|
113
|
-
export interface ProactiveFamilyStateRecord {
|
|
114
|
-
familyId: string;
|
|
115
|
-
type: "anchor" | "field" | string;
|
|
116
|
-
status: "draft" | "broadcasting" | "broadcast-unknown" | "live" | "confirmed" | "canceled" | "repair-required";
|
|
117
|
-
intentFingerprintHex: string;
|
|
118
|
-
createdAtUnixMs: number;
|
|
119
|
-
lastUpdatedAtUnixMs?: number;
|
|
120
|
-
domainName?: string | null;
|
|
121
|
-
domainId?: number | null;
|
|
122
|
-
sourceSenderLocalIndex?: number | null;
|
|
123
|
-
sourceSenderScriptPubKeyHex?: ScriptPubKeyHex | null;
|
|
124
|
-
reservedDedicatedIndex?: number | null;
|
|
125
|
-
reservedScriptPubKeyHex?: ScriptPubKeyHex | null;
|
|
126
|
-
foundingMessageText?: string | null;
|
|
127
|
-
foundingMessagePayloadHex?: string | null;
|
|
128
|
-
listingCancelCommitted?: boolean;
|
|
129
|
-
fieldName?: string | null;
|
|
130
|
-
expectedFieldId?: number | null;
|
|
131
|
-
fieldPermanent?: boolean | null;
|
|
132
|
-
fieldFormat?: number | null;
|
|
133
|
-
fieldValueHex?: string | null;
|
|
134
|
-
currentStep?: "reserved" | "tx1" | "tx2" | null;
|
|
135
|
-
tx1?: ProactiveFamilyTransactionRecord | null;
|
|
136
|
-
tx2?: ProactiveFamilyTransactionRecord | null;
|
|
137
|
-
}
|
|
138
89
|
export interface WalletStateV1 {
|
|
139
|
-
schemaVersion:
|
|
90
|
+
schemaVersion: 5;
|
|
140
91
|
stateRevision: number;
|
|
141
92
|
lastWrittenAtUnixMs: number;
|
|
142
93
|
walletRootId: string;
|
|
143
94
|
network: WalletNetwork;
|
|
144
|
-
|
|
145
|
-
proactiveReserveSats: number;
|
|
146
|
-
proactiveReserveOutpoints: OutpointRecord[];
|
|
147
|
-
nextDedicatedIndex: number;
|
|
148
|
-
fundingIndex: 0;
|
|
95
|
+
localScriptPubKeyHexes?: ScriptPubKeyHex[];
|
|
149
96
|
mnemonic: {
|
|
150
97
|
phrase: string;
|
|
151
98
|
language: WalletMnemonicLanguage;
|
|
@@ -172,69 +119,22 @@ export interface WalletStateV1 {
|
|
|
172
119
|
walletName: string;
|
|
173
120
|
internalPassphrase: string;
|
|
174
121
|
descriptorChecksum: string | null;
|
|
175
|
-
|
|
176
|
-
|
|
122
|
+
walletAddress?: string | null;
|
|
123
|
+
walletScriptPubKeyHex?: ScriptPubKeyHex | null;
|
|
177
124
|
proofStatus: "not-proven" | "ready" | "missing" | "mismatch";
|
|
178
125
|
lastImportedAtUnixMs: number | null;
|
|
179
126
|
lastVerifiedAtUnixMs: number | null;
|
|
180
127
|
};
|
|
181
|
-
identities: LocalIdentityRecord[];
|
|
182
128
|
domains: DomainRecord[];
|
|
183
129
|
miningState: MiningStateRecord;
|
|
184
|
-
hookClientState: {
|
|
185
|
-
mining: HookClientStateRecord;
|
|
186
|
-
};
|
|
187
|
-
proactiveFamilies: ProactiveFamilyStateRecord[];
|
|
188
130
|
pendingMutations?: PendingMutationRecord[];
|
|
189
131
|
}
|
|
190
|
-
export interface PortableWalletArchivePayloadV1 {
|
|
191
|
-
schemaVersion: 1;
|
|
192
|
-
exportedAtUnixMs: number;
|
|
193
|
-
walletRootId: string;
|
|
194
|
-
network: WalletNetwork;
|
|
195
|
-
anchorValueSats: number;
|
|
196
|
-
proactiveReserveSats: number;
|
|
197
|
-
proactiveReserveOutpoints: OutpointRecord[];
|
|
198
|
-
nextDedicatedIndex: number;
|
|
199
|
-
fundingIndex: 0;
|
|
200
|
-
mnemonic: {
|
|
201
|
-
phrase: string;
|
|
202
|
-
language: WalletMnemonicLanguage;
|
|
203
|
-
};
|
|
204
|
-
expected: {
|
|
205
|
-
masterFingerprintHex: string;
|
|
206
|
-
accountPath: string;
|
|
207
|
-
accountXpub: string;
|
|
208
|
-
publicExternalDescriptor: string;
|
|
209
|
-
descriptorChecksum: string | null;
|
|
210
|
-
rangeEnd: number;
|
|
211
|
-
safetyMargin: number;
|
|
212
|
-
fundingAddress0: string;
|
|
213
|
-
fundingScriptPubKeyHex0: ScriptPubKeyHex;
|
|
214
|
-
walletBirthTime: number;
|
|
215
|
-
};
|
|
216
|
-
identities: LocalIdentityRecord[];
|
|
217
|
-
domains: DomainRecord[];
|
|
218
|
-
miningState: MiningStateRecord;
|
|
219
|
-
hookClientState: {
|
|
220
|
-
mining: HookClientStateRecord;
|
|
221
|
-
};
|
|
222
|
-
proactiveFamilies: ProactiveFamilyStateRecord[];
|
|
223
|
-
}
|
|
224
|
-
export interface Argon2EnvelopeParams {
|
|
225
|
-
name: "argon2id";
|
|
226
|
-
memoryKib: number;
|
|
227
|
-
iterations: number;
|
|
228
|
-
parallelism: number;
|
|
229
|
-
salt: string;
|
|
230
|
-
}
|
|
231
132
|
export interface EncryptedEnvelopeV1 {
|
|
232
133
|
format: string;
|
|
233
134
|
version: 1;
|
|
234
135
|
cipher: "aes-256-gcm";
|
|
235
136
|
wrappedBy: string;
|
|
236
137
|
walletRootIdHint?: string | null;
|
|
237
|
-
argon2id?: Argon2EnvelopeParams | null;
|
|
238
138
|
secretProvider?: {
|
|
239
139
|
kind: string;
|
|
240
140
|
keyId: string;
|
|
@@ -243,20 +143,6 @@ export interface EncryptedEnvelopeV1 {
|
|
|
243
143
|
tag: string;
|
|
244
144
|
ciphertext: string;
|
|
245
145
|
}
|
|
246
|
-
export interface UnlockSessionStateV1 {
|
|
247
|
-
schemaVersion: 1;
|
|
248
|
-
walletRootId: string;
|
|
249
|
-
sessionId: string;
|
|
250
|
-
createdAtUnixMs: number;
|
|
251
|
-
unlockUntilUnixMs: number;
|
|
252
|
-
sourceStateRevision: number;
|
|
253
|
-
wrappedSessionKeyMaterial: string;
|
|
254
|
-
}
|
|
255
|
-
export interface WalletExplicitLockStateV1 {
|
|
256
|
-
schemaVersion: 1;
|
|
257
|
-
walletRootId: string;
|
|
258
|
-
lockedAtUnixMs: number;
|
|
259
|
-
}
|
|
260
146
|
export interface WalletPendingInitializationStateV1 {
|
|
261
147
|
schemaVersion: 1;
|
|
262
148
|
createdAtUnixMs: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cogcoin/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Store-backed Cogcoin client with wallet flows, SQLite persistence, and managed Bitcoin Core integration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -56,21 +56,21 @@
|
|
|
56
56
|
"dist"
|
|
57
57
|
],
|
|
58
58
|
"scripts": {
|
|
59
|
-
"build": "rm -rf dist && node ./node_modules/typescript/bin/tsc -p tsconfig.json && node
|
|
59
|
+
"build": "rm -rf dist && node ./node_modules/typescript/bin/tsc -p tsconfig.json && node ./scripts/copy-static-assets.mjs build",
|
|
60
60
|
"generate:default-snapshot-chunk-manifest": "node scripts/generate-default-snapshot-chunk-manifest.mjs",
|
|
61
61
|
"verify:default-snapshot-chunk-manifest": "node scripts/generate-default-snapshot-chunk-manifest.mjs --check",
|
|
62
|
-
"test": "rm -rf .test-dist && node ./node_modules/typescript/bin/tsc -p tsconfig.test.json && node
|
|
62
|
+
"test": "rm -rf .test-dist && node ./node_modules/typescript/bin/tsc -p tsconfig.test.json && node ./scripts/copy-static-assets.mjs test && node --test .test-dist/test/*.test.js"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@cogcoin/bitcoin": "30.2.0",
|
|
66
66
|
"@cogcoin/genesis": "1.0.0",
|
|
67
|
-
"@cogcoin/indexer": "1.0.
|
|
67
|
+
"@cogcoin/indexer": "1.0.1",
|
|
68
68
|
"@cogcoin/scoring": "1.0.0",
|
|
69
|
+
"@noble/hashes": "2.0.1",
|
|
69
70
|
"@scure/base": "^2.0.0",
|
|
70
71
|
"@scure/bip32": "^2.0.1",
|
|
71
72
|
"@scure/bip39": "^2.0.1",
|
|
72
73
|
"better-sqlite3": "12.8.0",
|
|
73
|
-
"hash-wasm": "^4.12.0",
|
|
74
74
|
"zeromq": "6.5.0"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
package/dist/wallet/archive.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { PortableWalletArchivePayloadV1 } from "./types.js";
|
|
2
|
-
export declare const PORTABLE_WALLET_ARCHIVE_FORMAT = "cogcoin-portable-wallet-archive";
|
|
3
|
-
export declare function writePortableWalletArchive(path: string, payload: PortableWalletArchivePayloadV1, passphrase: Uint8Array | string): Promise<void>;
|
|
4
|
-
export declare function readPortableWalletArchive(path: string, passphrase: Uint8Array | string): Promise<PortableWalletArchivePayloadV1>;
|
package/dist/wallet/archive.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { writeJsonFileAtomic } from "./fs/atomic.js";
|
|
3
|
-
import { normalizePortableWalletArchivePayload } from "./coin-control.js";
|
|
4
|
-
import { decryptJsonWithPassphrase, encryptJsonWithPassphrase, } from "./state/crypto.js";
|
|
5
|
-
export const PORTABLE_WALLET_ARCHIVE_FORMAT = "cogcoin-portable-wallet-archive";
|
|
6
|
-
function assertPortableWalletArchivePayload(payload) {
|
|
7
|
-
const normalized = normalizePortableWalletArchivePayload(payload);
|
|
8
|
-
if (normalized.schemaVersion !== 1
|
|
9
|
-
|| normalized.walletRootId.trim() === ""
|
|
10
|
-
|| normalized.mnemonic.phrase.trim() === ""
|
|
11
|
-
|| normalized.expected.accountPath.trim() === ""
|
|
12
|
-
|| normalized.expected.publicExternalDescriptor.trim() === ""
|
|
13
|
-
|| normalized.expected.fundingAddress0.trim() === ""
|
|
14
|
-
|| normalized.expected.fundingScriptPubKeyHex0.trim() === "") {
|
|
15
|
-
throw new Error("wallet_archive_payload_invalid");
|
|
16
|
-
}
|
|
17
|
-
return normalized;
|
|
18
|
-
}
|
|
19
|
-
export async function writePortableWalletArchive(path, payload, passphrase) {
|
|
20
|
-
const envelope = await encryptJsonWithPassphrase(assertPortableWalletArchivePayload(payload), passphrase, {
|
|
21
|
-
format: PORTABLE_WALLET_ARCHIVE_FORMAT,
|
|
22
|
-
});
|
|
23
|
-
await writeJsonFileAtomic(path, envelope, { mode: 0o600 });
|
|
24
|
-
}
|
|
25
|
-
export async function readPortableWalletArchive(path, passphrase) {
|
|
26
|
-
let raw;
|
|
27
|
-
try {
|
|
28
|
-
raw = await readFile(path, "utf8");
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
32
|
-
throw new Error("wallet_import_archive_not_found");
|
|
33
|
-
}
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
|
-
const envelope = JSON.parse(raw);
|
|
37
|
-
if (envelope.format !== PORTABLE_WALLET_ARCHIVE_FORMAT || envelope.version !== 1) {
|
|
38
|
-
throw new Error("wallet_archive_format_invalid");
|
|
39
|
-
}
|
|
40
|
-
return assertPortableWalletArchivePayload(await decryptJsonWithPassphrase(envelope, passphrase));
|
|
41
|
-
}
|