@cogcoin/client 0.5.15 → 1.0.0
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 +38 -3
- package/dist/cli/commands/service-runtime.js +0 -2
- package/dist/cli/commands/status.js +8 -2
- package/dist/cli/commands/sync.js +51 -4
- 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 +4 -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/types.d.ts +8 -17
- package/dist/cli/types.js +0 -2
- package/dist/cli/wallet-format.d.ts +1 -0
- package/dist/cli/wallet-format.js +205 -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 +3 -4
- package/dist/wallet/mining/index.js +1 -2
- package/dist/wallet/mining/runner.d.ts +116 -13
- package/dist/wallet/mining/runner.js +885 -501
- 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
|
@@ -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 { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransactionWithReserveFallback, formatCogAmount, getDecodedInputScriptPubKeyHex, isAlreadyAcceptedError, isBroadcastUnknownError, outpointKey, pauseMiningForWalletMutation, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "./common.js";
|
|
11
|
+
import { assertFixedInputPrefixMatches, assertFundingInputsAfterFixedPrefix, assertWalletMutationContextReady, buildWalletMutationTransactionWithReserveFallback, createBuiltWalletMutationFeeSummary, createFundingMutationSender, createWalletMutationFeeMetadata, formatCogAmount, getDecodedInputScriptPubKeyHex, isLocalWalletScript, isAlreadyAcceptedError, isBroadcastUnknownError, mergeFixedWalletInputs, outpointKey, pauseMiningForWalletMutation, resolvePendingMutationReuseDecision, resolveWalletMutationFeeSelection, 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";
|
|
@@ -96,9 +96,6 @@ function buildRootRegisterOutputs(options) {
|
|
|
96
96
|
{ data: Buffer.from(payload).toString("hex") },
|
|
97
97
|
{ [options.treasuryAddress]: satsToBtcNumber(options.priceSats) },
|
|
98
98
|
];
|
|
99
|
-
if (options.senderAddress !== null && options.anchorValueSats !== null) {
|
|
100
|
-
outputs.push({ [options.senderAddress]: satsToBtcNumber(options.anchorValueSats) });
|
|
101
|
-
}
|
|
102
99
|
return {
|
|
103
100
|
outputs,
|
|
104
101
|
changePosition: outputs.length,
|
|
@@ -108,11 +105,8 @@ function buildRootRegisterOutputs(options) {
|
|
|
108
105
|
function buildSubdomainRegisterOutputs(options) {
|
|
109
106
|
const payload = serializeDomainReg(options.domainName).opReturnData;
|
|
110
107
|
return {
|
|
111
|
-
outputs: [
|
|
112
|
-
|
|
113
|
-
{ [options.senderAddress]: satsToBtcNumber(options.anchorValueSats) },
|
|
114
|
-
],
|
|
115
|
-
changePosition: 2,
|
|
108
|
+
outputs: [{ data: Buffer.from(payload).toString("hex") }],
|
|
109
|
+
changePosition: 1,
|
|
116
110
|
expectedOpReturnScriptHex: encodeOpReturnScript(payload),
|
|
117
111
|
};
|
|
118
112
|
}
|
|
@@ -184,7 +178,7 @@ function describeRegisterEconomicEffect(summary) {
|
|
|
184
178
|
if (summary.economicEffect.kind === "treasury-payment") {
|
|
185
179
|
return `send ${summary.economicEffect.amount.toString()} sats to the Cogcoin treasury.`;
|
|
186
180
|
}
|
|
187
|
-
return `burn ${formatCogAmount(summary.economicEffect.amount)} from the parent
|
|
181
|
+
return `burn ${formatCogAmount(summary.economicEffect.amount)} from the parent owner.`;
|
|
188
182
|
}
|
|
189
183
|
function writeRegisterResolvedSummary(prompter, summary) {
|
|
190
184
|
prompter.writeLine(`Resolved path: ${summary.path} registration.`);
|
|
@@ -194,15 +188,6 @@ function writeRegisterResolvedSummary(prompter, summary) {
|
|
|
194
188
|
prompter.writeLine(`Resolved sender: ${summary.sender.selector} (${summary.sender.address})`);
|
|
195
189
|
prompter.writeLine(`Economic effect: ${describeRegisterEconomicEffect(summary)}`);
|
|
196
190
|
}
|
|
197
|
-
function replaceAssignedDomainNames(identity, domainName) {
|
|
198
|
-
if (identity.assignedDomainNames.includes(domainName)) {
|
|
199
|
-
return identity;
|
|
200
|
-
}
|
|
201
|
-
return {
|
|
202
|
-
...identity,
|
|
203
|
-
assignedDomainNames: [...identity.assignedDomainNames, domainName].sort((left, right) => left.localeCompare(right)),
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
191
|
function reserveLocalDomainRecord(options) {
|
|
207
192
|
const existing = options.state.domains.find((domain) => domain.name === options.domainName) ?? null;
|
|
208
193
|
const domains = options.state.domains.some((domain) => domain.name === options.domainName)
|
|
@@ -213,7 +198,6 @@ function reserveLocalDomainRecord(options) {
|
|
|
213
198
|
return {
|
|
214
199
|
...domain,
|
|
215
200
|
currentOwnerScriptPubKeyHex: options.sender.scriptPubKeyHex,
|
|
216
|
-
currentOwnerLocalIndex: options.sender.localIndex,
|
|
217
201
|
birthTime: domain.birthTime ?? Math.floor(options.nowUnixMs / 1000),
|
|
218
202
|
};
|
|
219
203
|
})
|
|
@@ -222,23 +206,15 @@ function reserveLocalDomainRecord(options) {
|
|
|
222
206
|
{
|
|
223
207
|
name: options.domainName,
|
|
224
208
|
domainId: null,
|
|
225
|
-
dedicatedIndex: null,
|
|
226
209
|
currentOwnerScriptPubKeyHex: options.sender.scriptPubKeyHex,
|
|
227
|
-
currentOwnerLocalIndex: options.sender.localIndex,
|
|
228
210
|
canonicalChainStatus: "unknown",
|
|
229
|
-
localAnchorIntent: "none",
|
|
230
|
-
currentCanonicalAnchorOutpoint: null,
|
|
231
211
|
foundingMessageText: existing?.foundingMessageText ?? null,
|
|
232
212
|
birthTime: Math.floor(options.nowUnixMs / 1000),
|
|
233
213
|
},
|
|
234
214
|
];
|
|
235
|
-
const identities = options.state.identities.map((identity) => identity.index === options.sender.localIndex
|
|
236
|
-
? replaceAssignedDomainNames(identity, options.domainName)
|
|
237
|
-
: identity);
|
|
238
215
|
return {
|
|
239
216
|
...options.state,
|
|
240
217
|
domains,
|
|
241
|
-
identities,
|
|
242
218
|
};
|
|
243
219
|
}
|
|
244
220
|
function getMutationStatusAfterAcceptance(options) {
|
|
@@ -250,78 +226,20 @@ function getMutationStatusAfterAcceptance(options) {
|
|
|
250
226
|
? "confirmed"
|
|
251
227
|
: "live";
|
|
252
228
|
}
|
|
253
|
-
function resolveRootRegisterAnchorOutpoint(state, senderIndex) {
|
|
254
|
-
const anchoredDomain = state.domains.find((domain) => domain.currentOwnerLocalIndex === senderIndex
|
|
255
|
-
&& domain.canonicalChainStatus === "anchored"
|
|
256
|
-
&& domain.currentCanonicalAnchorOutpoint !== null) ?? null;
|
|
257
|
-
if (anchoredDomain?.currentCanonicalAnchorOutpoint === undefined
|
|
258
|
-
|| anchoredDomain?.currentCanonicalAnchorOutpoint === null) {
|
|
259
|
-
return null;
|
|
260
|
-
}
|
|
261
|
-
return {
|
|
262
|
-
txid: anchoredDomain.currentCanonicalAnchorOutpoint.txid,
|
|
263
|
-
vout: anchoredDomain.currentCanonicalAnchorOutpoint.vout,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
229
|
function resolveRegisterSender(context, domainName, fromIdentity) {
|
|
267
230
|
const state = context.localState.state;
|
|
268
|
-
|
|
269
|
-
if (fundingIdentity == null || fundingIdentity.address === null) {
|
|
231
|
+
if (context.model.walletAddress === null) {
|
|
270
232
|
throw new Error("wallet_register_funding_identity_unavailable");
|
|
271
233
|
}
|
|
234
|
+
void fromIdentity;
|
|
272
235
|
if (!domainName.includes("-")) {
|
|
273
|
-
if (fromIdentity !== null && fromIdentity !== undefined) {
|
|
274
|
-
const selectedIdentity = resolveIdentityBySelector(context, fromIdentity, "wallet_register");
|
|
275
|
-
if (selectedIdentity.address === null) {
|
|
276
|
-
throw new Error("wallet_register_sender_address_unavailable");
|
|
277
|
-
}
|
|
278
|
-
if (selectedIdentity.readOnly) {
|
|
279
|
-
throw new Error("wallet_register_sender_read_only");
|
|
280
|
-
}
|
|
281
|
-
if (selectedIdentity.index === fundingIdentity.index) {
|
|
282
|
-
return {
|
|
283
|
-
registerKind: "root",
|
|
284
|
-
parentDomainName: null,
|
|
285
|
-
senderSelector: getCanonicalIdentitySelector(selectedIdentity),
|
|
286
|
-
sender: {
|
|
287
|
-
localIndex: selectedIdentity.index,
|
|
288
|
-
scriptPubKeyHex: selectedIdentity.scriptPubKeyHex,
|
|
289
|
-
address: selectedIdentity.address,
|
|
290
|
-
},
|
|
291
|
-
anchorOutpoint: null,
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
const anchorOutpoint = resolveRootRegisterAnchorOutpoint(state, selectedIdentity.index);
|
|
295
|
-
if (anchorOutpoint === null) {
|
|
296
|
-
throw new Error("wallet_register_sender_not_root_eligible");
|
|
297
|
-
}
|
|
298
|
-
return {
|
|
299
|
-
registerKind: "root",
|
|
300
|
-
parentDomainName: null,
|
|
301
|
-
senderSelector: getCanonicalIdentitySelector(selectedIdentity),
|
|
302
|
-
sender: {
|
|
303
|
-
localIndex: selectedIdentity.index,
|
|
304
|
-
scriptPubKeyHex: selectedIdentity.scriptPubKeyHex,
|
|
305
|
-
address: selectedIdentity.address,
|
|
306
|
-
},
|
|
307
|
-
anchorOutpoint,
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
236
|
return {
|
|
311
237
|
registerKind: "root",
|
|
312
238
|
parentDomainName: null,
|
|
313
|
-
senderSelector:
|
|
314
|
-
sender:
|
|
315
|
-
localIndex: fundingIdentity.index,
|
|
316
|
-
scriptPubKeyHex: fundingIdentity.scriptPubKeyHex,
|
|
317
|
-
address: fundingIdentity.address,
|
|
318
|
-
},
|
|
319
|
-
anchorOutpoint: null,
|
|
239
|
+
senderSelector: context.model.walletAddress,
|
|
240
|
+
sender: createFundingMutationSender(state),
|
|
320
241
|
};
|
|
321
242
|
}
|
|
322
|
-
if (fromIdentity !== null && fromIdentity !== undefined) {
|
|
323
|
-
throw new Error("wallet_register_from_not_supported_for_subdomain");
|
|
324
|
-
}
|
|
325
243
|
const parent = getParent(context.snapshot.state, domainName);
|
|
326
244
|
if (parent === null) {
|
|
327
245
|
throw new Error("wallet_register_parent_not_found");
|
|
@@ -330,37 +248,17 @@ function resolveRegisterSender(context, domainName, fromIdentity) {
|
|
|
330
248
|
throw new Error("wallet_register_parent_not_anchored");
|
|
331
249
|
}
|
|
332
250
|
const parentDomain = context.model.domains.find((domain) => domain.name === parent.parentName) ?? null;
|
|
333
|
-
if (
|
|
251
|
+
if (!isLocalWalletScript(state, parentDomain?.ownerScriptPubKeyHex)) {
|
|
334
252
|
throw new Error("wallet_register_parent_not_locally_controlled");
|
|
335
253
|
}
|
|
336
|
-
if (
|
|
337
|
-
throw new Error("wallet_register_parent_read_only");
|
|
338
|
-
}
|
|
339
|
-
const senderIdentity = context.model.identities.find((identity) => identity.index === parentDomain.ownerLocalIndex) ?? null;
|
|
340
|
-
if (senderIdentity === null || senderIdentity.address === null) {
|
|
341
|
-
throw new Error("wallet_register_sender_identity_unavailable");
|
|
342
|
-
}
|
|
343
|
-
if (getBalance(context.snapshot.state, senderIdentity.scriptPubKeyHex) < SUBDOMAIN_REGISTRATION_FEE_COGTOSHI) {
|
|
254
|
+
if (getBalance(context.snapshot.state, state.funding.scriptPubKeyHex) < SUBDOMAIN_REGISTRATION_FEE_COGTOSHI) {
|
|
344
255
|
throw new Error("wallet_register_insufficient_cog_balance");
|
|
345
256
|
}
|
|
346
|
-
const localParentRecord = state.domains.find((domain) => domain.name === parent.parentName) ?? null;
|
|
347
|
-
const anchorOutpoint = localParentRecord?.currentCanonicalAnchorOutpoint ?? null;
|
|
348
|
-
if (anchorOutpoint === null) {
|
|
349
|
-
throw new Error("wallet_register_anchor_outpoint_unavailable");
|
|
350
|
-
}
|
|
351
257
|
return {
|
|
352
258
|
registerKind: "subdomain",
|
|
353
259
|
parentDomainName: parent.parentName,
|
|
354
|
-
senderSelector:
|
|
355
|
-
sender:
|
|
356
|
-
localIndex: senderIdentity.index,
|
|
357
|
-
scriptPubKeyHex: senderIdentity.scriptPubKeyHex,
|
|
358
|
-
address: senderIdentity.address,
|
|
359
|
-
},
|
|
360
|
-
anchorOutpoint: {
|
|
361
|
-
txid: anchorOutpoint.txid,
|
|
362
|
-
vout: anchorOutpoint.vout,
|
|
363
|
-
},
|
|
260
|
+
senderSelector: context.model.walletAddress,
|
|
261
|
+
sender: createFundingMutationSender(state),
|
|
364
262
|
};
|
|
365
263
|
}
|
|
366
264
|
function createDraftMutation(options) {
|
|
@@ -375,6 +273,7 @@ function createDraftMutation(options) {
|
|
|
375
273
|
lastUpdatedAtUnixMs: options.nowUnixMs,
|
|
376
274
|
attemptedTxid: null,
|
|
377
275
|
attemptedWtxid: null,
|
|
276
|
+
...createWalletMutationFeeMetadata(options.feeSelection),
|
|
378
277
|
temporaryBuilderLockedOutpoints: [],
|
|
379
278
|
};
|
|
380
279
|
}
|
|
@@ -392,6 +291,7 @@ function createDraftMutation(options) {
|
|
|
392
291
|
lastUpdatedAtUnixMs: options.nowUnixMs,
|
|
393
292
|
attemptedTxid: null,
|
|
394
293
|
attemptedWtxid: null,
|
|
294
|
+
...createWalletMutationFeeMetadata(options.feeSelection),
|
|
395
295
|
temporaryBuilderLockedOutpoints: [],
|
|
396
296
|
};
|
|
397
297
|
}
|
|
@@ -401,17 +301,6 @@ function validateFundedDraft(decoded, funded, plan) {
|
|
|
401
301
|
if (inputs.length === 0) {
|
|
402
302
|
throw new Error("wallet_register_missing_sender_input");
|
|
403
303
|
}
|
|
404
|
-
assertFixedInputPrefixMatches(inputs, plan.fixedInputs, "wallet_register_sender_input_mismatch");
|
|
405
|
-
if (getDecodedInputScriptPubKeyHex(decoded, 0) !== plan.sender.scriptPubKeyHex) {
|
|
406
|
-
throw new Error("wallet_register_sender_input_mismatch");
|
|
407
|
-
}
|
|
408
|
-
assertFundingInputsAfterFixedPrefix({
|
|
409
|
-
decoded,
|
|
410
|
-
fixedInputs: plan.fixedInputs,
|
|
411
|
-
allowedFundingScriptPubKeyHex: plan.allowedFundingScriptPubKeyHex,
|
|
412
|
-
eligibleFundingOutpointKeys: plan.eligibleFundingOutpointKeys,
|
|
413
|
-
errorCode: "wallet_register_unexpected_funding_input",
|
|
414
|
-
});
|
|
415
304
|
if (outputs[0]?.scriptPubKey?.hex !== plan.expectedOpReturnScriptHex) {
|
|
416
305
|
throw new Error("wallet_register_opreturn_mismatch");
|
|
417
306
|
}
|
|
@@ -423,17 +312,7 @@ function validateFundedDraft(decoded, funded, plan) {
|
|
|
423
312
|
throw new Error("wallet_register_treasury_value_too_small");
|
|
424
313
|
}
|
|
425
314
|
}
|
|
426
|
-
|
|
427
|
-
if (outputs[plan.expectedAnchorOutputIndex]?.scriptPubKey?.hex !== plan.expectedAnchorScriptHex) {
|
|
428
|
-
throw new Error("wallet_register_anchor_output_mismatch");
|
|
429
|
-
}
|
|
430
|
-
if (valueToSats(outputs[plan.expectedAnchorOutputIndex]?.value ?? 0) !== (plan.expectedAnchorValueSats ?? 0n)) {
|
|
431
|
-
throw new Error("wallet_register_anchor_value_mismatch");
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
const expectedWithoutChange = 1
|
|
435
|
-
+ Number(plan.expectedTreasuryOutputIndex !== null)
|
|
436
|
-
+ Number(plan.expectedAnchorOutputIndex !== null);
|
|
315
|
+
const expectedWithoutChange = 1 + Number(plan.expectedTreasuryOutputIndex !== null);
|
|
437
316
|
if (funded.changepos === -1) {
|
|
438
317
|
if (outputs.length !== expectedWithoutChange) {
|
|
439
318
|
throw new Error("wallet_register_unexpected_output_count");
|
|
@@ -455,87 +334,36 @@ function buildRegisterPlan(options) {
|
|
|
455
334
|
treasuryAddress: options.treasuryAddress,
|
|
456
335
|
treasuryScriptPubKeyHex: options.treasuryScriptPubKeyHex,
|
|
457
336
|
priceSats: options.rootPriceSats,
|
|
458
|
-
senderAddress: options.anchorOutpoint === null ? null : options.sender.address,
|
|
459
|
-
anchorValueSats: options.anchorOutpoint === null ? null : options.anchorValueSats,
|
|
460
337
|
});
|
|
461
|
-
if (options.anchorOutpoint === null) {
|
|
462
|
-
return {
|
|
463
|
-
registerKind: "root",
|
|
464
|
-
sender: options.sender,
|
|
465
|
-
changeAddress: options.state.funding.address,
|
|
466
|
-
fixedInputs: [],
|
|
467
|
-
outputs: rootOutputs.outputs,
|
|
468
|
-
changePosition: rootOutputs.changePosition,
|
|
469
|
-
expectedOpReturnScriptHex: rootOutputs.expectedOpReturnScriptHex,
|
|
470
|
-
expectedTreasuryOutputIndex: 1,
|
|
471
|
-
expectedTreasuryScriptHex: options.treasuryScriptPubKeyHex,
|
|
472
|
-
expectedTreasuryValueSats: options.rootPriceSats,
|
|
473
|
-
expectedAnchorOutputIndex: null,
|
|
474
|
-
expectedAnchorScriptHex: null,
|
|
475
|
-
expectedAnchorValueSats: null,
|
|
476
|
-
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
477
|
-
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey(entry))),
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
const anchorUtxo = options.allUtxos.find((entry) => entry.txid === options.anchorOutpoint?.txid
|
|
481
|
-
&& entry.vout === options.anchorOutpoint.vout
|
|
482
|
-
&& entry.scriptPubKey === options.sender.scriptPubKeyHex
|
|
483
|
-
&& isSpendableConfirmedUtxo(entry));
|
|
484
|
-
if (anchorUtxo === undefined) {
|
|
485
|
-
throw new Error("wallet_register_anchor_utxo_missing");
|
|
486
|
-
}
|
|
487
338
|
return {
|
|
488
339
|
registerKind: "root",
|
|
489
340
|
sender: options.sender,
|
|
490
341
|
changeAddress: options.state.funding.address,
|
|
491
|
-
fixedInputs: [
|
|
492
|
-
{ txid: anchorUtxo.txid, vout: anchorUtxo.vout },
|
|
493
|
-
],
|
|
342
|
+
fixedInputs: [],
|
|
494
343
|
outputs: rootOutputs.outputs,
|
|
495
344
|
changePosition: rootOutputs.changePosition,
|
|
496
345
|
expectedOpReturnScriptHex: rootOutputs.expectedOpReturnScriptHex,
|
|
497
346
|
expectedTreasuryOutputIndex: 1,
|
|
498
347
|
expectedTreasuryScriptHex: options.treasuryScriptPubKeyHex,
|
|
499
348
|
expectedTreasuryValueSats: options.rootPriceSats,
|
|
500
|
-
expectedAnchorOutputIndex: 2,
|
|
501
|
-
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
502
|
-
expectedAnchorValueSats: options.anchorValueSats,
|
|
503
349
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
504
350
|
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey(entry))),
|
|
505
351
|
};
|
|
506
352
|
}
|
|
507
|
-
const anchor = options.anchorOutpoint;
|
|
508
|
-
if (anchor === null) {
|
|
509
|
-
throw new Error("wallet_register_anchor_outpoint_unavailable");
|
|
510
|
-
}
|
|
511
|
-
const anchorUtxo = options.allUtxos.find((entry) => entry.txid === anchor.txid
|
|
512
|
-
&& entry.vout === anchor.vout
|
|
513
|
-
&& entry.scriptPubKey === options.sender.scriptPubKeyHex
|
|
514
|
-
&& isSpendableConfirmedUtxo(entry));
|
|
515
|
-
if (anchorUtxo === undefined) {
|
|
516
|
-
throw new Error("wallet_register_anchor_utxo_missing");
|
|
517
|
-
}
|
|
518
353
|
const subdomainOutputs = buildSubdomainRegisterOutputs({
|
|
519
354
|
domainName: options.domainName,
|
|
520
|
-
senderAddress: options.sender.address,
|
|
521
|
-
anchorValueSats: options.anchorValueSats,
|
|
522
355
|
});
|
|
523
356
|
return {
|
|
524
357
|
registerKind: "subdomain",
|
|
525
358
|
sender: options.sender,
|
|
526
359
|
changeAddress: options.state.funding.address,
|
|
527
|
-
fixedInputs: [
|
|
528
|
-
{ txid: anchorUtxo.txid, vout: anchorUtxo.vout },
|
|
529
|
-
],
|
|
360
|
+
fixedInputs: [],
|
|
530
361
|
outputs: subdomainOutputs.outputs,
|
|
531
362
|
changePosition: subdomainOutputs.changePosition,
|
|
532
363
|
expectedOpReturnScriptHex: subdomainOutputs.expectedOpReturnScriptHex,
|
|
533
364
|
expectedTreasuryOutputIndex: null,
|
|
534
365
|
expectedTreasuryScriptHex: null,
|
|
535
366
|
expectedTreasuryValueSats: null,
|
|
536
|
-
expectedAnchorOutputIndex: 1,
|
|
537
|
-
expectedAnchorScriptHex: options.sender.scriptPubKeyHex,
|
|
538
|
-
expectedAnchorValueSats: options.anchorValueSats,
|
|
539
367
|
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
540
368
|
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey(entry))),
|
|
541
369
|
};
|
|
@@ -549,7 +377,7 @@ async function buildRegisterTransaction(options) {
|
|
|
549
377
|
validateFundedDraft,
|
|
550
378
|
finalizeErrorCode: "wallet_register_finalize_failed",
|
|
551
379
|
mempoolRejectPrefix: "wallet_register_mempool_rejected",
|
|
552
|
-
|
|
380
|
+
feeRate: options.feeRateSatVb,
|
|
553
381
|
});
|
|
554
382
|
}
|
|
555
383
|
async function reconcilePendingRegisterMutation(options) {
|
|
@@ -573,7 +401,6 @@ async function reconcilePendingRegisterMutation(options) {
|
|
|
573
401
|
await saveWalletStatePreservingUnlock({
|
|
574
402
|
state: nextState,
|
|
575
403
|
provider: options.provider,
|
|
576
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
577
404
|
nowUnixMs: options.nowUnixMs,
|
|
578
405
|
paths: options.paths,
|
|
579
406
|
});
|
|
@@ -596,7 +423,6 @@ async function reconcilePendingRegisterMutation(options) {
|
|
|
596
423
|
await saveWalletStatePreservingUnlock({
|
|
597
424
|
state: nextState,
|
|
598
425
|
provider: options.provider,
|
|
599
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
600
426
|
nowUnixMs: options.nowUnixMs,
|
|
601
427
|
paths: options.paths,
|
|
602
428
|
});
|
|
@@ -622,7 +448,6 @@ async function reconcilePendingRegisterMutation(options) {
|
|
|
622
448
|
await saveWalletStatePreservingUnlock({
|
|
623
449
|
state: nextState,
|
|
624
450
|
provider: options.provider,
|
|
625
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
626
451
|
nowUnixMs: options.nowUnixMs,
|
|
627
452
|
paths: options.paths,
|
|
628
453
|
});
|
|
@@ -645,7 +470,6 @@ async function reconcilePendingRegisterMutation(options) {
|
|
|
645
470
|
await saveWalletStatePreservingUnlock({
|
|
646
471
|
state: nextState,
|
|
647
472
|
provider: options.provider,
|
|
648
|
-
unlockUntilUnixMs: options.unlockUntilUnixMs,
|
|
649
473
|
nowUnixMs: options.nowUnixMs,
|
|
650
474
|
paths: options.paths,
|
|
651
475
|
});
|
|
@@ -688,7 +512,6 @@ export async function registerDomain(options) {
|
|
|
688
512
|
try {
|
|
689
513
|
assertWalletMutationContextReady(readContext, "wallet_register");
|
|
690
514
|
const state = readContext.localState.state;
|
|
691
|
-
const unlockUntilUnixMs = readContext.localState.unlockUntilUnixMs;
|
|
692
515
|
const senderResolution = resolveRegisterSender(readContext, normalizedDomainName, options.fromIdentity);
|
|
693
516
|
const intentFingerprintHex = createRegisterIntentFingerprint({
|
|
694
517
|
walletRootId: state.walletRootId,
|
|
@@ -713,13 +536,18 @@ export async function registerDomain(options) {
|
|
|
713
536
|
});
|
|
714
537
|
const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
|
|
715
538
|
const walletName = state.managedCoreWallet.walletName;
|
|
539
|
+
const feeSelection = await resolveWalletMutationFeeSelection({
|
|
540
|
+
rpc,
|
|
541
|
+
feeRateSatVb: options.feeRateSatVb ?? null,
|
|
542
|
+
});
|
|
716
543
|
const existingMutation = findPendingMutationByIntent(state, intentFingerprintHex);
|
|
544
|
+
let workingState = state;
|
|
545
|
+
let replacementFixedInputs = null;
|
|
717
546
|
if (existingMutation !== null) {
|
|
718
547
|
const reconciled = await reconcilePendingRegisterMutation({
|
|
719
548
|
state,
|
|
720
549
|
mutation: existingMutation,
|
|
721
550
|
provider,
|
|
722
|
-
unlockUntilUnixMs,
|
|
723
551
|
nowUnixMs,
|
|
724
552
|
paths,
|
|
725
553
|
rpc,
|
|
@@ -727,22 +555,33 @@ export async function registerDomain(options) {
|
|
|
727
555
|
context: readContext,
|
|
728
556
|
sender: senderResolution.sender,
|
|
729
557
|
});
|
|
558
|
+
workingState = reconciled.state;
|
|
730
559
|
if (reconciled.resolution === "confirmed" || reconciled.resolution === "live") {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
560
|
+
const reuse = await resolvePendingMutationReuseDecision({
|
|
561
|
+
rpc,
|
|
562
|
+
walletName,
|
|
563
|
+
mutation: reconciled.mutation,
|
|
564
|
+
nextFeeSelection: feeSelection,
|
|
565
|
+
});
|
|
566
|
+
if (reuse.reuseExisting) {
|
|
567
|
+
return {
|
|
568
|
+
domainName: normalizedDomainName,
|
|
569
|
+
registerKind: senderResolution.registerKind,
|
|
570
|
+
parentDomainName: senderResolution.parentDomainName,
|
|
571
|
+
senderSelector: senderResolution.senderSelector,
|
|
572
|
+
senderLocalIndex: senderResolution.sender.localIndex,
|
|
573
|
+
senderScriptPubKeyHex: senderResolution.sender.scriptPubKeyHex,
|
|
574
|
+
senderAddress: senderResolution.sender.address,
|
|
575
|
+
economicEffectKind: senderResolution.registerKind === "root" ? "treasury-payment" : "cog-burn",
|
|
576
|
+
economicEffectAmount: senderResolution.registerKind === "root" ? rootPriceSats : SUBDOMAIN_REGISTRATION_FEE_COGTOSHI,
|
|
577
|
+
resolved: resolvedSummary,
|
|
578
|
+
txid: reconciled.mutation.attemptedTxid ?? "unknown",
|
|
579
|
+
status: reconciled.resolution,
|
|
580
|
+
reusedExisting: true,
|
|
581
|
+
fees: reuse.fees,
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
replacementFixedInputs = reuse.replacementFixedInputs;
|
|
746
585
|
}
|
|
747
586
|
if (reconciled.resolution === "repair-required") {
|
|
748
587
|
throw new Error("wallet_register_repair_required");
|
|
@@ -767,13 +606,14 @@ export async function registerDomain(options) {
|
|
|
767
606
|
else {
|
|
768
607
|
await confirmSubdomainRegistration(options.prompter, normalizedDomainName, resolvedSummary, options.assumeYes);
|
|
769
608
|
}
|
|
770
|
-
let nextState = upsertPendingMutation(
|
|
609
|
+
let nextState = upsertPendingMutation(workingState, createDraftMutation({
|
|
771
610
|
domainName: normalizedDomainName,
|
|
772
611
|
parentDomainName: senderResolution.parentDomainName,
|
|
773
612
|
sender: senderResolution.sender,
|
|
774
613
|
registerKind: senderResolution.registerKind,
|
|
775
614
|
intentFingerprintHex,
|
|
776
615
|
nowUnixMs,
|
|
616
|
+
feeSelection,
|
|
777
617
|
existing: existingMutation,
|
|
778
618
|
}));
|
|
779
619
|
nextState = {
|
|
@@ -784,7 +624,6 @@ export async function registerDomain(options) {
|
|
|
784
624
|
await saveWalletStatePreservingUnlock({
|
|
785
625
|
state: nextState,
|
|
786
626
|
provider,
|
|
787
|
-
unlockUntilUnixMs,
|
|
788
627
|
nowUnixMs,
|
|
789
628
|
paths,
|
|
790
629
|
});
|
|
@@ -794,20 +633,22 @@ export async function registerDomain(options) {
|
|
|
794
633
|
state: nextState,
|
|
795
634
|
allUtxos,
|
|
796
635
|
sender: senderResolution.sender,
|
|
797
|
-
anchorOutpoint: senderResolution.anchorOutpoint,
|
|
798
636
|
registerKind: senderResolution.registerKind,
|
|
799
637
|
domainName: normalizedDomainName,
|
|
800
638
|
parentDomainName: senderResolution.parentDomainName,
|
|
801
639
|
treasuryAddress: genesis.treasuryAddress,
|
|
802
640
|
treasuryScriptPubKeyHex: Buffer.from(genesis.treasuryScriptPubKey).toString("hex"),
|
|
803
|
-
anchorValueSats: BigInt(nextState.anchorValueSats),
|
|
804
641
|
rootPriceSats,
|
|
805
642
|
});
|
|
806
643
|
const built = await buildRegisterTransaction({
|
|
807
644
|
rpc,
|
|
808
645
|
walletName,
|
|
809
646
|
state: nextState,
|
|
810
|
-
plan
|
|
647
|
+
plan: {
|
|
648
|
+
...plan,
|
|
649
|
+
fixedInputs: mergeFixedWalletInputs(plan.fixedInputs, replacementFixedInputs),
|
|
650
|
+
},
|
|
651
|
+
feeRateSatVb: feeSelection.feeRateSatVb,
|
|
811
652
|
});
|
|
812
653
|
const currentMutation = nextState.pendingMutations?.find((mutation) => mutation.intentFingerprintHex === intentFingerprintHex)
|
|
813
654
|
?? createDraftMutation({
|
|
@@ -817,6 +658,7 @@ export async function registerDomain(options) {
|
|
|
817
658
|
registerKind: senderResolution.registerKind,
|
|
818
659
|
intentFingerprintHex,
|
|
819
660
|
nowUnixMs,
|
|
661
|
+
feeSelection,
|
|
820
662
|
});
|
|
821
663
|
const broadcastingMutation = updateMutationRecord(currentMutation, "broadcasting", nowUnixMs, {
|
|
822
664
|
attemptedTxid: built.txid,
|
|
@@ -831,7 +673,6 @@ export async function registerDomain(options) {
|
|
|
831
673
|
await saveWalletStatePreservingUnlock({
|
|
832
674
|
state: nextState,
|
|
833
675
|
provider,
|
|
834
|
-
unlockUntilUnixMs,
|
|
835
676
|
nowUnixMs,
|
|
836
677
|
paths,
|
|
837
678
|
});
|
|
@@ -863,7 +704,6 @@ export async function registerDomain(options) {
|
|
|
863
704
|
await saveWalletStatePreservingUnlock({
|
|
864
705
|
state: nextState,
|
|
865
706
|
provider,
|
|
866
|
-
unlockUntilUnixMs,
|
|
867
707
|
nowUnixMs,
|
|
868
708
|
paths,
|
|
869
709
|
});
|
|
@@ -884,7 +724,6 @@ export async function registerDomain(options) {
|
|
|
884
724
|
await saveWalletStatePreservingUnlock({
|
|
885
725
|
state: nextState,
|
|
886
726
|
provider,
|
|
887
|
-
unlockUntilUnixMs,
|
|
888
727
|
nowUnixMs,
|
|
889
728
|
paths,
|
|
890
729
|
});
|
|
@@ -919,7 +758,6 @@ export async function registerDomain(options) {
|
|
|
919
758
|
await saveWalletStatePreservingUnlock({
|
|
920
759
|
state: nextState,
|
|
921
760
|
provider,
|
|
922
|
-
unlockUntilUnixMs,
|
|
923
761
|
nowUnixMs,
|
|
924
762
|
paths,
|
|
925
763
|
});
|
|
@@ -937,6 +775,10 @@ export async function registerDomain(options) {
|
|
|
937
775
|
txid: built.txid,
|
|
938
776
|
status: finalStatus,
|
|
939
777
|
reusedExisting: false,
|
|
778
|
+
fees: createBuiltWalletMutationFeeSummary({
|
|
779
|
+
selection: feeSelection,
|
|
780
|
+
built,
|
|
781
|
+
}),
|
|
940
782
|
};
|
|
941
783
|
}
|
|
942
784
|
finally {
|
|
@@ -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
|
interface ReputationRpcClient extends WalletMutationRpcClient {
|
|
10
10
|
getBlockchainInfo(): Promise<{
|
|
11
11
|
blocks: number;
|
|
@@ -23,6 +23,7 @@ export interface ReputationMutationResult {
|
|
|
23
23
|
reusedExisting: boolean;
|
|
24
24
|
reviewIncluded: boolean;
|
|
25
25
|
resolved?: ReputationResolvedSummary | null;
|
|
26
|
+
fees: WalletMutationFeeSummary;
|
|
26
27
|
}
|
|
27
28
|
export interface ReputationResolvedSenderSummary {
|
|
28
29
|
selector: string;
|
|
@@ -52,6 +53,7 @@ interface ReputationBaseOptions {
|
|
|
52
53
|
targetDomainName: string;
|
|
53
54
|
amountCogtoshi: bigint;
|
|
54
55
|
reviewText?: string | null;
|
|
56
|
+
feeRateSatVb?: number | null;
|
|
55
57
|
dataDir: string;
|
|
56
58
|
databasePath: string;
|
|
57
59
|
provider?: WalletSecretProvider;
|