@arkade-os/sdk 0.3.12 → 0.4.0-next.0

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 (250) hide show
  1. package/README.md +483 -54
  2. package/dist/cjs/adapters/expo-db.js +35 -0
  3. package/dist/cjs/asset/assetGroup.js +141 -0
  4. package/dist/cjs/asset/assetId.js +88 -0
  5. package/dist/cjs/asset/assetInput.js +204 -0
  6. package/dist/cjs/asset/assetOutput.js +159 -0
  7. package/dist/cjs/asset/assetRef.js +82 -0
  8. package/dist/cjs/asset/index.js +24 -0
  9. package/dist/cjs/asset/metadata.js +172 -0
  10. package/dist/cjs/asset/packet.js +164 -0
  11. package/dist/cjs/asset/types.js +25 -0
  12. package/dist/cjs/asset/utils.js +105 -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/db/manager.js +97 -0
  25. package/dist/cjs/forfeit.js +12 -8
  26. package/dist/cjs/identity/index.js +1 -0
  27. package/dist/cjs/identity/seedIdentity.js +255 -0
  28. package/dist/cjs/index.js +70 -14
  29. package/dist/cjs/intent/index.js +28 -2
  30. package/dist/cjs/providers/ark.js +7 -0
  31. package/dist/cjs/providers/delegator.js +66 -0
  32. package/dist/cjs/providers/expoIndexer.js +5 -0
  33. package/dist/cjs/providers/indexer.js +68 -1
  34. package/dist/cjs/providers/onchain.js +2 -2
  35. package/dist/cjs/providers/utils.js +1 -0
  36. package/dist/cjs/repositories/contractRepository.js +0 -103
  37. package/dist/cjs/repositories/inMemory/contractRepository.js +55 -0
  38. package/dist/cjs/repositories/inMemory/walletRepository.js +80 -0
  39. package/dist/cjs/repositories/index.js +16 -0
  40. package/dist/cjs/repositories/indexedDB/contractRepository.js +187 -0
  41. package/dist/cjs/repositories/indexedDB/db.js +57 -0
  42. package/dist/cjs/repositories/indexedDB/schema.js +159 -0
  43. package/dist/cjs/repositories/indexedDB/walletRepository.js +338 -0
  44. package/dist/cjs/repositories/indexedDB/websqlAdapter.js +144 -0
  45. package/dist/cjs/repositories/migrations/contractRepositoryImpl.js +127 -0
  46. package/dist/cjs/repositories/migrations/fromStorageAdapter.js +66 -0
  47. package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +180 -0
  48. package/dist/cjs/repositories/walletRepository.js +0 -169
  49. package/dist/cjs/script/base.js +54 -0
  50. package/dist/cjs/script/delegate.js +49 -0
  51. package/dist/cjs/storage/asyncStorage.js +4 -1
  52. package/dist/cjs/storage/fileSystem.js +3 -0
  53. package/dist/cjs/storage/inMemory.js +3 -0
  54. package/dist/cjs/storage/indexedDB.js +5 -1
  55. package/dist/cjs/storage/localStorage.js +3 -0
  56. package/dist/cjs/utils/arkTransaction.js +16 -0
  57. package/dist/cjs/utils/transactionHistory.js +50 -0
  58. package/dist/cjs/utils/txSizeEstimator.js +39 -14
  59. package/dist/cjs/wallet/asset-manager.js +338 -0
  60. package/dist/cjs/wallet/asset.js +117 -0
  61. package/dist/cjs/wallet/batch.js +1 -1
  62. package/dist/cjs/wallet/delegator.js +235 -0
  63. package/dist/cjs/wallet/expo/background.js +133 -0
  64. package/dist/cjs/wallet/expo/index.js +9 -0
  65. package/dist/cjs/wallet/expo/wallet.js +231 -0
  66. package/dist/cjs/wallet/onchain.js +57 -12
  67. package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +568 -0
  68. package/dist/cjs/wallet/serviceWorker/wallet.js +383 -102
  69. package/dist/cjs/wallet/unroll.js +7 -2
  70. package/dist/cjs/wallet/utils.js +60 -0
  71. package/dist/cjs/wallet/validation.js +151 -0
  72. package/dist/cjs/wallet/vtxo-manager.js +1 -1
  73. package/dist/cjs/wallet/wallet.js +702 -260
  74. package/dist/cjs/worker/browser/service-worker-manager.js +82 -0
  75. package/dist/cjs/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
  76. package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +78 -0
  77. package/dist/cjs/worker/expo/index.js +12 -0
  78. package/dist/cjs/worker/expo/processors/contractPollProcessor.js +61 -0
  79. package/dist/cjs/worker/expo/processors/index.js +6 -0
  80. package/dist/cjs/worker/expo/taskQueue.js +41 -0
  81. package/dist/cjs/worker/expo/taskRunner.js +57 -0
  82. package/dist/cjs/worker/messageBus.js +252 -0
  83. package/dist/esm/adapters/expo-db.js +27 -0
  84. package/dist/esm/asset/assetGroup.js +137 -0
  85. package/dist/esm/asset/assetId.js +84 -0
  86. package/dist/esm/asset/assetInput.js +199 -0
  87. package/dist/esm/asset/assetOutput.js +154 -0
  88. package/dist/esm/asset/assetRef.js +78 -0
  89. package/dist/esm/asset/index.js +8 -0
  90. package/dist/esm/asset/metadata.js +167 -0
  91. package/dist/esm/asset/packet.js +159 -0
  92. package/dist/esm/asset/types.js +22 -0
  93. package/dist/esm/asset/utils.js +99 -0
  94. package/dist/esm/contracts/arkcontract.js +141 -0
  95. package/dist/esm/contracts/contractManager.js +432 -0
  96. package/dist/esm/contracts/contractWatcher.js +563 -0
  97. package/dist/esm/contracts/handlers/default.js +82 -0
  98. package/dist/esm/contracts/handlers/delegate.js +86 -0
  99. package/dist/esm/contracts/handlers/helpers.js +66 -0
  100. package/dist/esm/contracts/handlers/index.js +12 -0
  101. package/dist/esm/contracts/handlers/registry.js +86 -0
  102. package/dist/esm/contracts/handlers/vhtlc.js +190 -0
  103. package/dist/esm/contracts/index.js +13 -0
  104. package/dist/esm/contracts/types.js +1 -0
  105. package/dist/esm/db/manager.js +92 -0
  106. package/dist/esm/forfeit.js +11 -8
  107. package/dist/esm/identity/index.js +1 -0
  108. package/dist/esm/identity/seedIdentity.js +249 -0
  109. package/dist/esm/index.js +25 -15
  110. package/dist/esm/intent/index.js +28 -2
  111. package/dist/esm/providers/ark.js +7 -0
  112. package/dist/esm/providers/delegator.js +62 -0
  113. package/dist/esm/providers/expoIndexer.js +5 -0
  114. package/dist/esm/providers/indexer.js +68 -1
  115. package/dist/esm/providers/onchain.js +2 -2
  116. package/dist/esm/providers/utils.js +1 -0
  117. package/dist/esm/repositories/contractRepository.js +1 -101
  118. package/dist/esm/repositories/inMemory/contractRepository.js +51 -0
  119. package/dist/esm/repositories/inMemory/walletRepository.js +76 -0
  120. package/dist/esm/repositories/index.js +8 -0
  121. package/dist/esm/repositories/indexedDB/contractRepository.js +183 -0
  122. package/dist/esm/repositories/indexedDB/db.js +42 -0
  123. package/dist/esm/repositories/indexedDB/schema.js +155 -0
  124. package/dist/esm/repositories/indexedDB/walletRepository.js +334 -0
  125. package/dist/esm/repositories/indexedDB/websqlAdapter.js +138 -0
  126. package/dist/esm/repositories/migrations/contractRepositoryImpl.js +121 -0
  127. package/dist/esm/repositories/migrations/fromStorageAdapter.js +58 -0
  128. package/dist/esm/repositories/migrations/walletRepositoryImpl.js +176 -0
  129. package/dist/esm/repositories/walletRepository.js +1 -167
  130. package/dist/esm/script/base.js +21 -1
  131. package/dist/esm/script/delegate.js +46 -0
  132. package/dist/esm/storage/asyncStorage.js +4 -1
  133. package/dist/esm/storage/fileSystem.js +3 -0
  134. package/dist/esm/storage/inMemory.js +3 -0
  135. package/dist/esm/storage/indexedDB.js +5 -1
  136. package/dist/esm/storage/localStorage.js +3 -0
  137. package/dist/esm/utils/arkTransaction.js +15 -0
  138. package/dist/esm/utils/transactionHistory.js +50 -0
  139. package/dist/esm/utils/txSizeEstimator.js +39 -14
  140. package/dist/esm/wallet/asset-manager.js +333 -0
  141. package/dist/esm/wallet/asset.js +111 -0
  142. package/dist/esm/wallet/batch.js +1 -1
  143. package/dist/esm/wallet/delegator.js +231 -0
  144. package/dist/esm/wallet/expo/background.js +128 -0
  145. package/dist/esm/wallet/expo/index.js +2 -0
  146. package/dist/esm/wallet/expo/wallet.js +194 -0
  147. package/dist/esm/wallet/onchain.js +57 -12
  148. package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +564 -0
  149. package/dist/esm/wallet/serviceWorker/wallet.js +382 -101
  150. package/dist/esm/wallet/unroll.js +7 -2
  151. package/dist/esm/wallet/utils.js +55 -0
  152. package/dist/esm/wallet/validation.js +139 -0
  153. package/dist/esm/wallet/vtxo-manager.js +1 -1
  154. package/dist/esm/wallet/wallet.js +704 -229
  155. package/dist/esm/worker/browser/service-worker-manager.js +76 -0
  156. package/dist/esm/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
  157. package/dist/esm/worker/expo/asyncStorageTaskQueue.js +74 -0
  158. package/dist/esm/worker/expo/index.js +4 -0
  159. package/dist/esm/worker/expo/processors/contractPollProcessor.js +58 -0
  160. package/dist/esm/worker/expo/processors/index.js +1 -0
  161. package/dist/esm/worker/expo/taskQueue.js +37 -0
  162. package/dist/esm/worker/expo/taskRunner.js +54 -0
  163. package/dist/esm/worker/messageBus.js +248 -0
  164. package/dist/types/adapters/expo-db.d.ts +7 -0
  165. package/dist/types/asset/assetGroup.d.ts +28 -0
  166. package/dist/types/asset/assetId.d.ts +19 -0
  167. package/dist/types/asset/assetInput.d.ts +46 -0
  168. package/dist/types/asset/assetOutput.d.ts +39 -0
  169. package/dist/types/asset/assetRef.d.ts +25 -0
  170. package/dist/types/asset/index.d.ts +8 -0
  171. package/dist/types/asset/metadata.d.ts +37 -0
  172. package/dist/types/asset/packet.d.ts +27 -0
  173. package/dist/types/asset/types.d.ts +18 -0
  174. package/dist/types/asset/utils.d.ts +21 -0
  175. package/dist/types/contracts/arkcontract.d.ts +101 -0
  176. package/dist/types/contracts/contractManager.d.ts +331 -0
  177. package/dist/types/contracts/contractWatcher.d.ts +192 -0
  178. package/dist/types/contracts/handlers/default.d.ts +19 -0
  179. package/dist/types/contracts/handlers/delegate.d.ts +21 -0
  180. package/dist/types/contracts/handlers/helpers.d.ts +18 -0
  181. package/dist/types/contracts/handlers/index.d.ts +7 -0
  182. package/dist/types/contracts/handlers/registry.d.ts +65 -0
  183. package/dist/types/contracts/handlers/vhtlc.d.ts +32 -0
  184. package/dist/types/contracts/index.d.ts +14 -0
  185. package/dist/types/contracts/types.d.ts +222 -0
  186. package/dist/types/db/manager.d.ts +22 -0
  187. package/dist/types/forfeit.d.ts +2 -1
  188. package/dist/types/identity/index.d.ts +1 -0
  189. package/dist/types/identity/seedIdentity.d.ts +128 -0
  190. package/dist/types/index.d.ts +21 -12
  191. package/dist/types/intent/index.d.ts +2 -1
  192. package/dist/types/providers/ark.d.ts +11 -2
  193. package/dist/types/providers/delegator.d.ts +29 -0
  194. package/dist/types/providers/indexer.d.ts +11 -1
  195. package/dist/types/repositories/contractRepository.d.ts +30 -19
  196. package/dist/types/repositories/inMemory/contractRepository.d.ts +17 -0
  197. package/dist/types/repositories/inMemory/walletRepository.d.ts +26 -0
  198. package/dist/types/repositories/index.d.ts +7 -0
  199. package/dist/types/repositories/indexedDB/contractRepository.d.ts +21 -0
  200. package/dist/types/repositories/indexedDB/db.d.ts +56 -0
  201. package/dist/types/repositories/indexedDB/schema.d.ts +8 -0
  202. package/dist/types/repositories/indexedDB/walletRepository.d.ts +25 -0
  203. package/dist/types/repositories/indexedDB/websqlAdapter.d.ts +49 -0
  204. package/dist/types/repositories/migrations/contractRepositoryImpl.d.ts +24 -0
  205. package/dist/types/repositories/migrations/fromStorageAdapter.d.ts +19 -0
  206. package/dist/types/repositories/migrations/walletRepositoryImpl.d.ts +27 -0
  207. package/dist/types/repositories/walletRepository.d.ts +13 -24
  208. package/dist/types/script/base.d.ts +1 -0
  209. package/dist/types/script/delegate.d.ts +36 -0
  210. package/dist/types/storage/asyncStorage.d.ts +4 -0
  211. package/dist/types/storage/fileSystem.d.ts +3 -0
  212. package/dist/types/storage/inMemory.d.ts +3 -0
  213. package/dist/types/storage/index.d.ts +3 -0
  214. package/dist/types/storage/indexedDB.d.ts +3 -0
  215. package/dist/types/storage/localStorage.d.ts +3 -0
  216. package/dist/types/utils/arkTransaction.d.ts +6 -0
  217. package/dist/types/utils/txSizeEstimator.d.ts +12 -2
  218. package/dist/types/wallet/asset-manager.d.ts +78 -0
  219. package/dist/types/wallet/asset.d.ts +21 -0
  220. package/dist/types/wallet/batch.d.ts +1 -1
  221. package/dist/types/wallet/delegator.d.ts +24 -0
  222. package/dist/types/wallet/expo/background.d.ts +66 -0
  223. package/dist/types/wallet/expo/index.d.ts +4 -0
  224. package/dist/types/wallet/expo/wallet.d.ts +97 -0
  225. package/dist/types/wallet/index.d.ts +75 -2
  226. package/dist/types/wallet/onchain.d.ts +22 -1
  227. package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +366 -0
  228. package/dist/types/wallet/serviceWorker/wallet.d.ts +20 -11
  229. package/dist/types/wallet/utils.d.ts +13 -1
  230. package/dist/types/wallet/validation.d.ts +24 -0
  231. package/dist/types/wallet/wallet.d.ts +111 -17
  232. package/dist/types/worker/browser/service-worker-manager.d.ts +21 -0
  233. package/dist/types/{wallet/serviceWorker → worker/browser}/utils.d.ts +2 -1
  234. package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +46 -0
  235. package/dist/types/worker/expo/index.d.ts +7 -0
  236. package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +14 -0
  237. package/dist/types/worker/expo/processors/index.d.ts +1 -0
  238. package/dist/types/worker/expo/taskQueue.d.ts +50 -0
  239. package/dist/types/worker/expo/taskRunner.d.ts +42 -0
  240. package/dist/types/worker/messageBus.d.ts +109 -0
  241. package/package.json +71 -17
  242. package/dist/cjs/wallet/serviceWorker/request.js +0 -78
  243. package/dist/cjs/wallet/serviceWorker/response.js +0 -222
  244. package/dist/cjs/wallet/serviceWorker/worker.js +0 -655
  245. package/dist/esm/wallet/serviceWorker/request.js +0 -75
  246. package/dist/esm/wallet/serviceWorker/response.js +0 -219
  247. package/dist/esm/wallet/serviceWorker/worker.js +0 -651
  248. package/dist/types/wallet/serviceWorker/request.d.ts +0 -74
  249. package/dist/types/wallet/serviceWorker/response.d.ts +0 -123
  250. package/dist/types/wallet/serviceWorker/worker.d.ts +0 -53
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ExpoWallet = void 0;
37
+ const base_1 = require("@scure/base");
38
+ const wallet_1 = require("../wallet");
39
+ const ark_1 = require("../../providers/ark");
40
+ const taskRunner_1 = require("../../worker/expo/taskRunner");
41
+ const processors_1 = require("../../worker/expo/processors");
42
+ const utils_1 = require("../utils");
43
+ const default_1 = require("../../script/default");
44
+ /**
45
+ * Expo/React Native wallet with built-in background task processing.
46
+ *
47
+ * Wraps a standard {@link Wallet} and adds a lightweight task queue
48
+ * for keeping contract/VTXO state fresh while the app is active and
49
+ * across Expo BackgroundTask wakes.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * import { ExpoWallet } from "@arkade-os/sdk/wallet/expo";
54
+ * import { AsyncStorageTaskQueue } from "@arkade-os/sdk/worker/expo";
55
+ *
56
+ * const wallet = await ExpoWallet.setup({
57
+ * identity: SingleKey.fromHex(privateKey),
58
+ * arkServerUrl,
59
+ * esploraUrl,
60
+ * storage: { walletRepository, contractRepository },
61
+ * background: {
62
+ * taskName: "ark-background-poll",
63
+ * taskQueue: new AsyncStorageTaskQueue(AsyncStorage),
64
+ * foregroundIntervalMs: 20_000,
65
+ * minimumBackgroundInterval: 15,
66
+ * },
67
+ * });
68
+ *
69
+ * const balance = await wallet.getBalance();
70
+ * ```
71
+ */
72
+ class ExpoWallet {
73
+ constructor(wallet, taskQueue, processors, deps, taskName, foregroundIntervalMs) {
74
+ this.wallet = wallet;
75
+ this.taskQueue = taskQueue;
76
+ this.processors = processors;
77
+ this.deps = deps;
78
+ this.identity = wallet.identity;
79
+ this.arkProvider = wallet.arkProvider;
80
+ this.indexerProvider = wallet.indexerProvider;
81
+ this.taskName = taskName;
82
+ if (foregroundIntervalMs && foregroundIntervalMs > 0) {
83
+ this.startForegroundPolling(foregroundIntervalMs);
84
+ }
85
+ }
86
+ /**
87
+ * Create an ExpoWallet with background task support.
88
+ *
89
+ * 1. Creates the inner {@link Wallet} via `Wallet.create()`.
90
+ * 2. Wires up processors (defaults to {@link contractPollProcessor}).
91
+ * 3. Persists background config for the background handler (if the queue supports it).
92
+ * 4. Seeds the task queue with a `contract-poll` task.
93
+ * 5. Registers the background task with the OS scheduler (if `minimumBackgroundInterval` is set).
94
+ * 6. Starts foreground polling if `foregroundIntervalMs` is set.
95
+ */
96
+ static async setup(config) {
97
+ const wallet = await wallet_1.Wallet.create(config);
98
+ const processors = config.background.processors ?? [
99
+ processors_1.contractPollProcessor,
100
+ ];
101
+ const deps = {
102
+ walletRepository: wallet.walletRepository,
103
+ contractRepository: wallet.contractRepository,
104
+ indexerProvider: wallet.indexerProvider,
105
+ arkProvider: wallet.arkProvider,
106
+ extendVtxo: (vtxo, contract) => {
107
+ if (contract) {
108
+ return (0, utils_1.extendVtxoFromContract)(vtxo, contract);
109
+ }
110
+ return (0, utils_1.extendVirtualCoin)(wallet, vtxo);
111
+ },
112
+ };
113
+ const { taskQueue } = config.background;
114
+ // Persist wallet params so the background handler can rehydrate
115
+ // without a network call. Only works with AsyncStorageTaskQueue.
116
+ if ("persistConfig" in taskQueue) {
117
+ const arkServerUrl = config.arkServerUrl ??
118
+ (wallet.arkProvider instanceof ark_1.RestArkProvider
119
+ ? wallet.arkProvider.serverUrl
120
+ : undefined);
121
+ if (arkServerUrl) {
122
+ const timelock = wallet.offchainTapscript.options.csvTimelock ??
123
+ default_1.DefaultVtxo.Script.DEFAULT_TIMELOCK;
124
+ const bgConfig = {
125
+ arkServerUrl,
126
+ pubkeyHex: base_1.hex.encode(wallet.offchainTapscript.options.pubKey),
127
+ serverPubKeyHex: base_1.hex.encode(wallet.offchainTapscript.options.serverPubKey),
128
+ exitTimelockValue: timelock.value.toString(),
129
+ exitTimelockType: timelock.type,
130
+ };
131
+ await taskQueue.persistConfig(bgConfig);
132
+ }
133
+ }
134
+ const expoWallet = new ExpoWallet(wallet, taskQueue, processors, deps, config.background.taskName, config.background.foregroundIntervalMs);
135
+ // Seed the queue so the first tick (or background wake) has work to do
136
+ await expoWallet.seedContractPollTask();
137
+ // Activate OS-level background scheduling
138
+ if (config.background.minimumBackgroundInterval) {
139
+ try {
140
+ const { registerExpoBackgroundTask } = await Promise.resolve().then(() => __importStar(require("./background")));
141
+ await registerExpoBackgroundTask(config.background.taskName, {
142
+ minimumInterval: config.background.minimumBackgroundInterval,
143
+ });
144
+ }
145
+ catch {
146
+ // expo-background-task not installed — foreground-only mode
147
+ }
148
+ }
149
+ return expoWallet;
150
+ }
151
+ // ── Foreground polling ───────────────────────────────────────────
152
+ startForegroundPolling(intervalMs) {
153
+ this.foregroundIntervalId = setInterval(() => {
154
+ this.runForegroundPoll().catch(console.error);
155
+ }, intervalMs);
156
+ }
157
+ async runForegroundPoll() {
158
+ await (0, taskRunner_1.runTasks)(this.taskQueue, this.processors, this.deps);
159
+ // Consume results immediately (no background handoff needed)
160
+ const results = await this.taskQueue.getResults();
161
+ if (results.length > 0) {
162
+ await this.taskQueue.acknowledgeResults(results.map((r) => r.id));
163
+ }
164
+ // Re-seed for the next tick
165
+ await this.seedContractPollTask();
166
+ }
167
+ async seedContractPollTask() {
168
+ const existing = await this.taskQueue.getTasks(processors_1.CONTRACT_POLL_TASK_TYPE);
169
+ if (existing.length > 0)
170
+ return;
171
+ const task = {
172
+ id: (0, utils_1.getRandomId)(),
173
+ type: processors_1.CONTRACT_POLL_TASK_TYPE,
174
+ data: {},
175
+ createdAt: Date.now(),
176
+ };
177
+ await this.taskQueue.addTask(task);
178
+ }
179
+ // ── Lifecycle ────────────────────────────────────────────────────
180
+ /**
181
+ * Stop foreground polling and unregister the background task.
182
+ */
183
+ async dispose() {
184
+ if (this.foregroundIntervalId) {
185
+ clearInterval(this.foregroundIntervalId);
186
+ this.foregroundIntervalId = undefined;
187
+ }
188
+ try {
189
+ const { unregisterExpoBackgroundTask } = await Promise.resolve().then(() => __importStar(require("./background")));
190
+ await unregisterExpoBackgroundTask(this.taskName);
191
+ }
192
+ catch {
193
+ // expo-background-task not installed — nothing to unregister
194
+ }
195
+ }
196
+ // ── IWallet delegation ───────────────────────────────────────────
197
+ getAddress() {
198
+ return this.wallet.getAddress();
199
+ }
200
+ getBoardingAddress() {
201
+ return this.wallet.getBoardingAddress();
202
+ }
203
+ getBalance() {
204
+ return this.wallet.getBalance();
205
+ }
206
+ getVtxos(filter) {
207
+ return this.wallet.getVtxos(filter);
208
+ }
209
+ getBoardingUtxos() {
210
+ return this.wallet.getBoardingUtxos();
211
+ }
212
+ getTransactionHistory() {
213
+ return this.wallet.getTransactionHistory();
214
+ }
215
+ getContractManager() {
216
+ return this.wallet.getContractManager();
217
+ }
218
+ sendBitcoin(params) {
219
+ return this.wallet.sendBitcoin(params);
220
+ }
221
+ settle(params, eventCallback) {
222
+ return this.wallet.settle(params, eventCallback);
223
+ }
224
+ send(...recipients) {
225
+ return this.wallet.send(...recipients);
226
+ }
227
+ get assetManager() {
228
+ return this.wallet.assetManager;
229
+ }
230
+ }
231
+ exports.ExpoWallet = ExpoWallet;
@@ -8,6 +8,7 @@ const onchain_1 = require("../providers/onchain");
8
8
  const anchor_1 = require("../utils/anchor");
