@arkade-os/sdk 0.4.17 → 0.4.18
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 +16 -6
- package/dist/cjs/contracts/arkcontract.js +0 -2
- package/dist/cjs/contracts/contractManager.js +111 -215
- package/dist/cjs/contracts/contractWatcher.js +86 -115
- package/dist/cjs/repositories/indexedDB/manager.js +6 -3
- package/dist/cjs/repositories/indexedDB/schema.js +47 -2
- package/dist/cjs/repositories/indexedDB/walletRepository.js +21 -2
- package/dist/cjs/repositories/realm/contractRepository.js +0 -4
- package/dist/cjs/repositories/realm/index.js +3 -1
- package/dist/cjs/repositories/realm/schemas.js +50 -1
- package/dist/cjs/repositories/realm/walletRepository.js +8 -4
- package/dist/cjs/repositories/scriptFromAddress.js +16 -0
- package/dist/cjs/repositories/sqlite/contractRepository.js +2 -6
- package/dist/cjs/repositories/sqlite/walletRepository.js +121 -33
- package/dist/cjs/utils/syncCursors.js +48 -56
- package/dist/cjs/wallet/expo/background.js +0 -13
- package/dist/cjs/wallet/expo/wallet.js +1 -6
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +16 -7
- package/dist/cjs/wallet/serviceWorker/wallet.js +19 -0
- package/dist/cjs/wallet/utils.js +41 -10
- package/dist/cjs/wallet/vtxo-manager.js +153 -39
- package/dist/cjs/wallet/wallet.js +72 -195
- package/dist/cjs/worker/expo/processors/contractPollProcessor.js +9 -13
- package/dist/cjs/worker/expo/taskRunner.js +2 -11
- package/dist/esm/contracts/arkcontract.js +0 -2
- package/dist/esm/contracts/contractManager.js +113 -217
- package/dist/esm/contracts/contractWatcher.js +86 -115
- package/dist/esm/repositories/indexedDB/manager.js +6 -3
- package/dist/esm/repositories/indexedDB/schema.js +46 -2
- package/dist/esm/repositories/indexedDB/walletRepository.js +21 -2
- package/dist/esm/repositories/realm/contractRepository.js +0 -4
- package/dist/esm/repositories/realm/index.js +1 -1
- package/dist/esm/repositories/realm/schemas.js +48 -0
- package/dist/esm/repositories/realm/walletRepository.js +8 -4
- package/dist/esm/repositories/scriptFromAddress.js +13 -0
- package/dist/esm/repositories/sqlite/contractRepository.js +2 -6
- package/dist/esm/repositories/sqlite/walletRepository.js +121 -33
- package/dist/esm/utils/syncCursors.js +47 -53
- package/dist/esm/wallet/expo/background.js +0 -13
- package/dist/esm/wallet/expo/wallet.js +2 -7
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +17 -8
- package/dist/esm/wallet/serviceWorker/wallet.js +19 -0
- package/dist/esm/wallet/utils.js +41 -9
- package/dist/esm/wallet/vtxo-manager.js +153 -39
- package/dist/esm/wallet/wallet.js +75 -198
- package/dist/esm/worker/expo/processors/contractPollProcessor.js +9 -13
- package/dist/esm/worker/expo/taskRunner.js +3 -12
- package/dist/types/contracts/arkcontract.d.ts +0 -2
- package/dist/types/contracts/contractManager.d.ts +38 -9
- package/dist/types/contracts/contractWatcher.d.ts +22 -21
- package/dist/types/contracts/types.d.ts +0 -7
- package/dist/types/repositories/indexedDB/manager.d.ts +5 -2
- package/dist/types/repositories/indexedDB/schema.d.ts +3 -2
- package/dist/types/repositories/realm/index.d.ts +1 -1
- package/dist/types/repositories/realm/schemas.d.ts +41 -0
- package/dist/types/repositories/scriptFromAddress.d.ts +9 -0
- package/dist/types/repositories/serialization.d.ts +1 -1
- package/dist/types/repositories/sqlite/walletRepository.d.ts +22 -0
- package/dist/types/repositories/walletRepository.d.ts +10 -2
- package/dist/types/utils/syncCursors.d.ts +25 -23
- package/dist/types/wallet/index.d.ts +1 -1
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +15 -3
- package/dist/types/wallet/utils.d.ts +20 -4
- package/dist/types/wallet/vtxo-manager.d.ts +16 -6
- package/dist/types/wallet/wallet.d.ts +5 -17
- package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +9 -4
- package/dist/types/worker/expo/taskRunner.d.ts +6 -3
- package/package.json +1 -1
|
@@ -108,6 +108,14 @@ export declare class ContractWatcher {
|
|
|
108
108
|
* (which may cause them to be watched even if inactive).
|
|
109
109
|
*/
|
|
110
110
|
addContract(contract: Contract): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Pre-populate `lastKnownVtxos` from the wallet repository.
|
|
113
|
+
*
|
|
114
|
+
* Runs on add (and can be re-run after reconnect) so polling always
|
|
115
|
+
* compares the indexer's view against what is already persisted,
|
|
116
|
+
* emitting only genuine deltas.
|
|
117
|
+
*/
|
|
118
|
+
private seedLastKnownVtxos;
|
|
111
119
|
/**
|
|
112
120
|
* Update an existing contract.
|
|
113
121
|
*/
|
|
@@ -121,20 +129,17 @@ export declare class ContractWatcher {
|
|
|
121
129
|
*/
|
|
122
130
|
getAllContracts(): Contract[];
|
|
123
131
|
/**
|
|
124
|
-
*
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
*
|
|
132
|
+
* Contracts the watcher is actually tracking:
|
|
133
|
+
* - all active contracts, plus
|
|
134
|
+
* - inactive contracts that still hold known virtual outputs
|
|
135
|
+
* (the subscription keeps watching them so `vtxo_spent` events for
|
|
136
|
+
* those unspent outputs are still observed).
|
|
129
137
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* This ensures we continue monitoring contracts even after they're
|
|
135
|
-
* deactivated, as long as they have unspent virtual outputs.
|
|
138
|
+
* This is the single source of truth for "contracts whose VTXO state
|
|
139
|
+
* we still care about" — callers and the subscription itself fan out
|
|
140
|
+
* over the same set so nothing is reconciled that isn't also watched.
|
|
136
141
|
*/
|
|
137
|
-
|
|
142
|
+
getWatchedContracts(): Contract[];
|
|
138
143
|
/**
|
|
139
144
|
* Get virtual outputs for contracts, grouped by contract script.
|
|
140
145
|
* @see WalletRepository for `repo`
|
|
@@ -161,10 +166,6 @@ export declare class ContractWatcher {
|
|
|
161
166
|
* Useful for manual refresh or after app resume.
|
|
162
167
|
*/
|
|
163
168
|
forcePoll(): Promise<void>;
|
|
164
|
-
/**
|
|
165
|
-
* Check for expired contracts, update their state, and emit events.
|
|
166
|
-
*/
|
|
167
|
-
private checkExpiredContracts;
|
|
168
169
|
/**
|
|
169
170
|
* Connect to the subscription.
|
|
170
171
|
*/
|
|
@@ -177,9 +178,6 @@ export declare class ContractWatcher {
|
|
|
177
178
|
* Start the failsafe polling interval.
|
|
178
179
|
*/
|
|
179
180
|
private startFailsafePolling;
|
|
180
|
-
/**
|
|
181
|
-
* Poll all active contracts for current state.
|
|
182
|
-
*/
|
|
183
181
|
private pollAllContracts;
|
|
184
182
|
/**
|
|
185
183
|
* Poll specific contracts and emit events for changes.
|
|
@@ -201,8 +199,11 @@ export declare class ContractWatcher {
|
|
|
201
199
|
*/
|
|
202
200
|
private handleSubscriptionUpdate;
|
|
203
201
|
/**
|
|
204
|
-
* Process virtual outputs from subscription and route to
|
|
205
|
-
*
|
|
202
|
+
* Process virtual outputs from subscription and route each VTXO to the
|
|
203
|
+
* single contract that actually locks it via `vtxo.script`. If the script
|
|
204
|
+
* doesn't match any watched contract, skip the VTXO rather than fan it
|
|
205
|
+
* out to every matching contract — fan-out produced phantom state in
|
|
206
|
+
* non-owning contracts that then never reconciled.
|
|
206
207
|
*/
|
|
207
208
|
private processSubscriptionVtxos;
|
|
208
209
|
/**
|
|
@@ -58,8 +58,6 @@ export interface Contract {
|
|
|
58
58
|
state: ContractState;
|
|
59
59
|
/** Unix timestamp in milliseconds when this contract was created. */
|
|
60
60
|
createdAt: number;
|
|
61
|
-
/** Unix timestamp in milliseconds when this contract expires. */
|
|
62
|
-
expiresAt?: number;
|
|
63
61
|
/**
|
|
64
62
|
* Optional metadata for external integrations.
|
|
65
63
|
*/
|
|
@@ -194,11 +192,6 @@ export type ContractEvent = {
|
|
|
194
192
|
vtxos: ContractVtxo[];
|
|
195
193
|
contract: Contract;
|
|
196
194
|
timestamp: number;
|
|
197
|
-
} | {
|
|
198
|
-
type: "contract_expired";
|
|
199
|
-
contractScript: string;
|
|
200
|
-
contract: Contract;
|
|
201
|
-
timestamp: number;
|
|
202
195
|
} | {
|
|
203
196
|
type: "connection_reset";
|
|
204
197
|
timestamp: number;
|
|
@@ -7,11 +7,14 @@ export declare function getGlobalObject(): {
|
|
|
7
7
|
*
|
|
8
8
|
* @param dbName The name of the database to open.
|
|
9
9
|
* @param dbVersion The database version to open.
|
|
10
|
-
* @param initDatabase A function that migrates the database schema, called
|
|
10
|
+
* @param initDatabase A function that migrates the database schema, called
|
|
11
|
+
* on `onupgradeneeded` only. Receives the database, the previous version
|
|
12
|
+
* (0 for fresh installs), and the upgrade transaction — the transaction is
|
|
13
|
+
* required for data migrations (cursor/update on existing stores).
|
|
11
14
|
*
|
|
12
15
|
* @returns A promise that resolves to the database instance.
|
|
13
16
|
*/
|
|
14
|
-
export declare function openDatabase(dbName: string, dbVersion: number, initDatabase: (db: IDBDatabase) => void): Promise<IDBDatabase>;
|
|
17
|
+
export declare function openDatabase(dbName: string, dbVersion: number, initDatabase: (db: IDBDatabase, oldVersion: number, transaction: IDBTransaction | null) => void): Promise<IDBDatabase>;
|
|
15
18
|
/**
|
|
16
19
|
* Decrements the reference count and closes the database when no references remain.
|
|
17
20
|
*
|
|
@@ -4,5 +4,6 @@ export declare const STORE_TRANSACTIONS = "transactions";
|
|
|
4
4
|
export declare const STORE_WALLET_STATE = "walletState";
|
|
5
5
|
export declare const STORE_CONTRACTS = "contracts";
|
|
6
6
|
export declare const LEGACY_STORE_CONTRACT_COLLECTIONS = "contractsCollections";
|
|
7
|
-
export declare const DB_VERSION =
|
|
8
|
-
export declare function initDatabase(db: IDBDatabase): void;
|
|
7
|
+
export declare const DB_VERSION = 3;
|
|
8
|
+
export declare function initDatabase(db: IDBDatabase, oldVersion: number, transaction: IDBTransaction | null): void;
|
|
9
|
+
export declare function backfillVtxoScripts(transaction: IDBTransaction): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { RealmWalletRepository } from "./walletRepository";
|
|
2
2
|
export { RealmContractRepository } from "./contractRepository";
|
|
3
|
-
export { ArkRealmSchemas } from "./schemas";
|
|
3
|
+
export { ArkRealmSchemas, ARK_REALM_SCHEMA_VERSION, runArkRealmMigrations, } from "./schemas";
|
|
4
4
|
export type { RealmLike, RealmResults } from "./types";
|
|
@@ -35,6 +35,10 @@ export declare const ArkVtxoSchema: {
|
|
|
35
35
|
readonly isUnrolled: "bool";
|
|
36
36
|
readonly isSpent: "bool?";
|
|
37
37
|
readonly assetsJson: "string?";
|
|
38
|
+
readonly script: {
|
|
39
|
+
readonly type: "string";
|
|
40
|
+
readonly indexed: true;
|
|
41
|
+
};
|
|
38
42
|
};
|
|
39
43
|
};
|
|
40
44
|
export declare const ArkUtxoSchema: {
|
|
@@ -138,6 +142,10 @@ export declare const ArkRealmSchemas: ({
|
|
|
138
142
|
readonly isUnrolled: "bool";
|
|
139
143
|
readonly isSpent: "bool?";
|
|
140
144
|
readonly assetsJson: "string?";
|
|
145
|
+
readonly script: {
|
|
146
|
+
readonly type: "string";
|
|
147
|
+
readonly indexed: true;
|
|
148
|
+
};
|
|
141
149
|
};
|
|
142
150
|
} | {
|
|
143
151
|
readonly name: "ArkUtxo";
|
|
@@ -206,3 +214,36 @@ export declare const ArkRealmSchemas: ({
|
|
|
206
214
|
readonly metadataJson: "string?";
|
|
207
215
|
};
|
|
208
216
|
})[];
|
|
217
|
+
/**
|
|
218
|
+
* Current Realm schema version for the Arkade wallet.
|
|
219
|
+
*
|
|
220
|
+
* Consumers opening Realm must pass a `schemaVersion` at least this high so
|
|
221
|
+
* legacy databases get migrated; merge it with your own app's version:
|
|
222
|
+
*
|
|
223
|
+
* ```ts
|
|
224
|
+
* await Realm.open({
|
|
225
|
+
* schema: [...ArkRealmSchemas, ...yourSchemas],
|
|
226
|
+
* schemaVersion: Math.max(ARK_REALM_SCHEMA_VERSION, yourSchemaVersion),
|
|
227
|
+
* onMigration: (oldRealm, newRealm) => {
|
|
228
|
+
* runArkRealmMigrations(oldRealm, newRealm);
|
|
229
|
+
* // your own migrations
|
|
230
|
+
* },
|
|
231
|
+
* });
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* History:
|
|
235
|
+
* - v1: initial ArkVtxo/ArkUtxo/... schemas, `script` nullable.
|
|
236
|
+
* - v2: ArkVtxo.script becomes required; NULL values are backfilled from
|
|
237
|
+
* the owning Ark address during migration.
|
|
238
|
+
*/
|
|
239
|
+
export declare const ARK_REALM_SCHEMA_VERSION = 2;
|
|
240
|
+
/**
|
|
241
|
+
* Run every Arkade schema migration applicable to the open Realm.
|
|
242
|
+
*
|
|
243
|
+
* Designed to be composed with the consumer's own migrations inside a single
|
|
244
|
+
* `onMigration` callback. Each migration step does a per-row check so it
|
|
245
|
+
* remains idempotent and independent of the app's global `schemaVersion` —
|
|
246
|
+
* a consumer whose app is already at version 10 can still trigger the
|
|
247
|
+
* Arkade v1→v2 script backfill when the row has never been populated.
|
|
248
|
+
*/
|
|
249
|
+
export declare function runArkRealmMigrations(oldRealm: any, newRealm: any): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute the hex-encoded `scriptPubKey` locking a VTXO from its owning Ark
|
|
3
|
+
* address. Used by repository-layer migrations to backfill `script` on legacy
|
|
4
|
+
* rows that pre-date the column (the indexer now guarantees the field, so new
|
|
5
|
+
* rows never go through this path). The `script` field is required by the
|
|
6
|
+
* domain type, so backfill must produce the same value the indexer would
|
|
7
|
+
* have returned — which is the hex of the address's `pkScript`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function scriptFromArkAddress(address: string): string;
|
|
@@ -20,7 +20,7 @@ export declare const serializeVtxo: (v: ExtendedVirtualCoin) => {
|
|
|
20
20
|
isUnrolled: boolean;
|
|
21
21
|
isSpent?: boolean;
|
|
22
22
|
assets?: import("../wallet").Asset[];
|
|
23
|
-
script
|
|
23
|
+
script: string;
|
|
24
24
|
value: number;
|
|
25
25
|
status: import("../wallet").Status;
|
|
26
26
|
txid: string;
|
|
@@ -23,6 +23,28 @@ export declare class SQLiteWalletRepository implements WalletRepository {
|
|
|
23
23
|
constructor(db: SQLExecutor, options?: SQLiteWalletRepositoryOptions);
|
|
24
24
|
private ensureInit;
|
|
25
25
|
private init;
|
|
26
|
+
/**
|
|
27
|
+
* Bring the `vtxos` table to the current schema (v1 = `script` NOT NULL).
|
|
28
|
+
*
|
|
29
|
+
* Three cases:
|
|
30
|
+
* - Fresh install: create the v1 schema directly.
|
|
31
|
+
* - Legacy install without a `script` column: add it, backfill from
|
|
32
|
+
* `address`, then rebuild the table with NOT NULL (SQLite cannot add
|
|
33
|
+
* the NOT NULL constraint in place).
|
|
34
|
+
* - Legacy install with a nullable `script` column: backfill the NULLs
|
|
35
|
+
* and rebuild.
|
|
36
|
+
*
|
|
37
|
+
* The backfill derives `script` from the Ark address, matching what the
|
|
38
|
+
* indexer would have returned — new rows from the indexer always carry a
|
|
39
|
+
* populated `script`, so the migration is idempotent.
|
|
40
|
+
*
|
|
41
|
+
* The rebuild path is wrapped in a transaction: without it, a crash
|
|
42
|
+
* between the `DROP TABLE vtxos` and the `RENAME tmp → vtxos` commits
|
|
43
|
+
* would leave the next startup seeing no `vtxos` table and create a
|
|
44
|
+
* fresh empty one, silently orphaning every row in the temp table.
|
|
45
|
+
*/
|
|
46
|
+
private migrateVtxosTable;
|
|
47
|
+
private vtxosCreateSql;
|
|
26
48
|
[Symbol.asyncDispose](): Promise<void>;
|
|
27
49
|
clear(): Promise<void>;
|
|
28
50
|
getVtxos(address: string): Promise<ExtendedVirtualCoin[]>;
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { ArkTransaction, ExtendedCoin, ExtendedVirtualCoin } from "../wallet";
|
|
2
2
|
export interface WalletState {
|
|
3
|
-
/** Timestamp of the last successful wallet sync, in milliseconds. */
|
|
4
|
-
lastSyncTime?: number;
|
|
5
3
|
/** Arbitrary stored wallet settings. */
|
|
6
4
|
settings?: Record<string, any>;
|
|
5
|
+
/**
|
|
6
|
+
* High-water mark for VTXO indexer syncs, in milliseconds.
|
|
7
|
+
*
|
|
8
|
+
* Reused the legacy `lastSyncTime` column name to avoid an
|
|
9
|
+
* `ALTER TABLE` migration; the value is interpreted as the new
|
|
10
|
+
* "max indexer `updatedAt`" cursor only after `settings.vtxoCursorMigrated`
|
|
11
|
+
* is set, so pre-existing values written by the buggy pre-PR sync
|
|
12
|
+
* are ignored and force a one-shot re-bootstrap on upgrade.
|
|
13
|
+
*/
|
|
14
|
+
lastSyncTime?: number;
|
|
7
15
|
}
|
|
8
16
|
/** Stored commitment transaction metadata. */
|
|
9
17
|
export type CommitmentTxRecord = {
|
|
@@ -2,8 +2,7 @@ import { WalletRepository, WalletState } from "../repositories/walletRepository"
|
|
|
2
2
|
/** Lag behind real-time to avoid racing with indexer writes. */
|
|
3
3
|
export declare const SAFETY_LAG_MS = 30000;
|
|
4
4
|
/** Overlap window so boundary virtual outputs are never missed. */
|
|
5
|
-
export declare const OVERLAP_MS
|
|
6
|
-
type SyncCursors = Record<string, number>;
|
|
5
|
+
export declare const OVERLAP_MS: number;
|
|
7
6
|
/**
|
|
8
7
|
* Atomically read, mutate, and persist wallet state.
|
|
9
8
|
* All callers that modify wallet state should go through this helper
|
|
@@ -11,39 +10,43 @@ type SyncCursors = Record<string, number>;
|
|
|
11
10
|
*/
|
|
12
11
|
export declare function updateWalletState(repo: WalletRepository, updater: (state: WalletState) => WalletState): Promise<void>;
|
|
13
12
|
/**
|
|
14
|
-
* Read the high-water mark for
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*
|
|
20
|
-
*/
|
|
21
|
-
export declare function getAllSyncCursors(repo: WalletRepository): Promise<SyncCursors>;
|
|
22
|
-
/**
|
|
23
|
-
* Advance the cursor for one script after a successful delta sync.
|
|
24
|
-
* `cursor` should be the `before` cutoff used in the request.
|
|
13
|
+
* Read the global high-water mark for VTXO indexer syncs.
|
|
14
|
+
*
|
|
15
|
+
* Returns `0` when:
|
|
16
|
+
* - the wallet has never been synced (bootstrap case), or
|
|
17
|
+
* - the stored `lastSyncTime` was written by pre-PR code and is not
|
|
18
|
+
* safe to reuse under the new semantics (see {@link CURSOR_MIGRATED_KEY}).
|
|
25
19
|
*/
|
|
26
|
-
export declare function
|
|
20
|
+
export declare function getSyncCursor(repo: WalletRepository): Promise<number>;
|
|
27
21
|
/**
|
|
28
|
-
* Advance
|
|
22
|
+
* Advance the global cursor after a successful full-scope delta sync.
|
|
23
|
+
*
|
|
24
|
+
* Clamped with `Math.max` against the current value so concurrent syncs
|
|
25
|
+
* that finish out of order can't rewind the cursor: `lastUpdatedAt` is
|
|
26
|
+
* captured before each sync enters the `updateWalletState` mutex, and
|
|
27
|
+
* the later-started sync would otherwise overwrite the earlier-captured
|
|
28
|
+
* one with a smaller value. The legacy value is discarded on the first
|
|
29
|
+
* advance if the migration marker is absent so pre-PR data doesn't
|
|
30
|
+
* survive the upgrade.
|
|
29
31
|
*/
|
|
30
|
-
export declare function
|
|
32
|
+
export declare function advanceSyncCursor(repo: WalletRepository, lastUpdatedAt: number): Promise<void>;
|
|
31
33
|
/**
|
|
32
|
-
* Remove sync
|
|
33
|
-
*
|
|
34
|
+
* Remove the sync cursor, forcing a full re-bootstrap on next sync.
|
|
35
|
+
*
|
|
36
|
+
* Also clears the migration marker so any stored `lastSyncTime` is
|
|
37
|
+
* treated as untrusted on the next read.
|
|
34
38
|
*/
|
|
35
|
-
export declare function
|
|
39
|
+
export declare function clearSyncCursor(repo: WalletRepository): Promise<void>;
|
|
36
40
|
/**
|
|
37
41
|
* Compute the `after` lower-bound for a delta sync query.
|
|
38
|
-
* Returns `undefined` when the script has no cursor (bootstrap needed).
|
|
39
42
|
*
|
|
40
43
|
* No upper bound (`before`) is applied to the query so that freshly
|
|
41
44
|
* created virtual outputs are never excluded. The safety lag is applied only
|
|
42
45
|
* when advancing the cursor (see @see cursorCutoff).
|
|
43
46
|
*/
|
|
44
|
-
export declare function computeSyncWindow(cursor: number
|
|
47
|
+
export declare function computeSyncWindow(cursor: number): {
|
|
45
48
|
after: number;
|
|
46
|
-
}
|
|
49
|
+
};
|
|
47
50
|
/**
|
|
48
51
|
* The safe high-water mark for cursor advancement.
|
|
49
52
|
* Lags behind real-time by @see SAFETY_LAG_MS so that virtual outputs still
|
|
@@ -55,4 +58,3 @@ export declare function computeSyncWindow(cursor: number | undefined): {
|
|
|
55
58
|
* data they actually observed.
|
|
56
59
|
*/
|
|
57
60
|
export declare function cursorCutoff(requestStartedAt?: number): number;
|
|
58
|
-
export {};
|
|
@@ -480,7 +480,7 @@ export interface VirtualCoin extends Coin {
|
|
|
480
480
|
/** Assets carried by this virtual output, if any. */
|
|
481
481
|
assets?: Asset[];
|
|
482
482
|
/** The scriptPubKey (hex) locking this virtual output, as returned by the indexer. */
|
|
483
|
-
script
|
|
483
|
+
script: string;
|
|
484
484
|
}
|
|
485
485
|
/** Wallet transaction direction. */
|
|
486
486
|
export declare enum TxType {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SettlementEvent } from "../../providers/ark";
|
|
2
2
|
import type { Contract, ContractEvent, ContractWithVtxos, GetContractsFilter, PathSelection } from "../../contracts";
|
|
3
3
|
import type { CreateContractParams, GetAllSpendingPathsOptions, GetSpendablePathsOptions } from "../../contracts/contractManager";
|
|
4
|
-
import { ArkTransaction, AssetDetails, BurnParams, ExtendedCoin, ExtendedVirtualCoin, GetVtxosFilter, IssuanceParams, IssuanceResult, IWallet, Recipient, ReissuanceParams, SendBitcoinParams, SettleParams, WalletBalance } from "../index";
|
|
4
|
+
import { ArkTransaction, AssetDetails, BurnParams, ExtendedCoin, ExtendedVirtualCoin, GetVtxosFilter, IssuanceParams, IssuanceResult, IWallet, Recipient, ReissuanceParams, SendBitcoinParams, SettleParams, VirtualCoin, WalletBalance } from "../index";
|
|
5
5
|
import { DelegateInfo } from "../../providers/delegator";
|
|
6
6
|
import { MessageHandler, RequestEnvelope, ResponseEnvelope } from "../../worker/messageBus";
|
|
7
7
|
import { Transaction } from "../../utils/transaction";
|
|
@@ -182,6 +182,18 @@ export type ResponseGetContractsWithVtxos = ResponseEnvelope & {
|
|
|
182
182
|
contracts: ContractWithVtxos[];
|
|
183
183
|
};
|
|
184
184
|
};
|
|
185
|
+
export type RequestAnnotateVtxos = RequestEnvelope & {
|
|
186
|
+
type: "ANNOTATE_VTXOS";
|
|
187
|
+
payload: {
|
|
188
|
+
vtxos: VirtualCoin[];
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
export type ResponseAnnotateVtxos = ResponseEnvelope & {
|
|
192
|
+
type: "ANNOTATED_VTXOS";
|
|
193
|
+
payload: {
|
|
194
|
+
vtxos: ExtendedVirtualCoin[];
|
|
195
|
+
};
|
|
196
|
+
};
|
|
185
197
|
export type RequestUpdateContract = RequestEnvelope & {
|
|
186
198
|
type: "UPDATE_CONTRACT";
|
|
187
199
|
payload: {
|
|
@@ -443,8 +455,8 @@ export type ResponseSweepExpiredBoardingUtxos = ResponseEnvelope & {
|
|
|
443
455
|
txid: string;
|
|
444
456
|
};
|
|
445
457
|
};
|
|
446
|
-
export type WalletUpdaterRequest = RequestInitWallet | RequestSettle | RequestSendBitcoin | RequestGetAddress | RequestGetBoardingAddress | RequestGetBalance | RequestGetVtxos | RequestGetBoardingUtxos | RequestGetTransactionHistory | RequestGetStatus | RequestClear | RequestReloadWallet | RequestSignTransaction | RequestCreateContract | RequestGetContracts | RequestGetContractsWithVtxos | RequestUpdateContract | RequestDeleteContract | RequestGetSpendablePaths | RequestGetAllSpendingPaths | RequestIsContractManagerWatching | RequestRefreshVtxos | RequestSend | RequestGetAssetDetails | RequestIssue | RequestReissue | RequestBurn | RequestDelegate | RequestGetDelegateInfo | RequestRecoverVtxos | RequestGetRecoverableBalance | RequestGetExpiringVtxos | RequestRenewVtxos | RequestGetExpiredBoardingUtxos | RequestSweepExpiredBoardingUtxos;
|
|
447
|
-
export type WalletUpdaterResponse = ResponseEnvelope & (ResponseInitWallet | ResponseSettle | ResponseSettleEvent | ResponseSendBitcoin | ResponseGetAddress | ResponseGetBoardingAddress | ResponseGetBalance | ResponseGetVtxos | ResponseGetBoardingUtxos | ResponseGetTransactionHistory | ResponseGetStatus | ResponseClear | ResponseReloadWallet | ResponseUtxoUpdate | ResponseVtxoUpdate | ResponseSignTransaction | ResponseCreateContract | ResponseGetContracts | ResponseGetContractsWithVtxos | ResponseUpdateContract | ResponseDeleteContract | ResponseGetSpendablePaths | ResponseGetAllSpendingPaths | ResponseIsContractManagerWatching | ResponseRefreshVtxos | ResponseContractEvent | ResponseSend | ResponseGetAssetDetails | ResponseIssue | ResponseReissue | ResponseBurn | ResponseDelegate | ResponseGetDelegateInfo | ResponseRecoverVtxos | ResponseRecoverVtxosEvent | ResponseGetRecoverableBalance | ResponseGetExpiringVtxos | ResponseRenewVtxos | ResponseRenewVtxosEvent | ResponseGetExpiredBoardingUtxos | ResponseSweepExpiredBoardingUtxos);
|
|
458
|
+
export type WalletUpdaterRequest = RequestInitWallet | RequestSettle | RequestSendBitcoin | RequestGetAddress | RequestGetBoardingAddress | RequestGetBalance | RequestGetVtxos | RequestGetBoardingUtxos | RequestGetTransactionHistory | RequestGetStatus | RequestClear | RequestReloadWallet | RequestSignTransaction | RequestCreateContract | RequestGetContracts | RequestGetContractsWithVtxos | RequestAnnotateVtxos | RequestUpdateContract | RequestDeleteContract | RequestGetSpendablePaths | RequestGetAllSpendingPaths | RequestIsContractManagerWatching | RequestRefreshVtxos | RequestSend | RequestGetAssetDetails | RequestIssue | RequestReissue | RequestBurn | RequestDelegate | RequestGetDelegateInfo | RequestRecoverVtxos | RequestGetRecoverableBalance | RequestGetExpiringVtxos | RequestRenewVtxos | RequestGetExpiredBoardingUtxos | RequestSweepExpiredBoardingUtxos;
|
|
459
|
+
export type WalletUpdaterResponse = ResponseEnvelope & (ResponseInitWallet | ResponseSettle | ResponseSettleEvent | ResponseSendBitcoin | ResponseGetAddress | ResponseGetBoardingAddress | ResponseGetBalance | ResponseGetVtxos | ResponseGetBoardingUtxos | ResponseGetTransactionHistory | ResponseGetStatus | ResponseClear | ResponseReloadWallet | ResponseUtxoUpdate | ResponseVtxoUpdate | ResponseSignTransaction | ResponseCreateContract | ResponseGetContracts | ResponseGetContractsWithVtxos | ResponseAnnotateVtxos | ResponseUpdateContract | ResponseDeleteContract | ResponseGetSpendablePaths | ResponseGetAllSpendingPaths | ResponseIsContractManagerWatching | ResponseRefreshVtxos | ResponseContractEvent | ResponseSend | ResponseGetAssetDetails | ResponseIssue | ResponseReissue | ResponseBurn | ResponseDelegate | ResponseGetDelegateInfo | ResponseRecoverVtxos | ResponseRecoverVtxosEvent | ResponseGetRecoverableBalance | ResponseGetExpiringVtxos | ResponseRenewVtxos | ResponseRenewVtxosEvent | ResponseGetExpiredBoardingUtxos | ResponseSweepExpiredBoardingUtxos);
|
|
448
460
|
export declare class WalletMessageHandler implements MessageHandler<WalletUpdaterRequest, WalletUpdaterResponse> {
|
|
449
461
|
readonly messageTag: string;
|
|
450
462
|
private wallet;
|
|
@@ -4,13 +4,29 @@ import type { Contract } from "../contracts/types";
|
|
|
4
4
|
import { ReadonlyWallet } from "./wallet";
|
|
5
5
|
import { Bytes } from "@scure/btc-signer/utils";
|
|
6
6
|
export declare const DUST_AMOUNT = 546;
|
|
7
|
-
export declare function extendVirtualCoin(wallet: {
|
|
8
|
-
offchainTapscript: ReadonlyWallet["offchainTapscript"];
|
|
9
|
-
}, vtxo: VirtualCoin): ExtendedVirtualCoin;
|
|
10
7
|
export declare function extendCoin(wallet: {
|
|
11
8
|
boardingTapscript: ReadonlyWallet["boardingTapscript"];
|
|
12
9
|
}, utxo: Coin): ExtendedCoin;
|
|
13
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Extend a VirtualCoin with the tap scripts of whichever contract locks it.
|
|
12
|
+
*
|
|
13
|
+
* The second argument accepts either form, so each callsite passes what it
|
|
14
|
+
* already has:
|
|
15
|
+
* - a single `Contract` (when the caller already knows the owning contract,
|
|
16
|
+
* e.g. the contract manager iterating its own `scriptToContract` map), or
|
|
17
|
+
* - a `ReadonlyMap<script, Contract>` (when the caller resolves by
|
|
18
|
+
* `vtxo.script`, populated by the indexer).
|
|
19
|
+
*
|
|
20
|
+
* Throws when no contract can be resolved — there is intentionally no
|
|
21
|
+
* default-tapscript fallback. When the wallet owns multiple contracts
|
|
22
|
+
* (default + delegate, several active vHTLCs, etc.) a default-tapscript path
|
|
23
|
+
* silently stamps every VTXO with the same forfeit/intent data, overwriting
|
|
24
|
+
* the correct data for any VTXO locked to a non-default contract. Callers
|
|
25
|
+
* must feed a Contract or a populated script→Contract map; otherwise the
|
|
26
|
+
* caller (typically `ContractManager.annotateVtxos`) should fetch the owning
|
|
27
|
+
* contract first.
|
|
28
|
+
*/
|
|
29
|
+
export declare function extendVirtualCoinForContract(vtxo: VirtualCoin, contractOrMap?: Contract | ReadonlyMap<string, Contract>): ExtendedVirtualCoin;
|
|
14
30
|
export declare function getRandomId(): string;
|
|
15
31
|
export declare function isValidArkAddress(address: string): boolean;
|
|
16
32
|
type ValidatedRecipient = Required<Recipient> & {
|
|
@@ -220,6 +220,10 @@ export declare class VtxoManager implements AsyncDisposable, IVtxoManager {
|
|
|
220
220
|
private renewalInProgress;
|
|
221
221
|
private lastRenewalTimestamp;
|
|
222
222
|
private static readonly RENEWAL_COOLDOWN_MS;
|
|
223
|
+
private lastPeriodicSettleTimestamp;
|
|
224
|
+
private consecutivePeriodicSettleFailures;
|
|
225
|
+
private static readonly PERIODIC_SETTLE_COOLDOWN_MS;
|
|
226
|
+
private static readonly PERIODIC_SETTLE_MAX_BACKOFF_MS;
|
|
223
227
|
constructor(wallet: IWallet,
|
|
224
228
|
/** @deprecated Use settlementConfig instead */
|
|
225
229
|
renewalConfig?: RenewalConfig | undefined, settlementConfig?: SettlementConfig | false);
|
|
@@ -412,13 +416,19 @@ export declare class VtxoManager implements AsyncDisposable, IVtxoManager {
|
|
|
412
416
|
private schedulePoll;
|
|
413
417
|
private pollBoardingUtxos;
|
|
414
418
|
/**
|
|
415
|
-
* Auto-settle new (unexpired) boarding inputs into
|
|
416
|
-
* Skips UTXOs that are already expired
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
419
|
+
* Auto-settle new (unexpired) boarding inputs AND near-expiry VTXOs into
|
|
420
|
+
* Arkade in a single intent. Skips boarding UTXOs that are already expired
|
|
421
|
+
* (those are handled by sweep) and those already in-flight (tracked in
|
|
422
|
+
* knownBoardingUtxos). If the event-driven renewal path is currently
|
|
423
|
+
* running, VTXOs are omitted from this cycle to avoid double-spending.
|
|
424
|
+
*
|
|
425
|
+
* Failure bookkeeping: after every settle *attempt*, lastPeriodicSettleTimestamp
|
|
426
|
+
* is armed and consecutive failures are counted so the next attempt is
|
|
427
|
+
* blocked by an exponentially growing cooldown (capped). This stops a
|
|
428
|
+
* persistently failing input from producing identical RegisterIntent +
|
|
429
|
+
* DeleteIntent retries on every 60s poll.
|
|
420
430
|
*/
|
|
421
|
-
private
|
|
431
|
+
private runPeriodicSettle;
|
|
422
432
|
dispose(): Promise<void>;
|
|
423
433
|
[Symbol.asyncDispose](): Promise<void>;
|
|
424
434
|
}
|
|
@@ -7,7 +7,7 @@ import { OnchainProvider } from "../providers/onchain";
|
|
|
7
7
|
import { ArkProvider, SettlementEvent, SignedIntent } from "../providers/ark";
|
|
8
8
|
import { SignerSession } from "../tree/signingSession";
|
|
9
9
|
import { Identity, ReadonlyIdentity } from "../identity";
|
|
10
|
-
import { ArkTransaction,
|
|
10
|
+
import { ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, GetVtxosFilter, IAssetManager, IReadonlyAssetManager, IReadonlyWallet, IWallet, ReadonlyWalletConfig, Recipient, SendBitcoinParams, SettleParams, WalletBalance, WalletConfig } from ".";
|
|
11
11
|
import { CSVMultisigTapscript } from "../script/tapscript";
|
|
12
12
|
import { SettlementConfig, VtxoManager } from "./vtxo-manager";
|
|
13
13
|
import { Intent } from "../intent";
|
|
@@ -97,21 +97,10 @@ export declare class ReadonlyWallet implements IReadonlyWallet {
|
|
|
97
97
|
*/
|
|
98
98
|
getTransactionHistory(): Promise<ArkTransaction[]>;
|
|
99
99
|
/**
|
|
100
|
-
*
|
|
101
|
-
* cursor, or do a full bootstrap when no cursor exists. Upserts
|
|
102
|
-
* the result into the cache and advances the sync cursors.
|
|
103
|
-
*
|
|
104
|
-
* Concurrent calls are deduplicated: if a sync is already in flight,
|
|
105
|
-
* subsequent callers receive the same promise instead of triggering
|
|
106
|
-
* a second network round-trip.
|
|
107
|
-
*/
|
|
108
|
-
private syncVtxos;
|
|
109
|
-
private doSyncVtxos;
|
|
110
|
-
/**
|
|
111
|
-
* Clear all virtual output sync cursors, forcing a full re-bootstrap on next sync.
|
|
100
|
+
* Clear the global VTXO sync cursor, forcing a full re-bootstrap on next sync.
|
|
112
101
|
* Useful for recovery after indexer reprocessing or debugging.
|
|
113
102
|
*/
|
|
114
|
-
|
|
103
|
+
clearSyncCursor(): Promise<void>;
|
|
115
104
|
/**
|
|
116
105
|
* Build a transaction history view for the wallet's boarding address.
|
|
117
106
|
*/
|
|
@@ -211,7 +200,6 @@ export declare class ReadonlyWallet implements IReadonlyWallet {
|
|
|
211
200
|
* ```
|
|
212
201
|
*/
|
|
213
202
|
export declare class Wallet extends ReadonlyWallet implements IWallet {
|
|
214
|
-
readonly networkName: NetworkName;
|
|
215
203
|
readonly arkProvider: ArkProvider;
|
|
216
204
|
readonly serverUnrollScript: CSVMultisigTapscript.Type;
|
|
217
205
|
readonly forfeitOutputScript: Bytes;
|
|
@@ -236,7 +224,7 @@ export declare class Wallet extends ReadonlyWallet implements IWallet {
|
|
|
236
224
|
thresholdMs: number;
|
|
237
225
|
};
|
|
238
226
|
readonly settlementConfig: SettlementConfig | false;
|
|
239
|
-
protected constructor(identity: Identity, network: Network,
|
|
227
|
+
protected constructor(identity: Identity, network: Network, onchainProvider: OnchainProvider, arkProvider: ArkProvider, indexerProvider: IndexerProvider, arkServerPublicKey: Bytes, offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script, boardingTapscript: DefaultVtxo.Script, serverUnrollScript: CSVMultisigTapscript.Type, forfeitOutputScript: Bytes, forfeitPubkey: Bytes, dustAmount: bigint, walletRepository: WalletRepository, contractRepository: ContractRepository,
|
|
240
228
|
/** @deprecated Use settlementConfig */
|
|
241
229
|
renewalConfig?: WalletConfig["renewalConfig"], delegatorProvider?: DelegatorProvider, watcherConfig?: WalletConfig["watcherConfig"], settlementConfig?: WalletConfig["settlementConfig"]);
|
|
242
230
|
get assetManager(): IAssetManager;
|
|
@@ -302,7 +290,7 @@ export declare class Wallet extends ReadonlyWallet implements IWallet {
|
|
|
302
290
|
* @param session - Optional musig2 signing session. When omitted, signing steps are skipped.
|
|
303
291
|
*/
|
|
304
292
|
createBatchHandler(intentId: string, inputs: ExtendedCoin[], expectedRecipients: Recipient[], session?: SignerSession): Batch.Handler;
|
|
305
|
-
safeRegisterIntent(intent: SignedIntent<Intent.RegisterMessage
|
|
293
|
+
safeRegisterIntent(intent: SignedIntent<Intent.RegisterMessage>, inputs: ExtendedCoin[]): Promise<string>;
|
|
306
294
|
makeRegisterIntentSignature(coins: ExtendedCoin[], outputs: TransactionOutput[], onchainOutputsIndexes: number[], cosignerPubKeys: string[], validAt?: number): Promise<SignedIntent<Intent.RegisterMessage>>;
|
|
307
295
|
makeDeleteIntentSignature(coins: ExtendedCoin[]): Promise<SignedIntent<Intent.DeleteMessage>>;
|
|
308
296
|
makeGetPendingTxIntentSignature(coins: ExtendedVirtualCoin[]): Promise<SignedIntent<Intent.GetPendingTxMessage>>;
|
|
@@ -6,9 +6,14 @@ export declare const CONTRACT_POLL_TASK_TYPE = "contract-poll";
|
|
|
6
6
|
*
|
|
7
7
|
* Replicates the polling subset of @see ContractManager.initialize:
|
|
8
8
|
* 1. Load all contracts from the contract repository.
|
|
9
|
-
* 2.
|
|
10
|
-
* 3.
|
|
11
|
-
* 4.
|
|
12
|
-
*
|
|
9
|
+
* 2. Paginated fetch of every VTXO (including spent) from the indexer.
|
|
10
|
+
* 3. Extend each VTXO with tapscript data.
|
|
11
|
+
* 4. Save to the wallet repository.
|
|
12
|
+
*
|
|
13
|
+
* NOTE: the indexer query deliberately omits `spendableOnly`. Every
|
|
14
|
+
* repository implements `saveVtxos` as an upsert with no batch delete,
|
|
15
|
+
* so filtering to spendable-only would leave VTXOs that became spent
|
|
16
|
+
* between polls marked as spendable forever. Fetching the full set lets
|
|
17
|
+
* the upsert overwrite stale records with their latest state.
|
|
13
18
|
*/
|
|
14
19
|
export declare const contractPollProcessor: TaskProcessor;
|
|
@@ -5,16 +5,20 @@ import type { IndexerProvider } from "../../providers/indexer";
|
|
|
5
5
|
import type { ArkProvider } from "../../providers/ark";
|
|
6
6
|
import type { ExtendedVirtualCoin, VirtualCoin } from "../../wallet";
|
|
7
7
|
import type { Contract } from "../../contracts/types";
|
|
8
|
-
import type { ReadonlyWallet } from "../../wallet/wallet";
|
|
9
8
|
/**
|
|
10
9
|
* Shared dependencies injected into every processor at runtime.
|
|
10
|
+
*
|
|
11
|
+
* `extendVtxo` requires the owning contract — processors must resolve each
|
|
12
|
+
* vtxo's `script` to a known contract (via the contract repository) before
|
|
13
|
+
* calling this. The strict signature prevents the footgun where a missing
|
|
14
|
+
* contract silently falls back to the wallet's default tapscript.
|
|
11
15
|
*/
|
|
12
16
|
export interface TaskDependencies {
|
|
13
17
|
walletRepository: WalletRepository;
|
|
14
18
|
contractRepository: ContractRepository;
|
|
15
19
|
indexerProvider: IndexerProvider;
|
|
16
20
|
arkProvider: ArkProvider;
|
|
17
|
-
extendVtxo: (vtxo: VirtualCoin, contract
|
|
21
|
+
extendVtxo: (vtxo: VirtualCoin, contract: Contract) => ExtendedVirtualCoin;
|
|
18
22
|
}
|
|
19
23
|
/**
|
|
20
24
|
* A stateless unit that handles one type of task item.
|
|
@@ -49,7 +53,6 @@ export interface CreateTaskDependenciesOptions {
|
|
|
49
53
|
contractRepository: ContractRepository;
|
|
50
54
|
indexerProvider: IndexerProvider;
|
|
51
55
|
arkProvider: ArkProvider;
|
|
52
|
-
offchainTapscript: ReadonlyWallet["offchainTapscript"];
|
|
53
56
|
}
|
|
54
57
|
/**
|
|
55
58
|
* Build the @see TaskDependencies needed by task processors
|