@did-btcr2/method 0.37.0 → 0.39.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/dist/.tsbuildinfo +1 -1
- package/dist/browser.js +47868 -34771
- package/dist/browser.mjs +47867 -34770
- package/dist/cjs/index.js +462 -6060
- package/dist/esm/core/beacon/beacon.js +101 -10
- package/dist/esm/core/beacon/beacon.js.map +1 -1
- package/dist/esm/core/beacon/fee-estimator.js +12 -27
- package/dist/esm/core/beacon/fee-estimator.js.map +1 -1
- package/dist/esm/core/did-sender-resolver.js +26 -0
- package/dist/esm/core/did-sender-resolver.js.map +1 -0
- package/dist/esm/index.js +3 -17
- package/dist/esm/index.js.map +1 -1
- package/dist/types/core/beacon/beacon.d.ts +59 -3
- package/dist/types/core/beacon/beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/fee-estimator.d.ts +10 -37
- package/dist/types/core/beacon/fee-estimator.d.ts.map +1 -1
- package/dist/types/core/did-sender-resolver.d.ts +14 -0
- package/dist/types/core/did-sender-resolver.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -16
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +6 -5
- package/src/core/beacon/beacon.ts +131 -12
- package/src/core/beacon/fee-estimator.ts +15 -49
- package/src/core/did-sender-resolver.ts +25 -0
- package/src/index.ts +3 -17
- package/dist/esm/core/aggregation/beacon-strategy.js +0 -76
- package/dist/esm/core/aggregation/beacon-strategy.js.map +0 -1
- package/dist/esm/core/aggregation/cohort.js +0 -316
- package/dist/esm/core/aggregation/cohort.js.map +0 -1
- package/dist/esm/core/aggregation/conditions.js +0 -102
- package/dist/esm/core/aggregation/conditions.js.map +0 -1
- package/dist/esm/core/aggregation/errors.js +0 -22
- package/dist/esm/core/aggregation/errors.js.map +0 -1
- package/dist/esm/core/aggregation/fallback-spend.js +0 -132
- package/dist/esm/core/aggregation/fallback-spend.js.map +0 -1
- package/dist/esm/core/aggregation/logger.js +0 -15
- package/dist/esm/core/aggregation/logger.js.map +0 -1
- package/dist/esm/core/aggregation/messages/base.js +0 -36
- package/dist/esm/core/aggregation/messages/base.js.map +0 -1
- package/dist/esm/core/aggregation/messages/bodies.js +0 -149
- package/dist/esm/core/aggregation/messages/bodies.js.map +0 -1
- package/dist/esm/core/aggregation/messages/constants.js +0 -37
- package/dist/esm/core/aggregation/messages/constants.js.map +0 -1
- package/dist/esm/core/aggregation/messages/factories.js +0 -139
- package/dist/esm/core/aggregation/messages/factories.js.map +0 -1
- package/dist/esm/core/aggregation/messages/guards.js +0 -40
- package/dist/esm/core/aggregation/messages/guards.js.map +0 -1
- package/dist/esm/core/aggregation/messages/index.js +0 -6
- package/dist/esm/core/aggregation/messages/index.js.map +0 -1
- package/dist/esm/core/aggregation/participant.js +0 -588
- package/dist/esm/core/aggregation/participant.js.map +0 -1
- package/dist/esm/core/aggregation/phases.js +0 -45
- package/dist/esm/core/aggregation/phases.js.map +0 -1
- package/dist/esm/core/aggregation/recovery-policy.js +0 -156
- package/dist/esm/core/aggregation/recovery-policy.js.map +0 -1
- package/dist/esm/core/aggregation/recovery-spend.js +0 -106
- package/dist/esm/core/aggregation/recovery-spend.js.map +0 -1
- package/dist/esm/core/aggregation/runner/aggregation-runner.js +0 -74
- package/dist/esm/core/aggregation/runner/aggregation-runner.js.map +0 -1
- package/dist/esm/core/aggregation/runner/events.js +0 -2
- package/dist/esm/core/aggregation/runner/events.js.map +0 -1
- package/dist/esm/core/aggregation/runner/index.js +0 -6
- package/dist/esm/core/aggregation/runner/index.js.map +0 -1
- package/dist/esm/core/aggregation/runner/participant-runner.js +0 -407
- package/dist/esm/core/aggregation/runner/participant-runner.js.map +0 -1
- package/dist/esm/core/aggregation/runner/service-runner.js +0 -694
- package/dist/esm/core/aggregation/runner/service-runner.js.map +0 -1
- package/dist/esm/core/aggregation/runner/typed-emitter.js +0 -80
- package/dist/esm/core/aggregation/runner/typed-emitter.js.map +0 -1
- package/dist/esm/core/aggregation/service.js +0 -774
- package/dist/esm/core/aggregation/service.js.map +0 -1
- package/dist/esm/core/aggregation/signer.js +0 -33
- package/dist/esm/core/aggregation/signer.js.map +0 -1
- package/dist/esm/core/aggregation/signing-session.js +0 -195
- package/dist/esm/core/aggregation/signing-session.js.map +0 -1
- package/dist/esm/core/aggregation/transport/didcomm.js +0 -41
- package/dist/esm/core/aggregation/transport/didcomm.js.map +0 -1
- package/dist/esm/core/aggregation/transport/error.js +0 -12
- package/dist/esm/core/aggregation/transport/error.js.map +0 -1
- package/dist/esm/core/aggregation/transport/factory.js +0 -29
- package/dist/esm/core/aggregation/transport/factory.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/client.js +0 -350
- package/dist/esm/core/aggregation/transport/http/client.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/envelope.js +0 -126
- package/dist/esm/core/aggregation/transport/http/envelope.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/errors.js +0 -11
- package/dist/esm/core/aggregation/transport/http/errors.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/inbox-buffer.js +0 -45
- package/dist/esm/core/aggregation/transport/http/inbox-buffer.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/index.js +0 -12
- package/dist/esm/core/aggregation/transport/http/index.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/nonce-cache.js +0 -38
- package/dist/esm/core/aggregation/transport/http/nonce-cache.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/protocol.js +0 -28
- package/dist/esm/core/aggregation/transport/http/protocol.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/rate-limiter.js +0 -45
- package/dist/esm/core/aggregation/transport/http/rate-limiter.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/request-auth.js +0 -100
- package/dist/esm/core/aggregation/transport/http/request-auth.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/server.js +0 -481
- package/dist/esm/core/aggregation/transport/http/server.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/sse-stream.js +0 -110
- package/dist/esm/core/aggregation/transport/http/sse-stream.js.map +0 -1
- package/dist/esm/core/aggregation/transport/http/sse-writer.js +0 -25
- package/dist/esm/core/aggregation/transport/http/sse-writer.js.map +0 -1
- package/dist/esm/core/aggregation/transport/in-memory.js +0 -149
- package/dist/esm/core/aggregation/transport/in-memory.js.map +0 -1
- package/dist/esm/core/aggregation/transport/index.js +0 -8
- package/dist/esm/core/aggregation/transport/index.js.map +0 -1
- package/dist/esm/core/aggregation/transport/nostr.js +0 -491
- package/dist/esm/core/aggregation/transport/nostr.js.map +0 -1
- package/dist/esm/core/aggregation/transport/transport.js +0 -2
- package/dist/esm/core/aggregation/transport/transport.js.map +0 -1
- package/dist/types/core/aggregation/beacon-strategy.d.ts +0 -56
- package/dist/types/core/aggregation/beacon-strategy.d.ts.map +0 -1
- package/dist/types/core/aggregation/cohort.d.ts +0 -182
- package/dist/types/core/aggregation/cohort.d.ts.map +0 -1
- package/dist/types/core/aggregation/conditions.d.ts +0 -86
- package/dist/types/core/aggregation/conditions.d.ts.map +0 -1
- package/dist/types/core/aggregation/errors.d.ts +0 -14
- package/dist/types/core/aggregation/errors.d.ts.map +0 -1
- package/dist/types/core/aggregation/fallback-spend.d.ts +0 -94
- package/dist/types/core/aggregation/fallback-spend.d.ts.map +0 -1
- package/dist/types/core/aggregation/logger.d.ts +0 -22
- package/dist/types/core/aggregation/logger.d.ts.map +0 -1
- package/dist/types/core/aggregation/messages/base.d.ts +0 -58
- package/dist/types/core/aggregation/messages/base.d.ts.map +0 -1
- package/dist/types/core/aggregation/messages/bodies.d.ts +0 -177
- package/dist/types/core/aggregation/messages/bodies.d.ts.map +0 -1
- package/dist/types/core/aggregation/messages/constants.d.ts +0 -31
- package/dist/types/core/aggregation/messages/constants.d.ts.map +0 -1
- package/dist/types/core/aggregation/messages/factories.d.ts +0 -217
- package/dist/types/core/aggregation/messages/factories.d.ts.map +0 -1
- package/dist/types/core/aggregation/messages/guards.d.ts +0 -11
- package/dist/types/core/aggregation/messages/guards.d.ts.map +0 -1
- package/dist/types/core/aggregation/messages/index.d.ts +0 -6
- package/dist/types/core/aggregation/messages/index.d.ts.map +0 -1
- package/dist/types/core/aggregation/participant.d.ts +0 -162
- package/dist/types/core/aggregation/participant.d.ts.map +0 -1
- package/dist/types/core/aggregation/phases.d.ts +0 -55
- package/dist/types/core/aggregation/phases.d.ts.map +0 -1
- package/dist/types/core/aggregation/recovery-policy.d.ts +0 -132
- package/dist/types/core/aggregation/recovery-policy.d.ts.map +0 -1
- package/dist/types/core/aggregation/recovery-spend.d.ts +0 -94
- package/dist/types/core/aggregation/recovery-spend.d.ts.map +0 -1
- package/dist/types/core/aggregation/runner/aggregation-runner.d.ts +0 -66
- package/dist/types/core/aggregation/runner/aggregation-runner.d.ts.map +0 -1
- package/dist/types/core/aggregation/runner/events.d.ts +0 -147
- package/dist/types/core/aggregation/runner/events.d.ts.map +0 -1
- package/dist/types/core/aggregation/runner/index.d.ts +0 -6
- package/dist/types/core/aggregation/runner/index.d.ts.map +0 -1
- package/dist/types/core/aggregation/runner/participant-runner.d.ts +0 -122
- package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +0 -1
- package/dist/types/core/aggregation/runner/service-runner.d.ts +0 -211
- package/dist/types/core/aggregation/runner/service-runner.d.ts.map +0 -1
- package/dist/types/core/aggregation/runner/typed-emitter.d.ts +0 -41
- package/dist/types/core/aggregation/runner/typed-emitter.d.ts.map +0 -1
- package/dist/types/core/aggregation/service.d.ts +0 -177
- package/dist/types/core/aggregation/service.d.ts.map +0 -1
- package/dist/types/core/aggregation/signer.d.ts +0 -50
- package/dist/types/core/aggregation/signer.d.ts.map +0 -1
- package/dist/types/core/aggregation/signing-session.d.ts +0 -81
- package/dist/types/core/aggregation/signing-session.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/didcomm.d.ts +0 -23
- package/dist/types/core/aggregation/transport/didcomm.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/error.d.ts +0 -8
- package/dist/types/core/aggregation/transport/error.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/factory.d.ts +0 -28
- package/dist/types/core/aggregation/transport/factory.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/client.d.ts +0 -48
- package/dist/types/core/aggregation/transport/http/client.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/envelope.d.ts +0 -64
- package/dist/types/core/aggregation/transport/http/envelope.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/errors.d.ts +0 -9
- package/dist/types/core/aggregation/transport/http/errors.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/inbox-buffer.d.ts +0 -32
- package/dist/types/core/aggregation/transport/http/inbox-buffer.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/index.d.ts +0 -12
- package/dist/types/core/aggregation/transport/http/index.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/nonce-cache.d.ts +0 -26
- package/dist/types/core/aggregation/transport/http/nonce-cache.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/protocol.d.ts +0 -53
- package/dist/types/core/aggregation/transport/http/protocol.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/rate-limiter.d.ts +0 -41
- package/dist/types/core/aggregation/transport/http/rate-limiter.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/request-auth.d.ts +0 -50
- package/dist/types/core/aggregation/transport/http/request-auth.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/server.d.ts +0 -110
- package/dist/types/core/aggregation/transport/http/server.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/sse-stream.d.ts +0 -34
- package/dist/types/core/aggregation/transport/http/sse-stream.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/http/sse-writer.d.ts +0 -12
- package/dist/types/core/aggregation/transport/http/sse-writer.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/in-memory.d.ts +0 -64
- package/dist/types/core/aggregation/transport/in-memory.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/index.d.ts +0 -8
- package/dist/types/core/aggregation/transport/index.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/nostr.d.ts +0 -153
- package/dist/types/core/aggregation/transport/nostr.d.ts.map +0 -1
- package/dist/types/core/aggregation/transport/transport.d.ts +0 -62
- package/dist/types/core/aggregation/transport/transport.d.ts.map +0 -1
- package/src/core/aggregation/beacon-strategy.ts +0 -142
- package/src/core/aggregation/cohort.ts +0 -415
- package/src/core/aggregation/conditions.ts +0 -172
- package/src/core/aggregation/errors.ts +0 -25
- package/src/core/aggregation/fallback-spend.ts +0 -223
- package/src/core/aggregation/logger.ts +0 -33
- package/src/core/aggregation/messages/base.ts +0 -80
- package/src/core/aggregation/messages/bodies.ts +0 -328
- package/src/core/aggregation/messages/constants.ts +0 -40
- package/src/core/aggregation/messages/factories.ts +0 -297
- package/src/core/aggregation/messages/guards.ts +0 -61
- package/src/core/aggregation/messages/index.ts +0 -5
- package/src/core/aggregation/participant.ts +0 -779
- package/src/core/aggregation/phases.ts +0 -91
- package/src/core/aggregation/recovery-policy.ts +0 -237
- package/src/core/aggregation/recovery-spend.ts +0 -192
- package/src/core/aggregation/runner/aggregation-runner.ts +0 -118
- package/src/core/aggregation/runner/events.ts +0 -129
- package/src/core/aggregation/runner/index.ts +0 -5
- package/src/core/aggregation/runner/participant-runner.ts +0 -488
- package/src/core/aggregation/runner/service-runner.ts +0 -866
- package/src/core/aggregation/runner/typed-emitter.ts +0 -87
- package/src/core/aggregation/service.ts +0 -1000
- package/src/core/aggregation/signer.ts +0 -67
- package/src/core/aggregation/signing-session.ts +0 -290
- package/src/core/aggregation/transport/didcomm.ts +0 -59
- package/src/core/aggregation/transport/error.ts +0 -13
- package/src/core/aggregation/transport/factory.ts +0 -65
- package/src/core/aggregation/transport/http/client.ts +0 -409
- package/src/core/aggregation/transport/http/envelope.ts +0 -204
- package/src/core/aggregation/transport/http/errors.ts +0 -11
- package/src/core/aggregation/transport/http/inbox-buffer.ts +0 -53
- package/src/core/aggregation/transport/http/index.ts +0 -11
- package/src/core/aggregation/transport/http/nonce-cache.ts +0 -43
- package/src/core/aggregation/transport/http/protocol.ts +0 -57
- package/src/core/aggregation/transport/http/rate-limiter.ts +0 -75
- package/src/core/aggregation/transport/http/request-auth.ts +0 -164
- package/src/core/aggregation/transport/http/server.ts +0 -615
- package/src/core/aggregation/transport/http/sse-stream.ts +0 -121
- package/src/core/aggregation/transport/http/sse-writer.ts +0 -23
- package/src/core/aggregation/transport/in-memory.ts +0 -178
- package/src/core/aggregation/transport/index.ts +0 -7
- package/src/core/aggregation/transport/nostr.ts +0 -576
- package/src/core/aggregation/transport/transport.ts +0 -79
|
@@ -7,13 +7,10 @@ import { Address, OutScript, p2pkh, p2tr, p2wpkh, Script, SigHash, Transaction }
|
|
|
7
7
|
import type { BeaconProcessResult } from '../resolver.js';
|
|
8
8
|
import type { SidecarData } from '../types.js';
|
|
9
9
|
import { BeaconError } from './error.js';
|
|
10
|
-
import {
|
|
10
|
+
import { DEFAULT_FEE_ESTIMATOR } from './fee-estimator.js';
|
|
11
11
|
import type { FeeEstimator } from './fee-estimator.js';
|
|
12
12
|
import type { BeaconService, BeaconSignal } from './interfaces.js';
|
|
13
13
|
|
|
14
|
-
/** Default fee estimator used when none is supplied. ~5 sat/vB static rate. */
|
|
15
|
-
const DEFAULT_FEE_ESTIMATOR: FeeEstimator = new StaticFeeEstimator(5);
|
|
16
|
-
|
|
17
14
|
/**
|
|
18
15
|
* Singleton beacon script kinds. Per the did:btcr2 spec, deterministic DID documents
|
|
19
16
|
* include three beacon services: P2PKH, P2WPKH, and P2TR (taproot key-path), all
|
|
@@ -51,6 +48,54 @@ export const SINGLETON_BEACON_TX_VSIZE: Readonly<Record<SingletonScriptKind, num
|
|
|
51
48
|
p2tr : P2TR_BEACON_TX_VSIZE,
|
|
52
49
|
};
|
|
53
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Serialized size (vbytes) of a single change output, by script kind:
|
|
53
|
+
* 8 (value) + 1 (scriptPubKey length) + scriptPubKey bytes. P2PKH 25, P2WPKH 22,
|
|
54
|
+
* P2TR 34. These are non-witness bytes, so each contributes its full byte count to
|
|
55
|
+
* the transaction vsize. The {@link SINGLETON_BEACON_TX_VSIZE} constants bake in a
|
|
56
|
+
* same-kind change output; {@link beaconTxVsize} uses these deltas to re-size the
|
|
57
|
+
* fee when a caller routes change to an address of a different kind (ADR 044).
|
|
58
|
+
*/
|
|
59
|
+
export const CHANGE_OUTPUT_VBYTES: Readonly<Record<SingletonScriptKind, number>> = {
|
|
60
|
+
p2pkh : 34,
|
|
61
|
+
p2wpkh : 31,
|
|
62
|
+
p2tr : 43,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Dust threshold (sats) below which a change output is not worth creating, by script
|
|
67
|
+
* kind (the standard Bitcoin Core dust relay thresholds at the default 3 sat/vB dust
|
|
68
|
+
* rate). When the change after fees falls below this, the builders omit the change
|
|
69
|
+
* output and let the remainder fall into the fee rather than emit an unspendable,
|
|
70
|
+
* relay-rejected dust output (ADR 044).
|
|
71
|
+
*/
|
|
72
|
+
export const DUST_LIMIT_SATS: Readonly<Record<SingletonScriptKind, number>> = {
|
|
73
|
+
p2pkh : 546,
|
|
74
|
+
p2wpkh : 294,
|
|
75
|
+
p2tr : 330,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* vsize (vbytes) for a beacon transaction that spends one input of `beaconKind`
|
|
80
|
+
* and returns change to an output of `changeKind`, plus the OP_RETURN(32) signal.
|
|
81
|
+
*
|
|
82
|
+
* When `changeKind === beaconKind` (the default, change to the beacon address) this
|
|
83
|
+
* returns the per-kind {@link SINGLETON_BEACON_TX_VSIZE} constant unchanged, so the
|
|
84
|
+
* default path and the constants' lock-in tests are byte-identical. A differing
|
|
85
|
+
* `changeKind` swaps the assumed same-kind change output for the actual one, keeping
|
|
86
|
+
* the result a valid upper bound. The aggregation key-path spend is the
|
|
87
|
+
* `beaconKind: 'p2tr'` case (its input is always the cohort's P2TR key path; only the
|
|
88
|
+
* change output varies), the analytical sizing ADR 045 calls for, computed without a
|
|
89
|
+
* secret.
|
|
90
|
+
*/
|
|
91
|
+
export function beaconTxVsize(
|
|
92
|
+
beaconKind: SingletonScriptKind,
|
|
93
|
+
changeKind: SingletonScriptKind,
|
|
94
|
+
): number {
|
|
95
|
+
const base = SINGLETON_BEACON_TX_VSIZE[beaconKind] - CHANGE_OUTPUT_VBYTES[beaconKind];
|
|
96
|
+
return base + CHANGE_OUTPUT_VBYTES[changeKind];
|
|
97
|
+
}
|
|
98
|
+
|
|
54
99
|
/**
|
|
55
100
|
* Detect the singleton script kind of a Bitcoin address (P2PKH / P2WPKH / P2TR).
|
|
56
101
|
* The deterministic-DID document emits all three kinds; the broadcast path needs
|
|
@@ -88,12 +133,56 @@ export function deriveSingletonAddress(
|
|
|
88
133
|
return p2tr(pubkey.slice(1, 33), undefined, network).address!;
|
|
89
134
|
}
|
|
90
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Resolve the change-output recipient for a beacon transaction. Returns the beacon
|
|
138
|
+
* address when no change address is supplied (preserving the prior behavior of
|
|
139
|
+
* returning change to the spent address), otherwise validates the caller-supplied
|
|
140
|
+
* address against the network and returns it. Validating here fails fast rather than
|
|
141
|
+
* burning a real UTXO on a transaction that breaks at broadcast (ADR 044).
|
|
142
|
+
*/
|
|
143
|
+
export function resolveChangeAddress(
|
|
144
|
+
beaconAddress: string,
|
|
145
|
+
network: BTCNetwork,
|
|
146
|
+
changeAddress?: string,
|
|
147
|
+
): string {
|
|
148
|
+
if(!changeAddress || changeAddress === beaconAddress) return beaconAddress;
|
|
149
|
+
try {
|
|
150
|
+
Address(network).decode(changeAddress);
|
|
151
|
+
} catch {
|
|
152
|
+
throw new BeaconError(
|
|
153
|
+
`Invalid change address "${changeAddress}" for network "${network}".`,
|
|
154
|
+
'INVALID_CHANGE_ADDRESS',
|
|
155
|
+
{ changeAddress, network }
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return changeAddress;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Detect the change output's script kind for fee sizing. A change address that is not
|
|
163
|
+
* one of the three singleton kinds (for example P2SH or P2WSH) is sized as P2TR, the
|
|
164
|
+
* largest standard change output, so the estimated fee stays a valid upper bound.
|
|
165
|
+
*/
|
|
166
|
+
function changeOutputKind(changeAddress: string, network: BTCNetwork): SingletonScriptKind {
|
|
167
|
+
try {
|
|
168
|
+
return detectSingletonScriptKind(changeAddress, network);
|
|
169
|
+
} catch {
|
|
170
|
+
return 'p2tr';
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
91
174
|
/**
|
|
92
175
|
* Options accepted by {@link SinglePartyBeacon.buildSignAndBroadcast} and related helpers.
|
|
93
176
|
*/
|
|
94
177
|
export interface BroadcastOptions {
|
|
95
178
|
/** Fee estimator for computing the transaction fee. Defaults to {@link DEFAULT_FEE_ESTIMATOR}. */
|
|
96
179
|
feeEstimator?: FeeEstimator;
|
|
180
|
+
/**
|
|
181
|
+
* Address to send change to. Defaults to the beacon address (reuses the spent
|
|
182
|
+
* address, the prior behavior). Supply a fresh address the controller owns to
|
|
183
|
+
* stop linking the beacon's announcements into one on-chain chain (ADR 044).
|
|
184
|
+
*/
|
|
185
|
+
changeAddress?: string;
|
|
97
186
|
}
|
|
98
187
|
|
|
99
188
|
/**
|
|
@@ -107,8 +196,10 @@ export interface BeaconTxPlan {
|
|
|
107
196
|
prevOutScripts: Uint8Array[];
|
|
108
197
|
/** Amounts (sats) of the consumed previous outputs. */
|
|
109
198
|
prevOutValues: bigint[];
|
|
110
|
-
/**
|
|
199
|
+
/** The beacon address this tx spends from. */
|
|
111
200
|
beaconAddress: string;
|
|
201
|
+
/** Address the change output was sent to (the beacon address unless a change address was supplied). */
|
|
202
|
+
changeAddress: string;
|
|
112
203
|
/** The UTXO this tx consumes. */
|
|
113
204
|
utxo: AddressUtxo;
|
|
114
205
|
/** The fee (sats) already deducted from the change output. */
|
|
@@ -188,9 +279,17 @@ export async function buildAggregationBeaconTx(opts: {
|
|
|
188
279
|
network: BTCNetwork;
|
|
189
280
|
/** Optional fee estimator (defaults to 5 sat/vB). */
|
|
190
281
|
feeEstimator?: FeeEstimator;
|
|
282
|
+
/**
|
|
283
|
+
* Address to send change to. Defaults to the beacon (cohort) address. Supply the
|
|
284
|
+
* funder's address (an operator-funded cohort's funding wallet) to stop reusing the
|
|
285
|
+
* cohort address for change (ADR 044). Change ownership is the funder's call, which
|
|
286
|
+
* the cohort-condition model leaves to the caller (ADR 039).
|
|
287
|
+
*/
|
|
288
|
+
changeAddress?: string;
|
|
191
289
|
}): Promise<BeaconTxPlan> {
|
|
192
290
|
const feeEstimator = opts.feeEstimator ?? DEFAULT_FEE_ESTIMATOR;
|
|
193
291
|
const { utxo, prevTxBytes } = await fetchSpendableUtxo(opts.beaconAddress, opts.bitcoin);
|
|
292
|
+
const changeAddress = resolveChangeAddress(opts.beaconAddress, opts.network, opts.changeAddress);
|
|
194
293
|
|
|
195
294
|
// The funded beacon output is a Taproot script-tree output: key path is the
|
|
196
295
|
// MuSig2 aggregate, script path is the k-of-n fallback + CSV recovery leaves
|
|
@@ -200,8 +299,11 @@ export async function buildAggregationBeaconTx(opts: {
|
|
|
200
299
|
// key-path sighash and the fallback script-path sighash.
|
|
201
300
|
const witnessScript = OutScript.encode(Address(opts.network).decode(opts.beaconAddress));
|
|
202
301
|
|
|
203
|
-
//
|
|
204
|
-
|
|
302
|
+
// The fee cannot be probe-measured (no secret key until the downstream MuSig2
|
|
303
|
+
// round), so size it analytically. The input is the cohort's P2TR key path; only
|
|
304
|
+
// the change output's kind varies, so the vsize follows the change address (ADR 045).
|
|
305
|
+
const changeKind = changeOutputKind(changeAddress, opts.network);
|
|
306
|
+
const feeSats = await feeEstimator.estimateFee(beaconTxVsize('p2tr', changeKind));
|
|
205
307
|
if(BigInt(utxo.value) <= feeSats) {
|
|
206
308
|
throw new BeaconError(
|
|
207
309
|
`UTXO value (${utxo.value}) insufficient to cover fee (${feeSats}).`,
|
|
@@ -221,7 +323,12 @@ export async function buildAggregationBeaconTx(opts: {
|
|
|
221
323
|
witnessUtxo : { amount: BigInt(utxo.value), script: witnessScript },
|
|
222
324
|
tapInternalKey : opts.internalPubkey,
|
|
223
325
|
});
|
|
224
|
-
|
|
326
|
+
// Change first (omitted when it would be dust, sweeping the remainder into the
|
|
327
|
+
// fee), then the OP_RETURN signal, which the spec requires to be the last output.
|
|
328
|
+
const changeValue = BigInt(utxo.value) - feeSats;
|
|
329
|
+
if(changeValue >= BigInt(DUST_LIMIT_SATS[changeKind])) {
|
|
330
|
+
tx.addOutputAddress(changeAddress, changeValue, opts.network);
|
|
331
|
+
}
|
|
225
332
|
tx.addOutput({ script: opReturnScript(opts.signalBytes), amount: 0n });
|
|
226
333
|
|
|
227
334
|
return {
|
|
@@ -229,6 +336,7 @@ export async function buildAggregationBeaconTx(opts: {
|
|
|
229
336
|
prevOutScripts : [witnessScript],
|
|
230
337
|
prevOutValues : [BigInt(utxo.value)],
|
|
231
338
|
beaconAddress : opts.beaconAddress,
|
|
339
|
+
changeAddress,
|
|
232
340
|
utxo,
|
|
233
341
|
feeSats,
|
|
234
342
|
scriptKind : 'p2tr',
|
|
@@ -404,6 +512,7 @@ export abstract class SinglePartyBeacon {
|
|
|
404
512
|
const { utxo, prevTxBytes } = await fetchSpendableUtxo(beaconAddress, bitcoin);
|
|
405
513
|
const plan = await this.buildSinglePartyTx({
|
|
406
514
|
signalBytes, beaconAddress, utxo, prevTxBytes, signer, bitcoin, feeEstimator,
|
|
515
|
+
changeAddress : options?.changeAddress,
|
|
407
516
|
});
|
|
408
517
|
const signedHex = await this.signSinglePartyTx(plan, signer);
|
|
409
518
|
return this.broadcastRawTx(bitcoin, signedHex);
|
|
@@ -416,8 +525,9 @@ export abstract class SinglePartyBeacon {
|
|
|
416
525
|
* the input accordingly. Validates that the signer's pubkey produces the beacon
|
|
417
526
|
* address under that script kind: without this check, a misconfigured caller
|
|
418
527
|
* would burn a real UTXO on a tx that fails at broadcast. Fees are computed from
|
|
419
|
-
* the per-kind {@link SINGLETON_BEACON_TX_VSIZE} constant
|
|
420
|
-
* round-trip
|
|
528
|
+
* the per-kind {@link SINGLETON_BEACON_TX_VSIZE} constant (via {@link beaconTxVsize}),
|
|
529
|
+
* avoiding any probe-sign round-trip; a change address of a different kind re-sizes
|
|
530
|
+
* the fee by the change output's size delta so it stays a valid upper bound.
|
|
421
531
|
*/
|
|
422
532
|
protected async buildSinglePartyTx(opts: {
|
|
423
533
|
signalBytes: Uint8Array;
|
|
@@ -427,10 +537,12 @@ export abstract class SinglePartyBeacon {
|
|
|
427
537
|
signer: Signer;
|
|
428
538
|
bitcoin: BitcoinConnection;
|
|
429
539
|
feeEstimator: FeeEstimator;
|
|
540
|
+
changeAddress?: string;
|
|
430
541
|
}): Promise<BeaconTxPlan> {
|
|
431
542
|
const network = opts.bitcoin.data;
|
|
432
543
|
const pubkey = opts.signer.publicKey;
|
|
433
544
|
const kind = detectSingletonScriptKind(opts.beaconAddress, network);
|
|
545
|
+
const changeAddress = resolveChangeAddress(opts.beaconAddress, network, opts.changeAddress);
|
|
434
546
|
|
|
435
547
|
const derivedAddress = deriveSingletonAddress(kind, pubkey, network);
|
|
436
548
|
if(derivedAddress !== opts.beaconAddress) {
|
|
@@ -441,7 +553,8 @@ export abstract class SinglePartyBeacon {
|
|
|
441
553
|
);
|
|
442
554
|
}
|
|
443
555
|
|
|
444
|
-
const
|
|
556
|
+
const changeKind = changeOutputKind(changeAddress, network);
|
|
557
|
+
const feeSats = await opts.feeEstimator.estimateFee(beaconTxVsize(kind, changeKind));
|
|
445
558
|
const amount = BigInt(opts.utxo.value);
|
|
446
559
|
if(amount <= feeSats) {
|
|
447
560
|
throw new BeaconError(
|
|
@@ -487,7 +600,12 @@ export abstract class SinglePartyBeacon {
|
|
|
487
600
|
});
|
|
488
601
|
}
|
|
489
602
|
|
|
490
|
-
|
|
603
|
+
// Change first (omitted when it would be dust, sweeping the remainder into the
|
|
604
|
+
// fee), then the OP_RETURN signal, which the spec requires to be the last output.
|
|
605
|
+
const changeValue = amount - feeSats;
|
|
606
|
+
if(changeValue >= BigInt(DUST_LIMIT_SATS[changeKind])) {
|
|
607
|
+
tx.addOutputAddress(changeAddress, changeValue, network);
|
|
608
|
+
}
|
|
491
609
|
tx.addOutput({ script: opReturnScript(opts.signalBytes), amount: 0n });
|
|
492
610
|
|
|
493
611
|
return {
|
|
@@ -495,6 +613,7 @@ export abstract class SinglePartyBeacon {
|
|
|
495
613
|
prevOutScripts : [prevOutScript],
|
|
496
614
|
prevOutValues : [amount],
|
|
497
615
|
beaconAddress : opts.beaconAddress,
|
|
616
|
+
changeAddress,
|
|
498
617
|
utxo : opts.utxo,
|
|
499
618
|
feeSats,
|
|
500
619
|
scriptKind : kind,
|
|
@@ -1,52 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* the given virtual size (`vsize`). Callers pass the vsize; the estimator
|
|
11
|
-
* decides the fee rate and computes the total.
|
|
12
|
-
*/
|
|
13
|
-
export interface FeeEstimator {
|
|
14
|
-
/**
|
|
15
|
-
* Estimate the total fee in satoshis for a transaction of the given vsize.
|
|
16
|
-
* @param vsize Transaction virtual size in vbytes.
|
|
17
|
-
* @returns Total fee in satoshis.
|
|
18
|
-
*/
|
|
19
|
-
estimateFee(vsize: number): Promise<bigint>;
|
|
20
|
-
}
|
|
1
|
+
// The FeeEstimator contract and the StaticFeeEstimator implementation live in
|
|
2
|
+
// @did-btcr2/bitcoin, the natural home for a sat/vB fee primitive shared by the
|
|
3
|
+
// single-party and aggregated beacon broadcast paths. They are re-exported here so
|
|
4
|
+
// the @did-btcr2/method public surface is unchanged.
|
|
5
|
+
import { StaticFeeEstimator } from '@did-btcr2/bitcoin';
|
|
6
|
+
import type { FeeEstimator } from '@did-btcr2/bitcoin';
|
|
7
|
+
|
|
8
|
+
export { StaticFeeEstimator };
|
|
9
|
+
export type { FeeEstimator };
|
|
21
10
|
|
|
22
11
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* - Environments where a fee rate is supplied out-of-band
|
|
29
|
-
*
|
|
30
|
-
* For mainnet production use, prefer a dynamic estimator that queries current
|
|
31
|
-
* network conditions (mempool APIs, Bitcoin Core RPC).
|
|
12
|
+
* Default fee estimator used when a caller supplies none: a static 5 sat/vB rate.
|
|
13
|
+
* Suitable for tests and regtest. Production callers should inject a dynamic
|
|
14
|
+
* estimator (a mempool API, or Bitcoin Core `estimatesmartfee`) at the point the
|
|
15
|
+
* beacon transaction is built (single-party broadcast options, or the aggregation
|
|
16
|
+
* service runner's fee estimator).
|
|
32
17
|
*/
|
|
33
|
-
export
|
|
34
|
-
readonly satsPerVbyte: number;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @param satsPerVbyte Fee rate in satoshis per virtual byte. Default: 5 sat/vB.
|
|
38
|
-
*/
|
|
39
|
-
constructor(satsPerVbyte: number = 5) {
|
|
40
|
-
if(satsPerVbyte < 0 || !Number.isFinite(satsPerVbyte)) {
|
|
41
|
-
throw new Error(`Invalid satsPerVbyte: ${satsPerVbyte}`);
|
|
42
|
-
}
|
|
43
|
-
this.satsPerVbyte = satsPerVbyte;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async estimateFee(vsize: number): Promise<bigint> {
|
|
47
|
-
if(vsize < 0 || !Number.isFinite(vsize)) {
|
|
48
|
-
throw new Error(`Invalid vsize: ${vsize}`);
|
|
49
|
-
}
|
|
50
|
-
return BigInt(Math.ceil(vsize * this.satsPerVbyte));
|
|
51
|
-
}
|
|
52
|
-
}
|
|
18
|
+
export const DEFAULT_FEE_ESTIMATOR: FeeEstimator = new StaticFeeEstimator(5);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CompressedSecp256k1PublicKey } from '@did-btcr2/keypair';
|
|
2
|
+
import { Identifier } from './identifier.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a did:btcr2 sender's communication public key from its DID, for the
|
|
6
|
+
* aggregation HTTP transport's `resolveSenderPk` option: a KEY identifier decodes to
|
|
7
|
+
* its genesis public key. The aggregation transport is DID-method-agnostic and does
|
|
8
|
+
* not name `Identifier`; method supplies this resolver when it wires the transport so
|
|
9
|
+
* a sender that is not a pre-registered peer can still be authenticated from its DID.
|
|
10
|
+
*
|
|
11
|
+
* @param did The sender's DID.
|
|
12
|
+
* @returns The sender's compressed public key, or `undefined` when the DID is not a
|
|
13
|
+
* decodable did:btcr2 KEY identifier (resolution then falls back to registered peers).
|
|
14
|
+
*/
|
|
15
|
+
export function resolveBtcr2SenderPk(did: string): CompressedSecp256k1PublicKey | undefined {
|
|
16
|
+
try {
|
|
17
|
+
const components = Identifier.decode(did);
|
|
18
|
+
if(components.idType === 'KEY') {
|
|
19
|
+
return new CompressedSecp256k1PublicKey(components.genesisBytes);
|
|
20
|
+
}
|
|
21
|
+
} catch {
|
|
22
|
+
// Not a decodable did:btcr2 KEY identifier.
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
|
-
// Aggregation
|
|
2
|
-
export * from '
|
|
3
|
-
export * from './core/aggregation/participant.js';
|
|
4
|
-
export * from './core/aggregation/signer.js';
|
|
5
|
-
export * from './core/aggregation/conditions.js';
|
|
6
|
-
export * from './core/aggregation/recovery-policy.js';
|
|
7
|
-
export * from './core/aggregation/recovery-spend.js';
|
|
8
|
-
export * from './core/aggregation/fallback-spend.js';
|
|
9
|
-
export * from './core/aggregation/cohort.js';
|
|
10
|
-
export * from './core/aggregation/signing-session.js';
|
|
11
|
-
export * from './core/aggregation/phases.js';
|
|
12
|
-
export * from './core/aggregation/errors.js';
|
|
13
|
-
export * from './core/aggregation/beacon-strategy.js';
|
|
14
|
-
export * from './core/aggregation/logger.js';
|
|
15
|
-
export * from './core/aggregation/messages/index.js';
|
|
16
|
-
export * from './core/aggregation/transport/index.js';
|
|
17
|
-
export * from './core/aggregation/runner/index.js';
|
|
1
|
+
// Aggregation (extracted to @did-btcr2/aggregation; re-exported here for backward compatibility)
|
|
2
|
+
export * from '@did-btcr2/aggregation';
|
|
18
3
|
|
|
19
4
|
// Beacons
|
|
20
5
|
export * from './core/beacon/beacon.js';
|
|
@@ -29,6 +14,7 @@ export * from './core/beacon/smt-beacon.js';
|
|
|
29
14
|
export * from './core/beacon/utils.js';
|
|
30
15
|
|
|
31
16
|
// Core
|
|
17
|
+
export * from './core/did-sender-resolver.js';
|
|
32
18
|
export * from './core/identifier.js';
|
|
33
19
|
export * from './core/interfaces.js';
|
|
34
20
|
export * from './core/resolver.js';
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { canonicalize } from '@did-btcr2/common';
|
|
2
|
-
import { base64UrlToHash, blockHash, didToIndex, hashToBase64Url, verifySerializedProof } from '@did-btcr2/smt';
|
|
3
|
-
const CAS_STRATEGY = {
|
|
4
|
-
type: 'CASBeacon',
|
|
5
|
-
buildAggregatedData(cohort) {
|
|
6
|
-
cohort.buildCASAnnouncement();
|
|
7
|
-
},
|
|
8
|
-
getDistributePayload(cohort) {
|
|
9
|
-
return { casAnnouncement: cohort.casAnnouncement };
|
|
10
|
-
},
|
|
11
|
-
validateParticipantView({ participantDid, included, expectedHash, body }) {
|
|
12
|
-
const casAnnouncement = body.casAnnouncement;
|
|
13
|
-
if (!casAnnouncement)
|
|
14
|
-
return { matches: false };
|
|
15
|
-
if (!included) {
|
|
16
|
-
// Cooperative non-inclusion: the decliner must be ABSENT from the map.
|
|
17
|
-
return { matches: !(participantDid in casAnnouncement), casAnnouncement };
|
|
18
|
-
}
|
|
19
|
-
return {
|
|
20
|
-
matches: casAnnouncement[participantDid] === expectedHash,
|
|
21
|
-
casAnnouncement,
|
|
22
|
-
};
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
const SMT_STRATEGY = {
|
|
26
|
-
type: 'SMTBeacon',
|
|
27
|
-
buildAggregatedData(cohort) {
|
|
28
|
-
cohort.buildSMTTree();
|
|
29
|
-
},
|
|
30
|
-
getDistributePayload(cohort, participantDid) {
|
|
31
|
-
const proof = cohort.smtProofs?.get(participantDid);
|
|
32
|
-
return { smtProof: proof };
|
|
33
|
-
},
|
|
34
|
-
validateParticipantView({ participantDid, included, submittedUpdate, body }) {
|
|
35
|
-
const smtProof = body.smtProof;
|
|
36
|
-
const index = didToIndex(participantDid);
|
|
37
|
-
if (!included) {
|
|
38
|
-
// Cooperative non-inclusion: the proof has a nonce but no updateId by
|
|
39
|
-
// construction. The leaf is SHA-256(SHA-256(nonce)); do NOT run the
|
|
40
|
-
// inclusion-only updateId guard (a missing updateId is correct here).
|
|
41
|
-
if (!smtProof?.nonce || smtProof?.updateId)
|
|
42
|
-
return { matches: false, smtProof };
|
|
43
|
-
const candidateHash = blockHash(blockHash(base64UrlToHash(smtProof.nonce)));
|
|
44
|
-
return { matches: verifySerializedProof(smtProof, index, candidateHash), smtProof };
|
|
45
|
-
}
|
|
46
|
-
if (!smtProof?.updateId || !smtProof?.nonce || !submittedUpdate)
|
|
47
|
-
return { matches: false, smtProof };
|
|
48
|
-
// Verify updateId matches the canonicalized update hash. Proof hash fields
|
|
49
|
-
// are base64url (no padding) per the SMT Proof spec.
|
|
50
|
-
const canonicalBytes = new TextEncoder().encode(canonicalize(submittedUpdate));
|
|
51
|
-
const expectedUpdateId = hashToBase64Url(blockHash(canonicalBytes));
|
|
52
|
-
if (smtProof.updateId !== expectedUpdateId) {
|
|
53
|
-
return { matches: false, smtProof };
|
|
54
|
-
}
|
|
55
|
-
// Verify Merkle inclusion. The leaf is SHA-256(SHA-256(nonce) || SHA-256(update)).
|
|
56
|
-
const candidateHash = blockHash(blockHash(base64UrlToHash(smtProof.nonce)), base64UrlToHash(smtProof.updateId));
|
|
57
|
-
return {
|
|
58
|
-
matches: verifySerializedProof(smtProof, index, candidateHash),
|
|
59
|
-
smtProof,
|
|
60
|
-
};
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
/** Registered strategies keyed by `beaconType` string. */
|
|
64
|
-
const STRATEGIES = new Map([
|
|
65
|
-
[CAS_STRATEGY.type, CAS_STRATEGY],
|
|
66
|
-
[SMT_STRATEGY.type, SMT_STRATEGY],
|
|
67
|
-
]);
|
|
68
|
-
/** Register a custom beacon strategy. Overwrites any existing entry with the same type. */
|
|
69
|
-
export function registerBeaconStrategy(strategy) {
|
|
70
|
-
STRATEGIES.set(strategy.type, strategy);
|
|
71
|
-
}
|
|
72
|
-
/** Look up a registered beacon strategy by type, or undefined if not registered. */
|
|
73
|
-
export function getBeaconStrategy(type) {
|
|
74
|
-
return STRATEGIES.get(type);
|
|
75
|
-
}
|
|
76
|
-
//# sourceMappingURL=beacon-strategy.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"beacon-strategy.js","sourceRoot":"","sources":["../../../../src/core/aggregation/beacon-strategy.ts"],"names":[],"mappings":"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"}
|