@cogcoin/client 1.1.6 → 1.1.8

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 (125) hide show
  1. package/README.md +2 -2
  2. package/dist/bitcoind/indexer-daemon.js +29 -79
  3. package/dist/bitcoind/managed-runtime/bitcoind-runtime.d.ts +20 -0
  4. package/dist/bitcoind/managed-runtime/bitcoind-runtime.js +74 -0
  5. package/dist/bitcoind/managed-runtime/bitcoind-status.d.ts +11 -0
  6. package/dist/bitcoind/managed-runtime/bitcoind-status.js +44 -0
  7. package/dist/bitcoind/managed-runtime/indexer-runtime.d.ts +15 -0
  8. package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
  9. package/dist/bitcoind/managed-runtime/types.d.ts +40 -0
  10. package/dist/bitcoind/node.d.ts +2 -2
  11. package/dist/bitcoind/node.js +2 -2
  12. package/dist/bitcoind/rpc.d.ts +2 -1
  13. package/dist/bitcoind/rpc.js +53 -3
  14. package/dist/bitcoind/service.js +47 -127
  15. package/dist/cli/command-registry.d.ts +1 -1
  16. package/dist/cli/command-registry.js +2 -64
  17. package/dist/cli/commands/client-admin.js +3 -18
  18. package/dist/cli/commands/mining-runtime.js +4 -60
  19. package/dist/cli/commands/wallet-admin.js +6 -6
  20. package/dist/cli/context.js +1 -3
  21. package/dist/cli/mining-json.d.ts +1 -22
  22. package/dist/cli/mining-json.js +0 -23
  23. package/dist/cli/output.js +16 -2
  24. package/dist/cli/parse.js +0 -2
  25. package/dist/cli/preview-json.d.ts +1 -22
  26. package/dist/cli/preview-json.js +0 -19
  27. package/dist/cli/types.d.ts +1 -3
  28. package/dist/cli/wallet-format.js +1 -1
  29. package/dist/cli/workflow-hints.d.ts +1 -2
  30. package/dist/cli/workflow-hints.js +5 -8
  31. package/dist/wallet/lifecycle/context.js +0 -1
  32. package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
  33. package/dist/wallet/lifecycle/repair-mining.js +5 -39
  34. package/dist/wallet/lifecycle/repair.js +0 -3
  35. package/dist/wallet/lifecycle/setup.js +10 -8
  36. package/dist/wallet/lifecycle/types.d.ts +1 -4
  37. package/dist/wallet/managed-core-wallet.d.ts +2 -0
  38. package/dist/wallet/managed-core-wallet.js +27 -1
  39. package/dist/wallet/mining/candidate.d.ts +1 -0
  40. package/dist/wallet/mining/candidate.js +38 -6
  41. package/dist/wallet/mining/competitiveness.d.ts +1 -0
  42. package/dist/wallet/mining/competitiveness.js +6 -0
  43. package/dist/wallet/mining/cycle.d.ts +2 -0
  44. package/dist/wallet/mining/cycle.js +14 -4
  45. package/dist/wallet/mining/engine-state.js +10 -0
  46. package/dist/wallet/mining/engine-types.d.ts +1 -0
  47. package/dist/wallet/mining/index.d.ts +1 -1
  48. package/dist/wallet/mining/index.js +1 -1
  49. package/dist/wallet/mining/publish.d.ts +3 -0
  50. package/dist/wallet/mining/publish.js +78 -6
  51. package/dist/wallet/mining/runner.d.ts +0 -32
  52. package/dist/wallet/mining/runner.js +59 -104
  53. package/dist/wallet/mining/stop.d.ts +7 -0
  54. package/dist/wallet/mining/stop.js +23 -0
  55. package/dist/wallet/mining/supervisor.d.ts +2 -36
  56. package/dist/wallet/mining/supervisor.js +139 -246
  57. package/dist/wallet/mining/visualizer-sync.js +79 -15
  58. package/dist/wallet/read/context.d.ts +1 -5
  59. package/dist/wallet/read/context.js +21 -205
  60. package/dist/wallet/read/managed-services.d.ts +33 -0
  61. package/dist/wallet/read/managed-services.js +222 -0
  62. package/dist/wallet/reset/artifacts.d.ts +16 -0
  63. package/dist/wallet/reset/artifacts.js +141 -0
  64. package/dist/wallet/reset/execution.d.ts +38 -0
  65. package/dist/wallet/reset/execution.js +458 -0
  66. package/dist/wallet/reset/preflight.d.ts +7 -0
  67. package/dist/wallet/reset/preflight.js +116 -0
  68. package/dist/wallet/reset/preview.d.ts +2 -0
  69. package/dist/wallet/reset/preview.js +50 -0
  70. package/dist/wallet/reset/process-cleanup.d.ts +12 -0
  71. package/dist/wallet/reset/process-cleanup.js +179 -0
  72. package/dist/wallet/reset/types.d.ts +189 -0
  73. package/dist/wallet/reset/types.js +1 -0
  74. package/dist/wallet/reset.d.ts +4 -119
  75. package/dist/wallet/reset.js +4 -882
  76. package/dist/wallet/state/client-password/bootstrap.d.ts +2 -0
  77. package/dist/wallet/state/client-password/bootstrap.js +3 -0
  78. package/dist/wallet/state/client-password/context.d.ts +10 -0
  79. package/dist/wallet/state/client-password/context.js +46 -0
  80. package/dist/wallet/state/client-password/crypto.d.ts +34 -0
  81. package/dist/wallet/state/client-password/crypto.js +117 -0
  82. package/dist/wallet/state/client-password/files.d.ts +10 -0
  83. package/dist/wallet/state/client-password/files.js +109 -0
  84. package/dist/wallet/state/client-password/legacy-cleanup.d.ts +11 -0
  85. package/dist/wallet/state/client-password/legacy-cleanup.js +338 -0
  86. package/dist/wallet/state/client-password/messages.d.ts +3 -0
  87. package/dist/wallet/state/client-password/messages.js +9 -0
  88. package/dist/wallet/state/client-password/migration.d.ts +4 -0
  89. package/dist/wallet/state/client-password/migration.js +32 -0
  90. package/dist/wallet/state/client-password/prompts.d.ts +12 -0
  91. package/dist/wallet/state/client-password/prompts.js +79 -0
  92. package/dist/wallet/state/client-password/protected-secrets.d.ts +13 -0
  93. package/dist/wallet/state/client-password/protected-secrets.js +90 -0
  94. package/dist/wallet/state/client-password/readiness.d.ts +4 -0
  95. package/dist/wallet/state/client-password/readiness.js +48 -0
  96. package/dist/wallet/state/client-password/references.d.ts +1 -0
  97. package/dist/wallet/state/client-password/references.js +56 -0
  98. package/dist/wallet/state/client-password/rotation.d.ts +6 -0
  99. package/dist/wallet/state/client-password/rotation.js +98 -0
  100. package/dist/wallet/state/client-password/session-policy.d.ts +6 -0
  101. package/dist/wallet/state/client-password/session-policy.js +28 -0
  102. package/dist/wallet/state/client-password/session.d.ts +19 -0
  103. package/dist/wallet/state/client-password/session.js +170 -0
  104. package/dist/wallet/state/client-password/setup.d.ts +8 -0
  105. package/dist/wallet/state/client-password/setup.js +49 -0
  106. package/dist/wallet/state/client-password/types.d.ts +82 -0
  107. package/dist/wallet/state/client-password/types.js +5 -0
  108. package/dist/wallet/state/client-password.d.ts +7 -38
  109. package/dist/wallet/state/client-password.js +52 -937
  110. package/dist/wallet/tx/anchor.js +123 -216
  111. package/dist/wallet/tx/cog.js +294 -489
  112. package/dist/wallet/tx/common.d.ts +2 -0
  113. package/dist/wallet/tx/common.js +2 -0
  114. package/dist/wallet/tx/domain-admin.js +111 -220
  115. package/dist/wallet/tx/domain-market.js +401 -681
  116. package/dist/wallet/tx/executor.d.ts +176 -0
  117. package/dist/wallet/tx/executor.js +302 -0
  118. package/dist/wallet/tx/field.js +109 -215
  119. package/dist/wallet/tx/register.js +158 -269
  120. package/dist/wallet/tx/reputation.js +120 -227
  121. package/package.json +1 -1
  122. package/dist/wallet/mining/worker-main.d.ts +0 -1
  123. package/dist/wallet/mining/worker-main.js +0 -17
  124. package/dist/wallet/state/client-password-agent.d.ts +0 -1
  125. package/dist/wallet/state/client-password-agent.js +0 -211
