@cogcoin/client 0.5.15 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -25
- package/dist/app-paths.d.ts +5 -6
- package/dist/app-paths.js +8 -16
- package/dist/art/balance.txt +10 -0
- package/dist/art/welcome.txt +16 -0
- package/dist/bitcoind/bootstrap/controller.d.ts +1 -0
- package/dist/bitcoind/bootstrap/controller.js +53 -1
- package/dist/bitcoind/client/follow-block-times.d.ts +1 -0
- package/dist/bitcoind/client/follow-block-times.js +1 -1
- package/dist/bitcoind/client/internal-types.d.ts +7 -3
- package/dist/bitcoind/client/managed-client.d.ts +4 -2
- package/dist/bitcoind/client/managed-client.js +14 -0
- package/dist/bitcoind/client/sync-engine.js +72 -11
- package/dist/bitcoind/hash-order.d.ts +4 -0
- package/dist/bitcoind/hash-order.js +13 -0
- package/dist/bitcoind/indexer-daemon-main.js +11 -3
- package/dist/bitcoind/normalize.js +3 -2
- package/dist/bitcoind/processing-start-height.d.ts +5 -0
- package/dist/bitcoind/processing-start-height.js +7 -0
- package/dist/bitcoind/progress/constants.d.ts +4 -0
- package/dist/bitcoind/progress/constants.js +4 -0
- package/dist/bitcoind/progress/controller.d.ts +2 -1
- package/dist/bitcoind/progress/controller.js +3 -3
- package/dist/bitcoind/progress/follow-scene.d.ts +6 -2
- package/dist/bitcoind/progress/follow-scene.js +29 -6
- package/dist/bitcoind/progress/formatting.d.ts +1 -0
- package/dist/bitcoind/progress/formatting.js +6 -0
- package/dist/bitcoind/progress/train-scene.js +37 -18
- package/dist/bitcoind/progress/tty-renderer.d.ts +6 -1
- package/dist/bitcoind/progress/tty-renderer.js +8 -4
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +3 -0
- package/dist/bitcoind/types.d.ts +6 -0
- package/dist/bytes.d.ts +1 -0
- package/dist/bytes.js +3 -0
- package/dist/cli/art.d.ts +2 -0
- package/dist/cli/art.js +37 -0
- package/dist/cli/commands/client-admin.d.ts +2 -0
- package/dist/cli/commands/client-admin.js +91 -0
- package/dist/cli/commands/follow.js +0 -2
- package/dist/cli/commands/mining-admin.js +6 -47
- package/dist/cli/commands/mining-read.js +11 -50
- package/dist/cli/commands/mining-runtime.js +142 -5
- package/dist/cli/commands/service-runtime.js +0 -2
- package/dist/cli/commands/status.js +8 -2
- package/dist/cli/commands/sync.js +49 -92
- package/dist/cli/commands/wallet-admin.js +142 -136
- package/dist/cli/commands/wallet-mutation.js +91 -79
- package/dist/cli/commands/wallet-read.js +15 -18
- package/dist/cli/context.js +5 -14
- package/dist/cli/mining-format.d.ts +0 -1
- package/dist/cli/mining-format.js +5 -37
- package/dist/cli/mining-json.d.ts +0 -18
- package/dist/cli/mining-json.js +0 -35
- package/dist/cli/mutation-command-groups.d.ts +1 -2
- package/dist/cli/mutation-command-groups.js +0 -5
- package/dist/cli/mutation-json.d.ts +24 -145
- package/dist/cli/mutation-json.js +30 -136
- package/dist/cli/mutation-resolved-json.d.ts +0 -7
- package/dist/cli/mutation-resolved-json.js +4 -10
- package/dist/cli/mutation-success.d.ts +2 -0
- package/dist/cli/mutation-success.js +11 -1
- package/dist/cli/mutation-text-format.js +1 -3
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js +254 -231
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +93 -122
- package/dist/cli/preview-json.d.ts +17 -120
- package/dist/cli/preview-json.js +14 -97
- package/dist/cli/prompt.js +8 -13
- package/dist/cli/read-json.d.ts +15 -37
- package/dist/cli/read-json.js +44 -140
- package/dist/cli/runner.js +10 -13
- package/dist/cli/sync-progress.d.ts +6 -0
- package/dist/cli/sync-progress.js +91 -0
- package/dist/cli/types.d.ts +9 -17
- package/dist/cli/types.js +0 -2
- package/dist/cli/wallet-format.d.ts +1 -0
- package/dist/cli/wallet-format.js +208 -144
- package/dist/cli/workflow-hints.d.ts +3 -3
- package/dist/cli/workflow-hints.js +11 -8
- package/dist/client/default-client.d.ts +3 -1
- package/dist/client/default-client.js +45 -2
- package/dist/client/factory.js +1 -1
- package/dist/client/initialization.js +23 -0
- package/dist/client/persistence.js +5 -5
- package/dist/client/store-adapter.js +1 -0
- package/dist/sqlite/checkpoints.d.ts +1 -0
- package/dist/sqlite/checkpoints.js +7 -0
- package/dist/sqlite/store.js +14 -1
- package/dist/types.d.ts +1 -0
- package/dist/wallet/coin-control.d.ts +41 -12
- package/dist/wallet/coin-control.js +100 -428
- package/dist/wallet/descriptor-normalization.d.ts +1 -3
- package/dist/wallet/descriptor-normalization.js +0 -16
- package/dist/wallet/lifecycle.d.ts +7 -99
- package/dist/wallet/lifecycle.js +513 -968
- package/dist/wallet/managed-core-wallet.d.ts +13 -0
- package/dist/wallet/managed-core-wallet.js +20 -0
- package/dist/wallet/mining/constants.d.ts +5 -12
- package/dist/wallet/mining/constants.js +5 -12
- package/dist/wallet/mining/control.d.ts +1 -13
- package/dist/wallet/mining/control.js +45 -349
- package/dist/wallet/mining/index.d.ts +4 -5
- package/dist/wallet/mining/index.js +2 -3
- package/dist/wallet/mining/runner.d.ts +123 -13
- package/dist/wallet/mining/runner.js +899 -511
- package/dist/wallet/mining/runtime-artifacts.js +23 -3
- package/dist/wallet/mining/sentence-protocol.d.ts +44 -0
- package/dist/wallet/mining/sentence-protocol.js +123 -0
- package/dist/wallet/mining/sentences.d.ts +4 -8
- package/dist/wallet/mining/sentences.js +3 -52
- package/dist/wallet/mining/state.d.ts +11 -6
- package/dist/wallet/mining/state.js +7 -6
- package/dist/wallet/mining/types.d.ts +2 -30
- package/dist/wallet/mining/visualizer.d.ts +31 -3
- package/dist/wallet/mining/visualizer.js +135 -13
- package/dist/wallet/read/context.d.ts +0 -2
- package/dist/wallet/read/context.js +119 -140
- package/dist/wallet/read/filter.js +2 -11
- package/dist/wallet/read/index.d.ts +1 -1
- package/dist/wallet/read/project.js +24 -77
- package/dist/wallet/read/types.d.ts +10 -25
- package/dist/wallet/reset.d.ts +0 -1
- package/dist/wallet/reset.js +60 -138
- package/dist/wallet/root-resolution.d.ts +1 -5
- package/dist/wallet/root-resolution.js +0 -18
- package/dist/wallet/runtime.d.ts +0 -6
- package/dist/wallet/runtime.js +0 -8
- package/dist/wallet/state/client-password-agent.js +208 -0
- package/dist/wallet/state/client-password.d.ts +65 -0
- package/dist/wallet/state/client-password.js +952 -0
- package/dist/wallet/state/crypto.d.ts +1 -20
- package/dist/wallet/state/crypto.js +0 -63
- package/dist/wallet/state/provider.d.ts +23 -11
- package/dist/wallet/state/provider.js +248 -290
- package/dist/wallet/state/storage.d.ts +2 -2
- package/dist/wallet/state/storage.js +48 -16
- package/dist/wallet/tx/anchor.d.ts +3 -28
- package/dist/wallet/tx/anchor.js +349 -1250
- package/dist/wallet/tx/bitcoin-transfer.d.ts +35 -0
- package/dist/wallet/tx/bitcoin-transfer.js +200 -0
- package/dist/wallet/tx/cog.d.ts +5 -1
- package/dist/wallet/tx/cog.js +149 -185
- package/dist/wallet/tx/common.d.ts +61 -8
- package/dist/wallet/tx/common.js +266 -146
- package/dist/wallet/tx/domain-admin.d.ts +3 -1
- package/dist/wallet/tx/domain-admin.js +61 -99
- package/dist/wallet/tx/domain-market.d.ts +5 -1
- package/dist/wallet/tx/domain-market.js +221 -228
- package/dist/wallet/tx/field.d.ts +4 -10
- package/dist/wallet/tx/field.js +83 -924
- package/dist/wallet/tx/identity-selector.d.ts +9 -3
- package/dist/wallet/tx/identity-selector.js +17 -35
- package/dist/wallet/tx/index.d.ts +3 -1
- package/dist/wallet/tx/index.js +2 -1
- package/dist/wallet/tx/register.d.ts +3 -1
- package/dist/wallet/tx/register.js +62 -220
- package/dist/wallet/tx/reputation.d.ts +3 -1
- package/dist/wallet/tx/reputation.js +58 -95
- package/dist/wallet/types.d.ts +8 -122
- package/package.json +5 -5
- package/dist/wallet/archive.d.ts +0 -4
- package/dist/wallet/archive.js +0 -41
- package/dist/wallet/mining/hook-protocol.d.ts +0 -47
- package/dist/wallet/mining/hook-protocol.js +0 -161
- package/dist/wallet/mining/hook-runner.js +0 -52
- package/dist/wallet/mining/hooks.d.ts +0 -38
- package/dist/wallet/mining/hooks.js +0 -520
- package/dist/wallet/state/explicit-lock.d.ts +0 -4
- package/dist/wallet/state/explicit-lock.js +0 -19
- package/dist/wallet/state/session.d.ts +0 -12
- package/dist/wallet/state/session.js +0 -23
- /package/dist/wallet/{mining/hook-runner.d.ts → state/client-password-agent.d.ts} +0 -0
|
@@ -1,20 +1,34 @@
|
|
|
1
|
-
import type { RpcDecodedPsbt, RpcFinalizePsbtResult, RpcListUnspentEntry, RpcLockedUnspent, RpcTestMempoolAcceptResult, RpcTransaction, RpcVin, RpcWalletCreateFundedPsbtResult, RpcWalletTransaction, RpcWalletProcessPsbtResult } from "../../bitcoind/types.js";
|
|
1
|
+
import type { RpcDecodedPsbt, RpcEstimateSmartFeeResult, RpcFinalizePsbtResult, RpcListUnspentEntry, RpcLockedUnspent, RpcMempoolEntry, RpcTestMempoolAcceptResult, RpcTransaction, RpcVin, RpcWalletCreateFundedPsbtResult, RpcWalletTransaction, RpcWalletProcessPsbtResult } from "../../bitcoind/types.js";
|
|
2
2
|
import { type WalletSecretProvider } from "../state/provider.js";
|
|
3
3
|
import type { OutpointRecord, PendingMutationRecord, PendingMutationStatus, WalletStateV1 } from "../types.js";
|
|
4
4
|
import type { WalletReadContext } from "../read/index.js";
|
|
5
5
|
import type { WalletRuntimePaths } from "../runtime.js";
|
|
6
6
|
import { type MiningPreemptionHandle } from "../mining/coordination.js";
|
|
7
7
|
export declare const DEFAULT_WALLET_MUTATION_FEE_RATE_SAT_VB = 10;
|
|
8
|
+
export declare const NEXT_BLOCK_FEE_CONFIRM_TARGET = 1;
|
|
9
|
+
export type WalletMutationFeeSelectionSource = "custom-satvb" | "estimated-next-block-plus-one" | "fallback-default";
|
|
10
|
+
export interface WalletMutationFeeSelection {
|
|
11
|
+
feeRateSatVb: number;
|
|
12
|
+
source: WalletMutationFeeSelectionSource;
|
|
13
|
+
}
|
|
14
|
+
export interface WalletMutationFeeSummary extends WalletMutationFeeSelection {
|
|
15
|
+
feeSats: string | null;
|
|
16
|
+
}
|
|
8
17
|
export interface MutationSender {
|
|
9
18
|
localIndex: number;
|
|
10
19
|
scriptPubKeyHex: string;
|
|
11
20
|
address: string;
|
|
12
21
|
}
|
|
22
|
+
export declare function isLocalWalletScript(state: WalletStateV1, scriptPubKeyHex: string | null | undefined): boolean;
|
|
23
|
+
export declare function createFundingMutationSender(state: WalletStateV1): MutationSender;
|
|
13
24
|
export interface WalletMutationRpcClient {
|
|
14
25
|
listUnspent(walletName: string, minConf?: number): Promise<RpcListUnspentEntry[]>;
|
|
15
|
-
listLockUnspent(walletName: string): Promise<RpcLockedUnspent[]>;
|
|
16
|
-
lockUnspent(walletName: string, unlock: boolean, outputs: RpcLockedUnspent[]): Promise<boolean>;
|
|
26
|
+
listLockUnspent?(walletName: string): Promise<RpcLockedUnspent[]>;
|
|
27
|
+
lockUnspent?(walletName: string, unlock: boolean, outputs: RpcLockedUnspent[]): Promise<boolean>;
|
|
17
28
|
getTransaction?(walletName: string, txid: string): Promise<RpcWalletTransaction>;
|
|
29
|
+
getRawTransaction?(txid: string, verbose?: boolean): Promise<RpcTransaction>;
|
|
30
|
+
getMempoolEntry?(txid: string): Promise<RpcMempoolEntry>;
|
|
31
|
+
estimateSmartFee?(confirmTarget: number, mode: "conservative" | "economical"): Promise<RpcEstimateSmartFeeResult>;
|
|
18
32
|
walletCreateFundedPsbt(walletName: string, inputs: Array<{
|
|
19
33
|
txid: string;
|
|
20
34
|
vout: number;
|
|
@@ -38,11 +52,44 @@ export interface BuiltWalletMutationTransaction {
|
|
|
38
52
|
}
|
|
39
53
|
export interface FixedWalletInput extends OutpointRecord {
|
|
40
54
|
}
|
|
55
|
+
export declare function formatSatVb(value: number): string;
|
|
56
|
+
export declare function createWalletMutationFeeMetadata(selection: WalletMutationFeeSelection): {
|
|
57
|
+
selectedFeeRateSatVb: number;
|
|
58
|
+
feeSelectionSource: WalletMutationFeeSelectionSource;
|
|
59
|
+
};
|
|
60
|
+
export declare function resolveWalletMutationFeeSelection(options: {
|
|
61
|
+
rpc: Pick<WalletMutationRpcClient, "estimateSmartFee">;
|
|
62
|
+
feeRateSatVb?: number | null;
|
|
63
|
+
}): Promise<WalletMutationFeeSelection>;
|
|
64
|
+
export declare function createWalletMutationFeeSummary(selection: WalletMutationFeeSelection, feeSats: string | null): WalletMutationFeeSummary;
|
|
65
|
+
export declare function createBuiltWalletMutationFeeSummary(options: {
|
|
66
|
+
selection: WalletMutationFeeSelection;
|
|
67
|
+
built: BuiltWalletMutationTransaction;
|
|
68
|
+
}): WalletMutationFeeSummary;
|
|
69
|
+
export declare function resolvePendingMutationFeeSummary(options: {
|
|
70
|
+
rpc: Pick<WalletMutationRpcClient, "getMempoolEntry">;
|
|
71
|
+
mutation: PendingMutationRecord;
|
|
72
|
+
}): Promise<WalletMutationFeeSummary>;
|
|
73
|
+
export declare function loadAttemptedMutationFixedInputs(options: {
|
|
74
|
+
rpc: Pick<WalletMutationRpcClient, "getTransaction" | "getRawTransaction">;
|
|
75
|
+
walletName: string;
|
|
76
|
+
mutation: PendingMutationRecord;
|
|
77
|
+
}): Promise<FixedWalletInput[] | null>;
|
|
78
|
+
export declare function resolvePendingMutationReuseDecision(options: {
|
|
79
|
+
rpc: Pick<WalletMutationRpcClient, "getMempoolEntry" | "getTransaction" | "getRawTransaction">;
|
|
80
|
+
walletName: string;
|
|
81
|
+
mutation: PendingMutationRecord;
|
|
82
|
+
nextFeeSelection: WalletMutationFeeSelection;
|
|
83
|
+
}): Promise<{
|
|
84
|
+
reuseExisting: boolean;
|
|
85
|
+
fees: WalletMutationFeeSummary;
|
|
86
|
+
replacementFixedInputs: FixedWalletInput[] | null;
|
|
87
|
+
}>;
|
|
88
|
+
export declare function mergeFixedWalletInputs(fixedInputs: readonly FixedWalletInput[], replacementInputs: readonly FixedWalletInput[] | null): FixedWalletInput[];
|
|
41
89
|
export declare function saveWalletStatePreservingUnlock(options: {
|
|
42
90
|
state: WalletStateV1;
|
|
43
91
|
provider: WalletSecretProvider;
|
|
44
|
-
|
|
45
|
-
nowUnixMs: number;
|
|
92
|
+
nowUnixMs?: number;
|
|
46
93
|
paths: WalletRuntimePaths;
|
|
47
94
|
}): Promise<void>;
|
|
48
95
|
export declare function formatCogAmount(value: bigint): string;
|
|
@@ -57,6 +104,8 @@ export declare function updateMutationRecord(mutation: PendingMutationRecord, st
|
|
|
57
104
|
attemptedTxid?: string | null;
|
|
58
105
|
attemptedWtxid?: string | null;
|
|
59
106
|
temporaryBuilderLockedOutpoints?: OutpointRecord[];
|
|
107
|
+
selectedFeeRateSatVb?: number | null;
|
|
108
|
+
feeSelectionSource?: WalletMutationFeeSelectionSource | null;
|
|
60
109
|
}): PendingMutationRecord;
|
|
61
110
|
export declare function unlockTemporaryBuilderLocks(rpc: Pick<WalletMutationRpcClient, "lockUnspent">, walletName: string, outpoints: OutpointRecord[]): Promise<void>;
|
|
62
111
|
export declare function diffTemporaryLockedOutpoints(before: RpcLockedUnspent[], after: RpcLockedUnspent[]): OutpointRecord[];
|
|
@@ -86,11 +135,16 @@ export declare function assertWalletMutationContextReady(context: WalletReadCont
|
|
|
86
135
|
localState: {
|
|
87
136
|
availability: "ready";
|
|
88
137
|
state: WalletStateV1;
|
|
89
|
-
unlockUntilUnixMs: number;
|
|
90
138
|
};
|
|
91
139
|
snapshot: NonNullable<WalletReadContext["snapshot"]>;
|
|
92
140
|
model: NonNullable<WalletReadContext["model"]>;
|
|
93
141
|
};
|
|
142
|
+
export declare function assertWalletBitcoinTransferContextReady(context: WalletReadContext, errorPrefix: string): asserts context is WalletReadContext & {
|
|
143
|
+
localState: {
|
|
144
|
+
availability: "ready";
|
|
145
|
+
state: WalletStateV1;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
94
148
|
export declare function pauseMiningForWalletMutation(options: {
|
|
95
149
|
paths: WalletRuntimePaths;
|
|
96
150
|
reason: string;
|
|
@@ -103,7 +157,7 @@ export declare function buildWalletMutationTransaction<TPlan>(options: {
|
|
|
103
157
|
fixedInputs: FixedWalletInput[];
|
|
104
158
|
outputs: unknown[];
|
|
105
159
|
changeAddress: string;
|
|
106
|
-
changePosition
|
|
160
|
+
changePosition?: number | null;
|
|
107
161
|
allowedFundingScriptPubKeyHex: string;
|
|
108
162
|
eligibleFundingOutpointKeys: Set<string>;
|
|
109
163
|
};
|
|
@@ -131,5 +185,4 @@ export declare function buildWalletMutationTransactionWithReserveFallback<TPlan>
|
|
|
131
185
|
mempoolRejectPrefix: string;
|
|
132
186
|
feeRate?: number;
|
|
133
187
|
availableFundingMinConf?: number;
|
|
134
|
-
reserveCandidates: readonly OutpointRecord[];
|
|
135
188
|
}): Promise<BuiltWalletMutationTransaction>;
|
package/dist/wallet/tx/common.js
CHANGED
|
@@ -1,30 +1,194 @@
|
|
|
1
|
-
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { saveUnlockSession } from "../state/session.js";
|
|
3
1
|
import { saveWalletState } from "../state/storage.js";
|
|
4
2
|
import { createWalletSecretReference, } from "../state/provider.js";
|
|
3
|
+
import { MANAGED_CORE_WALLET_UNLOCK_TIMEOUT_SECONDS, withUnlockedManagedCoreWallet, } from "../managed-core-wallet.js";
|
|
5
4
|
import { reconcilePersistentPolicyLocks as reconcileWalletCoinControlLocks } from "../coin-control.js";
|
|
6
5
|
import { requestMiningGenerationPreemption } from "../mining/coordination.js";
|
|
7
6
|
export const DEFAULT_WALLET_MUTATION_FEE_RATE_SAT_VB = 10;
|
|
8
|
-
const
|
|
7
|
+
export const NEXT_BLOCK_FEE_CONFIRM_TARGET = 1;
|
|
8
|
+
export function isLocalWalletScript(state, scriptPubKeyHex) {
|
|
9
|
+
if (typeof scriptPubKeyHex !== "string" || scriptPubKeyHex.length === 0) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return scriptPubKeyHex === state.funding.scriptPubKeyHex
|
|
13
|
+
|| (state.localScriptPubKeyHexes ?? []).includes(scriptPubKeyHex);
|
|
14
|
+
}
|
|
15
|
+
export function createFundingMutationSender(state) {
|
|
16
|
+
return {
|
|
17
|
+
localIndex: 0,
|
|
18
|
+
scriptPubKeyHex: state.funding.scriptPubKeyHex,
|
|
19
|
+
address: state.funding.address,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
9
22
|
function btcNumberToSats(value) {
|
|
10
23
|
return BigInt(Math.round(value * 100_000_000));
|
|
11
24
|
}
|
|
25
|
+
function normalizeSatVb(value) {
|
|
26
|
+
return Number.parseFloat(value.toFixed(8));
|
|
27
|
+
}
|
|
28
|
+
function satVbFromBtcPerKvB(value) {
|
|
29
|
+
return normalizeSatVb((value * 100_000_000) / 1_000);
|
|
30
|
+
}
|
|
12
31
|
function valueToSats(value) {
|
|
13
32
|
return typeof value === "string"
|
|
14
33
|
? BigInt(Math.round(Number(value) * 100_000_000))
|
|
15
34
|
: btcNumberToSats(value);
|
|
16
35
|
}
|
|
17
|
-
function
|
|
36
|
+
function feeRateFromMempoolEntry(entry) {
|
|
37
|
+
if (!Number.isFinite(entry.vsize) || entry.vsize <= 0) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const feeSats = Number(btcNumberToSats(entry.fees.base));
|
|
41
|
+
if (!Number.isFinite(feeSats) || feeSats <= 0) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return normalizeSatVb(feeSats / entry.vsize);
|
|
45
|
+
}
|
|
46
|
+
export function formatSatVb(value) {
|
|
47
|
+
return normalizeSatVb(value).toString();
|
|
48
|
+
}
|
|
49
|
+
export function createWalletMutationFeeMetadata(selection) {
|
|
18
50
|
return {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
sessionId: randomBytes(16).toString("hex"),
|
|
22
|
-
createdAtUnixMs: nowUnixMs,
|
|
23
|
-
unlockUntilUnixMs,
|
|
24
|
-
sourceStateRevision: state.stateRevision,
|
|
25
|
-
wrappedSessionKeyMaterial: createWalletSecretReference(state.walletRootId).keyId,
|
|
51
|
+
selectedFeeRateSatVb: selection.feeRateSatVb,
|
|
52
|
+
feeSelectionSource: selection.source,
|
|
26
53
|
};
|
|
27
54
|
}
|
|
55
|
+
export async function resolveWalletMutationFeeSelection(options) {
|
|
56
|
+
if (typeof options.feeRateSatVb === "number") {
|
|
57
|
+
return {
|
|
58
|
+
feeRateSatVb: normalizeSatVb(options.feeRateSatVb),
|
|
59
|
+
source: "custom-satvb",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (options.rpc.estimateSmartFee !== undefined) {
|
|
63
|
+
try {
|
|
64
|
+
const estimate = await options.rpc.estimateSmartFee(NEXT_BLOCK_FEE_CONFIRM_TARGET, "conservative");
|
|
65
|
+
const estimatedSatVb = typeof estimate.feerate === "number"
|
|
66
|
+
? satVbFromBtcPerKvB(estimate.feerate)
|
|
67
|
+
: null;
|
|
68
|
+
if (estimatedSatVb !== null && Number.isFinite(estimatedSatVb) && estimatedSatVb > 0) {
|
|
69
|
+
return {
|
|
70
|
+
feeRateSatVb: normalizeSatVb(estimatedSatVb + 1),
|
|
71
|
+
source: "estimated-next-block-plus-one",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Fall through to the compatibility default.
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
feeRateSatVb: DEFAULT_WALLET_MUTATION_FEE_RATE_SAT_VB,
|
|
81
|
+
source: "fallback-default",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function createWalletMutationFeeSummary(selection, feeSats) {
|
|
85
|
+
return {
|
|
86
|
+
feeRateSatVb: selection.feeRateSatVb,
|
|
87
|
+
feeSats,
|
|
88
|
+
source: selection.source,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export function createBuiltWalletMutationFeeSummary(options) {
|
|
92
|
+
return createWalletMutationFeeSummary(options.selection, btcNumberToSats(options.built.funded.fee).toString());
|
|
93
|
+
}
|
|
94
|
+
export async function resolvePendingMutationFeeSummary(options) {
|
|
95
|
+
const source = options.mutation.feeSelectionSource ?? "fallback-default";
|
|
96
|
+
const selectedFeeRateSatVb = typeof options.mutation.selectedFeeRateSatVb === "number"
|
|
97
|
+
&& Number.isFinite(options.mutation.selectedFeeRateSatVb)
|
|
98
|
+
&& options.mutation.selectedFeeRateSatVb > 0
|
|
99
|
+
? normalizeSatVb(options.mutation.selectedFeeRateSatVb)
|
|
100
|
+
: DEFAULT_WALLET_MUTATION_FEE_RATE_SAT_VB;
|
|
101
|
+
if (options.mutation.attemptedTxid !== null && options.rpc.getMempoolEntry !== undefined) {
|
|
102
|
+
try {
|
|
103
|
+
const entry = await options.rpc.getMempoolEntry(options.mutation.attemptedTxid);
|
|
104
|
+
const feeRateSatVb = feeRateFromMempoolEntry(entry);
|
|
105
|
+
if (feeRateSatVb !== null) {
|
|
106
|
+
return {
|
|
107
|
+
feeRateSatVb,
|
|
108
|
+
feeSats: btcNumberToSats(entry.fees.base).toString(),
|
|
109
|
+
source,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Fall back to stored metadata or the historical default.
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
feeRateSatVb: selectedFeeRateSatVb,
|
|
119
|
+
feeSats: null,
|
|
120
|
+
source,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export async function loadAttemptedMutationFixedInputs(options) {
|
|
124
|
+
if (options.mutation.attemptedTxid === null) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const txid = options.mutation.attemptedTxid;
|
|
128
|
+
let decoded = null;
|
|
129
|
+
if (options.rpc.getTransaction !== undefined) {
|
|
130
|
+
try {
|
|
131
|
+
decoded = (await options.rpc.getTransaction(options.walletName, txid)).decoded ?? null;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
decoded = null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (decoded === null && options.rpc.getRawTransaction !== undefined) {
|
|
138
|
+
try {
|
|
139
|
+
decoded = await options.rpc.getRawTransaction(txid, true);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
decoded = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (decoded === null) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const fixedInputs = decoded.vin
|
|
149
|
+
.filter((input) => typeof input.txid === "string" && typeof input.vout === "number")
|
|
150
|
+
.map((input) => ({
|
|
151
|
+
txid: input.txid,
|
|
152
|
+
vout: input.vout,
|
|
153
|
+
}));
|
|
154
|
+
return fixedInputs.length > 0 ? fixedInputs : null;
|
|
155
|
+
}
|
|
156
|
+
export async function resolvePendingMutationReuseDecision(options) {
|
|
157
|
+
const fees = await resolvePendingMutationFeeSummary({
|
|
158
|
+
rpc: options.rpc,
|
|
159
|
+
mutation: options.mutation,
|
|
160
|
+
});
|
|
161
|
+
if (options.mutation.status === "confirmed"
|
|
162
|
+
|| options.nextFeeSelection.feeRateSatVb <= fees.feeRateSatVb) {
|
|
163
|
+
return {
|
|
164
|
+
reuseExisting: true,
|
|
165
|
+
fees,
|
|
166
|
+
replacementFixedInputs: null,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
reuseExisting: false,
|
|
171
|
+
fees,
|
|
172
|
+
replacementFixedInputs: await loadAttemptedMutationFixedInputs({
|
|
173
|
+
rpc: options.rpc,
|
|
174
|
+
walletName: options.walletName,
|
|
175
|
+
mutation: options.mutation,
|
|
176
|
+
}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
export function mergeFixedWalletInputs(fixedInputs, replacementInputs) {
|
|
180
|
+
if (replacementInputs === null || replacementInputs.length === 0) {
|
|
181
|
+
return [...fixedInputs];
|
|
182
|
+
}
|
|
183
|
+
const merged = new Map();
|
|
184
|
+
for (const input of fixedInputs) {
|
|
185
|
+
merged.set(outpointKey(input), { txid: input.txid, vout: input.vout });
|
|
186
|
+
}
|
|
187
|
+
for (const input of replacementInputs) {
|
|
188
|
+
merged.set(outpointKey(input), { txid: input.txid, vout: input.vout });
|
|
189
|
+
}
|
|
190
|
+
return [...merged.values()];
|
|
191
|
+
}
|
|
28
192
|
export async function saveWalletStatePreservingUnlock(options) {
|
|
29
193
|
const secretReference = createWalletSecretReference(options.state.walletRootId);
|
|
30
194
|
await saveWalletState({
|
|
@@ -34,10 +198,6 @@ export async function saveWalletStatePreservingUnlock(options) {
|
|
|
34
198
|
provider: options.provider,
|
|
35
199
|
secretReference,
|
|
36
200
|
});
|
|
37
|
-
await saveUnlockSession(options.paths.walletUnlockSessionPath, createUnlockSessionState(options.state, options.unlockUntilUnixMs, options.nowUnixMs), {
|
|
38
|
-
provider: options.provider,
|
|
39
|
-
secretReference,
|
|
40
|
-
});
|
|
41
201
|
}
|
|
42
202
|
export function formatCogAmount(value) {
|
|
43
203
|
const sign = value < 0n ? "-" : "";
|
|
@@ -75,10 +235,12 @@ export function updateMutationRecord(mutation, status, nowUnixMs, options = {})
|
|
|
75
235
|
attemptedTxid: options.attemptedTxid ?? mutation.attemptedTxid,
|
|
76
236
|
attemptedWtxid: options.attemptedWtxid ?? mutation.attemptedWtxid,
|
|
77
237
|
temporaryBuilderLockedOutpoints: options.temporaryBuilderLockedOutpoints ?? mutation.temporaryBuilderLockedOutpoints,
|
|
238
|
+
selectedFeeRateSatVb: options.selectedFeeRateSatVb ?? mutation.selectedFeeRateSatVb,
|
|
239
|
+
feeSelectionSource: options.feeSelectionSource ?? mutation.feeSelectionSource,
|
|
78
240
|
};
|
|
79
241
|
}
|
|
80
242
|
export async function unlockTemporaryBuilderLocks(rpc, walletName, outpoints) {
|
|
81
|
-
if (outpoints.length === 0) {
|
|
243
|
+
if (outpoints.length === 0 || rpc.lockUnspent === undefined) {
|
|
82
244
|
return;
|
|
83
245
|
}
|
|
84
246
|
await rpc.lockUnspent(walletName, true, outpoints).catch(() => undefined);
|
|
@@ -124,40 +286,18 @@ export function inputMatchesOutpoint(input, outpoint) {
|
|
|
124
286
|
return input.txid === outpoint.txid && getDecodedInputVout(input) === outpoint.vout;
|
|
125
287
|
}
|
|
126
288
|
export function assertFixedInputPrefixMatches(inputs, fixedInputs, errorCode) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
for (const [index, fixedInput] of fixedInputs.entries()) {
|
|
131
|
-
if (!inputMatchesOutpoint(inputs[index], fixedInput)) {
|
|
132
|
-
throw new Error(errorCode);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
289
|
+
void inputs;
|
|
290
|
+
void fixedInputs;
|
|
291
|
+
void errorCode;
|
|
135
292
|
}
|
|
136
293
|
export function assertFundingInputsAfterFixedPrefix(options) {
|
|
137
|
-
|
|
138
|
-
const input = options.decoded.tx.vin[index];
|
|
139
|
-
const scriptPubKeyHex = getDecodedInputScriptPubKeyHex(options.decoded, index);
|
|
140
|
-
const vout = getDecodedInputVout(input);
|
|
141
|
-
if (scriptPubKeyHex !== options.allowedFundingScriptPubKeyHex || vout === null || typeof input.txid !== "string") {
|
|
142
|
-
throw new Error(options.errorCode);
|
|
143
|
-
}
|
|
144
|
-
const key = outpointKey({
|
|
145
|
-
txid: input.txid,
|
|
146
|
-
vout,
|
|
147
|
-
});
|
|
148
|
-
if (!options.eligibleFundingOutpointKeys.has(key)) {
|
|
149
|
-
throw new Error(options.errorCode);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
294
|
+
void options;
|
|
152
295
|
}
|
|
153
296
|
export async function reconcilePersistentPolicyLocks(options) {
|
|
154
297
|
await reconcileWalletCoinControlLocks({
|
|
155
298
|
rpc: options.rpc,
|
|
156
299
|
walletName: options.walletName,
|
|
157
300
|
state: options.state,
|
|
158
|
-
fixedInputs: options.fixedInputs,
|
|
159
|
-
temporarilyUnlockedOutpoints: options.temporarilyUnlockedOutpoints,
|
|
160
|
-
cleanupInactiveTemporaryBuilderLocks: options.cleanupInactiveTemporaryBuilderLocks,
|
|
161
301
|
});
|
|
162
302
|
}
|
|
163
303
|
export function isBroadcastUnknownError(error) {
|
|
@@ -181,8 +321,8 @@ export function isInsufficientFundsError(error) {
|
|
|
181
321
|
return message.includes("insufficient funds");
|
|
182
322
|
}
|
|
183
323
|
function isReserveFloorFundingError(error) {
|
|
184
|
-
|
|
185
|
-
return
|
|
324
|
+
void error;
|
|
325
|
+
return false;
|
|
186
326
|
}
|
|
187
327
|
function computeRemainingFundingValueSats(options) {
|
|
188
328
|
let remaining = 0n;
|
|
@@ -212,11 +352,20 @@ export function assertWalletMutationContextReady(context, errorPrefix) {
|
|
|
212
352
|
if (context.localState.availability === "uninitialized") {
|
|
213
353
|
throw new Error("wallet_uninitialized");
|
|
214
354
|
}
|
|
355
|
+
if (context.localState.clientPasswordReadiness === "setup-required") {
|
|
356
|
+
throw new Error("wallet_client_password_setup_required");
|
|
357
|
+
}
|
|
358
|
+
if (context.localState.clientPasswordReadiness === "migration-required") {
|
|
359
|
+
throw new Error("wallet_client_password_migration_required");
|
|
360
|
+
}
|
|
361
|
+
if (context.localState.unlockRequired) {
|
|
362
|
+
throw new Error("wallet_client_password_locked");
|
|
363
|
+
}
|
|
215
364
|
if (context.localState.availability === "local-state-corrupt") {
|
|
216
365
|
throw new Error("local-state-corrupt");
|
|
217
366
|
}
|
|
218
|
-
if (context.localState.availability !== "ready" || context.localState.state === null
|
|
219
|
-
throw new Error("
|
|
367
|
+
if (context.localState.availability !== "ready" || context.localState.state === null) {
|
|
368
|
+
throw new Error("wallet_secret_provider_unavailable");
|
|
220
369
|
}
|
|
221
370
|
if (context.bitcoind.health !== "ready") {
|
|
222
371
|
throw new Error(`${errorPrefix}_bitcoind_${context.bitcoind.health.replaceAll("-", "_")}`);
|
|
@@ -231,6 +380,35 @@ export function assertWalletMutationContextReady(context, errorPrefix) {
|
|
|
231
380
|
throw new Error(`${errorPrefix}_core_replica_not_ready`);
|
|
232
381
|
}
|
|
233
382
|
}
|
|
383
|
+
export function assertWalletBitcoinTransferContextReady(context, errorPrefix) {
|
|
384
|
+
if (context.localState.availability === "uninitialized") {
|
|
385
|
+
throw new Error("wallet_uninitialized");
|
|
386
|
+
}
|
|
387
|
+
if (context.localState.clientPasswordReadiness === "setup-required") {
|
|
388
|
+
throw new Error("wallet_client_password_setup_required");
|
|
389
|
+
}
|
|
390
|
+
if (context.localState.clientPasswordReadiness === "migration-required") {
|
|
391
|
+
throw new Error("wallet_client_password_migration_required");
|
|
392
|
+
}
|
|
393
|
+
if (context.localState.unlockRequired) {
|
|
394
|
+
throw new Error("wallet_client_password_locked");
|
|
395
|
+
}
|
|
396
|
+
if (context.localState.availability === "local-state-corrupt") {
|
|
397
|
+
throw new Error("local-state-corrupt");
|
|
398
|
+
}
|
|
399
|
+
if (context.localState.availability !== "ready" || context.localState.state === null) {
|
|
400
|
+
throw new Error("wallet_secret_provider_unavailable");
|
|
401
|
+
}
|
|
402
|
+
if (context.bitcoind.health !== "ready") {
|
|
403
|
+
throw new Error(`${errorPrefix}_bitcoind_${context.bitcoind.health.replaceAll("-", "_")}`);
|
|
404
|
+
}
|
|
405
|
+
if (context.nodeHealth !== "synced") {
|
|
406
|
+
throw new Error(`${errorPrefix}_node_${context.nodeHealth.replaceAll("-", "_")}`);
|
|
407
|
+
}
|
|
408
|
+
if (context.nodeStatus?.walletReplica?.proofStatus !== "ready") {
|
|
409
|
+
throw new Error(`${errorPrefix}_core_replica_not_ready`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
234
412
|
export async function pauseMiningForWalletMutation(options) {
|
|
235
413
|
return requestMiningGenerationPreemption({
|
|
236
414
|
paths: options.paths,
|
|
@@ -238,13 +416,6 @@ export async function pauseMiningForWalletMutation(options) {
|
|
|
238
416
|
});
|
|
239
417
|
}
|
|
240
418
|
export async function buildWalletMutationTransaction(options) {
|
|
241
|
-
await reconcilePersistentPolicyLocks({
|
|
242
|
-
rpc: options.rpc,
|
|
243
|
-
walletName: options.walletName,
|
|
244
|
-
state: options.state,
|
|
245
|
-
fixedInputs: options.plan.fixedInputs,
|
|
246
|
-
temporarilyUnlockedOutpoints: options.temporarilyUnlockedPolicyOutpoints,
|
|
247
|
-
});
|
|
248
419
|
const availableFundingMinConf = options.availableFundingMinConf ?? 1;
|
|
249
420
|
const availableFundingUtxos = (await options.rpc.listUnspent(options.walletName, availableFundingMinConf))
|
|
250
421
|
.filter((entry) => isSpendableFundingUtxo(entry, options.plan.allowedFundingScriptPubKeyHex, availableFundingMinConf));
|
|
@@ -259,67 +430,56 @@ export async function buildWalletMutationTransaction(options) {
|
|
|
259
430
|
...availableFundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout })),
|
|
260
431
|
]),
|
|
261
432
|
};
|
|
262
|
-
const
|
|
263
|
-
let temporaryBuilderLockedOutpoints = [];
|
|
433
|
+
const temporaryBuilderLockedOutpoints = [];
|
|
264
434
|
try {
|
|
265
435
|
const funded = await options.rpc.walletCreateFundedPsbt(options.walletName, options.plan.fixedInputs, options.plan.outputs, 0, {
|
|
266
436
|
add_inputs: true,
|
|
267
437
|
include_unsafe: false,
|
|
268
438
|
minconf: 1,
|
|
269
439
|
changeAddress: options.plan.changeAddress,
|
|
270
|
-
changePosition: options.plan.changePosition,
|
|
271
|
-
lockUnspents:
|
|
440
|
+
...(options.plan.changePosition == null ? {} : { changePosition: options.plan.changePosition }),
|
|
441
|
+
lockUnspents: false,
|
|
272
442
|
fee_rate: options.feeRate ?? DEFAULT_WALLET_MUTATION_FEE_RATE_SAT_VB,
|
|
273
443
|
replaceable: true,
|
|
274
444
|
subtractFeeFromOutputs: [],
|
|
275
445
|
});
|
|
276
|
-
const lockedAfter = await options.rpc.listLockUnspent(options.walletName);
|
|
277
|
-
temporaryBuilderLockedOutpoints = diffTemporaryLockedOutpoints(lockedBefore, lockedAfter);
|
|
278
446
|
const decoded = await options.rpc.decodePsbt(funded.psbt);
|
|
279
447
|
options.validateFundedDraft(decoded, funded, validationPlan);
|
|
280
|
-
if (options.state.proactiveReserveSats > 0) {
|
|
281
|
-
const remainingFundingValueSats = computeRemainingFundingValueSats({
|
|
282
|
-
decoded,
|
|
283
|
-
fundingScriptPubKeyHex: options.plan.allowedFundingScriptPubKeyHex,
|
|
284
|
-
availableFundingValueByKey,
|
|
285
|
-
});
|
|
286
|
-
if (remainingFundingValueSats < BigInt(options.state.proactiveReserveSats)) {
|
|
287
|
-
throw new Error("wallet_mutation_insufficient_funding_after_reserve");
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
await options.rpc.walletPassphrase(options.walletName, options.state.managedCoreWallet.internalPassphrase, MANAGED_CORE_WALLET_SIGNING_UNLOCK_TIMEOUT_SECONDS);
|
|
291
448
|
let signed;
|
|
292
449
|
let finalized;
|
|
450
|
+
let rawHex;
|
|
293
451
|
let decodedRaw;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
452
|
+
({ signed, finalized, rawHex, decodedRaw } = await withUnlockedManagedCoreWallet({
|
|
453
|
+
rpc: options.rpc,
|
|
454
|
+
walletName: options.walletName,
|
|
455
|
+
internalPassphrase: options.state.managedCoreWallet.internalPassphrase,
|
|
456
|
+
timeoutSeconds: MANAGED_CORE_WALLET_UNLOCK_TIMEOUT_SECONDS,
|
|
457
|
+
run: async () => {
|
|
458
|
+
const signed = await options.rpc.walletProcessPsbt(options.walletName, funded.psbt, true, "DEFAULT");
|
|
459
|
+
const finalized = await options.rpc.finalizePsbt(signed.psbt, true);
|
|
460
|
+
if (!finalized.complete || finalized.hex == null) {
|
|
461
|
+
throw new Error(options.finalizeErrorCode);
|
|
462
|
+
}
|
|
463
|
+
const rawHex = finalized.hex;
|
|
464
|
+
const decodedRaw = await options.rpc.decodeRawTransaction(rawHex);
|
|
465
|
+
const mempoolResult = await options.rpc.testMempoolAccept([rawHex]);
|
|
466
|
+
const accepted = mempoolResult[0];
|
|
467
|
+
if (accepted == null || !accepted.allowed) {
|
|
468
|
+
throw new Error(`${options.mempoolRejectPrefix}_${accepted?.["reject-reason"] ?? "unknown"}`);
|
|
469
|
+
}
|
|
470
|
+
return {
|
|
471
|
+
signed,
|
|
472
|
+
finalized,
|
|
473
|
+
rawHex,
|
|
474
|
+
decodedRaw,
|
|
475
|
+
};
|
|
476
|
+
},
|
|
477
|
+
}));
|
|
318
478
|
return {
|
|
319
479
|
funded,
|
|
320
480
|
decoded,
|
|
321
481
|
psbt: signed.psbt,
|
|
322
|
-
rawHex
|
|
482
|
+
rawHex,
|
|
323
483
|
txid: decodedRaw.txid,
|
|
324
484
|
wtxid: decodedRaw.hash ?? null,
|
|
325
485
|
temporaryBuilderLockedOutpoints,
|
|
@@ -327,59 +487,19 @@ export async function buildWalletMutationTransaction(options) {
|
|
|
327
487
|
}
|
|
328
488
|
catch (error) {
|
|
329
489
|
await unlockTemporaryBuilderLocks(options.rpc, options.walletName, temporaryBuilderLockedOutpoints);
|
|
330
|
-
if ((options.temporarilyUnlockedPolicyOutpoints?.length ?? 0) > 0) {
|
|
331
|
-
await reconcilePersistentPolicyLocks({
|
|
332
|
-
rpc: options.rpc,
|
|
333
|
-
walletName: options.walletName,
|
|
334
|
-
state: options.state,
|
|
335
|
-
fixedInputs: options.plan.fixedInputs,
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
490
|
throw error;
|
|
339
491
|
}
|
|
340
492
|
}
|
|
341
493
|
export async function buildWalletMutationTransactionWithReserveFallback(options) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
:
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
: [...effectiveState.proactiveReserveOutpoints];
|
|
354
|
-
let unlockedReserveOutpoints = [];
|
|
355
|
-
let lastError = null;
|
|
356
|
-
for (let attempt = 0; attempt <= reserveCandidates.length; attempt += 1) {
|
|
357
|
-
if (attempt > 0) {
|
|
358
|
-
unlockedReserveOutpoints = [
|
|
359
|
-
...unlockedReserveOutpoints,
|
|
360
|
-
reserveCandidates[attempt - 1],
|
|
361
|
-
];
|
|
362
|
-
}
|
|
363
|
-
try {
|
|
364
|
-
return await buildWalletMutationTransaction({
|
|
365
|
-
rpc: options.rpc,
|
|
366
|
-
walletName: options.walletName,
|
|
367
|
-
state: effectiveState,
|
|
368
|
-
plan: options.plan,
|
|
369
|
-
validateFundedDraft: options.validateFundedDraft,
|
|
370
|
-
finalizeErrorCode: options.finalizeErrorCode,
|
|
371
|
-
mempoolRejectPrefix: options.mempoolRejectPrefix,
|
|
372
|
-
feeRate: options.feeRate,
|
|
373
|
-
availableFundingMinConf: options.availableFundingMinConf,
|
|
374
|
-
temporarilyUnlockedPolicyOutpoints: unlockedReserveOutpoints,
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
catch (error) {
|
|
378
|
-
lastError = error;
|
|
379
|
-
if ((!isInsufficientFundsError(error) && !isReserveFloorFundingError(error)) || attempt === reserveCandidates.length) {
|
|
380
|
-
throw error;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
throw lastError;
|
|
494
|
+
return buildWalletMutationTransaction({
|
|
495
|
+
rpc: options.rpc,
|
|
496
|
+
walletName: options.walletName,
|
|
497
|
+
state: options.state,
|
|
498
|
+
plan: options.plan,
|
|
499
|
+
validateFundedDraft: options.validateFundedDraft,
|
|
500
|
+
finalizeErrorCode: options.finalizeErrorCode,
|
|
501
|
+
mempoolRejectPrefix: options.mempoolRejectPrefix,
|
|
502
|
+
feeRate: options.feeRate,
|
|
503
|
+
availableFundingMinConf: options.availableFundingMinConf,
|
|
504
|
+
});
|
|
385
505
|
}
|
|
@@ -5,7 +5,7 @@ import type { WalletPrompter } from "../lifecycle.js";
|
|
|
5
5
|
import { type WalletRuntimePaths } from "../runtime.js";
|
|
6
6
|
import { type WalletSecretProvider } from "../state/provider.js";
|
|
7
7
|
import { openWalletReadContext } from "../read/index.js";
|
|
8
|
-
import { type WalletMutationRpcClient } from "./common.js";
|
|
8
|
+
import { type WalletMutationFeeSummary, type WalletMutationRpcClient } from "./common.js";
|
|
9
9
|
type DomainAdminKind = "endpoint" | "delegate" | "miner" | "canonical";
|
|
10
10
|
interface DomainAdminRpcClient extends WalletMutationRpcClient {
|
|
11
11
|
getBlockchainInfo(): Promise<{
|
|
@@ -55,9 +55,11 @@ export interface DomainAdminMutationResult {
|
|
|
55
55
|
recipientScriptPubKeyHex?: string | null;
|
|
56
56
|
endpointValueHex?: string | null;
|
|
57
57
|
resolved?: DomainAdminResolvedSummary | null;
|
|
58
|
+
fees: WalletMutationFeeSummary;
|
|
58
59
|
}
|
|
59
60
|
interface DomainAdminBaseOptions {
|
|
60
61
|
domainName: string;
|
|
62
|
+
feeRateSatVb?: number | null;
|
|
61
63
|
dataDir: string;
|
|
62
64
|
databasePath: string;
|
|
63
65
|
provider?: WalletSecretProvider;
|