@cogcoin/client 0.5.12 → 0.5.14

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.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/dist/bitcoind/bootstrap/getblock-archive.d.ts +23 -1
  3. package/dist/bitcoind/bootstrap/getblock-archive.js +127 -37
  4. package/dist/bitcoind/bootstrap.d.ts +1 -1
  5. package/dist/bitcoind/bootstrap.js +1 -1
  6. package/dist/bitcoind/client/managed-client.js +62 -40
  7. package/dist/bitcoind/client/sync-engine.js +7 -2
  8. package/dist/bitcoind/testing.d.ts +1 -1
  9. package/dist/bitcoind/testing.js +1 -1
  10. package/dist/cli/commands/status.js +1 -1
  11. package/dist/cli/commands/sync.js +99 -1
  12. package/dist/cli/commands/wallet-mutation.js +39 -2
  13. package/dist/cli/context.js +20 -3
  14. package/dist/cli/mutation-success.d.ts +2 -0
  15. package/dist/cli/mutation-success.js +2 -0
  16. package/dist/cli/mutation-text-write.d.ts +2 -0
  17. package/dist/cli/mutation-text-write.js +7 -0
  18. package/dist/cli/output.js +22 -1
  19. package/dist/cli/types.d.ts +2 -0
  20. package/dist/cli/wallet-format.d.ts +1 -1
  21. package/dist/cli/wallet-format.js +2 -2
  22. package/dist/wallet/archive.js +10 -8
  23. package/dist/wallet/coin-control.d.ts +41 -0
  24. package/dist/wallet/coin-control.js +406 -0
  25. package/dist/wallet/lifecycle.js +39 -2
  26. package/dist/wallet/mining/runner.js +46 -44
  27. package/dist/wallet/read/context.js +15 -6
  28. package/dist/wallet/reset.js +2 -0
  29. package/dist/wallet/state/storage.js +5 -4
  30. package/dist/wallet/tx/anchor.d.ts +2 -0
  31. package/dist/wallet/tx/anchor.js +76 -56
  32. package/dist/wallet/tx/cog.js +19 -22
  33. package/dist/wallet/tx/common.d.ts +45 -10
  34. package/dist/wallet/tx/common.js +178 -6
  35. package/dist/wallet/tx/domain-admin.js +15 -9
  36. package/dist/wallet/tx/domain-market.js +19 -22
  37. package/dist/wallet/tx/field.js +19 -18
  38. package/dist/wallet/tx/register.js +19 -22
  39. package/dist/wallet/tx/reputation.js +15 -9
  40. package/dist/wallet/types.d.ts +4 -0
  41. package/package.json +1 -1
@@ -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, buildWalletMutationTransactionWithReserveFallback, 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
- for (let index = 1; index < inputs.length; index += 1) {
408
- if (inputs[index]?.prevout?.scriptPubKey?.hex !== plan.allowedFundingScriptPubKeyHex) {
409
- throw new Error("wallet_register_unexpected_funding_input");
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
  }
@@ -456,21 +459,11 @@ function buildRegisterPlan(options) {
456
459
  anchorValueSats: options.anchorOutpoint === null ? null : options.anchorValueSats,
457
460
  });
458
461
  if (options.anchorOutpoint === null) {
459
- if (fundingUtxos.length === 0) {
460
- throw new Error("wallet_register_sender_utxo_unavailable");
461
- }
462
- const senderInput = fundingUtxos[0];
463
- const additionalFunding = fundingUtxos
464
- .slice(1)
465
- .map((entry) => ({ txid: entry.txid, vout: entry.vout }));
466
462
  return {
467
463
  registerKind: "root",
468
464
  sender: options.sender,
469
465
  changeAddress: options.state.funding.address,
470
- inputs: [
471
- { txid: senderInput.txid, vout: senderInput.vout },
472
- ...additionalFunding,
473
- ],
466
+ fixedInputs: [],
474
467
  outputs: rootOutputs.outputs,
475
468
  changePosition: rootOutputs.changePosition,
476
469
  expectedOpReturnScriptHex: rootOutputs.expectedOpReturnScriptHex,
@@ -481,6 +474,7 @@ function buildRegisterPlan(options) {
481
474
  expectedAnchorScriptHex: null,
482
475
  expectedAnchorValueSats: null,
483
476
  allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
477
+ eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey(entry))),
484
478
  };
