@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.
- package/README.md +483 -54
- package/dist/cjs/adapters/expo-db.js +35 -0
- package/dist/cjs/asset/assetGroup.js +141 -0
- package/dist/cjs/asset/assetId.js +88 -0
- package/dist/cjs/asset/assetInput.js +204 -0
- package/dist/cjs/asset/assetOutput.js +159 -0
- package/dist/cjs/asset/assetRef.js +82 -0
- package/dist/cjs/asset/index.js +24 -0
- package/dist/cjs/asset/metadata.js +172 -0
- package/dist/cjs/asset/packet.js +164 -0
- package/dist/cjs/asset/types.js +25 -0
- package/dist/cjs/asset/utils.js +105 -0
- package/dist/cjs/contracts/arkcontract.js +148 -0
- package/dist/cjs/contracts/contractManager.js +436 -0
- package/dist/cjs/contracts/contractWatcher.js +567 -0
- package/dist/cjs/contracts/handlers/default.js +85 -0
- package/dist/cjs/contracts/handlers/delegate.js +89 -0
- package/dist/cjs/contracts/handlers/helpers.js +105 -0
- package/dist/cjs/contracts/handlers/index.js +19 -0
- package/dist/cjs/contracts/handlers/registry.js +89 -0
- package/dist/cjs/contracts/handlers/vhtlc.js +193 -0
- package/dist/cjs/contracts/index.js +41 -0
- package/dist/cjs/contracts/types.js +2 -0
- package/dist/cjs/db/manager.js +97 -0
- package/dist/cjs/forfeit.js +12 -8
- package/dist/cjs/identity/index.js +1 -0
- package/dist/cjs/identity/seedIdentity.js +255 -0
- package/dist/cjs/index.js +70 -14
- package/dist/cjs/intent/index.js +28 -2
- package/dist/cjs/providers/ark.js +7 -0
- package/dist/cjs/providers/delegator.js +66 -0
- package/dist/cjs/providers/expoIndexer.js +5 -0
- package/dist/cjs/providers/indexer.js +68 -1
- package/dist/cjs/providers/onchain.js +2 -2
- package/dist/cjs/providers/utils.js +1 -0
- package/dist/cjs/repositories/contractRepository.js +0 -103
- package/dist/cjs/repositories/inMemory/contractRepository.js +55 -0
- package/dist/cjs/repositories/inMemory/walletRepository.js +80 -0
- package/dist/cjs/repositories/index.js +16 -0
- package/dist/cjs/repositories/indexedDB/contractRepository.js +187 -0
- package/dist/cjs/repositories/indexedDB/db.js +57 -0
- package/dist/cjs/repositories/indexedDB/schema.js +159 -0
- package/dist/cjs/repositories/indexedDB/walletRepository.js +338 -0
- package/dist/cjs/repositories/indexedDB/websqlAdapter.js +144 -0
- package/dist/cjs/repositories/migrations/contractRepositoryImpl.js +127 -0
- package/dist/cjs/repositories/migrations/fromStorageAdapter.js +66 -0
- package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +180 -0
- package/dist/cjs/repositories/walletRepository.js +0 -169
- package/dist/cjs/script/base.js +54 -0
- package/dist/cjs/script/delegate.js +49 -0
- package/dist/cjs/storage/asyncStorage.js +4 -1
- package/dist/cjs/storage/fileSystem.js +3 -0
- package/dist/cjs/storage/inMemory.js +3 -0
- package/dist/cjs/storage/indexedDB.js +5 -1
- package/dist/cjs/storage/localStorage.js +3 -0
- package/dist/cjs/utils/arkTransaction.js +16 -0
- package/dist/cjs/utils/transactionHistory.js +50 -0
- package/dist/cjs/utils/txSizeEstimator.js +39 -14
- package/dist/cjs/wallet/asset-manager.js +338 -0
- package/dist/cjs/wallet/asset.js +117 -0
- package/dist/cjs/wallet/batch.js +1 -1
- package/dist/cjs/wallet/delegator.js +235 -0
- package/dist/cjs/wallet/expo/background.js +133 -0
- package/dist/cjs/wallet/expo/index.js +9 -0
- package/dist/cjs/wallet/expo/wallet.js +231 -0
- package/dist/cjs/wallet/onchain.js +57 -12
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +568 -0
- package/dist/cjs/wallet/serviceWorker/wallet.js +383 -102
- package/dist/cjs/wallet/unroll.js +7 -2
- package/dist/cjs/wallet/utils.js +60 -0
- package/dist/cjs/wallet/validation.js +151 -0
- package/dist/cjs/wallet/vtxo-manager.js +1 -1
- package/dist/cjs/wallet/wallet.js +702 -260
- package/dist/cjs/worker/browser/service-worker-manager.js +82 -0
- package/dist/cjs/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
- package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +78 -0
- package/dist/cjs/worker/expo/index.js +12 -0
- package/dist/cjs/worker/expo/processors/contractPollProcessor.js +61 -0
- package/dist/cjs/worker/expo/processors/index.js +6 -0
- package/dist/cjs/worker/expo/taskQueue.js +41 -0
- package/dist/cjs/worker/expo/taskRunner.js +57 -0
- package/dist/cjs/worker/messageBus.js +252 -0
- package/dist/esm/adapters/expo-db.js +27 -0
- package/dist/esm/asset/assetGroup.js +137 -0
- package/dist/esm/asset/assetId.js +84 -0
- package/dist/esm/asset/assetInput.js +199 -0
- package/dist/esm/asset/assetOutput.js +154 -0
- package/dist/esm/asset/assetRef.js +78 -0
- package/dist/esm/asset/index.js +8 -0
- package/dist/esm/asset/metadata.js +167 -0
- package/dist/esm/asset/packet.js +159 -0
- package/dist/esm/asset/types.js +22 -0
- package/dist/esm/asset/utils.js +99 -0
- package/dist/esm/contracts/arkcontract.js +141 -0
- package/dist/esm/contracts/contractManager.js +432 -0
- package/dist/esm/contracts/contractWatcher.js +563 -0
- package/dist/esm/contracts/handlers/default.js +82 -0
- package/dist/esm/contracts/handlers/delegate.js +86 -0
- package/dist/esm/contracts/handlers/helpers.js +66 -0
- package/dist/esm/contracts/handlers/index.js +12 -0
- package/dist/esm/contracts/handlers/registry.js +86 -0
- package/dist/esm/contracts/handlers/vhtlc.js +190 -0
- package/dist/esm/contracts/index.js +13 -0
- package/dist/esm/contracts/types.js +1 -0
- package/dist/esm/db/manager.js +92 -0
- package/dist/esm/forfeit.js +11 -8
- package/dist/esm/identity/index.js +1 -0
- package/dist/esm/identity/seedIdentity.js +249 -0
- package/dist/esm/index.js +25 -15
- package/dist/esm/intent/index.js +28 -2
- package/dist/esm/providers/ark.js +7 -0
- package/dist/esm/providers/delegator.js +62 -0
- package/dist/esm/providers/expoIndexer.js +5 -0
- package/dist/esm/providers/indexer.js +68 -1
- package/dist/esm/providers/onchain.js +2 -2
- package/dist/esm/providers/utils.js +1 -0
- package/dist/esm/repositories/contractRepository.js +1 -101
- package/dist/esm/repositories/inMemory/contractRepository.js +51 -0
- package/dist/esm/repositories/inMemory/walletRepository.js +76 -0
- package/dist/esm/repositories/index.js +8 -0
- package/dist/esm/repositories/indexedDB/contractRepository.js +183 -0
- package/dist/esm/repositories/indexedDB/db.js +42 -0
- package/dist/esm/repositories/indexedDB/schema.js +155 -0
- package/dist/esm/repositories/indexedDB/walletRepository.js +334 -0
- package/dist/esm/repositories/indexedDB/websqlAdapter.js +138 -0
- package/dist/esm/repositories/migrations/contractRepositoryImpl.js +121 -0
- package/dist/esm/repositories/migrations/fromStorageAdapter.js +58 -0
- package/dist/esm/repositories/migrations/walletRepositoryImpl.js +176 -0
- package/dist/esm/repositories/walletRepository.js +1 -167
- package/dist/esm/script/base.js +21 -1
- package/dist/esm/script/delegate.js +46 -0
- package/dist/esm/storage/asyncStorage.js +4 -1
- package/dist/esm/storage/fileSystem.js +3 -0
- package/dist/esm/storage/inMemory.js +3 -0
- package/dist/esm/storage/indexedDB.js +5 -1
- package/dist/esm/storage/localStorage.js +3 -0
- package/dist/esm/utils/arkTransaction.js +15 -0
- package/dist/esm/utils/transactionHistory.js +50 -0
- package/dist/esm/utils/txSizeEstimator.js +39 -14
- package/dist/esm/wallet/asset-manager.js +333 -0
- package/dist/esm/wallet/asset.js +111 -0
- package/dist/esm/wallet/batch.js +1 -1
- package/dist/esm/wallet/delegator.js +231 -0
- package/dist/esm/wallet/expo/background.js +128 -0
- package/dist/esm/wallet/expo/index.js +2 -0
- package/dist/esm/wallet/expo/wallet.js +194 -0
- package/dist/esm/wallet/onchain.js +57 -12
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +564 -0
- package/dist/esm/wallet/serviceWorker/wallet.js +382 -101
- package/dist/esm/wallet/unroll.js +7 -2
- package/dist/esm/wallet/utils.js +55 -0
- package/dist/esm/wallet/validation.js +139 -0
- package/dist/esm/wallet/vtxo-manager.js +1 -1
- package/dist/esm/wallet/wallet.js +704 -229
- package/dist/esm/worker/browser/service-worker-manager.js +76 -0
- package/dist/esm/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
- package/dist/esm/worker/expo/asyncStorageTaskQueue.js +74 -0
- package/dist/esm/worker/expo/index.js +4 -0
- package/dist/esm/worker/expo/processors/contractPollProcessor.js +58 -0
- package/dist/esm/worker/expo/processors/index.js +1 -0
- package/dist/esm/worker/expo/taskQueue.js +37 -0
- package/dist/esm/worker/expo/taskRunner.js +54 -0
- package/dist/esm/worker/messageBus.js +248 -0
- package/dist/types/adapters/expo-db.d.ts +7 -0
- package/dist/types/asset/assetGroup.d.ts +28 -0
- package/dist/types/asset/assetId.d.ts +19 -0
- package/dist/types/asset/assetInput.d.ts +46 -0
- package/dist/types/asset/assetOutput.d.ts +39 -0
- package/dist/types/asset/assetRef.d.ts +25 -0
- package/dist/types/asset/index.d.ts +8 -0
- package/dist/types/asset/metadata.d.ts +37 -0
- package/dist/types/asset/packet.d.ts +27 -0
- package/dist/types/asset/types.d.ts +18 -0
- package/dist/types/asset/utils.d.ts +21 -0
- package/dist/types/contracts/arkcontract.d.ts +101 -0
- package/dist/types/contracts/contractManager.d.ts +331 -0
- package/dist/types/contracts/contractWatcher.d.ts +192 -0
- package/dist/types/contracts/handlers/default.d.ts +19 -0
- package/dist/types/contracts/handlers/delegate.d.ts +21 -0
- package/dist/types/contracts/handlers/helpers.d.ts +18 -0
- package/dist/types/contracts/handlers/index.d.ts +7 -0
- package/dist/types/contracts/handlers/registry.d.ts +65 -0
- package/dist/types/contracts/handlers/vhtlc.d.ts +32 -0
- package/dist/types/contracts/index.d.ts +14 -0
- package/dist/types/contracts/types.d.ts +222 -0
- package/dist/types/db/manager.d.ts +22 -0
- package/dist/types/forfeit.d.ts +2 -1
- package/dist/types/identity/index.d.ts +1 -0
- package/dist/types/identity/seedIdentity.d.ts +128 -0
- package/dist/types/index.d.ts +21 -12
- package/dist/types/intent/index.d.ts +2 -1
- package/dist/types/providers/ark.d.ts +11 -2
- package/dist/types/providers/delegator.d.ts +29 -0
- package/dist/types/providers/indexer.d.ts +11 -1
- package/dist/types/repositories/contractRepository.d.ts +30 -19
- package/dist/types/repositories/inMemory/contractRepository.d.ts +17 -0
- package/dist/types/repositories/inMemory/walletRepository.d.ts +26 -0
- package/dist/types/repositories/index.d.ts +7 -0
- package/dist/types/repositories/indexedDB/contractRepository.d.ts +21 -0
- package/dist/types/repositories/indexedDB/db.d.ts +56 -0
- package/dist/types/repositories/indexedDB/schema.d.ts +8 -0
- package/dist/types/repositories/indexedDB/walletRepository.d.ts +25 -0
- package/dist/types/repositories/indexedDB/websqlAdapter.d.ts +49 -0
- package/dist/types/repositories/migrations/contractRepositoryImpl.d.ts +24 -0
- package/dist/types/repositories/migrations/fromStorageAdapter.d.ts +19 -0
- package/dist/types/repositories/migrations/walletRepositoryImpl.d.ts +27 -0
- package/dist/types/repositories/walletRepository.d.ts +13 -24
- package/dist/types/script/base.d.ts +1 -0
- package/dist/types/script/delegate.d.ts +36 -0
- package/dist/types/storage/asyncStorage.d.ts +4 -0
- package/dist/types/storage/fileSystem.d.ts +3 -0
- package/dist/types/storage/inMemory.d.ts +3 -0
- package/dist/types/storage/index.d.ts +3 -0
- package/dist/types/storage/indexedDB.d.ts +3 -0
- package/dist/types/storage/localStorage.d.ts +3 -0
- package/dist/types/utils/arkTransaction.d.ts +6 -0
- package/dist/types/utils/txSizeEstimator.d.ts +12 -2
- package/dist/types/wallet/asset-manager.d.ts +78 -0
- package/dist/types/wallet/asset.d.ts +21 -0
- package/dist/types/wallet/batch.d.ts +1 -1
- package/dist/types/wallet/delegator.d.ts +24 -0
- package/dist/types/wallet/expo/background.d.ts +66 -0
- package/dist/types/wallet/expo/index.d.ts +4 -0
- package/dist/types/wallet/expo/wallet.d.ts +97 -0
- package/dist/types/wallet/index.d.ts +75 -2
- package/dist/types/wallet/onchain.d.ts +22 -1
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +366 -0
- package/dist/types/wallet/serviceWorker/wallet.d.ts +20 -11
- package/dist/types/wallet/utils.d.ts +13 -1
- package/dist/types/wallet/validation.d.ts +24 -0
- package/dist/types/wallet/wallet.d.ts +111 -17
- package/dist/types/worker/browser/service-worker-manager.d.ts +21 -0
- package/dist/types/{wallet/serviceWorker → worker/browser}/utils.d.ts +2 -1
- package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +46 -0
- package/dist/types/worker/expo/index.d.ts +7 -0
- package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +14 -0
- package/dist/types/worker/expo/processors/index.d.ts +1 -0
- package/dist/types/worker/expo/taskQueue.d.ts +50 -0
- package/dist/types/worker/expo/taskRunner.d.ts +42 -0
- package/dist/types/worker/messageBus.d.ts +109 -0
- package/package.json +71 -17
- package/dist/cjs/wallet/serviceWorker/request.js +0 -78
- package/dist/cjs/wallet/serviceWorker/response.js +0 -222
- package/dist/cjs/wallet/serviceWorker/worker.js +0 -655
- package/dist/esm/wallet/serviceWorker/request.js +0 -75
- package/dist/esm/wallet/serviceWorker/response.js +0 -219
- package/dist/esm/wallet/serviceWorker/worker.js +0 -651
- package/dist/types/wallet/serviceWorker/request.d.ts +0 -74
- package/dist/types/wallet/serviceWorker/response.d.ts +0 -123
- package/dist/types/wallet/serviceWorker/worker.d.ts +0 -53
|
@@ -0,0 +1,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
|
+
}
|
package/dist/cjs/wallet/batch.js
CHANGED
|
@@ -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; } });
|