@arkade-os/sdk 0.4.19 → 0.4.21
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/cjs/contracts/contractWatcher.js +33 -3
- package/dist/cjs/contracts/handlers/default.js +10 -3
- package/dist/cjs/contracts/handlers/helpers.js +47 -5
- package/dist/cjs/contracts/handlers/vhtlc.js +4 -2
- package/dist/cjs/identity/descriptor.js +98 -0
- package/dist/cjs/identity/descriptorProvider.js +2 -0
- package/dist/cjs/identity/index.js +15 -1
- package/dist/cjs/identity/seedIdentity.js +91 -6
- package/dist/cjs/identity/serialize.js +166 -0
- package/dist/cjs/identity/staticDescriptorProvider.js +65 -0
- package/dist/cjs/index.js +6 -3
- package/dist/cjs/providers/ark.js +71 -46
- package/dist/cjs/providers/electrum.js +663 -0
- package/dist/cjs/providers/indexer.js +60 -43
- package/dist/cjs/providers/utils.js +62 -12
- package/dist/cjs/wallet/ramps.js +1 -1
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +10 -0
- package/dist/cjs/wallet/serviceWorker/wallet.js +137 -91
- package/dist/cjs/wallet/vtxo-manager.js +56 -8
- package/dist/cjs/wallet/wallet.js +130 -156
- package/dist/cjs/worker/messageBus.js +200 -56
- package/dist/esm/contracts/contractWatcher.js +33 -3
- package/dist/esm/contracts/handlers/default.js +10 -3
- package/dist/esm/contracts/handlers/helpers.js +47 -5
- package/dist/esm/contracts/handlers/vhtlc.js +4 -2
- package/dist/esm/identity/descriptor.js +92 -0
- package/dist/esm/identity/descriptorProvider.js +1 -0
- package/dist/esm/identity/index.js +6 -1
- package/dist/esm/identity/seedIdentity.js +89 -6
- package/dist/esm/identity/serialize.js +159 -0
- package/dist/esm/identity/staticDescriptorProvider.js +61 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/providers/ark.js +72 -47
- package/dist/esm/providers/electrum.js +658 -0
- package/dist/esm/providers/indexer.js +61 -44
- package/dist/esm/providers/utils.js +61 -12
- package/dist/esm/wallet/ramps.js +1 -1
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +10 -0
- package/dist/esm/wallet/serviceWorker/wallet.js +137 -91
- package/dist/esm/wallet/vtxo-manager.js +56 -8
- package/dist/esm/wallet/wallet.js +130 -156
- package/dist/esm/worker/messageBus.js +201 -57
- package/dist/types/contracts/contractWatcher.d.ts +3 -0
- package/dist/types/contracts/handlers/default.d.ts +1 -1
- package/dist/types/contracts/handlers/helpers.d.ts +1 -1
- package/dist/types/contracts/types.d.ts +11 -3
- package/dist/types/identity/descriptor.d.ts +35 -0
- package/dist/types/identity/descriptorProvider.d.ts +28 -0
- package/dist/types/identity/index.d.ts +7 -1
- package/dist/types/identity/seedIdentity.d.ts +41 -4
- package/dist/types/identity/serialize.d.ts +84 -0
- package/dist/types/identity/staticDescriptorProvider.d.ts +18 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/providers/electrum.d.ts +212 -0
- package/dist/types/providers/utils.d.ts +10 -5
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +11 -2
- package/dist/types/wallet/serviceWorker/wallet.d.ts +27 -10
- package/dist/types/wallet/vtxo-manager.d.ts +2 -0
- package/dist/types/wallet/wallet.d.ts +7 -6
- package/dist/types/worker/messageBus.d.ts +68 -8
- package/package.json +3 -2
|
@@ -10,6 +10,8 @@ const base_1 = require("@scure/base");
|
|
|
10
10
|
const base_2 = require("../script/base");
|
|
11
11
|
const transaction_1 = require("../utils/transaction");
|
|
12
12
|
const txSizeEstimator_1 = require("../utils/txSizeEstimator");
|
|
13
|
+
const arkfee_1 = require("../arkfee");
|
|
14
|
+
const address_1 = require("../script/address");
|
|
13
15
|
/**
|
|
14
16
|
* Return whether a wallet exposes the properties required for boarding input sweep operations.
|
|
15
17
|
*
|
|
@@ -19,6 +21,7 @@ const txSizeEstimator_1 = require("../utils/txSizeEstimator");
|
|
|
19
21
|
function isSweepCapable(wallet) {
|
|
20
22
|
return ("boardingTapscript" in wallet &&
|
|
21
23
|
"onchainProvider" in wallet &&
|
|
24
|
+
"arkProvider" in wallet &&
|
|
22
25
|
"network" in wallet);
|
|
23
26
|
}
|
|
24
27
|
/**
|
|
@@ -29,7 +32,7 @@ function isSweepCapable(wallet) {
|
|
|
29
32
|
*/
|
|
30
33
|
function assertSweepCapable(wallet) {
|
|
31
34
|
if (!isSweepCapable(wallet)) {
|
|
32
|
-
throw new Error("Boarding UTXO sweep requires a Wallet instance with boardingTapscript, onchainProvider, and network");
|
|
35
|
+
throw new Error("Boarding UTXO sweep requires a Wallet instance with boardingTapscript, onchainProvider, arkProvider, and network");
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
/**
|
|
@@ -627,6 +630,10 @@ class VtxoManager {
|
|
|
627
630
|
getOnchainProvider() {
|
|
628
631
|
return this.getSweepWallet().onchainProvider;
|
|
629
632
|
}
|
|
633
|
+
/** Returns the Ark provider for intent fee and server info lookups. */
|
|
634
|
+
getArkProvider() {
|
|
635
|
+
return this.getSweepWallet().arkProvider;
|
|
636
|
+
}
|
|
630
637
|
/** Returns the Bitcoin network configuration from the wallet. */
|
|
631
638
|
getNetwork() {
|
|
632
639
|
return this.getSweepWallet().network;
|
|
@@ -896,13 +903,54 @@ class VtxoManager {
|
|
|
896
903
|
return;
|
|
897
904
|
}
|
|
898
905
|
const dustAmount = getDustAmount(this.wallet);
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
906
|
+
// Fetch server intent-fee config so each input/output can be priced.
|
|
907
|
+
// Without this, settle sends `outputAmount = sum(inputs)` and the
|
|
908
|
+
// server rejects with INTENT_INSUFFICIENT_FEE whenever the operator
|
|
909
|
+
// charges non-zero intent fees.
|
|
910
|
+
const { fees } = await this.getArkProvider().getInfo();
|
|
911
|
+
const estimator = new arkfee_1.Estimator(fees.intentFee);
|
|
912
|
+
let totalAmount = 0n;
|
|
913
|
+
const filteredBoarding = [];
|
|
914
|
+
for (const u of unsettledBoarding) {
|
|
915
|
+
const inputFee = estimator.evalOnchainInput({
|
|
916
|
+
amount: BigInt(u.value),
|
|
917
|
+
});
|
|
918
|
+
if (inputFee.value >= BigInt(u.value)) {
|
|
919
|
+
// Fee exceeds input value — including it would drain the output.
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
filteredBoarding.push(u);
|
|
923
|
+
totalAmount += BigInt(u.value) - BigInt(inputFee.satoshis);
|
|
924
|
+
}
|
|
925
|
+
const filteredVtxos = [];
|
|
926
|
+
for (const v of expiringVtxos) {
|
|
927
|
+
const inputFee = estimator.evalOffchainInput({
|
|
928
|
+
amount: BigInt(v.value),
|
|
929
|
+
type: v.virtualStatus.state === "swept" ? "recoverable" : "vtxo",
|
|
930
|
+
weight: 0,
|
|
931
|
+
birth: v.createdAt,
|
|
932
|
+
expiry: v.virtualStatus.batchExpiry
|
|
933
|
+
? new Date(v.virtualStatus.batchExpiry)
|
|
934
|
+
: undefined,
|
|
935
|
+
});
|
|
936
|
+
if (inputFee.satoshis >= v.value) {
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
filteredVtxos.push(v);
|
|
940
|
+
totalAmount += BigInt(v.value) - BigInt(inputFee.satoshis);
|
|
941
|
+
}
|
|
942
|
+
if (filteredBoarding.length === 0 && filteredVtxos.length === 0) {
|
|
903
943
|
return;
|
|
944
|
+
}
|
|
904
945
|
const arkAddress = await this.wallet.getAddress();
|
|
905
|
-
const
|
|
946
|
+
const outputFee = estimator.evalOffchainOutput({
|
|
947
|
+
amount: totalAmount,
|
|
948
|
+
script: base_1.hex.encode(address_1.ArkAddress.decode(arkAddress).pkScript),
|
|
949
|
+
});
|
|
950
|
+
totalAmount -= BigInt(outputFee.satoshis);
|
|
951
|
+
if (totalAmount < dustAmount)
|
|
952
|
+
return;
|
|
953
|
+
const includesVtxos = filteredVtxos.length > 0;
|
|
906
954
|
// Block the event-driven renewal path while this settle is in flight
|
|
907
955
|
// when VTXOs are part of the intent. Mirrors renewVtxos()'s guard so
|
|
908
956
|
// the two paths can't race on the same VTXO inputs.
|
|
@@ -914,11 +962,11 @@ class VtxoManager {
|
|
|
914
962
|
try {
|
|
915
963
|
try {
|
|
916
964
|
await this.wallet.settle({
|
|
917
|
-
inputs: [...
|
|
965
|
+
inputs: [...filteredBoarding, ...filteredVtxos],
|
|
918
966
|
outputs: [{ address: arkAddress, amount: totalAmount }],
|
|
919
967
|
});
|
|
920
968
|
// Mark boarding inputs as known only after successful settle.
|
|
921
|
-
for (const u of
|
|
969
|
+
for (const u of filteredBoarding) {
|
|
922
970
|
this.knownBoardingUtxos.add(`${u.txid}:${u.vout}`);
|
|
923
971
|
}
|
|
924
972
|
success = true;
|
|
@@ -39,10 +39,28 @@ const contractManager_1 = require("../contracts/contractManager");
|
|
|
39
39
|
const handlers_1 = require("../contracts/handlers");
|
|
40
40
|
const helpers_1 = require("../contracts/handlers/helpers");
|
|
41
41
|
const syncCursors_1 = require("../utils/syncCursors");
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
42
|
+
// Historical unilateral exit delay for mainnet (~7 days in seconds).
|
|
43
|
+
// Kept so existing wallets can still discover and spend VTXOs sent to the
|
|
44
|
+
// legacy address after arkd starts advertising a different delay.
|
|
45
45
|
const MAINNET_UNILATERAL_EXIT_DELAY = 605184n;
|
|
46
|
+
function delayToTimelock(delay) {
|
|
47
|
+
return {
|
|
48
|
+
value: delay,
|
|
49
|
+
type: delay < 512n ? "blocks" : "seconds",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function dedupeTimelocks(timelocks) {
|
|
53
|
+
const seen = new Set();
|
|
54
|
+
const deduped = [];
|
|
55
|
+
for (const timelock of timelocks) {
|
|
56
|
+
const sequence = (0, helpers_1.timelockToSequence)(timelock).toString();
|
|
57
|
+
if (seen.has(sequence))
|
|
58
|
+
continue;
|
|
59
|
+
seen.add(sequence);
|
|
60
|
+
deduped.push(timelock);
|
|
61
|
+
}
|
|
62
|
+
return deduped;
|
|
63
|
+
}
|
|
46
64
|
/**
|
|
47
65
|
* Type guard function to check if an identity has a toReadonly method.
|
|
48
66
|
*/
|
|
@@ -56,7 +74,7 @@ class ReadonlyWallet {
|
|
|
56
74
|
get assetManager() {
|
|
57
75
|
return this._assetManager;
|
|
58
76
|
}
|
|
59
|
-
constructor(identity, network, onchainProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, dustAmount, walletRepository, contractRepository, delegatorProvider, watcherConfig) {
|
|
77
|
+
constructor(identity, network, onchainProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, dustAmount, walletRepository, contractRepository, delegatorProvider, watcherConfig, walletContractTimelocks) {
|
|
60
78
|
this.identity = identity;
|
|
61
79
|
this.network = network;
|
|
62
80
|
this.onchainProvider = onchainProvider;
|
|
@@ -89,6 +107,15 @@ class ReadonlyWallet {
|
|
|
89
107
|
}
|
|
90
108
|
this.watcherConfig = watcherConfig;
|
|
91
109
|
this._assetManager = new asset_manager_1.ReadonlyAssetManager(this.indexerProvider);
|
|
110
|
+
// Defensive for direct-construction callers; setupWalletConfig already
|
|
111
|
+
// passes a deduped list through the public create() factories.
|
|
112
|
+
this.walletContractTimelocks =
|
|
113
|
+
walletContractTimelocks && walletContractTimelocks.length > 0
|
|
114
|
+
? dedupeTimelocks(walletContractTimelocks)
|
|
115
|
+
: [
|
|
116
|
+
this.offchainTapscript.options.csvTimelock ??
|
|
117
|
+
default_1.DefaultVtxo.Script.DEFAULT_TIMELOCK,
|
|
118
|
+
];
|
|
92
119
|
}
|
|
93
120
|
/**
|
|
94
121
|
* Protected helper to set up shared wallet configuration.
|
|
@@ -144,17 +171,17 @@ class ReadonlyWallet {
|
|
|
144
171
|
throw new Error("invalid exitTimelock");
|
|
145
172
|
}
|
|
146
173
|
}
|
|
147
|
-
|
|
148
|
-
// that addresses derived by existing wallets remain stable even if the
|
|
149
|
-
// server starts advertising a shorter delay.
|
|
150
|
-
const unilateralExitDelay = info.network === "bitcoin"
|
|
151
|
-
? MAINNET_UNILATERAL_EXIT_DELAY
|
|
152
|
-
: info.unilateralExitDelay;
|
|
174
|
+
const arkdExitTimelock = delayToTimelock(info.unilateralExitDelay);
|
|
153
175
|
// create unilateral exit timelock
|
|
154
|
-
const exitTimelock = config.exitTimelock ??
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
176
|
+
const exitTimelock = config.exitTimelock ?? arkdExitTimelock;
|
|
177
|
+
const walletContractTimelocks = config.exitTimelock
|
|
178
|
+
? [exitTimelock]
|
|
179
|
+
: dedupeTimelocks([
|
|
180
|
+
arkdExitTimelock,
|
|
181
|
+
...(info.network === "bitcoin"
|
|
182
|
+
? [delayToTimelock(MAINNET_UNILATERAL_EXIT_DELAY)]
|
|
183
|
+
: []),
|
|
184
|
+
]);
|
|
158
185
|
// validate boarding timelock passed in config if any
|
|
159
186
|
if (config.boardingTimelock) {
|
|
160
187
|
const { value, type } = config.boardingTimelock;
|
|
@@ -204,6 +231,7 @@ class ReadonlyWallet {
|
|
|
204
231
|
contractRepository,
|
|
205
232
|
info,
|
|
206
233
|
delegatorProvider: config.delegatorProvider,
|
|
234
|
+
walletContractTimelocks,
|
|
207
235
|
};
|
|
208
236
|
}
|
|
209
237
|
/**
|
|
@@ -218,14 +246,14 @@ class ReadonlyWallet {
|
|
|
218
246
|
throw new Error("Invalid configured public key");
|
|
219
247
|
}
|
|
220
248
|
const setup = await ReadonlyWallet.setupWalletConfig(config, pubkey);
|
|
221
|
-
return new ReadonlyWallet(config.identity, setup.network, setup.onchainProvider, setup.indexerProvider, setup.serverPubKey, setup.offchainTapscript, setup.boardingTapscript, setup.dustAmount, setup.walletRepository, setup.contractRepository, setup.delegatorProvider, config.watcherConfig);
|
|
249
|
+
return new ReadonlyWallet(config.identity, setup.network, setup.onchainProvider, setup.indexerProvider, setup.serverPubKey, setup.offchainTapscript, setup.boardingTapscript, setup.dustAmount, setup.walletRepository, setup.contractRepository, setup.delegatorProvider, config.watcherConfig, setup.walletContractTimelocks);
|
|
222
250
|
}
|
|
223
251
|
get arkAddress() {
|
|
224
252
|
return this.offchainTapscript.address(this.network.hrp, this.arkServerPublicKey);
|
|
225
253
|
}
|
|
226
254
|
/**
|
|
227
|
-
* Get the
|
|
228
|
-
*
|
|
255
|
+
* Get the pkScript hex for the wallet's primary offchain address.
|
|
256
|
+
* For the full wallet-owned script set registered in ContractManager, use getWalletScripts().
|
|
229
257
|
*/
|
|
230
258
|
get defaultContractScript() {
|
|
231
259
|
return base_1.hex.encode(this.offchainTapscript.pkScript);
|
|
@@ -469,56 +497,39 @@ class ReadonlyWallet {
|
|
|
469
497
|
});
|
|
470
498
|
}
|
|
471
499
|
if (this.indexerProvider && arkAddress) {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
// resolves to the owning contract so the extension uses the
|
|
485
|
-
// correct forfeit/intent tapscripts.
|
|
486
|
-
(async () => {
|
|
487
|
-
try {
|
|
488
|
-
const cm = await this.getContractManager();
|
|
489
|
-
for await (const update of subscription) {
|
|
490
|
-
if (update.newVtxos?.length === 0 &&
|
|
491
|
-
update.spentVtxos?.length === 0) {
|
|
492
|
-
continue;
|
|
493
|
-
}
|
|
494
|
-
// Isolate per-update annotation failures (e.g. a VTXO
|
|
495
|
-
// arriving for a contract we haven't registered yet).
|
|
496
|
-
// Without this a single bad update would kill the
|
|
497
|
-
// for-await loop and silently drop every subsequent
|
|
498
|
-
// subscription event for the session.
|
|
499
|
-
try {
|
|
500
|
-
// Default to `[]` so a one-sided update (e.g.
|
|
501
|
-
// only `newVtxos`) doesn't pass `undefined` into
|
|
502
|
-
// annotateVtxos and throw on `.length`.
|
|
503
|
-
const [newVtxos, spentVtxos] = await Promise.all([
|
|
504
|
-
cm.annotateVtxos(update.newVtxos ?? []),
|
|
505
|
-
cm.annotateVtxos(update.spentVtxos ?? []),
|
|
506
|
-
]);
|
|
507
|
-
eventCallback({
|
|
508
|
-
type: "vtxo",
|
|
509
|
-
newVtxos,
|
|
510
|
-
spentVtxos,
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
catch (error) {
|
|
514
|
-
console.warn("Dropping subscription update after annotation failed; next sync will reconcile:", error);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
500
|
+
// Share the ContractWatcher's single subscription instead of
|
|
501
|
+
// opening a second SSE stream.
|
|
502
|
+
const cm = await this.getContractManager();
|
|
503
|
+
// Serialize annotation+notification: parallel `annotateVtxos`
|
|
504
|
+
// awaits could resolve out of order and deliver eventCallback
|
|
505
|
+
// calls in the wrong sequence (e.g. `vtxo_spent` before its
|
|
506
|
+
// matching `vtxo_received`).
|
|
507
|
+
let annotationQueue = Promise.resolve();
|
|
508
|
+
indexerStopFunc = cm.onContractEvent((event) => {
|
|
509
|
+
if (event.type !== "vtxo_received" &&
|
|
510
|
+
event.type !== "vtxo_spent") {
|
|
511
|
+
return;
|
|
517
512
|
}
|
|
518
|
-
|
|
519
|
-
|
|
513
|
+
if (event.contract.type !== "default" &&
|
|
514
|
+
event.contract.type !== "delegate") {
|
|
515
|
+
return;
|
|
520
516
|
}
|
|
521
|
-
|
|
517
|
+
// `event.vtxos` carries placeholder tapscript fields from
|
|
518
|
+
// the watcher; `annotateVtxos` fills them in.
|
|
519
|
+
annotationQueue = annotationQueue.then(async () => {
|
|
520
|
+
try {
|
|
521
|
+
const annotated = await cm.annotateVtxos(event.vtxos);
|
|
522
|
+
eventCallback({
|
|
523
|
+
type: "vtxo",
|
|
524
|
+
newVtxos: event.type === "vtxo_received" ? annotated : [],
|
|
525
|
+
spentVtxos: event.type === "vtxo_spent" ? annotated : [],
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
console.warn("Dropping subscription update after annotation failed; next sync will reconcile:", error);
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
});
|
|
522
533
|
}
|
|
523
534
|
const stopFunc = () => {
|
|
524
535
|
onchainStopFunc?.();
|
|
@@ -545,27 +556,13 @@ class ReadonlyWallet {
|
|
|
545
556
|
/**
|
|
546
557
|
* Get all pkScript hex strings for the wallet's own addresses
|
|
547
558
|
* (both delegate and non-delegate, current and historical).
|
|
548
|
-
* Falls back to only the current script if ContractManager is not yet initialized.
|
|
549
559
|
*/
|
|
550
560
|
async getWalletScripts() {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const manager = await this.getContractManager();
|
|
557
|
-
const contracts = await manager.getContracts({
|
|
558
|
-
type: ["default", "delegate"],
|
|
559
|
-
});
|
|
560
|
-
if (contracts.length > 0) {
|
|
561
|
-
return contracts.map((c) => c.script);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
catch {
|
|
565
|
-
// fall through to current script only
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
return [base_1.hex.encode(this.offchainTapscript.pkScript)];
|
|
561
|
+
const manager = await this.getContractManager();
|
|
562
|
+
const contracts = await manager.getContracts({
|
|
563
|
+
type: ["default", "delegate"],
|
|
564
|
+
});
|
|
565
|
+
return contracts.map((c) => c.script);
|
|
569
566
|
}
|
|
570
567
|
/**
|
|
571
568
|
* Build a map of scriptHex → VtxoScript for all wallet contracts,
|
|
@@ -573,26 +570,17 @@ class ReadonlyWallet {
|
|
|
573
570
|
*/
|
|
574
571
|
async getScriptMap() {
|
|
575
572
|
const map = new Map();
|
|
576
|
-
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
const handler = handlers_1.contractHandlers.get(contract.type);
|
|
588
|
-
if (handler) {
|
|
589
|
-
const script = handler.createScript(contract.params);
|
|
590
|
-
map.set(contract.script, script);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
catch {
|
|
595
|
-
// ContractManager error — only current script in map
|
|
573
|
+
const manager = await this.getContractManager();
|
|
574
|
+
const contracts = await manager.getContracts({
|
|
575
|
+
type: ["default", "delegate"],
|
|
576
|
+
});
|
|
577
|
+
for (const contract of contracts) {
|
|
578
|
+
if (map.has(contract.script))
|
|
579
|
+
continue;
|
|
580
|
+
const handler = handlers_1.contractHandlers.get(contract.type);
|
|
581
|
+
if (handler) {
|
|
582
|
+
const script = handler.createScript(contract.params);
|
|
583
|
+
map.set(contract.script, script);
|
|
596
584
|
}
|
|
597
585
|
}
|
|
598
586
|
return map;
|
|
@@ -660,62 +648,48 @@ class ReadonlyWallet {
|
|
|
660
648
|
walletRepository: this.walletRepository,
|
|
661
649
|
watcherConfig: this.watcherConfig,
|
|
662
650
|
});
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
default_1.DefaultVtxo.Script
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
if (isDelegateScript) {
|
|
669
|
-
const delegateScript = this
|
|
670
|
-
.offchainTapscript;
|
|
671
|
-
// Register the delegate contract (current address)
|
|
672
|
-
await manager.createContract({
|
|
673
|
-
type: "delegate",
|
|
674
|
-
params: {
|
|
675
|
-
pubKey: base_1.hex.encode(delegateScript.options.pubKey),
|
|
676
|
-
serverPubKey: base_1.hex.encode(delegateScript.options.serverPubKey),
|
|
677
|
-
delegatePubKey: base_1.hex.encode(delegateScript.options.delegatePubKey),
|
|
678
|
-
csvTimelock: csvTimelockStr,
|
|
679
|
-
},
|
|
680
|
-
script: this.defaultContractScript,
|
|
681
|
-
address: await this.getAddress(),
|
|
682
|
-
state: "active",
|
|
683
|
-
});
|
|
684
|
-
// Also register the non-delegate version so old virtual outputs remain visible
|
|
685
|
-
const nonDelegateScript = new default_1.DefaultVtxo.Script({
|
|
686
|
-
pubKey: delegateScript.options.pubKey,
|
|
687
|
-
serverPubKey: delegateScript.options.serverPubKey,
|
|
651
|
+
for (const csvTimelock of this.walletContractTimelocks) {
|
|
652
|
+
const csvTimelockStr = (0, helpers_1.timelockToSequence)(csvTimelock).toString();
|
|
653
|
+
const defaultScript = new default_1.DefaultVtxo.Script({
|
|
654
|
+
pubKey: this.offchainTapscript.options.pubKey,
|
|
655
|
+
serverPubKey: this.offchainTapscript.options.serverPubKey,
|
|
688
656
|
csvTimelock,
|
|
689
657
|
});
|
|
690
658
|
await manager.createContract({
|
|
691
659
|
type: "default",
|
|
692
660
|
params: {
|
|
693
|
-
pubKey: base_1.hex.encode(
|
|
694
|
-
serverPubKey: base_1.hex.encode(
|
|
661
|
+
pubKey: base_1.hex.encode(defaultScript.options.pubKey),
|
|
662
|
+
serverPubKey: base_1.hex.encode(defaultScript.options.serverPubKey),
|
|
695
663
|
csvTimelock: csvTimelockStr,
|
|
696
664
|
},
|
|
697
|
-
script: base_1.hex.encode(
|
|
698
|
-
address:
|
|
665
|
+
script: base_1.hex.encode(defaultScript.pkScript),
|
|
666
|
+
address: defaultScript
|
|
699
667
|
.address(this.network.hrp, this.arkServerPublicKey)
|
|
700
668
|
.encode(),
|
|
701
669
|
state: "active",
|
|
702
670
|
});
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
671
|
+
if (this.offchainTapscript instanceof delegate_1.DelegateVtxo.Script) {
|
|
672
|
+
const delegateScript = new delegate_1.DelegateVtxo.Script({
|
|
673
|
+
pubKey: this.offchainTapscript.options.pubKey,
|
|
674
|
+
serverPubKey: this.offchainTapscript.options.serverPubKey,
|
|
675
|
+
delegatePubKey: this.offchainTapscript.options.delegatePubKey,
|
|
676
|
+
csvTimelock,
|
|
677
|
+
});
|
|
678
|
+
await manager.createContract({
|
|
679
|
+
type: "delegate",
|
|
680
|
+
params: {
|
|
681
|
+
pubKey: base_1.hex.encode(delegateScript.options.pubKey),
|
|
682
|
+
serverPubKey: base_1.hex.encode(delegateScript.options.serverPubKey),
|
|
683
|
+
delegatePubKey: base_1.hex.encode(delegateScript.options.delegatePubKey),
|
|
684
|
+
csvTimelock: csvTimelockStr,
|
|
685
|
+
},
|
|
686
|
+
script: base_1.hex.encode(delegateScript.pkScript),
|
|
687
|
+
address: delegateScript
|
|
688
|
+
.address(this.network.hrp, this.arkServerPublicKey)
|
|
689
|
+
.encode(),
|
|
690
|
+
state: "active",
|
|
691
|
+
});
|
|
692
|
+
}
|
|
719
693
|
}
|
|
720
694
|
return manager;
|
|
721
695
|
}
|
|
@@ -799,8 +773,8 @@ class Wallet extends ReadonlyWallet {
|
|
|
799
773
|
}
|
|
800
774
|
constructor(identity, network, onchainProvider, arkProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, serverUnrollScript, forfeitOutputScript, forfeitPubkey, dustAmount, walletRepository, contractRepository,
|
|
801
775
|
/** @deprecated Use settlementConfig */
|
|
802
|
-
renewalConfig, delegatorProvider, watcherConfig, settlementConfig) {
|
|
803
|
-
super(identity, network, onchainProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, dustAmount, walletRepository, contractRepository, delegatorProvider, watcherConfig);
|
|
776
|
+
renewalConfig, delegatorProvider, watcherConfig, settlementConfig, walletContractTimelocks) {
|
|
777
|
+
super(identity, network, onchainProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, dustAmount, walletRepository, contractRepository, delegatorProvider, watcherConfig, walletContractTimelocks);
|
|
804
778
|
this.arkProvider = arkProvider;
|
|
805
779
|
this.serverUnrollScript = serverUnrollScript;
|
|
806
780
|
this.forfeitOutputScript = forfeitOutputScript;
|
|
@@ -920,7 +894,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
920
894
|
const forfeitPubkey = base_1.hex.decode(setup.info.forfeitPubkey).slice(1);
|
|
921
895
|
const forfeitAddress = (0, btc_signer_1.Address)(setup.network).decode(setup.info.forfeitAddress);
|
|
922
896
|
const forfeitOutputScript = btc_signer_1.OutScript.encode(forfeitAddress);
|
|
923
|
-
const wallet = new Wallet(config.identity, setup.network, setup.onchainProvider, setup.arkProvider, setup.indexerProvider, setup.serverPubKey, setup.offchainTapscript, setup.boardingTapscript, serverUnrollScript, forfeitOutputScript, forfeitPubkey, setup.dustAmount, setup.walletRepository, setup.contractRepository, config.renewalConfig, config.delegatorProvider, config.watcherConfig, config.settlementConfig);
|
|
897
|
+
const wallet = new Wallet(config.identity, setup.network, setup.onchainProvider, setup.arkProvider, setup.indexerProvider, setup.serverPubKey, setup.offchainTapscript, setup.boardingTapscript, serverUnrollScript, forfeitOutputScript, forfeitPubkey, setup.dustAmount, setup.walletRepository, setup.contractRepository, config.renewalConfig, config.delegatorProvider, config.watcherConfig, config.settlementConfig, setup.walletContractTimelocks);
|
|
924
898
|
await wallet.getVtxoManager();
|
|
925
899
|
return wallet;
|
|
926
900
|
}
|
|
@@ -946,7 +920,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
946
920
|
const readonlyIdentity = hasToReadonly(this.identity)
|
|
947
921
|
? await this.identity.toReadonly()
|
|
948
922
|
: this.identity; // Identity extends ReadonlyIdentity, so this is safe
|
|
949
|
-
return new ReadonlyWallet(readonlyIdentity, this.network, this.onchainProvider, this.indexerProvider, this.arkServerPublicKey, this.offchainTapscript, this.boardingTapscript, this.dustAmount, this.walletRepository, this.contractRepository, this.delegatorProvider, this.watcherConfig);
|
|
923
|
+
return new ReadonlyWallet(readonlyIdentity, this.network, this.onchainProvider, this.indexerProvider, this.arkServerPublicKey, this.offchainTapscript, this.boardingTapscript, this.dustAmount, this.walletRepository, this.contractRepository, this.delegatorProvider, this.watcherConfig, this.walletContractTimelocks);
|
|
950
924
|
}
|
|
951
925
|
/** Returns the delegator manager when delegation support is configured. */
|
|
952
926
|
async getDelegatorManager() {
|
|
@@ -1077,10 +1051,10 @@ class Wallet extends ReadonlyWallet {
|
|
|
1077
1051
|
weight: 0,
|
|
1078
1052
|
birth: vtxo.createdAt,
|
|
1079
1053
|
expiry: vtxo.virtualStatus.batchExpiry
|
|
1080
|
-
? new Date(vtxo.virtualStatus.batchExpiry
|
|
1081
|
-
:
|
|
1054
|
+
? new Date(vtxo.virtualStatus.batchExpiry)
|
|
1055
|
+
: undefined,
|
|
1082
1056
|
});
|
|
1083
|
-
if (inputFee.
|
|
1057
|
+
if (inputFee.satoshis >= vtxo.value) {
|
|
1084
1058
|
// skip if fees are greater than the virtual output value
|
|
1085
1059
|
continue;
|
|
1086
1060
|
}
|