@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.cjs
CHANGED
|
@@ -479,18 +479,31 @@ var BID_COLUMNS = `
|
|
|
479
479
|
retracted_at as retractedAt,
|
|
480
480
|
retract_extrinsic_hash as retractExtrinsicHash,
|
|
481
481
|
dead,
|
|
482
|
-
|
|
482
|
+
on_orderbook as onOrderbook,
|
|
483
|
+
priced_by as pricedBy,
|
|
483
484
|
reservations
|
|
484
485
|
`;
|
|
485
|
-
function
|
|
486
|
-
if (!raw) return
|
|
486
|
+
function parseJson(raw) {
|
|
487
|
+
if (!raw) return null;
|
|
487
488
|
try {
|
|
488
|
-
|
|
489
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
489
|
+
return JSON.parse(raw);
|
|
490
490
|
} catch {
|
|
491
|
-
return
|
|
491
|
+
return null;
|
|
492
492
|
}
|
|
493
493
|
}
|
|
494
|
+
function pricedBy(row) {
|
|
495
|
+
const current = parseJson(row.pricedBy);
|
|
496
|
+
if (current && typeof current === "object") return current;
|
|
497
|
+
const legacy = parseJson(row.reservations);
|
|
498
|
+
const first = Array.isArray(legacy) ? legacy[0] : null;
|
|
499
|
+
if (!first || typeof first !== "object" || typeof first.limitOrderId !== "string") return null;
|
|
500
|
+
return {
|
|
501
|
+
limitOrderId: first.limitOrderId,
|
|
502
|
+
payout: String(first.payout ?? first.amount),
|
|
503
|
+
...first.take !== void 0 ? { take: String(first.take) } : {},
|
|
504
|
+
...first.takeDecimals !== void 0 ? { takeDecimals: Number(first.takeDecimals) } : {}
|
|
505
|
+
};
|
|
506
|
+
}
|
|
494
507
|
var SqliteBidStore = class {
|
|
495
508
|
constructor(db, loggers = defaultLoggerContext()) {
|
|
496
509
|
this.db = db;
|
|
@@ -513,7 +526,11 @@ var SqliteBidStore = class {
|
|
|
513
526
|
retracted_at TEXT,
|
|
514
527
|
retract_extrinsic_hash TEXT,
|
|
515
528
|
dead INTEGER NOT NULL DEFAULT 0,
|
|
516
|
-
|
|
529
|
+
on_orderbook INTEGER NOT NULL DEFAULT 0,
|
|
530
|
+
-- Only read, as the provenance of a bid written before priced_by. Kept, and
|
|
531
|
+
-- never written, so a rollback to a build that still reads it finds the column.
|
|
532
|
+
reservations TEXT,
|
|
533
|
+
priced_by TEXT
|
|
517
534
|
);
|
|
518
535
|
|
|
519
536
|
CREATE INDEX IF NOT EXISTS idx_bids_commitment ON bids(commitment);
|
|
@@ -522,12 +539,12 @@ var SqliteBidStore = class {
|
|
|
522
539
|
CREATE INDEX IF NOT EXISTS idx_bids_created_at ON bids(created_at);
|
|
523
540
|
`);
|
|
524
541
|
const columns = columnNames(this.db, "bids");
|
|
525
|
-
for (const column of ["dead", "pending"]) {
|
|
542
|
+
for (const column of ["dead", "pending", "on_orderbook"]) {
|
|
526
543
|
if (columns.has(column)) continue;
|
|
527
544
|
this.db.exec(`ALTER TABLE bids ADD COLUMN ${column} INTEGER NOT NULL DEFAULT 0`);
|
|
528
545
|
this.logger.info({ column }, "Migrated bid storage schema");
|
|
529
546
|
}
|
|
530
|
-
for (const column of ["bid", "reservations"]) {
|
|
547
|
+
for (const column of ["bid", "reservations", "priced_by"]) {
|
|
531
548
|
if (columns.has(column)) continue;
|
|
532
549
|
this.db.exec(`ALTER TABLE bids ADD COLUMN ${column} TEXT`);
|
|
533
550
|
this.logger.info({ column }, "Migrated bid storage schema");
|
|
@@ -536,19 +553,21 @@ var SqliteBidStore = class {
|
|
|
536
553
|
}
|
|
537
554
|
// biome-ignore lint/suspicious/noExplicitAny: raw sqlite row
|
|
538
555
|
toStoredBid(row) {
|
|
556
|
+
const { reservations: _legacy, ...rest } = row;
|
|
539
557
|
return {
|
|
540
|
-
...
|
|
558
|
+
...rest,
|
|
541
559
|
success: Boolean(row.success),
|
|
542
560
|
pending: Boolean(row.pending),
|
|
543
561
|
retracted: Boolean(row.retracted),
|
|
544
562
|
dead: Boolean(row.dead),
|
|
545
|
-
|
|
563
|
+
onOrderbook: Boolean(row.onOrderbook),
|
|
564
|
+
pricedBy: pricedBy(row)
|
|
546
565
|
};
|
|
547
566
|
}
|
|
548
567
|
async store(bid) {
|
|
549
568
|
const result = this.db.prepare(`
|
|
550
|
-
INSERT INTO bids (commitment, bid, extrinsic_hash, block_hash, success, pending, error,
|
|
551
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
569
|
+
INSERT INTO bids (commitment, bid, extrinsic_hash, block_hash, success, pending, error, on_orderbook, priced_by)
|
|
570
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
552
571
|
`).run(
|
|
553
572
|
bid.commitment,
|
|
554
573
|
bid.bid ?? null,
|
|
@@ -557,7 +576,8 @@ var SqliteBidStore = class {
|
|
|
557
576
|
bid.success ? 1 : 0,
|
|
558
577
|
bid.pending ? 1 : 0,
|
|
559
578
|
bid.error || null,
|
|
560
|
-
bid.
|
|
579
|
+
bid.onOrderbook ? 1 : 0,
|
|
580
|
+
bid.pricedBy ? JSON.stringify(bid.pricedBy) : null
|
|
561
581
|
);
|
|
562
582
|
this.logger.debug({ id: result.lastInsertRowid, commitment: bid.commitment, success: bid.success }, "Bid stored");
|
|
563
583
|
}
|
|
@@ -583,37 +603,33 @@ var SqliteBidStore = class {
|
|
|
583
603
|
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));
|
|
584
604
|
return rows.map((row) => this.toStoredBid(row));
|
|
585
605
|
}
|
|
586
|
-
async markRetracted(commitment, retractExtrinsicHash) {
|
|
606
|
+
async markRetracted(commitment, retractExtrinsicHash, rows) {
|
|
607
|
+
if (rows?.length === 0) return false;
|
|
587
608
|
const result = this.db.prepare(`
|
|
588
609
|
UPDATE bids
|
|
589
610
|
SET retracted = 1, retracted_at = datetime('now'), retract_extrinsic_hash = ?
|
|
590
|
-
WHERE commitment = ? AND retracted = 0
|
|
591
|
-
`).run(retractExtrinsicHash, commitment);
|
|
611
|
+
WHERE commitment = ? AND retracted = 0${rows ? ` AND id IN (${rows.map(() => "?").join(",")})` : ""}
|
|
612
|
+
`).run(retractExtrinsicHash, commitment, ...rows ?? []);
|
|
592
613
|
if (result.changes > 0) {
|
|
593
614
|
this.logger.info({ commitment, retractExtrinsicHash }, "Bid marked as retracted");
|
|
594
615
|
return true;
|
|
595
616
|
}
|
|
596
617
|
return false;
|
|
597
618
|
}
|
|
598
|
-
async claimReservation(commitment, bid) {
|
|
599
|
-
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(
|
|
600
|
-
"SELECT id, reservations FROM bids WHERE commitment = ? AND bid = ? AND reservations IS NOT NULL ORDER BY id"
|
|
601
|
-
).all(commitment, bid);
|
|
602
|
-
const claimed = [];
|
|
603
|
-
for (const row of rows) {
|
|
604
|
-
const result = this.db.prepare("UPDATE bids SET reservations = NULL WHERE id = ? AND reservations = ?").run(row.id, row.reservations);
|
|
605
|
-
if (result.changes === 1) claimed.push(...parseHolds(row.reservations));
|
|
606
|
-
}
|
|
607
|
-
return claimed;
|
|
608
|
-
}
|
|
609
619
|
async byLimitOrder(limitOrderId, limit = 100) {
|
|
610
|
-
const
|
|
611
|
-
|
|
620
|
+
const pattern = `%${limitOrderId}%`;
|
|
621
|
+
const rows = this.db.prepare(
|
|
622
|
+
`SELECT ${BID_COLUMNS} FROM bids WHERE priced_by LIKE ? OR (priced_by IS NULL AND reservations LIKE ?) ORDER BY id DESC LIMIT ?`
|
|
623
|
+
).all(pattern, pattern, Math.min(Math.max(limit, 1), 500));
|
|
624
|
+
return rows.map((row) => this.toStoredBid(row)).filter((bid) => bid.pricedBy?.limitOrderId === limitOrderId);
|
|
612
625
|
}
|
|
613
|
-
async markDead(commitment) {
|
|
614
|
-
|
|
626
|
+
async markDead(commitment, rows) {
|
|
627
|
+
if (rows?.length === 0) return false;
|
|
628
|
+
const result = this.db.prepare(
|
|
629
|
+
`UPDATE bids SET dead = 1 WHERE commitment = ? AND retracted = 0 AND dead = 0${rows ? ` AND id IN (${rows.map(() => "?").join(",")})` : ""}`
|
|
630
|
+
).run(commitment, ...rows ?? []);
|
|
615
631
|
if (result.changes > 0) {
|
|
616
|
-
this.logger.debug({ commitment }, "Bid marked
|
|
632
|
+
this.logger.debug({ commitment }, "Bid marked dead, due for retraction on the next sweep");
|
|
617
633
|
return true;
|
|
618
634
|
}
|
|
619
635
|
return false;
|
|
@@ -622,8 +638,8 @@ var SqliteBidStore = class {
|
|
|
622
638
|
const stats = this.db.prepare(`
|
|
623
639
|
SELECT
|
|
624
640
|
COUNT(*) as total,
|
|
625
|
-
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successful,
|
|
626
|
-
SUM(CASE WHEN success = 0 THEN 1 ELSE 0 END) as failed,
|
|
641
|
+
SUM(CASE WHEN success = 1 OR on_orderbook = 1 THEN 1 ELSE 0 END) as successful,
|
|
642
|
+
SUM(CASE WHEN success = 0 AND on_orderbook = 0 THEN 1 ELSE 0 END) as failed,
|
|
627
643
|
SUM(CASE WHEN retracted = 1 THEN 1 ELSE 0 END) as retracted,
|
|
628
644
|
SUM(CASE WHEN (success = 1 OR pending = 1) AND retracted = 0 THEN 1 ELSE 0 END) as pendingRetraction
|
|
629
645
|
FROM bids
|
|
@@ -637,7 +653,7 @@ var SqliteBidStore = class {
|
|
|
637
653
|
};
|
|
638
654
|
}
|
|
639
655
|
async failed(limit = 100) {
|
|
640
|
-
const rows = this.db.prepare(`SELECT ${BID_COLUMNS} FROM bids WHERE success = 0 ORDER BY created_at DESC LIMIT ?`).all(limit);
|
|
656
|
+
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);
|
|
641
657
|
return rows.map((row) => this.toStoredBid(row));
|
|
642
658
|
}
|
|
643
659
|
async byCommitments(commitments) {
|
|
@@ -697,7 +713,6 @@ var LIMIT_ORDER_COLUMNS = `
|
|
|
697
713
|
price,
|
|
698
714
|
size,
|
|
699
715
|
remaining,
|
|
700
|
-
reserved,
|
|
701
716
|
accepted_sources as acceptedSources,
|
|
702
717
|
ttl_secs as ttlSecs,
|
|
703
718
|
expires_at as expiresAt,
|
|
@@ -711,11 +726,13 @@ var LIMIT_ORDER_COLUMNS = `
|
|
|
711
726
|
created_at as createdAt,
|
|
712
727
|
updated_at as updatedAt
|
|
713
728
|
`;
|
|
714
|
-
var LimitOrderWriteError = class extends Error {
|
|
715
|
-
};
|
|
716
729
|
function statusGuard(only) {
|
|
717
730
|
return only && only.length > 0 ? ` AND status IN (${only.map(() => "?").join(", ")})` : "";
|
|
718
731
|
}
|
|
732
|
+
function clampable(only) {
|
|
733
|
+
const live = ["open", "resizing"];
|
|
734
|
+
return only && only.length > 0 ? live.filter((status) => only.includes(status)) : live;
|
|
735
|
+
}
|
|
719
736
|
var SqliteLimitOrderStore = class {
|
|
720
737
|
constructor(db, loggers = defaultLoggerContext()) {
|
|
721
738
|
this.db = db;
|
|
@@ -734,6 +751,9 @@ var SqliteLimitOrderStore = class {
|
|
|
734
751
|
price TEXT NOT NULL,
|
|
735
752
|
size TEXT NOT NULL,
|
|
736
753
|
remaining TEXT NOT NULL,
|
|
754
|
+
-- Never read or written: limit orders keep no local holds. Kept, and reset to
|
|
755
|
+
-- '0' on every start, so a rollback to a build that still reads it finds the
|
|
756
|
+
-- column and no stale hold.
|
|
737
757
|
reserved TEXT NOT NULL DEFAULT '0',
|
|
738
758
|
accepted_sources TEXT NOT NULL,
|
|
739
759
|
ttl_secs INTEGER NOT NULL,
|
|
@@ -761,11 +781,15 @@ var SqliteLimitOrderStore = class {
|
|
|
761
781
|
amount TEXT NOT NULL,
|
|
762
782
|
amount_in TEXT,
|
|
763
783
|
transaction_hash TEXT,
|
|
784
|
+
log_index INTEGER,
|
|
764
785
|
filled_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
765
786
|
);
|
|
766
787
|
|
|
767
788
|
CREATE INDEX IF NOT EXISTS idx_limit_order_fills_order ON limit_order_fills(limit_order_id);
|
|
768
789
|
`);
|
|
790
|
+
if (columnNames(this.db, "limit_orders").has("reserved") && this.db.prepare("SELECT 1 FROM limit_orders WHERE reserved <> '0' LIMIT 1").get()) {
|
|
791
|
+
this.db.exec("UPDATE limit_orders SET reserved = '0' WHERE reserved <> '0'");
|
|
792
|
+
}
|
|
769
793
|
if (!columnNames(this.db, "limit_orders").has("entry_point")) {
|
|
770
794
|
this.db.exec("ALTER TABLE limit_orders ADD COLUMN entry_point TEXT");
|
|
771
795
|
this.logger.info({ column: "entry_point" }, "Migrated limit order storage schema");
|
|
@@ -774,6 +798,10 @@ var SqliteLimitOrderStore = class {
|
|
|
774
798
|
this.db.exec("ALTER TABLE limit_order_fills ADD COLUMN amount_in TEXT");
|
|
775
799
|
this.logger.info({ column: "amount_in" }, "Migrated limit order fill schema");
|
|
776
800
|
}
|
|
801
|
+
if (!columnNames(this.db, "limit_order_fills").has("log_index")) {
|
|
802
|
+
this.db.exec("ALTER TABLE limit_order_fills ADD COLUMN log_index INTEGER");
|
|
803
|
+
this.logger.info({ column: "log_index" }, "Migrated limit order fill schema");
|
|
804
|
+
}
|
|
777
805
|
}
|
|
778
806
|
// biome-ignore lint/suspicious/noExplicitAny: raw sqlite row
|
|
779
807
|
toLimitOrder(row) {
|
|
@@ -855,43 +883,17 @@ var SqliteLimitOrderStore = class {
|
|
|
855
883
|
).run(status, lastError, id, ...only ?? []);
|
|
856
884
|
return result.changes === 1 ? this.read(id) : null;
|
|
857
885
|
}
|
|
858
|
-
async reserve(id, amount) {
|
|
859
|
-
const order = this.read(id);
|
|
860
|
-
if (!order || order.status !== "open") return false;
|
|
861
|
-
if (BigInt(amount) > BigInt(order.remaining)) return false;
|
|
862
|
-
const reserved = BigInt(order.reserved) + BigInt(amount);
|
|
863
|
-
const result = this.db.prepare(`
|
|
864
|
-
UPDATE limit_orders SET reserved = ?, updated_at = datetime('now')
|
|
865
|
-
WHERE id = ? AND reserved = ? AND status = 'open'
|
|
866
|
-
`).run(reserved.toString(), id, order.reserved);
|
|
867
|
-
return result.changes === 1;
|
|
868
|
-
}
|
|
869
|
-
async transaction(settle) {
|
|
870
|
-
this.db.exec("BEGIN");
|
|
871
|
-
try {
|
|
872
|
-
const result = await settle();
|
|
873
|
-
this.db.exec("COMMIT");
|
|
874
|
-
return result;
|
|
875
|
-
} catch (err) {
|
|
876
|
-
if (this.db.isTransaction !== false) {
|
|
877
|
-
try {
|
|
878
|
-
this.db.exec("ROLLBACK");
|
|
879
|
-
} catch {
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
throw err;
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
886
|
async recordFill(fill) {
|
|
886
887
|
this.db.prepare(
|
|
887
|
-
"INSERT INTO limit_order_fills (limit_order_id, commitment, bid, amount, amount_in, transaction_hash) VALUES (?, ?, ?, ?, ?, ?)"
|
|
888
|
+
"INSERT INTO limit_order_fills (limit_order_id, commitment, bid, amount, amount_in, transaction_hash, log_index) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
888
889
|
).run(
|
|
889
890
|
fill.limitOrderId,
|
|
890
891
|
fill.commitment,
|
|
891
892
|
fill.bid ?? null,
|
|
892
893
|
fill.amount,
|
|
893
894
|
fill.amountIn ?? null,
|
|
894
|
-
fill.transactionHash ?? null
|
|
895
|
+
fill.transactionHash ?? null,
|
|
896
|
+
fill.logIndex ?? null
|
|
895
897
|
);
|
|
896
898
|
}
|
|
897
899
|
async fillHistory() {
|
|
@@ -904,38 +906,23 @@ var SqliteLimitOrderStore = class {
|
|
|
904
906
|
}
|
|
905
907
|
async fills(limitOrderId, limit = 100) {
|
|
906
908
|
return this.db.prepare(
|
|
907
|
-
`SELECT id, limit_order_id as limitOrderId, commitment, bid, amount, amount_in as amountIn, transaction_hash as transactionHash,
|
|
909
|
+
`SELECT id, limit_order_id as limitOrderId, commitment, bid, amount, amount_in as amountIn, transaction_hash as transactionHash, log_index as logIndex,
|
|
908
910
|
filled_at as filledAt
|
|
909
911
|
FROM limit_order_fills WHERE limit_order_id = ? ORDER BY id DESC LIMIT ?`
|
|
910
912
|
).all(limitOrderId, Math.min(Math.max(limit, 1), 500));
|
|
911
913
|
}
|
|
912
|
-
async
|
|
913
|
-
const
|
|
914
|
-
if (!order) return null;
|
|
915
|
-
const remaining = BigInt(order.remaining) - BigInt(amount);
|
|
916
|
-
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);
|
|
917
|
-
if (result.changes !== 1) throw new LimitOrderWriteError(`Another writer moved limit order '${id}' mid draw-down`);
|
|
918
|
-
return this.read(id);
|
|
919
|
-
}
|
|
920
|
-
async clampRemaining(id, room) {
|
|
914
|
+
async clampRemaining(id, room, only) {
|
|
915
|
+
const statuses = clampable(only);
|
|
921
916
|
const order = this.read(id);
|
|
922
|
-
if (!order || order.status
|
|
923
|
-
const
|
|
924
|
-
const target = sum > 0n ? sum : 0n;
|
|
917
|
+
if (!order || !statuses.includes(order.status)) return null;
|
|
918
|
+
const target = BigInt(room) > 0n ? BigInt(room) : 0n;
|
|
925
919
|
if (target >= BigInt(order.remaining)) return null;
|
|
926
920
|
const result = this.db.prepare(`
|
|
927
921
|
UPDATE limit_orders SET remaining = ?, updated_at = datetime('now')
|
|
928
|
-
WHERE id = ? AND remaining = ? AND
|
|
929
|
-
`).run(target.toString(), id, order.remaining,
|
|
922
|
+
WHERE id = ? AND remaining = ? AND status IN (${statuses.map(() => "?").join(", ")})
|
|
923
|
+
`).run(target.toString(), id, order.remaining, ...statuses);
|
|
930
924
|
return result.changes === 1 ? this.read(id) : null;
|
|
931
925
|
}
|
|
932
|
-
async release(id, amount) {
|
|
933
|
-
const order = this.read(id);
|
|
934
|
-
if (!order) return;
|
|
935
|
-
const reserved = BigInt(order.reserved) - BigInt(amount);
|
|
936
|
-
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);
|
|
937
|
-
if (result.changes !== 1) throw new LimitOrderWriteError(`Another writer moved limit order '${id}' mid release`);
|
|
938
|
-
}
|
|
939
926
|
};
|
|
940
927
|
|
|
941
928
|
// src/data/sqlite/state.ts
|