@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,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAssetPacket = createAssetPacket;
4
+ exports.selectCoinsWithAsset = selectCoinsWithAsset;
5
+ exports.computeAssetChange = computeAssetChange;
6
+ exports.selectedCoinsToAssetInputs = selectedCoinsToAssetInputs;
7
+ const asset_1 = require("../asset");
8
+ /**
9
+ * Creates an asset packet from asset inputs and receivers.
10
+ * Groups inputs and outputs by asset ID and creates the Packet object
11
+ * @param assetInputs - map input index -> assets
12
+ * @param receivers - array of recipients with their asset allocations
13
+ * @param changeReceiver - (optional) change receiver containing remaining assets
14
+ * @returns packet containing all asset groups
15
+ */
16
+ function createAssetPacket(assetInputs, receivers, changeReceiver) {
17
+ // map inputs by asset id
18
+ const inputsByAssetId = new Map();
19
+ for (const [inputIndex, assets] of assetInputs) {
20
+ for (const asset of assets) {
21
+ const existing = inputsByAssetId.get(asset.assetId);
22
+ inputsByAssetId.set(asset.assetId, [
23
+ ...(existing ?? []),
24
+ asset_1.AssetInput.create(inputIndex, BigInt(asset.amount)),
25
+ ]);
26
+ }
27
+ }
28
+ // map outputs by asset id
29
+ const outputsByAssetId = new Map();
30
+ // track tx output index
31
+ let outputIndex = 0;
32
+ for (const receiver of receivers) {
33
+ if (receiver.assets) {
34
+ for (const asset of receiver.assets) {
35
+ const existing = outputsByAssetId.get(asset.assetId);
36
+ outputsByAssetId.set(asset.assetId, [
37
+ ...(existing ?? []),
38
+ asset_1.AssetOutput.create(outputIndex, BigInt(asset.amount)),
39
+ ]);
40
+ }
41
+ }
42
+ outputIndex++;
43
+ }
44
+ // add change receiver assets if present
45
+ if (changeReceiver?.assets) {
46
+ for (const asset of changeReceiver.assets) {
47
+ const existing = outputsByAssetId.get(asset.assetId);
48
+ outputsByAssetId.set(asset.assetId, [
49
+ ...(existing ?? []),
50
+ asset_1.AssetOutput.create(outputIndex, BigInt(asset.amount)),
51
+ ]);
52
+ }
53
+ }
54
+ const groups = [];
55
+ // get all unique asset ids from both inputs and outputs
56
+ const allAssetIds = new Set([
57
+ ...inputsByAssetId.keys(),
58
+ ...outputsByAssetId.keys(),
59
+ ]);
60
+ for (const assetIdStr of allAssetIds) {
61
+ const inputs = inputsByAssetId.get(assetIdStr);
62
+ const outputs = outputsByAssetId.get(assetIdStr);
63
+ const assetId = asset_1.AssetId.fromString(assetIdStr);
64
+ const group = asset_1.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
65
+ groups.push(group);
66
+ }
67
+ return asset_1.Packet.create(groups);
68
+ }
69
+ /**
70
+ * Selects coins that contain a specific asset.
71
+ * Returns coins sorted by amount (smallest first for better coin selection).
72
+ */
73
+ function selectCoinsWithAsset(coins, assetId, requiredAmount) {
74
+ // filter only coins that have the specified asset
75
+ const coinsWithAsset = coins.filter((coin) => coin.assets?.some((a) => a.assetId === assetId));
76
+ // sort by asset amount (smallest first for better selection)
77
+ coinsWithAsset.sort((a, b) => {
78
+ const amountA = a.assets?.find((asset) => asset.assetId === assetId)?.amount ?? 0;
79
+ const amountB = b.assets?.find((asset) => asset.assetId === assetId)?.amount ?? 0;
80
+ return amountA - amountB;
81
+ });
82
+ const selected = [];
83
+ let totalAssetAmount = 0n;
84
+ for (const coin of coinsWithAsset) {
85
+ if (totalAssetAmount >= requiredAmount)
86
+ break;
87
+ selected.push(coin);
88
+ const assetAmount = coin.assets?.find((a) => a.assetId === assetId)?.amount ?? 0;
89
+ totalAssetAmount += BigInt(assetAmount);
90
+ }
91
+ if (totalAssetAmount < requiredAmount) {
92
+ throw new Error(`Insufficient asset balance: have ${totalAssetAmount}, need ${requiredAmount}`);
93
+ }
94
+ return { selected, totalAssetAmount };
95
+ }
96
+ function computeAssetChange(inputAssets, outputAssets) {
97
+ const change = new Map();
98
+ for (const [assetId, inputAmount] of inputAssets) {
99
+ const outputAmount = outputAssets.get(assetId) ?? 0n;
100
+ const changeAmount = inputAmount - outputAmount;
101
+ if (changeAmount > 0n) {
102
+ change.set(assetId, changeAmount);
103
+ }
104
+ }
105
+ return change;
106
+ }
107
+ function selectedCoinsToAssetInputs(selectedCoins) {
108
+ const assetInputs = new Map();
109
+ for (let inputIndex = 0; inputIndex < selectedCoins.length; inputIndex++) {
110
+ const coin = selectedCoins[inputIndex];
111
+ if (!coin.assets || coin.assets.length === 0) {
112
+ continue;
113
+ }
114
+ assetInputs.set(inputIndex, coin.assets);
115
+ }
116
+ return assetInputs;
117
+ }
@@ -11,7 +11,7 @@ const base_1 = require("@scure/base");
11
11
  * @example