@@ -0,0 +1,176 @@
1
+ import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
2
+ import { createRpcClient } from "../../bitcoind/node.js";
3
+ import { openWalletReadContext, type WalletReadContext } from "../read/index.js";
4
+ import { type WalletRuntimePaths } from "../runtime.js";
5
+ import { type WalletSecretProvider } from "../state/provider.js";
6
+ import type { PendingMutationRecord, PendingMutationStatus, WalletStateV1 } from "../types.js";
7
+ import { type BuiltWalletMutationTransaction, type FixedWalletInput, type WalletMutationFeeSelection, type WalletMutationFeeSummary, type WalletMutationRpcClient } from "./common.js";
8
+ export interface WalletMutationExecutionContext<TRpc extends WalletMutationRpcClient> {
9
+ provider: WalletSecretProvider;
10
+ nowUnixMs: number;
11
+ paths: WalletRuntimePaths;
12
+ readContext: WalletReadContext;
13
+ rpc: TRpc;
14
+ walletName: string;
15
+ feeSelection: WalletMutationFeeSelection;
16
+ }
17
+ export interface WalletMutationExecutionResult<TResult, TBuilt extends BuiltWalletMutationTransaction = BuiltWalletMutationTransaction> {
18
+ result: TResult;
19
+ state: WalletStateV1;
20
+ mutation: PendingMutationRecord | null;
21
+ built: TBuilt | null;
22
+ reusedExisting: boolean;
23
+ }
24
+ export interface WalletMutationReconcileResult {
25
+ state: WalletStateV1;
26
+ mutation: PendingMutationRecord;
27
+ resolution: "confirmed" | "live" | "repair-required" | "not-seen" | "continue";
28
+ }
29
+ export interface WalletMutationPublishResult {
30
+ state: WalletStateV1;
31
+ mutation: PendingMutationRecord;
32
+ status: PendingMutationStatus;
33
+ }
34
+ export interface WalletMutationPublishRpcClient extends Pick<WalletMutationRpcClient, "lockUnspent"> {
35
+ getBlockchainInfo(): Promise<{
36
+ blocks: number;
37
+ }>;
38
+ sendRawTransaction(hex: string): Promise<string>;
39
+ }
40
+ export interface WalletMutationRuntimeOptions<TRpc extends WalletMutationRpcClient> {
41
+ dataDir: string;
42
+ databasePath: string;
43
+ provider?: WalletSecretProvider;
44
+ nowUnixMs?: number;
45
+ paths?: WalletRuntimePaths;
46
+ feeRateSatVb?: number | null;
47
+ openReadContext?: typeof openWalletReadContext;
48
+ attachService?: typeof attachOrStartManagedBitcoindService;
49
+ rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => TRpc;
50
+ }
51
+ export interface WalletMutationOperationSpec<TOperation extends {
52
+ state: WalletStateV1;
53
+ }, TRpc extends WalletMutationRpcClient, TPrepared, TBuilt extends BuiltWalletMutationTransaction, TResult> {
54
+ controlLockPurpose: string;
55
+ preemptionReason: string;
56
+ resolveOperation(readContext: WalletReadContext): Promise<TOperation> | TOperation;
57
+ createIntentFingerprint(operation: TOperation): string;
58
+ resolveExistingMutation?(options: {
59
+ operation: TOperation;
60
+ existingMutation: PendingMutationRecord | null;
61
+ execution: WalletMutationExecutionContext<TRpc>;
62
+ }): Promise<{
63
+ state: WalletStateV1;
64
+ replacementFixedInputs: FixedWalletInput[] | null;
65
+ result: TResult | null;
66
+ }>;
67
+ confirm(options: {
68
+ operation: TOperation;
69
+ existingMutation: PendingMutationRecord | null;
70
+ execution: WalletMutationExecutionContext<TRpc>;
71
+ }): Promise<void>;
72
+ createDraftMutation(options: {
73
+ operation: TOperation;
74
+ existingMutation: PendingMutationRecord | null;
75
+ execution: WalletMutationExecutionContext<TRpc>;
76
+ intentFingerprintHex: string;
77
+ }): Promise<{
78
+ mutation: PendingMutationRecord;
79
+ prepared: TPrepared;
80
+ }> | {
81
+ mutation: PendingMutationRecord;
82
+ prepared: TPrepared;
83
+ };
84
+ prepareBuildState?(options: {
85
+ operation: TOperation;
86
+ state: WalletStateV1;
87
+ execution: WalletMutationExecutionContext<TRpc>;
88
+ existingMutation: PendingMutationRecord | null;
89
+ prepared: TPrepared;
90
+ }): Promise<WalletStateV1>;
91
+ build(options: {
92
+ operation: TOperation;
93
+ state: WalletStateV1;
94
+ execution: WalletMutationExecutionContext<TRpc>;
95
+ replacementFixedInputs: FixedWalletInput[] | null;
96
+ existingMutation: PendingMutationRecord | null;
97
+ prepared: TPrepared;
98
+ }): Promise<TBuilt>;
99
+ beforePublish?(options: {
100
+ operation: TOperation;
101
+ state: WalletStateV1;
102
+ execution: WalletMutationExecutionContext<TRpc>;
103
+ built: TBuilt;
104
+ mutation: PendingMutationRecord;
105
+ prepared: TPrepared;
106
+ }): Promise<void>;
107
+ publish(options: {
108
+ operation: TOperation;
109
+ state: WalletStateV1;
110
+ execution: WalletMutationExecutionContext<TRpc>;
111
+ built: TBuilt;
112
+ mutation: PendingMutationRecord;
113
+ prepared: TPrepared;
114
+ }): Promise<WalletMutationPublishResult>;
115
+ createResult(options: {
116
+ operation: TOperation;
117
+ state: WalletStateV1;
118
+ mutation: PendingMutationRecord;
119
+ execution: WalletMutationExecutionContext<TRpc>;
120
+ built: TBuilt | null;
121
+ status: PendingMutationStatus;
122
+ reusedExisting: boolean;
123
+ fees: WalletMutationFeeSummary;
124
+ prepared: TPrepared | null;
125
+ }): TResult;
126
+ }
127
+ export declare function persistWalletMutationState(options: {
128
+ state: WalletStateV1;
129
+ provider: WalletSecretProvider;
130
+ nowUnixMs: number;
131
+ paths: WalletRuntimePaths;
132
+ }): Promise<WalletStateV1>;
133
+ export declare function resolveExistingWalletMutation<TRpc extends Pick<WalletMutationRpcClient, "getMempoolEntry" | "getTransaction" | "getRawTransaction">, TResult>(options: {
134
+ existingMutation: PendingMutationRecord | null;
135
+ execution: {
136
+ rpc: TRpc;
137
+ walletName: string;
138
+ feeSelection: WalletMutationFeeSelection;
139
+ };
140
+ repairRequiredErrorCode: string;
141
+ reconcileExistingMutation(existingMutation: PendingMutationRecord): Promise<WalletMutationReconcileResult>;
142
+ createReuseResult(options: {
143
+ mutation: PendingMutationRecord;
144
+ resolution: "confirmed" | "live";
145
+ fees: WalletMutationFeeSummary;
146
+ }): TResult;
147
+ }): Promise<{
148
+ state: WalletStateV1;
149
+ replacementFixedInputs: FixedWalletInput[] | null;
150
+ result: TResult | null;
151
+ }>;
152
+ export declare function publishWalletMutation<TRpc extends WalletMutationPublishRpcClient>(options: {
153
+ rpc: TRpc;
154
+ walletName: string;
155
+ snapshotHeight: number | null;
156
+ built: BuiltWalletMutationTransaction;
157
+ mutation: PendingMutationRecord;
158
+ state: WalletStateV1;
159
+ provider: WalletSecretProvider;
160
+ nowUnixMs: number;
161
+ paths: WalletRuntimePaths;
162
+ errorPrefix: string;
163
+ afterAccepted?(options: {
164
+ state: WalletStateV1;
165
+ broadcastingMutation: PendingMutationRecord;
166
+ built: BuiltWalletMutationTransaction;
167
+ nowUnixMs: number;
168
+ }): Promise<{
169
+ state: WalletStateV1;
170
+ mutation: PendingMutationRecord;
171
+ status: PendingMutationStatus;
172
+ }>;
173
+ }): Promise<WalletMutationPublishResult>;
174
+ export declare function executeWalletMutationOperation<TOperation extends {
175
+ state: WalletStateV1;
176
+ }, TRpc extends WalletMutationRpcClient, TPrepared, TBuilt extends BuiltWalletMutationTransaction, TResult>(options: WalletMutationRuntimeOptions<TRpc> & WalletMutationOperationSpec<TOperation, TRpc, TPrepared, TBuilt, TResult>): Promise<WalletMutationExecutionResult<TResult, TBuilt>>;
@@ -0,0 +1,302 @@
1
+ import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
2
+ import { createRpcClient } from "../../bitcoind/node.js";
3
+ import { acquireFileLock } from "../fs/lock.js";
4
+ import { openWalletReadContext, } from "../read/index.js";
5
+ import { resolveWalletRuntimePathsForTesting, } from "../runtime.js";
6
+ import { createDefaultWalletSecretProvider, } from "../state/provider.js";
7
+ import { createBuiltWalletMutationFeeSummary, isAlreadyAcceptedError, isBroadcastUnknownError, pauseMiningForWalletMutation, resolvePendingMutationReuseDecision, resolveWalletMutationFeeSelection, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
8
+ import { findPendingMutationByIntent, upsertPendingMutation, } from "./journal.js";
9
+ export async function persistWalletMutationState(options) {
10
+ const nextState = {
11
+ ...options.state,
12
+ stateRevision: options.state.stateRevision + 1,
13
+ lastWrittenAtUnixMs: options.nowUnixMs,
14
+ };
15
+ await saveWalletStatePreservingUnlock({
16
+ state: nextState,
17
+ provider: options.provider,
18
+ nowUnixMs: options.nowUnixMs,
19
+ paths: options.paths,
20
+ });
21
+ return nextState;
22
+ }
23
+ export async function resolveExistingWalletMutation(options) {
24
+ if (options.existingMutation === null) {
25
+ throw new Error("wallet_mutation_existing_required");
26
+ }
27
+ const reconciled = await options.reconcileExistingMutation(options.existingMutation);
28
+ if (reconciled.resolution === "repair-required") {
29
+ throw new Error(options.repairRequiredErrorCode);
30
+ }
31
+ if (reconciled.resolution !== "confirmed" && reconciled.resolution !== "live") {
32
+ return {
33
+ state: reconciled.state,
34
+ replacementFixedInputs: null,
35
+ result: null,
36
+ };
37
+ }
38
+ const reuse = await resolvePendingMutationReuseDecision({
39
+ rpc: options.execution.rpc,
40
+ walletName: options.execution.walletName,
41
+ mutation: reconciled.mutation,
42
+ nextFeeSelection: options.execution.feeSelection,
43
+ });
44
+ if (reuse.reuseExisting) {
45
+ return {
46
+ state: reconciled.state,
47
+ replacementFixedInputs: null,
48
+ result: options.createReuseResult({
49
+ mutation: reconciled.mutation,
50
+ resolution: reconciled.resolution,
51
+ fees: reuse.fees,
52
+ }),
53
+ };
54
+ }
55
+ return {
56
+ state: reconciled.state,
57
+ replacementFixedInputs: reuse.replacementFixedInputs,
58
+ result: null,
59
+ };
60
+ }
61
+ export async function publishWalletMutation(options) {
62
+ let nextState = options.state;
63
+ const broadcastingMutation = updateMutationRecord(options.mutation, "broadcasting", options.nowUnixMs, {
64
+ attemptedTxid: options.built.txid,
65
+ attemptedWtxid: options.built.wtxid,
66
+ temporaryBuilderLockedOutpoints: options.built.temporaryBuilderLockedOutpoints,
67
+ });
68
+ nextState = await persistWalletMutationState({
69
+ state: upsertPendingMutation(nextState, broadcastingMutation),
70
+ provider: options.provider,
71
+ nowUnixMs: options.nowUnixMs,
72
+ paths: options.paths,
73
+ });
74
+ if (options.snapshotHeight !== null
75
+ && options.snapshotHeight !== (await options.rpc.getBlockchainInfo()).blocks) {
76
+ await unlockTemporaryBuilderLocks(options.rpc, options.walletName, options.built.temporaryBuilderLockedOutpoints);
77
+ throw new Error(`${options.errorPrefix}_tip_mismatch`);
78
+ }
79
+ try {
80
+ await options.rpc.sendRawTransaction(options.built.rawHex);
81
+ }
82
+ catch (error) {
83
+ if (!isAlreadyAcceptedError(error)) {
84
+ if (isBroadcastUnknownError(error)) {
85
+ const unknownMutation = updateMutationRecord(broadcastingMutation, "broadcast-unknown", options.nowUnixMs, {
86
+ attemptedTxid: options.built.txid,
87
+ attemptedWtxid: options.built.wtxid,
88
+ temporaryBuilderLockedOutpoints: options.built.temporaryBuilderLockedOutpoints,
89
+ });
90
+ nextState = await persistWalletMutationState({
91
+ state: upsertPendingMutation(nextState, unknownMutation),
92
+ provider: options.provider,
93
+ nowUnixMs: options.nowUnixMs,
94
+ paths: options.paths,
95
+ });
96
+ throw new Error(`${options.errorPrefix}_broadcast_unknown`);
97
+ }
98
+ await unlockTemporaryBuilderLocks(options.rpc, options.walletName, options.built.temporaryBuilderLockedOutpoints);
99
+ const canceledMutation = updateMutationRecord(broadcastingMutation, "canceled", options.nowUnixMs, {
100
+ attemptedTxid: options.built.txid,
101
+ attemptedWtxid: options.built.wtxid,
102
+ temporaryBuilderLockedOutpoints: [],
103
+ });
104
+ nextState = await persistWalletMutationState({
105
+ state: upsertPendingMutation(nextState, canceledMutation),
106
+ provider: options.provider,
107
+ nowUnixMs: options.nowUnixMs,
108
+ paths: options.paths,
109
+ });
110
+ throw error;
111
+ }
112
+ }
113
+ await unlockTemporaryBuilderLocks(options.rpc, options.walletName, options.built.temporaryBuilderLockedOutpoints);
114
+ const accepted = options.afterAccepted === undefined
115
+ ? {
116
+ state: upsertPendingMutation(nextState, updateMutationRecord(broadcastingMutation, "live", options.nowUnixMs, {
117
+ attemptedTxid: options.built.txid,
118
+ attemptedWtxid: options.built.wtxid,
119
+ temporaryBuilderLockedOutpoints: [],
120
+ })),
121
+ mutation: updateMutationRecord(broadcastingMutation, "live", options.nowUnixMs, {
122
+ attemptedTxid: options.built.txid,
123
+ attemptedWtxid: options.built.wtxid,
124
+ temporaryBuilderLockedOutpoints: [],
125
+ }),
126
+ status: "live",
127
+ }
128
+ : await options.afterAccepted({
129
+ state: nextState,
130
+ broadcastingMutation,
131
+ built: options.built,
132
+ nowUnixMs: options.nowUnixMs,
133
+ });
134
+ const persistedState = await persistWalletMutationState({
135
+ state: accepted.state,
136
+ provider: options.provider,
137
+ nowUnixMs: options.nowUnixMs,
138
+ paths: options.paths,
139
+ });
140
+ return {
141
+ state: persistedState,
142
+ mutation: accepted.mutation,
143
+ status: accepted.status,
144
+ };
145
+ }
146
+ export async function executeWalletMutationOperation(options) {
147
+ const provider = options.provider ?? createDefaultWalletSecretProvider();
148
+ const nowUnixMs = options.nowUnixMs ?? Date.now();
149
+ const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
150
+ const controlLock = await acquireFileLock(paths.walletControlLockPath, {
151
+ purpose: options.controlLockPurpose,
152
+ walletRootId: null,
153
+ });
154
+ try {
155
+ const miningPreemption = await pauseMiningForWalletMutation({
156
+ paths,
157
+ reason: options.preemptionReason,
158
+ });
159
+ const readContext = await (options.openReadContext ?? openWalletReadContext)({
160
+ dataDir: options.dataDir,
161
+ databasePath: options.databasePath,
162
+ secretProvider: provider,
163
+ walletControlLockHeld: true,
164
+ paths,
165
+ });
166
+ try {
167
+ const operation = await options.resolveOperation(readContext);
168
+ const node = await (options.attachService ?? attachOrStartManagedBitcoindService)({
169
+ dataDir: options.dataDir,
170
+ chain: "main",
171
+ startHeight: 0,
172
+ walletRootId: operation.state.walletRootId,
173
+ });
174
+ const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
175
+ const execution = {
176
+ provider,
177
+ nowUnixMs,
178
+ paths,
179
+ readContext,
180
+ rpc,
181
+ walletName: operation.state.managedCoreWallet.walletName,
182
+ feeSelection: await resolveWalletMutationFeeSelection({
183
+ rpc,
184
+ feeRateSatVb: options.feeRateSatVb ?? null,
185
+ }),
186
+ };
187
+ const intentFingerprintHex = options.createIntentFingerprint(operation);
188
+ const existingMutation = findPendingMutationByIntent(operation.state, intentFingerprintHex);
189
+ let workingState = operation.state;
190
+ let replacementFixedInputs = null;
191
+ if (options.resolveExistingMutation !== undefined) {
192
+ const existingResolution = await options.resolveExistingMutation({
193
+ operation,
194
+ existingMutation,
195
+ execution,
196
+ });
197
+ workingState = existingResolution.state;
198
+ replacementFixedInputs = existingResolution.replacementFixedInputs;
199
+ if (existingResolution.result !== null && existingMutation !== null) {
200
+ return {
201
+ result: existingResolution.result,
202
+ state: workingState,
203
+ mutation: existingMutation,
204
+ built: null,
205
+ reusedExisting: true,
206
+ };
207
+ }
208
+ }
209
+ await options.confirm({
210
+ operation,
211
+ existingMutation,
212
+ execution,
213
+ });
214
+ const draft = await options.createDraftMutation({
215
+ operation,
216
+ existingMutation,
217
+ execution,
218
+ intentFingerprintHex,
219
+ });
220
+ let nextState = upsertPendingMutation(workingState, draft.mutation);
221
+ nextState = await persistWalletMutationState({
222
+ state: nextState,
223
+ provider,
224
+ nowUnixMs,
225
+ paths,
226
+ });
227
+ if (options.prepareBuildState !== undefined) {
228
+ nextState = await options.prepareBuildState({
229
+ operation,
230
+ state: nextState,
231
+ execution,
232
+ existingMutation,
233
+ prepared: draft.prepared,
234
+ });
235
+ }
236
+ const currentMutation = nextState.pendingMutations?.find((mutation) => mutation.intentFingerprintHex === intentFingerprintHex);
237
+ if (currentMutation === undefined) {
238
+ throw new Error("wallet_mutation_draft_missing");
239
+ }
240
+ const built = await options.build({
241
+ operation,
242
+ state: nextState,
243
+ execution,
244
+ replacementFixedInputs,
245
+ existingMutation,
246
+ prepared: draft.prepared,
247
+ });
248
+ if (options.beforePublish !== undefined) {
249
+ try {
250
+ await options.beforePublish({
251
+ operation,
252
+ state: nextState,
253
+ execution,
254
+ built,
255
+ mutation: currentMutation,
256
+ prepared: draft.prepared,
257
+ });
258
+ }
259
+ catch (error) {
260
+ await unlockTemporaryBuilderLocks(execution.rpc, execution.walletName, built.temporaryBuilderLockedOutpoints);
261
+ throw error;
262
+ }
263
+ }
264
+ const published = await options.publish({
265
+ operation,
266
+ state: nextState,
267
+ execution,
268
+ built,
269
+ mutation: currentMutation,
270
+ prepared: draft.prepared,
271
+ });
272
+ const result = options.createResult({
273
+ operation,
274
+ state: published.state,
275
+ mutation: published.mutation,
276
+ execution,
277
+ built,
278
+ status: published.status,
279
+ reusedExisting: false,
280
+ fees: createBuiltWalletMutationFeeSummary({
281
+ selection: execution.feeSelection,
282
+ built,
283
+ }),
284
+ prepared: draft.prepared,
285
+ });
286
+ return {
287
+ result,
288
+ state: published.state,
289
+ mutation: published.mutation,
290
+ built,
291
+ reusedExisting: false,
292
+ };
293
+ }
294
+ finally {
295
+ await readContext.close();
296
+ await miningPreemption.release();
297
+ }
298
+ }
299
+ finally {
300
+ await controlLock.release();
301
+ }
302
+ }