@totemsdk/wots-lease 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +202 -21
  2. package/NOTICE +60 -0
  3. package/dist/axia.d.ts +1 -1
  4. package/dist/axia.js +41 -28
  5. package/dist/certificate.d.ts +37 -0
  6. package/dist/certificate.js +69 -0
  7. package/dist/cjs/axia.d.ts +33 -0
  8. package/dist/cjs/axia.js +145 -0
  9. package/dist/cjs/certificate.d.ts +37 -0
  10. package/dist/cjs/certificate.js +74 -0
  11. package/dist/cjs/device.d.ts +18 -0
  12. package/dist/cjs/device.js +34 -0
  13. package/dist/cjs/errors.d.ts +71 -0
  14. package/dist/cjs/errors.js +135 -0
  15. package/dist/cjs/hybrid.d.ts +37 -0
  16. package/dist/cjs/hybrid.js +145 -0
  17. package/dist/cjs/index.d.ts +17 -0
  18. package/dist/cjs/index.js +45 -0
  19. package/dist/cjs/journal.d.ts +30 -0
  20. package/dist/cjs/journal.js +369 -0
  21. package/dist/cjs/local.d.ts +83 -0
  22. package/dist/cjs/local.js +440 -0
  23. package/dist/cjs/onchain.d.ts +54 -0
  24. package/dist/cjs/onchain.js +314 -0
  25. package/dist/cjs/package.json +1 -0
  26. package/dist/cjs/quorum.d.ts +75 -0
  27. package/dist/cjs/quorum.js +307 -0
  28. package/dist/cjs/replicated-backup.d.ts +30 -0
  29. package/dist/cjs/replicated-backup.js +52 -0
  30. package/dist/cjs/seed.d.ts +41 -0
  31. package/dist/cjs/seed.js +84 -0
  32. package/dist/cjs/stubs.d.ts +50 -0
  33. package/dist/cjs/stubs.js +125 -0
  34. package/dist/cjs/types.d.ts +272 -0
  35. package/dist/cjs/types.js +5 -0
  36. package/dist/cjs/watermark.d.ts +51 -0
  37. package/dist/cjs/watermark.js +328 -0
  38. package/dist/device.js +2 -6
  39. package/dist/errors.d.ts +26 -0
  40. package/dist/errors.js +49 -25
  41. package/dist/hybrid.d.ts +4 -1
  42. package/dist/hybrid.js +72 -26
  43. package/dist/index.d.ts +6 -2
  44. package/dist/index.js +12 -38
  45. package/dist/journal.d.ts +14 -4
  46. package/dist/journal.js +327 -49
  47. package/dist/local.d.ts +31 -1
  48. package/dist/local.js +267 -68
  49. package/dist/onchain.d.ts +3 -1
  50. package/dist/onchain.js +63 -28
  51. package/dist/quorum.d.ts +15 -0
  52. package/dist/quorum.js +54 -15
  53. package/dist/replicated-backup.d.ts +30 -0
  54. package/dist/replicated-backup.js +48 -0
  55. package/dist/seed.d.ts +41 -0
  56. package/dist/seed.js +80 -0
  57. package/dist/stubs.d.ts +2 -0
  58. package/dist/stubs.js +20 -10
  59. package/dist/types.d.ts +74 -1
  60. package/dist/types.js +1 -2
  61. package/dist/watermark.d.ts +22 -1
  62. package/dist/watermark.js +133 -16
  63. package/package.json +25 -15
  64. package/rust/pkg/package.json +3 -3
  65. package/rust/pkg/wots_lease_wasm_bg.wasm +0 -0
  66. package/rust/pkg-node/package.json +3 -3
  67. package/rust/pkg-node/wots_lease_wasm_bg.wasm +0 -0
