@cogcoin/client 1.1.7 → 1.1.9
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 +1 -1
- package/dist/bitcoind/service.js +1 -1
- package/dist/cli/commands/mining-read.js +1 -1
- package/dist/cli/commands/wallet-mutation/anchor.d.ts +2 -0
- package/dist/cli/commands/wallet-mutation/anchor.js +33 -0
- package/dist/cli/commands/wallet-mutation/bitcoin-transfer.d.ts +2 -0
- package/dist/cli/commands/wallet-mutation/bitcoin-transfer.js +32 -0
- package/dist/cli/commands/wallet-mutation/cog.d.ts +2 -0
- package/dist/cli/commands/wallet-mutation/cog.js +131 -0
- package/dist/cli/commands/wallet-mutation/context.d.ts +3 -0
- package/dist/cli/commands/wallet-mutation/context.js +18 -0
- package/dist/cli/commands/wallet-mutation/domain-admin.d.ts +2 -0
- package/dist/cli/commands/wallet-mutation/domain-admin.js +173 -0
- package/dist/cli/commands/wallet-mutation/domain-market.d.ts +2 -0
- package/dist/cli/commands/wallet-mutation/domain-market.js +107 -0
- package/dist/cli/commands/wallet-mutation/field.d.ts +2 -0
- package/dist/cli/commands/wallet-mutation/field.js +125 -0
- package/dist/cli/commands/wallet-mutation/register.d.ts +2 -0
- package/dist/cli/commands/wallet-mutation/register.js +38 -0
- package/dist/cli/commands/wallet-mutation/registry.d.ts +3 -0
- package/dist/cli/commands/wallet-mutation/registry.js +39 -0
- package/dist/cli/commands/wallet-mutation/reputation.d.ts +2 -0
- package/dist/cli/commands/wallet-mutation/reputation.js +57 -0
- package/dist/cli/commands/wallet-mutation/types.d.ts +32 -0
- package/dist/cli/commands/wallet-mutation/types.js +1 -0
- package/dist/cli/commands/wallet-mutation.js +13 -765
- package/dist/cli/commands/wallet-read.js +4 -4
- package/dist/cli/mutation-success.d.ts +0 -2
- package/dist/cli/output/classify.d.ts +7 -0
- package/dist/cli/output/classify.js +94 -0
- package/dist/cli/output/render.d.ts +2 -0
- package/dist/cli/output/render.js +13 -0
- package/dist/cli/output/rules/cli-surface.d.ts +2 -0
- package/dist/cli/output/rules/cli-surface.js +110 -0
- package/dist/cli/output/rules/generic.d.ts +2 -0
- package/dist/cli/output/rules/generic.js +13 -0
- package/dist/cli/output/rules/index.d.ts +2 -0
- package/dist/cli/output/rules/index.js +24 -0
- package/dist/cli/output/rules/mining-update.d.ts +2 -0
- package/dist/cli/output/rules/mining-update.js +68 -0
- package/dist/cli/output/rules/services.d.ts +2 -0
- package/dist/cli/output/rules/services.js +110 -0
- package/dist/cli/output/rules/wallet-admin.d.ts +2 -0
- package/dist/cli/output/rules/wallet-admin.js +224 -0
- package/dist/cli/output/rules/wallet-mutations.d.ts +2 -0
- package/dist/cli/output/rules/wallet-mutations.js +274 -0
- package/dist/cli/output/types.d.ts +16 -0
- package/dist/cli/output/types.js +1 -0
- package/dist/cli/output.d.ts +2 -168
- package/dist/cli/output.js +6 -989
- package/dist/cli/pagination.d.ts +15 -0
- package/dist/cli/pagination.js +16 -0
- package/dist/cli/recommendations.d.ts +4 -0
- package/dist/cli/recommendations.js +108 -0
- package/dist/cli/wallet-format/availability.d.ts +5 -0
- package/dist/cli/wallet-format/availability.js +96 -0
- package/dist/cli/wallet-format/balance.d.ts +2 -0
- package/dist/cli/wallet-format/balance.js +162 -0
- package/dist/cli/wallet-format/domains.d.ts +8 -0
- package/dist/cli/wallet-format/domains.js +84 -0
- package/dist/cli/wallet-format/fields.d.ts +6 -0
- package/dist/cli/wallet-format/fields.js +61 -0
- package/dist/cli/wallet-format/identity.d.ts +5 -0
- package/dist/cli/wallet-format/identity.js +19 -0
- package/dist/cli/wallet-format/locks.d.ts +7 -0
- package/dist/cli/wallet-format/locks.js +52 -0
- package/dist/cli/wallet-format/overview.d.ts +2 -0
- package/dist/cli/wallet-format/overview.js +122 -0
- package/dist/cli/wallet-format/pending.d.ts +13 -0
- package/dist/cli/wallet-format/pending.js +101 -0
- package/dist/cli/wallet-format/shared.d.ts +7 -0
- package/dist/cli/wallet-format/shared.js +31 -0
- package/dist/cli/wallet-format/status.d.ts +3 -0
- package/dist/cli/wallet-format/status.js +27 -0
- package/dist/cli/wallet-format.d.ts +8 -30
- package/dist/cli/wallet-format.js +8 -830
- package/dist/cli/wallet-read-helpers.d.ts +6 -0
- package/dist/cli/wallet-read-helpers.js +17 -0
- package/dist/wallet/mining/candidate.d.ts +1 -1
- package/dist/wallet/mining/candidate.js +3 -3
- package/dist/wallet/mining/constants.d.ts +2 -2
- package/dist/wallet/mining/constants.js +2 -2
- package/dist/wallet/mining/engine-state.js +10 -0
- package/dist/wallet/mining/sentence-protocol.d.ts +2 -2
- package/dist/wallet/mining/sentences.js +8 -8
- package/dist/wallet/mining/visualizer-sync.js +79 -15
- package/dist/wallet/read/context.js +1 -1
- package/dist/wallet/reset/artifacts.d.ts +16 -0
- package/dist/wallet/reset/artifacts.js +141 -0
- package/dist/wallet/reset/execution.d.ts +38 -0
- package/dist/wallet/reset/execution.js +458 -0
- package/dist/wallet/reset/preflight.d.ts +7 -0
- package/dist/wallet/reset/preflight.js +116 -0
- package/dist/wallet/reset/preview.d.ts +2 -0
- package/dist/wallet/reset/preview.js +50 -0
- package/dist/wallet/reset/process-cleanup.d.ts +12 -0
- package/dist/wallet/reset/process-cleanup.js +179 -0
- package/dist/wallet/reset/types.d.ts +189 -0
- package/dist/wallet/reset/types.js +1 -0
- package/dist/wallet/reset.d.ts +4 -119
- package/dist/wallet/reset.js +4 -882
- package/dist/wallet/tx/anchor/confirm.d.ts +15 -0
- package/dist/wallet/tx/anchor/confirm.js +60 -0
- package/dist/wallet/tx/anchor/draft.d.ts +39 -0
- package/dist/wallet/tx/anchor/draft.js +167 -0
- package/dist/wallet/tx/anchor/index.d.ts +5 -0
- package/dist/wallet/tx/anchor/index.js +148 -0
- package/dist/wallet/tx/anchor/intent.d.ts +61 -0
- package/dist/wallet/tx/anchor/intent.js +101 -0
- package/dist/wallet/tx/anchor/plan.d.ts +3 -0
- package/dist/wallet/tx/anchor/plan.js +18 -0
- package/dist/wallet/tx/anchor/result.d.ts +25 -0
- package/dist/wallet/tx/anchor/result.js +20 -0
- package/dist/wallet/tx/anchor.d.ts +1 -39
- package/dist/wallet/tx/anchor.js +1 -494
- package/dist/wallet/tx/bitcoin-transfer/confirm.d.ts +7 -0
- package/dist/wallet/tx/bitcoin-transfer/confirm.js +11 -0
- package/dist/wallet/tx/bitcoin-transfer/index.d.ts +5 -0
- package/dist/wallet/tx/bitcoin-transfer/index.js +112 -0
- package/dist/wallet/tx/bitcoin-transfer/intent.d.ts +52 -0
- package/dist/wallet/tx/bitcoin-transfer/intent.js +74 -0
- package/dist/wallet/tx/bitcoin-transfer/plan.d.ts +5 -0
- package/dist/wallet/tx/bitcoin-transfer/plan.js +21 -0
- package/dist/wallet/tx/bitcoin-transfer/result.d.ts +19 -0
- package/dist/wallet/tx/bitcoin-transfer/result.js +16 -0
- package/dist/wallet/tx/bitcoin-transfer.d.ts +1 -35
- package/dist/wallet/tx/bitcoin-transfer.js +1 -200
- package/dist/wallet/tx/cog/confirm.d.ts +13 -0
- package/dist/wallet/tx/cog/confirm.js +59 -0
- package/dist/wallet/tx/cog/draft.d.ts +20 -0
- package/dist/wallet/tx/cog/draft.js +114 -0
- package/dist/wallet/tx/cog/index.d.ts +6 -0
- package/dist/wallet/tx/cog/index.js +117 -0
- package/dist/wallet/tx/cog/intent.d.ts +30 -0
- package/dist/wallet/tx/cog/intent.js +169 -0
- package/dist/wallet/tx/cog/plan.d.ts +19 -0
- package/dist/wallet/tx/cog/plan.js +65 -0
- package/dist/wallet/tx/cog/result.d.ts +27 -0
- package/dist/wallet/tx/cog/result.js +28 -0
- package/dist/wallet/tx/cog/types.d.ts +186 -0
- package/dist/wallet/tx/cog/types.js +2 -0
- package/dist/wallet/tx/cog/variants/claim.d.ts +3 -0
- package/dist/wallet/tx/cog/variants/claim.js +92 -0
- package/dist/wallet/tx/cog/variants/lock.d.ts +2 -0
- package/dist/wallet/tx/cog/variants/lock.js +102 -0
- package/dist/wallet/tx/cog/variants/send.d.ts +2 -0
- package/dist/wallet/tx/cog/variants/send.js +77 -0
- package/dist/wallet/tx/cog.d.ts +1 -96
- package/dist/wallet/tx/cog.js +1 -824
- package/dist/wallet/tx/common.d.ts +14 -199
- package/dist/wallet/tx/common.js +10 -493
- package/dist/wallet/tx/domain-admin/confirm.d.ts +17 -0
- package/dist/wallet/tx/domain-admin/confirm.js +58 -0
- package/dist/wallet/tx/domain-admin/draft.d.ts +20 -0
- package/dist/wallet/tx/domain-admin/draft.js +161 -0
- package/dist/wallet/tx/domain-admin/index.d.ts +9 -0
- package/dist/wallet/tx/domain-admin/index.js +150 -0
- package/dist/wallet/tx/domain-admin/intent.d.ts +12 -0
- package/dist/wallet/tx/domain-admin/intent.js +61 -0
- package/dist/wallet/tx/domain-admin/plan.d.ts +19 -0
- package/dist/wallet/tx/domain-admin/plan.js +64 -0
- package/dist/wallet/tx/domain-admin/result.d.ts +19 -0
- package/dist/wallet/tx/domain-admin/result.js +33 -0
- package/dist/wallet/tx/domain-admin/types.d.ts +162 -0
- package/dist/wallet/tx/domain-admin/types.js +1 -0
- package/dist/wallet/tx/domain-admin/variants/canonical.d.ts +2 -0
- package/dist/wallet/tx/domain-admin/variants/canonical.js +22 -0
- package/dist/wallet/tx/domain-admin/variants/delegate.d.ts +3 -0
- package/dist/wallet/tx/domain-admin/variants/delegate.js +60 -0
- package/dist/wallet/tx/domain-admin/variants/endpoint.d.ts +3 -0
- package/dist/wallet/tx/domain-admin/variants/endpoint.js +102 -0
- package/dist/wallet/tx/domain-admin/variants/miner.d.ts +3 -0
- package/dist/wallet/tx/domain-admin/variants/miner.js +59 -0
- package/dist/wallet/tx/domain-admin.d.ts +1 -107
- package/dist/wallet/tx/domain-admin.js +1 -729
- package/dist/wallet/tx/domain-market/confirm.d.ts +6 -0
- package/dist/wallet/tx/domain-market/confirm.js +52 -0
- package/dist/wallet/tx/domain-market/draft.d.ts +43 -0
- package/dist/wallet/tx/domain-market/draft.js +286 -0
- package/dist/wallet/tx/domain-market/index.d.ts +6 -0
- package/dist/wallet/tx/domain-market/index.js +145 -0
- package/dist/wallet/tx/domain-market/intent.d.ts +15 -0
- package/dist/wallet/tx/domain-market/intent.js +131 -0
- package/dist/wallet/tx/domain-market/plan.d.ts +31 -0
- package/dist/wallet/tx/domain-market/plan.js +98 -0
- package/dist/wallet/tx/domain-market/result.d.ts +45 -0
- package/dist/wallet/tx/domain-market/result.js +88 -0
- package/dist/wallet/tx/domain-market/types.d.ts +221 -0
- package/dist/wallet/tx/domain-market/types.js +1 -0
- package/dist/wallet/tx/domain-market/variants/buy.d.ts +2 -0
- package/dist/wallet/tx/domain-market/variants/buy.js +103 -0
- package/dist/wallet/tx/domain-market/variants/sell.d.ts +2 -0
- package/dist/wallet/tx/domain-market/variants/sell.js +91 -0
- package/dist/wallet/tx/domain-market/variants/transfer.d.ts +2 -0
- package/dist/wallet/tx/domain-market/variants/transfer.js +105 -0
- package/dist/wallet/tx/domain-market.d.ts +1 -116
- package/dist/wallet/tx/domain-market.js +1 -1078
- package/dist/wallet/tx/draft-build.d.ts +60 -0
- package/dist/wallet/tx/draft-build.js +127 -0
- package/dist/wallet/tx/executor.d.ts +6 -40
- package/dist/wallet/tx/executor.js +6 -100
- package/dist/wallet/tx/fee.d.ts +30 -0
- package/dist/wallet/tx/fee.js +98 -0
- package/dist/wallet/tx/field/confirm.d.ts +11 -0
- package/dist/wallet/tx/field/confirm.js +19 -0
- package/dist/wallet/tx/field/draft.d.ts +23 -0
- package/dist/wallet/tx/field/draft.js +202 -0
- package/dist/wallet/tx/field/index.d.ts +5 -0
- package/dist/wallet/tx/field/index.js +140 -0
- package/dist/wallet/tx/field/intent.d.ts +5 -0
- package/dist/wallet/tx/field/intent.js +50 -0
- package/dist/wallet/tx/field/plan.d.ts +20 -0
- package/dist/wallet/tx/field/plan.js +65 -0
- package/dist/wallet/tx/field/result.d.ts +29 -0
- package/dist/wallet/tx/field/result.js +103 -0
- package/dist/wallet/tx/field/types.d.ts +163 -0
- package/dist/wallet/tx/field/types.js +1 -0
- package/dist/wallet/tx/field/variants/clear.d.ts +2 -0
- package/dist/wallet/tx/field/variants/clear.js +60 -0
- package/dist/wallet/tx/field/variants/create.d.ts +2 -0
- package/dist/wallet/tx/field/variants/create.js +67 -0
- package/dist/wallet/tx/field/variants/set.d.ts +2 -0
- package/dist/wallet/tx/field/variants/set.js +195 -0
- package/dist/wallet/tx/field.d.ts +1 -95
- package/dist/wallet/tx/field.js +1 -920
- package/dist/wallet/tx/mining-preemption.d.ts +6 -0
- package/dist/wallet/tx/mining-preemption.js +7 -0
- package/dist/wallet/tx/primitives.d.ts +13 -0
- package/dist/wallet/tx/primitives.js +42 -0
- package/dist/wallet/tx/psbt-assert.d.ts +14 -0
- package/dist/wallet/tx/psbt-assert.js +39 -0
- package/dist/wallet/tx/publish.d.ts +37 -0
- package/dist/wallet/tx/publish.js +88 -0
- package/dist/wallet/tx/readiness.d.ts +7 -0
- package/dist/wallet/tx/readiness.js +61 -0
- package/dist/wallet/tx/reconcile.d.ts +24 -0
- package/dist/wallet/tx/reconcile.js +72 -0
- package/dist/wallet/tx/register/confirm.d.ts +6 -0
- package/dist/wallet/tx/register/confirm.js +66 -0
- package/dist/wallet/tx/register/draft.d.ts +42 -0
- package/dist/wallet/tx/register/draft.js +181 -0
- package/dist/wallet/tx/register/index.d.ts +6 -0
- package/dist/wallet/tx/register/index.js +158 -0
- package/dist/wallet/tx/register/intent.d.ts +74 -0
- package/dist/wallet/tx/register/intent.js +119 -0
- package/dist/wallet/tx/register/plan.d.ts +43 -0
- package/dist/wallet/tx/register/plan.js +168 -0
- package/dist/wallet/tx/register/result.d.ts +78 -0
- package/dist/wallet/tx/register/result.js +41 -0
- package/dist/wallet/tx/register.d.ts +1 -70
- package/dist/wallet/tx/register.js +1 -681
- package/dist/wallet/tx/reputation/confirm.d.ts +11 -0
- package/dist/wallet/tx/reputation/confirm.js +51 -0
- package/dist/wallet/tx/reputation/draft.d.ts +20 -0
- package/dist/wallet/tx/reputation/draft.js +130 -0
- package/dist/wallet/tx/reputation/index.d.ts +4 -0
- package/dist/wallet/tx/reputation/index.js +162 -0
- package/dist/wallet/tx/reputation/intent.d.ts +36 -0
- package/dist/wallet/tx/reputation/intent.js +157 -0
- package/dist/wallet/tx/reputation/plan.d.ts +19 -0
- package/dist/wallet/tx/reputation/plan.js +64 -0
- package/dist/wallet/tx/reputation/result.d.ts +21 -0
- package/dist/wallet/tx/reputation/result.js +31 -0
- package/dist/wallet/tx/reputation/types.d.ts +130 -0
- package/dist/wallet/tx/reputation/types.js +1 -0
- package/dist/wallet/tx/reputation.d.ts +1 -74
- package/dist/wallet/tx/reputation.js +1 -556
- package/dist/wallet/tx/signing.d.ts +18 -0
- package/dist/wallet/tx/signing.js +31 -0
- package/dist/wallet/tx/state-persist.d.ts +27 -0
- package/dist/wallet/tx/state-persist.js +54 -0
- package/dist/wallet/tx/types.d.ts +44 -0
- package/dist/wallet/tx/types.js +1 -0
- package/package.json +1 -1
- package/dist/cli/mining-json.d.ts +0 -20
- package/dist/cli/mining-json.js +0 -46
- package/dist/cli/mutation-json.d.ts +0 -325
- package/dist/cli/mutation-json.js +0 -269
- package/dist/cli/mutation-resolved-json.d.ts +0 -117
- package/dist/cli/mutation-resolved-json.js +0 -123
- package/dist/cli/preview-json.d.ts +0 -319
- package/dist/cli/preview-json.js +0 -254
- package/dist/cli/read-json.d.ts +0 -190
- package/dist/cli/read-json.js +0 -627
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { RpcListUnspentEntry } from "../../../bitcoind/types.js";
|
|
2
|
+
import { attachOrStartManagedBitcoindService } from "../../../bitcoind/service.js";
|
|
3
|
+
import { createRpcClient } from "../../../bitcoind/node.js";
|
|
4
|
+
import type { WalletPrompter } from "../../lifecycle.js";
|
|
5
|
+
import { openWalletReadContext } from "../../read/index.js";
|
|
6
|
+
import type { WalletRuntimePaths } from "../../runtime.js";
|
|
7
|
+
import type { WalletSecretProvider } from "../../state/provider.js";
|
|
8
|
+
import type { WalletStateV1 } from "../../types.js";
|
|
9
|
+
import type { FixedWalletInput, WalletMutationRpcClient } from "../common.js";
|
|
10
|
+
export interface WalletBitcoinTransferRpcClient extends WalletMutationRpcClient {
|
|
11
|
+
sendRawTransaction(hex: string): Promise<string>;
|
|
12
|
+
}
|
|
13
|
+
export interface TransferBitcoinOptions {
|
|
14
|
+
amountSatsText: string;
|
|
15
|
+
target: string;
|
|
16
|
+
dataDir: string;
|
|
17
|
+
databasePath: string;
|
|
18
|
+
provider?: WalletSecretProvider;
|
|
19
|
+
prompter: WalletPrompter;
|
|
20
|
+
assumeYes?: boolean;
|
|
21
|
+
paths?: WalletRuntimePaths;
|
|
22
|
+
openReadContext?: typeof openWalletReadContext;
|
|
23
|
+
attachService?: typeof attachOrStartManagedBitcoindService;
|
|
24
|
+
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletBitcoinTransferRpcClient;
|
|
25
|
+
}
|
|
26
|
+
export interface BitcoinTransferIntent {
|
|
27
|
+
amountSats: bigint;
|
|
28
|
+
recipientAddress: string;
|
|
29
|
+
recipientScriptPubKeyHex: string;
|
|
30
|
+
}
|
|
31
|
+
export interface BitcoinTransferPlan {
|
|
32
|
+
fixedInputs: FixedWalletInput[];
|
|
33
|
+
outputs: unknown[];
|
|
34
|
+
changeAddress: string;
|
|
35
|
+
changePosition: number | null;
|
|
36
|
+
allowedFundingScriptPubKeyHex: string;
|
|
37
|
+
eligibleFundingOutpointKeys: Set<string>;
|
|
38
|
+
recipientScriptPubKeyHex: string;
|
|
39
|
+
amountSats: bigint;
|
|
40
|
+
}
|
|
41
|
+
export declare function resolveBitcoinTransferIntent(options: TransferBitcoinOptions): BitcoinTransferIntent;
|
|
42
|
+
export declare function buildPlanForBitcoinTransfer(options: {
|
|
43
|
+
state: WalletStateV1;
|
|
44
|
+
allUtxos: RpcListUnspentEntry[];
|
|
45
|
+
recipientAddress: string;
|
|
46
|
+
recipientScriptPubKeyHex: string;
|
|
47
|
+
amountSats: bigint;
|
|
48
|
+
outpointKey(outpoint: {
|
|
49
|
+
txid: string;
|
|
50
|
+
vout: number;
|
|
51
|
+
}): string;
|
|
52
|
+
}): BitcoinTransferPlan;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { attachOrStartManagedBitcoindService } from "../../../bitcoind/service.js";
|
|
2
|
+
import { createRpcClient } from "../../../bitcoind/node.js";
|
|
3
|
+
import { openWalletReadContext } from "../../read/index.js";
|
|
4
|
+
import { normalizeBtcTarget } from "../targets.js";
|
|
5
|
+
function parsePositiveSats(value) {
|
|
6
|
+
const trimmed = value.trim();
|
|
7
|
+
if (!/^[1-9]\d*$/.test(trimmed)) {
|
|
8
|
+
throw new Error("wallet_bitcoin_transfer_invalid_amount");
|
|
9
|
+
}
|
|
10
|
+
return BigInt(trimmed);
|
|
11
|
+
}
|
|
12
|
+
function normalizeRecipientAddress(target) {
|
|
13
|
+
const trimmed = target.trim();
|
|
14
|
+
try {
|
|
15
|
+
const normalized = normalizeBtcTarget(trimmed);
|
|
16
|
+
if (trimmed.startsWith("spk:") || normalized.opaque || normalized.address === null) {
|
|
17
|
+
throw new Error("wallet_bitcoin_transfer_address_required");
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
address: normalized.address,
|
|
21
|
+
scriptPubKeyHex: normalized.scriptPubKeyHex,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (error instanceof Error && error.message === "wallet_bitcoin_transfer_address_required") {
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
if (trimmed.startsWith("spk:")) {
|
|
29
|
+
throw new Error("wallet_bitcoin_transfer_address_required", { cause: error });
|
|
30
|
+
}
|
|
31
|
+
if (error instanceof Error
|
|
32
|
+
&& (error.message === "wallet_target_missing"
|
|
33
|
+
|| error.message === "wallet_target_invalid_address"
|
|
34
|
+
|| error.message === "wallet_target_invalid_script")) {
|
|
35
|
+
throw new Error("wallet_bitcoin_transfer_invalid_address", { cause: error });
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function satsToBtcNumber(value) {
|
|
41
|
+
return Number(value) / 100_000_000;
|
|
42
|
+
}
|
|
43
|
+
function isSpendableFundingUtxo(entry, fundingScriptPubKeyHex) {
|
|
44
|
+
return entry.scriptPubKey === fundingScriptPubKeyHex
|
|
45
|
+
&& entry.confirmations >= 1
|
|
46
|
+
&& entry.spendable !== false
|
|
47
|
+
&& entry.safe !== false;
|
|
48
|
+
}
|
|
49
|
+
export function resolveBitcoinTransferIntent(options) {
|
|
50
|
+
const amountSats = parsePositiveSats(options.amountSatsText);
|
|
51
|
+
const recipient = normalizeRecipientAddress(options.target);
|
|
52
|
+
return {
|
|
53
|
+
amountSats,
|
|
54
|
+
recipientAddress: recipient.address,
|
|
55
|
+
recipientScriptPubKeyHex: recipient.scriptPubKeyHex,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function buildPlanForBitcoinTransfer(options) {
|
|
59
|
+
const fundingUtxos = options.allUtxos.filter((entry) => isSpendableFundingUtxo(entry, options.state.funding.scriptPubKeyHex));
|
|
60
|
+
return {
|
|
61
|
+
fixedInputs: [],
|
|
62
|
+
outputs: [
|
|
63
|
+
{
|
|
64
|
+
[options.recipientAddress]: satsToBtcNumber(options.amountSats),
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
changeAddress: options.state.funding.address,
|
|
68
|
+
changePosition: null,
|
|
69
|
+
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
70
|
+
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => options.outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
71
|
+
recipientScriptPubKeyHex: options.recipientScriptPubKeyHex,
|
|
72
|
+
amountSats: options.amountSats,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function btcValueToSats(value) {
|
|
2
|
+
const numeric = typeof value === "string" ? Number(value) : value;
|
|
3
|
+
return BigInt(Math.round(numeric * 100_000_000));
|
|
4
|
+
}
|
|
5
|
+
export function validateFundedBitcoinTransfer(decoded, _funded, plan) {
|
|
6
|
+
if (decoded.tx.vin.length === 0) {
|
|
7
|
+
throw new Error("wallet_bitcoin_transfer_missing_sender_input");
|
|
8
|
+
}
|
|
9
|
+
const recipientOutputs = decoded.tx.vout.filter((output) => output.scriptPubKey?.hex === plan.recipientScriptPubKeyHex);
|
|
10
|
+
if (recipientOutputs.length !== 1) {
|
|
11
|
+
throw new Error("wallet_bitcoin_transfer_missing_recipient_output");
|
|
12
|
+
}
|
|
13
|
+
if (btcValueToSats(recipientOutputs[0].value) !== plan.amountSats) {
|
|
14
|
+
throw new Error("wallet_bitcoin_transfer_recipient_amount_mismatch");
|
|
15
|
+
}
|
|
16
|
+
const hasUnexpectedOutput = decoded.tx.vout.some((output) => output.scriptPubKey?.hex !== plan.recipientScriptPubKeyHex
|
|
17
|
+
&& output.scriptPubKey?.hex !== plan.allowedFundingScriptPubKeyHex);
|
|
18
|
+
if (hasUnexpectedOutput) {
|
|
19
|
+
throw new Error("wallet_bitcoin_transfer_unexpected_output");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { WalletStateV1 } from "../../types.js";
|
|
2
|
+
import type { BuiltWalletMutationTransaction } from "../common.js";
|
|
3
|
+
export interface BitcoinTransferResult {
|
|
4
|
+
amountSats: bigint;
|
|
5
|
+
feeSats: bigint;
|
|
6
|
+
senderAddress: string;
|
|
7
|
+
recipientAddress: string;
|
|
8
|
+
recipientScriptPubKeyHex: string;
|
|
9
|
+
changeAddress: string;
|
|
10
|
+
txid: string;
|
|
11
|
+
wtxid: string | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function createBitcoinTransferResult(options: {
|
|
14
|
+
state: WalletStateV1;
|
|
15
|
+
built: BuiltWalletMutationTransaction;
|
|
16
|
+
amountSats: bigint;
|
|
17
|
+
recipientAddress: string;
|
|
18
|
+
recipientScriptPubKeyHex: string;
|
|
19
|
+
}): BitcoinTransferResult;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function btcValueToSats(value) {
|
|
2
|
+
const numeric = typeof value === "string" ? Number(value) : value;
|
|
3
|
+
return BigInt(Math.round(numeric * 100_000_000));
|
|
4
|
+
}
|
|
5
|
+
export function createBitcoinTransferResult(options) {
|
|
6
|
+
return {
|
|
7
|
+
amountSats: options.amountSats,
|
|
8
|
+
feeSats: btcValueToSats(options.built.funded.fee),
|
|
9
|
+
senderAddress: options.state.funding.address,
|
|
10
|
+
recipientAddress: options.recipientAddress,
|
|
11
|
+
recipientScriptPubKeyHex: options.recipientScriptPubKeyHex,
|
|
12
|
+
changeAddress: options.state.funding.address,
|
|
13
|
+
txid: options.built.txid,
|
|
14
|
+
wtxid: options.built.wtxid,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -1,35 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { createRpcClient } from "../../bitcoind/node.js";
|
|
3
|
-
import type { WalletPrompter } from "../lifecycle.js";
|
|
4
|
-
import { openWalletReadContext } from "../read/index.js";
|
|
5
|
-
import { type WalletRuntimePaths } from "../runtime.js";
|
|
6
|
-
import { type WalletSecretProvider } from "../state/provider.js";
|
|
7
|
-
import { type WalletMutationRpcClient } from "./common.js";
|
|
8
|
-
interface WalletBitcoinTransferRpcClient extends WalletMutationRpcClient {
|
|
9
|
-
sendRawTransaction(hex: string): Promise<string>;
|
|
10
|
-
}
|
|
11
|
-
export interface BitcoinTransferResult {
|
|
12
|
-
amountSats: bigint;
|
|
13
|
-
feeSats: bigint;
|
|
14
|
-
senderAddress: string;
|
|
15
|
-
recipientAddress: string;
|
|
16
|
-
recipientScriptPubKeyHex: string;
|
|
17
|
-
changeAddress: string;
|
|
18
|
-
txid: string;
|
|
19
|
-
wtxid: string | null;
|
|
20
|
-
}
|
|
21
|
-
export interface TransferBitcoinOptions {
|
|
22
|
-
amountSatsText: string;
|
|
23
|
-
target: string;
|
|
24
|
-
dataDir: string;
|
|
25
|
-
databasePath: string;
|
|
26
|
-
provider?: WalletSecretProvider;
|
|
27
|
-
prompter: WalletPrompter;
|
|
28
|
-
assumeYes?: boolean;
|
|
29
|
-
paths?: WalletRuntimePaths;
|
|
30
|
-
openReadContext?: typeof openWalletReadContext;
|
|
31
|
-
attachService?: typeof attachOrStartManagedBitcoindService;
|
|
32
|
-
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletBitcoinTransferRpcClient;
|
|
33
|
-
}
|
|
34
|
-
export declare function transferBitcoin(options: TransferBitcoinOptions): Promise<BitcoinTransferResult>;
|
|
35
|
-
export {};
|
|
1
|
+
export * from "./bitcoin-transfer/index.js";
|
|
@@ -1,200 +1 @@
|
|
|
1
|
-
|
|
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 { confirmYesNo } from "./confirm.js";
|
|
8
|
-
import { assertWalletBitcoinTransferContextReady, buildWalletMutationTransaction, isAlreadyAcceptedError, isBroadcastUnknownError, isInsufficientFundsError, outpointKey, pauseMiningForWalletMutation, unlockTemporaryBuilderLocks, } from "./common.js";
|
|
9
|
-
import { normalizeBtcTarget } from "./targets.js";
|
|
10
|
-
function parsePositiveSats(value) {
|
|
11
|
-
const trimmed = value.trim();
|
|
12
|
-
if (!/^[1-9]\d*$/.test(trimmed)) {
|
|
13
|
-
throw new Error("wallet_bitcoin_transfer_invalid_amount");
|
|
14
|
-
}
|
|
15
|
-
return BigInt(trimmed);
|
|
16
|
-
}
|
|
17
|
-
function satsToBtcNumber(value) {
|
|
18
|
-
return Number(value) / 100_000_000;
|
|
19
|
-
}
|
|
20
|
-
function btcValueToSats(value) {
|
|
21
|
-
const numeric = typeof value === "string" ? Number(value) : value;
|
|
22
|
-
return BigInt(Math.round(numeric * 100_000_000));
|
|
23
|
-
}
|
|
24
|
-
function normalizeRecipientAddress(target) {
|
|
25
|
-
const trimmed = target.trim();
|
|
26
|
-
try {
|
|
27
|
-
const normalized = normalizeBtcTarget(trimmed);
|
|
28
|
-
if (trimmed.startsWith("spk:") || normalized.opaque || normalized.address === null) {
|
|
29
|
-
throw new Error("wallet_bitcoin_transfer_address_required");
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
address: normalized.address,
|
|
33
|
-
scriptPubKeyHex: normalized.scriptPubKeyHex,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
if (error instanceof Error && error.message === "wallet_bitcoin_transfer_address_required") {
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
if (trimmed.startsWith("spk:")) {
|
|
41
|
-
throw new Error("wallet_bitcoin_transfer_address_required", { cause: error });
|
|
42
|
-
}
|
|
43
|
-
if (error instanceof Error
|
|
44
|
-
&& (error.message === "wallet_target_missing"
|
|
45
|
-
|| error.message === "wallet_target_invalid_address"
|
|
46
|
-
|| error.message === "wallet_target_invalid_script")) {
|
|
47
|
-
throw new Error("wallet_bitcoin_transfer_invalid_address", { cause: error });
|
|
48
|
-
}
|
|
49
|
-
throw error;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function isSpendableFundingUtxo(entry, fundingScriptPubKeyHex) {
|
|
53
|
-
return entry.scriptPubKey === fundingScriptPubKeyHex
|
|
54
|
-
&& entry.confirmations >= 1
|
|
55
|
-
&& entry.spendable !== false
|
|
56
|
-
&& entry.safe !== false;
|
|
57
|
-
}
|
|
58
|
-
function buildPlanForBitcoinTransfer(options) {
|
|
59
|
-
const fundingUtxos = options.allUtxos.filter((entry) => isSpendableFundingUtxo(entry, options.state.funding.scriptPubKeyHex));
|
|
60
|
-
return {
|
|
61
|
-
fixedInputs: [],
|
|
62
|
-
outputs: [
|
|
63
|
-
{
|
|
64
|
-
[options.recipientAddress]: satsToBtcNumber(options.amountSats),
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
changeAddress: options.state.funding.address,
|
|
68
|
-
changePosition: null,
|
|
69
|
-
allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
|
|
70
|
-
eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
|
|
71
|
-
recipientScriptPubKeyHex: options.recipientScriptPubKeyHex,
|
|
72
|
-
amountSats: options.amountSats,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function validateFundedBitcoinTransfer(decoded, _funded, plan) {
|
|
76
|
-
if (decoded.tx.vin.length === 0) {
|
|
77
|
-
throw new Error("wallet_bitcoin_transfer_missing_sender_input");
|
|
78
|
-
}
|
|
79
|
-
const recipientOutputs = decoded.tx.vout.filter((output) => output.scriptPubKey?.hex === plan.recipientScriptPubKeyHex);
|
|
80
|
-
if (recipientOutputs.length !== 1) {
|
|
81
|
-
throw new Error("wallet_bitcoin_transfer_missing_recipient_output");
|
|
82
|
-
}
|
|
83
|
-
if (btcValueToSats(recipientOutputs[0].value) !== plan.amountSats) {
|
|
84
|
-
throw new Error("wallet_bitcoin_transfer_recipient_amount_mismatch");
|
|
85
|
-
}
|
|
86
|
-
const hasUnexpectedOutput = decoded.tx.vout.some((output) => output.scriptPubKey?.hex !== plan.recipientScriptPubKeyHex
|
|
87
|
-
&& output.scriptPubKey?.hex !== plan.allowedFundingScriptPubKeyHex);
|
|
88
|
-
if (hasUnexpectedOutput) {
|
|
89
|
-
throw new Error("wallet_bitcoin_transfer_unexpected_output");
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
async function confirmBitcoinTransfer(prompter, senderAddress, recipientAddress, amountSats, assumeYes = false) {
|
|
93
|
-
prompter.writeLine(`You are sending ${amountSats.toString()} sats.`);
|
|
94
|
-
prompter.writeLine(`Wallet address: ${senderAddress}`);
|
|
95
|
-
prompter.writeLine(`Recipient: ${recipientAddress}`);
|
|
96
|
-
await confirmYesNo(prompter, "This will publish a standard Bitcoin payment from the wallet address.", {
|
|
97
|
-
assumeYes,
|
|
98
|
-
errorCode: "wallet_bitcoin_transfer_confirmation_rejected",
|
|
99
|
-
requiresTtyErrorCode: "wallet_bitcoin_transfer_requires_tty",
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
export async function transferBitcoin(options) {
|
|
103
|
-
const amountSats = parsePositiveSats(options.amountSatsText);
|
|
104
|
-
const recipient = normalizeRecipientAddress(options.target);
|
|
105
|
-
const provider = options.provider ?? createDefaultWalletSecretProvider();
|
|
106
|
-
const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
|
|
107
|
-
const controlLock = await acquireFileLock(paths.walletControlLockPath, {
|
|
108
|
-
purpose: "wallet-bitcoin-transfer",
|
|
109
|
-
walletRootId: null,
|
|
110
|
-
});
|
|
111
|
-
try {
|
|
112
|
-
const miningPreemption = await pauseMiningForWalletMutation({
|
|
113
|
-
paths,
|
|
114
|
-
reason: "wallet-bitcoin-transfer",
|
|
115
|
-
});
|
|
116
|
-
const readContext = await (options.openReadContext ?? openWalletReadContext)({
|
|
117
|
-
dataDir: options.dataDir,
|
|
118
|
-
databasePath: options.databasePath,
|
|
119
|
-
secretProvider: provider,
|
|
120
|
-
walletControlLockHeld: true,
|
|
121
|
-
paths,
|
|
122
|
-
});
|
|
123
|
-
try {
|
|
124
|
-
assertWalletBitcoinTransferContextReady(readContext, "wallet_bitcoin_transfer");
|
|
125
|
-
const state = readContext.localState.state;
|
|
126
|
-
if (state.funding.scriptPubKeyHex === recipient.scriptPubKeyHex) {
|
|
127
|
-
throw new Error("wallet_bitcoin_transfer_self_transfer");
|
|
128
|
-
}
|
|
129
|
-
await confirmBitcoinTransfer(options.prompter, state.funding.address, recipient.address, amountSats, options.assumeYes);
|
|
130
|
-
const node = await (options.attachService ?? attachOrStartManagedBitcoindService)({
|
|
131
|
-
dataDir: options.dataDir,
|
|
132
|
-
chain: "main",
|
|
133
|
-
startHeight: 0,
|
|
134
|
-
walletRootId: state.walletRootId,
|
|
135
|
-
});
|
|
136
|
-
const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
|
|
137
|
-
const walletName = state.managedCoreWallet.walletName;
|
|
138
|
-
const allUtxos = await rpc.listUnspent(walletName, 1);
|
|
139
|
-
const plan = buildPlanForBitcoinTransfer({
|
|
140
|
-
state,
|
|
141
|
-
allUtxos,
|
|
142
|
-
recipientAddress: recipient.address,
|
|
143
|
-
recipientScriptPubKeyHex: recipient.scriptPubKeyHex,
|
|
144
|
-
amountSats,
|
|
145
|
-
});
|
|
146
|
-
let built;
|
|
147
|
-
try {
|
|
148
|
-
built = await buildWalletMutationTransaction({
|
|
149
|
-
rpc,
|
|
150
|
-
walletName,
|
|
151
|
-
state,
|
|
152
|
-
plan,
|
|
153
|
-
validateFundedDraft: validateFundedBitcoinTransfer,
|
|
154
|
-
finalizeErrorCode: "wallet_bitcoin_transfer_finalize_failed",
|
|
155
|
-
mempoolRejectPrefix: "wallet_bitcoin_transfer_mempool_reject",
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
if (isInsufficientFundsError(error)) {
|
|
160
|
-
throw new Error("wallet_bitcoin_transfer_insufficient_funds", { cause: error });
|
|
161
|
-
}
|
|
162
|
-
throw error;
|
|
163
|
-
}
|
|
164
|
-
try {
|
|
165
|
-
await rpc.sendRawTransaction(built.rawHex);
|
|
166
|
-
}
|
|
167
|
-
catch (error) {
|
|
168
|
-
if (!isAlreadyAcceptedError(error)) {
|
|
169
|
-
if (isInsufficientFundsError(error)) {
|
|
170
|
-
throw new Error("wallet_bitcoin_transfer_insufficient_funds", { cause: error });
|
|
171
|
-
}
|
|
172
|
-
if (isBroadcastUnknownError(error)) {
|
|
173
|
-
throw new Error("wallet_bitcoin_transfer_broadcast_unknown", { cause: error });
|
|
174
|
-
}
|
|
175
|
-
throw error;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
finally {
|
|
179
|
-
await unlockTemporaryBuilderLocks(rpc, walletName, built.temporaryBuilderLockedOutpoints);
|
|
180
|
-
}
|
|
181
|
-
return {
|
|
182
|
-
amountSats,
|
|
183
|
-
feeSats: btcValueToSats(built.funded.fee),
|
|
184
|
-
senderAddress: state.funding.address,
|
|
185
|
-
recipientAddress: recipient.address,
|
|
186
|
-
recipientScriptPubKeyHex: recipient.scriptPubKeyHex,
|
|
187
|
-
changeAddress: state.funding.address,
|
|
188
|
-
txid: built.txid,
|
|
189
|
-
wtxid: built.wtxid,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
finally {
|
|
193
|
-
await readContext.close();
|
|
194
|
-
await miningPreemption.release();
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
finally {
|
|
198
|
-
await controlLock.release();
|
|
199
|
-
}
|
|
200
|
-
}
|
|
1
|
+
export * from "./bitcoin-transfer/index.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WalletPrompter } from "../../lifecycle.js";
|
|
2
|
+
import type { CogResolvedSummary } from "./types.js";
|
|
3
|
+
import { normalizeBtcTarget } from "../targets.js";
|
|
4
|
+
export declare function confirmSend(prompter: WalletPrompter, resolved: CogResolvedSummary, target: string, normalizedRecipient: ReturnType<typeof normalizeBtcTarget>, amountCogtoshi: bigint, assumeYes?: boolean): Promise<void>;
|
|
5
|
+
export declare function confirmLock(prompter: WalletPrompter, resolved: CogResolvedSummary, amountCogtoshi: bigint, recipientDomainName: string, timeoutHeight: number, assumeYes?: boolean): Promise<void>;
|
|
6
|
+
export declare function confirmClaim(prompter: WalletPrompter, options: {
|
|
7
|
+
kind: "claim" | "reclaim";
|
|
8
|
+
lockId: number;
|
|
9
|
+
recipientDomainName: string | null;
|
|
10
|
+
amountCogtoshi: bigint;
|
|
11
|
+
resolved: CogResolvedSummary;
|
|
12
|
+
assumeYes?: boolean;
|
|
13
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { formatCogAmount } from "../common.js";
|
|
2
|
+
import { confirmTypedAcknowledgement, confirmYesNo, } from "../confirm.js";
|
|
3
|
+
import { normalizeBtcTarget } from "../targets.js";
|
|
4
|
+
export async function confirmSend(prompter, resolved, target, normalizedRecipient, amountCogtoshi, assumeYes = false) {
|
|
5
|
+
prompter.writeLine(`You are sending ${formatCogAmount(amountCogtoshi)}.`);
|
|
6
|
+
prompter.writeLine(`Resolved sender: ${resolved.sender.selector} (${resolved.sender.address})`);
|
|
7
|
+
prompter.writeLine(`Recipient: ${normalizedRecipient.address ?? `spk:${normalizedRecipient.scriptPubKeyHex}`}`);
|
|
8
|
+
if (normalizedRecipient.opaque) {
|
|
9
|
+
await confirmTypedAcknowledgement(prompter, {
|
|
10
|
+
assumeYes,
|
|
11
|
+
expected: target.trim(),
|
|
12
|
+
prompt: "Type the exact target to continue: ",
|
|
13
|
+
errorCode: "wallet_send_confirmation_rejected",
|
|
14
|
+
requiresTtyErrorCode: "wallet_send_requires_tty",
|
|
15
|
+
typedAckRequiredErrorCode: "wallet_send_typed_ack_required",
|
|
16
|
+
});
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
await confirmYesNo(prompter, "This will publish an on-chain COG transfer.", {
|
|
20
|
+
assumeYes,
|
|
21
|
+
errorCode: "wallet_send_confirmation_rejected",
|
|
22
|
+
requiresTtyErrorCode: "wallet_send_requires_tty",
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export async function confirmLock(prompter, resolved, amountCogtoshi, recipientDomainName, timeoutHeight, assumeYes = false) {
|
|
26
|
+
prompter.writeLine(`You are locking ${formatCogAmount(amountCogtoshi)}.`);
|
|
27
|
+
prompter.writeLine(`Resolved sender: ${resolved.sender.selector} (${resolved.sender.address})`);
|
|
28
|
+
prompter.writeLine(`Recipient domain: ${recipientDomainName}`);
|
|
29
|
+
prompter.writeLine(`Resolved timeout height: ${timeoutHeight}`);
|
|
30
|
+
await confirmYesNo(prompter, "This creates an escrowed COG lock and the funds cannot be spent until claimed or reclaimed.", {
|
|
31
|
+
assumeYes,
|
|
32
|
+
errorCode: "wallet_mutation_confirmation_rejected",
|
|
33
|
+
requiresTtyErrorCode: "wallet_lock_requires_tty",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export async function confirmClaim(prompter, options) {
|
|
37
|
+
prompter.writeLine(`${options.kind === "claim" ? "Claiming" : "Reclaiming"} lock:${options.lockId} for ${formatCogAmount(options.amountCogtoshi)}.`);
|
|
38
|
+
prompter.writeLine(`Resolved sender: ${options.resolved.sender.selector} (${options.resolved.sender.address})`);
|
|
39
|
+
if (options.resolved.claimPath !== null) {
|
|
40
|
+
prompter.writeLine(`Resolved path: ${options.resolved.claimPath}.`);
|
|
41
|
+
}
|
|
42
|
+
if (options.recipientDomainName !== null) {
|
|
43
|
+
prompter.writeLine(`Recipient domain: ${options.recipientDomainName}`);
|
|
44
|
+
}
|
|
45
|
+
if (options.kind === "claim") {
|
|
46
|
+
prompter.writeLine("Warning: the claim preimage becomes public in the mempool and on-chain.");
|
|
47
|
+
}
|
|
48
|
+
await confirmYesNo(prompter, options.kind === "claim"
|
|
49
|
+
? "This spends the lock via the recipient claim path."
|
|
50
|
+
: "This spends the lock via the timeout reclaim path.", {
|
|
51
|
+
assumeYes: options.assumeYes,
|
|
52
|
+
errorCode: options.kind === "claim"
|
|
53
|
+
? "wallet_claim_confirmation_rejected"
|
|
54
|
+
: "wallet_reclaim_confirmation_rejected",
|
|
55
|
+
requiresTtyErrorCode: options.kind === "claim"
|
|
56
|
+
? "wallet_claim_requires_tty"
|
|
57
|
+
: "wallet_reclaim_requires_tty",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { WalletRuntimePaths } from "../../runtime.js";
|
|
2
|
+
import type { WalletSecretProvider } from "../../state/provider.js";
|
|
3
|
+
import type { PendingMutationRecord, WalletStateV1 } from "../../types.js";
|
|
4
|
+
import type { WalletReadContext } from "../../read/index.js";
|
|
5
|
+
import type { CogDraftMutationOptions, WalletCogRpcClient } from "./types.js";
|
|
6
|
+
export declare function createCogDraftMutation(options: CogDraftMutationOptions): PendingMutationRecord;
|
|
7
|
+
export declare function reconcilePendingCogMutation(options: {
|
|
8
|
+
state: WalletStateV1;
|
|
9
|
+
mutation: PendingMutationRecord;
|
|
10
|
+
provider: WalletSecretProvider;
|
|
11
|
+
nowUnixMs: number;
|
|
12
|
+
paths: WalletRuntimePaths;
|
|
13
|
+
rpc: WalletCogRpcClient;
|
|
14
|
+
walletName: string;
|
|
15
|
+
context: WalletReadContext;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
state: WalletStateV1;
|
|
18
|
+
mutation: PendingMutationRecord;
|
|
19
|
+
resolution: "confirmed" | "live" | "repair-required" | "continue";
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { getLock } from "@cogcoin/indexer/queries";
|
|
3
|
+
import { createWalletMutationFeeMetadata, saveWalletStatePreservingUnlock, unlockTemporaryBuilderLocks, updateMutationRecord, } from "../common.js";
|
|
4
|
+
import { upsertPendingMutation } from "../journal.js";
|
|
5
|
+
import { ZERO_PREIMAGE_HEX } from "./types.js";
|
|
6
|
+
export function createCogDraftMutation(options) {
|
|
7
|
+
if (options.existing !== null && options.existing !== undefined) {
|
|
8
|
+
return {
|
|
9
|
+
...options.existing,
|
|
10
|
+
kind: options.kind,
|
|
11
|
+
domainName: options.domainName ?? "",
|
|
12
|
+
senderScriptPubKeyHex: options.sender.scriptPubKeyHex,
|
|
13
|
+
senderLocalIndex: options.sender.localIndex,
|
|
14
|
+
recipientScriptPubKeyHex: options.recipientScriptPubKeyHex ?? null,
|
|
15
|
+
recipientDomainName: options.recipientDomainName ?? null,
|
|
16
|
+
amountCogtoshi: options.amountCogtoshi ?? null,
|
|
17
|
+
timeoutHeight: options.timeoutHeight ?? null,
|
|
18
|
+
conditionHex: options.conditionHex ?? null,
|
|
19
|
+
lockId: options.lockId ?? null,
|
|
20
|
+
preimageHex: options.preimageHex ?? null,
|
|
21
|
+
status: "draft",
|
|
22
|
+
lastUpdatedAtUnixMs: options.nowUnixMs,
|
|
23
|
+
attemptedTxid: null,
|
|
24
|
+
attemptedWtxid: null,
|
|
25
|
+
...createWalletMutationFeeMetadata(options.feeSelection),
|
|
26
|
+
temporaryBuilderLockedOutpoints: [],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
mutationId: randomBytes(12).toString("hex"),
|
|
31
|
+
kind: options.kind,
|
|
32
|
+
domainName: options.domainName ?? "",
|
|
33
|
+
parentDomainName: null,
|
|
34
|
+
senderScriptPubKeyHex: options.sender.scriptPubKeyHex,
|
|
35
|
+
senderLocalIndex: options.sender.localIndex,
|
|
36
|
+
recipientScriptPubKeyHex: options.recipientScriptPubKeyHex ?? null,
|
|
37
|
+
recipientDomainName: options.recipientDomainName ?? null,
|
|
38
|
+
amountCogtoshi: options.amountCogtoshi ?? null,
|
|
39
|
+
timeoutHeight: options.timeoutHeight ?? null,
|
|
40
|
+
conditionHex: options.conditionHex ?? null,
|
|
41
|
+
lockId: options.lockId ?? null,
|
|
42
|
+
preimageHex: options.preimageHex ?? null,
|
|
43
|
+
intentFingerprintHex: options.intentFingerprintHex,
|
|
44
|
+
status: "draft",
|
|
45
|
+
createdAtUnixMs: options.nowUnixMs,
|
|
46
|
+
lastUpdatedAtUnixMs: options.nowUnixMs,
|
|
47
|
+
attemptedTxid: null,
|
|
48
|
+
attemptedWtxid: null,
|
|
49
|
+
...createWalletMutationFeeMetadata(options.feeSelection),
|
|
50
|
+
temporaryBuilderLockedOutpoints: [],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export async function reconcilePendingCogMutation(options) {
|
|
54
|
+
if (options.mutation.status === "confirmed" || options.mutation.status === "live") {
|
|
55
|
+
return {
|
|
56
|
+
state: options.state,
|
|
57
|
+
mutation: options.mutation,
|
|
58
|
+
resolution: options.mutation.status,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (options.mutation.status === "repair-required") {
|
|
62
|
+
return {
|
|
63
|
+
state: options.state,
|
|
64
|
+
mutation: options.mutation,
|
|
65
|
+
resolution: "repair-required",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (options.mutation.kind === "claim" && options.context.snapshot !== null && options.mutation.lockId != null) {
|
|
69
|
+
const lock = getLock(options.context.snapshot.state, options.mutation.lockId);
|
|
70
|
+
const expectedStatus = options.mutation.preimageHex === ZERO_PREIMAGE_HEX ? "reclaimed" : "claimed";
|
|
71
|
+
if (lock !== null
|
|
72
|
+
&& lock.status === expectedStatus
|
|
73
|
+
&& Buffer.from(lock.resolverScriptPubKey ?? new Uint8Array()).toString("hex") === options.mutation.senderScriptPubKeyHex) {
|
|
74
|
+
await unlockTemporaryBuilderLocks(options.rpc, options.walletName, options.mutation.temporaryBuilderLockedOutpoints);
|
|
75
|
+
const confirmed = updateMutationRecord(options.mutation, "confirmed", options.nowUnixMs, {
|
|
76
|
+
temporaryBuilderLockedOutpoints: [],
|
|
77
|
+
});
|
|
78
|
+
const nextState = {
|
|
79
|
+
...upsertPendingMutation(options.state, confirmed),
|
|
80
|
+
stateRevision: options.state.stateRevision + 1,
|
|
81
|
+
lastWrittenAtUnixMs: options.nowUnixMs,
|
|
82
|
+
};
|
|
83
|
+
await saveWalletStatePreservingUnlock({
|
|
84
|
+
state: nextState,
|
|
85
|
+
provider: options.provider,
|
|
86
|
+
nowUnixMs: options.nowUnixMs,
|
|
87
|
+
paths: options.paths,
|
|
88
|
+
});
|
|
89
|
+
return { state: nextState, mutation: confirmed, resolution: "confirmed" };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const known = options.mutation.attemptedTxid === null
|
|
93
|
+
? false
|
|
94
|
+
: await options.rpc.getRawTransaction(options.mutation.attemptedTxid, true).then(() => true).catch(() => false);
|
|
95
|
+
if (known) {
|
|
96
|
+
await unlockTemporaryBuilderLocks(options.rpc, options.walletName, options.mutation.temporaryBuilderLockedOutpoints);
|
|
97
|
+
const live = updateMutationRecord(options.mutation, "live", options.nowUnixMs, {
|
|
98
|
+
temporaryBuilderLockedOutpoints: [],
|
|
99
|
+
});
|
|
100
|
+
const nextState = {
|
|
101
|
+
...upsertPendingMutation(options.state, live),
|
|
102
|
+
stateRevision: options.state.stateRevision + 1,
|
|
103
|
+
lastWrittenAtUnixMs: options.nowUnixMs,
|
|
104
|
+
};
|
|
105
|
+
await saveWalletStatePreservingUnlock({
|
|
106
|
+
state: nextState,
|
|
107
|
+
provider: options.provider,
|
|
108
|
+
nowUnixMs: options.nowUnixMs,
|
|
109
|
+
paths: options.paths,
|
|
110
|
+
});
|
|
111
|
+
return { state: nextState, mutation: live, resolution: "live" };
|
|
112
|
+
}
|
|
113
|
+
return { state: options.state, mutation: options.mutation, resolution: "continue" };
|
|
114
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ClaimCogLockOptions, CogMutationResult, LockCogToDomainOptions, ReclaimCogLockOptions, SendCogOptions } from "./types.js";
|
|
2
|
+
export type { ClaimCogLockOptions, CogMutationResult, CogResolvedClaimPath, CogResolvedSenderSummary, CogResolvedSummary, LockCogToDomainOptions, ReclaimCogLockOptions, SendCogOptions, } from "./types.js";
|
|
3
|
+
export declare function sendCog(options: SendCogOptions): Promise<CogMutationResult>;
|
|
4
|
+
export declare function lockCogToDomain(options: LockCogToDomainOptions): Promise<CogMutationResult>;
|
|
5
|
+
export declare function claimCogLock(options: ClaimCogLockOptions): Promise<CogMutationResult>;
|
|
6
|
+
export declare function reclaimCogLock(options: ReclaimCogLockOptions): Promise<CogMutationResult>;
|