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