@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.
Files changed (270) hide show
  1. package/README.md +586 -54
  2. package/dist/cjs/asset/assetGroup.js +141 -0
  3. package/dist/cjs/asset/assetId.js +88 -0
  4. package/dist/cjs/asset/assetInput.js +204 -0
  5. package/dist/cjs/asset/assetOutput.js +159 -0
  6. package/dist/cjs/asset/assetRef.js +82 -0
  7. package/dist/cjs/asset/index.js +24 -0
  8. package/dist/cjs/asset/metadata.js +172 -0
  9. package/dist/cjs/asset/packet.js +164 -0
  10. package/dist/cjs/asset/types.js +25 -0
  11. package/dist/cjs/asset/utils.js +105 -0
  12. package/dist/cjs/bip322/index.js +270 -0
  13. package/dist/cjs/contracts/arkcontract.js +148 -0
  14. package/dist/cjs/contracts/contractManager.js +436 -0
  15. package/dist/cjs/contracts/contractWatcher.js +567 -0
  16. package/dist/cjs/contracts/handlers/default.js +85 -0
  17. package/dist/cjs/contracts/handlers/delegate.js +89 -0
  18. package/dist/cjs/contracts/handlers/helpers.js +105 -0
  19. package/dist/cjs/contracts/handlers/index.js +19 -0
  20. package/dist/cjs/contracts/handlers/registry.js +89 -0
  21. package/dist/cjs/contracts/handlers/vhtlc.js +193 -0
  22. package/dist/cjs/contracts/index.js +41 -0
  23. package/dist/cjs/contracts/types.js +2 -0
  24. package/dist/cjs/forfeit.js +12 -8
  25. package/dist/cjs/identity/index.js +1 -0
  26. package/dist/cjs/identity/seedIdentity.js +255 -0
  27. package/dist/cjs/index.js +72 -14
  28. package/dist/cjs/intent/index.js +47 -11
  29. package/dist/cjs/providers/ark.js +7 -0
  30. package/dist/cjs/providers/delegator.js +66 -0
  31. package/dist/cjs/providers/expoIndexer.js +5 -0
  32. package/dist/cjs/providers/indexer.js +68 -1
  33. package/dist/cjs/providers/utils.js +1 -0
  34. package/dist/cjs/repositories/contractRepository.js +0 -103
  35. package/dist/cjs/repositories/inMemory/contractRepository.js +55 -0
  36. package/dist/cjs/repositories/inMemory/walletRepository.js +80 -0
  37. package/dist/cjs/repositories/index.js +16 -0
  38. package/dist/cjs/repositories/indexedDB/contractRepository.js +187 -0
  39. package/dist/cjs/repositories/indexedDB/db.js +19 -0
  40. package/dist/cjs/repositories/indexedDB/manager.js +97 -0
  41. package/dist/cjs/repositories/indexedDB/schema.js +159 -0
  42. package/dist/cjs/repositories/indexedDB/walletRepository.js +338 -0
  43. package/dist/cjs/repositories/indexedDB/websqlAdapter.js +144 -0
  44. package/dist/cjs/repositories/migrations/contractRepositoryImpl.js +127 -0
  45. package/dist/cjs/repositories/migrations/fromStorageAdapter.js +66 -0
  46. package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +180 -0
  47. package/dist/cjs/repositories/realm/contractRepository.js +120 -0
  48. package/dist/cjs/repositories/realm/index.js +9 -0
  49. package/dist/cjs/repositories/realm/schemas.js +108 -0
  50. package/dist/cjs/repositories/realm/types.js +7 -0
  51. package/dist/cjs/repositories/realm/walletRepository.js +273 -0
  52. package/dist/cjs/repositories/serialization.js +49 -0
  53. package/dist/cjs/repositories/sqlite/contractRepository.js +139 -0
  54. package/dist/cjs/repositories/sqlite/index.js +7 -0
  55. package/dist/cjs/repositories/sqlite/types.js +2 -0
  56. package/dist/cjs/repositories/sqlite/walletRepository.js +328 -0
  57. package/dist/cjs/repositories/walletRepository.js +0 -169
  58. package/dist/cjs/script/base.js +54 -0
  59. package/dist/cjs/script/delegate.js +49 -0
  60. package/dist/cjs/storage/asyncStorage.js +4 -1
  61. package/dist/cjs/storage/fileSystem.js +3 -0
  62. package/dist/cjs/storage/inMemory.js +3 -0
  63. package/dist/cjs/storage/indexedDB.js +5 -1
  64. package/dist/cjs/storage/localStorage.js +3 -0
  65. package/dist/cjs/utils/arkTransaction.js +16 -0
  66. package/dist/cjs/utils/transactionHistory.js +50 -0
  67. package/dist/cjs/wallet/asset-manager.js +338 -0
  68. package/dist/cjs/wallet/asset.js +117 -0
  69. package/dist/cjs/wallet/batch.js +1 -1
  70. package/dist/cjs/wallet/delegator.js +235 -0
  71. package/dist/cjs/wallet/expo/background.js +133 -0
  72. package/dist/cjs/wallet/expo/index.js +9 -0
  73. package/dist/cjs/wallet/expo/wallet.js +231 -0
  74. package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +568 -0
  75. package/dist/cjs/wallet/serviceWorker/wallet.js +383 -102
  76. package/dist/cjs/wallet/utils.js +58 -0
  77. package/dist/cjs/wallet/validation.js +151 -0
  78. package/dist/cjs/wallet/vtxo-manager.js +8 -1
  79. package/dist/cjs/wallet/wallet.js +702 -260
  80. package/dist/cjs/worker/browser/service-worker-manager.js +82 -0
  81. package/dist/cjs/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
  82. package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +78 -0
  83. package/dist/cjs/worker/expo/index.js +12 -0
  84. package/dist/cjs/worker/expo/processors/contractPollProcessor.js +61 -0
  85. package/dist/cjs/worker/expo/processors/index.js +6 -0
  86. package/dist/cjs/worker/expo/taskQueue.js +41 -0
  87. package/dist/cjs/worker/expo/taskRunner.js +57 -0
  88. package/dist/cjs/worker/messageBus.js +252 -0
  89. package/dist/esm/asset/assetGroup.js +137 -0
  90. package/dist/esm/asset/assetId.js +84 -0
  91. package/dist/esm/asset/assetInput.js +199 -0
  92. package/dist/esm/asset/assetOutput.js +154 -0
  93. package/dist/esm/asset/assetRef.js +78 -0
  94. package/dist/esm/asset/index.js +8 -0
  95. package/dist/esm/asset/metadata.js +167 -0
  96. package/dist/esm/asset/packet.js +159 -0
  97. package/dist/esm/asset/types.js +22 -0
  98. package/dist/esm/asset/utils.js +99 -0
  99. package/dist/esm/bip322/index.js +267 -0
  100. package/dist/esm/contracts/arkcontract.js +141 -0
  101. package/dist/esm/contracts/contractManager.js +432 -0
  102. package/dist/esm/contracts/contractWatcher.js +563 -0
  103. package/dist/esm/contracts/handlers/default.js +82 -0
  104. package/dist/esm/contracts/handlers/delegate.js +86 -0
  105. package/dist/esm/contracts/handlers/helpers.js +66 -0
  106. package/dist/esm/contracts/handlers/index.js +12 -0
  107. package/dist/esm/contracts/handlers/registry.js +86 -0
  108. package/dist/esm/contracts/handlers/vhtlc.js +190 -0
  109. package/dist/esm/contracts/index.js +13 -0
  110. package/dist/esm/contracts/types.js +1 -0
  111. package/dist/esm/forfeit.js +11 -8
  112. package/dist/esm/identity/index.js +1 -0
  113. package/dist/esm/identity/seedIdentity.js +249 -0
  114. package/dist/esm/index.js +28 -15
  115. package/dist/esm/intent/index.js +44 -9
  116. package/dist/esm/providers/ark.js +7 -0
  117. package/dist/esm/providers/delegator.js +62 -0
  118. package/dist/esm/providers/expoIndexer.js +5 -0
  119. package/dist/esm/providers/indexer.js +68 -1
  120. package/dist/esm/providers/utils.js +1 -0
  121. package/dist/esm/repositories/contractRepository.js +1 -101
  122. package/dist/esm/repositories/inMemory/contractRepository.js +51 -0
  123. package/dist/esm/repositories/inMemory/walletRepository.js +76 -0
  124. package/dist/esm/repositories/index.js +8 -0
  125. package/dist/esm/repositories/indexedDB/contractRepository.js +183 -0
  126. package/dist/esm/repositories/indexedDB/db.js +4 -0
  127. package/dist/esm/repositories/indexedDB/manager.js +92 -0
  128. package/dist/esm/repositories/indexedDB/schema.js +155 -0
  129. package/dist/esm/repositories/indexedDB/walletRepository.js +334 -0
  130. package/dist/esm/repositories/indexedDB/websqlAdapter.js +138 -0
  131. package/dist/esm/repositories/migrations/contractRepositoryImpl.js +121 -0
  132. package/dist/esm/repositories/migrations/fromStorageAdapter.js +58 -0
  133. package/dist/esm/repositories/migrations/walletRepositoryImpl.js +176 -0
  134. package/dist/esm/repositories/realm/contractRepository.js +116 -0
  135. package/dist/esm/repositories/realm/index.js +3 -0
  136. package/dist/esm/repositories/realm/schemas.js +105 -0
  137. package/dist/esm/repositories/realm/types.js +6 -0
  138. package/dist/esm/repositories/realm/walletRepository.js +269 -0
  139. package/dist/esm/repositories/serialization.js +40 -0
  140. package/dist/esm/repositories/sqlite/contractRepository.js +135 -0
  141. package/dist/esm/repositories/sqlite/index.js +2 -0
  142. package/dist/esm/repositories/sqlite/types.js +1 -0
  143. package/dist/esm/repositories/sqlite/walletRepository.js +324 -0
  144. package/dist/esm/repositories/walletRepository.js +1 -167
  145. package/dist/esm/script/base.js +21 -1
  146. package/dist/esm/script/delegate.js +46 -0
  147. package/dist/esm/storage/asyncStorage.js +4 -1
  148. package/dist/esm/storage/fileSystem.js +3 -0
  149. package/dist/esm/storage/inMemory.js +3 -0
  150. package/dist/esm/storage/indexedDB.js +5 -1
  151. package/dist/esm/storage/localStorage.js +3 -0
  152. package/dist/esm/utils/arkTransaction.js +15 -0
  153. package/dist/esm/utils/transactionHistory.js +50 -0
  154. package/dist/esm/wallet/asset-manager.js +333 -0
  155. package/dist/esm/wallet/asset.js +111 -0
  156. package/dist/esm/wallet/batch.js +1 -1
  157. package/dist/esm/wallet/delegator.js +231 -0
  158. package/dist/esm/wallet/expo/background.js +128 -0
  159. package/dist/esm/wallet/expo/index.js +2 -0
  160. package/dist/esm/wallet/expo/wallet.js +194 -0
  161. package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +564 -0
  162. package/dist/esm/wallet/serviceWorker/wallet.js +382 -101
  163. package/dist/esm/wallet/utils.js +54 -0
  164. package/dist/esm/wallet/validation.js +139 -0
  165. package/dist/esm/wallet/vtxo-manager.js +8 -1
  166. package/dist/esm/wallet/wallet.js +704 -229
  167. package/dist/esm/worker/browser/service-worker-manager.js +76 -0
  168. package/dist/esm/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
  169. package/dist/esm/worker/expo/asyncStorageTaskQueue.js +74 -0
  170. package/dist/esm/worker/expo/index.js +4 -0
  171. package/dist/esm/worker/expo/processors/contractPollProcessor.js +58 -0
  172. package/dist/esm/worker/expo/processors/index.js +1 -0
  173. package/dist/esm/worker/expo/taskQueue.js +37 -0
  174. package/dist/esm/worker/expo/taskRunner.js +54 -0
  175. package/dist/esm/worker/messageBus.js +248 -0
  176. package/dist/types/asset/assetGroup.d.ts +28 -0
  177. package/dist/types/asset/assetId.d.ts +19 -0
  178. package/dist/types/asset/assetInput.d.ts +46 -0
  179. package/dist/types/asset/assetOutput.d.ts +39 -0
  180. package/dist/types/asset/assetRef.d.ts +25 -0
  181. package/dist/types/asset/index.d.ts +8 -0
  182. package/dist/types/asset/metadata.d.ts +37 -0
  183. package/dist/types/asset/packet.d.ts +27 -0
  184. package/dist/types/asset/types.d.ts +18 -0
  185. package/dist/types/asset/utils.d.ts +21 -0
  186. package/dist/types/bip322/index.d.ts +55 -0
  187. package/dist/types/contracts/arkcontract.d.ts +101 -0
  188. package/dist/types/contracts/contractManager.d.ts +331 -0
  189. package/dist/types/contracts/contractWatcher.d.ts +192 -0
  190. package/dist/types/contracts/handlers/default.d.ts +19 -0
  191. package/dist/types/contracts/handlers/delegate.d.ts +21 -0
  192. package/dist/types/contracts/handlers/helpers.d.ts +18 -0
  193. package/dist/types/contracts/handlers/index.d.ts +7 -0
  194. package/dist/types/contracts/handlers/registry.d.ts +65 -0
  195. package/dist/types/contracts/handlers/vhtlc.d.ts +32 -0
  196. package/dist/types/contracts/index.d.ts +14 -0
  197. package/dist/types/contracts/types.d.ts +222 -0
  198. package/dist/types/forfeit.d.ts +2 -1
  199. package/dist/types/identity/index.d.ts +1 -0
  200. package/dist/types/identity/seedIdentity.d.ts +128 -0
  201. package/dist/types/index.d.ts +22 -12
  202. package/dist/types/intent/index.d.ts +15 -1
  203. package/dist/types/providers/ark.d.ts +11 -2
  204. package/dist/types/providers/delegator.d.ts +29 -0
  205. package/dist/types/providers/indexer.d.ts +11 -1
  206. package/dist/types/repositories/contractRepository.d.ts +30 -19
  207. package/dist/types/repositories/inMemory/contractRepository.d.ts +17 -0
  208. package/dist/types/repositories/inMemory/walletRepository.d.ts +26 -0
  209. package/dist/types/repositories/index.d.ts +7 -0
  210. package/dist/types/repositories/indexedDB/contractRepository.d.ts +21 -0
  211. package/dist/types/repositories/indexedDB/db.d.ts +4 -0
  212. package/dist/types/repositories/indexedDB/manager.d.ts +22 -0
  213. package/dist/types/repositories/indexedDB/schema.d.ts +8 -0
  214. package/dist/types/repositories/indexedDB/walletRepository.d.ts +25 -0
  215. package/dist/types/repositories/indexedDB/websqlAdapter.d.ts +49 -0
  216. package/dist/types/repositories/migrations/contractRepositoryImpl.d.ts +24 -0
  217. package/dist/types/repositories/migrations/fromStorageAdapter.d.ts +19 -0
  218. package/dist/types/repositories/migrations/walletRepositoryImpl.d.ts +27 -0
  219. package/dist/types/repositories/realm/contractRepository.d.ts +24 -0
  220. package/dist/types/repositories/realm/index.d.ts +4 -0
  221. package/dist/types/repositories/realm/schemas.d.ts +208 -0
  222. package/dist/types/repositories/realm/types.d.ts +16 -0
  223. package/dist/types/repositories/realm/walletRepository.d.ts +31 -0
  224. package/dist/types/repositories/serialization.d.ts +40 -0
  225. package/dist/types/repositories/sqlite/contractRepository.d.ts +33 -0
  226. package/dist/types/repositories/sqlite/index.d.ts +3 -0
  227. package/dist/types/repositories/sqlite/types.d.ts +18 -0
  228. package/dist/types/repositories/sqlite/walletRepository.d.ts +40 -0
  229. package/dist/types/repositories/walletRepository.d.ts +13 -24
  230. package/dist/types/script/base.d.ts +1 -0
  231. package/dist/types/script/delegate.d.ts +36 -0
  232. package/dist/types/storage/asyncStorage.d.ts +4 -0
  233. package/dist/types/storage/fileSystem.d.ts +3 -0
  234. package/dist/types/storage/inMemory.d.ts +3 -0
  235. package/dist/types/storage/index.d.ts +3 -0
  236. package/dist/types/storage/indexedDB.d.ts +3 -0
  237. package/dist/types/storage/localStorage.d.ts +3 -0
  238. package/dist/types/utils/arkTransaction.d.ts +6 -0
  239. package/dist/types/wallet/asset-manager.d.ts +78 -0
  240. package/dist/types/wallet/asset.d.ts +21 -0
  241. package/dist/types/wallet/batch.d.ts +1 -1
  242. package/dist/types/wallet/delegator.d.ts +24 -0
  243. package/dist/types/wallet/expo/background.d.ts +66 -0
  244. package/dist/types/wallet/expo/index.d.ts +4 -0
  245. package/dist/types/wallet/expo/wallet.d.ts +97 -0
  246. package/dist/types/wallet/index.d.ts +75 -2
  247. package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +366 -0
  248. package/dist/types/wallet/serviceWorker/wallet.d.ts +20 -11
  249. package/dist/types/wallet/utils.d.ts +12 -1
  250. package/dist/types/wallet/validation.d.ts +24 -0
  251. package/dist/types/wallet/wallet.d.ts +111 -17
  252. package/dist/types/worker/browser/service-worker-manager.d.ts +21 -0
  253. package/dist/types/{wallet/serviceWorker → worker/browser}/utils.d.ts +2 -1
  254. package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +46 -0
  255. package/dist/types/worker/expo/index.d.ts +7 -0
  256. package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +14 -0
  257. package/dist/types/worker/expo/processors/index.d.ts +1 -0
  258. package/dist/types/worker/expo/taskQueue.d.ts +50 -0
  259. package/dist/types/worker/expo/taskRunner.d.ts +42 -0
  260. package/dist/types/worker/messageBus.d.ts +109 -0
  261. package/package.json +69 -11
  262. package/dist/cjs/wallet/serviceWorker/request.js +0 -78
  263. package/dist/cjs/wallet/serviceWorker/response.js +0 -222
  264. package/dist/cjs/wallet/serviceWorker/worker.js +0 -655
  265. package/dist/esm/wallet/serviceWorker/request.js +0 -75
  266. package/dist/esm/wallet/serviceWorker/response.js +0 -219
  267. package/dist/esm/wallet/serviceWorker/worker.js +0 -651
  268. package/dist/types/wallet/serviceWorker/request.d.ts +0 -74
  269. package/dist/types/wallet/serviceWorker/response.d.ts +0 -123
  270. 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;