@arkade-os/sdk 0.4.14 → 0.4.16
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 +287 -215
- package/dist/cjs/arkfee/estimator.js +1 -1
- package/dist/cjs/arkfee/types.js +2 -1
- package/dist/cjs/arknote/index.js +43 -4
- package/dist/cjs/bip322/index.js +1 -1
- package/dist/cjs/contracts/arkcontract.js +1 -1
- package/dist/cjs/contracts/contractManager.js +40 -24
- package/dist/cjs/contracts/contractWatcher.js +29 -22
- package/dist/cjs/contracts/handlers/default.js +1 -1
- package/dist/cjs/contracts/handlers/delegate.js +1 -1
- package/dist/cjs/contracts/handlers/helpers.js +25 -1
- package/dist/cjs/contracts/handlers/vhtlc.js +2 -4
- package/dist/cjs/extension/asset/assetGroup.js +92 -5
- package/dist/cjs/extension/asset/assetId.js +67 -3
- package/dist/cjs/extension/asset/assetInput.js +18 -0
- package/dist/cjs/extension/asset/assetOutput.js +15 -0
- package/dist/cjs/extension/asset/assetRef.js +66 -0
- package/dist/cjs/extension/asset/metadata.js +15 -0
- package/dist/cjs/extension/asset/packet.js +4 -1
- package/dist/cjs/extension/index.js +1 -1
- package/dist/cjs/forfeit.js +14 -0
- package/dist/cjs/identity/index.js +6 -0
- package/dist/cjs/identity/seedIdentity.js +5 -5
- package/dist/cjs/identity/singleKey.js +4 -0
- package/dist/cjs/index.js +5 -3
- package/dist/cjs/intent/index.js +28 -12
- package/dist/cjs/providers/ark.js +3 -2
- package/dist/cjs/providers/delegator.js +20 -1
- package/dist/cjs/providers/expoArk.js +2 -2
- package/dist/cjs/providers/indexer.js +2 -2
- package/dist/cjs/providers/onchain.js +2 -1
- package/dist/cjs/repositories/realm/schemas.js +2 -2
- package/dist/cjs/repositories/realm/types.js +1 -1
- package/dist/cjs/script/address.js +37 -6
- package/dist/cjs/script/base.js +70 -1
- package/dist/cjs/script/default.js +3 -0
- package/dist/cjs/script/delegate.js +4 -0
- package/dist/cjs/script/tapscript.js +25 -4
- package/dist/cjs/script/vhtlc.js +35 -27
- package/dist/cjs/storage/fileSystem.js +1 -1
- package/dist/cjs/storage/inMemory.js +1 -1
- package/dist/cjs/storage/indexedDB.js +1 -1
- package/dist/cjs/storage/localStorage.js +1 -1
- package/dist/cjs/tree/validation.js +1 -1
- package/dist/cjs/utils/arkTransaction.js +5 -5
- package/dist/cjs/utils/bip21.js +16 -3
- package/dist/cjs/utils/syncCursors.js +4 -4
- package/dist/cjs/utils/transaction.js +1 -1
- package/dist/cjs/utils/transactionHistory.js +11 -11
- package/dist/cjs/utils/unknownFields.js +3 -3
- package/dist/cjs/wallet/asset-manager.js +4 -4
- package/dist/cjs/wallet/batch.js +5 -5
- package/dist/cjs/wallet/delegator.js +9 -8
- package/dist/cjs/wallet/expo/background.js +3 -3
- package/dist/cjs/wallet/expo/wallet.js +7 -7
- package/dist/cjs/wallet/index.js +43 -0
- package/dist/cjs/wallet/onchain.js +43 -5
- package/dist/cjs/wallet/ramps.js +44 -14
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +22 -22
- package/dist/cjs/wallet/serviceWorker/wallet.js +28 -24
- package/dist/cjs/wallet/unroll.js +12 -8
- package/dist/cjs/wallet/utils.js +1 -1
- package/dist/cjs/wallet/vtxo-manager.js +123 -82
- package/dist/cjs/wallet/wallet.js +231 -98
- package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +1 -1
- package/dist/cjs/worker/expo/processors/contractPollProcessor.js +2 -2
- package/dist/cjs/worker/expo/taskRunner.js +3 -3
- package/dist/cjs/worker/messageBus.js +3 -0
- package/dist/esm/arkfee/estimator.js +1 -1
- package/dist/esm/arkfee/types.js +2 -1
- package/dist/esm/arknote/index.js +43 -4
- package/dist/esm/bip322/index.js +1 -1
- package/dist/esm/contracts/arkcontract.js +1 -1
- package/dist/esm/contracts/contractManager.js +40 -24
- package/dist/esm/contracts/contractWatcher.js +29 -22
- package/dist/esm/contracts/handlers/default.js +1 -1
- package/dist/esm/contracts/handlers/delegate.js +1 -1
- package/dist/esm/contracts/handlers/helpers.js +24 -1
- package/dist/esm/contracts/handlers/vhtlc.js +3 -5
- package/dist/esm/extension/asset/assetGroup.js +92 -5
- package/dist/esm/extension/asset/assetId.js +67 -3
- package/dist/esm/extension/asset/assetInput.js +18 -0
- package/dist/esm/extension/asset/assetOutput.js +15 -0
- package/dist/esm/extension/asset/assetRef.js +66 -0
- package/dist/esm/extension/asset/metadata.js +15 -0
- package/dist/esm/extension/asset/packet.js +4 -1
- package/dist/esm/extension/index.js +1 -1
- package/dist/esm/forfeit.js +14 -0
- package/dist/esm/identity/index.js +5 -0
- package/dist/esm/identity/seedIdentity.js +5 -5
- package/dist/esm/identity/singleKey.js +4 -0
- package/dist/esm/index.js +3 -2
- package/dist/esm/intent/index.js +28 -12
- package/dist/esm/providers/ark.js +3 -2
- package/dist/esm/providers/delegator.js +20 -1
- package/dist/esm/providers/expoArk.js +2 -2
- package/dist/esm/providers/indexer.js +2 -2
- package/dist/esm/providers/onchain.js +2 -1
- package/dist/esm/repositories/realm/schemas.js +2 -2
- package/dist/esm/repositories/realm/types.js +1 -1
- package/dist/esm/script/address.js +37 -6
- package/dist/esm/script/base.js +70 -1
- package/dist/esm/script/default.js +3 -0
- package/dist/esm/script/delegate.js +4 -0
- package/dist/esm/script/tapscript.js +25 -4
- package/dist/esm/script/vhtlc.js +35 -27
- package/dist/esm/storage/fileSystem.js +1 -1
- package/dist/esm/storage/inMemory.js +1 -1
- package/dist/esm/storage/indexedDB.js +1 -1
- package/dist/esm/storage/localStorage.js +1 -1
- package/dist/esm/tree/validation.js +1 -1
- package/dist/esm/utils/arkTransaction.js +5 -5
- package/dist/esm/utils/bip21.js +16 -3
- package/dist/esm/utils/syncCursors.js +4 -4
- package/dist/esm/utils/transaction.js +1 -1
- package/dist/esm/utils/transactionHistory.js +11 -11
- package/dist/esm/utils/unknownFields.js +3 -3
- package/dist/esm/wallet/asset-manager.js +4 -4
- package/dist/esm/wallet/batch.js +5 -5
- package/dist/esm/wallet/delegator.js +9 -8
- package/dist/esm/wallet/expo/background.js +3 -3
- package/dist/esm/wallet/expo/wallet.js +7 -7
- package/dist/esm/wallet/index.js +43 -0
- package/dist/esm/wallet/onchain.js +43 -5
- package/dist/esm/wallet/ramps.js +44 -14
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +22 -22
- package/dist/esm/wallet/serviceWorker/wallet.js +28 -24
- package/dist/esm/wallet/unroll.js +12 -8
- package/dist/esm/wallet/utils.js +1 -1
- package/dist/esm/wallet/vtxo-manager.js +122 -81
- package/dist/esm/wallet/wallet.js +232 -99
- package/dist/esm/worker/expo/asyncStorageTaskQueue.js +1 -1
- package/dist/esm/worker/expo/processors/contractPollProcessor.js +2 -2
- package/dist/esm/worker/expo/taskRunner.js +3 -3
- package/dist/esm/worker/messageBus.js +3 -0
- package/dist/types/arkfee/estimator.d.ts +1 -1
- package/dist/types/arkfee/types.d.ts +2 -1
- package/dist/types/arknote/index.d.ts +44 -4
- package/dist/types/bip322/index.d.ts +1 -1
- package/dist/types/contracts/arkcontract.d.ts +1 -1
- package/dist/types/contracts/contractManager.d.ts +40 -63
- package/dist/types/contracts/contractWatcher.d.ts +39 -18
- package/dist/types/contracts/handlers/default.d.ts +1 -1
- package/dist/types/contracts/handlers/delegate.d.ts +1 -1
- package/dist/types/contracts/handlers/helpers.d.ts +11 -1
- package/dist/types/contracts/types.d.ts +36 -26
- package/dist/types/extension/asset/assetGroup.d.ts +92 -1
- package/dist/types/extension/asset/assetId.d.ts +67 -3
- package/dist/types/extension/asset/assetInput.d.ts +18 -0
- package/dist/types/extension/asset/assetOutput.d.ts +15 -0
- package/dist/types/extension/asset/assetRef.d.ts +66 -0
- package/dist/types/extension/asset/metadata.d.ts +15 -0
- package/dist/types/extension/asset/packet.d.ts +4 -1
- package/dist/types/extension/index.d.ts +1 -1
- package/dist/types/forfeit.d.ts +14 -0
- package/dist/types/identity/index.d.ts +36 -0
- package/dist/types/identity/seedIdentity.d.ts +10 -8
- package/dist/types/identity/singleKey.d.ts +4 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/intent/index.d.ts +19 -6
- package/dist/types/providers/ark.d.ts +40 -2
- package/dist/types/providers/delegator.d.ts +54 -1
- package/dist/types/providers/expoArk.d.ts +2 -2
- package/dist/types/providers/indexer.d.ts +105 -2
- package/dist/types/providers/onchain.d.ts +62 -1
- package/dist/types/repositories/realm/schemas.d.ts +2 -2
- package/dist/types/repositories/realm/types.d.ts +2 -2
- package/dist/types/repositories/walletRepository.d.ts +16 -0
- package/dist/types/script/address.d.ts +35 -2
- package/dist/types/script/base.d.ts +66 -1
- package/dist/types/script/default.d.ts +3 -0
- package/dist/types/script/delegate.d.ts +4 -0
- package/dist/types/script/tapscript.d.ts +17 -2
- package/dist/types/script/vhtlc.d.ts +35 -27
- package/dist/types/storage/fileSystem.d.ts +1 -1
- package/dist/types/storage/inMemory.d.ts +1 -1
- package/dist/types/storage/index.d.ts +1 -1
- package/dist/types/storage/indexedDB.d.ts +1 -1
- package/dist/types/storage/localStorage.d.ts +1 -1
- package/dist/types/utils/arkTransaction.d.ts +3 -3
- package/dist/types/utils/bip21.d.ts +17 -0
- package/dist/types/utils/syncCursors.d.ts +4 -4
- package/dist/types/utils/transaction.d.ts +1 -1
- package/dist/types/utils/transactionHistory.d.ts +3 -3
- package/dist/types/utils/unknownFields.d.ts +5 -5
- package/dist/types/wallet/asset-manager.d.ts +3 -3
- package/dist/types/wallet/batch.d.ts +27 -7
- package/dist/types/wallet/delegator.d.ts +10 -0
- package/dist/types/wallet/expo/background.d.ts +4 -4
- package/dist/types/wallet/expo/wallet.d.ts +10 -10
- package/dist/types/wallet/index.d.ts +457 -25
- package/dist/types/wallet/onchain.d.ts +42 -4
- package/dist/types/wallet/ramps.d.ts +40 -10
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +4 -4
- package/dist/types/wallet/serviceWorker/wallet.d.ts +71 -33
- package/dist/types/wallet/unroll.d.ts +8 -6
- package/dist/types/wallet/vtxo-manager.d.ts +146 -93
- package/dist/types/wallet/wallet.d.ts +91 -33
- package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +1 -1
- package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +1 -1
- package/dist/types/worker/expo/taskRunner.d.ts +6 -6
- package/dist/types/worker/messageBus.d.ts +5 -3
- package/package.json +18 -10
|
@@ -2,7 +2,7 @@ import * as bip68 from "bip68";
|
|
|
2
2
|
import { RawWitness, ScriptNum } from "@scure/btc-signer";
|
|
3
3
|
import { hex } from "@scure/base";
|
|
4
4
|
/**
|
|
5
|
-
* ArkPsbtFieldKey
|
|
5
|
+
* ArkPsbtFieldKey are the available key names for the Arkade PSBT custom fields.
|
|
6
6
|
*/
|
|
7
7
|
export var ArkPsbtFieldKey;
|
|
8
8
|
(function (ArkPsbtFieldKey) {
|
|
@@ -12,8 +12,8 @@ export var ArkPsbtFieldKey;
|
|
|
12
12
|
ArkPsbtFieldKey["ConditionWitness"] = "condition";
|
|
13
13
|
})(ArkPsbtFieldKey || (ArkPsbtFieldKey = {}));
|
|
14
14
|
/**
|
|
15
|
-
* ArkPsbtFieldKeyType is the type of the
|
|
16
|
-
* Every
|
|
15
|
+
* ArkPsbtFieldKeyType is the key type of the Arkade PSBT custom field.
|
|
16
|
+
* Every Arkade PSBT field has key type 222.
|
|
17
17
|
*/
|
|
18
18
|
export const ArkPsbtFieldKeyType = 222;
|
|
19
19
|
/**
|
|
@@ -23,7 +23,7 @@ export class AssetManager extends ReadonlyAssetManager {
|
|
|
23
23
|
* @param params.amount - Amount of asset units to issue
|
|
24
24
|
* @param params.controlAssetId - Optional control asset ID (for reissuable assets)
|
|
25
25
|
* @param params.metadata - Optional metadata to attach to the asset
|
|
26
|
-
* @returns Promise resolving to the
|
|
26
|
+
* @returns Promise resolving to the Arkade transaction ID and asset ID
|
|
27
27
|
*
|
|
28
28
|
* @example
|
|
29
29
|
* ```typescript
|
|
@@ -108,7 +108,7 @@ export class AssetManager extends ReadonlyAssetManager {
|
|
|
108
108
|
* @param params - Parameters for asset reissuance
|
|
109
109
|
* @param params.assetId - The asset ID to reissue (control asset ID is resolved via getAssetDetails)
|
|
110
110
|
* @param params.amount - Amount of additional units to issue
|
|
111
|
-
* @returns Promise resolving to the
|
|
111
|
+
* @returns Promise resolving to the Arkade transaction ID
|
|
112
112
|
*
|
|
113
113
|
* @example
|
|
114
114
|
* ```typescript
|
|
@@ -215,7 +215,7 @@ export class AssetManager extends ReadonlyAssetManager {
|
|
|
215
215
|
* @param params - Parameters for burning
|
|
216
216
|
* @param params.assetId - The asset ID to burn
|
|
217
217
|
* @param params.amount - Amount of units to burn
|
|
218
|
-
* @returns Promise resolving to the
|
|
218
|
+
* @returns Promise resolving to the Arkade transaction ID
|
|
219
219
|
*
|
|
220
220
|
* @example
|
|
221
221
|
* ```typescript
|
|
@@ -233,7 +233,7 @@ export class AssetManager extends ReadonlyAssetManager {
|
|
|
233
233
|
withRecoverable: false,
|
|
234
234
|
});
|
|
235
235
|
const assetChanges = new Map();
|
|
236
|
-
// select
|
|
236
|
+
// select virtual outputs with the asset to burn
|
|
237
237
|
const { selected: assetCoins } = selectCoinsWithAsset(virtualCoins, params.assetId, BigInt(params.amount));
|
|
238
238
|
const selectedCoins = [...assetCoins];
|
|
239
239
|
let totalBtcSelected = 0;
|
package/dist/esm/wallet/batch.js
CHANGED
|
@@ -11,7 +11,7 @@ import { hex } from "@scure/base";
|
|
|
11
11
|
* const handler = wallet.createBatchHandler(intentId, inputs, expectedRecipients, musig2session);
|
|
12
12
|
*
|
|
13
13
|
* const abortController = new AbortController();
|
|
14
|
-
* // Get event stream from
|
|
14
|
+
* // Get event stream from the Arkade provider
|
|
15
15
|
* const eventStream = arkProvider.getEventStream(
|
|
16
16
|
* abortController.signal,
|
|
17
17
|
* ['your-topic-1', 'your-topic-2']
|
|
@@ -96,7 +96,7 @@ export var Batch;
|
|
|
96
96
|
step !== Step.TreeNoncesAggregated) {
|
|
97
97
|
continue;
|
|
98
98
|
}
|
|
99
|
-
// batchIndex 0 =
|
|
99
|
+
// batchIndex 0 = virtual output tree, batchIndex 1 = connector tree
|
|
100
100
|
if (event.batchIndex === 0) {
|
|
101
101
|
flatVtxoTree.push(event.chunk);
|
|
102
102
|
}
|
|
@@ -115,7 +115,7 @@ export var Batch;
|
|
|
115
115
|
if (!vtxoTree) {
|
|
116
116
|
throw new Error("vtxo tree not initialized");
|
|
117
117
|
}
|
|
118
|
-
// push signature to the
|
|
118
|
+
// push signature to the virtual output tree
|
|
119
119
|
const tapKeySig = hex.decode(event.signature);
|
|
120
120
|
vtxoTree.update(event.txid, (tx) => {
|
|
121
121
|
tx.updateInput(0, {
|
|
@@ -131,7 +131,7 @@ export var Batch;
|
|
|
131
131
|
if (step !== Step.BatchStarted) {
|
|
132
132
|
continue;
|
|
133
133
|
}
|
|
134
|
-
// create
|
|
134
|
+
// create virtual output tree from collected chunks
|
|
135
135
|
vtxoTree = TxTree.create(flatVtxoTree);
|
|
136
136
|
const { skip } = await handler.onTreeSigningStarted(event, vtxoTree);
|
|
137
137
|
if (!skip) {
|
|
@@ -153,7 +153,7 @@ export var Batch;
|
|
|
153
153
|
if (step !== Step.TreeNoncesAggregated) {
|
|
154
154
|
continue;
|
|
155
155
|
}
|
|
156
|
-
// Build
|
|
156
|
+
// Build virtual output tree if it hasn't been built yet
|
|
157
157
|
if (!vtxoTree && flatVtxoTree.length > 0) {
|
|
158
158
|
vtxoTree = TxTree.create(flatVtxoTree);
|
|
159
159
|
}
|
|
@@ -8,6 +8,7 @@ import { getNetwork } from '../networks.js';
|
|
|
8
8
|
import { createAssetPacket } from './asset.js';
|
|
9
9
|
import { Extension } from '../extension/index.js';
|
|
10
10
|
export class DelegatorManagerImpl {
|
|
11
|
+
/** Create a delegator manager from the configured provider, Arkade info source, and wallet identity. */
|
|
11
12
|
constructor(delegatorProvider, arkInfoProvider, identity) {
|
|
12
13
|
this.delegatorProvider = delegatorProvider;
|
|
13
14
|
this.arkInfoProvider = arkInfoProvider;
|
|
@@ -24,7 +25,7 @@ export class DelegatorManagerImpl {
|
|
|
24
25
|
// fetch server and delegator info once, shared across all groups
|
|
25
26
|
const arkInfo = await this.arkInfoProvider.getInfo();
|
|
26
27
|
const delegateInfo = await this.delegatorProvider.getDelegateInfo();
|
|
27
|
-
// if explicit delegateAt is provided, delegate all
|
|
28
|
+
// if explicit delegateAt is provided, delegate all virtual outputs at once without sorting
|
|
28
29
|
if (delegateAt) {
|
|
29
30
|
try {
|
|
30
31
|
await delegate(this.identity, this.delegatorProvider, arkInfo, delegateInfo, vtxos, destinationScript, delegateAt);
|
|
@@ -34,7 +35,7 @@ export class DelegatorManagerImpl {
|
|
|
34
35
|
}
|
|
35
36
|
return { delegated: vtxos, failed: [] };
|
|
36
37
|
}
|
|
37
|
-
// if no explicit delegateAt is provided, sort
|
|
38
|
+
// if no explicit delegateAt is provided, sort virtual outputs by expiry and delegate in groups of the same expiry day
|
|
38
39
|
const groupByExpiry = new Map();
|
|
39
40
|
let recoverableVtxos = [];
|
|
40
41
|
for (const vtxo of vtxos) {
|
|
@@ -51,7 +52,7 @@ export class DelegatorManagerImpl {
|
|
|
51
52
|
vtxo,
|
|
52
53
|
]);
|
|
53
54
|
}
|
|
54
|
-
// if no groups, it means we only need to delegate the recoverable
|
|
55
|
+
// if no groups, it means we only need to delegate the recoverable virtual outputs
|
|
55
56
|
if (groupByExpiry.size === 0) {
|
|
56
57
|
try {
|
|
57
58
|
await delegate(this.identity, this.delegatorProvider, arkInfo, delegateInfo, recoverableVtxos, destinationScript, delegateAt);
|
|
@@ -64,7 +65,7 @@ export class DelegatorManagerImpl {
|
|
|
64
65
|
}
|
|
65
66
|
return { delegated: recoverableVtxos, failed: [] };
|
|
66
67
|
}
|
|
67
|
-
// search for the earliest group, include recoverable
|
|
68
|
+
// search for the earliest group, include recoverable virtual outputs into it
|
|
68
69
|
const earliestGroup = Math.min(...groupByExpiry.keys());
|
|
69
70
|
groupByExpiry.set(earliestGroup, [
|
|
70
71
|
...(groupByExpiry.get(earliestGroup) ?? []),
|
|
@@ -86,9 +87,9 @@ export class DelegatorManagerImpl {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
/**
|
|
89
|
-
* Delegates virtual
|
|
90
|
-
* on behalf of the wallet.
|
|
91
|
-
* @param vtxos - Array of extended virtual
|
|
90
|
+
* Delegates virtual outputs to a delegation service, allowing them to manage their renewal
|
|
91
|
+
* on behalf of the wallet owner.
|
|
92
|
+
* @param vtxos - Array of extended virtual outputs to delegate. Must not be empty.
|
|
92
93
|
* @param delegateAt - Optional Date specifying when the delegation
|
|
93
94
|
* should occur. If not provided, defaults to 12 hours before the earliest
|
|
94
95
|
* expiry time of the provided vtxos.
|
|
@@ -105,7 +106,7 @@ async function delegate(identity, delegatorProvider, arkInfo, delegateInfo, vtxo
|
|
|
105
106
|
.filter((coin) => !isRecoverable(coin) && coin.virtualStatus.batchExpiry)
|
|
106
107
|
.reduce((min, coin) => Math.min(min, coin.virtualStatus.batchExpiry), Number.MAX_SAFE_INTEGER);
|
|
107
108
|
if (!expiryTimestamp || expiryTimestamp === Number.MAX_SAFE_INTEGER) {
|
|
108
|
-
// if no expiry (recoverable
|
|
109
|
+
// if no expiry (recoverable virtual outputs), delegate 1 minute from now
|
|
109
110
|
delegateAt = new Date(Date.now() + 1 * 60 * 1000);
|
|
110
111
|
}
|
|
111
112
|
else {
|
|
@@ -60,7 +60,7 @@ export function defineExpoBackgroundTask(taskName, options) {
|
|
|
60
60
|
const indexerProvider = new ExpoIndexerProvider(config.arkServerUrl);
|
|
61
61
|
const arkProvider = new ExpoArkProvider(config.arkServerUrl);
|
|
62
62
|
// Reconstruct default offchainTapscript as fallback
|
|
63
|
-
// for
|
|
63
|
+
// for virtual outputs not associated with a contract.
|
|
64
64
|
const offchainTapscript = new DefaultVtxo.Script({
|
|
65
65
|
pubKey: hex.decode(config.pubkeyHex),
|
|
66
66
|
serverPubKey: hex.decode(config.serverPubKeyHex),
|
|
@@ -104,8 +104,8 @@ export function defineExpoBackgroundTask(taskName, options) {
|
|
|
104
104
|
/**
|
|
105
105
|
* Activate the OS-level background task scheduler.
|
|
106
106
|
*
|
|
107
|
-
* Call this after
|
|
108
|
-
*
|
|
107
|
+
* Call this after @see defineExpoBackgroundTask (typically inside
|
|
108
|
+
* @see ExpoWallet.setup or in a React component after wallet init).
|
|
109
109
|
*
|
|
110
110
|
* @param minimumInterval - Minimum interval in minutes (default 15).
|
|
111
111
|
*/
|
|
@@ -8,7 +8,7 @@ import { DefaultVtxo } from '../../script/default.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* Expo/React Native wallet with built-in background task processing.
|
|
10
10
|
*
|
|
11
|
-
* Wraps a standard
|
|
11
|
+
* Wraps a standard @see Wallet and adds a lightweight task queue
|
|
12
12
|
* for keeping contract/VTXO state fresh while the app is active and
|
|
13
13
|
* across Expo BackgroundTask wakes.
|
|
14
14
|
*
|
|
@@ -18,10 +18,10 @@ import { DefaultVtxo } from '../../script/default.js';
|
|
|
18
18
|
* import { AsyncStorageTaskQueue } from "@arkade-os/sdk/worker/expo";
|
|
19
19
|
*
|
|
20
20
|
* const wallet = await ExpoWallet.setup({
|
|
21
|
-
* identity:
|
|
22
|
-
* arkServerUrl,
|
|
23
|
-
* esploraUrl,
|
|
24
|
-
* storage: {
|
|
21
|
+
* identity: MnemonicIdentity.fromMnemonic('abandon abandon...'),
|
|
22
|
+
* arkServerUrl: 'https://arkade.computer',
|
|
23
|
+
* esploraUrl: 'https://mempool.space/api',
|
|
24
|
+
* storage: { ... },
|
|
25
25
|
* background: {
|
|
26
26
|
* taskName: "ark-background-poll",
|
|
27
27
|
* taskQueue: new AsyncStorageTaskQueue(AsyncStorage),
|
|
@@ -50,8 +50,8 @@ export class ExpoWallet {
|
|
|
50
50
|
/**
|
|
51
51
|
* Create an ExpoWallet with background task support.
|
|
52
52
|
*
|
|
53
|
-
* 1. Creates the inner
|
|
54
|
-
* 2. Wires up processors (defaults to
|
|
53
|
+
* 1. Creates the inner @see Wallet via `Wallet.create()`.
|
|
54
|
+
* 2. Wires up processors (defaults to @see contractPollProcessor).
|
|
55
55
|
* 3. Persists background config for the background handler (if the queue supports it).
|
|
56
56
|
* 4. Seeds the task queue with a `contract-poll` task.
|
|
57
57
|
* 5. Registers the background task with the OS scheduler (if `minimumBackgroundInterval` is set).
|
package/dist/esm/wallet/index.js
CHANGED
|
@@ -1,14 +1,48 @@
|
|
|
1
|
+
/** Wallet transaction direction. */
|
|
1
2
|
export var TxType;
|
|
2
3
|
(function (TxType) {
|
|
3
4
|
TxType["TxSent"] = "SENT";
|
|
4
5
|
TxType["TxReceived"] = "RECEIVED";
|
|
5
6
|
})(TxType || (TxType = {}));
|
|
7
|
+
/**
|
|
8
|
+
* Return whether a virtual output is still spendable.
|
|
9
|
+
*
|
|
10
|
+
* @param vtxo - virtual output to inspect
|
|
11
|
+
* @returns `true` when the virtual output is not marked as spent
|
|
12
|
+
*
|
|
13
|
+
* @see isRecoverable
|
|
14
|
+
* @see isExpired
|
|
15
|
+
*/
|
|
6
16
|
export function isSpendable(vtxo) {
|
|
7
17
|
return !vtxo.isSpent;
|
|
8
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Return whether a virtual output is recoverable.
|
|
21
|
+
*
|
|
22
|
+
* @param vtxo - virtual output to inspect
|
|
23
|
+
* @returns `true` when the virtual output is swept but still spendable
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* Recoverable virtual outputs are typically re-settled into fresh virtual outputs by the virtual output manager.
|
|
27
|
+
*
|
|
28
|
+
* @see isSpendable
|
|
29
|
+
* @see isExpired
|
|
30
|
+
*/
|
|
9
31
|
export function isRecoverable(vtxo) {
|
|
10
32
|
return vtxo.virtualStatus.state === "swept" && isSpendable(vtxo);
|
|
11
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Return whether a virtual output should be treated as expired.
|
|
36
|
+
*
|
|
37
|
+
* @param vtxo - virtual output to inspect
|
|
38
|
+
* @returns `true` when the virtual output is swept or its batch expiry has passed
|
|
39
|
+
* @remarks
|
|
40
|
+
* On regtest-like environments the upstream expiry value may be expressed as a block
|
|
41
|
+
* height instead of a timestamp. This helper intentionally ignores obviously non-time
|
|
42
|
+
* values to avoid false positives.
|
|
43
|
+
*
|
|
44
|
+
* @see VirtualStatus.batchExpiry
|
|
45
|
+
*/
|
|
12
46
|
export function isExpired(vtxo) {
|
|
13
47
|
if (vtxo.virtualStatus.state === "swept")
|
|
14
48
|
return true; // swept by server = expired
|
|
@@ -23,6 +57,15 @@ export function isExpired(vtxo) {
|
|
|
23
57
|
return false;
|
|
24
58
|
return expiry <= Date.now();
|
|
25
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Return whether a virtual output is below the dust threshold.
|
|
62
|
+
*
|
|
63
|
+
* @param vtxo - virtual output to inspect
|
|
64
|
+
* @param dust - dust threshold in satoshis
|
|
65
|
+
* @returns `true` when the virtual output value is below `dust`
|
|
66
|
+
*
|
|
67
|
+
* @see isRecoverable
|
|
68
|
+
*/
|
|
26
69
|
export function isSubdust(vtxo, dust) {
|
|
27
70
|
return vtxo.value < dust;
|
|
28
71
|
}
|
|
@@ -9,7 +9,7 @@ import { DUST_AMOUNT } from './utils.js';
|
|
|
9
9
|
* Onchain Bitcoin wallet implementation for traditional Bitcoin transactions.
|
|
10
10
|
*
|
|
11
11
|
* This wallet handles regular Bitcoin transactions on the blockchain without
|
|
12
|
-
* using the
|
|
12
|
+
* using the Arkade protocol. It supports P2TR (Pay-to-Taproot) addresses and
|
|
13
13
|
* provides basic Bitcoin wallet functionality.
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
@@ -29,6 +29,16 @@ export class OnchainWallet {
|
|
|
29
29
|
this.onchainP2TR = onchainP2TR;
|
|
30
30
|
this.provider = provider;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Create an onchain wallet for the given identity and Bitcoin network.
|
|
34
|
+
*
|
|
35
|
+
* @param identity - Identity used to derive the Taproot key and sign transactions
|
|
36
|
+
* @param networkName - Bitcoin network name, @see NetworkName
|
|
37
|
+
* @param provider - Optional onchain provider override, @see OnchainProvider
|
|
38
|
+
* @returns Configured onchain wallet
|
|
39
|
+
* @defaultValue `provider = new EsploraProvider('https://mempool.space/api')`
|
|
40
|
+
* @throws Error if the configured identity cannot produce a valid x-only public key
|
|
41
|
+
*/
|
|
32
42
|
static async create(identity, networkName, provider) {
|
|
33
43
|
const pubkey = await identity.xOnlyPublicKey();
|
|
34
44
|
if (!pubkey) {
|
|
@@ -42,9 +52,21 @@ export class OnchainWallet {
|
|
|
42
52
|
get address() {
|
|
43
53
|
return this.onchainP2TR.address || "";
|
|
44
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Fetch spendable onchain outputs for the wallet address.
|
|
57
|
+
*
|
|
58
|
+
* @returns Spendable onchain outputs for the wallet address
|
|
59
|
+
* @see getBalance
|
|
60
|
+
*/
|
|
45
61
|
async getCoins() {
|
|
46
62
|
return this.provider.getCoins(this.address);
|
|
47
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Return the wallet's total onchain balance in satoshis.
|
|
66
|
+
*
|
|
67
|
+
* @returns Confirmed plus unconfirmed onchain balance
|
|
68
|
+
* @see getCoins
|
|
69
|
+
*/
|
|
48
70
|
async getBalance() {
|
|
49
71
|
const coins = await this.getCoins();
|
|
50
72
|
const onchainConfirmed = coins
|
|
@@ -59,9 +81,9 @@ export class OnchainWallet {
|
|
|
59
81
|
/**
|
|
60
82
|
* Iteratively selects coins and estimates transaction fees until convergence.
|
|
61
83
|
*
|
|
62
|
-
* This method handles the circular dependency between
|
|
84
|
+
* This method handles the circular dependency between output selection and fee
|
|
63
85
|
* estimation: the fee depends on transaction size, which depends on the number
|
|
64
|
-
* of inputs (selected
|
|
86
|
+
* of inputs (selected outputs) and whether a change output is needed.
|
|
65
87
|
*
|
|
66
88
|
* The algorithm iterates up to 10 times, refining the fee estimate based on
|
|
67
89
|
* the actual transaction structure. It resolves dust oscillation loops that
|
|
@@ -70,7 +92,7 @@ export class OnchainWallet {
|
|
|
70
92
|
* When a lower fee is computed (indicating the change output was dropped),
|
|
71
93
|
* the function accepts this state to guarantee termination.
|
|
72
94
|
*
|
|
73
|
-
* @param coins - Available
|
|
95
|
+
* @param coins - Available onchain outputs to select from
|
|
74
96
|
* @param amount - Target send amount in satoshis
|
|
75
97
|
* @param feeRate - Fee rate in sat/vbyte
|
|
76
98
|
* @param recipientAddress - Destination address for size estimation
|
|
@@ -103,6 +125,14 @@ export class OnchainWallet {
|
|
|
103
125
|
}
|
|
104
126
|
throw new Error("Fee estimation failed: could not converge");
|
|
105
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Send bitcoin to a single onchain address.
|
|
130
|
+
*
|
|
131
|
+
* @param params - destination `address`, `amount` (in satoshis), and optional `feeRate` override (other fields ignored)
|
|
132
|
+
* @returns Broadcast transaction id
|
|
133
|
+
* @throws Error if the amount is non-positive, below dust, or cannot be funded
|
|
134
|
+
* @see SendBitcoinParams
|
|
135
|
+
*/
|
|
106
136
|
async send(params) {
|
|
107
137
|
if (params.amount <= 0) {
|
|
108
138
|
throw new Error("Amount must be positive");
|
|
@@ -148,6 +178,14 @@ export class OnchainWallet {
|
|
|
148
178
|
const txid = await this.provider.broadcastTransaction(tx.hex);
|
|
149
179
|
return txid;
|
|
150
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* CPFP-bump a parent transaction that contains a pay-to-anchor output.
|
|
183
|
+
*
|
|
184
|
+
* @param parent - Parent transaction containing a pay-to-anchor output
|
|
185
|
+
* @returns Tuple of parent transaction id and child transaction id
|
|
186
|
+
* @throws Error if the parent transaction has no pay-to-anchor output or bumping cannot be funded
|
|
187
|
+
* @see send
|
|
188
|
+
*/
|
|
151
189
|
async bumpP2A(parent) {
|
|
152
190
|
const parentVsize = parent.vsize;
|
|
153
191
|
let child = new Transaction({
|
|
@@ -169,7 +207,7 @@ export class OnchainWallet {
|
|
|
169
207
|
if (!fee) {
|
|
170
208
|
throw new Error(`invalid fee, got ${fee} with vsize ${packageVSize}, feeRate ${feeRate}`);
|
|
171
209
|
}
|
|
172
|
-
// Select
|
|
210
|
+
// Select onchain outputs
|
|
173
211
|
const coins = await this.getCoins();
|
|
174
212
|
const selected = selectCoins(coins, fee, true);
|
|
175
213
|
for (const input of selected.inputs) {
|
package/dist/esm/wallet/ramps.js
CHANGED
|
@@ -4,30 +4,50 @@ import { hex } from "@scure/base";
|
|
|
4
4
|
import { networks } from '../networks.js';
|
|
5
5
|
import { ArkAddress } from '../script/address.js';
|
|
6
6
|
/**
|
|
7
|
-
* Ramps is a class wrapping
|
|
7
|
+
* Ramps is a class wrapping `settle` method to provide a more convenient interface for onboarding and offboarding operations.
|
|
8
|
+
*
|
|
9
|
+
* @see IWallet.settle
|
|
10
|
+
* @see onboard
|
|
11
|
+
* @see offboard
|
|
8
12
|
*
|
|
9
13
|
* @example
|
|
10
14
|
* ```typescript
|
|
11
15
|
* const ramps = new Ramps(wallet);
|
|
12
|
-
*
|
|
13
|
-
* await ramps.
|
|
16
|
+
* const feeInfo = { intentFee: {}, txFeeRate: '1' };
|
|
17
|
+
* await ramps.onboard(feeInfo); // onboard all boarding inputs
|
|
18
|
+
* await ramps.offboard('bc1q...', feeInfo); // collaboratively exit all virtual outputs to an onchain address
|
|
14
19
|
* ```
|
|
15
20
|
*/
|
|
16
21
|
export class Ramps {
|
|
22
|
+
/**
|
|
23
|
+
* Create convenience wrappers for onboarding and offboarding flows.
|
|
24
|
+
*
|
|
25
|
+
* @param wallet - Wallet used to query funds and execute settlement transactions
|
|
26
|
+
*/
|
|
17
27
|
constructor(wallet) {
|
|
18
28
|
this.wallet = wallet;
|
|
19
29
|
}
|
|
20
30
|
/**
|
|
21
|
-
* Onboard boarding
|
|
31
|
+
* Onboard boarding inputs.
|
|
22
32
|
*
|
|
23
33
|
* @param feeInfo - The fee info to deduct from the onboard amount.
|
|
24
|
-
* @param boardingUtxos -
|
|
25
|
-
* @param amount -
|
|
26
|
-
* @param eventCallback -
|
|
34
|
+
* @param boardingUtxos - Specific boarding inputs to onboard. If not provided, all boarding inputs will be used.
|
|
35
|
+
* @param amount - Amount to onboard. If not provided, the total amount of boarding inputs will be onboarded.
|
|
36
|
+
* @param eventCallback - Optional callback that receives settlement events
|
|
37
|
+
* @returns The Arkade transaction id created by settlement
|
|
38
|
+
* @throws Error if no boarding inputs remain after fee deduction or if `amount` exceeds available value
|
|
39
|
+
* @see IWallet.getBoardingUtxos
|
|
40
|
+
* @see IWallet.settle
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const feeInfo = { intentFee: {}, txFeeRate: '1' };
|
|
44
|
+
* const ramps = new Ramps(wallet);
|
|
45
|
+
* await ramps.onboard(feeInfo);
|
|
46
|
+
* ```
|
|
27
47
|
*/
|
|
28
48
|
async onboard(feeInfo, boardingUtxos, amount, eventCallback) {
|
|
29
49
|
boardingUtxos = boardingUtxos ?? (await this.wallet.getBoardingUtxos());
|
|
30
|
-
// Calculate input fees and filter out
|
|
50
|
+
// Calculate input fees and filter out boarding inputs where fee >= value.
|
|
31
51
|
const estimator = new Estimator(feeInfo?.intentFee ?? {});
|
|
32
52
|
const filteredBoardingUtxos = [];
|
|
33
53
|
let totalAmount = 0n;
|
|
@@ -36,7 +56,7 @@ export class Ramps {
|
|
|
36
56
|
amount: BigInt(utxo.value),
|
|
37
57
|
});
|
|
38
58
|
if (inputFee.satoshis >= utxo.value) {
|
|
39
|
-
//
|
|
59
|
+
// Skip boarding inputs where spending fees are greater than or equal to the input value.
|
|
40
60
|
continue;
|
|
41
61
|
}
|
|
42
62
|
filteredBoardingUtxos.push(utxo);
|
|
@@ -84,19 +104,29 @@ export class Ramps {
|
|
|
84
104
|
}, eventCallback);
|
|
85
105
|
}
|
|
86
106
|
/**
|
|
87
|
-
* Offboard
|
|
107
|
+
* Offboard virtual outputs, or collaboratively exit them to an onchain address.
|
|
88
108
|
*
|
|
89
109
|
* @param destinationAddress - The destination address to offboard to.
|
|
90
110
|
* @param feeInfo - The fee info to deduct from the offboard amount.
|
|
91
|
-
* @param amount - The amount to offboard. If not provided, the total amount of
|
|
92
|
-
* @param eventCallback -
|
|
111
|
+
* @param amount - The amount to offboard. If not provided, the total amount of virtual outputs will be offboarded.
|
|
112
|
+
* @param eventCallback - Optional callback that receives settlement events
|
|
113
|
+
* @returns The Arkade transaction id created by settlement
|
|
114
|
+
* @throws Error if no virtual outputs remain after fee deduction or the destination address cannot be decoded
|
|
115
|
+
* @see IWallet.getVtxos
|
|
116
|
+
* @see IWallet.settle
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const feeInfo = { intentFee: {}, txFeeRate: '1' };
|
|
120
|
+
* const ramps = new Ramps(wallet);
|
|
121
|
+
* await ramps.offboard('bc1q...', feeInfo);
|
|
122
|
+
* ```
|
|
93
123
|
*/
|
|
94
124
|
async offboard(destinationAddress, feeInfo, amount, eventCallback) {
|
|
95
125
|
const vtxos = await this.wallet.getVtxos({
|
|
96
126
|
withRecoverable: true,
|
|
97
127
|
withUnrolled: false,
|
|
98
128
|
});
|
|
99
|
-
// Calculate input fees and filter out
|
|
129
|
+
// Calculate input fees and filter out virtual outputs where fee >= value.
|
|
100
130
|
const estimator = new Estimator(feeInfo?.intentFee ?? {});
|
|
101
131
|
const filteredVtxos = [];
|
|
102
132
|
let totalAmount = 0n;
|
|
@@ -113,7 +143,7 @@ export class Ramps {
|
|
|
113
143
|
: undefined,
|
|
114
144
|
});
|
|
115
145
|
if (inputFee.satoshis >= vtxo.value) {
|
|
116
|
-
//
|
|
146
|
+
// Skip virtual outputs where spending fees are greater than or equal to the output value.
|
|
117
147
|
continue;
|
|
118
148
|
}
|
|
119
149
|
filteredVtxos.push(vtxo);
|
|
@@ -49,7 +49,7 @@ export class WalletMessageHandler {
|
|
|
49
49
|
this.contractEventsSubscription = undefined;
|
|
50
50
|
}
|
|
51
51
|
// Dispose the wallet to stop VtxoManager background tasks
|
|
52
|
-
// (auto-renewal, boarding
|
|
52
|
+
// (auto-renewal, boarding input polling) and ContractWatcher.
|
|
53
53
|
try {
|
|
54
54
|
if (this.wallet) {
|
|
55
55
|
await this.wallet.dispose();
|
|
@@ -484,7 +484,7 @@ export class WalletMessageHandler {
|
|
|
484
484
|
}
|
|
485
485
|
const totalBoarding = confirmed + unconfirmed;
|
|
486
486
|
const totalOffchain = settled + preconfirmed + recoverable;
|
|
487
|
-
// aggregate asset balances from spendable
|
|
487
|
+
// aggregate asset balances from spendable virtual outputs
|
|
488
488
|
const assetBalances = new Map();
|
|
489
489
|
for (const vtxo of spendableVtxos) {
|
|
490
490
|
if (vtxo.assets) {
|
|
@@ -529,9 +529,9 @@ export class WalletMessageHandler {
|
|
|
529
529
|
return;
|
|
530
530
|
}
|
|
531
531
|
// Initialize contract manager FIRST — this populates the repository
|
|
532
|
-
// with full
|
|
532
|
+
// with full virtual output history for all contracts (one indexer call per contract)
|
|
533
533
|
await this.ensureContractEventBroadcasting();
|
|
534
|
-
// Refresh cached data (
|
|
534
|
+
// Refresh cached data (virtual outputs, boarding inputs, tx history)
|
|
535
535
|
await this.refreshCachedData();
|
|
536
536
|
// Recover pending transactions (init-only, not on reload).
|
|
537
537
|
// Pending txs only exist if a send was interrupted mid-finalization.
|
|
@@ -562,12 +562,12 @@ export class WalletMessageHandler {
|
|
|
562
562
|
: [];
|
|
563
563
|
if ([...newVtxos, ...spentVtxos].length === 0)
|
|
564
564
|
return;
|
|
565
|
-
// save
|
|
565
|
+
// save virtual outputs using unified repository
|
|
566
566
|
await this.walletRepository?.saveVtxos(address, [
|
|
567
567
|
...newVtxos,
|
|
568
568
|
...spentVtxos,
|
|
569
569
|
]);
|
|
570
|
-
// notify all clients about the
|
|
570
|
+
// notify all clients about the virtual output state update
|
|
571
571
|
this.scheduleForNextTick(() => this.tagged({
|
|
572
572
|
type: "VTXO_UPDATE",
|
|
573
573
|
broadcast: true,
|
|
@@ -577,11 +577,11 @@ export class WalletMessageHandler {
|
|
|
577
577
|
if (funds.type === "utxo") {
|
|
578
578
|
const utxos = funds.coins.map((utxo) => extendCoin(this.readonlyWallet, utxo));
|
|
579
579
|
const boardingAddress = await this.readonlyWallet.getBoardingAddress();
|
|
580
|
-
// save
|
|
581
|
-
// TODO: remove
|
|
580
|
+
// save boarding inputs using unified repository
|
|
581
|
+
// TODO: remove UTXOs by address
|
|
582
582
|
// await this.walletRepository.clearUtxos(boardingAddress);
|
|
583
583
|
await this.walletRepository?.saveUtxos(boardingAddress, utxos);
|
|
584
|
-
// notify all clients about the
|
|
584
|
+
// notify all clients about the boarding input state update
|
|
585
585
|
this.scheduleForNextTick(() => this.tagged({
|
|
586
586
|
type: "UTXO_UPDATE",
|
|
587
587
|
broadcast: true,
|
|
@@ -590,8 +590,8 @@ export class WalletMessageHandler {
|
|
|
590
590
|
}
|
|
591
591
|
});
|
|
592
592
|
// Eagerly start the VtxoManager so its background tasks (auto-renewal,
|
|
593
|
-
// boarding
|
|
594
|
-
// waiting for a client to send a
|
|
593
|
+
// boarding input polling/sweep) run inside the service worker without
|
|
594
|
+
// waiting for a client to send a VtxoManager message first.
|
|
595
595
|
if (this.wallet) {
|
|
596
596
|
try {
|
|
597
597
|
await this.wallet.getVtxoManager();
|
|
@@ -602,7 +602,7 @@ export class WalletMessageHandler {
|
|
|
602
602
|
}
|
|
603
603
|
}
|
|
604
604
|
/**
|
|
605
|
-
* Refresh
|
|
605
|
+
* Refresh virtual outputs, boarding inputs, and transaction history from cache.
|
|
606
606
|
* Shared by onWalletInitialized (full bootstrap) and reloadWallet
|
|
607
607
|
* (post-refresh), avoiding duplicate subscriptions and VtxoManager restarts.
|
|
608
608
|
*/
|
|
@@ -610,14 +610,14 @@ export class WalletMessageHandler {
|
|
|
610
610
|
if (!this.readonlyWallet || !this.walletRepository) {
|
|
611
611
|
return;
|
|
612
612
|
}
|
|
613
|
-
// Read
|
|
613
|
+
// Read virtual outputs from repository (now populated by contract manager)
|
|
614
614
|
const vtxos = await this.getVtxosFromRepo();
|
|
615
|
-
// Fetch boarding
|
|
615
|
+
// Fetch boarding inputs and save using unified repository
|
|
616
616
|
const boardingAddress = await this.readonlyWallet.getBoardingAddress();
|
|
617
617
|
const coins = await this.readonlyWallet.onchainProvider.getCoins(boardingAddress);
|
|
618
618
|
await this.walletRepository.deleteUtxos(boardingAddress);
|
|
619
619
|
await this.walletRepository.saveUtxos(boardingAddress, coins.map((utxo) => extendCoin(this.readonlyWallet, utxo)));
|
|
620
|
-
// Build transaction history from cached
|
|
620
|
+
// Build transaction history from cached virtual outputs (no indexer call)
|
|
621
621
|
const address = await this.readonlyWallet.getAddress();
|
|
622
622
|
const txs = await this.buildTransactionHistoryFromCache(vtxos);
|
|
623
623
|
if (txs)
|
|
@@ -759,7 +759,7 @@ export class WalletMessageHandler {
|
|
|
759
759
|
this.indexerProvider = undefined;
|
|
760
760
|
}
|
|
761
761
|
/**
|
|
762
|
-
* Read all
|
|
762
|
+
* Read all virtual outputs from the repository, aggregated across all contract
|
|
763
763
|
* addresses and the wallet's primary address, with deduplication.
|
|
764
764
|
*/
|
|
765
765
|
async getVtxosFromRepo() {
|
|
@@ -776,7 +776,7 @@ export class WalletMessageHandler {
|
|
|
776
776
|
}
|
|
777
777
|
}
|
|
778
778
|
};
|
|
779
|
-
// Aggregate
|
|
779
|
+
// Aggregate virtual outputs from all contract addresses
|
|
780
780
|
const manager = await this.readonlyWallet.getContractManager();
|
|
781
781
|
const contracts = await manager.getContracts();
|
|
782
782
|
for (const contract of contracts) {
|
|
@@ -790,15 +790,15 @@ export class WalletMessageHandler {
|
|
|
790
790
|
return allVtxos;
|
|
791
791
|
}
|
|
792
792
|
/**
|
|
793
|
-
* Build transaction history from cached
|
|
793
|
+
* Build transaction history from cached virtual outputs without hitting the indexer.
|
|
794
794
|
* Falls back to indexer only for uncached transaction timestamps.
|
|
795
795
|
*/
|
|
796
796
|
async buildTransactionHistoryFromCache(vtxos) {
|
|
797
797
|
if (!this.readonlyWallet)
|
|
798
798
|
return null;
|
|
799
799
|
const { boardingTxs, commitmentsToIgnore } = await this.readonlyWallet.getBoardingTxs();
|
|
800
|
-
// Build a lookup for cached
|
|
801
|
-
// Multiple
|
|
800
|
+
// Build a lookup for cached virtual output timestamps, keyed by txid.
|
|
801
|
+
// Multiple virtual outputs can share a txid (different vouts) — we keep the
|
|
802
802
|
// earliest createdAt so the history ordering is stable.
|
|
803
803
|
const vtxoCreatedAt = new Map();
|
|
804
804
|
for (const vtxo of vtxos) {
|
|
@@ -809,8 +809,8 @@ export class WalletMessageHandler {
|
|
|
809
809
|
}
|
|
810
810
|
}
|
|
811
811
|
// Pre-fetch uncached timestamps in a single batched indexer call.
|
|
812
|
-
// buildTransactionHistory needs these for spent-offchain
|
|
813
|
-
// no change outputs (i.e. arkTxId is set but no
|
|
812
|
+
// buildTransactionHistory needs these for spent-offchain virtual outputs with
|
|
813
|
+
// no change outputs (i.e. arkTxId is set but no virtual output has txid === arkTxId).
|
|
814
814
|
if (this.indexerProvider) {
|
|
815
815
|
const uncachedTxids = new Set();
|
|
816
816
|
for (const vtxo of vtxos) {
|