9
9
  const txSizeEstimator_1 = require("../utils/txSizeEstimator");
10
10
  const transaction_1 = require("../utils/transaction");
11
+ const utils_1 = require("./utils");
11
12
  /**
12
13
  * Onchain Bitcoin wallet implementation for traditional Bitcoin transactions.
13
14
  *
@@ -59,11 +60,58 @@ class OnchainWallet {
59
60
  const onchainTotal = onchainConfirmed + onchainUnconfirmed;
60
61
  return onchainTotal;
61
62
  }
63
+ /**
64
+ * Iteratively selects coins and estimates transaction fees until convergence.
65
+ *
66
+ * This method handles the circular dependency between coin selection and fee
67
+ * estimation: the fee depends on transaction size, which depends on the number
68
+ * of inputs (selected coins) and whether a change output is needed.
69
+ *
70
+ * The algorithm iterates up to 10 times, refining the fee estimate based on
71
+ * the actual transaction structure. It resolves dust oscillation loops that
72
+ * occur when the change amount hovers near the dust threshold—adding/removing
73
+ * the change output causes the fee to fluctuate, preventing convergence.
74
+ * When a lower fee is computed (indicating the change output was dropped),
75
+ * the function accepts this state to guarantee termination.
76
+ *
77
+ * @param coins - Available coins to select from
78
+ * @param amount - Target send amount in satoshis
79
+ * @param feeRate - Fee rate in sat/vbyte
80
+ * @param recipientAddress - Destination address for size estimation
81
+ * @returns Selected inputs, change amount, and calculated fee
82
+ * @throws Error if fee estimation fails to converge within max iterations
83
+ */
84
+ estimateFeesAndSelectCoins(coins, amount, feeRate, recipientAddress) {
85
+ const MAX_ITERATIONS = 10;
86
+ let fee = 0;
87
+ for (let i = 0; i < MAX_ITERATIONS; i++) {
88
+ const totalNeeded = amount + fee;
89
+ const selected = selectCoins(coins, totalNeeded);
90
+ const estimator = txSizeEstimator_1.TxWeightEstimator.create();
91
+ for (const _ of selected.inputs) {
92
+ estimator.addKeySpendInput();
93
+ }
94
+ estimator.addOutputAddress(recipientAddress, this.network);
95
+ if (selected.changeAmount >= BigInt(utils_1.DUST_AMOUNT)) {
96
+ estimator.addOutputAddress(this.address, this.network);
97
+ }
98
+ const newFee = Number(estimator.vsize().value) * feeRate;
99
+ const roundedNewFee = Math.ceil(newFee);
100
+ // Prevent oscillation loops when change falls just below the dust limit.
101
+ // If removing the change output reduces the fee below our budget,
102
+ // we accept the valid transaction state to guarantee convergence.
103
+ if (roundedNewFee <= fee) {
104
+ return { ...selected, fee: roundedNewFee };
105
+ }
106
+ fee = roundedNewFee;
107
+ }
108
+ throw new Error("Fee estimation failed: could not converge");
109
+ }
62
110
  async send(params) {
63
111
  if (params.amount <= 0) {
64
112
  throw new Error("Amount must be positive");
65
113
  }
66
- if (params.amount < OnchainWallet.DUST_AMOUNT) {
114
+ if (params.amount < utils_1.DUST_AMOUNT) {
67
115
  throw new Error("Amount is below dust limit");
68
116
  }
69
117
  const coins = await this.getCoins();
@@ -74,15 +122,14 @@ class OnchainWallet {
74
122
  if (!feeRate || feeRate < OnchainWallet.MIN_FEE_RATE) {
75
123
  feeRate = OnchainWallet.MIN_FEE_RATE;
76
124
  }
77
- // Ensure fee is an integer by rounding up
78
- const estimatedFee = Math.ceil(174 * feeRate);
79
- const totalNeeded = params.amount + estimatedFee;
80
- // Select coins
81
- const selected = selectCoins(coins, totalNeeded);
125
+ const { inputs, changeAmount } = this.estimateFeesAndSelectCoins(coins, params.amount, feeRate, params.address);
126
+ if (!inputs) {
127
+ throw new Error("Fee estimation failed");
128
+ }
82
129
  // Create transaction
83
130
  let tx = new transaction_1.Transaction();
84
131
  // Add inputs
85
- for (const input of selected.inputs) {
132
+ for (const input of inputs) {
86
133
  tx.addInput({
87
134
  txid: input.txid,
88
135
  index: input.vout,
@@ -95,9 +142,8 @@ class OnchainWallet {
95
142
  }
96
143
  // Add payment output
97
144
  tx.addOutputAddress(params.address, BigInt(params.amount), this.network);
98
- // Add change output if needed
99
- if (selected.changeAmount > 0n) {
100
- tx.addOutputAddress(this.address, selected.changeAmount, this.network);
145
+ if (changeAmount >= BigInt(utils_1.DUST_AMOUNT)) {
146
+ tx.addOutputAddress(this.address, changeAmount, this.network);
101
147
  }
102
148
  // Sign inputs and Finalize
103
149
  tx = await this.identity.sign(tx);
@@ -116,7 +162,7 @@ class OnchainWallet {
116
162
  const childVsize = txSizeEstimator_1.TxWeightEstimator.create()
117
163
  .addKeySpendInput(true)
118
164
  .addP2AInput()
119
- .addP2TROutput()
165
+ .addOutputAddress(this.address, this.network)
120
166
  .vsize().value;
121
167
  const packageVSize = parentVsize + Number(childVsize);
122
168
  let feeRate = await this.provider.getFeeRate();
@@ -160,7 +206,6 @@ class OnchainWallet {
160
206
  }
161
207
  exports.OnchainWallet = OnchainWallet;
162
208
  OnchainWallet.MIN_FEE_RATE = 1; // sat/vbyte
163
- OnchainWallet.DUST_AMOUNT = 546; // sats
164
209
  /**
165
210
  * Select coins to reach a target amount, prioritizing those closer to expiry
166
211
  * @param coins List of coins to select from