@arkade-os/sdk 0.3.13 → 0.4.0-next.1
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 +586 -54
- package/dist/cjs/asset/assetGroup.js +141 -0
- package/dist/cjs/asset/assetId.js +88 -0
- package/dist/cjs/asset/assetInput.js +204 -0
- package/dist/cjs/asset/assetOutput.js +159 -0
- package/dist/cjs/asset/assetRef.js +82 -0
- package/dist/cjs/asset/index.js +24 -0
- package/dist/cjs/asset/metadata.js +172 -0
- package/dist/cjs/asset/packet.js +164 -0
- package/dist/cjs/asset/types.js +25 -0
- package/dist/cjs/asset/utils.js +105 -0
- package/dist/cjs/bip322/index.js +270 -0
- package/dist/cjs/contracts/arkcontract.js +148 -0
- package/dist/cjs/contracts/contractManager.js +436 -0
- package/dist/cjs/contracts/contractWatcher.js +567 -0
- package/dist/cjs/contracts/handlers/default.js +85 -0
- package/dist/cjs/contracts/handlers/delegate.js +89 -0
- package/dist/cjs/contracts/handlers/helpers.js +105 -0
- package/dist/cjs/contracts/handlers/index.js +19 -0
- package/dist/cjs/contracts/handlers/registry.js +89 -0
- package/dist/cjs/contracts/handlers/vhtlc.js +193 -0
- package/dist/cjs/contracts/index.js +41 -0
- package/dist/cjs/contracts/types.js +2 -0
- package/dist/cjs/forfeit.js +12 -8
- package/dist/cjs/identity/index.js +1 -0
- package/dist/cjs/identity/seedIdentity.js +255 -0
- package/dist/cjs/index.js +72 -14
- package/dist/cjs/intent/index.js +47 -11
- package/dist/cjs/providers/ark.js +7 -0
- package/dist/cjs/providers/delegator.js +66 -0
- package/dist/cjs/providers/expoIndexer.js +5 -0
- package/dist/cjs/providers/indexer.js +68 -1
- package/dist/cjs/providers/utils.js +1 -0
- package/dist/cjs/repositories/contractRepository.js +0 -103
- package/dist/cjs/repositories/inMemory/contractRepository.js +55 -0
- package/dist/cjs/repositories/inMemory/walletRepository.js +80 -0
- package/dist/cjs/repositories/index.js +16 -0
- package/dist/cjs/repositories/indexedDB/contractRepository.js +187 -0
- package/dist/cjs/repositories/indexedDB/db.js +19 -0
- package/dist/cjs/repositories/indexedDB/manager.js +97 -0
- package/dist/cjs/repositories/indexedDB/schema.js +159 -0
- package/dist/cjs/repositories/indexedDB/walletRepository.js +338 -0
- package/dist/cjs/repositories/indexedDB/websqlAdapter.js +144 -0
- package/dist/cjs/repositories/migrations/contractRepositoryImpl.js +127 -0
- package/dist/cjs/repositories/migrations/fromStorageAdapter.js +66 -0
- package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +180 -0
- package/dist/cjs/repositories/realm/contractRepository.js +120 -0
- package/dist/cjs/repositories/realm/index.js +9 -0
- package/dist/cjs/repositories/realm/schemas.js +108 -0
- package/dist/cjs/repositories/realm/types.js +7 -0
- package/dist/cjs/repositories/realm/walletRepository.js +273 -0
- package/dist/cjs/repositories/serialization.js +49 -0
- package/dist/cjs/repositories/sqlite/contractRepository.js +139 -0
- package/dist/cjs/repositories/sqlite/index.js +7 -0
- package/dist/cjs/repositories/sqlite/types.js +2 -0
- package/dist/cjs/repositories/sqlite/walletRepository.js +328 -0
- package/dist/cjs/repositories/walletRepository.js +0 -169
- package/dist/cjs/script/base.js +54 -0
- package/dist/cjs/script/delegate.js +49 -0
- package/dist/cjs/storage/asyncStorage.js +4 -1
- package/dist/cjs/storage/fileSystem.js +3 -0
- package/dist/cjs/storage/inMemory.js +3 -0
- package/dist/cjs/storage/indexedDB.js +5 -1
- package/dist/cjs/storage/localStorage.js +3 -0
- package/dist/cjs/utils/arkTransaction.js +16 -0
- package/dist/cjs/utils/transactionHistory.js +50 -0
- package/dist/cjs/wallet/asset-manager.js +338 -0
- package/dist/cjs/wallet/asset.js +117 -0
- package/dist/cjs/wallet/batch.js +1 -1
- package/dist/cjs/wallet/delegator.js +235 -0
- package/dist/cjs/wallet/expo/background.js +133 -0
- package/dist/cjs/wallet/expo/index.js +9 -0
- package/dist/cjs/wallet/expo/wallet.js +231 -0
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +568 -0
- package/dist/cjs/wallet/serviceWorker/wallet.js +383 -102
- package/dist/cjs/wallet/utils.js +58 -0
- package/dist/cjs/wallet/validation.js +151 -0
- package/dist/cjs/wallet/vtxo-manager.js +8 -1
- package/dist/cjs/wallet/wallet.js +702 -260
- package/dist/cjs/worker/browser/service-worker-manager.js +82 -0
- package/dist/cjs/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
- package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +78 -0
- package/dist/cjs/worker/expo/index.js +12 -0
- package/dist/cjs/worker/expo/processors/contractPollProcessor.js +61 -0
- package/dist/cjs/worker/expo/processors/index.js +6 -0
- package/dist/cjs/worker/expo/taskQueue.js +41 -0
- package/dist/cjs/worker/expo/taskRunner.js +57 -0
- package/dist/cjs/worker/messageBus.js +252 -0
- package/dist/esm/asset/assetGroup.js +137 -0
- package/dist/esm/asset/assetId.js +84 -0
- package/dist/esm/asset/assetInput.js +199 -0
- package/dist/esm/asset/assetOutput.js +154 -0
- package/dist/esm/asset/assetRef.js +78 -0
- package/dist/esm/asset/index.js +8 -0
- package/dist/esm/asset/metadata.js +167 -0
- package/dist/esm/asset/packet.js +159 -0
- package/dist/esm/asset/types.js +22 -0
- package/dist/esm/asset/utils.js +99 -0
- package/dist/esm/bip322/index.js +267 -0
- package/dist/esm/contracts/arkcontract.js +141 -0
- package/dist/esm/contracts/contractManager.js +432 -0
- package/dist/esm/contracts/contractWatcher.js +563 -0
- package/dist/esm/contracts/handlers/default.js +82 -0
- package/dist/esm/contracts/handlers/delegate.js +86 -0
- package/dist/esm/contracts/handlers/helpers.js +66 -0
- package/dist/esm/contracts/handlers/index.js +12 -0
- package/dist/esm/contracts/handlers/registry.js +86 -0
- package/dist/esm/contracts/handlers/vhtlc.js +190 -0
- package/dist/esm/contracts/index.js +13 -0
- package/dist/esm/contracts/types.js +1 -0
- package/dist/esm/forfeit.js +11 -8
- package/dist/esm/identity/index.js +1 -0
- package/dist/esm/identity/seedIdentity.js +249 -0
- package/dist/esm/index.js +28 -15
- package/dist/esm/intent/index.js +44 -9
- package/dist/esm/providers/ark.js +7 -0
- package/dist/esm/providers/delegator.js +62 -0
- package/dist/esm/providers/expoIndexer.js +5 -0
- package/dist/esm/providers/indexer.js +68 -1
- package/dist/esm/providers/utils.js +1 -0
- package/dist/esm/repositories/contractRepository.js +1 -101
- package/dist/esm/repositories/inMemory/contractRepository.js +51 -0
- package/dist/esm/repositories/inMemory/walletRepository.js +76 -0
- package/dist/esm/repositories/index.js +8 -0
- package/dist/esm/repositories/indexedDB/contractRepository.js +183 -0
- package/dist/esm/repositories/indexedDB/db.js +4 -0
- package/dist/esm/repositories/indexedDB/manager.js +92 -0
- package/dist/esm/repositories/indexedDB/schema.js +155 -0
- package/dist/esm/repositories/indexedDB/walletRepository.js +334 -0
- package/dist/esm/repositories/indexedDB/websqlAdapter.js +138 -0
- package/dist/esm/repositories/migrations/contractRepositoryImpl.js +121 -0
- package/dist/esm/repositories/migrations/fromStorageAdapter.js +58 -0
- package/dist/esm/repositories/migrations/walletRepositoryImpl.js +176 -0
- package/dist/esm/repositories/realm/contractRepository.js +116 -0
- package/dist/esm/repositories/realm/index.js +3 -0
- package/dist/esm/repositories/realm/schemas.js +105 -0
- package/dist/esm/repositories/realm/types.js +6 -0
- package/dist/esm/repositories/realm/walletRepository.js +269 -0
- package/dist/esm/repositories/serialization.js +40 -0
- package/dist/esm/repositories/sqlite/contractRepository.js +135 -0
- package/dist/esm/repositories/sqlite/index.js +2 -0
- package/dist/esm/repositories/sqlite/types.js +1 -0
- package/dist/esm/repositories/sqlite/walletRepository.js +324 -0
- package/dist/esm/repositories/walletRepository.js +1 -167
- package/dist/esm/script/base.js +21 -1
- package/dist/esm/script/delegate.js +46 -0
- package/dist/esm/storage/asyncStorage.js +4 -1
- package/dist/esm/storage/fileSystem.js +3 -0
- package/dist/esm/storage/inMemory.js +3 -0
- package/dist/esm/storage/indexedDB.js +5 -1
- package/dist/esm/storage/localStorage.js +3 -0
- package/dist/esm/utils/arkTransaction.js +15 -0
- package/dist/esm/utils/transactionHistory.js +50 -0
- package/dist/esm/wallet/asset-manager.js +333 -0
- package/dist/esm/wallet/asset.js +111 -0
- package/dist/esm/wallet/batch.js +1 -1
- package/dist/esm/wallet/delegator.js +231 -0
- package/dist/esm/wallet/expo/background.js +128 -0
- package/dist/esm/wallet/expo/index.js +2 -0
- package/dist/esm/wallet/expo/wallet.js +194 -0
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +564 -0
- package/dist/esm/wallet/serviceWorker/wallet.js +382 -101
- package/dist/esm/wallet/utils.js +54 -0
- package/dist/esm/wallet/validation.js +139 -0
- package/dist/esm/wallet/vtxo-manager.js +8 -1
- package/dist/esm/wallet/wallet.js +704 -229
- package/dist/esm/worker/browser/service-worker-manager.js +76 -0
- package/dist/esm/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
- package/dist/esm/worker/expo/asyncStorageTaskQueue.js +74 -0
- package/dist/esm/worker/expo/index.js +4 -0
- package/dist/esm/worker/expo/processors/contractPollProcessor.js +58 -0
- package/dist/esm/worker/expo/processors/index.js +1 -0
- package/dist/esm/worker/expo/taskQueue.js +37 -0
- package/dist/esm/worker/expo/taskRunner.js +54 -0
- package/dist/esm/worker/messageBus.js +248 -0
- package/dist/types/asset/assetGroup.d.ts +28 -0
- package/dist/types/asset/assetId.d.ts +19 -0
- package/dist/types/asset/assetInput.d.ts +46 -0
- package/dist/types/asset/assetOutput.d.ts +39 -0
- package/dist/types/asset/assetRef.d.ts +25 -0
- package/dist/types/asset/index.d.ts +8 -0
- package/dist/types/asset/metadata.d.ts +37 -0
- package/dist/types/asset/packet.d.ts +27 -0
- package/dist/types/asset/types.d.ts +18 -0
- package/dist/types/asset/utils.d.ts +21 -0
- package/dist/types/bip322/index.d.ts +55 -0
- package/dist/types/contracts/arkcontract.d.ts +101 -0
- package/dist/types/contracts/contractManager.d.ts +331 -0
- package/dist/types/contracts/contractWatcher.d.ts +192 -0
- package/dist/types/contracts/handlers/default.d.ts +19 -0
- package/dist/types/contracts/handlers/delegate.d.ts +21 -0
- package/dist/types/contracts/handlers/helpers.d.ts +18 -0
- package/dist/types/contracts/handlers/index.d.ts +7 -0
- package/dist/types/contracts/handlers/registry.d.ts +65 -0
- package/dist/types/contracts/handlers/vhtlc.d.ts +32 -0
- package/dist/types/contracts/index.d.ts +14 -0
- package/dist/types/contracts/types.d.ts +222 -0
- package/dist/types/forfeit.d.ts +2 -1
- package/dist/types/identity/index.d.ts +1 -0
- package/dist/types/identity/seedIdentity.d.ts +128 -0
- package/dist/types/index.d.ts +22 -12
- package/dist/types/intent/index.d.ts +15 -1
- package/dist/types/providers/ark.d.ts +11 -2
- package/dist/types/providers/delegator.d.ts +29 -0
- package/dist/types/providers/indexer.d.ts +11 -1
- package/dist/types/repositories/contractRepository.d.ts +30 -19
- package/dist/types/repositories/inMemory/contractRepository.d.ts +17 -0
- package/dist/types/repositories/inMemory/walletRepository.d.ts +26 -0
- package/dist/types/repositories/index.d.ts +7 -0
- package/dist/types/repositories/indexedDB/contractRepository.d.ts +21 -0
- package/dist/types/repositories/indexedDB/db.d.ts +4 -0
- package/dist/types/repositories/indexedDB/manager.d.ts +22 -0
- package/dist/types/repositories/indexedDB/schema.d.ts +8 -0
- package/dist/types/repositories/indexedDB/walletRepository.d.ts +25 -0
- package/dist/types/repositories/indexedDB/websqlAdapter.d.ts +49 -0
- package/dist/types/repositories/migrations/contractRepositoryImpl.d.ts +24 -0
- package/dist/types/repositories/migrations/fromStorageAdapter.d.ts +19 -0
- package/dist/types/repositories/migrations/walletRepositoryImpl.d.ts +27 -0
- package/dist/types/repositories/realm/contractRepository.d.ts +24 -0
- package/dist/types/repositories/realm/index.d.ts +4 -0
- package/dist/types/repositories/realm/schemas.d.ts +208 -0
- package/dist/types/repositories/realm/types.d.ts +16 -0
- package/dist/types/repositories/realm/walletRepository.d.ts +31 -0
- package/dist/types/repositories/serialization.d.ts +40 -0
- package/dist/types/repositories/sqlite/contractRepository.d.ts +33 -0
- package/dist/types/repositories/sqlite/index.d.ts +3 -0
- package/dist/types/repositories/sqlite/types.d.ts +18 -0
- package/dist/types/repositories/sqlite/walletRepository.d.ts +40 -0
- package/dist/types/repositories/walletRepository.d.ts +13 -24
- package/dist/types/script/base.d.ts +1 -0
- package/dist/types/script/delegate.d.ts +36 -0
- package/dist/types/storage/asyncStorage.d.ts +4 -0
- package/dist/types/storage/fileSystem.d.ts +3 -0
- package/dist/types/storage/inMemory.d.ts +3 -0
- package/dist/types/storage/index.d.ts +3 -0
- package/dist/types/storage/indexedDB.d.ts +3 -0
- package/dist/types/storage/localStorage.d.ts +3 -0
- package/dist/types/utils/arkTransaction.d.ts +6 -0
- package/dist/types/wallet/asset-manager.d.ts +78 -0
- package/dist/types/wallet/asset.d.ts +21 -0
- package/dist/types/wallet/batch.d.ts +1 -1
- package/dist/types/wallet/delegator.d.ts +24 -0
- package/dist/types/wallet/expo/background.d.ts +66 -0
- package/dist/types/wallet/expo/index.d.ts +4 -0
- package/dist/types/wallet/expo/wallet.d.ts +97 -0
- package/dist/types/wallet/index.d.ts +75 -2
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +366 -0
- package/dist/types/wallet/serviceWorker/wallet.d.ts +20 -11
- package/dist/types/wallet/utils.d.ts +12 -1
- package/dist/types/wallet/validation.d.ts +24 -0
- package/dist/types/wallet/wallet.d.ts +111 -17
- package/dist/types/worker/browser/service-worker-manager.d.ts +21 -0
- package/dist/types/{wallet/serviceWorker → worker/browser}/utils.d.ts +2 -1
- package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +46 -0
- package/dist/types/worker/expo/index.d.ts +7 -0
- package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +14 -0
- package/dist/types/worker/expo/processors/index.d.ts +1 -0
- package/dist/types/worker/expo/taskQueue.d.ts +50 -0
- package/dist/types/worker/expo/taskRunner.d.ts +42 -0
- package/dist/types/worker/messageBus.d.ts +109 -0
- package/package.json +69 -11
- package/dist/cjs/wallet/serviceWorker/request.js +0 -78
- package/dist/cjs/wallet/serviceWorker/response.js +0 -222
- package/dist/cjs/wallet/serviceWorker/worker.js +0 -655
- package/dist/esm/wallet/serviceWorker/request.js +0 -75
- package/dist/esm/wallet/serviceWorker/response.js +0 -219
- package/dist/esm/wallet/serviceWorker/worker.js +0 -651
- package/dist/types/wallet/serviceWorker/request.d.ts +0 -74
- package/dist/types/wallet/serviceWorker/response.d.ts +0 -123
- package/dist/types/wallet/serviceWorker/worker.d.ts +0 -53
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import { RestIndexerProvider } from '../../providers/indexer.js';
|
|
2
|
+
import { isExpired, isRecoverable, isSpendable, isSubdust, } from '../index.js';
|
|
3
|
+
import { extendCoin, extendVirtualCoin } from '../utils.js';
|
|
4
|
+
export const DEFAULT_MESSAGE_TAG = "WALLET_UPDATER";
|
|
5
|
+
export class WalletMessageHandler {
|
|
6
|
+
/**
|
|
7
|
+
* Instantiate a new WalletUpdater.
|
|
8
|
+
* Can override the default `messageTag` allowing more than one updater to run in parallel.
|
|
9
|
+
* Note that the default ServiceWorkerWallet sends messages to the default WalletUpdater tag.
|
|
10
|
+
*/
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.onNextTick = [];
|
|
13
|
+
this.messageTag = options?.messageTag ?? DEFAULT_MESSAGE_TAG;
|
|
14
|
+
}
|
|
15
|
+
// lifecycle methods
|
|
16
|
+
async start(...params) {
|
|
17
|
+
const [services, repositories] = params;
|
|
18
|
+
this.readonlyWallet = services.readonlyWallet;
|
|
19
|
+
this.wallet = services.wallet;
|
|
20
|
+
this.arkProvider = services.arkProvider;
|
|
21
|
+
this.walletRepository = repositories.walletRepository;
|
|
22
|
+
}
|
|
23
|
+
async stop() {
|
|
24
|
+
// optional cleanup and persistence
|
|
25
|
+
}
|
|
26
|
+
async tick(_now) {
|
|
27
|
+
const results = await Promise.allSettled(this.onNextTick.map((fn) => fn()));
|
|
28
|
+
this.onNextTick = [];
|
|
29
|
+
return results
|
|
30
|
+
.map((result) => {
|
|
31
|
+
if (result.status === "fulfilled") {
|
|
32
|
+
return result.value;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.error(`[${this.messageTag}] tick failed`, result.reason);
|
|
36
|
+
// TODO: how to deliver errors down the stream? a broadcast?
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
.filter((response) => response !== null);
|
|
41
|
+
}
|
|
42
|
+
scheduleForNextTick(callback) {
|
|
43
|
+
this.onNextTick.push(callback);
|
|
44
|
+
}
|
|
45
|
+
requireWallet() {
|
|
46
|
+
if (!this.wallet) {
|
|
47
|
+
throw new Error("Read-only wallet: operation requires signing");
|
|
48
|
+
}
|
|
49
|
+
return this.wallet;
|
|
50
|
+
}
|
|
51
|
+
tagged(res) {
|
|
52
|
+
return {
|
|
53
|
+
...res,
|
|
54
|
+
tag: this.messageTag,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async handleMessage(message) {
|
|
58
|
+
const id = message.id;
|
|
59
|
+
if (message.type === "INIT_WALLET") {
|
|
60
|
+
await this.handleInitWallet(message);
|
|
61
|
+
return this.tagged({
|
|
62
|
+
id,
|
|
63
|
+
type: "WALLET_INITIALIZED",
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (!this.readonlyWallet) {
|
|
67
|
+
return this.tagged({
|
|
68
|
+
id,
|
|
69
|
+
error: new Error("Wallet handler not initialized"),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
switch (message.type) {
|
|
74
|
+
case "SETTLE": {
|
|
75
|
+
const response = await this.handleSettle(message);
|
|
76
|
+
return this.tagged({
|
|
77
|
+
id,
|
|
78
|
+
...response,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
case "SEND_BITCOIN": {
|
|
82
|
+
const response = await this.handleSendBitcoin(message);
|
|
83
|
+
return this.tagged({
|
|
84
|
+
id,
|
|
85
|
+
...response,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
case "GET_ADDRESS": {
|
|
89
|
+
const address = await this.readonlyWallet.getAddress();
|
|
90
|
+
return this.tagged({
|
|
91
|
+
id,
|
|
92
|
+
type: "ADDRESS",
|
|
93
|
+
payload: { address },
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
case "GET_BOARDING_ADDRESS": {
|
|
97
|
+
const address = await this.readonlyWallet.getBoardingAddress();
|
|
98
|
+
return this.tagged({
|
|
99
|
+
id,
|
|
100
|
+
type: "BOARDING_ADDRESS",
|
|
101
|
+
payload: { address },
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
case "GET_BALANCE": {
|
|
105
|
+
const balance = await this.handleGetBalance();
|
|
106
|
+
return this.tagged({
|
|
107
|
+
id,
|
|
108
|
+
type: "BALANCE",
|
|
109
|
+
payload: balance,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
case "GET_VTXOS": {
|
|
113
|
+
const vtxos = await this.handleGetVtxos(message);
|
|
114
|
+
return {
|
|
115
|
+
tag: this.messageTag,
|
|
116
|
+
id,
|
|
117
|
+
type: "VTXOS",
|
|
118
|
+
payload: { vtxos },
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
case "GET_BOARDING_UTXOS": {
|
|
122
|
+
const utxos = await this.getAllBoardingUtxos();
|
|
123
|
+
return this.tagged({
|
|
124
|
+
id,
|
|
125
|
+
type: "BOARDING_UTXOS",
|
|
126
|
+
payload: { utxos },
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
case "GET_TRANSACTION_HISTORY": {
|
|
130
|
+
const transactions = await this.readonlyWallet.getTransactionHistory();
|
|
131
|
+
return this.tagged({
|
|
132
|
+
id,
|
|
133
|
+
type: "TRANSACTION_HISTORY",
|
|
134
|
+
payload: { transactions },
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
case "GET_STATUS": {
|
|
138
|
+
const pubKey = await this.readonlyWallet.identity.xOnlyPublicKey();
|
|
139
|
+
return this.tagged({
|
|
140
|
+
id,
|
|
141
|
+
type: "WALLET_STATUS",
|
|
142
|
+
payload: {
|
|
143
|
+
walletInitialized: true,
|
|
144
|
+
xOnlyPublicKey: pubKey,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
case "CLEAR": {
|
|
149
|
+
await this.clear();
|
|
150
|
+
return this.tagged({
|
|
151
|
+
id,
|
|
152
|
+
type: "CLEAR_SUCCESS",
|
|
153
|
+
payload: { cleared: true },
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
case "RELOAD_WALLET": {
|
|
157
|
+
await this.onWalletInitialized();
|
|
158
|
+
return this.tagged({
|
|
159
|
+
id,
|
|
160
|
+
type: "RELOAD_SUCCESS",
|
|
161
|
+
payload: { reloaded: true },
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
case "SIGN_TRANSACTION": {
|
|
165
|
+
const response = await this.handleSignTransaction(message);
|
|
166
|
+
return this.tagged({
|
|
167
|
+
id,
|
|
168
|
+
...response,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
case "CREATE_CONTRACT": {
|
|
172
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
173
|
+
const contract = await manager.createContract(message.payload);
|
|
174
|
+
return this.tagged({
|
|
175
|
+
id,
|
|
176
|
+
type: "CONTRACT_CREATED",
|
|
177
|
+
payload: { contract },
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
case "GET_CONTRACTS": {
|
|
181
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
182
|
+
const contracts = await manager.getContracts(message.payload.filter);
|
|
183
|
+
return this.tagged({
|
|
184
|
+
id,
|
|
185
|
+
type: "CONTRACTS",
|
|
186
|
+
payload: { contracts },
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
case "GET_CONTRACTS_WITH_VTXOS": {
|
|
190
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
191
|
+
const contracts = await manager.getContractsWithVtxos(message.payload.filter);
|
|
192
|
+
return this.tagged({
|
|
193
|
+
id,
|
|
194
|
+
type: "CONTRACTS_WITH_VTXOS",
|
|
195
|
+
payload: { contracts },
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
case "UPDATE_CONTRACT": {
|
|
199
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
200
|
+
const contract = await manager.updateContract(message.payload.script, message.payload.updates);
|
|
201
|
+
return this.tagged({
|
|
202
|
+
id,
|
|
203
|
+
type: "CONTRACT_UPDATED",
|
|
204
|
+
payload: { contract },
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
case "DELETE_CONTRACT": {
|
|
208
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
209
|
+
await manager.deleteContract(message.payload.script);
|
|
210
|
+
return this.tagged({
|
|
211
|
+
id,
|
|
212
|
+
type: "CONTRACT_DELETED",
|
|
213
|
+
payload: { deleted: true },
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
case "GET_SPENDABLE_PATHS": {
|
|
217
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
218
|
+
const paths = await manager.getSpendablePaths(message.payload.options);
|
|
219
|
+
return this.tagged({
|
|
220
|
+
id,
|
|
221
|
+
type: "SPENDABLE_PATHS",
|
|
222
|
+
payload: { paths },
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
case "GET_ALL_SPENDING_PATHS": {
|
|
226
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
227
|
+
const paths = await manager.getAllSpendingPaths(message.payload.options);
|
|
228
|
+
return this.tagged({
|
|
229
|
+
id,
|
|
230
|
+
type: "ALL_SPENDING_PATHS",
|
|
231
|
+
payload: { paths },
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
case "IS_CONTRACT_MANAGER_WATCHING": {
|
|
235
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
236
|
+
const isWatching = await manager.isWatching();
|
|
237
|
+
return this.tagged({
|
|
238
|
+
id,
|
|
239
|
+
type: "CONTRACT_WATCHING",
|
|
240
|
+
payload: { isWatching },
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
case "SEND": {
|
|
244
|
+
const { recipients } = message.payload;
|
|
245
|
+
const txid = await this.wallet.send(...recipients);
|
|
246
|
+
return this.tagged({
|
|
247
|
+
id,
|
|
248
|
+
type: "SEND_SUCCESS",
|
|
249
|
+
payload: { txid },
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
case "GET_ASSET_DETAILS": {
|
|
253
|
+
const { assetId } = message
|
|
254
|
+
.payload;
|
|
255
|
+
const assetDetails = await this.readonlyWallet.assetManager.getAssetDetails(assetId);
|
|
256
|
+
return this.tagged({
|
|
257
|
+
id,
|
|
258
|
+
type: "ASSET_DETAILS",
|
|
259
|
+
payload: { assetDetails },
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
case "ISSUE": {
|
|
263
|
+
const { params } = message.payload;
|
|
264
|
+
const result = await this.wallet.assetManager.issue(params);
|
|
265
|
+
return this.tagged({
|
|
266
|
+
id,
|
|
267
|
+
type: "ISSUE_SUCCESS",
|
|
268
|
+
payload: { result },
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
case "REISSUE": {
|
|
272
|
+
const { params } = message.payload;
|
|
273
|
+
const txid = await this.wallet.assetManager.reissue(params);
|
|
274
|
+
return this.tagged({
|
|
275
|
+
id,
|
|
276
|
+
type: "REISSUE_SUCCESS",
|
|
277
|
+
payload: { txid },
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
case "BURN": {
|
|
281
|
+
const { params } = message.payload;
|
|
282
|
+
const txid = await this.wallet.assetManager.burn(params);
|
|
283
|
+
return this.tagged({
|
|
284
|
+
id,
|
|
285
|
+
type: "BURN_SUCCESS",
|
|
286
|
+
payload: { txid },
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
default:
|
|
290
|
+
console.error("Unknown message type", message);
|
|
291
|
+
throw new Error("Unknown message");
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
return this.tagged({ id, error: error });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Wallet methods
|
|
299
|
+
async handleInitWallet({ payload }) {
|
|
300
|
+
const { arkServerUrl } = payload;
|
|
301
|
+
this.indexerProvider = new RestIndexerProvider(arkServerUrl);
|
|
302
|
+
await this.onWalletInitialized();
|
|
303
|
+
}
|
|
304
|
+
async handleGetBalance() {
|
|
305
|
+
const [boardingUtxos, spendableVtxos, sweptVtxos] = await Promise.all([
|
|
306
|
+
this.getAllBoardingUtxos(),
|
|
307
|
+
this.getSpendableVtxos(),
|
|
308
|
+
this.getSweptVtxos(),
|
|
309
|
+
]);
|
|
310
|
+
// boarding
|
|
311
|
+
let confirmed = 0;
|
|
312
|
+
let unconfirmed = 0;
|
|
313
|
+
for (const utxo of boardingUtxos) {
|
|
314
|
+
if (utxo.status.confirmed) {
|
|
315
|
+
confirmed += utxo.value;
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
unconfirmed += utxo.value;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// offchain
|
|
322
|
+
let settled = 0;
|
|
323
|
+
let preconfirmed = 0;
|
|
324
|
+
let recoverable = 0;
|
|
325
|
+
for (const vtxo of spendableVtxos) {
|
|
326
|
+
if (vtxo.virtualStatus.state === "settled") {
|
|
327
|
+
settled += vtxo.value;
|
|
328
|
+
}
|
|
329
|
+
else if (vtxo.virtualStatus.state === "preconfirmed") {
|
|
330
|
+
preconfirmed += vtxo.value;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
for (const vtxo of sweptVtxos) {
|
|
334
|
+
if (isSpendable(vtxo)) {
|
|
335
|
+
recoverable += vtxo.value;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const totalBoarding = confirmed + unconfirmed;
|
|
339
|
+
const totalOffchain = settled + preconfirmed + recoverable;
|
|
340
|
+
// aggregate asset balances from spendable vtxos
|
|
341
|
+
const assetBalances = new Map();
|
|
342
|
+
for (const vtxo of spendableVtxos) {
|
|
343
|
+
if (vtxo.assets) {
|
|
344
|
+
for (const a of vtxo.assets) {
|
|
345
|
+
const current = assetBalances.get(a.assetId) ?? 0;
|
|
346
|
+
assetBalances.set(a.assetId, current + a.amount);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const assets = Array.from(assetBalances.entries()).map(([assetId, amount]) => ({ assetId, amount }));
|
|
351
|
+
return {
|
|
352
|
+
boarding: {
|
|
353
|
+
confirmed,
|
|
354
|
+
unconfirmed,
|
|
355
|
+
total: totalBoarding,
|
|
356
|
+
},
|
|
357
|
+
settled,
|
|
358
|
+
preconfirmed,
|
|
359
|
+
available: settled + preconfirmed,
|
|
360
|
+
recoverable,
|
|
361
|
+
total: totalBoarding + totalOffchain,
|
|
362
|
+
assets,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
async getAllBoardingUtxos() {
|
|
366
|
+
if (!this.readonlyWallet)
|
|
367
|
+
return [];
|
|
368
|
+
return this.readonlyWallet.getBoardingUtxos();
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Get spendable vtxos for the current wallet address
|
|
372
|
+
*/
|
|
373
|
+
async getSpendableVtxos() {
|
|
374
|
+
if (!this.readonlyWallet)
|
|
375
|
+
return [];
|
|
376
|
+
const vtxos = await this.readonlyWallet.getVtxos();
|
|
377
|
+
return vtxos.filter(isSpendable);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Get swept vtxos for the current wallet address
|
|
381
|
+
*/
|
|
382
|
+
async getSweptVtxos() {
|
|
383
|
+
if (!this.readonlyWallet)
|
|
384
|
+
return [];
|
|
385
|
+
const vtxos = await this.readonlyWallet.getVtxos();
|
|
386
|
+
return vtxos.filter((vtxo) => vtxo.virtualStatus.state === "swept");
|
|
387
|
+
}
|
|
388
|
+
async onWalletInitialized() {
|
|
389
|
+
if (!this.readonlyWallet ||
|
|
390
|
+
!this.arkProvider ||
|
|
391
|
+
!this.indexerProvider ||
|
|
392
|
+
!this.walletRepository) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
// Get all wallet scripts (current + historical delegate/non-delegate)
|
|
396
|
+
const scripts = await this.readonlyWallet.getWalletScripts();
|
|
397
|
+
const response = await this.indexerProvider.getVtxos({ scripts });
|
|
398
|
+
const vtxos = response.vtxos.map((vtxo) => extendVirtualCoin(this.readonlyWallet, vtxo));
|
|
399
|
+
if (this.wallet) {
|
|
400
|
+
try {
|
|
401
|
+
// recover pending transactions if possible
|
|
402
|
+
const { pending, finalized } = await this.wallet.finalizePendingTxs(vtxos.filter((vtxo) => vtxo.virtualStatus.state !== "swept" &&
|
|
403
|
+
vtxo.virtualStatus.state !== "settled"));
|
|
404
|
+
console.info(`Recovered ${finalized.length}/${pending.length} pending transactions: ${finalized.join(", ")}`);
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
console.error("Error recovering pending transactions:", error);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
// Get wallet address and save vtxos using unified repository
|
|
411
|
+
const address = await this.readonlyWallet.getAddress();
|
|
412
|
+
await this.walletRepository.saveVtxos(address, vtxos);
|
|
413
|
+
// Fetch boarding utxos and save using unified repository
|
|
414
|
+
const boardingAddress = await this.readonlyWallet.getBoardingAddress();
|
|
415
|
+
const coins = await this.readonlyWallet.onchainProvider.getCoins(boardingAddress);
|
|
416
|
+
await this.walletRepository.saveUtxos(boardingAddress, coins.map((utxo) => extendCoin(this.readonlyWallet, utxo)));
|
|
417
|
+
// Get transaction history to cache boarding txs
|
|
418
|
+
const txs = await this.readonlyWallet.getTransactionHistory();
|
|
419
|
+
if (txs)
|
|
420
|
+
await this.walletRepository.saveTransactions(address, txs);
|
|
421
|
+
// unsubscribe previous subscription if any
|
|
422
|
+
if (this.incomingFundsSubscription)
|
|
423
|
+
this.incomingFundsSubscription();
|
|
424
|
+
// subscribe for incoming funds and notify all clients when new funds arrive
|
|
425
|
+
this.incomingFundsSubscription =
|
|
426
|
+
await this.readonlyWallet.notifyIncomingFunds(async (funds) => {
|
|
427
|
+
if (funds.type === "vtxo") {
|
|
428
|
+
const newVtxos = funds.newVtxos.length > 0
|
|
429
|
+
? funds.newVtxos.map((vtxo) => extendVirtualCoin(this.readonlyWallet, vtxo))
|
|
430
|
+
: [];
|
|
431
|
+
const spentVtxos = funds.spentVtxos.length > 0
|
|
432
|
+
? funds.spentVtxos.map((vtxo) => extendVirtualCoin(this.readonlyWallet, vtxo))
|
|
433
|
+
: [];
|
|
434
|
+
if ([...newVtxos, ...spentVtxos].length === 0)
|
|
435
|
+
return;
|
|
436
|
+
// save vtxos using unified repository
|
|
437
|
+
await this.walletRepository?.saveVtxos(address, [
|
|
438
|
+
...newVtxos,
|
|
439
|
+
...spentVtxos,
|
|
440
|
+
]);
|
|
441
|
+
// notify all clients about the vtxo update
|
|
442
|
+
this.scheduleForNextTick(() => this.tagged({
|
|
443
|
+
type: "VTXO_UPDATE",
|
|
444
|
+
broadcast: true,
|
|
445
|
+
payload: { newVtxos, spentVtxos },
|
|
446
|
+
}));
|
|
447
|
+
}
|
|
448
|
+
if (funds.type === "utxo") {
|
|
449
|
+
const utxos = funds.coins.map((utxo) => extendCoin(this.readonlyWallet, utxo));
|
|
450
|
+
const boardingAddress = await this.readonlyWallet.getBoardingAddress();
|
|
451
|
+
// save utxos using unified repository
|
|
452
|
+
// TODO: remove UTXOS by address
|
|
453
|
+
// await this.walletRepository.clearUtxos(boardingAddress);
|
|
454
|
+
await this.walletRepository?.saveUtxos(boardingAddress, utxos);
|
|
455
|
+
// notify all clients about the utxo update
|
|
456
|
+
this.scheduleForNextTick(() => this.tagged({
|
|
457
|
+
type: "UTXO_UPDATE",
|
|
458
|
+
broadcast: true,
|
|
459
|
+
payload: { coins: utxos },
|
|
460
|
+
}));
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
await this.ensureContractEventBroadcasting();
|
|
464
|
+
}
|
|
465
|
+
async handleSettle(message) {
|
|
466
|
+
const wallet = this.requireWallet();
|
|
467
|
+
const txid = await wallet.settle(message.payload.params, (e) => {
|
|
468
|
+
this.scheduleForNextTick(() => this.tagged({
|
|
469
|
+
id: message.id,
|
|
470
|
+
type: "SETTLE_EVENT",
|
|
471
|
+
payload: e,
|
|
472
|
+
}));
|
|
473
|
+
});
|
|
474
|
+
if (!txid) {
|
|
475
|
+
throw new Error("Settlement failed");
|
|
476
|
+
}
|
|
477
|
+
return { type: "SETTLE_SUCCESS", payload: { txid } };
|
|
478
|
+
}
|
|
479
|
+
async handleSendBitcoin(message) {
|
|
480
|
+
const wallet = this.requireWallet();
|
|
481
|
+
const txid = await wallet.sendBitcoin(message.payload);
|
|
482
|
+
if (!txid) {
|
|
483
|
+
throw new Error("Send bitcoin failed");
|
|
484
|
+
}
|
|
485
|
+
return {
|
|
486
|
+
type: "SEND_BITCOIN_SUCCESS",
|
|
487
|
+
payload: { txid },
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
async handleSignTransaction(message) {
|
|
491
|
+
const wallet = this.requireWallet();
|
|
492
|
+
const { tx, inputIndexes } = message.payload;
|
|
493
|
+
const signature = await wallet.identity.sign(tx, inputIndexes);
|
|
494
|
+
if (!signature) {
|
|
495
|
+
throw new Error("Sign transaction failed");
|
|
496
|
+
}
|
|
497
|
+
return {
|
|
498
|
+
type: "SIGN_TRANSACTION",
|
|
499
|
+
payload: { tx: signature },
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
async handleGetVtxos(message) {
|
|
503
|
+
if (!this.readonlyWallet) {
|
|
504
|
+
throw new Error("Wallet handler not initialized");
|
|
505
|
+
}
|
|
506
|
+
const vtxos = await this.getSpendableVtxos();
|
|
507
|
+
const dustAmount = this.readonlyWallet.dustAmount;
|
|
508
|
+
const includeRecoverable = message.payload.filter?.withRecoverable ?? false;
|
|
509
|
+
const filteredVtxos = includeRecoverable
|
|
510
|
+
? vtxos
|
|
511
|
+
: vtxos.filter((v) => {
|
|
512
|
+
if (dustAmount != null && isSubdust(v, dustAmount)) {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
if (isRecoverable(v)) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
if (isExpired(v)) {
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
return true;
|
|
522
|
+
});
|
|
523
|
+
return filteredVtxos;
|
|
524
|
+
}
|
|
525
|
+
async clear() {
|
|
526
|
+
if (!this.readonlyWallet)
|
|
527
|
+
return;
|
|
528
|
+
if (this.incomingFundsSubscription)
|
|
529
|
+
this.incomingFundsSubscription();
|
|
530
|
+
if (this.contractEventsSubscription) {
|
|
531
|
+
this.contractEventsSubscription();
|
|
532
|
+
this.contractEventsSubscription = undefined;
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
await this.walletRepository?.clear();
|
|
536
|
+
}
|
|
537
|
+
catch (_) {
|
|
538
|
+
console.warn("Failed to clear vtxos from wallet repository");
|
|
539
|
+
}
|
|
540
|
+
this.wallet = undefined;
|
|
541
|
+
this.readonlyWallet = undefined;
|
|
542
|
+
this.arkProvider = undefined;
|
|
543
|
+
this.indexerProvider = undefined;
|
|
544
|
+
}
|
|
545
|
+
async ensureContractEventBroadcasting() {
|
|
546
|
+
if (!this.readonlyWallet)
|
|
547
|
+
return;
|
|
548
|
+
if (this.contractEventsSubscription)
|
|
549
|
+
return;
|
|
550
|
+
try {
|
|
551
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
552
|
+
this.contractEventsSubscription = manager.onContractEvent((event) => {
|
|
553
|
+
this.scheduleForNextTick(() => this.tagged({
|
|
554
|
+
type: "CONTRACT_EVENT",
|
|
555
|
+
broadcast: true,
|
|
556
|
+
payload: { event },
|
|
557
|
+
}));
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
catch (error) {
|
|
561
|
+
console.error("Error subscribing to contract events:", error);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|