@arkade-os/sdk 0.5.0-rc.2 → 0.5.0-rc.20
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 +90 -83
- package/dist/adapters/expo.cjs +5 -6
- package/dist/adapters/expo.d.cts +4 -4
- package/dist/adapters/expo.d.ts +4 -4
- package/dist/adapters/expo.js +3 -4
- package/dist/{asyncStorageTaskQueue-C5rBYlru.d.ts → asyncStorageTaskQueue-aL7K14e4.d.ts} +2 -2
- package/dist/{asyncStorageTaskQueue-BuDvgWh6.d.cts → asyncStorageTaskQueue-x8ok3tJy.d.cts} +2 -2
- package/dist/{chunk-43FKNLX4.cjs → chunk-5SLUXXWQ.cjs} +357 -1114
- package/dist/chunk-5SLUXXWQ.cjs.map +1 -0
- package/dist/{chunk-HLCGYOIH.cjs → chunk-6YVGWOLG.cjs} +37 -36
- package/dist/chunk-6YVGWOLG.cjs.map +1 -0
- package/dist/{chunk-4PKLULWT.js → chunk-AARSVV3S.js} +109 -246
- package/dist/chunk-AARSVV3S.js.map +1 -0
- package/dist/{chunk-D25O4EGY.cjs → chunk-AFJSJACF.cjs} +12 -10
- package/dist/chunk-AFJSJACF.cjs.map +1 -0
- package/dist/{chunk-6DNR46C7.js → chunk-IM3J3T5P.js} +7 -5
- package/dist/chunk-IM3J3T5P.js.map +1 -0
- package/dist/{chunk-ISO4TI5J.js → chunk-NR4XYTN3.js} +566 -459
- package/dist/chunk-NR4XYTN3.js.map +1 -0
- package/dist/{chunk-ZRNQV6HV.js → chunk-O2ZZD5Z6.js} +4578 -4396
- package/dist/chunk-O2ZZD5Z6.js.map +1 -0
- package/dist/{chunk-ZOTXDOS5.js → chunk-P267BXL7.js} +30 -29
- package/dist/chunk-P267BXL7.js.map +1 -0
- package/dist/{chunk-NVZJSKZS.cjs → chunk-P42MGA4K.cjs} +121 -257
- package/dist/chunk-P42MGA4K.cjs.map +1 -0
- package/dist/{chunk-GMZZQXV5.cjs → chunk-QARA4IYT.cjs} +4961 -4767
- package/dist/chunk-QARA4IYT.cjs.map +1 -0
- package/dist/{chunk-JZWLXNHV.cjs → chunk-T6N6B7HK.cjs} +574 -464
- package/dist/chunk-T6N6B7HK.cjs.map +1 -0
- package/dist/{chunk-3R476TDV.js → chunk-TIVYJIIX.js} +293 -1071
- package/dist/chunk-TIVYJIIX.js.map +1 -0
- package/dist/contracts/handlers/index.cjs +9 -10
- package/dist/contracts/handlers/index.d.cts +5 -5
- package/dist/contracts/handlers/index.d.ts +5 -5
- package/dist/contracts/handlers/index.js +2 -3
- package/dist/{delegate-BAX5QftB.d.ts → delegate-BT5iON1T.d.ts} +1 -1
- package/dist/{delegate-1yp1HyP7.d.cts → delegate-u6kXTtWY.d.cts} +1 -1
- package/dist/index-BCnhItOQ.d.cts +639 -0
- package/dist/{index-DUxufw76.d.cts → index-CK5QbTmZ.d.cts} +1387 -2404
- package/dist/{index-DUxufw76.d.ts → index-CK5QbTmZ.d.ts} +1387 -2404
- package/dist/index-D1D4cR-G.d.ts +639 -0
- package/dist/index.cjs +375 -340
- package/dist/index.d.cts +784 -1197
- package/dist/index.d.ts +784 -1197
- package/dist/index.js +4 -5
- package/dist/repositories/realm/index.cjs +201 -106
- package/dist/repositories/realm/index.cjs.map +1 -1
- package/dist/repositories/realm/index.d.cts +28 -16
- package/dist/repositories/realm/index.d.ts +28 -16
- package/dist/repositories/realm/index.js +190 -95
- package/dist/repositories/realm/index.js.map +1 -1
- package/dist/repositories/sqlite/index.cjs +301 -189
- package/dist/repositories/sqlite/index.cjs.map +1 -1
- package/dist/repositories/sqlite/index.d.cts +32 -21
- package/dist/repositories/sqlite/index.d.ts +32 -21
- package/dist/repositories/sqlite/index.js +294 -182
- package/dist/repositories/sqlite/index.js.map +1 -1
- package/dist/{taskRunner-D_iPiZIi.d.ts → taskRunner-BeYR6NpQ.d.ts} +2 -2
- package/dist/{taskRunner-Dr3NStc0.d.cts → taskRunner-Csey3EYJ.d.cts} +2 -2
- package/dist/wallet/expo/background.cjs +14 -15
- package/dist/wallet/expo/background.cjs.map +1 -1
- package/dist/wallet/expo/background.d.cts +10 -16
- package/dist/wallet/expo/background.d.ts +10 -16
- package/dist/wallet/expo/background.js +6 -7
- package/dist/wallet/expo/background.js.map +1 -1
- package/dist/wallet/expo/index.cjs +16 -23
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +6 -9
- package/dist/wallet/expo/index.d.ts +6 -9
- package/dist/wallet/expo/index.js +8 -15
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/wallet-DG3Qmbmt.d.cts +1848 -0
- package/dist/wallet-DzSLMxBZ.d.ts +1848 -0
- package/dist/worker/expo/index.cjs +9 -10
- package/dist/worker/expo/index.cjs.map +1 -1
- package/dist/worker/expo/index.d.cts +6 -6
- package/dist/worker/expo/index.d.ts +6 -6
- package/dist/worker/expo/index.js +5 -6
- package/dist/worker/expo/index.js.map +1 -1
- package/package.json +12 -51
- package/dist/adapters/asyncStorage.cjs +0 -48
- package/dist/adapters/asyncStorage.cjs.map +0 -1
- package/dist/adapters/asyncStorage.d.cts +0 -16
- package/dist/adapters/asyncStorage.d.ts +0 -16
- package/dist/adapters/asyncStorage.js +0 -46
- package/dist/adapters/asyncStorage.js.map +0 -1
- package/dist/adapters/fileSystem.cjs +0 -116
- package/dist/adapters/fileSystem.cjs.map +0 -1
- package/dist/adapters/fileSystem.d.cts +0 -17
- package/dist/adapters/fileSystem.d.ts +0 -17
- package/dist/adapters/fileSystem.js +0 -93
- package/dist/adapters/fileSystem.js.map +0 -1
- package/dist/adapters/indexedDB.cjs +0 -103
- package/dist/adapters/indexedDB.cjs.map +0 -1
- package/dist/adapters/indexedDB.d.cts +0 -18
- package/dist/adapters/indexedDB.d.ts +0 -18
- package/dist/adapters/indexedDB.js +0 -101
- package/dist/adapters/indexedDB.js.map +0 -1
- package/dist/adapters/localStorage.cjs +0 -50
- package/dist/adapters/localStorage.cjs.map +0 -1
- package/dist/adapters/localStorage.d.cts +0 -14
- package/dist/adapters/localStorage.d.ts +0 -14
- package/dist/adapters/localStorage.js +0 -48
- package/dist/adapters/localStorage.js.map +0 -1
- package/dist/chunk-3R476TDV.js.map +0 -1
- package/dist/chunk-43FKNLX4.cjs.map +0 -1
- package/dist/chunk-4PKLULWT.js.map +0 -1
- package/dist/chunk-5BLDMQED.cjs +0 -18
- package/dist/chunk-5BLDMQED.cjs.map +0 -1
- package/dist/chunk-6DNR46C7.js.map +0 -1
- package/dist/chunk-D25O4EGY.cjs.map +0 -1
- package/dist/chunk-GMZZQXV5.cjs.map +0 -1
- package/dist/chunk-HLCGYOIH.cjs.map +0 -1
- package/dist/chunk-ISO4TI5J.js.map +0 -1
- package/dist/chunk-JZWLXNHV.cjs.map +0 -1
- package/dist/chunk-NSBPE2FW.js +0 -15
- package/dist/chunk-NSBPE2FW.js.map +0 -1
- package/dist/chunk-NVZJSKZS.cjs.map +0 -1
- package/dist/chunk-ZOTXDOS5.js.map +0 -1
- package/dist/chunk-ZRNQV6HV.js.map +0 -1
- package/dist/hdWalletCapable-CmEU0NP1.d.ts +0 -2232
- package/dist/hdWalletCapable-eJgaT-ec.d.cts +0 -2232
- package/dist/index-Bem5vKzX.d.ts +0 -850
- package/dist/index-C0IanN1m.d.cts +0 -11
- package/dist/index-C0IanN1m.d.ts +0 -11
- package/dist/index-W_oMcOmG.d.cts +0 -850
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { scriptFromArkAddress, serializeVtxo,
|
|
2
|
-
export { ChainedTxType } from '../../chunk-
|
|
3
|
-
import '../../chunk-
|
|
4
|
-
import '../../chunk-
|
|
5
|
-
import '../../chunk-
|
|
6
|
-
import '../../chunk-NSBPE2FW.js';
|
|
1
|
+
import { scriptFromArkAddress, legacyVtxoFacts, serializeVtxo, createdAtToIso, assertPageRequest, pageResult, checkSaveVtxosForScript, utxoEntries, serializeUtxo, assertHistoryPageFilter, serializeAssets, deserializeVtxo, deserializeUtxo, deserializeAssets, contractFilterMatchesNothing, intentMatchesFilter, isTerminalIntentState, mergeChainedTxType } from '../../chunk-O2ZZD5Z6.js';
|
|
2
|
+
export { ChainedTxType } from '../../chunk-O2ZZD5Z6.js';
|
|
3
|
+
import '../../chunk-AARSVV3S.js';
|
|
4
|
+
import '../../chunk-TIVYJIIX.js';
|
|
5
|
+
import { isVtxoSpent } from '../../chunk-NR4XYTN3.js';
|
|
7
6
|
|
|
8
7
|
// src/repositories/sqlite/transaction.ts
|
|
9
8
|
var writeChains = /* @__PURE__ */ new WeakMap();
|
|
@@ -30,11 +29,19 @@ function runInTransaction(db, fn) {
|
|
|
30
29
|
return run;
|
|
31
30
|
}
|
|
32
31
|
|
|
32
|
+
// src/repositories/sqlite/prefix.ts
|
|
33
|
+
var SAFE_PREFIX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
34
|
+
function sanitizeTablePrefix(p) {
|
|
35
|
+
if (!SAFE_PREFIX.test(p)) throw new Error(`Invalid table prefix "${p}"`);
|
|
36
|
+
return p;
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
// src/repositories/sqlite/walletRepository.ts
|
|
40
|
+
var MAX_BOUND_PARAMETERS = 999;
|
|
34
41
|
var SQLiteWalletRepository = class {
|
|
35
42
|
constructor(db, options) {
|
|
36
43
|
this.db = db;
|
|
37
|
-
this.prefix =
|
|
44
|
+
this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
|
|
38
45
|
this.tables = {
|
|
39
46
|
vtxos: `${this.prefix}vtxos`,
|
|
40
47
|
utxos: `${this.prefix}utxos`,
|
|
@@ -43,7 +50,7 @@ var SQLiteWalletRepository = class {
|
|
|
43
50
|
};
|
|
44
51
|
}
|
|
45
52
|
db;
|
|
46
|
-
version =
|
|
53
|
+
version = 2;
|
|
47
54
|
initPromise = null;
|
|
48
55
|
prefix;
|
|
49
56
|
tables;
|
|
@@ -99,23 +106,42 @@ var SQLiteWalletRepository = class {
|
|
|
99
106
|
await this.db.run(
|
|
100
107
|
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}vtxos_script ON ${this.tables.vtxos} (script)`
|
|
101
108
|
);
|
|
109
|
+
await this.db.run(
|
|
110
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}vtxos_script_page ON ${this.tables.vtxos} (script, address, txid, vout)`
|
|
111
|
+
);
|
|
112
|
+
await this.db.run(
|
|
113
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}vtxos_address_page ON ${this.tables.vtxos} (address, txid, vout)`
|
|
114
|
+
);
|
|
115
|
+
await this.db.run(`DROP INDEX IF EXISTS idx_${this.prefix}vtxos_live_script`);
|
|
116
|
+
await this.db.run(
|
|
117
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}vtxos_live_script_page ON ${this.tables.vtxos} (script, address, txid, vout)
|
|
118
|
+
WHERE ${UNSPENT_VTXO_PREDICATE}`
|
|
119
|
+
);
|
|
102
120
|
await this.db.run(
|
|
103
121
|
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}utxos_address ON ${this.tables.utxos} (address)`
|
|
104
122
|
);
|
|
123
|
+
await this.db.run(
|
|
124
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}utxos_address_page ON ${this.tables.utxos} (address, txid, vout)`
|
|
125
|
+
);
|
|
105
126
|
await this.db.run(
|
|
106
127
|
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}transactions_address ON ${this.tables.transactions} (address)`
|
|
107
128
|
);
|
|
129
|
+
await this.db.run(
|
|
130
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}transactions_history ON ${this.tables.transactions} (address, created_at, boarding_txid, commitment_txid, ark_txid)`
|
|
131
|
+
);
|
|
108
132
|
}
|
|
109
133
|
/**
|
|
110
134
|
* Bring the `vtxos` table to the current schema (v1 = `script` NOT NULL).
|
|
111
135
|
*
|
|
112
|
-
*
|
|
136
|
+
* Four cases:
|
|
113
137
|
* - Fresh install: create the v1 schema directly.
|
|
114
138
|
* - Legacy install without a `script` column: add it, backfill from
|
|
115
139
|
* `address`, then rebuild the table with NOT NULL (SQLite cannot add
|
|
116
140
|
* the NOT NULL constraint in place).
|
|
117
141
|
* - Legacy install with a nullable `script` column: backfill the NULLs
|
|
118
142
|
* and rebuild.
|
|
143
|
+
* - 0.4.x install: `script` is already NOT NULL but `virtual_status_json
|
|
144
|
+
* NOT NULL` is still there, and `saveVtxos` no longer writes it.
|
|
119
145
|
*
|
|
120
146
|
* The backfill derives `script` from the Ark address, matching what the
|
|
121
147
|
* indexer would have returned — new rows from the indexer always carry a
|
|
@@ -143,7 +169,27 @@ var SQLiteWalletRepository = class {
|
|
|
143
169
|
`PRAGMA table_info(${this.tables.vtxos})`
|
|
144
170
|
);
|
|
145
171
|
const scriptCol = cols.find((c) => c.name === "script");
|
|
146
|
-
|
|
172
|
+
const nullableCanonicalColumns = [
|
|
173
|
+
["is_swept", "INTEGER"],
|
|
174
|
+
["is_preconfirmed", "INTEGER"],
|
|
175
|
+
["commitment_txids_json", "TEXT"],
|
|
176
|
+
["expires_at", "TEXT"],
|
|
177
|
+
["expires_at_height", "INTEGER"]
|
|
178
|
+
];
|
|
179
|
+
let addedCanonicalColumns = false;
|
|
180
|
+
for (const [name, type] of nullableCanonicalColumns) {
|
|
181
|
+
if (!cols.some((c) => c.name === name)) {
|
|
182
|
+
await this.db.run(
|
|
183
|
+
`ALTER TABLE ${this.tables.vtxos} ADD COLUMN ${name} ${type}`
|
|
184
|
+
);
|
|
185
|
+
addedCanonicalColumns = true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const hasLegacyBlob = cols.some((c) => c.name === "virtual_status_json");
|
|
189
|
+
if (addedCanonicalColumns && hasLegacyBlob) {
|
|
190
|
+
await this.backfillCanonicalVtxoColumns();
|
|
191
|
+
}
|
|
192
|
+
if (scriptCol && scriptCol.notnull === 1 && !hasLegacyBlob) {
|
|
147
193
|
return;
|
|
148
194
|
}
|
|
149
195
|
if (!scriptCol) {
|
|
@@ -163,20 +209,58 @@ var SQLiteWalletRepository = class {
|
|
|
163
209
|
INSERT INTO ${tempName}
|
|
164
210
|
(txid, vout, value, address, tap_tree,
|
|
165
211
|
forfeit_cb, forfeit_s, intent_cb, intent_s,
|
|
166
|
-
status_json,
|
|
167
|
-
|
|
168
|
-
|
|
212
|
+
status_json, created_at, is_unrolled, is_spent,
|
|
213
|
+
is_swept, is_preconfirmed, commitment_txids_json,
|
|
214
|
+
expires_at, expires_at_height,
|
|
215
|
+
spent_by, settled_by, ark_tx_id, extra_witness_json, assets_json, script)
|
|
169
216
|
SELECT txid, vout, value, address, tap_tree,
|
|
170
217
|
forfeit_cb, forfeit_s, intent_cb, intent_s,
|
|
171
|
-
status_json,
|
|
172
|
-
|
|
173
|
-
|
|
218
|
+
status_json, created_at, is_unrolled, is_spent,
|
|
219
|
+
is_swept, is_preconfirmed, commitment_txids_json,
|
|
220
|
+
expires_at, expires_at_height,
|
|
221
|
+
spent_by, settled_by, ark_tx_id, extra_witness_json, assets_json, script
|
|
174
222
|
FROM ${this.tables.vtxos}
|
|
175
223
|
`);
|
|
176
224
|
await this.db.run(`DROP TABLE ${this.tables.vtxos}`);
|
|
177
225
|
await this.db.run(`ALTER TABLE ${tempName} RENAME TO ${this.tables.vtxos}`);
|
|
178
226
|
});
|
|
179
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Copy the canonical VTXO facts out of the legacy `virtual_status_json` blob.
|
|
230
|
+
*
|
|
231
|
+
* Scoped to rows that still have `is_swept` NULL, which is what "never backfilled" looks
|
|
232
|
+
* like: the copy writes 0 or 1 to every row it touches, so a second pass — a later column
|
|
233
|
+
* addition, say — cannot overwrite what an indexer sync has since corrected. Rows whose blob
|
|
234
|
+
* is missing or corrupt are left alone: a migration must not be stopped by one bad row, and
|
|
235
|
+
* the next sync repairs it.
|
|
236
|
+
*/
|
|
237
|
+
async backfillCanonicalVtxoColumns() {
|
|
238
|
+
const rows = await this.db.all(
|
|
239
|
+
`SELECT txid, vout, virtual_status_json FROM ${this.tables.vtxos}
|
|
240
|
+
WHERE virtual_status_json IS NOT NULL AND is_swept IS NULL`
|
|
241
|
+
);
|
|
242
|
+
for (const row of rows) {
|
|
243
|
+
const facts = legacyVtxoFacts(row.virtual_status_json);
|
|
244
|
+
if (!facts) continue;
|
|
245
|
+
await this.db.run(
|
|
246
|
+
`UPDATE ${this.tables.vtxos}
|
|
247
|
+
SET is_swept = ?, is_preconfirmed = ?, commitment_txids_json = ?,
|
|
248
|
+
expires_at = ?, expires_at_height = ?,
|
|
249
|
+
is_spent = COALESCE(is_spent, ?)
|
|
250
|
+
WHERE txid = ? AND vout = ?`,
|
|
251
|
+
[
|
|
252
|
+
facts.isSwept ? 1 : 0,
|
|
253
|
+
facts.isPreconfirmed ? 1 : 0,
|
|
254
|
+
facts.commitmentTxIds ? JSON.stringify(facts.commitmentTxIds) : null,
|
|
255
|
+
facts.expiresAt ? facts.expiresAt.toISOString() : null,
|
|
256
|
+
facts.expiresAtHeight ?? null,
|
|
257
|
+
facts.isSpent ? 1 : 0,
|
|
258
|
+
row.txid,
|
|
259
|
+
row.vout
|
|
260
|
+
]
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
180
264
|
vtxosCreateSql(tableName) {
|
|
181
265
|
return `CREATE TABLE ${tableName} (
|
|
182
266
|
txid TEXT NOT NULL,
|
|
@@ -189,10 +273,14 @@ var SQLiteWalletRepository = class {
|
|
|
189
273
|
intent_cb TEXT NOT NULL,
|
|
190
274
|
intent_s TEXT NOT NULL,
|
|
191
275
|
status_json TEXT NOT NULL,
|
|
192
|
-
virtual_status_json TEXT NOT NULL,
|
|
193
276
|
created_at TEXT NOT NULL,
|
|
194
277
|
is_unrolled INTEGER NOT NULL DEFAULT 0,
|
|
195
278
|
is_spent INTEGER,
|
|
279
|
+
is_swept INTEGER,
|
|
280
|
+
is_preconfirmed INTEGER,
|
|
281
|
+
commitment_txids_json TEXT,
|
|
282
|
+
expires_at TEXT,
|
|
283
|
+
expires_at_height INTEGER,
|
|
196
284
|
spent_by TEXT,
|
|
197
285
|
settled_by TEXT,
|
|
198
286
|
ark_tx_id TEXT,
|
|
@@ -202,6 +290,23 @@ var SQLiteWalletRepository = class {
|
|
|
202
290
|
PRIMARY KEY (txid, vout)
|
|
203
291
|
)`;
|
|
204
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* `INSERT OR REPLACE` rows, as many to a statement as the parameter budget allows.
|
|
295
|
+
* No enclosing transaction: on the shared connection it would take in other repos' writes.
|
|
296
|
+
*/
|
|
297
|
+
async insertOrReplace(table, columns, rows) {
|
|
298
|
+
const width = columns.split(",").length;
|
|
299
|
+
const tuple = `(${Array(width).fill("?").join(", ")})`;
|
|
300
|
+
const rowsPerStatement = Math.floor(MAX_BOUND_PARAMETERS / width);
|
|
301
|
+
for (let i = 0; i < rows.length; i += rowsPerStatement) {
|
|
302
|
+
const chunk = rows.slice(i, i + rowsPerStatement);
|
|
303
|
+
await this.db.run(
|
|
304
|
+
`INSERT OR REPLACE INTO ${table} (${columns})
|
|
305
|
+
VALUES ${chunk.map(() => tuple).join(", ")}`,
|
|
306
|
+
chunk.flat()
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
205
310
|
async [Symbol.asyncDispose]() {
|
|
206
311
|
}
|
|
207
312
|
// ── Clear ──────────────────────────────────────────────────────────
|
|
@@ -213,31 +318,22 @@ var SQLiteWalletRepository = class {
|
|
|
213
318
|
await this.db.run(`DELETE FROM ${this.tables.walletState}`);
|
|
214
319
|
}
|
|
215
320
|
// ── VTXO management ────────────────────────────────────────────────
|
|
216
|
-
async
|
|
217
|
-
|
|
218
|
-
const rows = await this.db.all(
|
|
219
|
-
`SELECT * FROM ${this.tables.vtxos} WHERE address = ?`,
|
|
220
|
-
[address]
|
|
221
|
-
);
|
|
222
|
-
return rows.map(vtxoRowToDomain);
|
|
321
|
+
async getVtxosPage(address, page) {
|
|
322
|
+
return this.pageByAddress(this.tables.vtxos, address, page, vtxoRowToDomain);
|
|
223
323
|
}
|
|
224
324
|
async saveVtxos(address, vtxos) {
|
|
225
325
|
await this.ensureInit();
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
?, ?, ?,
|
|
238
|
-
?, ?, ?, ?, ?,
|
|
239
|
-
?, ?, ?)`,
|
|
240
|
-
[
|
|
326
|
+
await this.insertOrReplace(
|
|
327
|
+
this.tables.vtxos,
|
|
328
|
+
`txid, vout, value, address,
|
|
329
|
+
tap_tree, forfeit_cb, forfeit_s, intent_cb, intent_s,
|
|
330
|
+
status_json, created_at, is_unrolled, is_spent,
|
|
331
|
+
is_swept, is_preconfirmed, commitment_txids_json,
|
|
332
|
+
expires_at, expires_at_height,
|
|
333
|
+
spent_by, settled_by, ark_tx_id, extra_witness_json, assets_json, script`,
|
|
334
|
+
vtxos.map((vtxo) => {
|
|
335
|
+
const s = serializeVtxo(vtxo);
|
|
336
|
+
return [
|
|
241
337
|
s.txid,
|
|
242
338
|
s.vout,
|
|
243
339
|
s.value,
|
|
@@ -248,71 +344,82 @@ var SQLiteWalletRepository = class {
|
|
|
248
344
|
s.intentTapLeafScript.cb,
|
|
249
345
|
s.intentTapLeafScript.s,
|
|
250
346
|
JSON.stringify(s.status),
|
|
251
|
-
|
|
252
|
-
typeof s.createdAt === "string" ? s.createdAt : s.createdAt instanceof Date ? s.createdAt.toISOString() : new Date(s.createdAt).toISOString(),
|
|
347
|
+
createdAtToIso(s.createdAt),
|
|
253
348
|
s.isUnrolled ? 1 : 0,
|
|
254
349
|
s.isSpent === void 0 ? null : s.isSpent ? 1 : 0,
|
|
350
|
+
s.isSwept === void 0 ? null : s.isSwept ? 1 : 0,
|
|
351
|
+
s.isPreconfirmed === void 0 ? null : s.isPreconfirmed ? 1 : 0,
|
|
352
|
+
s.commitmentTxIds ? JSON.stringify(s.commitmentTxIds) : null,
|
|
353
|
+
s.expiresAt === void 0 ? null : new Date(s.expiresAt).toISOString(),
|
|
354
|
+
s.expiresAtHeight ?? null,
|
|
255
355
|
s.spentBy ?? null,
|
|
256
356
|
s.settledBy ?? null,
|
|
257
357
|
s.arkTxId ?? null,
|
|
258
358
|
s.extraWitness ? JSON.stringify(s.extraWitness) : null,
|
|
259
359
|
s.assets ? JSON.stringify(s.assets) : null,
|
|
260
360
|
s.script ?? null
|
|
261
|
-
]
|
|
262
|
-
)
|
|
263
|
-
|
|
361
|
+
];
|
|
362
|
+
})
|
|
363
|
+
);
|
|
264
364
|
}
|
|
265
365
|
async deleteVtxos(address) {
|
|
266
366
|
await this.ensureInit();
|
|
267
367
|
await this.db.run(`DELETE FROM ${this.tables.vtxos} WHERE address = ?`, [address]);
|
|
268
368
|
}
|
|
269
|
-
async
|
|
369
|
+
async getVtxosForScriptPage(script, page, options) {
|
|
370
|
+
assertPageRequest(page);
|
|
270
371
|
await this.ensureInit();
|
|
372
|
+
const after = page.after;
|
|
271
373
|
const rows = await this.db.all(
|
|
272
|
-
`SELECT * FROM ${this.tables.vtxos} WHERE script =
|
|
273
|
-
|
|
374
|
+
`SELECT * FROM ${this.tables.vtxos} WHERE script = ?
|
|
375
|
+
${options?.unspentOnly ? `AND ${UNSPENT_VTXO_PREDICATE}` : ""}
|
|
376
|
+
${after ? "AND (address > ? OR (address = ? AND (txid > ? OR (txid = ? AND vout > ?))))" : ""}
|
|
377
|
+
ORDER BY address, txid, vout LIMIT ?`,
|
|
378
|
+
after ? [
|
|
379
|
+
script,
|
|
380
|
+
after.address,
|
|
381
|
+
after.address,
|
|
382
|
+
after.txid,
|
|
383
|
+
after.txid,
|
|
384
|
+
after.vout,
|
|
385
|
+
page.limit + 1
|
|
386
|
+
] : [script, page.limit + 1]
|
|
274
387
|
);
|
|
275
|
-
|
|
388
|
+
const result = pageResult(
|
|
389
|
+
rows.map((row) => ({ address: row.address, vtxo: vtxoRowToDomain(row) })),
|
|
390
|
+
page.limit,
|
|
391
|
+
(row) => ({ address: row.address, txid: row.vtxo.txid, vout: row.vtxo.vout })
|
|
392
|
+
);
|
|
393
|
+
return options?.unspentOnly ? { ...result, items: result.items.filter((row) => !isVtxoSpent(row.vtxo)) } : result;
|
|
276
394
|
}
|
|
277
395
|
async saveVtxosForScript(key, vtxos) {
|
|
278
|
-
|
|
279
|
-
throw new Error("SQLiteWalletRepository requires an address");
|
|
280
|
-
}
|
|
281
|
-
for (const vtxo of vtxos) {
|
|
282
|
-
if (!isVtxoForScript(vtxo, key.script)) {
|
|
283
|
-
throw new Error(
|
|
284
|
-
`VTXO ${vtxo.txid}:${vtxo.vout} script mismatch: expected ${key.script}, got ${vtxo.script}`
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return this.saveVtxos(key.address, vtxos);
|
|
396
|
+
return this.saveVtxos(checkSaveVtxosForScript("SQLiteWalletRepository", key, vtxos), vtxos);
|
|
289
397
|
}
|
|
290
398
|
async deleteVtxosForScript(script) {
|
|
291
399
|
await this.ensureInit();
|
|
292
400
|
await this.db.run(`DELETE FROM ${this.tables.vtxos} WHERE script = ?`, [script]);
|
|
293
401
|
}
|
|
294
402
|
// ── UTXO management ────────────────────────────────────────────────
|
|
295
|
-
async
|
|
403
|
+
async getUtxosPage(address, page) {
|
|
404
|
+
return this.pageByAddress(this.tables.utxos, address, page, utxoRowToDomain);
|
|
405
|
+
}
|
|
406
|
+
async pageByAddress(table, address, page, deserialize) {
|
|
407
|
+
assertPageRequest(page);
|
|
296
408
|
await this.ensureInit();
|
|
297
409
|
const rows = await this.db.all(
|
|
298
|
-
`SELECT * FROM ${
|
|
299
|
-
|
|
410
|
+
`SELECT * FROM ${table} WHERE address = ? AND (txid, vout) > (?, ?)
|
|
411
|
+
ORDER BY txid, vout LIMIT ?`,
|
|
412
|
+
[address, page.after?.txid ?? "", page.after?.vout ?? -1, page.limit + 1]
|
|
300
413
|
);
|
|
301
|
-
|
|
414
|
+
const result = pageResult(rows, page.limit, ({ txid, vout }) => ({ txid, vout }));
|
|
415
|
+
return { items: result.items.map(deserialize), nextCursor: result.nextCursor };
|
|
302
416
|
}
|
|
303
|
-
async saveUtxos(
|
|
417
|
+
async saveUtxos(addressOrBatch, utxos) {
|
|
304
418
|
await this.ensureInit();
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
(txid, vout, value, address,
|
|
310
|
-
tap_tree, forfeit_cb, forfeit_s, intent_cb, intent_s,
|
|
311
|
-
status_json, extra_witness_json)
|
|
312
|
-
VALUES (?, ?, ?, ?,
|
|
313
|
-
?, ?, ?, ?, ?,
|
|
314
|
-
?, ?)`,
|
|
315
|
-
[
|
|
419
|
+
const rows = utxoEntries(addressOrBatch, utxos).flatMap(
|
|
420
|
+
([address, list]) => list.map((utxo) => {
|
|
421
|
+
const s = serializeUtxo(utxo);
|
|
422
|
+
return [
|
|
316
423
|
s.txid,
|
|
317
424
|
s.vout,
|
|
318
425
|
s.value,
|
|
@@ -324,45 +431,71 @@ var SQLiteWalletRepository = class {
|
|
|
324
431
|
s.intentTapLeafScript.s,
|
|
325
432
|
JSON.stringify(s.status),
|
|
326
433
|
s.extraWitness ? JSON.stringify(s.extraWitness) : null
|
|
327
|
-
]
|
|
328
|
-
)
|
|
329
|
-
|
|
434
|
+
];
|
|
435
|
+
})
|
|
436
|
+
);
|
|
437
|
+
await this.insertOrReplace(
|
|
438
|
+
this.tables.utxos,
|
|
439
|
+
`txid, vout, value, address,
|
|
440
|
+
tap_tree, forfeit_cb, forfeit_s, intent_cb, intent_s,
|
|
441
|
+
status_json, extra_witness_json`,
|
|
442
|
+
rows
|
|
443
|
+
);
|
|
330
444
|
}
|
|
331
445
|
async deleteUtxos(address) {
|
|
332
446
|
await this.ensureInit();
|
|
333
447
|
await this.db.run(`DELETE FROM ${this.tables.utxos} WHERE address = ?`, [address]);
|
|
334
448
|
}
|
|
335
449
|
// ── Transaction history ────────────────────────────────────────────
|
|
336
|
-
async
|
|
450
|
+
async getTransactionHistoryPage(filter, page) {
|
|
451
|
+
assertPageRequest(page);
|
|
452
|
+
assertHistoryPageFilter(filter);
|
|
337
453
|
await this.ensureInit();
|
|
454
|
+
const conditions = ["address = ?"];
|
|
455
|
+
const params = [filter.address];
|
|
456
|
+
if (filter.since !== void 0) {
|
|
457
|
+
conditions.push("created_at >= ?");
|
|
458
|
+
params.push(filter.since);
|
|
459
|
+
}
|
|
460
|
+
if (page.after !== void 0) {
|
|
461
|
+
conditions.push(
|
|
462
|
+
"(created_at, boarding_txid, commitment_txid, ark_txid) > (?, ?, ?, ?)"
|
|
463
|
+
);
|
|
464
|
+
params.push(
|
|
465
|
+
page.after.createdAt,
|
|
466
|
+
page.after.key.boardingTxid,
|
|
467
|
+
page.after.key.commitmentTxid,
|
|
468
|
+
page.after.key.arkTxid
|
|
469
|
+
);
|
|
470
|
+
}
|
|
338
471
|
const rows = await this.db.all(
|
|
339
|
-
`SELECT * FROM ${this.tables.transactions} WHERE
|
|
340
|
-
|
|
472
|
+
`SELECT * FROM ${this.tables.transactions} WHERE ${conditions.join(" AND ")}
|
|
473
|
+
ORDER BY created_at, boarding_txid, commitment_txid, ark_txid LIMIT ?`,
|
|
474
|
+
[...params, page.limit + 1]
|
|
341
475
|
);
|
|
342
|
-
return rows.map(txRowToDomain)
|
|
476
|
+
return pageResult(rows.map(txRowToDomain), page.limit, (tx) => ({
|
|
477
|
+
createdAt: tx.createdAt,
|
|
478
|
+
key: tx.key
|
|
479
|
+
}));
|
|
343
480
|
}
|
|
344
481
|
async saveTransactions(address, txs) {
|
|
345
482
|
await this.ensureInit();
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
tx.assets ? JSON.stringify(serializeAssets(tx.assets)) : null
|
|
363
|
-
]
|
|
364
|
-
);
|
|
365
|
-
}
|
|
483
|
+
await this.insertOrReplace(
|
|
484
|
+
this.tables.transactions,
|
|
485
|
+
`address, boarding_txid, commitment_txid, ark_txid,
|
|
486
|
+
type, amount, settled, created_at, assets_json`,
|
|
487
|
+
txs.map((tx) => [
|
|
488
|
+
address,
|
|
489
|
+
tx.key.boardingTxid,
|
|
490
|
+
tx.key.commitmentTxid,
|
|
491
|
+
tx.key.arkTxid,
|
|
492
|
+
tx.type,
|
|
493
|
+
tx.amount,
|
|
494
|
+
tx.settled ? 1 : 0,
|
|
495
|
+
tx.createdAt,
|
|
496
|
+
tx.assets ? JSON.stringify(serializeAssets(tx.assets)) : null
|
|
497
|
+
])
|
|
498
|
+
);
|
|
366
499
|
}
|
|
367
500
|
async deleteTransactions(address) {
|
|
368
501
|
await this.ensureInit();
|
|
@@ -397,15 +530,7 @@ var SQLiteWalletRepository = class {
|
|
|
397
530
|
);
|
|
398
531
|
}
|
|
399
532
|
};
|
|
400
|
-
var
|
|
401
|
-
function sanitizePrefix(prefix) {
|
|
402
|
-
if (!SAFE_PREFIX.test(prefix)) {
|
|
403
|
-
throw new Error(
|
|
404
|
-
`Invalid table prefix "${prefix}": only letters, digits, and underscores are allowed`
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
return prefix;
|
|
408
|
-
}
|
|
533
|
+
var UNSPENT_VTXO_PREDICATE = "(is_spent IS NULL OR is_spent = 0) AND (spent_by IS NULL OR spent_by = '') AND (settled_by IS NULL OR settled_by = '')";
|
|
409
534
|
function vtxoRowToDomain(row) {
|
|
410
535
|
const serialized = {
|
|
411
536
|
txid: row.txid,
|
|
@@ -421,10 +546,14 @@ function vtxoRowToDomain(row) {
|
|
|
421
546
|
s: row.intent_s
|
|
422
547
|
},
|
|
423
548
|
status: JSON.parse(row.status_json),
|
|
424
|
-
virtualStatus: JSON.parse(row.virtual_status_json),
|
|
425
549
|
createdAt: new Date(row.created_at),
|
|
426
550
|
isUnrolled: row.is_unrolled === 1,
|
|
427
551
|
isSpent: row.is_spent === null ? void 0 : row.is_spent === 1,
|
|
552
|
+
isSwept: row.is_swept == null ? void 0 : row.is_swept === 1,
|
|
553
|
+
isPreconfirmed: row.is_preconfirmed == null ? void 0 : row.is_preconfirmed === 1,
|
|
554
|
+
commitmentTxIds: row.commitment_txids_json ? JSON.parse(row.commitment_txids_json) : void 0,
|
|
555
|
+
expiresAt: row.expires_at ? new Date(row.expires_at) : void 0,
|
|
556
|
+
expiresAtHeight: row.expires_at_height ?? void 0,
|
|
428
557
|
spentBy: row.spent_by ?? void 0,
|
|
429
558
|
settledBy: row.settled_by ?? void 0,
|
|
430
559
|
arkTxId: row.ark_tx_id ?? void 0,
|
|
@@ -475,14 +604,15 @@ function txRowToDomain(row) {
|
|
|
475
604
|
}
|
|
476
605
|
|
|
477
606
|
// src/repositories/sqlite/contractRepository.ts
|
|
607
|
+
var WATCH_STATE = "IFNULL(watch, 'watched')";
|
|
478
608
|
var SQLiteContractRepository = class {
|
|
479
609
|
constructor(db, options) {
|
|
480
610
|
this.db = db;
|
|
481
|
-
this.prefix =
|
|
611
|
+
this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
|
|
482
612
|
this.table = `${this.prefix}contracts`;
|
|
483
613
|
}
|
|
484
614
|
db;
|
|
485
|
-
version =
|
|
615
|
+
version = 3;
|
|
486
616
|
initPromise = null;
|
|
487
617
|
prefix;
|
|
488
618
|
table;
|
|
@@ -515,6 +645,12 @@ var SQLiteContractRepository = class {
|
|
|
515
645
|
await this.db.run(
|
|
516
646
|
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}contracts_state ON ${this.table} (state)`
|
|
517
647
|
);
|
|
648
|
+
await this.db.run(
|
|
649
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}contracts_watch_state ON ${this.table} (${WATCH_STATE}, script)`
|
|
650
|
+
);
|
|
651
|
+
await this.db.run(
|
|
652
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}contracts_type_watch_state ON ${this.table} (type, ${WATCH_STATE}, script)`
|
|
653
|
+
);
|
|
518
654
|
}
|
|
519
655
|
async addColumnIfMissing(column, type) {
|
|
520
656
|
const columns = await this.db.all(`PRAGMA table_info(${this.table})`);
|
|
@@ -529,22 +665,28 @@ var SQLiteContractRepository = class {
|
|
|
529
665
|
await this.db.run(`DELETE FROM ${this.table}`);
|
|
530
666
|
}
|
|
531
667
|
// ── Contract management ────────────────────────────────────────────
|
|
532
|
-
async
|
|
668
|
+
async getContractsPage(filter, page) {
|
|
669
|
+
assertPageRequest(page);
|
|
533
670
|
await this.ensureInit();
|
|
671
|
+
if (contractFilterMatchesNothing(filter)) return { items: [] };
|
|
534
672
|
const conditions = [];
|
|
535
673
|
const params = [];
|
|
536
674
|
if (filter) {
|
|
537
675
|
this.addFilterCondition(conditions, params, "script", filter.script);
|
|
538
676
|
this.addFilterCondition(conditions, params, "state", filter.state);
|
|
539
677
|
this.addFilterCondition(conditions, params, "type", filter.type);
|
|
540
|
-
this.
|
|
678
|
+
this.addFilterCondition(conditions, params, WATCH_STATE, filter.watch);
|
|
541
679
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
680
|
+
if (page.after !== void 0) {
|
|
681
|
+
conditions.push("script > ?");
|
|
682
|
+
params.push(page.after);
|
|
545
683
|
}
|
|
546
|
-
const
|
|
547
|
-
|
|
684
|
+
const where = conditions.length ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
685
|
+
const rows = await this.db.all(
|
|
686
|
+
`SELECT * FROM ${this.table}${where} ORDER BY script LIMIT ?`,
|
|
687
|
+
[...params, page.limit + 1]
|
|
688
|
+
);
|
|
689
|
+
return pageResult(rows.map(contractRowToDomain), page.limit, (contract) => contract.script);
|
|
548
690
|
}
|
|
549
691
|
async saveContract(contract) {
|
|
550
692
|
await this.ensureInit();
|
|
@@ -584,29 +726,7 @@ var SQLiteContractRepository = class {
|
|
|
584
726
|
params.push(value);
|
|
585
727
|
}
|
|
586
728
|
}
|
|
587
|
-
/**
|
|
588
|
-
* Same as {@link addFilterCondition}, except a row predating the
|
|
589
|
-
* column stores NULL and must match `"watched"`.
|
|
590
|
-
*/
|
|
591
|
-
addWatchCondition(conditions, params, value) {
|
|
592
|
-
if (value === void 0) return;
|
|
593
|
-
const wanted = Array.isArray(value) ? value : [value];
|
|
594
|
-
if (wanted.length === 0) return;
|
|
595
|
-
const placeholders = wanted.map(() => "?").join(", ");
|
|
596
|
-
const clause = `watch IN (${placeholders})`;
|
|
597
|
-
conditions.push(wanted.includes("watched") ? `(${clause} OR watch IS NULL)` : clause);
|
|
598
|
-
params.push(...wanted);
|
|
599
|
-
}
|
|
600
729
|
};
|
|
601
|
-
var SAFE_PREFIX2 = /^[a-zA-Z0-9_]+$/;
|
|
602
|
-
function sanitizePrefix2(prefix) {
|
|
603
|
-
if (!SAFE_PREFIX2.test(prefix)) {
|
|
604
|
-
throw new Error(
|
|
605
|
-
`Invalid table prefix "${prefix}": only letters, digits, and underscores are allowed`
|
|
606
|
-
);
|
|
607
|
-
}
|
|
608
|
-
return prefix;
|
|
609
|
-
}
|
|
610
730
|
function contractRowToDomain(row) {
|
|
611
731
|
const contract = {
|
|
612
732
|
script: row.script,
|
|
@@ -629,15 +749,10 @@ function contractRowToDomain(row) {
|
|
|
629
749
|
}
|
|
630
750
|
|
|
631
751
|
// src/repositories/sqlite/intentRepository.ts
|
|
632
|
-
var SAFE_PREFIX3 = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
633
|
-
function sanitizePrefix3(p) {
|
|
634
|
-
if (!SAFE_PREFIX3.test(p)) throw new Error(`Invalid table prefix "${p}"`);
|
|
635
|
-
return p;
|
|
636
|
-
}
|
|
637
752
|
var SQLiteIntentRepository = class {
|
|
638
753
|
constructor(db, options) {
|
|
639
754
|
this.db = db;
|
|
640
|
-
this.prefix =
|
|
755
|
+
this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
|
|
641
756
|
this.t = `${this.prefix}intents`;
|
|
642
757
|
}
|
|
643
758
|
db;
|
|
@@ -676,19 +791,16 @@ var SQLiteIntentRepository = class {
|
|
|
676
791
|
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}intent_state ON ${this.t} (state)`
|
|
677
792
|
);
|
|
678
793
|
}
|
|
679
|
-
withTx(fn) {
|
|
680
|
-
return runInTransaction(this.db, fn);
|
|
681
|
-
}
|
|
682
794
|
async clear() {
|
|
683
795
|
await this.ensureInit();
|
|
684
|
-
await this.
|
|
796
|
+
await runInTransaction(this.db, async () => {
|
|
685
797
|
await this.db.run(`DELETE FROM ${this.t}`);
|
|
686
798
|
});
|
|
687
799
|
}
|
|
688
800
|
async saveIntent(intent) {
|
|
689
801
|
await this.ensureInit();
|
|
690
802
|
const now = Date.now();
|
|
691
|
-
await this.
|
|
803
|
+
await runInTransaction(this.db, async () => {
|
|
692
804
|
await this.db.run(
|
|
693
805
|
`INSERT INTO ${this.t}
|
|
694
806
|
(intent_tx_id, intent_id, state, valid_from, valid_until,
|
|
@@ -736,15 +848,30 @@ var SQLiteIntentRepository = class {
|
|
|
736
848
|
);
|
|
737
849
|
});
|
|
738
850
|
}
|
|
739
|
-
async
|
|
851
|
+
async getIntentsPage(filter, page) {
|
|
852
|
+
assertPageRequest(page);
|
|
740
853
|
await this.ensureInit();
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
854
|
+
if (filter?.states?.length === 0) return { items: [] };
|
|
855
|
+
const stateSql = filter?.states ? ` AND state IN (${filter.states.map(() => "?").join(", ")})` : "";
|
|
856
|
+
const stateParams = filter?.states ?? [];
|
|
857
|
+
const batchSize = Math.max(64, page.limit + 1);
|
|
858
|
+
const rows = [];
|
|
859
|
+
let after = page.after;
|
|
860
|
+
while (rows.length <= page.limit) {
|
|
861
|
+
const batch = await this.db.all(
|
|
862
|
+
`SELECT * FROM ${this.t} WHERE intent_tx_id > ?${stateSql} ORDER BY intent_tx_id LIMIT ?`,
|
|
863
|
+
[after ?? "", ...stateParams, batchSize]
|
|
864
|
+
);
|
|
865
|
+
if (batch.length === 0) break;
|
|
866
|
+
for (const row of batch) {
|
|
867
|
+
after = row.intent_tx_id;
|
|
868
|
+
const intent = rowToIntent(row);
|
|
869
|
+
if (!filter || intentMatchesFilter(intent, filter)) rows.push(intent);
|
|
870
|
+
if (rows.length > page.limit) break;
|
|
871
|
+
}
|
|
872
|
+
if (batch.length < batchSize) break;
|
|
873
|
+
}
|
|
874
|
+
return pageResult(rows, page.limit, (intent) => intent.intentTxId);
|
|
748
875
|
}
|
|
749
876
|
async getLockedVtxoOutpoints() {
|
|
750
877
|
await this.ensureInit();
|
|
@@ -782,15 +909,10 @@ function rowToIntent(r) {
|
|
|
782
909
|
}
|
|
783
910
|
|
|
784
911
|
// src/repositories/sqlite/virtualTxRepository.ts
|
|
785
|
-
var SAFE_PREFIX4 = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
786
|
-
function sanitizePrefix4(p) {
|
|
787
|
-
if (!SAFE_PREFIX4.test(p)) throw new Error(`Invalid table prefix "${p}"`);
|
|
788
|
-
return p;
|
|
789
|
-
}
|
|
790
912
|
var SQLiteVirtualTxRepository = class {
|
|
791
913
|
constructor(db, options) {
|
|
792
914
|
this.db = db;
|
|
793
|
-
this.prefix =
|
|
915
|
+
this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
|
|
794
916
|
this.tTx = `${this.prefix}virtual_txs`;
|
|
795
917
|
this.tBranch = `${this.prefix}vtxo_branches`;
|
|
796
918
|
}
|
|
@@ -822,12 +944,9 @@ var SQLiteVirtualTxRepository = class {
|
|
|
822
944
|
`CREATE INDEX IF NOT EXISTS idx_${this.prefix}branch_vtxid ON ${this.tBranch} (virtual_txid)`
|
|
823
945
|
);
|
|
824
946
|
}
|
|
825
|
-
tx(fn) {
|
|
826
|
-
return runInTransaction(this.db, fn);
|
|
827
|
-
}
|
|
828
947
|
async clear() {
|
|
829
948
|
await this.ensureInit();
|
|
830
|
-
await this.
|
|
949
|
+
await runInTransaction(this.db, async () => {
|
|
831
950
|
await this.db.run(`DELETE FROM ${this.tTx}`);
|
|
832
951
|
await this.db.run(`DELETE FROM ${this.tBranch}`);
|
|
833
952
|
});
|
|
@@ -835,7 +954,7 @@ var SQLiteVirtualTxRepository = class {
|
|
|
835
954
|
async upsertVirtualTxs(txs) {
|
|
836
955
|
if (txs.length === 0) return;
|
|
837
956
|
await this.ensureInit();
|
|
838
|
-
await this.
|
|
957
|
+
await runInTransaction(this.db, async () => {
|
|
839
958
|
const placeholders = txs.map(() => "?").join(", ");
|
|
840
959
|
const existing = await this.db.all(
|
|
841
960
|
`SELECT * FROM ${this.tTx} WHERE txid IN (${placeholders})`,
|
|
@@ -862,7 +981,7 @@ var SQLiteVirtualTxRepository = class {
|
|
|
862
981
|
}
|
|
863
982
|
async setBranch(vtxo, branch) {
|
|
864
983
|
await this.ensureInit();
|
|
865
|
-
await this.
|
|
984
|
+
await runInTransaction(this.db, async () => {
|
|
866
985
|
await this.db.run(`DELETE FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`, [
|
|
867
986
|
vtxo.txid,
|
|
868
987
|
vtxo.vout
|
|
@@ -897,7 +1016,7 @@ var SQLiteVirtualTxRepository = class {
|
|
|
897
1016
|
}
|
|
898
1017
|
async pruneForSpentVtxo(vtxo) {
|
|
899
1018
|
await this.ensureInit();
|
|
900
|
-
await this.
|
|
1019
|
+
await runInTransaction(this.db, async () => {
|
|
901
1020
|
const removed = await this.db.all(
|
|
902
1021
|
`SELECT DISTINCT virtual_txid FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`,
|
|
903
1022
|
[vtxo.txid, vtxo.vout]
|
|
@@ -930,13 +1049,6 @@ function rowToTx(r) {
|
|
|
930
1049
|
};
|
|
931
1050
|
}
|
|
932
1051
|
|
|
933
|
-
// src/repositories/sqlite/prefix.ts
|
|
934
|
-
var SAFE_PREFIX5 = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
935
|
-
function sanitizeTablePrefix(p) {
|
|
936
|
-
if (!SAFE_PREFIX5.test(p)) throw new Error(`Invalid table prefix "${p}"`);
|
|
937
|
-
return p;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
1052
|
export { SQLiteContractRepository, SQLiteIntentRepository, SQLiteVirtualTxRepository, SQLiteWalletRepository, runInTransaction, sanitizeTablePrefix };
|
|
941
1053
|
//# sourceMappingURL=index.js.map
|
|
942
1054
|
//# sourceMappingURL=index.js.map
|