@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,436 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContractManager = void 0;
|
|
4
|
+
const base_1 = require("@scure/base");
|
|
5
|
+
const contractWatcher_1 = require("./contractWatcher");
|
|
6
|
+
const handlers_1 = require("./handlers");
|
|
7
|
+
const utils_1 = require("../wallet/utils");
|
|
8
|
+
/**
|
|
9
|
+
* Central manager for contract lifecycle and operations.
|
|
10
|
+
*
|
|
11
|
+
* The ContractManager orchestrates:
|
|
12
|
+
* - Contract registration and persistence
|
|
13
|
+
* - Multi-contract watching via ContractWatcher
|
|
14
|
+
* - VTXO queries across contracts
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const manager = new ContractManager({
|
|
19
|
+
* indexerProvider: wallet.indexerProvider,
|
|
20
|
+
* contractRepository: wallet.contractRepository,
|
|
21
|
+
* getDefaultAddress: () => wallet.getAddress(),
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Initialize (loads persisted contracts)
|
|
25
|
+
* await manager.initialize();
|
|
26
|
+
*
|
|
27
|
+
* // Create a new VHTLC contract
|
|
28
|
+
* const contract = await manager.createContract({
|
|
29
|
+
* label: "Lightning Receive",
|
|
30
|
+
* type: "vhtlc",
|
|
31
|
+
* params: { sender: "ab12...", receiver: "cd34...", ... },
|
|
32
|
+
* script: "5120...",
|
|
33
|
+
* address: "tark1...",
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Start watching for events
|
|
37
|
+
* const stop = await manager.startWatching((event) => {
|
|
38
|
+
* console.log(`${event.type} on ${event.contractScript}`);
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* // Get balance across all contracts
|
|
42
|
+
* const balances = await manager.getAllBalances();
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
class ContractManager {
|
|
46
|
+
constructor(config) {
|
|
47
|
+
this.initialized = false;
|
|
48
|
+
this.eventCallbacks = new Set();
|
|
49
|
+
this.config = config;
|
|
50
|
+
// Create watcher with wallet repository for VTXO caching
|
|
51
|
+
this.watcher = new contractWatcher_1.ContractWatcher({
|
|
52
|
+
indexerProvider: config.indexerProvider,
|
|
53
|
+
walletRepository: config.walletRepository,
|
|
54
|
+
...config.watcherConfig,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Static factory method for creating a new ContractManager.
|
|
59
|
+
* Initialize the manager by loading persisted contracts and starting to watch.
|
|
60
|
+
*
|
|
61
|
+
* After initialization, the manager automatically watches all active contracts
|
|
62
|
+
* and contracts with VTXOs. Use `onContractEvent()` to register event callbacks.
|
|
63
|
+
*
|
|
64
|
+
* @param config ContractManagerConfig
|
|
65
|
+
*/
|
|
66
|
+
static async create(config) {
|
|
67
|
+
const cm = new ContractManager(config);
|
|
68
|
+
await cm.initialize();
|
|
69
|
+
return cm;
|
|
70
|
+
}
|
|
71
|
+
async initialize() {
|
|
72
|
+
if (this.initialized) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Load persisted contracts
|
|
76
|
+
const contracts = await this.config.contractRepository.getContracts();
|
|
77
|
+
// fetch latest VTXOs for all contracts, ensure cache is up to date
|
|
78
|
+
// TODO: what if the user has 1k contracts?
|
|
79
|
+
await this.getVtxosForContracts(contracts);
|
|
80
|
+
// add all contracts to the watcher
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
for (const contract of contracts) {
|
|
83
|
+
// Check for expired contracts and mark as inactive
|
|
84
|
+
if (contract.state === "active" &&
|
|
85
|
+
contract.expiresAt &&
|
|
86
|
+
contract.expiresAt <= now) {
|
|
87
|
+
contract.state = "inactive";
|
|
88
|
+
await this.config.contractRepository.saveContract(contract);
|
|
89
|
+
}
|
|
90
|
+
// Add to watcher
|
|
91
|
+
await this.watcher.addContract(contract);
|
|
92
|
+
}
|
|
93
|
+
this.initialized = true;
|
|
94
|
+
// Start watching automatically
|
|
95
|
+
this.stopWatcherFn = await this.watcher.startWatching((event) => {
|
|
96
|
+
this.handleContractEvent(event);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Create and register a new contract.
|
|
101
|
+
*
|
|
102
|
+
* @param params - Contract parameters
|
|
103
|
+
* @returns The created contract
|
|
104
|
+
*/
|
|
105
|
+
async createContract(params) {
|
|
106
|
+
// Validate that a handler exists for this contract type
|
|
107
|
+
const handler = handlers_1.contractHandlers.get(params.type);
|
|
108
|
+
if (!handler) {
|
|
109
|
+
throw new Error(`No handler registered for contract type '${params.type}'`);
|
|
110
|
+
}
|
|
111
|
+
// Validate params by attempting to create the script
|
|
112
|
+
// This catches invalid/missing params early
|
|
113
|
+
try {
|
|
114
|
+
const script = handler.createScript(params.params);
|
|
115
|
+
const derivedScript = base_1.hex.encode(script.pkScript);
|
|
116
|
+
// Verify the derived script matches the provided script
|
|
117
|
+
if (derivedScript !== params.script) {
|
|
118
|
+
throw new Error(`Script mismatch: provided script does not match script derived from params. ` +
|
|
119
|
+
`Expected ${derivedScript}, got ${params.script}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error instanceof Error && error.message.includes("mismatch")) {
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
throw new Error(`Invalid params for contract type '${params.type}': ${error instanceof Error ? error.message : String(error)}`);
|
|
127
|
+
}
|
|
128
|
+
// Check if contract already exists and verify it's the same type to avoid silent mismatches
|
|
129
|
+
const [existing] = await this.getContracts({ script: params.script });
|
|
130
|
+
if (existing) {
|
|
131
|
+
if (existing.type === params.type)
|
|
132
|
+
return existing;
|
|
133
|
+
throw new Error(`Contract with script ${params.script} already exists with with type ${existing.type}.`);
|
|
134
|
+
}
|
|
135
|
+
const contract = {
|
|
136
|
+
...params,
|
|
137
|
+
createdAt: Date.now(),
|
|
138
|
+
state: params.state || "active",
|
|
139
|
+
};
|
|
140
|
+
// Persist
|
|
141
|
+
await this.config.contractRepository.saveContract(contract);
|
|
142
|
+
// ensure we have the latest VTXOs for this contract
|
|
143
|
+
await this.getVtxosForContracts([contract]);
|
|
144
|
+
// Add to watcher
|
|
145
|
+
await this.watcher.addContract(contract);
|
|
146
|
+
return contract;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get contracts with optional filters.
|
|
150
|
+
*
|
|
151
|
+
* @param filter - Optional filter criteria
|
|
152
|
+
* @returns Filtered contracts TODO: filter spent/unspent
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* // Get all VHTLC contracts
|
|
157
|
+
* const vhtlcs = await manager.getContracts({ type: 'vhtlc' });
|
|
158
|
+
*
|
|
159
|
+
* // Get all active contracts
|
|
160
|
+
* const active = await manager.getContracts({ state: 'active' });
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
async getContracts(filter) {
|
|
164
|
+
const dbFilter = this.buildContractsDbFilter(filter ?? {});
|
|
165
|
+
return await this.config.contractRepository.getContracts(dbFilter);
|
|
166
|
+
}
|
|
167
|
+
async getContractsWithVtxos(filter) {
|
|
168
|
+
const contracts = await this.getContracts(filter);
|
|
169
|
+
const vtxos = await this.getVtxosForContracts(contracts);
|
|
170
|
+
return contracts.map((contract) => ({
|
|
171
|
+
contract,
|
|
172
|
+
vtxos: vtxos.get(contract.script) ?? [],
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
buildContractsDbFilter(filter) {
|
|
176
|
+
return {
|
|
177
|
+
script: filter.script,
|
|
178
|
+
state: filter.state,
|
|
179
|
+
type: filter.type,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Update a contract.
|
|
184
|
+
* Nested fields like `params` and `metadata` are replaced with the provided values.
|
|
185
|
+
* If you need to preserve existing fields, merge them manually.
|
|
186
|
+
*
|
|
187
|
+
* @param script - Contract script
|
|
188
|
+
* @param updates - Fields to update
|
|
189
|
+
*/
|
|
190
|
+
async updateContract(script, updates) {
|
|
191
|
+
const contracts = await this.config.contractRepository.getContracts({
|
|
192
|
+
script,
|
|
193
|
+
});
|
|
194
|
+
const existing = contracts[0];
|
|
195
|
+
if (!existing) {
|
|
196
|
+
throw new Error(`Contract ${script} not found`);
|
|
197
|
+
}
|
|
198
|
+
const updated = {
|
|
199
|
+
...existing,
|
|
200
|
+
...updates,
|
|
201
|
+
};
|
|
202
|
+
await this.config.contractRepository.saveContract(updated);
|
|
203
|
+
await this.watcher.updateContract(updated);
|
|
204
|
+
return updated;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Update a contract's params.
|
|
208
|
+
* This method preserves existing params by merging the provided values.
|
|
209
|
+
*
|
|
210
|
+
* @param script - Contract script
|
|
211
|
+
* @param updates - The new values to merge with existing params
|
|
212
|
+
*/
|
|
213
|
+
async updateContractParams(script, updates) {
|
|
214
|
+
const contracts = await this.config.contractRepository.getContracts({
|
|
215
|
+
script,
|
|
216
|
+
});
|
|
217
|
+
const existing = contracts[0];
|
|
218
|
+
if (!existing) {
|
|
219
|
+
throw new Error(`Contract ${script} not found`);
|
|
220
|
+
}
|
|
221
|
+
const updated = {
|
|
222
|
+
...existing,
|
|
223
|
+
params: { ...existing.params, ...updates },
|
|
224
|
+
};
|
|
225
|
+
await this.config.contractRepository.saveContract(updated);
|
|
226
|
+
await this.watcher.updateContract(updated);
|
|
227
|
+
return updated;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Set a contract's state.
|
|
231
|
+
*/
|
|
232
|
+
async setContractState(script, state) {
|
|
233
|
+
await this.updateContract(script, { state });
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Delete a contract.
|
|
237
|
+
*
|
|
238
|
+
* @param script - Contract script
|
|
239
|
+
*/
|
|
240
|
+
async deleteContract(script) {
|
|
241
|
+
await this.config.contractRepository.deleteContract(script);
|
|
242
|
+
await this.watcher.removeContract(script);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get currently spendable paths for a contract.
|
|
246
|
+
*
|
|
247
|
+
* @param contractScript - The contract script
|
|
248
|
+
* @param options - Options for getting spendable paths
|
|
249
|
+
*/
|
|
250
|
+
async getSpendablePaths(options) {
|
|
251
|
+
const { contractScript, collaborative = true, walletPubKey, vtxo, } = options;
|
|
252
|
+
const [contract] = await this.getContracts({ script: contractScript });
|
|
253
|
+
if (!contract)
|
|
254
|
+
return [];
|
|
255
|
+
const handler = handlers_1.contractHandlers.get(contract.type);
|
|
256
|
+
if (!handler)
|
|
257
|
+
return [];
|
|
258
|
+
const script = handler.createScript(contract.params);
|
|
259
|
+
const context = {
|
|
260
|
+
collaborative,
|
|
261
|
+
currentTime: Date.now(),
|
|
262
|
+
walletPubKey,
|
|
263
|
+
vtxo,
|
|
264
|
+
};
|
|
265
|
+
return handler.getSpendablePaths(script, contract, context);
|
|
266
|
+
}
|
|
267
|
+
async getAllSpendingPaths(options) {
|
|
268
|
+
const { contractScript, collaborative = true, walletPubKey } = options;
|
|
269
|
+
const [contract] = await this.getContracts({ script: contractScript });
|
|
270
|
+
if (!contract)
|
|
271
|
+
return [];
|
|
272
|
+
const handler = handlers_1.contractHandlers.get(contract.type);
|
|
273
|
+
if (!handler)
|
|
274
|
+
return [];
|
|
275
|
+
const script = handler.createScript(contract.params);
|
|
276
|
+
const context = {
|
|
277
|
+
collaborative,
|
|
278
|
+
currentTime: Date.now(),
|
|
279
|
+
walletPubKey,
|
|
280
|
+
};
|
|
281
|
+
return handler.getAllSpendingPaths(script, contract, context);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Register a callback for contract events.
|
|
285
|
+
*
|
|
286
|
+
* The manager automatically watches after `initialize()`. This method
|
|
287
|
+
* allows registering callbacks to receive events.
|
|
288
|
+
*
|
|
289
|
+
* @param callback - Event callback
|
|
290
|
+
* @returns Unsubscribe function to remove this callback
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```typescript
|
|
294
|
+
* const unsubscribe = manager.onContractEvent((event) => {
|
|
295
|
+
* console.log(`${event.type} on ${event.contractScript}`);
|
|
296
|
+
* });
|
|
297
|
+
*
|
|
298
|
+
* // Later: stop receiving events
|
|
299
|
+
* unsubscribe();
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
onContractEvent(callback) {
|
|
303
|
+
this.eventCallbacks.add(callback);
|
|
304
|
+
return () => {
|
|
305
|
+
this.eventCallbacks.delete(callback);
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Check if currently watching.
|
|
310
|
+
*/
|
|
311
|
+
async isWatching() {
|
|
312
|
+
return this.watcher.isCurrentlyWatching();
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Emit an event to all registered callbacks.
|
|
316
|
+
*/
|
|
317
|
+
emitEvent(event) {
|
|
318
|
+
for (const callback of this.eventCallbacks) {
|
|
319
|
+
try {
|
|
320
|
+
callback(event);
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
console.error("Error in contract event callback:", error);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Handle events from the watcher.
|
|
329
|
+
*/
|
|
330
|
+
async handleContractEvent(event) {
|
|
331
|
+
switch (event.type) {
|
|
332
|
+
// Every time there is a VTXO event for a contract, refresh all its VTXOs
|
|
333
|
+
case "vtxo_received":
|
|
334
|
+
case "vtxo_spent":
|
|
335
|
+
await this.fetchContractVxosFromIndexer([event.contract], true);
|
|
336
|
+
break;
|
|
337
|
+
case "connection_reset":
|
|
338
|
+
// Refetch all VTXOs for all active contracts
|
|
339
|
+
const activeWatchedContracts = this.watcher.getActiveContracts();
|
|
340
|
+
await this.fetchContractVxosFromIndexer(activeWatchedContracts, false);
|
|
341
|
+
break;
|
|
342
|
+
case "contract_expired":
|
|
343
|
+
// just update DB
|
|
344
|
+
await this.config.contractRepository.saveContract(event.contract);
|
|
345
|
+
}
|
|
346
|
+
// Forward to all callbacks
|
|
347
|
+
this.emitEvent(event);
|
|
348
|
+
}
|
|
349
|
+
async getVtxosForContracts(contracts) {
|
|
350
|
+
if (contracts.length === 0) {
|
|
351
|
+
return new Map();
|
|
352
|
+
}
|
|
353
|
+
return await this.fetchContractVxosFromIndexer(contracts, false);
|
|
354
|
+
}
|
|
355
|
+
async fetchContractVxosFromIndexer(contracts, includeSpent) {
|
|
356
|
+
const fetched = await this.fetchContractVtxosBulk(contracts, includeSpent);
|
|
357
|
+
const result = new Map();
|
|
358
|
+
for (const [contractScript, vtxos] of fetched) {
|
|
359
|
+
result.set(contractScript, vtxos);
|
|
360
|
+
const contract = contracts.find((c) => c.script === contractScript);
|
|
361
|
+
if (contract) {
|
|
362
|
+
await this.config.walletRepository.saveVtxos(contract.address, vtxos);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return result;
|
|
366
|
+
}
|
|
367
|
+
async fetchContractVtxosBulk(contracts, includeSpent) {
|
|
368
|
+
const result = new Map();
|
|
369
|
+
await Promise.all(contracts.map(async (contract) => {
|
|
370
|
+
const vtxos = await this.fetchContractVtxosPaginated(contract, includeSpent);
|
|
371
|
+
result.set(contract.script, vtxos);
|
|
372
|
+
}));
|
|
373
|
+
return result;
|
|
374
|
+
}
|
|
375
|
+
async fetchContractVtxosPaginated(contract, includeSpent) {
|
|
376
|
+
const pageSize = 100;
|
|
377
|
+
const allVtxos = [];
|
|
378
|
+
let pageIndex = 0;
|
|
379
|
+
let hasMore = true;
|
|
380
|
+
const opts = includeSpent ? {} : { spendableOnly: true };
|
|
381
|
+
while (hasMore) {
|
|
382
|
+
const { vtxos, page } = await this.config.indexerProvider.getVtxos({
|
|
383
|
+
scripts: [contract.script],
|
|
384
|
+
...opts,
|
|
385
|
+
pageIndex,
|
|
386
|
+
pageSize,
|
|
387
|
+
});
|
|
388
|
+
for (const vtxo of vtxos) {
|
|
389
|
+
allVtxos.push({
|
|
390
|
+
...(0, utils_1.extendVtxoFromContract)(vtxo, contract),
|
|
391
|
+
contractScript: contract.script,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
hasMore = page ? vtxos.length === pageSize : false;
|
|
395
|
+
pageIndex++;
|
|
396
|
+
}
|
|
397
|
+
return allVtxos;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Dispose of the ContractManager and release all resources.
|
|
401
|
+
*
|
|
402
|
+
* Stops the watcher, clears callbacks, and marks
|
|
403
|
+
* the manager as uninitialized.
|
|
404
|
+
*
|
|
405
|
+
* Implements the disposable pattern for cleanup.
|
|
406
|
+
*/
|
|
407
|
+
dispose() {
|
|
408
|
+
// Stop watching
|
|
409
|
+
this.stopWatcherFn?.();
|
|
410
|
+
this.stopWatcherFn = undefined;
|
|
411
|
+
// Clear callbacks
|
|
412
|
+
this.eventCallbacks.clear();
|
|
413
|
+
// Mark as uninitialized
|
|
414
|
+
this.initialized = false;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Symbol.dispose implementation for using with `using` keyword.
|
|
418
|
+
* @example
|
|
419
|
+
* ```typescript
|
|
420
|
+
* {
|
|
421
|
+
* using manager = await wallet.getContractManager();
|
|
422
|
+
* // ... use manager
|
|
423
|
+
* } // automatically disposed
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
426
|
+
[Symbol.dispose]() {
|
|
427
|
+
// Stop watching
|
|
428
|
+
this.stopWatcherFn?.();
|
|
429
|
+
this.stopWatcherFn = undefined;
|
|
430
|
+
// Clear callbacks
|
|
431
|
+
this.eventCallbacks.clear();
|
|
432
|
+
// Mark as uninitialized
|
|
433
|
+
this.initialized = false;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
exports.ContractManager = ContractManager;
|