@usherlabs/cex-broker 0.2.20 → 0.2.21
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/commands/cli.js +434 -13
- package/dist/handlers/execute-action/context.d.ts +2 -0
- package/dist/handlers/execute-action/handler.d.ts +2 -0
- package/dist/helpers/broker-execution-archive/capture.d.ts +8 -0
- package/dist/helpers/broker-execution-archive/index.d.ts +3 -3
- package/dist/helpers/broker-execution-archive/rows.d.ts +55 -1
- package/dist/helpers/broker-execution-archive/types.d.ts +5 -1
- package/dist/helpers/broker-execution-archive/writer.d.ts +2 -0
- package/dist/helpers/fill-archive-poller.d.ts +42 -0
- package/dist/helpers/order-activity-tracker.d.ts +22 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +435 -14
- package/dist/index.js.map +17 -15
- package/dist/server.d.ts +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -274531,6 +274531,8 @@ function hashMarketMetadata(payload) {
|
|
|
274531
274531
|
|
|
274532
274532
|
// src/helpers/broker-execution-archive/types.ts
|
|
274533
274533
|
var BROKER_WRITE_SOURCE = "broker_write";
|
|
274534
|
+
var ARCHIVE_SCHEMA_VERSION = "1";
|
|
274535
|
+
var FILL_EVENT_KIND = "trade_history_fill";
|
|
274534
274536
|
|
|
274535
274537
|
// src/helpers/broker-execution-archive/rows.ts
|
|
274536
274538
|
function firstString2(...values2) {
|
|
@@ -274544,6 +274546,26 @@ function firstString2(...values2) {
|
|
|
274544
274546
|
}
|
|
274545
274547
|
return;
|
|
274546
274548
|
}
|
|
274549
|
+
function firstNumber2(...values2) {
|
|
274550
|
+
for (const value of values2) {
|
|
274551
|
+
const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
274552
|
+
if (Number.isFinite(numeric)) {
|
|
274553
|
+
return numeric;
|
|
274554
|
+
}
|
|
274555
|
+
}
|
|
274556
|
+
return;
|
|
274557
|
+
}
|
|
274558
|
+
function normalizeTimestamp2(value) {
|
|
274559
|
+
if (typeof value === "string" && value.trim()) {
|
|
274560
|
+
return value.trim();
|
|
274561
|
+
}
|
|
274562
|
+
const ms = firstNumber2(value);
|
|
274563
|
+
if (ms === undefined) {
|
|
274564
|
+
return;
|
|
274565
|
+
}
|
|
274566
|
+
const date = new Date(ms);
|
|
274567
|
+
return Number.isNaN(date.getTime()) ? undefined : date.toISOString();
|
|
274568
|
+
}
|
|
274547
274569
|
function compactUndefined2(record) {
|
|
274548
274570
|
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
|
|
274549
274571
|
}
|
|
@@ -274608,6 +274630,99 @@ function buildSubscribeStreamArchiveRow(input) {
|
|
|
274608
274630
|
})
|
|
274609
274631
|
};
|
|
274610
274632
|
}
|
|
274633
|
+
function quantityString(...values2) {
|
|
274634
|
+
return firstString2(...values2);
|
|
274635
|
+
}
|
|
274636
|
+
function buildTransferEventArchiveRow(input) {
|
|
274637
|
+
const { tags, transfer } = input;
|
|
274638
|
+
return {
|
|
274639
|
+
table: "broker_execution.transfer_events",
|
|
274640
|
+
row: compactUndefined2({
|
|
274641
|
+
...tags,
|
|
274642
|
+
schema_version: ARCHIVE_SCHEMA_VERSION,
|
|
274643
|
+
event_kind: transfer.eventKind,
|
|
274644
|
+
lifecycle_action: transfer.lifecycleAction,
|
|
274645
|
+
status: transfer.status ?? "",
|
|
274646
|
+
asset_symbol: tags.symbol,
|
|
274647
|
+
amount: transfer.amount,
|
|
274648
|
+
address: transfer.address,
|
|
274649
|
+
network: transfer.network,
|
|
274650
|
+
external_id: transfer.externalId ?? "",
|
|
274651
|
+
txid: transfer.txid,
|
|
274652
|
+
result_index: transfer.resultIndex ?? 0,
|
|
274653
|
+
fee_amount: transfer.feeAmount,
|
|
274654
|
+
fee_currency: transfer.feeCurrency,
|
|
274655
|
+
exchange_timestamp: transfer.exchangeTimestamp,
|
|
274656
|
+
error_summary: transfer.errorSummary,
|
|
274657
|
+
payload_json: JSON.stringify(transfer.payload)
|
|
274658
|
+
})
|
|
274659
|
+
};
|
|
274660
|
+
}
|
|
274661
|
+
function normalizeCcxtTransactionForArchive(transaction) {
|
|
274662
|
+
const record = asRecord(transaction);
|
|
274663
|
+
const info = asRecord(record?.info);
|
|
274664
|
+
const fee = asRecord(record?.fee);
|
|
274665
|
+
return compactUndefined2({
|
|
274666
|
+
externalId: firstString2(record?.id, info?.id, record?.txid, info?.txId),
|
|
274667
|
+
txid: firstString2(record?.txid, info?.txId, info?.txid, info?.tx_hash),
|
|
274668
|
+
address: firstString2(record?.address, record?.addressTo, info?.address),
|
|
274669
|
+
network: firstString2(record?.network, info?.network),
|
|
274670
|
+
amount: quantityString(info?.amount, record?.amount),
|
|
274671
|
+
assetSymbol: firstString2(record?.currency, info?.coin, info?.asset),
|
|
274672
|
+
status: firstString2(record?.status, info?.status)?.toLowerCase(),
|
|
274673
|
+
feeAmount: quantityString(fee?.cost, record?.feeCost),
|
|
274674
|
+
feeCurrency: firstString2(fee?.currency, record?.feeCurrency),
|
|
274675
|
+
exchangeTimestamp: normalizeTimestamp2(firstValueForTransfer(record?.timestamp, record?.datetime, info?.applyTime))
|
|
274676
|
+
});
|
|
274677
|
+
}
|
|
274678
|
+
function firstValueForTransfer(...values2) {
|
|
274679
|
+
return values2.find((value) => value !== undefined && value !== null);
|
|
274680
|
+
}
|
|
274681
|
+
function buildFillEventArchiveRow(input) {
|
|
274682
|
+
const { tags, fill } = input;
|
|
274683
|
+
return {
|
|
274684
|
+
table: "broker_execution.fill_events",
|
|
274685
|
+
row: compactUndefined2({
|
|
274686
|
+
...tags,
|
|
274687
|
+
schema_version: ARCHIVE_SCHEMA_VERSION,
|
|
274688
|
+
event_kind: FILL_EVENT_KIND,
|
|
274689
|
+
order_id: fill.orderId ?? "",
|
|
274690
|
+
client_order_id: fill.clientOrderId,
|
|
274691
|
+
fill_id: fill.fillId,
|
|
274692
|
+
fill_index: fill.fillIndex ?? 0,
|
|
274693
|
+
side: fill.side,
|
|
274694
|
+
order_type: fill.orderType,
|
|
274695
|
+
price: fill.price,
|
|
274696
|
+
base_quantity: fill.baseQuantity,
|
|
274697
|
+
quote_quantity: fill.quoteQuantity,
|
|
274698
|
+
fee_amount: fill.feeAmount,
|
|
274699
|
+
fee_currency: fill.feeCurrency,
|
|
274700
|
+
fee_rate: fill.feeRate,
|
|
274701
|
+
exchange_timestamp: fill.exchangeTimestamp,
|
|
274702
|
+
payload_json: JSON.stringify(fill.payload)
|
|
274703
|
+
})
|
|
274704
|
+
};
|
|
274705
|
+
}
|
|
274706
|
+
function normalizeCcxtTradeForArchive(trade) {
|
|
274707
|
+
const record = asRecord(trade);
|
|
274708
|
+
const info = asRecord(record?.info);
|
|
274709
|
+
const fee = asRecord(record?.fee);
|
|
274710
|
+
return {
|
|
274711
|
+
orderId: firstString2(record?.order, info?.orderId, info?.orderID),
|
|
274712
|
+
clientOrderId: firstString2(record?.clientOrderId, info?.clientOrderId, info?.origClientOrderId),
|
|
274713
|
+
fillId: firstString2(record?.id, info?.id, info?.tradeId),
|
|
274714
|
+
side: firstString2(record?.side, info?.side)?.toLowerCase(),
|
|
274715
|
+
orderType: firstString2(record?.type, info?.type)?.toLowerCase(),
|
|
274716
|
+
price: quantityString(info?.price, record?.price),
|
|
274717
|
+
baseQuantity: quantityString(info?.qty, record?.amount),
|
|
274718
|
+
quoteQuantity: quantityString(info?.quoteQty, record?.cost),
|
|
274719
|
+
feeAmount: quantityString(fee?.cost, info?.commission),
|
|
274720
|
+
feeCurrency: firstString2(fee?.currency, info?.commissionAsset),
|
|
274721
|
+
feeRate: quantityString(fee?.rate),
|
|
274722
|
+
exchangeTimestamp: normalizeTimestamp2(firstValueForTransfer(record?.timestamp, record?.datetime, info?.time)),
|
|
274723
|
+
payload: trade
|
|
274724
|
+
};
|
|
274725
|
+
}
|
|
274611
274726
|
function buildMarketMetadataSnapshotRow(input) {
|
|
274612
274727
|
const redactedSnapshot = redactStreamPayload(input.marketSnapshot);
|
|
274613
274728
|
const metadataHash = hashMarketMetadata(redactedSnapshot);
|
|
@@ -274676,6 +274791,25 @@ function archiveSubscribeStreamInBackground(archiver, input) {
|
|
|
274676
274791
|
}
|
|
274677
274792
|
});
|
|
274678
274793
|
}
|
|
274794
|
+
function archiveTransferEventInBackground(archiver, input) {
|
|
274795
|
+
if (!archiver?.isEnabled()) {
|
|
274796
|
+
return;
|
|
274797
|
+
}
|
|
274798
|
+
queueMicrotask(() => {
|
|
274799
|
+
try {
|
|
274800
|
+
const tags = buildCommonArchiveTags({
|
|
274801
|
+
deploymentId: archiver.getDeploymentId(),
|
|
274802
|
+
accountSelector: input.accountSelector,
|
|
274803
|
+
exchange: input.exchange,
|
|
274804
|
+
symbol: input.assetSymbol,
|
|
274805
|
+
brokerObservedTimestamp: input.brokerObservedTimestamp
|
|
274806
|
+
});
|
|
274807
|
+
archiver.enqueue(buildTransferEventArchiveRow({ tags, transfer: input.transfer }));
|
|
274808
|
+
} catch (archiveError) {
|
|
274809
|
+
log.warn("Failed to archive transfer event", { error: archiveError });
|
|
274810
|
+
}
|
|
274811
|
+
});
|
|
274812
|
+
}
|
|
274679
274813
|
async function captureMarketMetadataSnapshot(archiver, broker, input) {
|
|
274680
274814
|
if (!archiver?.canPersistMarketMetadataSnapshot()) {
|
|
274681
274815
|
return;
|
|
@@ -275058,11 +275192,27 @@ class BrokerExecutionArchiver {
|
|
|
275058
275192
|
}
|
|
275059
275193
|
}
|
|
275060
275194
|
this.stats.flushed += batch.length;
|
|
275195
|
+
this.recordFlushHealth(batch);
|
|
275061
275196
|
return true;
|
|
275062
275197
|
}
|
|
275063
|
-
|
|
275198
|
+
recordFlushHealth(batch) {
|
|
275199
|
+
const countByTable = new Map;
|
|
275200
|
+
for (const entry of batch) {
|
|
275201
|
+
countByTable.set(entry.table, (countByTable.get(entry.table) ?? 0) + 1);
|
|
275202
|
+
}
|
|
275203
|
+
for (const [table, count2] of countByTable) {
|
|
275204
|
+
this.recordArchiveMetric("cex_archive_rows_flushed_total", { table }, count2);
|
|
275205
|
+
}
|
|
275206
|
+
this.recordArchiveGauge("cex_archive_last_flush_success", Math.floor(Date.now() / 1000));
|
|
275207
|
+
}
|
|
275208
|
+
async recordArchiveMetric(metricName, labels, value = 1) {
|
|
275209
|
+
try {
|
|
275210
|
+
await this.otelMetrics?.recordCounter(metricName, value, labels);
|
|
275211
|
+
} catch {}
|
|
275212
|
+
}
|
|
275213
|
+
async recordArchiveGauge(metricName, value) {
|
|
275064
275214
|
try {
|
|
275065
|
-
await this.otelMetrics?.
|
|
275215
|
+
await this.otelMetrics?.recordGauge(metricName, value, {});
|
|
275066
275216
|
} catch {}
|
|
275067
275217
|
}
|
|
275068
275218
|
emitOtelLog(entry) {
|
|
@@ -275159,6 +275309,159 @@ function parsePositiveInt(value, fallback) {
|
|
|
275159
275309
|
const parsed = Number.parseInt(value, 10);
|
|
275160
275310
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
275161
275311
|
}
|
|
275312
|
+
// src/helpers/fill-archive-poller.ts
|
|
275313
|
+
var DEFAULT_CONFIG = {
|
|
275314
|
+
pollIntervalMs: 60000,
|
|
275315
|
+
lookbackMs: 24 * 60 * 60 * 1000,
|
|
275316
|
+
tradesLimit: 500
|
|
275317
|
+
};
|
|
275318
|
+
function nextFillCursor(trades, currentSince) {
|
|
275319
|
+
let next = currentSince;
|
|
275320
|
+
for (const trade of trades) {
|
|
275321
|
+
const ts = asRecord(trade)?.timestamp;
|
|
275322
|
+
if (typeof ts === "number" && Number.isFinite(ts) && ts + 1 > next) {
|
|
275323
|
+
next = ts + 1;
|
|
275324
|
+
}
|
|
275325
|
+
}
|
|
275326
|
+
return next;
|
|
275327
|
+
}
|
|
275328
|
+
|
|
275329
|
+
class FillArchivePoller {
|
|
275330
|
+
params;
|
|
275331
|
+
#timer = null;
|
|
275332
|
+
#stopped = false;
|
|
275333
|
+
#running = false;
|
|
275334
|
+
#cursors = new Map;
|
|
275335
|
+
#config;
|
|
275336
|
+
constructor(params) {
|
|
275337
|
+
this.params = params;
|
|
275338
|
+
this.#config = { ...DEFAULT_CONFIG, ...params.config };
|
|
275339
|
+
}
|
|
275340
|
+
start() {
|
|
275341
|
+
if (this.#timer || this.#stopped) {
|
|
275342
|
+
return;
|
|
275343
|
+
}
|
|
275344
|
+
if (!this.params.archiver.isEnabled()) {
|
|
275345
|
+
return;
|
|
275346
|
+
}
|
|
275347
|
+
log.info("\uD83E\uDDFE Fill archive poller started");
|
|
275348
|
+
this.#timer = setTimeout(() => void this.#tick(), 0);
|
|
275349
|
+
this.#timer.unref?.();
|
|
275350
|
+
}
|
|
275351
|
+
stop() {
|
|
275352
|
+
this.#stopped = true;
|
|
275353
|
+
if (this.#timer) {
|
|
275354
|
+
clearTimeout(this.#timer);
|
|
275355
|
+
this.#timer = null;
|
|
275356
|
+
}
|
|
275357
|
+
}
|
|
275358
|
+
async#tick() {
|
|
275359
|
+
if (this.#stopped || this.#running) {
|
|
275360
|
+
return;
|
|
275361
|
+
}
|
|
275362
|
+
this.#running = true;
|
|
275363
|
+
try {
|
|
275364
|
+
await this.pollTrackedOnce();
|
|
275365
|
+
} catch (error) {
|
|
275366
|
+
log.error("Fill archive poller tick failed", error);
|
|
275367
|
+
} finally {
|
|
275368
|
+
this.#running = false;
|
|
275369
|
+
if (!this.#stopped) {
|
|
275370
|
+
this.#timer = setTimeout(() => void this.#tick(), this.#config.pollIntervalMs);
|
|
275371
|
+
this.#timer.unref?.();
|
|
275372
|
+
}
|
|
275373
|
+
}
|
|
275374
|
+
}
|
|
275375
|
+
async pollTrackedOnce() {
|
|
275376
|
+
for (const entry of this.params.tracker.list()) {
|
|
275377
|
+
if (this.#stopped) {
|
|
275378
|
+
break;
|
|
275379
|
+
}
|
|
275380
|
+
await this.#pollOne(entry.exchangeId, entry.accountLabel, entry.symbol);
|
|
275381
|
+
}
|
|
275382
|
+
}
|
|
275383
|
+
async#pollOne(exchangeId, accountLabel, symbol) {
|
|
275384
|
+
const account = resolveBrokerAccount(this.params.brokers[exchangeId], accountLabel);
|
|
275385
|
+
if (!account) {
|
|
275386
|
+
return;
|
|
275387
|
+
}
|
|
275388
|
+
const exchange = account.exchange;
|
|
275389
|
+
if (typeof exchange.fetchMyTrades !== "function" || exchange.has?.fetchMyTrades === false) {
|
|
275390
|
+
return;
|
|
275391
|
+
}
|
|
275392
|
+
const key = `${exchangeId}|${accountLabel}|${symbol}`;
|
|
275393
|
+
const since = this.#cursors.get(key) ?? Date.now() - this.#config.lookbackMs;
|
|
275394
|
+
let trades;
|
|
275395
|
+
try {
|
|
275396
|
+
trades = await exchange.fetchMyTrades(symbol, since, this.#config.tradesLimit);
|
|
275397
|
+
} catch (error) {
|
|
275398
|
+
this.params.metrics?.recordCounter("cex_fill_poller_errors_total", 1, {
|
|
275399
|
+
exchange: exchangeId
|
|
275400
|
+
});
|
|
275401
|
+
log.warn("Fill archive poll failed", {
|
|
275402
|
+
exchange: exchangeId,
|
|
275403
|
+
account: accountLabel,
|
|
275404
|
+
symbol,
|
|
275405
|
+
error
|
|
275406
|
+
});
|
|
275407
|
+
return;
|
|
275408
|
+
}
|
|
275409
|
+
if (!Array.isArray(trades) || trades.length === 0) {
|
|
275410
|
+
return;
|
|
275411
|
+
}
|
|
275412
|
+
trades.forEach((trade, fillIndex) => {
|
|
275413
|
+
const tags = buildCommonArchiveTags({
|
|
275414
|
+
deploymentId: this.params.archiver.getDeploymentId(),
|
|
275415
|
+
accountSelector: accountLabel,
|
|
275416
|
+
exchange: exchangeId,
|
|
275417
|
+
symbol
|
|
275418
|
+
});
|
|
275419
|
+
this.params.archiver.enqueue(buildFillEventArchiveRow({
|
|
275420
|
+
tags,
|
|
275421
|
+
fill: { ...normalizeCcxtTradeForArchive(trade), fillIndex }
|
|
275422
|
+
}));
|
|
275423
|
+
});
|
|
275424
|
+
this.params.metrics?.recordCounter("cex_fill_poller_trades_archived_total", trades.length, { exchange: exchangeId });
|
|
275425
|
+
this.#cursors.set(key, nextFillCursor(trades, since));
|
|
275426
|
+
}
|
|
275427
|
+
}
|
|
275428
|
+
|
|
275429
|
+
// src/helpers/order-activity-tracker.ts
|
|
275430
|
+
var DEFAULT_MAX_AGE_MS = 6 * 60 * 60 * 1000;
|
|
275431
|
+
|
|
275432
|
+
class OrderActivityTracker {
|
|
275433
|
+
#entries = new Map;
|
|
275434
|
+
#maxAgeMs;
|
|
275435
|
+
constructor(options) {
|
|
275436
|
+
this.#maxAgeMs = options?.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
275437
|
+
}
|
|
275438
|
+
record(exchangeId, accountLabel, symbol, now3 = Date.now()) {
|
|
275439
|
+
const exchange = exchangeId.trim().toLowerCase();
|
|
275440
|
+
const trimmedSymbol = symbol.trim();
|
|
275441
|
+
if (!exchange || !accountLabel.trim() || !trimmedSymbol) {
|
|
275442
|
+
return;
|
|
275443
|
+
}
|
|
275444
|
+
const key = `${exchange}|${accountLabel}|${trimmedSymbol}`;
|
|
275445
|
+
this.#entries.set(key, {
|
|
275446
|
+
exchangeId: exchange,
|
|
275447
|
+
accountLabel,
|
|
275448
|
+
symbol: trimmedSymbol,
|
|
275449
|
+
lastActivityAt: now3
|
|
275450
|
+
});
|
|
275451
|
+
}
|
|
275452
|
+
list(now3 = Date.now()) {
|
|
275453
|
+
const active = [];
|
|
275454
|
+
for (const [key, entry] of this.#entries) {
|
|
275455
|
+
if (now3 - entry.lastActivityAt > this.#maxAgeMs) {
|
|
275456
|
+
this.#entries.delete(key);
|
|
275457
|
+
continue;
|
|
275458
|
+
}
|
|
275459
|
+
active.push(entry);
|
|
275460
|
+
}
|
|
275461
|
+
return active;
|
|
275462
|
+
}
|
|
275463
|
+
}
|
|
275464
|
+
|
|
275162
275465
|
// src/helpers/otel.ts
|
|
275163
275466
|
var import_api14 = __toESM(require_src2(), 1);
|
|
275164
275467
|
|
|
@@ -292907,7 +293210,13 @@ function rejectWithGrpcError(ctx, error48, options) {
|
|
|
292907
293210
|
|
|
292908
293211
|
// src/handlers/execute-action/deposit.ts
|
|
292909
293212
|
async function handleDeposit(ctx) {
|
|
292910
|
-
const {
|
|
293213
|
+
const {
|
|
293214
|
+
normalizedCex,
|
|
293215
|
+
symbol: symbol2,
|
|
293216
|
+
selectedBrokerAccount,
|
|
293217
|
+
broker,
|
|
293218
|
+
brokerArchiver
|
|
293219
|
+
} = ctx;
|
|
292911
293220
|
if (!symbol2) {
|
|
292912
293221
|
return ctx.wrappedCallback({
|
|
292913
293222
|
code: grpc3.status.INVALID_ARGUMENT,
|
|
@@ -292970,6 +293279,32 @@ async function handleDeposit(ctx) {
|
|
|
292970
293279
|
}, null);
|
|
292971
293280
|
}
|
|
292972
293281
|
const status4 = normalizeDepositStatus(depositField(deposit, ["status", "state"]));
|
|
293282
|
+
const depositTxid = String(depositField(deposit, ["txid", "txId", "tx_hash", "txHash"]) ?? value.transactionHash);
|
|
293283
|
+
const creditedAt = depositField(deposit, [
|
|
293284
|
+
"creditedAt",
|
|
293285
|
+
"credited_at",
|
|
293286
|
+
"updated",
|
|
293287
|
+
"updatedAt",
|
|
293288
|
+
"timestamp",
|
|
293289
|
+
"datetime"
|
|
293290
|
+
]);
|
|
293291
|
+
archiveTransferEventInBackground(brokerArchiver, {
|
|
293292
|
+
exchange: normalizedCex,
|
|
293293
|
+
accountSelector: selectedBrokerAccount?.label,
|
|
293294
|
+
assetSymbol: symbol2,
|
|
293295
|
+
transfer: {
|
|
293296
|
+
eventKind: "deposit",
|
|
293297
|
+
lifecycleAction: "observe_deposit",
|
|
293298
|
+
status: status4,
|
|
293299
|
+
amount: observedAmount !== undefined ? String(observedAmount) : undefined,
|
|
293300
|
+
address: String(observedAddress ?? value.recipientAddress),
|
|
293301
|
+
network: depositNetwork?.exchangeNetworkId,
|
|
293302
|
+
externalId: depositTxid,
|
|
293303
|
+
txid: depositTxid,
|
|
293304
|
+
exchangeTimestamp: typeof creditedAt === "string" ? creditedAt : undefined,
|
|
293305
|
+
payload: deposit
|
|
293306
|
+
}
|
|
293307
|
+
});
|
|
292973
293308
|
log.info(`Amount ${value.amount} at ${value.transactionHash} . Paid to ${value.recipientAddress}`);
|
|
292974
293309
|
return ctx.wrappedCallback(null, {
|
|
292975
293310
|
proof: ctx.verity.proof,
|
|
@@ -293383,7 +293718,8 @@ async function handleInternalTransfer(ctx) {
|
|
|
293383
293718
|
symbol: symbol2,
|
|
293384
293719
|
verity,
|
|
293385
293720
|
useVerity,
|
|
293386
|
-
verityProverUrl
|
|
293721
|
+
verityProverUrl,
|
|
293722
|
+
brokerArchiver
|
|
293387
293723
|
} = ctx;
|
|
293388
293724
|
if (!symbol2) {
|
|
293389
293725
|
return ctx.wrappedCallback({
|
|
@@ -293431,6 +293767,21 @@ async function handleInternalTransfer(ctx) {
|
|
|
293431
293767
|
}), verityHttpClientOverridePredicate);
|
|
293432
293768
|
}
|
|
293433
293769
|
const result = await transferBinanceInternal(sourceAccount, destAccount, symbol2, transferPayload.amount);
|
|
293770
|
+
const normalized = normalizeCcxtTransactionForArchive(result);
|
|
293771
|
+
archiveTransferEventInBackground(brokerArchiver, {
|
|
293772
|
+
exchange: normalizedCex,
|
|
293773
|
+
accountSelector: fromSelector,
|
|
293774
|
+
assetSymbol: symbol2,
|
|
293775
|
+
transfer: {
|
|
293776
|
+
eventKind: "internal_transfer",
|
|
293777
|
+
lifecycleAction: "submit_internal_transfer",
|
|
293778
|
+
status: normalized.status ?? "ok",
|
|
293779
|
+
amount: normalized.amount ?? String(transferPayload.amount),
|
|
293780
|
+
network: "internal",
|
|
293781
|
+
externalId: normalized.externalId,
|
|
293782
|
+
payload: { from: fromSelector, to: toSelector, result }
|
|
293783
|
+
}
|
|
293784
|
+
});
|
|
293434
293785
|
ctx.wrappedCallback(null, {
|
|
293435
293786
|
proof: verity.proof,
|
|
293436
293787
|
result: JSON.stringify(result)
|
|
@@ -293478,7 +293829,8 @@ async function handleCreateOrder(ctx) {
|
|
|
293478
293829
|
useVerity,
|
|
293479
293830
|
verityProverUrl,
|
|
293480
293831
|
otelMetrics,
|
|
293481
|
-
brokerArchiver
|
|
293832
|
+
brokerArchiver,
|
|
293833
|
+
orderActivityTracker
|
|
293482
293834
|
} = ctx;
|
|
293483
293835
|
const verityProof = verity.proof;
|
|
293484
293836
|
const orderValue = parsePayloadForAction(ctx, CreateOrderPayloadSchema);
|
|
@@ -293504,6 +293856,9 @@ async function handleCreateOrder(ctx) {
|
|
|
293504
293856
|
side: resolution.side,
|
|
293505
293857
|
requestedQuantity: resolution.amountBase ?? orderValue.amount
|
|
293506
293858
|
};
|
|
293859
|
+
if (selectedBrokerAccount?.label) {
|
|
293860
|
+
orderActivityTracker?.record(cex3, selectedBrokerAccount.label, resolution.symbol);
|
|
293861
|
+
}
|
|
293507
293862
|
const telemetryIds = extractOrderTelemetryIds(orderValue.params);
|
|
293508
293863
|
const submissionTimestamp = new Date().toISOString();
|
|
293509
293864
|
const marketMetadataHash = await captureMarketMetadataSnapshot(brokerArchiver, broker, {
|
|
@@ -293568,7 +293923,8 @@ async function handleGetOrderDetails(ctx) {
|
|
|
293568
293923
|
useVerity,
|
|
293569
293924
|
verityProverUrl,
|
|
293570
293925
|
otelMetrics,
|
|
293571
|
-
brokerArchiver
|
|
293926
|
+
brokerArchiver,
|
|
293927
|
+
orderActivityTracker
|
|
293572
293928
|
} = ctx;
|
|
293573
293929
|
const verityProof = verity.proof;
|
|
293574
293930
|
const getOrderValue = parsePayloadForAction(ctx, GetOrderDetailsPayloadSchema);
|
|
@@ -293582,6 +293938,9 @@ async function handleGetOrderDetails(ctx) {
|
|
|
293582
293938
|
}, null);
|
|
293583
293939
|
}
|
|
293584
293940
|
const orderDetails = await broker.fetchOrder(getOrderValue.orderId, symbol2, { ...getOrderValue.params });
|
|
293941
|
+
if (selectedBrokerAccount?.label && symbol2) {
|
|
293942
|
+
orderActivityTracker?.record(cex3, selectedBrokerAccount.label, symbol2);
|
|
293943
|
+
}
|
|
293585
293944
|
const getOrderContext = {
|
|
293586
293945
|
action: "GetOrderDetails",
|
|
293587
293946
|
cex: cex3,
|
|
@@ -293637,7 +293996,8 @@ async function handleCancelOrder(ctx) {
|
|
|
293637
293996
|
useVerity,
|
|
293638
293997
|
verityProverUrl,
|
|
293639
293998
|
otelMetrics,
|
|
293640
|
-
brokerArchiver
|
|
293999
|
+
brokerArchiver,
|
|
294000
|
+
orderActivityTracker
|
|
293641
294001
|
} = ctx;
|
|
293642
294002
|
const verityProof = verity.proof;
|
|
293643
294003
|
const cancelOrderValue = parsePayloadForAction(ctx, CancelOrderPayloadSchema);
|
|
@@ -293658,6 +294018,9 @@ async function handleCancelOrder(ctx) {
|
|
|
293658
294018
|
...extractOrderTelemetryIds(cancelOrderValue.params)
|
|
293659
294019
|
};
|
|
293660
294020
|
const cancelledOrder = await broker.cancelOrder(cancelOrderValue.orderId, symbol2, cancelOrderValue.params ?? {});
|
|
294021
|
+
if (selectedBrokerAccount?.label && symbol2) {
|
|
294022
|
+
orderActivityTracker?.record(cex3, selectedBrokerAccount.label, symbol2);
|
|
294023
|
+
}
|
|
293661
294024
|
emitOrderExecutionTelemetryInBackground(otelMetrics, cancelOrderContext, cancelledOrder);
|
|
293662
294025
|
archiveOrderExecutionInBackground(brokerArchiver, cancelOrderContext, cancelledOrder);
|
|
293663
294026
|
ctx.wrappedCallback(null, {
|
|
@@ -294288,7 +294651,8 @@ async function handleWithdraw(ctx) {
|
|
|
294288
294651
|
applyVerityToBroker,
|
|
294289
294652
|
useVerity,
|
|
294290
294653
|
verityProverUrl,
|
|
294291
|
-
otelMetrics
|
|
294654
|
+
otelMetrics,
|
|
294655
|
+
brokerArchiver
|
|
294292
294656
|
} = ctx;
|
|
294293
294657
|
const verityProof = verity.proof;
|
|
294294
294658
|
if (!symbol2) {
|
|
@@ -294337,6 +294701,26 @@ async function handleWithdraw(ctx) {
|
|
|
294337
294701
|
network: withdrawNetwork.exchangeNetworkId
|
|
294338
294702
|
});
|
|
294339
294703
|
log.info(`Withdraw Result: ${JSON.stringify(transaction)}`);
|
|
294704
|
+
const normalized = normalizeCcxtTransactionForArchive(transaction);
|
|
294705
|
+
archiveTransferEventInBackground(brokerArchiver, {
|
|
294706
|
+
exchange: cex3,
|
|
294707
|
+
accountSelector: selectedBrokerAccount?.label,
|
|
294708
|
+
assetSymbol: normalized.assetSymbol ?? symbol2,
|
|
294709
|
+
transfer: {
|
|
294710
|
+
eventKind: "withdrawal",
|
|
294711
|
+
lifecycleAction: "submit_withdrawal",
|
|
294712
|
+
status: normalized.status,
|
|
294713
|
+
amount: normalized.amount ?? String(transferValue.amount),
|
|
294714
|
+
address: normalized.address ?? transferValue.recipientAddress,
|
|
294715
|
+
network: normalized.network ?? withdrawNetwork.exchangeNetworkId,
|
|
294716
|
+
externalId: normalized.externalId,
|
|
294717
|
+
txid: normalized.txid,
|
|
294718
|
+
feeAmount: normalized.feeAmount,
|
|
294719
|
+
feeCurrency: normalized.feeCurrency,
|
|
294720
|
+
exchangeTimestamp: normalized.exchangeTimestamp,
|
|
294721
|
+
payload: transaction
|
|
294722
|
+
}
|
|
294723
|
+
});
|
|
294340
294724
|
ctx.wrappedCallback(null, {
|
|
294341
294725
|
proof: ctx.verity.proof,
|
|
294342
294726
|
result: JSON.stringify({
|
|
@@ -294348,6 +294732,21 @@ async function handleWithdraw(ctx) {
|
|
|
294348
294732
|
});
|
|
294349
294733
|
} catch (error48) {
|
|
294350
294734
|
safeLogError("Withdraw failed", error48);
|
|
294735
|
+
archiveTransferEventInBackground(brokerArchiver, {
|
|
294736
|
+
exchange: cex3,
|
|
294737
|
+
accountSelector: selectedBrokerAccount?.label,
|
|
294738
|
+
assetSymbol: symbol2,
|
|
294739
|
+
transfer: {
|
|
294740
|
+
eventKind: "withdrawal",
|
|
294741
|
+
lifecycleAction: "submit_withdrawal",
|
|
294742
|
+
status: "failed",
|
|
294743
|
+
amount: String(transferValue.amount),
|
|
294744
|
+
address: transferValue.recipientAddress,
|
|
294745
|
+
network: withdrawNetwork.exchangeNetworkId,
|
|
294746
|
+
errorSummary: getErrorMessage(error48),
|
|
294747
|
+
payload: { recipientAddress: transferValue.recipientAddress }
|
|
294748
|
+
}
|
|
294749
|
+
});
|
|
294351
294750
|
const code = mapCcxtErrorToGrpcStatus(error48) ?? grpc10.status.INTERNAL;
|
|
294352
294751
|
ctx.wrappedCallback({
|
|
294353
294752
|
code,
|
|
@@ -294395,7 +294794,8 @@ function createExecuteActionHandler(deps) {
|
|
|
294395
294794
|
useVerity,
|
|
294396
294795
|
verityProverUrl,
|
|
294397
294796
|
otelMetrics,
|
|
294398
|
-
brokerArchiver
|
|
294797
|
+
brokerArchiver,
|
|
294798
|
+
orderActivityTracker
|
|
294399
294799
|
} = deps;
|
|
294400
294800
|
return async (call, callback) => {
|
|
294401
294801
|
const startTime = Date.now();
|
|
@@ -294474,7 +294874,8 @@ function createExecuteActionHandler(deps) {
|
|
|
294474
294874
|
useVerity,
|
|
294475
294875
|
verityProverUrl,
|
|
294476
294876
|
otelMetrics,
|
|
294477
|
-
brokerArchiver
|
|
294877
|
+
brokerArchiver,
|
|
294878
|
+
orderActivityTracker
|
|
294478
294879
|
};
|
|
294479
294880
|
if (action === Action.Call) {
|
|
294480
294881
|
const handled = await handleOrderBookCall(preludeCtx);
|
|
@@ -296064,7 +296465,7 @@ var CEX_BROKER_PACKAGE_DEFINITION = protoLoader.fromJSON(node_descriptor_default
|
|
|
296064
296465
|
// src/server.ts
|
|
296065
296466
|
var grpcObj = grpc14.loadPackageDefinition(CEX_BROKER_PACKAGE_DEFINITION);
|
|
296066
296467
|
var cexNode = grpcObj.cex_broker;
|
|
296067
|
-
function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, otelMetrics, brokerArchiver) {
|
|
296468
|
+
function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, otelMetrics, brokerArchiver, orderActivityTracker) {
|
|
296068
296469
|
const server = new grpc14.Server;
|
|
296069
296470
|
server.addService(cexNode.cex_service.service, {
|
|
296070
296471
|
ExecuteAction: createExecuteActionHandler({
|
|
@@ -296074,7 +296475,8 @@ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, ot
|
|
|
296074
296475
|
useVerity,
|
|
296075
296476
|
verityProverUrl,
|
|
296076
296477
|
otelMetrics,
|
|
296077
|
-
brokerArchiver
|
|
296478
|
+
brokerArchiver,
|
|
296479
|
+
orderActivityTracker
|
|
296078
296480
|
}),
|
|
296079
296481
|
Subscribe: createSubscribeHandler({
|
|
296080
296482
|
brokers,
|
|
@@ -296219,6 +296621,8 @@ class CEXBroker {
|
|
|
296219
296621
|
otelLogs;
|
|
296220
296622
|
brokerArchiver;
|
|
296221
296623
|
depositReconciler;
|
|
296624
|
+
orderActivityTracker = new OrderActivityTracker;
|
|
296625
|
+
fillArchivePoller;
|
|
296222
296626
|
loadEnvConfig() {
|
|
296223
296627
|
log.info("\uD83D\uDD27 Loading CEX_BROKER_ environment variables:");
|
|
296224
296628
|
const configMap = {};
|
|
@@ -296359,6 +296763,10 @@ class CEXBroker {
|
|
|
296359
296763
|
this.depositReconciler.stop();
|
|
296360
296764
|
this.depositReconciler = undefined;
|
|
296361
296765
|
}
|
|
296766
|
+
if (this.fillArchivePoller) {
|
|
296767
|
+
this.fillArchivePoller.stop();
|
|
296768
|
+
this.fillArchivePoller = undefined;
|
|
296769
|
+
}
|
|
296362
296770
|
if (this.server) {
|
|
296363
296771
|
await this.server.forceShutdown();
|
|
296364
296772
|
}
|
|
@@ -296380,11 +296788,15 @@ class CEXBroker {
|
|
|
296380
296788
|
this.depositReconciler.stop();
|
|
296381
296789
|
this.depositReconciler = undefined;
|
|
296382
296790
|
}
|
|
296791
|
+
if (this.fillArchivePoller) {
|
|
296792
|
+
this.fillArchivePoller.stop();
|
|
296793
|
+
this.fillArchivePoller = undefined;
|
|
296794
|
+
}
|
|
296383
296795
|
log.info(`Running CEXBroker at ${new Date().toISOString()}`);
|
|
296384
296796
|
if (this.otelMetrics?.isOtelEnabled()) {
|
|
296385
296797
|
await this.otelMetrics.initialize();
|
|
296386
296798
|
}
|
|
296387
|
-
this.server = getServer(this.policy, this.brokers, this.whitelistIps, this.useVerity, this.#verityProverUrl, this.otelMetrics, this.brokerArchiver);
|
|
296799
|
+
this.server = getServer(this.policy, this.brokers, this.whitelistIps, this.useVerity, this.#verityProverUrl, this.otelMetrics, this.brokerArchiver, this.orderActivityTracker);
|
|
296388
296800
|
this.server.bindAsync(`0.0.0.0:${this.port}`, grpc15.ServerCredentials.createInsecure(), (err2, port) => {
|
|
296389
296801
|
if (err2) {
|
|
296390
296802
|
log.error(err2);
|
|
@@ -296399,6 +296811,15 @@ class CEXBroker {
|
|
|
296399
296811
|
metrics: this.otelMetrics
|
|
296400
296812
|
});
|
|
296401
296813
|
this.depositReconciler.start();
|
|
296814
|
+
if (this.brokerArchiver?.isEnabled()) {
|
|
296815
|
+
this.fillArchivePoller = new FillArchivePoller({
|
|
296816
|
+
brokers: this.brokers,
|
|
296817
|
+
archiver: this.brokerArchiver,
|
|
296818
|
+
tracker: this.orderActivityTracker,
|
|
296819
|
+
metrics: this.otelMetrics
|
|
296820
|
+
});
|
|
296821
|
+
this.fillArchivePoller.start();
|
|
296822
|
+
}
|
|
296402
296823
|
return this;
|
|
296403
296824
|
}
|
|
296404
296825
|
}
|
|
@@ -296406,4 +296827,4 @@ export {
|
|
|
296406
296827
|
CEXBroker as default
|
|
296407
296828
|
};
|
|
296408
296829
|
|
|
296409
|
-
//# debugId=
|
|
296830
|
+
//# debugId=72B06323144A22CC64756E2164756E21
|