@cogcoin/client 1.1.6 → 1.1.7

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 (109) 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 +46 -126
  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-types.d.ts +1 -0
  46. package/dist/wallet/mining/index.d.ts +1 -1
  47. package/dist/wallet/mining/index.js +1 -1
  48. package/dist/wallet/mining/publish.d.ts +3 -0
  49. package/dist/wallet/mining/publish.js +78 -6
  50. package/dist/wallet/mining/runner.d.ts +0 -32
  51. package/dist/wallet/mining/runner.js +59 -104
  52. package/dist/wallet/mining/stop.d.ts +7 -0
  53. package/dist/wallet/mining/stop.js +23 -0
  54. package/dist/wallet/mining/supervisor.d.ts +2 -36
  55. package/dist/wallet/mining/supervisor.js +139 -246
  56. package/dist/wallet/read/context.d.ts +1 -5
  57. package/dist/wallet/read/context.js +20 -204
  58. package/dist/wallet/read/managed-services.d.ts +33 -0
  59. package/dist/wallet/read/managed-services.js +222 -0
  60. package/dist/wallet/state/client-password/bootstrap.d.ts +2 -0
  61. package/dist/wallet/state/client-password/bootstrap.js +3 -0
  62. package/dist/wallet/state/client-password/context.d.ts +10 -0
  63. package/dist/wallet/state/client-password/context.js +46 -0
  64. package/dist/wallet/state/client-password/crypto.d.ts +34 -0
  65. package/dist/wallet/state/client-password/crypto.js +117 -0
  66. package/dist/wallet/state/client-password/files.d.ts +10 -0
  67. package/dist/wallet/state/client-password/files.js +109 -0
  68. package/dist/wallet/state/client-password/legacy-cleanup.d.ts +11 -0
  69. package/dist/wallet/state/client-password/legacy-cleanup.js +338 -0
  70. package/dist/wallet/state/client-password/messages.d.ts +3 -0
  71. package/dist/wallet/state/client-password/messages.js +9 -0
  72. package/dist/wallet/state/client-password/migration.d.ts +4 -0
  73. package/dist/wallet/state/client-password/migration.js +32 -0
  74. package/dist/wallet/state/client-password/prompts.d.ts +12 -0
  75. package/dist/wallet/state/client-password/prompts.js +79 -0
  76. package/dist/wallet/state/client-password/protected-secrets.d.ts +13 -0
  77. package/dist/wallet/state/client-password/protected-secrets.js +90 -0
  78. package/dist/wallet/state/client-password/readiness.d.ts +4 -0
  79. package/dist/wallet/state/client-password/readiness.js +48 -0
  80. package/dist/wallet/state/client-password/references.d.ts +1 -0
  81. package/dist/wallet/state/client-password/references.js +56 -0
  82. package/dist/wallet/state/client-password/rotation.d.ts +6 -0
  83. package/dist/wallet/state/client-password/rotation.js +98 -0
  84. package/dist/wallet/state/client-password/session-policy.d.ts +6 -0
  85. package/dist/wallet/state/client-password/session-policy.js +28 -0
  86. package/dist/wallet/state/client-password/session.d.ts +19 -0
  87. package/dist/wallet/state/client-password/session.js +170 -0
  88. package/dist/wallet/state/client-password/setup.d.ts +8 -0
  89. package/dist/wallet/state/client-password/setup.js +49 -0
  90. package/dist/wallet/state/client-password/types.d.ts +82 -0
  91. package/dist/wallet/state/client-password/types.js +5 -0
  92. package/dist/wallet/state/client-password.d.ts +7 -38
  93. package/dist/wallet/state/client-password.js +52 -937
  94. package/dist/wallet/tx/anchor.js +123 -216
  95. package/dist/wallet/tx/cog.js +294 -489
  96. package/dist/wallet/tx/common.d.ts +2 -0
  97. package/dist/wallet/tx/common.js +2 -0
  98. package/dist/wallet/tx/domain-admin.js +111 -220
  99. package/dist/wallet/tx/domain-market.js +401 -681
  100. package/dist/wallet/tx/executor.d.ts +176 -0
  101. package/dist/wallet/tx/executor.js +302 -0
  102. package/dist/wallet/tx/field.js +109 -215
  103. package/dist/wallet/tx/register.js +158 -269
  104. package/dist/wallet/tx/reputation.js +120 -227
  105. package/package.json +1 -1
  106. package/dist/wallet/mining/worker-main.d.ts +0 -1
  107. package/dist/wallet/mining/worker-main.js +0 -17
  108. package/dist/wallet/state/client-password-agent.d.ts +0 -1
  109. 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
+ }