package/dist/local.js CHANGED
@@ -1,42 +1,147 @@
1
- "use strict";
2
1
  /**
3
2
  * LocalLeaseProvider — Layer 1: local durable ledger.
4
3
  *
5
4
  * Single-device, no network coordination.
6
5
  * All WOTS safety guaranteed by the local WotsWatermarkStore + LeaseJournal.
7
6
  */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.LocalLeaseProvider = void 0;
10
- const core_1 = require("@totemsdk/core");
11
- const core_2 = require("@totemsdk/core");
12
- const watermark_js_1 = require("./watermark.js");
13
- const journal_js_1 = require("./journal.js");
14
- const errors_js_1 = require("./errors.js");
7
+ import { NoopLogger } from '@totemsdk/core';
8
+ import { LeaseStore } from '@totemsdk/core';
9
+ import { WotsWatermarkStore, flatIndex } from './watermark.js';
10
+ import { LeaseJournal } from './journal.js';
11
+ import { LeaseNotFoundError, InvalidLeaseTransitionError, DeviceRangeViolationError, IndicesUnavailableError, } from './errors.js';
15
12
  function randomId() {
16
13
  if (typeof crypto !== 'undefined' && crypto.randomUUID) {
17
14
  return crypto.randomUUID();
18
15
  }
19
16
  return Math.random().toString(36).slice(2) + Date.now().toString(36);
20
17
  }