485
479
  }
486
480
  const anchorUtxo = options.allUtxos.find((entry) => entry.txid === options.anchorOutpoint?.txid
@@ -494,9 +488,8 @@ function buildRegisterPlan(options) {
494
488
  registerKind: "root",
495
489
  sender: options.sender,
496
490
  changeAddress: options.state.funding.address,
497
- inputs: [
491
+ fixedInputs: [
498
492
  { txid: anchorUtxo.txid, vout: anchorUtxo.vout },
499
- ...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
500
493
  ],
501
494
  outputs: rootOutputs.outputs,
502
495
  changePosition: rootOutputs.changePosition,
@@ -508,6 +501,7 @@ function buildRegisterPlan(options) {
508
501
  expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
509
502
  expectedAnchorValueSats: options.anchorValueSats,
510
503
  allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
504
+ eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey(entry))),
511
505
  };
512
506
  }
513
507
  const anchor = options.anchorOutpoint;
@@ -530,9 +524,8 @@ function buildRegisterPlan(options) {
530
524
  registerKind: "subdomain",
531
525
  sender: options.sender,
532
526
  changeAddress: options.state.funding.address,
533
- inputs: [
527
+ fixedInputs: [
534
528
  { txid: anchorUtxo.txid, vout: anchorUtxo.vout },
535
- ...fundingUtxos.map((entry) => ({ txid: entry.txid, vout: entry.vout })),
536
529
  ],
537
530
  outputs: subdomainOutputs.outputs,
538
531
  changePosition: subdomainOutputs.changePosition,
@@ -544,16 +537,19 @@ function buildRegisterPlan(options) {
544
537
  expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
545
538
  expectedAnchorValueSats: options.anchorValueSats,
546
539
  allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
540
+ eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey(entry))),
547
541
  };
548
542
  }
549
543
  async function buildRegisterTransaction(options) {
550
- return buildWalletMutationTransaction({
544
+ return buildWalletMutationTransactionWithReserveFallback({
551
545
  rpc: options.rpc,
552
546
  walletName: options.walletName,
547
+ state: options.state,
553
548
  plan: options.plan,
554
549
  validateFundedDraft,
555
550
  finalizeErrorCode: "wallet_register_finalize_failed",
556
551
  mempoolRejectPrefix: "wallet_register_mempool_rejected",
552
+ reserveCandidates: options.state.proactiveReserveOutpoints,
557
553
  });
558
554
  }
559
555
  async function reconcilePendingRegisterMutation(options) {
@@ -810,6 +806,7 @@ export async function registerDomain(options) {
810
806
  const built = await buildRegisterTransaction({
811
807
  rpc,
812
808
  walletName,
809
+ state: nextState,
813
810
  plan,
814
811
  });
815
812
  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, buildWalletMutationTransactionWithReserveFallback, 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
- inputs: [
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
- for (let index = 1; index < inputs.length; index += 1) {
191
- if (inputs[index]?.prevout?.scriptPubKey?.hex !== plan.allowedFundingScriptPubKeyHex) {
192
- throw new Error(`${plan.errorPrefix}_unexpected_funding_input`);
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
  }
@@ -215,13 +218,15 @@ function validateFundedDraft(decoded, funded, plan) {
215
218
  }
216
219
  }
217
220
  async function buildTransaction(options) {
218
- return buildWalletMutationTransaction({
221
+ return buildWalletMutationTransactionWithReserveFallback({
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`,
224
228
  mempoolRejectPrefix: `${options.plan.errorPrefix}_mempool_rejected`,
229
+ reserveCandidates: options.state.proactiveReserveOutpoints,
225
230
  });
226
231
  }
227
232
  function createDraftMutation(options) {
@@ -635,6 +640,7 @@ async function submitReputationMutation(options) {
635
640
  const built = await buildTransaction({
636
641
  rpc,
637
642
  walletName,
643
+ state: nextState,
638
644
  plan: buildPlanForReputationOperation({
639
645
  state: nextState,
640
646
  allUtxos: await rpc.listUnspent(walletName, 1),
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cogcoin/client",
3
- "version": "0.5.12",
3
+ "version": "0.5.14",
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",