@usherlabs/cex-broker 0.2.17 → 0.2.18
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 +54 -29
- package/dist/helpers/travel-rule-deposit-reconciler.d.ts +7 -0
- package/dist/index.js +59 -34
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/commands/cli.js
CHANGED
|
@@ -313971,6 +313971,10 @@ function authenticateRequest(call, whitelistIps) {
|
|
|
313971
313971
|
}
|
|
313972
313972
|
return true;
|
|
313973
313973
|
}
|
|
313974
|
+
// src/helpers/travel-rule-deposit-reconciler.ts
|
|
313975
|
+
import { request as httpRequest } from "node:http";
|
|
313976
|
+
import { request as httpsRequest } from "node:https";
|
|
313977
|
+
|
|
313974
313978
|
// src/helpers/deposit.ts
|
|
313975
313979
|
function depositField(deposit, fields) {
|
|
313976
313980
|
for (const field of fields) {
|
|
@@ -314051,36 +314055,54 @@ function parseLocalEntityDeposit(raw) {
|
|
|
314051
314055
|
};
|
|
314052
314056
|
}
|
|
314053
314057
|
var EVM_TX_HASH = /^0x[0-9a-fA-F]{64}$/;
|
|
314054
|
-
|
|
314058
|
+
function resolveOnChainSender(rpcUrl, txHash, timeoutMs = 1e4) {
|
|
314055
314059
|
if (!EVM_TX_HASH.test(txHash))
|
|
314056
|
-
return null;
|
|
314057
|
-
const
|
|
314058
|
-
|
|
314059
|
-
|
|
314060
|
-
|
|
314061
|
-
|
|
314060
|
+
return Promise.resolve(null);
|
|
314061
|
+
const body = JSON.stringify({
|
|
314062
|
+
jsonrpc: "2.0",
|
|
314063
|
+
id: 1,
|
|
314064
|
+
method: "eth_getTransactionByHash",
|
|
314065
|
+
params: [txHash]
|
|
314066
|
+
});
|
|
314067
|
+
const url2 = new URL(rpcUrl);
|
|
314068
|
+
const doRequest = url2.protocol === "http:" ? httpRequest : httpsRequest;
|
|
314069
|
+
return new Promise((resolve, reject) => {
|
|
314070
|
+
const req = doRequest(url2, {
|
|
314062
314071
|
method: "POST",
|
|
314063
|
-
headers: {
|
|
314064
|
-
|
|
314065
|
-
|
|
314066
|
-
|
|
314067
|
-
|
|
314068
|
-
|
|
314069
|
-
|
|
314070
|
-
|
|
314072
|
+
headers: {
|
|
314073
|
+
"content-type": "application/json",
|
|
314074
|
+
"content-length": Buffer.byteLength(body)
|
|
314075
|
+
},
|
|
314076
|
+
timeout: timeoutMs
|
|
314077
|
+
}, (res) => {
|
|
314078
|
+
const chunks = [];
|
|
314079
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
314080
|
+
res.on("end", () => {
|
|
314081
|
+
const status = res.statusCode ?? 0;
|
|
314082
|
+
if (status < 200 || status >= 300) {
|
|
314083
|
+
reject(new Error(`travel_rule_rpc_http_${status}`));
|
|
314084
|
+
return;
|
|
314085
|
+
}
|
|
314086
|
+
try {
|
|
314087
|
+
const json3 = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
314088
|
+
if (json3.error) {
|
|
314089
|
+
reject(new Error(`travel_rule_rpc_error: ${JSON.stringify(json3.error)}`));
|
|
314090
|
+
return;
|
|
314091
|
+
}
|
|
314092
|
+
const from = json3.result?.from;
|
|
314093
|
+
resolve(typeof from === "string" && from.length > 0 ? from.toLowerCase() : null);
|
|
314094
|
+
} catch (parseError) {
|
|
314095
|
+
reject(new Error(`travel_rule_rpc_parse_error: ${String(parseError)}`));
|
|
314096
|
+
}
|
|
314097
|
+
});
|
|
314071
314098
|
});
|
|
314072
|
-
|
|
314073
|
-
|
|
314074
|
-
|
|
314075
|
-
|
|
314076
|
-
|
|
314077
|
-
|
|
314078
|
-
|
|
314079
|
-
if (json3.error) {
|
|
314080
|
-
throw new Error(`travel_rule_rpc_error: ${JSON.stringify(json3.error)}`);
|
|
314081
|
-
}
|
|
314082
|
-
const from = json3.result?.from;
|
|
314083
|
-
return typeof from === "string" && from.length > 0 ? from.toLowerCase() : null;
|
|
314099
|
+
req.on("error", reject);
|
|
314100
|
+
req.on("timeout", () => {
|
|
314101
|
+
req.destroy(new Error("travel_rule_rpc_timeout"));
|
|
314102
|
+
});
|
|
314103
|
+
req.write(body);
|
|
314104
|
+
req.end();
|
|
314105
|
+
});
|
|
314084
314106
|
}
|
|
314085
314107
|
function errorText(error) {
|
|
314086
314108
|
if (error instanceof Error)
|
|
@@ -314182,17 +314204,19 @@ async function reconcileAccountOnce(deps) {
|
|
|
314182
314204
|
if (now3 < state.rateLimitedUntil)
|
|
314183
314205
|
break;
|
|
314184
314206
|
let sender = null;
|
|
314207
|
+
let resolveError;
|
|
314185
314208
|
try {
|
|
314186
314209
|
sender = await deps.resolveSender(deposit.network, deposit.txId);
|
|
314187
314210
|
} catch (error) {
|
|
314188
314211
|
sender = null;
|
|
314212
|
+
resolveError = errorText(error);
|
|
314189
314213
|
if (isRateLimitError(error)) {
|
|
314190
314214
|
state.rateLimitedUntil = now3 + deps.rateLimitCooldownMs;
|
|
314191
314215
|
}
|
|
314192
314216
|
}
|
|
314193
314217
|
if (!sender) {
|
|
314194
314218
|
state.backoffUntil.set(deposit.tranId, now3 + deps.failureBackoffMs);
|
|
314195
|
-
outcomes.push({ kind: "unproven-origin", deposit });
|
|
314219
|
+
outcomes.push({ kind: "unproven-origin", deposit, error: resolveError });
|
|
314196
314220
|
continue;
|
|
314197
314221
|
}
|
|
314198
314222
|
const questionnaire = deps.resolveQuestionnaire(deps.depositConfig, sender);
|
|
@@ -314448,7 +314472,8 @@ class TravelRuleDepositReconciler {
|
|
|
314448
314472
|
tranId: outcome.deposit.tranId,
|
|
314449
314473
|
coin: outcome.deposit.coin,
|
|
314450
314474
|
network: outcome.deposit.network,
|
|
314451
|
-
txId: outcome.deposit.txId
|
|
314475
|
+
txId: outcome.deposit.txId,
|
|
314476
|
+
rpcError: outcome.error ?? null
|
|
314452
314477
|
});
|
|
314453
314478
|
metrics?.recordCounter("travel_rule_deposit_anomalies_total", 1, {
|
|
314454
314479
|
...base2,
|
|
@@ -46,6 +46,12 @@ export declare function parseLocalEntityDeposit(raw: Record<string, unknown>): L
|
|
|
46
46
|
* churn (owner wallet → Binance via a direct ERC20 transfer) that equals the
|
|
47
47
|
* token originator. A transfer routed through a contract could differ; hardening
|
|
48
48
|
* to the ERC20 Transfer event's `from` is possible later if that case arises.
|
|
49
|
+
*
|
|
50
|
+
* Uses `node:https` rather than the global `fetch`: inside the Gramine SGX
|
|
51
|
+
* enclave undici (which backs global fetch) fails to establish outbound
|
|
52
|
+
* connections — the same failure mode as the enclave's dead Binance user-data
|
|
53
|
+
* WebSocket — while the ccxt HTTP path (node http/https) works. Using node's
|
|
54
|
+
* request keeps this on the transport that is proven to work in the enclave.
|
|
49
55
|
*/
|
|
50
56
|
export declare function resolveOnChainSender(rpcUrl: string, txHash: string, timeoutMs?: number): Promise<string | null>;
|
|
51
57
|
/** Binance rate-limit signals (-1003 / HTTP 429 / DDoS guard). */
|
|
@@ -78,6 +84,7 @@ export type ReconcileOutcome = {
|
|
|
78
84
|
} | {
|
|
79
85
|
kind: "unproven-origin";
|
|
80
86
|
deposit: LocalEntityDeposit;
|
|
87
|
+
error?: string;
|
|
81
88
|
} | {
|
|
82
89
|
kind: "entity-drift";
|
|
83
90
|
deposit: LocalEntityDeposit;
|
package/dist/index.js
CHANGED
|
@@ -273224,6 +273224,10 @@ function authenticateRequest(call, whitelistIps) {
|
|
|
273224
273224
|
}
|
|
273225
273225
|
return true;
|
|
273226
273226
|
}
|
|
273227
|
+
// src/helpers/travel-rule-deposit-reconciler.ts
|
|
273228
|
+
import { request as httpRequest } from "http";
|
|
273229
|
+
import { request as httpsRequest } from "https";
|
|
273230
|
+
|
|
273227
273231
|
// src/helpers/deposit.ts
|
|
273228
273232
|
function depositField(deposit, fields) {
|
|
273229
273233
|
for (const field of fields) {
|
|
@@ -273304,36 +273308,54 @@ function parseLocalEntityDeposit(raw) {
|
|
|
273304
273308
|
};
|
|
273305
273309
|
}
|
|
273306
273310
|
var EVM_TX_HASH = /^0x[0-9a-fA-F]{64}$/;
|
|
273307
|
-
|
|
273311
|
+
function resolveOnChainSender(rpcUrl, txHash, timeoutMs = 1e4) {
|
|
273308
273312
|
if (!EVM_TX_HASH.test(txHash))
|
|
273309
|
-
return null;
|
|
273310
|
-
const
|
|
273311
|
-
|
|
273312
|
-
|
|
273313
|
-
|
|
273314
|
-
|
|
273313
|
+
return Promise.resolve(null);
|
|
273314
|
+
const body = JSON.stringify({
|
|
273315
|
+
jsonrpc: "2.0",
|
|
273316
|
+
id: 1,
|
|
273317
|
+
method: "eth_getTransactionByHash",
|
|
273318
|
+
params: [txHash]
|
|
273319
|
+
});
|
|
273320
|
+
const url2 = new URL(rpcUrl);
|
|
273321
|
+
const doRequest = url2.protocol === "http:" ? httpRequest : httpsRequest;
|
|
273322
|
+
return new Promise((resolve, reject) => {
|
|
273323
|
+
const req = doRequest(url2, {
|
|
273315
273324
|
method: "POST",
|
|
273316
|
-
headers: {
|
|
273317
|
-
|
|
273318
|
-
|
|
273319
|
-
|
|
273320
|
-
|
|
273321
|
-
|
|
273322
|
-
|
|
273323
|
-
|
|
273325
|
+
headers: {
|
|
273326
|
+
"content-type": "application/json",
|
|
273327
|
+
"content-length": Buffer.byteLength(body)
|
|
273328
|
+
},
|
|
273329
|
+
timeout: timeoutMs
|
|
273330
|
+
}, (res) => {
|
|
273331
|
+
const chunks = [];
|
|
273332
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
273333
|
+
res.on("end", () => {
|
|
273334
|
+
const status = res.statusCode ?? 0;
|
|
273335
|
+
if (status < 200 || status >= 300) {
|
|
273336
|
+
reject(new Error(`travel_rule_rpc_http_${status}`));
|
|
273337
|
+
return;
|
|
273338
|
+
}
|
|
273339
|
+
try {
|
|
273340
|
+
const json3 = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
273341
|
+
if (json3.error) {
|
|
273342
|
+
reject(new Error(`travel_rule_rpc_error: ${JSON.stringify(json3.error)}`));
|
|
273343
|
+
return;
|
|
273344
|
+
}
|
|
273345
|
+
const from = json3.result?.from;
|
|
273346
|
+
resolve(typeof from === "string" && from.length > 0 ? from.toLowerCase() : null);
|
|
273347
|
+
} catch (parseError) {
|
|
273348
|
+
reject(new Error(`travel_rule_rpc_parse_error: ${String(parseError)}`));
|
|
273349
|
+
}
|
|
273350
|
+
});
|
|
273324
273351
|
});
|
|
273325
|
-
|
|
273326
|
-
|
|
273327
|
-
|
|
273328
|
-
|
|
273329
|
-
|
|
273330
|
-
|
|
273331
|
-
|
|
273332
|
-
if (json3.error) {
|
|
273333
|
-
throw new Error(`travel_rule_rpc_error: ${JSON.stringify(json3.error)}`);
|
|
273334
|
-
}
|
|
273335
|
-
const from = json3.result?.from;
|
|
273336
|
-
return typeof from === "string" && from.length > 0 ? from.toLowerCase() : null;
|
|
273352
|
+
req.on("error", reject);
|
|
273353
|
+
req.on("timeout", () => {
|
|
273354
|
+
req.destroy(new Error("travel_rule_rpc_timeout"));
|
|
273355
|
+
});
|
|
273356
|
+
req.write(body);
|
|
273357
|
+
req.end();
|
|
273358
|
+
});
|
|
273337
273359
|
}
|
|
273338
273360
|
function errorText(error) {
|
|
273339
273361
|
if (error instanceof Error)
|
|
@@ -273435,17 +273457,19 @@ async function reconcileAccountOnce(deps) {
|
|
|
273435
273457
|
if (now3 < state.rateLimitedUntil)
|
|
273436
273458
|
break;
|
|
273437
273459
|
let sender = null;
|
|
273460
|
+
let resolveError;
|
|
273438
273461
|
try {
|
|
273439
273462
|
sender = await deps.resolveSender(deposit.network, deposit.txId);
|
|
273440
273463
|
} catch (error) {
|
|
273441
273464
|
sender = null;
|
|
273465
|
+
resolveError = errorText(error);
|
|
273442
273466
|
if (isRateLimitError(error)) {
|
|
273443
273467
|
state.rateLimitedUntil = now3 + deps.rateLimitCooldownMs;
|
|
273444
273468
|
}
|
|
273445
273469
|
}
|
|
273446
273470
|
if (!sender) {
|
|
273447
273471
|
state.backoffUntil.set(deposit.tranId, now3 + deps.failureBackoffMs);
|
|
273448
|
-
outcomes.push({ kind: "unproven-origin", deposit });
|
|
273472
|
+
outcomes.push({ kind: "unproven-origin", deposit, error: resolveError });
|
|
273449
273473
|
continue;
|
|
273450
273474
|
}
|
|
273451
273475
|
const questionnaire = deps.resolveQuestionnaire(deps.depositConfig, sender);
|
|
@@ -273701,7 +273725,8 @@ class TravelRuleDepositReconciler {
|
|
|
273701
273725
|
tranId: outcome.deposit.tranId,
|
|
273702
273726
|
coin: outcome.deposit.coin,
|
|
273703
273727
|
network: outcome.deposit.network,
|
|
273704
|
-
txId: outcome.deposit.txId
|
|
273728
|
+
txId: outcome.deposit.txId,
|
|
273729
|
+
rpcError: outcome.error ?? null
|
|
273705
273730
|
});
|
|
273706
273731
|
metrics?.recordCounter("travel_rule_deposit_anomalies_total", 1, {
|
|
273707
273732
|
...base2,
|
|
@@ -277319,11 +277344,11 @@ var JsonMetricsSerializer = {
|
|
|
277319
277344
|
}
|
|
277320
277345
|
};
|
|
277321
277346
|
// node_modules/@opentelemetry/exporter-logs-otlp-http/build/esm/platform/node/OTLPLogExporter.js
|
|
277322
|
-
var
|
|
277347
|
+
var import_node_http2 = __toESM(require_index_node_http(), 1);
|
|
277323
277348
|
|
|
277324
277349
|
class OTLPLogExporter extends import_otlp_exporter_base.OTLPExporterBase {
|
|
277325
277350
|
constructor(config = {}) {
|
|
277326
|
-
super(
|
|
277351
|
+
super(import_node_http2.createOtlpHttpExportDelegate(import_node_http2.convertLegacyHttpOptions(config, "LOGS", "v1/logs", {
|
|
277327
277352
|
"Content-Type": "application/json"
|
|
277328
277353
|
}), JsonLogsSerializer));
|
|
277329
277354
|
}
|
|
@@ -277418,11 +277443,11 @@ class OTLPMetricExporterBase extends import_otlp_exporter_base2.OTLPExporterBase
|
|
|
277418
277443
|
}
|
|
277419
277444
|
|
|
277420
277445
|
// node_modules/@opentelemetry/exporter-metrics-otlp-http/build/esm/platform/node/OTLPMetricExporter.js
|
|
277421
|
-
var
|
|
277446
|
+
var import_node_http3 = __toESM(require_index_node_http(), 1);
|
|
277422
277447
|
|
|
277423
277448
|
class OTLPMetricExporter extends OTLPMetricExporterBase {
|
|
277424
277449
|
constructor(config) {
|
|
277425
|
-
super(
|
|
277450
|
+
super(import_node_http3.createOtlpHttpExportDelegate(import_node_http3.convertLegacyHttpOptions(config ?? {}, "METRICS", "v1/metrics", {
|
|
277426
277451
|
"Content-Type": "application/json"
|
|
277427
277452
|
}), JsonMetricsSerializer), config);
|
|
277428
277453
|
}
|
|
@@ -294953,4 +294978,4 @@ export {
|
|
|
294953
294978
|
CEXBroker as default
|
|
294954
294979
|
};
|
|
294955
294980
|
|
|
294956
|
-
//# debugId=
|
|
294981
|
+
//# debugId=75EE3175FC68761464756E2164756E21
|