21
- class LocalLeaseProvider {
22
- constructor(storage, logger = new core_1.NoopLogger(), deviceId = 'local') {
18
+ export class LocalLeaseProvider {
19
+ constructor(storage, logger = new NoopLogger(), deviceId = 'local') {
23
20
  this.logger = logger;
24
21
  this._initialized = false;
25
- this.watermark = new watermark_js_1.WotsWatermarkStore(storage, logger);
26
- this.leaseStore = new core_2.LeaseStore(storage, logger);
27
- this.journal = new journal_js_1.LeaseJournal(storage, logger);
22
+ this.initializePromise = null;
23
+ this.mutationTail = Promise.resolve();
24
+ this.watermark = new WotsWatermarkStore(storage, logger);
25
+ this.leaseStore = new LeaseStore(storage, logger);
26
+ this.journal = new LeaseJournal(storage, logger);
28
27
  this.deviceId = deviceId;
28
+ this.cas = LocalLeaseProvider.detectCas(storage);
29
+ }
30
+ static detectCas(storage) {
31
+ const candidate = storage;
32
+ return typeof candidate.conditionalUpdate === 'function' ? candidate : undefined;
29
33
  }
30
34
  async initialize() {
31
35
  if (this._initialized)
32
36
  return;
37
+ if (!this.initializePromise) {
38
+ this.initializePromise = this.initializeOnce().catch((error) => {
39
+ this.initializePromise = null;
40
+ throw error;
41
+ });
42
+ }
43
+ await this.initializePromise;
44
+ }
45
+ async initializeOnce() {
46
+ await this.journal.initialize();
33
47
  await this.watermark.initialize();
34
48
  await this.leaseStore.initialize();
35
- await this.journal.initialize();
49
+ await this.reconcileDurableSafetyState();
36
50
  await this.recoverExpiredReservations();
37
51
  await this.burnUnresolvedReservations();
38
52
  this._initialized = true;
39
53
  }
54
+ /**
55
+ * Rebuild the no-reuse watermark from immutable journal history and leases.
56
+ * The journal is audit authority; the watermark remains allocation authority.
57
+ */
58
+ async reconcileDurableSafetyState() {
59
+ const entries = this.journal.getAll();
60
+ const latestBySlot = new Map();
61
+ const latestByReservation = new Map();
62
+ for (const entry of entries) {
63
+ latestBySlot.set(`${entry.treeId}:${entry.wotsIndex}`, entry);
64
+ if (entry.reservationId)
65
+ latestByReservation.set(entry.reservationId, entry);
66
+ }
67
+ for (const entry of latestBySlot.values()) {
68
+ await this.watermark.markUnavailable(entry.treeId, entry.indices, entry.status);
69
+ }
70
+ const leases = this.leaseStore.getAll();
71
+ const leaseIds = new Set(leases.map((lease) => lease.leaseId));
72
+ for (const entry of latestByReservation.values()) {
73
+ if (entry.status !== 'reserved' || leaseIds.has(entry.reservationId))
74
+ continue;
75
+ await this.journal.append({
76
+ ...entry,
77
+ status: 'burned',
78
+ timestamp: Date.now(),
79
+ });
80
+ await this.watermark.markUnavailable(entry.treeId, entry.indices, 'burned');
81
+ }
82
+ for (const lease of leases) {
83
+ const treeId = lease.treeId ?? 'default';
84
+ const latest = this.journal.getByReservation(lease.leaseId);
85
+ if (!latest) {
86
+ const status = lease.status === 'finalized'
87
+ ? 'committed'
88
+ : lease.status === 'cancelled'
89
+ ? 'burned'
90
+ : lease.status === 'expired'
91
+ ? 'reserved-expired'
92
+ : 'reserved';
93
+ await this.journal.append({
94
+ treeId,
95
+ branchId: 'default',
96
+ wotsIndex: flatIndex(lease.indices),
97
+ indices: lease.indices,
98
+ status,
99
+ reservationId: lease.leaseId,
100
+ ...(lease.txId !== undefined ? { txId: lease.txId } : {}),
101
+ timestamp: lease.createdAt,
102
+ deviceId: this.deviceId,
103
+ });
104
+ await this.watermark.markUnavailable(treeId, lease.indices, status);
105
+ continue;
106
+ }
107
+ if (latest.status === 'committed' && lease.status !== 'finalized') {
108
+ await this.leaseStore.updateStatus(lease.leaseId, 'finalized');
109
+ }
110
+ else if (latest.status === 'burned' && lease.status !== 'cancelled') {
111
+ await this.leaseStore.updateStatus(lease.leaseId, 'cancelled');
112
+ }
113
+ else if (latest.status === 'reserved-expired' && lease.status !== 'expired') {
114
+ await this.leaseStore.updateStatus(lease.leaseId, 'expired');
115
+ }
116
+ else if (latest.status === 'reserved' && lease.status === 'finalized') {
117
+ await this.journal.append({
118
+ treeId,
119
+ branchId: 'default',
120
+ wotsIndex: flatIndex(lease.indices),
121
+ indices: lease.indices,
122
+ status: 'committed',
123
+ reservationId: lease.leaseId,
124
+ ...(lease.txId !== undefined ? { txId: lease.txId } : {}),
125
+ timestamp: Date.now(),
126
+ deviceId: this.deviceId,
127
+ });
128
+ await this.watermark.markUnavailable(treeId, lease.indices, 'committed');
129
+ }
130
+ else if (latest.status === 'reserved' && lease.status === 'cancelled') {
131
+ await this.journal.append({
132
+ treeId,
133
+ branchId: 'default',
134
+ wotsIndex: flatIndex(lease.indices),
135
+ indices: lease.indices,
136
+ status: 'burned',
137
+ reservationId: lease.leaseId,
138
+ timestamp: Date.now(),
139
+ deviceId: this.deviceId,
140
+ });
141
+ await this.watermark.markUnavailable(treeId, lease.indices, 'burned');
142
+ }
143
+ }
144
+ }
40
145
  /** Burn all active (non-expired) leases that have no matching treeId.
41
146
  * On restart, leases with missing treeId (from before the treeId field was added)
42
147
  * must be burned to prevent index reuse. */
@@ -45,46 +150,56 @@ class LocalLeaseProvider {
45
150
  for (const lease of this.leaseStore.getAll()) {
46
151
  if (lease.status === 'active' && lease.expiresAt >= now && !lease.treeId) {
47
152
  this.logger.warn(`[LocalLeaseProvider] Burning unresolved lease ${lease.leaseId} (no treeId)`);
153
+ if (this.journal.getByReservation(lease.leaseId)?.status !== 'burned') {
154
+ await this.journal.append({
155
+ treeId: 'default',
156
+ branchId: 'default',
157
+ wotsIndex: flatIndex(lease.indices),
158
+ indices: lease.indices,
159
+ status: 'burned',
160
+ reservationId: lease.leaseId,
161
+ timestamp: now,
162
+ deviceId: this.deviceId,
163
+ });
164
+ }
48
165
  await this.watermark.markUnavailable('default', lease.indices, 'burned');
49
166
  await this.leaseStore.updateStatus(lease.leaseId, 'cancelled');
50
- await this.journal.append({
51
- treeId: 'default',
52
- branchId: 'default',
53
- wotsIndex: (0, watermark_js_1.flatIndex)(lease.indices),
54
- indices: lease.indices,
55
- status: 'burned',
56
- reservationId: lease.leaseId,
57
- timestamp: now,
58
- deviceId: this.deviceId,
59
- });
60
167
  }
61
168
  }
62
169
  }
63
170
  async recoverExpiredReservations() {
64
171
  const now = Date.now();
65
172
  for (const lease of this.leaseStore.getAll()) {
66
- if (lease.status === 'active' && lease.expiresAt < now) {
173
+ if (lease.status === 'expired' || (lease.status === 'active' && lease.expiresAt < now)) {
67
174
  const treeId = lease.treeId ?? 'default';
175
+ if (this.journal.getByReservation(lease.leaseId)?.status !== 'reserved-expired') {
176
+ await this.journal.append({
177
+ treeId,
178
+ branchId: 'default',
179
+ wotsIndex: flatIndex(lease.indices),
180
+ indices: lease.indices,
181
+ status: 'reserved-expired',
182
+ reservationId: lease.leaseId,
183
+ timestamp: now,
184
+ deviceId: this.deviceId,
185
+ });
186
+ }
68
187
  await this.watermark.markUnavailable(treeId, lease.indices, 'reserved-expired');
69
- await this.leaseStore.updateStatus(lease.leaseId, 'expired');
70
- await this.journal.append({
71
- treeId,
72
- branchId: 'default',
73
- wotsIndex: (0, watermark_js_1.flatIndex)(lease.indices),
74
- indices: lease.indices,
75
- status: 'reserved-expired',
76
- reservationId: lease.leaseId,
77
- timestamp: now,
78
- deviceId: this.deviceId,
79
- });
188
+ if (lease.status !== 'expired')
189
+ await this.leaseStore.updateStatus(lease.leaseId, 'expired');
80
190
  }
81
191
  }
82
192
  }
83
193
  async reserveKeyUse(params) {
84
- if (!this._initialized)
85
- await this.initialize();
86
- const indices = this.watermark.getNextIndices(params.treeId);
87
- return this.reserveSpecificKeyUse(params, indices);
194
+ return this.withMutationLock(async () => {
195
+ if (!this._initialized)
196
+ await this.initialize();
197
+ // Pick up any allocation made by another provider over the same storage
198
+ // before choosing a slot (AUD-004).
199
+ await this.watermark.refresh();
200
+ const indices = this.watermark.getNextIndices(params.treeId);
201
+ return this.reserveSpecificKeyUseUnlocked(params, indices);
202
+ });
88
203
  }
89
204
  /**
90
205
  * Reserve a specific set of indices (used by quorum coordination so every
@@ -92,23 +207,63 @@ class LocalLeaseProvider {
92
207
  * slot is already taken.
93
208
  */
94
209
  async reserveSpecificKeyUse(params, indices) {
210
+ return this.withMutationLock(async () => {
211
+ if (!this._initialized)
212
+ await this.initialize();
213
+ await this.watermark.refresh();
214
+ return this.reserveSpecificKeyUseUnlocked(params, indices);
215
+ });
216
+ }
217
+ async reserveSpecificKeyUseUnlocked(params, indices) {
95
218
  if (!this._initialized)
96
219
  await this.initialize();
97
220
  const treeId = params.treeId;
98
221
  const ttlMs = params.ttlMs ?? 120000;
99
222
  if (this.watermark.isUnavailable(treeId, indices)) {
100
- throw new errors_js_1.IndicesUnavailableError(treeId, indices);
223
+ throw new IndicesUnavailableError(treeId, indices);
101
224
  }
102
225
  // Validate device range BEFORE marking unavailable — prevents permanent index loss
103
226
  if (params.deviceId) {
104
227
  const range = this.getDeviceRange(params.deviceId);
105
228
  if (range && (indices.addressIndex < range.start || indices.addressIndex > range.end)) {
106
- throw new errors_js_1.DeviceRangeViolationError(indices.addressIndex, range.start, range.end);
229
+ throw new DeviceRangeViolationError(indices.addressIndex, range.start, range.end);
107
230
  }
108
231
  }
109
- await this.watermark.markUnavailable(treeId, indices, 'reserved');
110
232
  const reservationId = randomId();
111
233
  const expiresAt = Date.now() + ttlMs;
234
+ // Cross-instance CAS claim (AUD-004): on a durable medium shared by two
235
+ // provider instances over distinct adapter objects, refresh() above can
236
+ // race and both pick the same slot. Claim it atomically first; a lost race
237
+ // means another instance owns it, so the slot is not re-allocated.
238
+ if (this.cas) {
239
+ const claimKey = `totem_wots_claim:${treeId}:${flatIndex(indices)}`;
240
+ const claim = await this.cas.conditionalUpdate(claimKey, (current) => current
241
+ ? { abort: 'slot already claimed' }
242
+ : {
243
+ next: {
244
+ reservationId,
245
+ ...(params.deviceId !== undefined ? { deviceId: params.deviceId } : {}),
246
+ claimedAt: Date.now(),
247
+ },
248
+ });
249
+ if (!claim.applied) {
250
+ throw new IndicesUnavailableError(treeId, indices);
251
+ }
252
+ }
253
+ // Write-ahead safety record: once this succeeds, recovery will never
254
+ // re-expose the index even if a later snapshot write fails.
255
+ await this.journal.append({
256
+ treeId,
257
+ branchId: params.branchId ?? 'default',
258
+ wotsIndex: flatIndex(indices),
259
+ indices,
260
+ status: 'reserved',
261
+ reservationId,
262
+ payloadHash: params.payloadHash,
263
+ timestamp: Date.now(),
264
+ deviceId: params.deviceId ?? this.deviceId,
265
+ });
266
+ await this.watermark.markUnavailable(treeId, indices, 'reserved');
112
267
  const lease = {
113
268
  leaseId: reservationId,
114
269
  leaseToken: reservationId,
@@ -120,35 +275,43 @@ class LocalLeaseProvider {
120
275
  leaseTTL: ttlMs,
121
276
  };
122
277
  await this.leaseStore.save(lease);
123
- await this.journal.append({
124
- treeId,
125
- branchId: params.branchId ?? 'default',
126
- wotsIndex: (0, watermark_js_1.flatIndex)(indices),
127
- indices,
128
- status: 'reserved',
129
- reservationId,
130
- payloadHash: params.payloadHash,
131
- timestamp: Date.now(),
132
- deviceId: params.deviceId ?? this.deviceId,
133
- });
134
278
  return { reservationId, indices, expiresAt };
135
279
  }
280
+ withMutationLock(operation) {
281
+ const run = this.mutationTail.then(operation, operation);
282
+ this.mutationTail = run.then(() => undefined, () => undefined);
283
+ return run;
284
+ }
136
285
  async commitKeyUse(reservationId, txId) {
286
+ return this.withMutationLock(() => this.commitKeyUseUnlocked(reservationId, txId));
287
+ }
288
+ async commitKeyUseUnlocked(reservationId, txId) {
137
289
  if (!this._initialized)
138
290
  await this.initialize();
291
+ await this.watermark.refresh();
139
292
  const lease = this.leaseStore.get(reservationId);
140
293
  if (!lease)
141
- throw new errors_js_1.LeaseNotFoundError(reservationId);
142
- if (lease.status === 'finalized')
143
- return;
294
+ throw new LeaseNotFoundError(reservationId);
144
295
  const treeId = lease.treeId ?? 'default';
145
296
  const indices = lease.indices;
146
- await this.watermark.markUnavailable(treeId, indices, 'committed');
147
- await this.leaseStore.updateStatus(reservationId, 'finalized');
297
+ const latest = this.journal.getByReservation(reservationId);
298
+ if (latest?.status === 'committed') {
299
+ if (latest.txId !== txId) {
300
+ throw new InvalidLeaseTransitionError(reservationId, 'committed', 'committed');
301
+ }
302
+ await this.watermark.markUnavailable(treeId, indices, 'committed');
303
+ if (lease.status !== 'finalized')
304
+ await this.leaseStore.updateStatus(reservationId, 'finalized');
305
+ return;
306
+ }
307
+ if (latest?.status === 'burned' || latest?.status === 'reserved-expired'
308
+ || lease.status === 'cancelled' || lease.status === 'expired') {
309
+ throw new InvalidLeaseTransitionError(reservationId, latest?.status ?? lease.status, 'committed');
310
+ }
148
311
  await this.journal.append({
149
312
  treeId,
150
313
  branchId: 'default',
151
- wotsIndex: (0, watermark_js_1.flatIndex)(indices),
314
+ wotsIndex: flatIndex(indices),
152
315
  indices,
153
316
  status: 'committed',
154
317
  reservationId,
@@ -156,34 +319,71 @@ class LocalLeaseProvider {
156
319
  timestamp: Date.now(),
157
320
  deviceId: this.deviceId,
158
321
  });
322
+ await this.watermark.markUnavailable(treeId, indices, 'committed');
323
+ await this.leaseStore.updateStatus(reservationId, 'finalized');
159
324
  }
160
325
  async burnReservation(reservationId, reason) {
326
+ return this.withMutationLock(() => this.burnReservationUnlocked(reservationId, reason));
327
+ }
328
+ async burnReservationUnlocked(reservationId, reason) {
161
329
  if (!this._initialized)
162
330
  await this.initialize();
331
+ await this.watermark.refresh();
163
332
  const lease = this.leaseStore.get(reservationId);
164
333
  if (!lease)
165
- throw new errors_js_1.LeaseNotFoundError(reservationId);
334
+ throw new LeaseNotFoundError(reservationId);
166
335
  const treeId = lease.treeId ?? 'default';
167
336
  const indices = lease.indices;
168
- await this.watermark.markUnavailable(treeId, indices, 'burned');
169
- await this.leaseStore.updateStatus(reservationId, 'cancelled');
170
- this.logger.warn(`[LocalLeaseProvider] Burning reservation ${reservationId}: ${reason}`);
337
+ const latest = this.journal.getByReservation(reservationId);
338
+ if (latest?.status === 'burned') {
339
+ await this.watermark.markUnavailable(treeId, indices, 'burned');
340
+ if (lease.status !== 'cancelled')
341
+ await this.leaseStore.updateStatus(reservationId, 'cancelled');
342
+ return;
343
+ }
344
+ if (latest?.status === 'committed' || latest?.status === 'reserved-expired'
345
+ || lease.status === 'finalized' || lease.status === 'expired') {
346
+ throw new InvalidLeaseTransitionError(reservationId, latest?.status ?? lease.status, 'burned');
347
+ }
171
348
  await this.journal.append({
172
349
  treeId,
173
350
  branchId: 'default',
174
- wotsIndex: (0, watermark_js_1.flatIndex)(indices),
351
+ wotsIndex: flatIndex(indices),
175
352
  indices,
176
353
  status: 'burned',
177
354
  reservationId,
178
355
  timestamp: Date.now(),
179
356
  deviceId: this.deviceId,
180
357
  });
358
+ await this.watermark.markUnavailable(treeId, indices, 'burned');
359
+ await this.leaseStore.updateStatus(reservationId, 'cancelled');
360
+ this.logger.warn(`[LocalLeaseProvider] Burning reservation ${reservationId}: ${reason}`);
181
361
  }
182
362
  async getLocalWatermark(treeId) {
183
363
  if (!this._initialized)
184
364
  await this.initialize();
185
365
  return this.watermark.getLocalWatermark(treeId);
186
366
  }
367
+ /**
368
+ * Export a portable watermark seed for restore (RFC-013 §9).
369
+ */
370
+ async exportWatermark(treeId) {
371
+ if (!this._initialized)
372
+ await this.initialize();
373
+ return this.watermark.exportSeed(treeId);
374
+ }
375
+ /**
376
+ * Seed the local watermark from an exported/operator/on-chain snapshot.
377
+ * Forward-only by default; refuses to start below the true high-water mark.
378
+ */
379
+ async seedWatermark(seed, options) {
380
+ return this.withMutationLock(async () => {
381
+ if (!this._initialized)
382
+ await this.initialize();
383
+ await this.watermark.refresh();
384
+ await this.watermark.seed(seed, options);
385
+ });
386
+ }
187
387
  /** List all tree IDs known to the local watermark store. */
188
388
  listTrees() {
189
389
  return Object.keys(this.watermark.getRawState().trees);
@@ -202,8 +402,8 @@ class LocalLeaseProvider {
202
402
  if (!this._initialized)
203
403
  await this.initialize();
204
404
  const local = this.watermark.getLocalWatermark(treeId);
205
- const localFlat = (0, watermark_js_1.flatIndex)({ addressIndex: local.addressCursor, l1: local.l1Cursor, l2: local.l2Cursor });
206
- const remoteFlat = (0, watermark_js_1.flatIndex)({ addressIndex: remote.addressCursor, l1: remote.l1Cursor, l2: remote.l2Cursor });
405
+ const localFlat = flatIndex({ addressIndex: local.addressCursor, l1: local.l1Cursor, l2: local.l2Cursor });
406
+ const remoteFlat = flatIndex({ addressIndex: remote.addressCursor, l1: remote.l1Cursor, l2: remote.l2Cursor });
207
407
  if (remoteFlat <= localFlat)
208
408
  return false;
209
409
  await this.watermark.save(treeId, {
@@ -234,4 +434,3 @@ class LocalLeaseProvider {
234
434
  return { start: slot * 8, end: slot * 8 + 7 };
235
435
  }
236
436
  }
237
- exports.LocalLeaseProvider = LocalLeaseProvider;
package/dist/onchain.d.ts CHANGED
@@ -23,7 +23,8 @@
23
23
  import type { WotsLeaseProvider, ReserveParams, LeaseReservation, LeaseCertificate, LocalWatermark, SyncResult, OnchainWatermarkProviderConfig } from './types.js';
24
24
  export declare class OnchainWatermarkProvider implements WotsLeaseProvider {
25
25
  private readonly chain;
26
- private readonly watermarkCoinId;
26
+ private readonly initialWatermarkCoinId;
27
+ private currentCoinId;
27
28
  private readonly watermarkAddress;
28
29
  private readonly tokenId;
29
30
  private readonly amount;
@@ -31,6 +32,7 @@ export declare class OnchainWatermarkProvider implements WotsLeaseProvider {
31
32
  private readonly signer;
32
33
  private readonly statePort;
33
34
  private readonly minBlocksBetweenPublishes;
35
+ private readonly storage?;
34
36
  private _initialized;
35
37
  private _lastPublishBlock;
36
38
  constructor(config: OnchainWatermarkProviderConfig);