@cogcoin/client 0.5.11 → 0.5.13
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 +3 -1
- package/dist/app-paths.d.ts +1 -0
- package/dist/app-paths.js +3 -0
- package/dist/bitcoind/bootstrap/controller.d.ts +3 -0
- package/dist/bitcoind/bootstrap/controller.js +7 -5
- package/dist/bitcoind/client/factory.d.ts +8 -0
- package/dist/bitcoind/client/factory.js +43 -6
- package/dist/bitcoind/client/managed-client.js +19 -10
- package/dist/bitcoind/client/sync-engine.js +35 -4
- package/dist/bitcoind/progress/formatting.js +1 -1
- package/dist/bitcoind/testing.d.ts +1 -0
- package/dist/bitcoind/testing.js +1 -0
- package/dist/cli/commands/follow.js +47 -14
- package/dist/cli/commands/sync.js +48 -15
- package/dist/cli/context.js +5 -1
- package/dist/cli/output.js +11 -0
- package/dist/cli/runner.js +2 -0
- package/dist/cli/signals.d.ts +1 -1
- package/dist/cli/signals.js +17 -4
- package/dist/cli/types.d.ts +4 -0
- package/dist/cli/update-notifier.d.ts +2 -0
- package/dist/cli/update-notifier.js +276 -0
- package/dist/client/default-client.d.ts +1 -1
- package/dist/client/default-client.js +7 -1
- package/dist/client/factory.js +6 -1
- package/dist/sqlite/store.js +3 -0
- package/dist/types.d.ts +2 -0
- package/dist/wallet/archive.js +10 -8
- package/dist/wallet/coin-control.d.ts +41 -0
- package/dist/wallet/coin-control.js +365 -0
- package/dist/wallet/lifecycle.js +39 -2
- package/dist/wallet/mining/runner.js +46 -44
- package/dist/wallet/read/context.js +15 -6
- package/dist/wallet/reset.js +2 -0
- package/dist/wallet/state/storage.js +5 -4
- package/dist/wallet/tx/anchor.js +36 -51
- package/dist/wallet/tx/cog.js +19 -12
- package/dist/wallet/tx/common.d.ts +41 -10
- package/dist/wallet/tx/common.js +112 -5
- package/dist/wallet/tx/domain-admin.js +13 -8
- package/dist/wallet/tx/domain-market.js +19 -12
- package/dist/wallet/tx/field.js +21 -18
- package/dist/wallet/tx/register.js +17 -12
- package/dist/wallet/tx/reputation.js +13 -8
- package/dist/wallet/types.d.ts +4 -0
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
|
9
9
|
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
10
10
|
import { serializeSetCanonical, serializeSetDelegate, serializeSetEndpoint, serializeSetMiner, validateDomainName, } from "../cogop/index.js";
|
|
11
11
|
import { openWalletReadContext } from "../read/index.js";
|
|
12
|
-
import { assertWalletMutationContextReady, buildWalletMutationTransaction, isAlreadyAcceptedError, isBroadcastUnknownError, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
12
|
+
import { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransaction, isAlreadyAcceptedError, isBroadcastUnknownError, outpointKey, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
13
13
|
import { confirmYesNo } from "./confirm.js";
|
|
14
14
|
import { getCanonicalIdentitySelector } from "./identity-selector.js";
|
|
15
15
|
import { findPendingMutationByIntent, upsertPendingMutation } from "./journal.js";
|
|
@@ -133,9 +133,8 @@ function buildPlanForDomainAdminOperation(options) {
|
|
|
133
133
|
return {
|
|
134
134
|
sender: options.sender,
|
|
135
135
|
changeAddress: options.state.funding.address,
|
|
136
|
-
|
|
136
|
+
fixedInputs: [
|
|
137
137
|
{ txid: anchorUtxo.txid, vout: anchorUtxo.vout },
|
|
138
|
-
...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
|
|
139
138
|
],
|
|
140
139
|
outputs: [
|
|
141
140
|
{ data: Buffer.from(options.opReturnData).toString("hex") },
|
|
@@ -146,6 +145,7 @@ function buildPlanForDomainAdminOperation(options) {
|
|
|
146
145
|
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
147
146
|
expectedAnchorValueSats: BigInt(options.state.anchorValueSats),
|
|
148
147
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
148
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
149
149
|
errorPrefix: options.errorPrefix,
|
|
150
150
|
};
|
|
151
151
|
}
|
|
@@ -155,14 +155,17 @@ function validateFundedDraft(decoded, funded, plan) {
|
|
|
155
155
|
if (inputs.length === 0) {
|
|
156
156
|
throw new Error(`${plan.errorPrefix}_missing_sender_input`);
|
|
157
157
|
}
|
|
158
|
+
assertFixedInputPrefixMatches(inputs, plan.fixedInputs, `${plan.errorPrefix}_sender_input_mismatch`);
|
|
158
159
|
if (inputs[0]?.prevout?.scriptPubKey?.hex !== plan.sender.scriptPubKeyHex) {
|
|
159
160
|
throw new Error(`${plan.errorPrefix}_sender_input_mismatch`);
|
|
160
161
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
assertFundingInputsAfterFixedPrefix({
|
|
163
|
+
inputs,
|
|
164
|
+
fixedInputs: plan.fixedInputs,
|
|
165
|
+
allowedFundingScriptPubKeyHex: plan.allowedFundingScriptPubKeyHex,
|
|
166
|
+
eligibleFundingOutpointKeys: plan.eligibleFundingOutpointKeys,
|
|
167
|
+
errorCode: `${plan.errorPrefix}_unexpected_funding_input`,
|
|
168
|
+
});
|
|
166
169
|
if (outputs[0]?.scriptPubKey?.hex !== plan.expectedOpReturnScriptHex) {
|
|
167
170
|
throw new Error(`${plan.errorPrefix}_opreturn_mismatch`);
|
|
168
171
|
}
|
|
@@ -189,6 +192,7 @@ async function buildTransaction(options) {
|
|
|
189
192
|
return buildWalletMutationTransaction({
|
|
190
193
|
rpc: options.rpc,
|
|
191
194
|
walletName: options.walletName,
|
|
195
|
+
state: options.state,
|
|
192
196
|
plan: options.plan,
|
|
193
197
|
validateFundedDraft,
|
|
194
198
|
finalizeErrorCode: `${options.plan.errorPrefix}_finalize_failed`,
|
|
@@ -632,6 +636,7 @@ async function submitDomainAdminMutation(options) {
|
|
|
632
636
|
const built = await buildTransaction({
|
|
633
637
|
rpc,
|
|
634
638
|
walletName,
|
|
639
|
+
state: nextState,
|
|
635
640
|
plan: buildPlanForDomainAdminOperation({
|
|
636
641
|
state: nextState,
|
|
637
642
|
allUtxos: await rpc.listUnspent(walletName, 1),
|
|
@@ -7,7 +7,7 @@ import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
|
7
7
|
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
8
8
|
import { serializeDomainBuy, serializeDomainSell, serializeDomainTransfer, validateDomainName, } from "../cogop/index.js";
|
|
9
9
|
import { openWalletReadContext } from "../read/index.js";
|
|
10
|
-
import { assertWalletMutationContextReady, buildWalletMutationTransaction, isAlreadyAcceptedError, isBroadcastUnknownError, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
10
|
+
import { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransaction, isAlreadyAcceptedError, isBroadcastUnknownError, outpointKey, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
11
11
|
import { confirmTypedAcknowledgement, confirmYesNo } from "./confirm.js";
|
|
12
12
|
import { getCanonicalIdentitySelector, resolveIdentityBySelector, } from "./identity-selector.js";
|
|
13
13
|
import { findPendingMutationByIntent, upsertPendingMutation } from "./journal.js";
|
|
@@ -258,11 +258,8 @@ function buildPlanForDomainOperation(options) {
|
|
|
258
258
|
return {
|
|
259
259
|
sender: options.sender,
|
|
260
260
|
changeAddress: options.state.funding.address,
|
|
261
|
-
|
|
261
|
+
fixedInputs: [
|
|
262
262
|
{ txid: senderUtxo.txid, vout: senderUtxo.vout },
|
|
263
|
-
...fundingUtxos
|
|
264
|
-
.filter((entry) => !(entry.txid === senderUtxo.txid && entry.vout === senderUtxo.vout))
|
|
265
|
-
.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
|
|
266
263
|
],
|
|
267
264
|
outputs,
|
|
268
265
|
changePosition: 1,
|
|
@@ -270,6 +267,9 @@ function buildPlanForDomainOperation(options) {
|
|
|
270
267
|
expectedAnchorScriptHex: null,
|
|
271
268
|
expectedAnchorValueSats: null,
|
|
272
269
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
270
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos
|
|
271
|
+
.filter((entry) => !(entry.txid === senderUtxo.txid && entry.vout === senderUtxo.vout))
|
|
272
|
+
.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
273
273
|
errorPrefix: options.errorPrefix,
|
|
274
274
|
};
|
|
275
275
|
}
|
|
@@ -288,9 +288,8 @@ function buildPlanForDomainOperation(options) {
|
|
|
288
288
|
return {
|
|
289
289
|
sender: options.sender,
|
|
290
290
|
changeAddress: options.state.funding.address,
|
|
291
|
-
|
|
291
|
+
fixedInputs: [
|
|
292
292
|
{ txid: anchorUtxo.txid, vout: anchorUtxo.vout },
|
|
293
|
-
...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
|
|
294
293
|
],
|
|
295
294
|
outputs,
|
|
296
295
|
changePosition: 2,
|
|
@@ -298,6 +297,7 @@ function buildPlanForDomainOperation(options) {
|
|
|
298
297
|
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
299
298
|
expectedAnchorValueSats: options.anchorValueSats,
|
|
300
299
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
300
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
301
301
|
errorPrefix: options.errorPrefix,
|
|
302
302
|
};
|
|
303
303
|
}
|
|
@@ -307,14 +307,17 @@ function validateFundedDraft(decoded, funded, plan) {
|
|
|
307
307
|
if (inputs.length === 0) {
|
|
308
308
|
throw new Error(`${plan.errorPrefix}_missing_sender_input`);
|
|
309
309
|
}
|
|
310
|
+
assertFixedInputPrefixMatches(inputs, plan.fixedInputs, `${plan.errorPrefix}_sender_input_mismatch`);
|
|
310
311
|
if (inputs[0]?.prevout?.scriptPubKey?.hex !== plan.sender.scriptPubKeyHex) {
|
|
311
312
|
throw new Error(`${plan.errorPrefix}_sender_input_mismatch`);
|
|
312
313
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
314
|
+
assertFundingInputsAfterFixedPrefix({
|
|
315
|
+
inputs,
|
|
316
|
+
fixedInputs: plan.fixedInputs,
|
|
317
|
+
allowedFundingScriptPubKeyHex: plan.allowedFundingScriptPubKeyHex,
|
|
318
|
+
eligibleFundingOutpointKeys: plan.eligibleFundingOutpointKeys,
|
|
319
|
+
errorCode: `${plan.errorPrefix}_unexpected_funding_input`,
|
|
320
|
+
});
|
|
318
321
|
if (outputs[0]?.scriptPubKey?.hex !== plan.expectedOpReturnScriptHex) {
|
|
319
322
|
throw new Error(`${plan.errorPrefix}_opreturn_mismatch`);
|
|
320
323
|
}
|
|
@@ -344,6 +347,7 @@ async function buildTransaction(options) {
|
|
|
344
347
|
return buildWalletMutationTransaction({
|
|
345
348
|
rpc: options.rpc,
|
|
346
349
|
walletName: options.walletName,
|
|
350
|
+
state: options.state,
|
|
347
351
|
plan: options.plan,
|
|
348
352
|
validateFundedDraft,
|
|
349
353
|
finalizeErrorCode: `${options.plan.errorPrefix}_finalize_failed`,
|
|
@@ -768,6 +772,7 @@ export async function transferDomain(options) {
|
|
|
768
772
|
const built = await buildTransaction({
|
|
769
773
|
rpc,
|
|
770
774
|
walletName,
|
|
775
|
+
state: nextState,
|
|
771
776
|
plan: buildPlanForDomainOperation({
|
|
772
777
|
state: nextState,
|
|
773
778
|
allUtxos: await rpc.listUnspent(walletName, 1),
|
|
@@ -998,6 +1003,7 @@ async function runSellMutation(options) {
|
|
|
998
1003
|
const built = await buildTransaction({
|
|
999
1004
|
rpc,
|
|
1000
1005
|
walletName,
|
|
1006
|
+
state: nextState,
|
|
1001
1007
|
plan: buildPlanForDomainOperation({
|
|
1002
1008
|
state: nextState,
|
|
1003
1009
|
allUtxos: await rpc.listUnspent(walletName, 1),
|
|
@@ -1233,6 +1239,7 @@ export async function buyDomain(options) {
|
|
|
1233
1239
|
const built = await buildTransaction({
|
|
1234
1240
|
rpc,
|
|
1235
1241
|
walletName,
|
|
1242
|
+
state: nextState,
|
|
1236
1243
|
plan: buildPlanForDomainOperation({
|
|
1237
1244
|
state: nextState,
|
|
1238
1245
|
allUtxos: await rpc.listUnspent(walletName, 1),
|
package/dist/wallet/tx/field.js
CHANGED
|
@@ -5,12 +5,13 @@ import { getBalance, lookupDomain, } from "@cogcoin/indexer/queries";
|
|
|
5
5
|
import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
|
|
6
6
|
import { createRpcClient } from "../../bitcoind/node.js";
|
|
7
7
|
import { acquireFileLock } from "../fs/lock.js";
|
|
8
|
+
import { computeDesignatedProactiveReserveOutpoints } from "../coin-control.js";
|
|
8
9
|
import { resolveWalletRuntimePathsForTesting, } from "../runtime.js";
|
|
9
10
|
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
10
11
|
import { FIELD_FORMAT_BYTES, serializeDataUpdate, serializeFieldReg, } from "../cogop/index.js";
|
|
11
12
|
import { validateFieldName } from "../cogop/validate-name.js";
|
|
12
13
|
import { findDomainField, openWalletReadContext, } from "../read/index.js";
|
|
13
|
-
import { assertWalletMutationContextReady,
|
|
14
|
+
import { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransactionWithReserveFallback, isAlreadyAcceptedError, isBroadcastUnknownError, outpointKey, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
14
15
|
import { confirmTypedAcknowledgement as confirmSharedTypedAcknowledgement, confirmYesNo as confirmSharedYesNo, } from "./confirm.js";
|
|
15
16
|
import { getCanonicalIdentitySelector } from "./identity-selector.js";
|
|
16
17
|
import { findPendingMutationByIntent, upsertPendingMutation } from "./journal.js";
|
|
@@ -253,9 +254,8 @@ function buildAnchoredFieldPlan(options) {
|
|
|
253
254
|
return {
|
|
254
255
|
sender: options.sender,
|
|
255
256
|
changeAddress: options.state.funding.address,
|
|
256
|
-
|
|
257
|
+
fixedInputs: [
|
|
257
258
|
{ txid: anchorUtxo.txid, vout: anchorUtxo.vout },
|
|
258
|
-
...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
|
|
259
259
|
],
|
|
260
260
|
outputs: [
|
|
261
261
|
{ data: Buffer.from(options.opReturnData).toString("hex") },
|
|
@@ -266,6 +266,7 @@ function buildAnchoredFieldPlan(options) {
|
|
|
266
266
|
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
267
267
|
expectedAnchorValueSats: BigInt(options.state.anchorValueSats),
|
|
268
268
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
269
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
269
270
|
errorPrefix: options.errorPrefix,
|
|
270
271
|
};
|
|
271
272
|
}
|
|
@@ -277,10 +278,7 @@ function buildFieldFamilyTx2Plan(options) {
|
|
|
277
278
|
return {
|
|
278
279
|
sender: options.sender,
|
|
279
280
|
changeAddress: options.state.funding.address,
|
|
280
|
-
|
|
281
|
-
{ txid: options.tx1Txid, vout: 1 },
|
|
282
|
-
...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
|
|
283
|
-
],
|
|
281
|
+
fixedInputs: [{ txid: options.tx1Txid, vout: 1 }],
|
|
284
282
|
outputs: [
|
|
285
283
|
{ data: Buffer.from(options.opReturnData).toString("hex") },
|
|
286
284
|
{ [options.sender.address]: satsToBtcNumber(BigInt(options.state.anchorValueSats)) },
|
|
@@ -290,6 +288,7 @@ function buildFieldFamilyTx2Plan(options) {
|
|
|
290
288
|
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
291
289
|
expectedAnchorValueSats: BigInt(options.state.anchorValueSats),
|
|
292
290
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
291
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
293
292
|
errorPrefix: "wallet_field_create_tx2",
|
|
294
293
|
};
|
|
295
294
|
}
|
|
@@ -299,14 +298,17 @@ function validateFieldDraft(decoded, funded, plan) {
|
|
|
299
298
|
if (inputs.length === 0) {
|
|
300
299
|
throw new Error(`${plan.errorPrefix}_missing_sender_input`);
|
|
301
300
|
}
|
|
301
|
+
assertFixedInputPrefixMatches(inputs, plan.fixedInputs, `${plan.errorPrefix}_sender_input_mismatch`);
|
|
302
302
|
if (inputs[0]?.prevout?.scriptPubKey?.hex !== plan.sender.scriptPubKeyHex) {
|
|
303
303
|
throw new Error(`${plan.errorPrefix}_sender_input_mismatch`);
|
|
304
304
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
305
|
+
assertFundingInputsAfterFixedPrefix({
|
|
306
|
+
inputs,
|
|
307
|
+
fixedInputs: plan.fixedInputs,
|
|
308
|
+
allowedFundingScriptPubKeyHex: plan.allowedFundingScriptPubKeyHex,
|
|
309
|
+
eligibleFundingOutpointKeys: plan.eligibleFundingOutpointKeys,
|
|
310
|
+
errorCode: `${plan.errorPrefix}_unexpected_funding_input`,
|
|
311
|
+
});
|
|
310
312
|
if (outputs[0]?.scriptPubKey?.hex !== plan.expectedOpReturnScriptHex) {
|
|
311
313
|
throw new Error(`${plan.errorPrefix}_opreturn_mismatch`);
|
|
312
314
|
}
|
|
@@ -330,14 +332,16 @@ function validateFieldDraft(decoded, funded, plan) {
|
|
|
330
332
|
}
|
|
331
333
|
}
|
|
332
334
|
async function buildFieldTransaction(options) {
|
|
333
|
-
|
|
335
|
+
const reserveCandidates = computeDesignatedProactiveReserveOutpoints(options.state, await options.rpc.listUnspent(options.walletName, 1));
|
|
336
|
+
return buildWalletMutationTransactionWithReserveFallback({
|
|
334
337
|
rpc: options.rpc,
|
|
335
338
|
walletName: options.walletName,
|
|
339
|
+
state: options.state,
|
|
336
340
|
plan: options.plan,
|
|
337
341
|
validateFundedDraft: validateFieldDraft,
|
|
338
342
|
finalizeErrorCode: `${options.plan.errorPrefix}_finalize_failed`,
|
|
339
343
|
mempoolRejectPrefix: `${options.plan.errorPrefix}_mempool_rejected`,
|
|
340
|
-
|
|
344
|
+
reserveCandidates,
|
|
341
345
|
});
|
|
342
346
|
}
|
|
343
347
|
async function saveUpdatedState(options) {
|
|
@@ -1348,6 +1352,7 @@ async function submitStandaloneFieldMutation(options) {
|
|
|
1348
1352
|
const built = await buildFieldTransaction({
|
|
1349
1353
|
rpc,
|
|
1350
1354
|
walletName,
|
|
1355
|
+
state: nextState,
|
|
1351
1356
|
plan: buildAnchoredFieldPlan({
|
|
1352
1357
|
state: nextState,
|
|
1353
1358
|
allUtxos: await rpc.listUnspent(walletName, 1),
|
|
@@ -1544,6 +1549,7 @@ async function submitFieldCreateFamily(options) {
|
|
|
1544
1549
|
const tx1 = await buildFieldTransaction({
|
|
1545
1550
|
rpc,
|
|
1546
1551
|
walletName,
|
|
1552
|
+
state: nextState,
|
|
1547
1553
|
plan: buildAnchoredFieldPlan({
|
|
1548
1554
|
state: nextState,
|
|
1549
1555
|
allUtxos: await rpc.listUnspent(walletName, 1),
|
|
@@ -1576,6 +1582,7 @@ async function submitFieldCreateFamily(options) {
|
|
|
1576
1582
|
const tx2 = await buildFieldTransaction({
|
|
1577
1583
|
rpc,
|
|
1578
1584
|
walletName,
|
|
1585
|
+
state: workingState,
|
|
1579
1586
|
plan: buildFieldFamilyTx2Plan({
|
|
1580
1587
|
state: workingState,
|
|
1581
1588
|
allUtxos: await rpc.listUnspent(walletName, 1),
|
|
@@ -1583,10 +1590,6 @@ async function submitFieldCreateFamily(options) {
|
|
|
1583
1590
|
tx1Txid,
|
|
1584
1591
|
opReturnData: serializeDataUpdate(operation.chainDomain.domainId, resumedFamily.expectedFieldId ?? operation.chainDomain.nextFieldId, options.value.format, options.value.value).opReturnData,
|
|
1585
1592
|
}),
|
|
1586
|
-
builderOptions: {
|
|
1587
|
-
includeUnsafe: true,
|
|
1588
|
-
minConf: 0,
|
|
1589
|
-
},
|
|
1590
1593
|
});
|
|
1591
1594
|
const final = await sendFamilyTx2({
|
|
1592
1595
|
rpc,
|
|
@@ -8,7 +8,7 @@ import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
|
8
8
|
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
9
9
|
import { computeRootRegistrationPriceSats, serializeDomainReg } from "../cogop/index.js";
|
|
10
10
|
import { openWalletReadContext } from "../read/index.js";
|
|
11
|
-
import { assertWalletMutationContextReady, buildWalletMutationTransaction, formatCogAmount, isAlreadyAcceptedError, isBroadcastUnknownError, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
11
|
+
import { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransaction, formatCogAmount, isAlreadyAcceptedError, isBroadcastUnknownError, outpointKey, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
12
12
|
import { confirmTypedAcknowledgement, confirmYesNo } from "./confirm.js";
|
|
13
13
|
import { getCanonicalIdentitySelector, resolveIdentityBySelector, } from "./identity-selector.js";
|
|
14
14
|
import { findPendingMutationByIntent, upsertPendingMutation } from "./journal.js";
|
|
@@ -401,14 +401,17 @@ function validateFundedDraft(decoded, funded, plan) {
|
|
|
401
401
|
if (inputs.length === 0) {
|
|
402
402
|
throw new Error("wallet_register_missing_sender_input");
|
|
403
403
|
}
|
|
404
|
+
assertFixedInputPrefixMatches(inputs, plan.fixedInputs, "wallet_register_sender_input_mismatch");
|
|
404
405
|
if (inputs[0]?.prevout?.scriptPubKey?.hex !== plan.sender.scriptPubKeyHex) {
|
|
405
406
|
throw new Error("wallet_register_sender_input_mismatch");
|
|
406
407
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
408
|
+
assertFundingInputsAfterFixedPrefix({
|
|
409
|
+
inputs,
|
|
410
|
+
fixedInputs: plan.fixedInputs,
|
|
411
|
+
allowedFundingScriptPubKeyHex: plan.allowedFundingScriptPubKeyHex,
|
|
412
|
+
eligibleFundingOutpointKeys: plan.eligibleFundingOutpointKeys,
|
|
413
|
+
errorCode: "wallet_register_unexpected_funding_input",
|
|
414
|
+
});
|
|
412
415
|
if (outputs[0]?.scriptPubKey?.hex !== plan.expectedOpReturnScriptHex) {
|
|
413
416
|
throw new Error("wallet_register_opreturn_mismatch");
|
|
414
417
|
}
|
|
@@ -467,9 +470,8 @@ function buildRegisterPlan(options) {
|
|
|
467
470
|
registerKind: "root",
|
|
468
471
|
sender: options.sender,
|
|
469
472
|
changeAddress: options.state.funding.address,
|
|
470
|
-
|
|
473
|
+
fixedInputs: [
|
|
471
474
|
{ txid: senderInput.txid, vout: senderInput.vout },
|
|
472
|
-
...additionalFunding,
|
|
473
475
|
],
|
|
474
476
|
outputs: rootOutputs.outputs,
|
|
475
477
|
changePosition: rootOutputs.changePosition,
|
|
@@ -481,6 +483,7 @@ function buildRegisterPlan(options) {
|
|
|
481
483
|
expectedAnchorScriptHex: null,
|
|
482
484
|
expectedAnchorValueSats: null,
|
|
483
485
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
486
|
+
eligibleFundingOutpointKeys: new Set(additionalFunding.map((entry) => outpointKey(entry))),
|
|
484
487
|
};
|
|
485
488
|
}
|
|
486
489
|
const anchorUtxo = options.allUtxos.find((entry) => entry.txid === options.anchorOutpoint?.txid
|
|
@@ -494,9 +497,8 @@ function buildRegisterPlan(options) {
|
|
|
494
497
|
registerKind: "root",
|
|
495
498
|
sender: options.sender,
|
|
496
499
|
changeAddress: options.state.funding.address,
|
|
497
|
-
|
|
500
|
+
fixedInputs: [
|
|
498
501
|
{ txid: anchorUtxo.txid, vout: anchorUtxo.vout },
|
|
499
|
-
...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
|
|
500
502
|
],
|
|
501
503
|
outputs: rootOutputs.outputs,
|
|
502
504
|
changePosition: rootOutputs.changePosition,
|
|
@@ -508,6 +510,7 @@ function buildRegisterPlan(options) {
|
|
|
508
510
|
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
509
511
|
expectedAnchorValueSats: options.anchorValueSats,
|
|
510
512
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
513
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey(entry))),
|
|
511
514
|
};
|
|
512
515
|
}
|
|
513
516
|
const anchor = options.anchorOutpoint;
|
|
@@ -530,9 +533,8 @@ function buildRegisterPlan(options) {
|
|
|
530
533
|
registerKind: "subdomain",
|
|
531
534
|
sender: options.sender,
|
|
532
535
|
changeAddress: options.state.funding.address,
|
|
533
|
-
|
|
536
|
+
fixedInputs: [
|
|
534
537
|
{ txid: anchorUtxo.txid, vout: anchorUtxo.vout },
|
|
535
|
-
...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
|
|
536
538
|
],
|
|
537
539
|
outputs: subdomainOutputs.outputs,
|
|
538
540
|
changePosition: subdomainOutputs.changePosition,
|
|
@@ -544,12 +546,14 @@ function buildRegisterPlan(options) {
|
|
|
544
546
|
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
545
547
|
expectedAnchorValueSats: options.anchorValueSats,
|
|
546
548
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
549
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey(entry))),
|
|
547
550
|
};
|
|
548
551
|
}
|
|
549
552
|
async function buildRegisterTransaction(options) {
|
|
550
553
|
return buildWalletMutationTransaction({
|
|
551
554
|
rpc: options.rpc,
|
|
552
555
|
walletName: options.walletName,
|
|
556
|
+
state: options.state,
|
|
553
557
|
plan: options.plan,
|
|
554
558
|
validateFundedDraft,
|
|
555
559
|
finalizeErrorCode: "wallet_register_finalize_failed",
|
|
@@ -810,6 +814,7 @@ export async function registerDomain(options) {
|
|
|
810
814
|
const built = await buildRegisterTransaction({
|
|
811
815
|
rpc,
|
|
812
816
|
walletName,
|
|
817
|
+
state: nextState,
|
|
813
818
|
plan,
|
|
814
819
|
});
|
|
815
820
|
const currentMutation = nextState.pendingMutations?.find((mutation) => mutation.intentFingerprintHex === intentFingerprintHex)
|
|
@@ -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 { assertWalletMutationContextReady, buildWalletMutationTransaction, formatCogAmount, isAlreadyAcceptedError, isBroadcastUnknownError, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
11
|
+
import { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransaction, formatCogAmount, isAlreadyAcceptedError, isBroadcastUnknownError, outpointKey, pauseMiningForWalletMutation, 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";
|
|
@@ -162,9 +162,8 @@ function buildPlanForReputationOperation(options) {
|
|
|
162
162
|
return {
|
|
163
163
|
sender: options.sender,
|
|
164
164
|
changeAddress: options.state.funding.address,
|
|
165
|
-
|
|
165
|
+
fixedInputs: [
|
|
166
166
|
{ txid: anchorUtxo.txid, vout: anchorUtxo.vout },
|
|
167
|
-
...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
|
|
168
167
|
],
|
|
169
168
|
outputs: [
|
|
170
169
|
{ data: Buffer.from(options.opReturnData).toString("hex") },
|
|
@@ -175,6 +174,7 @@ function buildPlanForReputationOperation(options) {
|
|
|
175
174
|
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
176
175
|
expectedAnchorValueSats: BigInt(options.state.anchorValueSats),
|
|
177
176
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
177
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
178
178
|
errorPrefix: options.errorPrefix,
|
|
179
179
|
};
|
|
180
180
|
}
|
|
@@ -184,14 +184,17 @@ function validateFundedDraft(decoded, funded, plan) {
|
|
|
184
184
|
if (inputs.length === 0) {
|
|
185
185
|
throw new Error(`${plan.errorPrefix}_missing_sender_input`);
|
|
186
186
|
}
|
|
187
|
+
assertFixedInputPrefixMatches(inputs, plan.fixedInputs, `${plan.errorPrefix}_sender_input_mismatch`);
|
|
187
188
|
if (inputs[0]?.prevout?.scriptPubKey?.hex !== plan.sender.scriptPubKeyHex) {
|
|
188
189
|
throw new Error(`${plan.errorPrefix}_sender_input_mismatch`);
|
|
189
190
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
191
|
+
assertFundingInputsAfterFixedPrefix({
|
|
192
|
+
inputs,
|
|
193
|
+
fixedInputs: plan.fixedInputs,
|
|
194
|
+
allowedFundingScriptPubKeyHex: plan.allowedFundingScriptPubKeyHex,
|
|
195
|
+
eligibleFundingOutpointKeys: plan.eligibleFundingOutpointKeys,
|
|
196
|
+
errorCode: `${plan.errorPrefix}_unexpected_funding_input`,
|
|
197
|
+
});
|
|
195
198
|
if (outputs[0]?.scriptPubKey?.hex !== plan.expectedOpReturnScriptHex) {
|
|
196
199
|
throw new Error(`${plan.errorPrefix}_opreturn_mismatch`);
|
|
197
200
|
}
|
|
@@ -218,6 +221,7 @@ async function buildTransaction(options) {
|
|
|
218
221
|
return buildWalletMutationTransaction({
|
|
219
222
|
rpc: options.rpc,
|
|
220
223
|
walletName: options.walletName,
|
|
224
|
+
state: options.state,
|
|
221
225
|
plan: options.plan,
|
|
222
226
|
validateFundedDraft,
|
|
223
227
|
finalizeErrorCode: `${options.plan.errorPrefix}_finalize_failed`,
|
|
@@ -635,6 +639,7 @@ async function submitReputationMutation(options) {
|
|
|
635
639
|
const built = await buildTransaction({
|
|
636
640
|
rpc,
|
|
637
641
|
walletName,
|
|
642
|
+
state: nextState,
|
|
638
643
|
plan: buildPlanForReputationOperation({
|
|
639
644
|
state: nextState,
|
|
640
645
|
allUtxos: await rpc.listUnspent(walletName, 1),
|
package/dist/wallet/types.d.ts
CHANGED
|
@@ -142,6 +142,8 @@ export interface WalletStateV1 {
|
|
|
142
142
|
walletRootId: string;
|
|
143
143
|
network: WalletNetwork;
|
|
144
144
|
anchorValueSats: number;
|
|
145
|
+
proactiveReserveSats: number;
|
|
146
|
+
proactiveReserveOutpoints: OutpointRecord[];
|
|
145
147
|
nextDedicatedIndex: number;
|
|
146
148
|
fundingIndex: 0;
|
|
147
149
|
mnemonic: {
|
|
@@ -191,6 +193,8 @@ export interface PortableWalletArchivePayloadV1 {
|
|
|
191
193
|
walletRootId: string;
|
|
192
194
|
network: WalletNetwork;
|
|
193
195
|
anchorValueSats: number;
|
|
196
|
+
proactiveReserveSats: number;
|
|
197
|
+
proactiveReserveOutpoints: OutpointRecord[];
|
|
194
198
|
nextDedicatedIndex: number;
|
|
195
199
|
fundingIndex: 0;
|
|
196
200
|
mnemonic: {
|
package/package.json
CHANGED