12
12
  * ```typescript
13
13
  * // use wallet handler or create a custom one
14
- * const handler = wallet.createBatchHandler(intentId, inputs, musig2session);
14
+ * const handler = wallet.createBatchHandler(intentId, inputs, expectedRecipients, musig2session);
15
15
  *
16
16
  * const abortController = new AbortController();
17
17
  * // Get event stream from Ark provider
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DelegatorManagerImpl = void 0;
4
+ const __1 = require("..");
5
+ const base_1 = require("@scure/base");
6
+ const base_2 = require("../script/base");
7
+ const forfeit_1 = require("../forfeit");
8
+ const btc_signer_1 = require("@scure/btc-signer");
9
+ const networks_1 = require("../networks");
10
+ class DelegatorManagerImpl {
11
+ constructor(delegatorProvider, arkInfoProvider, identity) {
12
+ this.delegatorProvider = delegatorProvider;
13
+ this.arkInfoProvider = arkInfoProvider;
14
+ this.identity = identity;
15
+ }
16
+ async delegate(vtxos, destination, delegateAt) {
17
+ if (vtxos.length === 0) {
18
+ return { delegated: [], failed: [] };
19
+ }
20
+ const destinationScript = __1.ArkAddress.decode(destination).pkScript;
21
+ // if explicit delegateAt is provided, delegate all vtxos at once without sorting
22
+ if (delegateAt) {
23
+ try {
24
+ await delegate(this.identity, this.delegatorProvider, this.arkInfoProvider, vtxos, destinationScript, delegateAt);
25
+ }
26
+ catch (error) {
27
+ return { delegated: [], failed: [{ outpoints: vtxos, error }] };
28
+ }
29
+ return { delegated: vtxos, failed: [] };
30
+ }
31
+ // if no explicit delegateAt is provided, sort vtxos by expiry and delegate in groups of the same expiry day
32
+ const groupByExpiry = new Map();
33
+ let recoverableVtxos = [];
34
+ for (const vtxo of vtxos) {
35
+ if ((0, __1.isRecoverable)(vtxo)) {
36
+ recoverableVtxos.push(vtxo);
37
+ continue;
38
+ }
39
+ const expiry = vtxo.virtualStatus.batchExpiry;
40
+ if (!expiry)
41
+ continue;
42
+ const dayKey = getDayTimestamp(expiry);
43
+ groupByExpiry.set(dayKey, [
44
+ ...(groupByExpiry.get(dayKey) ?? []),
45
+ vtxo,
46
+ ]);
47
+ }
48
+ // if no groups, it means we only need to delegate the recoverable vtxos
49
+ if (groupByExpiry.size === 0) {
50
+ try {
51
+ await delegate(this.identity, this.delegatorProvider, this.arkInfoProvider, recoverableVtxos, destinationScript, delegateAt);
52
+ }
53
+ catch (error) {
54
+ return {
55
+ delegated: [],
56
+ failed: [{ outpoints: recoverableVtxos, error }],
57
+ };
58
+ }
59
+ return { delegated: recoverableVtxos, failed: [] };
60
+ }
61
+ // search for the earliest group, include recoverable vtxos into it
62
+ const earliestGroup = Math.min(...groupByExpiry.keys());
63
+ groupByExpiry.set(earliestGroup, [
64
+ ...(groupByExpiry.get(earliestGroup) ?? []),
65
+ ...recoverableVtxos,
66
+ ]);
67
+ const groupsList = Array.from(groupByExpiry.entries());
68
+ const result = await Promise.allSettled(groupsList.map(async ([, vtxosGroup]) => delegate(this.identity, this.delegatorProvider, this.arkInfoProvider, vtxosGroup, destinationScript)));
69
+ const delegated = [];
70
+ const failed = [];
71
+ for (const [index, resultItem] of result.entries()) {
72
+ const vtxos = groupsList[index][1];
73
+ if (resultItem.status === "rejected") {
74
+ failed.push({ outpoints: vtxos, error: resultItem.reason });
75
+ continue;
76
+ }
77
+ delegated.push(...vtxos);
78
+ }
79
+ return { delegated, failed };
80
+ }
81
+ }
82
+ exports.DelegatorManagerImpl = DelegatorManagerImpl;
83
+ /**
84
+ * Delegates virtual coins to a delegator provider, allowing them to manage the coins renewal
85
+ * on behalf of the wallet.
86
+ * @param vtxos - Array of extended virtual coins to delegate. Must not be empty.
87
+ * @param delegateAt - Optional Date specifying when the delegation
88
+ * should occur. If not provided, defaults to 12 hours before the earliest
89
+ * expiry time of the provided vtxos.
90
+ */
91
+ async function delegate(identity, delegatorProvider, arkInfoProvider, vtxos, destinationScript, delegateAt) {
92
+ if (vtxos.length === 0) {
93
+ throw new Error("unable to delegate: no vtxos provided");
94
+ }
95
+ if (!delegatorProvider) {
96
+ throw new Error("unable to delegate: delegator provider not configured");
97
+ }
98
+ if (!delegateAt) {
99
+ const expiryTimestamp = vtxos
100
+ .filter((coin) => !(0, __1.isRecoverable)(coin) && coin.virtualStatus.batchExpiry)
101
+ .reduce((min, coin) => Math.min(min, coin.virtualStatus.batchExpiry), Number.MAX_SAFE_INTEGER);
102
+ if (!expiryTimestamp || expiryTimestamp === Number.MAX_SAFE_INTEGER) {
103
+ // if no expiry (recoverable vtxos), delegate 1 minute from now
104
+ delegateAt = new Date(Date.now() + 1 * 60 * 1000);
105
+ }
106
+ else {
107
+ const remainingTimeMs = expiryTimestamp - Date.now();
108
+ if (remainingTimeMs <= 0) {
109
+ delegateAt = new Date(Date.now() + 1 * 60 * 1000);
110
+ }
111
+ else {
112
+ // delegate 10% before the expiry
113
+ delegateAt = new Date(expiryTimestamp - remainingTimeMs * 0.1);
114
+ }
115
+ }
116
+ }
117
+ const { fees, dust, forfeitAddress, network } = await arkInfoProvider.getInfo();
118
+ const delegateAtSeconds = delegateAt.getTime() / 1000;
119
+ const estimator = new __1.Estimator({
120
+ ...fees.intentFee,
121
+ // replace now() function with the delegateAt timestamp
122
+ offchainInput: fees.intentFee.offchainInput?.replace("now()", `double(${delegateAtSeconds})`),
123
+ offchainOutput: fees.intentFee.offchainOutput?.replace("now()", `double(${delegateAtSeconds})`),
124
+ });
125
+ let amount = 0n;
126
+ for (const coin of vtxos) {
127
+ const inputFee = estimator.evalOffchainInput({
128
+ amount: BigInt(coin.value),
129
+ type: "vtxo",
130
+ weight: 0,
131
+ birth: coin.createdAt,
132
+ expiry: coin.virtualStatus.batchExpiry
133
+ ? new Date(coin.virtualStatus.batchExpiry)
134
+ : undefined,
135
+ });
136
+ if (inputFee.value >= coin.value) {
137
+ continue;
138
+ }
139
+ amount += BigInt(coin.value) - BigInt(inputFee.value);
140
+ }
141
+ const { delegatorAddress, pubkey, fee } = await delegatorProvider.getDelegateInfo();
142
+ const outputs = [];
143
+ const delegatorFee = BigInt(Number(fee));
144
+ if (delegatorFee > 0n) {
145
+ outputs.push({
146
+ script: __1.ArkAddress.decode(delegatorAddress).pkScript,
147
+ amount: delegatorFee,
148
+ });
149
+ }
150
+ const outputFee = outputs.reduce((fee, output) => {
151
+ if (!output.amount || !output.script)
152
+ return fee;
153
+ return (fee +
154
+ estimator.evalOffchainOutput({
155
+ amount: output.amount,
156
+ script: base_1.hex.encode(output.script),
157
+ }).satoshis);
158
+ }, 0);
159
+ if (amount - BigInt(outputFee) <= dust) {
160
+ throw new Error("Amount is below dust limit, cannot delegate");
161
+ }
162
+ amount -= BigInt(outputFee);
163
+ amount -= delegatorFee;
164
+ if (amount <= dust) {
165
+ throw new Error("Amount is below dust limit, cannot delegate");
166
+ }
167
+ outputs.push({
168
+ script: destinationScript,
169
+ amount: amount,
170
+ });
171
+ const registerIntent = await makeSignedDelegateIntent(identity, vtxos, outputs, [], [pubkey], delegateAtSeconds);
172
+ const forfeitOutputScript = btc_signer_1.OutScript.encode((0, btc_signer_1.Address)((0, networks_1.getNetwork)(network)).decode(forfeitAddress));
173
+ const forfeits = await Promise.all(vtxos
174
+ .filter((v) => !(0, __1.isRecoverable)(v))
175
+ .map(async (coin) => {
176
+ const forfeit = await makeDelegateForfeitTx(coin, dust, pubkey, forfeitOutputScript, identity);
177
+ return base_1.base64.encode(forfeit.toPSBT());
178
+ }));
179
+ await delegatorProvider.delegate(registerIntent, forfeits);
180
+ }
181
+ async function makeDelegateForfeitTx(input, connectorAmount, delegatePubkey, forfeitOutputScript, identity) {
182
+ if (delegatePubkey.length === 66) {
183
+ delegatePubkey = delegatePubkey.slice(2);
184
+ }
185
+ const vtxoScript = __1.VtxoScript.decode(input.tapTree);
186
+ const delegateTapLeaf = vtxoScript.leaves.find((tapLeaf) => {
187
+ const arkTapscript = (0, __1.decodeTapscript)((0, base_2.scriptFromTapLeafScript)(tapLeaf));
188
+ if (!__1.MultisigTapscript.is(arkTapscript))
189
+ return false;
190
+ if (!arkTapscript.params.pubkeys
191
+ .map(base_1.hex.encode)
192
+ .includes(delegatePubkey))
193
+ return false;
194
+ return true;
195
+ });
196
+ if (!delegateTapLeaf) {
197
+ throw new Error(`delegate tap leaf not found for input: ${input.txid}:${input.vout}`);
198
+ }
199
+ const tx = (0, forfeit_1.buildForfeitTxWithOutput)([
200
+ {
201
+ txid: input.txid,
202
+ index: input.vout,
203
+ witnessUtxo: {
204
+ amount: BigInt(input.value),
205
+ script: __1.VtxoScript.decode(input.tapTree).pkScript,
206
+ },
207
+ sighashType: btc_signer_1.SigHash.ALL_ANYONECANPAY,
208
+ tapLeafScript: [delegateTapLeaf],
209
+ },
210
+ ], {
211
+ script: forfeitOutputScript,
212
+ amount: BigInt(input.value) + connectorAmount,
213
+ });
214
+ return identity.sign(tx);
215
+ }
216
+ async function makeSignedDelegateIntent(identity, coins, outputs, onchainOutputsIndexes, cosignerPubKeys, validAt) {
217
+ const message = {
218
+ type: "register",
219
+ onchain_output_indexes: onchainOutputsIndexes,
220
+ valid_at: Math.floor(validAt),
221
+ expire_at: 0,
222
+ cosigners_public_keys: cosignerPubKeys,
223
+ };
224
+ const proof = __1.Intent.create(message, coins, outputs);
225
+ const signedProof = await identity.sign(proof);
226
+ return {
227
+ proof: base_1.base64.encode(signedProof.toPSBT()),
228
+ message,
229
+ };
230
+ }
231
+ function getDayTimestamp(timestamp) {
232
+ const date = new Date(timestamp);
233
+ date.setUTCHours(0, 0, 0, 0);
234
+ return date.getTime();
235
+ }
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defineExpoBackgroundTask = defineExpoBackgroundTask;
4
+ exports.registerExpoBackgroundTask = registerExpoBackgroundTask;
5
+ exports.unregisterExpoBackgroundTask = unregisterExpoBackgroundTask;
6
+ const base_1 = require("@scure/base");
7
+ const taskRunner_1 = require("../../worker/expo/taskRunner");
8
+ const processors_1 = require("../../worker/expo/processors");
9
+ const default_1 = require("../../script/default");
10
+ const expoArk_1 = require("../../providers/expoArk");
11
+ const expoIndexer_1 = require("../../providers/expoIndexer");
12
+ const utils_1 = require("../utils");
13
+ function requireTaskManager() {
14
+ try {
15
+ return require("expo-task-manager");
16
+ }
17
+ catch {
18
+ throw new Error("expo-task-manager is required for background tasks. " +
19
+ "Install it with: npx expo install expo-task-manager");
20
+ }
21
+ }
22
+ function requireBackgroundTask() {
23
+ try {
24
+ return require("expo-background-task");
25
+ }
26
+ catch {
27
+ throw new Error("expo-background-task is required for background tasks. " +
28
+ "Install it with: npx expo install expo-background-task");
29
+ }
30
+ }
31
+ /**
32
+ * Define the Expo background task handler.
33
+ *
34
+ * **Must be called at module/global scope** (before React mounts).
35
+ * Internally calls `TaskManager.defineTask()`.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * // At the top of your app entry file
40
+ * import { defineExpoBackgroundTask } from "@arkade-os/sdk/wallet/expo";
41
+ * import { AsyncStorageTaskQueue } from "@arkade-os/sdk/worker/expo";
42
+ * import AsyncStorage from "@react-native-async-storage/async-storage";
43
+ *
44
+ * const taskQueue = new AsyncStorageTaskQueue(AsyncStorage);
45
+ * defineExpoBackgroundTask("ark-background-poll", {
46
+ * taskQueue,
47
+ * walletRepository: new IndexedDBWalletRepository(),
48
+ * contractRepository: new IndexedDBContractRepository(),
49
+ * });
50
+ * ```
51
+ */
52
+ function defineExpoBackgroundTask(taskName, options) {
53
+ const TaskManager = requireTaskManager();
54
+ const BackgroundTask = requireBackgroundTask();
55
+ const { taskQueue, walletRepository, contractRepository, processors = [processors_1.contractPollProcessor], } = options;
56
+ TaskManager.defineTask(taskName, async () => {
57
+ try {
58
+ const config = await taskQueue.loadConfig();
59
+ if (!config) {
60
+ // No config persisted yet — ExpoWallet.setup() hasn't run.
61
+ // Nothing to do.
62
+ return BackgroundTask.BackgroundTaskResult.Success;
63
+ }
64
+ // Reconstruct providers
65
+ const indexerProvider = new expoIndexer_1.ExpoIndexerProvider(config.arkServerUrl);
66
+ const arkProvider = new expoArk_1.ExpoArkProvider(config.arkServerUrl);
67
+ // Reconstruct default offchainTapscript as fallback
68
+ // for VTXOs not associated with a contract.
69
+ const defaultTapscript = new default_1.DefaultVtxo.Script({
70
+ pubKey: base_1.hex.decode(config.pubkeyHex),
71
+ serverPubKey: base_1.hex.decode(config.serverPubKeyHex),
72
+ csvTimelock: {
73
+ value: BigInt(config.exitTimelockValue),
74
+ type: config.exitTimelockType,
75
+ },
76
+ });
77
+ await (0, taskRunner_1.runTasks)(taskQueue, processors, {
78
+ walletRepository,
79
+ contractRepository,
80
+ indexerProvider,
81
+ arkProvider,
82
+ extendVtxo: (vtxo, contract) => {
83
+ if (contract) {
84
+ return (0, utils_1.extendVtxoFromContract)(vtxo, contract);
85
+ }
86
+ return (0, utils_1.extendVirtualCoin)({ offchainTapscript: defaultTapscript }, vtxo);
87
+ },
88
+ });
89
+ // Acknowledge outbox results (no foreground to consume them)
90
+ const results = await taskQueue.getResults();
91
+ if (results.length > 0) {
92
+ await taskQueue.acknowledgeResults(results.map((r) => r.id));
93
+ }
94
+ // Re-seed the contract-poll task for the next OS wake
95
+ const existing = await taskQueue.getTasks(processors_1.CONTRACT_POLL_TASK_TYPE);
96
+ if (existing.length === 0) {
97
+ const task = {
98
+ id: (0, utils_1.getRandomId)(),
99
+ type: processors_1.CONTRACT_POLL_TASK_TYPE,
100
+ data: {},
101
+ createdAt: Date.now(),
102
+ };
103
+ await taskQueue.addTask(task);
104
+ }
105
+ return BackgroundTask.BackgroundTaskResult.Success;
106
+ }
107
+ catch (error) {
108
+ console.error("[ark-sdk] Background task failed:", error instanceof Error ? error.message : error);
109
+ return BackgroundTask.BackgroundTaskResult.Failed;
110
+ }
111
+ });
112
+ }
113
+ /**
114
+ * Activate the OS-level background task scheduler.
115
+ *
116
+ * Call this after {@link defineExpoBackgroundTask} (typically inside
117
+ * {@link ExpoWallet.setup} or in a React component after wallet init).
118
+ *
119
+ * @param minimumInterval - Minimum interval in minutes (default 15).
120
+ */
121
+ async function registerExpoBackgroundTask(taskName, options) {
122
+ const BackgroundTask = requireBackgroundTask();
123
+ await BackgroundTask.registerTaskAsync(taskName, {
124
+ minimumInterval: (options?.minimumInterval ?? 15) * 60,
125
+ });
126
+ }
127
+ /**
128
+ * Unregister the background task from the OS scheduler.
129
+ */
130
+ async function unregisterExpoBackgroundTask(taskName) {
131
+ const BackgroundTask = requireBackgroundTask();
132
+ await BackgroundTask.unregisterTaskAsync(taskName);
133
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unregisterExpoBackgroundTask = exports.registerExpoBackgroundTask = exports.defineExpoBackgroundTask = exports.ExpoWallet = void 0;
4
+ var wallet_1 = require("./wallet");
5
+ Object.defineProperty(exports, "ExpoWallet", { enumerable: true, get: function () { return wallet_1.ExpoWallet; } });
6
+ var background_1 = require("./background");
7
+ Object.defineProperty(exports, "defineExpoBackgroundTask", { enumerable: true, get: function () { return background_1.defineExpoBackgroundTask; } });
8
+ Object.defineProperty(exports, "registerExpoBackgroundTask", { enumerable: true, get: function () { return background_1.registerExpoBackgroundTask; } });
9
+ Object.defineProperty(exports, "unregisterExpoBackgroundTask", { enumerable: true, get: function () { return background_1.unregisterExpoBackgroundTask; } });