@hyperbridge/simplex 0.18.1 → 0.18.3
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/dist/bin/simplex.js +4311 -1541
- package/dist/bin/simplex.js.map +1 -1
- package/dist/index.cjs +7273 -4705
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1199 -812
- package/dist/index.d.ts +1199 -812
- package/dist/index.js +7311 -4737
- package/dist/index.js.map +1 -1
- package/dist/sqlite.cjs +77 -90
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.cts +4 -9
- package/dist/sqlite.d.ts +4 -9
- package/dist/sqlite.js +77 -90
- package/dist/sqlite.js.map +1 -1
- package/dist/{types-6MEltdkX.d.cts → types-CW6STIE7.d.cts} +725 -223
- package/dist/{types-6MEltdkX.d.ts → types-CW6STIE7.d.ts} +725 -223
- package/dist/ui/assets/{index-BEaKgtAo.js → index-BqOM_gBm.js} +44 -44
- package/dist/ui/assets/{index-aSBiKM_B.css → index-DypSLK4f.css} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +4 -4
package/dist/sqlite.js
CHANGED
|
@@ -442,18 +442,31 @@ var BID_COLUMNS = `
|
|
|
442
442
|
retracted_at as retractedAt,
|
|
443
443
|
retract_extrinsic_hash as retractExtrinsicHash,
|
|
444
444
|
dead,
|
|
445
|
-
|
|
445
|
+
on_orderbook as onOrderbook,
|
|
446
|
+
priced_by as pricedBy,
|
|
446
447
|
reservations
|
|
447
448
|
`;
|
|
448
|
-
function
|
|
449
|
-
if (!raw) return
|
|
449
|
+
function parseJson(raw) {
|
|
450
|
+
if (!raw) return null;
|
|
450
451
|
try {
|
|
451
|
-
|
|
452
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
452
|
+
return JSON.parse(raw);
|
|
453
453
|
} catch {
|
|
454
|
-
return
|
|
454
|
+
return null;
|
|
455
455
|
}
|
|
456
456
|
}
|
|
457
|
+
function pricedBy(row) {
|
|
458
|
+
const current = parseJson(row.pricedBy);
|
|
459
|
+
if (current && typeof current === "object") return current;
|
|
460
|
+
const legacy = parseJson(row.reservations);
|
|
461
|
+
const first = Array.isArray(legacy) ? legacy[0] : null;
|
|
462
|
+
if (!first || typeof first !== "object" || typeof first.limitOrderId !== "string") return null;
|
|
463
|
+
return {
|
|
464
|
+
limitOrderId: first.limitOrderId,
|
|
465
|
+
payout: String(first.payout ?? first.amount),
|
|
466
|
+
...first.take !== void 0 ? { take: String(first.take) } : {},
|
|
467
|
+
...first.takeDecimals !== void 0 ? { takeDecimals: Number(first.takeDecimals) } : {}
|
|
468
|
+
};
|
|
469
|
+
}
|
|
457
470
|
var SqliteBidStore = class {
|
|
458
471
|
constructor(db, loggers = defaultLoggerContext()) {
|
|
459
472
|
this.db = db;
|
|
@@ -476,7 +489,11 @@ var SqliteBidStore = class {
|
|
|
476
489
|
retracted_at TEXT,
|
|
477
490
|
retract_extrinsic_hash TEXT,
|
|
478
491
|
dead INTEGER NOT NULL DEFAULT 0,
|
|
479
|
-
|
|
492
|
+
on_orderbook INTEGER NOT NULL DEFAULT 0,
|
|
493
|
+
-- Only read, as the provenance of a bid written before priced_by. Kept, and
|
|
494
|
+
-- never written, so a rollback to a build that still reads it finds the column.
|
|
495
|
+
reservations TEXT,
|
|
496
|
+
priced_by TEXT
|
|
480
497
|
);
|
|
481
498
|
|
|
482
499
|
CREATE INDEX IF NOT EXISTS idx_bids_commitment ON bids(commitment);
|
|
@@ -485,12 +502,12 @@ var SqliteBidStore = class {
|
|
|
485
502
|
CREATE INDEX IF NOT EXISTS idx_bids_created_at ON bids(created_at);
|
|
486
503
|
`);
|
|
487
504
|
const columns = columnNames(this.db, "bids");
|
|
488
|
-
for (const column of ["dead", "pending"]) {
|
|
505
|
+
for (const column of ["dead", "pending", "on_orderbook"]) {
|
|
489
506
|
if (columns.has(column)) continue;
|
|
490
507
|
this.db.exec(`ALTER TABLE bids ADD COLUMN ${column} INTEGER NOT NULL DEFAULT 0`);
|
|
491
508
|
this.logger.info({ column }, "Migrated bid storage schema");
|
|
492
509
|
}
|
|
493
|
-
for (const column of ["bid", "reservations"]) {
|
|
510
|
+
for (const column of ["bid", "reservations", "priced_by"]) {
|
|
494
511
|
if (columns.has(column)) continue;
|
|
495
512
|
this.db.exec(`ALTER TABLE bids ADD COLUMN ${column} TEXT`);
|
|
496
513
|
this.logger.info({ column }, "Migrated bid storage schema");
|
|
@@ -499,19 +516,21 @@ var SqliteBidStore = class {
|
|
|
499
516
|
}
|
|
500
517
|
// biome-ignore lint/suspicious/noExplicitAny: raw sqlite row
|
|
501
518
|
toStoredBid(row) {
|
|
519
|
+
const { reservations: _legacy, ...rest } = row;
|
|
502
520
|
return {
|
|
503
|
-
...
|
|
521
|
+
...rest,
|
|
504
522
|
success: Boolean(row.success),
|
|
505
523
|
pending: Boolean(row.pending),
|
|
506
524
|
retracted: Boolean(row.retracted),
|
|
507
525
|
dead: Boolean(row.dead),
|
|
508
|
-
|
|
526
|
+
onOrderbook: Boolean(row.onOrderbook),
|
|
527
|
+
pricedBy: pricedBy(row)
|
|
509
528
|
};
|
|
510
529
|
}
|
|
511
530
|
async store(bid) {
|
|
512
531
|
const result = this.db.prepare(`
|
|
513
|
-
INSERT INTO bids (commitment, bid, extrinsic_hash, block_hash, success, pending, error,
|
|
514
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
532
|
+
INSERT INTO bids (commitment, bid, extrinsic_hash, block_hash, success, pending, error, on_orderbook, priced_by)
|
|
533
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
515
534
|
`).run(
|
|
516
535
|
bid.commitment,
|
|
517
536
|
bid.bid ?? null,
|
|
@@ -520,7 +539,8 @@ var SqliteBidStore = class {
|
|
|
520
539
|
bid.success ? 1 : 0,
|
|
521
540
|
bid.pending ? 1 : 0,
|
|
522
541
|
bid.error || null,
|
|
523
|
-
bid.
|
|
542
|
+
bid.onOrderbook ? 1 : 0,
|
|
543
|
+
bid.pricedBy ? JSON.stringify(bid.pricedBy) : null
|
|
524
544
|
);
|
|
525
545
|
this.logger.debug({ id: result.lastInsertRowid, commitment: bid.commitment, success: bid.success }, "Bid stored");
|
|
526
546
|
}
|
|
@@ -546,37 +566,33 @@ var SqliteBidStore = class {
|
|
|
546
566
|
const rows = this.db.prepare(`SELECT ${BID_COLUMNS} FROM bids WHERE created_at BETWEEN ? AND ? ORDER BY created_at DESC`).all(sqliteDatetime(from), sqliteDatetime(to));
|
|
547
567
|
return rows.map((row) => this.toStoredBid(row));
|
|
548
568
|
}
|
|
549
|
-
async markRetracted(commitment, retractExtrinsicHash) {
|
|
569
|
+
async markRetracted(commitment, retractExtrinsicHash, rows) {
|
|
570
|
+
if (rows?.length === 0) return false;
|
|
550
571
|
const result = this.db.prepare(`
|
|
551
572
|
UPDATE bids
|
|
552
573
|
SET retracted = 1, retracted_at = datetime('now'), retract_extrinsic_hash = ?
|
|
553
|
-
WHERE commitment = ? AND retracted = 0
|
|
554
|
-
`).run(retractExtrinsicHash, commitment);
|
|
574
|
+
WHERE commitment = ? AND retracted = 0${rows ? ` AND id IN (${rows.map(() => "?").join(",")})` : ""}
|
|
575
|
+
`).run(retractExtrinsicHash, commitment, ...rows ?? []);
|
|
555
576
|
if (result.changes > 0) {
|
|
556
577
|
this.logger.info({ commitment, retractExtrinsicHash }, "Bid marked as retracted");
|
|
557
578
|
return true;
|
|
558
579
|
}
|
|
559
580
|
return false;
|
|
560
581
|
}
|
|
561
|
-
async claimReservation(commitment, bid) {
|
|
562
|
-
const rows = bid === void 0 ? this.db.prepare("SELECT id, reservations FROM bids WHERE commitment = ? AND reservations IS NOT NULL ORDER BY id").all(commitment) : this.db.prepare(
|
|
563
|
-
"SELECT id, reservations FROM bids WHERE commitment = ? AND bid = ? AND reservations IS NOT NULL ORDER BY id"
|
|
564
|
-
).all(commitment, bid);
|
|
565
|
-
const claimed = [];
|
|
566
|
-
for (const row of rows) {
|
|
567
|
-
const result = this.db.prepare("UPDATE bids SET reservations = NULL WHERE id = ? AND reservations = ?").run(row.id, row.reservations);
|
|
568
|
-
if (result.changes === 1) claimed.push(...parseHolds(row.reservations));
|
|
569
|
-
}
|
|
570
|
-
return claimed;
|
|
571
|
-
}
|
|
572
582
|
async byLimitOrder(limitOrderId, limit = 100) {
|
|
573
|
-
const
|
|
574
|
-
|
|
583
|
+
const pattern = `%${limitOrderId}%`;
|
|
584
|
+
const rows = this.db.prepare(
|
|
585
|
+
`SELECT ${BID_COLUMNS} FROM bids WHERE priced_by LIKE ? OR (priced_by IS NULL AND reservations LIKE ?) ORDER BY id DESC LIMIT ?`
|
|
586
|
+
).all(pattern, pattern, Math.min(Math.max(limit, 1), 500));
|
|
587
|
+
return rows.map((row) => this.toStoredBid(row)).filter((bid) => bid.pricedBy?.limitOrderId === limitOrderId);
|
|
575
588
|
}
|
|
576
|
-
async markDead(commitment) {
|
|
577
|
-
|
|
589
|
+
async markDead(commitment, rows) {
|
|
590
|
+
if (rows?.length === 0) return false;
|
|
591
|
+
const result = this.db.prepare(
|
|
592
|
+
`UPDATE bids SET dead = 1 WHERE commitment = ? AND retracted = 0 AND dead = 0${rows ? ` AND id IN (${rows.map(() => "?").join(",")})` : ""}`
|
|
593
|
+
).run(commitment, ...rows ?? []);
|
|
578
594
|
if (result.changes > 0) {
|
|
579
|
-
this.logger.debug({ commitment }, "Bid marked
|
|
595
|
+
this.logger.debug({ commitment }, "Bid marked dead, due for retraction on the next sweep");
|
|
580
596
|
return true;
|
|
581
597
|
}
|
|
582
598
|
return false;
|
|
@@ -585,8 +601,8 @@ var SqliteBidStore = class {
|
|
|
585
601
|
const stats = this.db.prepare(`
|
|
586
602
|
SELECT
|
|
587
603
|
COUNT(*) as total,
|
|
588
|
-
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successful,
|
|
589
|
-
SUM(CASE WHEN success = 0 THEN 1 ELSE 0 END) as failed,
|
|
604
|
+
SUM(CASE WHEN success = 1 OR on_orderbook = 1 THEN 1 ELSE 0 END) as successful,
|
|
605
|
+
SUM(CASE WHEN success = 0 AND on_orderbook = 0 THEN 1 ELSE 0 END) as failed,
|
|
590
606
|
SUM(CASE WHEN retracted = 1 THEN 1 ELSE 0 END) as retracted,
|
|
591
607
|
SUM(CASE WHEN (success = 1 OR pending = 1) AND retracted = 0 THEN 1 ELSE 0 END) as pendingRetraction
|
|
592
608
|
FROM bids
|
|
@@ -600,7 +616,7 @@ var SqliteBidStore = class {
|
|
|
600
616
|
};
|
|
601
617
|
}
|
|
602
618
|
async failed(limit = 100) {
|
|
603
|
-
const rows = this.db.prepare(`SELECT ${BID_COLUMNS} FROM bids WHERE success = 0 ORDER BY created_at DESC LIMIT ?`).all(limit);
|
|
619
|
+
const rows = this.db.prepare(`SELECT ${BID_COLUMNS} FROM bids WHERE success = 0 AND on_orderbook = 0 ORDER BY created_at DESC LIMIT ?`).all(limit);
|
|
604
620
|
return rows.map((row) => this.toStoredBid(row));
|
|
605
621
|
}
|
|
606
622
|
async byCommitments(commitments) {
|
|
@@ -660,7 +676,6 @@ var LIMIT_ORDER_COLUMNS = `
|
|
|
660
676
|
price,
|
|
661
677
|
size,
|
|
662
678
|
remaining,
|
|
663
|
-
reserved,
|
|
664
679
|
accepted_sources as acceptedSources,
|
|
665
680
|
ttl_secs as ttlSecs,
|
|
666
681
|
expires_at as expiresAt,
|
|
@@ -674,11 +689,13 @@ var LIMIT_ORDER_COLUMNS = `
|
|
|
674
689
|
created_at as createdAt,
|
|
675
690
|
updated_at as updatedAt
|
|
676
691
|
`;
|
|
677
|
-
var LimitOrderWriteError = class extends Error {
|
|
678
|
-
};
|
|
679
692
|
function statusGuard(only) {
|
|
680
693
|
return only && only.length > 0 ? ` AND status IN (${only.map(() => "?").join(", ")})` : "";
|
|
681
694
|
}
|
|
695
|
+
function clampable(only) {
|
|
696
|
+
const live = ["open", "resizing"];
|
|
697
|
+
return only && only.length > 0 ? live.filter((status) => only.includes(status)) : live;
|
|
698
|
+
}
|
|
682
699
|
var SqliteLimitOrderStore = class {
|
|
683
700
|
constructor(db, loggers = defaultLoggerContext()) {
|
|
684
701
|
this.db = db;
|
|
@@ -697,6 +714,9 @@ var SqliteLimitOrderStore = class {
|
|
|
697
714
|
price TEXT NOT NULL,
|
|
698
715
|
size TEXT NOT NULL,
|
|
699
716
|
remaining TEXT NOT NULL,
|
|
717
|
+
-- Never read or written: limit orders keep no local holds. Kept, and reset to
|
|
718
|
+
-- '0' on every start, so a rollback to a build that still reads it finds the
|
|
719
|
+
-- column and no stale hold.
|
|
700
720
|
reserved TEXT NOT NULL DEFAULT '0',
|
|
701
721
|
accepted_sources TEXT NOT NULL,
|
|
702
722
|
ttl_secs INTEGER NOT NULL,
|
|
@@ -724,11 +744,15 @@ var SqliteLimitOrderStore = class {
|
|
|
724
744
|
amount TEXT NOT NULL,
|
|
725
745
|
amount_in TEXT,
|
|
726
746
|
transaction_hash TEXT,
|
|
747
|
+
log_index INTEGER,
|
|
727
748
|
filled_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
728
749
|
);
|
|
729
750
|
|
|
730
751
|
CREATE INDEX IF NOT EXISTS idx_limit_order_fills_order ON limit_order_fills(limit_order_id);
|
|
731
752
|
`);
|
|
753
|
+
if (columnNames(this.db, "limit_orders").has("reserved") && this.db.prepare("SELECT 1 FROM limit_orders WHERE reserved <> '0' LIMIT 1").get()) {
|
|
754
|
+
this.db.exec("UPDATE limit_orders SET reserved = '0' WHERE reserved <> '0'");
|
|
755
|
+
}
|
|
732
756
|
if (!columnNames(this.db, "limit_orders").has("entry_point")) {
|
|
733
757
|
this.db.exec("ALTER TABLE limit_orders ADD COLUMN entry_point TEXT");
|
|
734
758
|
this.logger.info({ column: "entry_point" }, "Migrated limit order storage schema");
|
|
@@ -737,6 +761,10 @@ var SqliteLimitOrderStore = class {
|
|
|
737
761
|
this.db.exec("ALTER TABLE limit_order_fills ADD COLUMN amount_in TEXT");
|
|
738
762
|
this.logger.info({ column: "amount_in" }, "Migrated limit order fill schema");
|
|
739
763
|
}
|
|
764
|
+
if (!columnNames(this.db, "limit_order_fills").has("log_index")) {
|
|
765
|
+
this.db.exec("ALTER TABLE limit_order_fills ADD COLUMN log_index INTEGER");
|
|
766
|
+
this.logger.info({ column: "log_index" }, "Migrated limit order fill schema");
|
|
767
|
+
}
|
|
740
768
|
}
|
|
741
769
|
// biome-ignore lint/suspicious/noExplicitAny: raw sqlite row
|
|
742
770
|
toLimitOrder(row) {
|
|
@@ -818,43 +846,17 @@ var SqliteLimitOrderStore = class {
|
|
|
818
846
|
).run(status, lastError, id, ...only ?? []);
|
|
819
847
|
return result.changes === 1 ? this.read(id) : null;
|
|
820
848
|
}
|
|
821
|
-
async reserve(id, amount) {
|
|
822
|
-
const order = this.read(id);
|
|
823
|
-
if (!order || order.status !== "open") return false;
|
|
824
|
-
if (BigInt(amount) > BigInt(order.remaining)) return false;
|
|
825
|
-
const reserved = BigInt(order.reserved) + BigInt(amount);
|
|
826
|
-
const result = this.db.prepare(`
|
|
827
|
-
UPDATE limit_orders SET reserved = ?, updated_at = datetime('now')
|
|
828
|
-
WHERE id = ? AND reserved = ? AND status = 'open'
|
|
829
|
-
`).run(reserved.toString(), id, order.reserved);
|
|
830
|
-
return result.changes === 1;
|
|
831
|
-
}
|
|
832
|
-
async transaction(settle) {
|
|
833
|
-
this.db.exec("BEGIN");
|
|
834
|
-
try {
|
|
835
|
-
const result = await settle();
|
|
836
|
-
this.db.exec("COMMIT");
|
|
837
|
-
return result;
|
|
838
|
-
} catch (err) {
|
|
839
|
-
if (this.db.isTransaction !== false) {
|
|
840
|
-
try {
|
|
841
|
-
this.db.exec("ROLLBACK");
|
|
842
|
-
} catch {
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
throw err;
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
849
|
async recordFill(fill) {
|
|
849
850
|
this.db.prepare(
|
|
850
|
-
"INSERT INTO limit_order_fills (limit_order_id, commitment, bid, amount, amount_in, transaction_hash) VALUES (?, ?, ?, ?, ?, ?)"
|
|
851
|
+
"INSERT INTO limit_order_fills (limit_order_id, commitment, bid, amount, amount_in, transaction_hash, log_index) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
851
852
|
).run(
|
|
852
853
|
fill.limitOrderId,
|
|
853
854
|
fill.commitment,
|
|
854
855
|
fill.bid ?? null,
|
|
855
856
|
fill.amount,
|
|
856
857
|
fill.amountIn ?? null,
|
|
857
|
-
fill.transactionHash ?? null
|
|
858
|
+
fill.transactionHash ?? null,
|
|
859
|
+
fill.logIndex ?? null
|
|
858
860
|
);
|
|
859
861
|
}
|
|
860
862
|
async fillHistory() {
|
|
@@ -867,38 +869,23 @@ var SqliteLimitOrderStore = class {
|
|
|
867
869
|
}
|
|
868
870
|
async fills(limitOrderId, limit = 100) {
|
|
869
871
|
return this.db.prepare(
|
|
870
|
-
`SELECT id, limit_order_id as limitOrderId, commitment, bid, amount, amount_in as amountIn, transaction_hash as transactionHash,
|
|
872
|
+
`SELECT id, limit_order_id as limitOrderId, commitment, bid, amount, amount_in as amountIn, transaction_hash as transactionHash, log_index as logIndex,
|
|
871
873
|
filled_at as filledAt
|
|
872
874
|
FROM limit_order_fills WHERE limit_order_id = ? ORDER BY id DESC LIMIT ?`
|
|
873
875
|
).all(limitOrderId, Math.min(Math.max(limit, 1), 500));
|
|
874
876
|
}
|
|
875
|
-
async
|
|
876
|
-
const
|
|
877
|
-
if (!order) return null;
|
|
878
|
-
const remaining = BigInt(order.remaining) - BigInt(amount);
|
|
879
|
-
const result = this.db.prepare("UPDATE limit_orders SET remaining = ?, updated_at = datetime('now') WHERE id = ? AND remaining = ?").run((remaining > 0n ? remaining : 0n).toString(), id, order.remaining);
|
|
880
|
-
if (result.changes !== 1) throw new LimitOrderWriteError(`Another writer moved limit order '${id}' mid draw-down`);
|
|
881
|
-
return this.read(id);
|
|
882
|
-
}
|
|
883
|
-
async clampRemaining(id, room) {
|
|
877
|
+
async clampRemaining(id, room, only) {
|
|
878
|
+
const statuses = clampable(only);
|
|
884
879
|
const order = this.read(id);
|
|
885
|
-
if (!order || order.status
|
|
886
|
-
const
|
|
887
|
-
const target = sum > 0n ? sum : 0n;
|
|
880
|
+
if (!order || !statuses.includes(order.status)) return null;
|
|
881
|
+
const target = BigInt(room) > 0n ? BigInt(room) : 0n;
|
|
888
882
|
if (target >= BigInt(order.remaining)) return null;
|
|
889
883
|
const result = this.db.prepare(`
|
|
890
884
|
UPDATE limit_orders SET remaining = ?, updated_at = datetime('now')
|
|
891
|
-
WHERE id = ? AND remaining = ? AND
|
|
892
|
-
`).run(target.toString(), id, order.remaining,
|
|
885
|
+
WHERE id = ? AND remaining = ? AND status IN (${statuses.map(() => "?").join(", ")})
|
|
886
|
+
`).run(target.toString(), id, order.remaining, ...statuses);
|
|
893
887
|
return result.changes === 1 ? this.read(id) : null;
|
|
894
888
|
}
|
|
895
|
-
async release(id, amount) {
|
|
896
|
-
const order = this.read(id);
|
|
897
|
-
if (!order) return;
|
|
898
|
-
const reserved = BigInt(order.reserved) - BigInt(amount);
|
|
899
|
-
const result = this.db.prepare("UPDATE limit_orders SET reserved = ?, updated_at = datetime('now') WHERE id = ? AND reserved = ?").run((reserved > 0n ? reserved : 0n).toString(), id, order.reserved);
|
|
900
|
-
if (result.changes !== 1) throw new LimitOrderWriteError(`Another writer moved limit order '${id}' mid release`);
|
|
901
|
-
}
|
|
902
889
|
};
|
|
903
890
|
|
|
904
891
|
// src/data/sqlite/state.ts
|