@usherlabs/cex-broker 0.2.50 → 0.2.52
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/cex-canonical-orderbook-export.js +7750 -920
- package/dist/commands/cex-canonical-orderbook-export.js.map +41 -10
- package/dist/commands/cli.js +219 -24
- package/dist/commands/market-data-vendor-backfill.js +8297 -6460
- package/dist/commands/market-data-vendor-backfill.js.map +16 -15
- package/dist/helpers/canonical-orderbook-export/parquet-projection.d.ts +19 -0
- package/dist/helpers/deposit-archive-poller.d.ts +33 -0
- package/dist/helpers/market-data-archive/canonical-orderbook.d.ts +1 -1
- package/dist/helpers/market-data-preparation/conformance-fixtures.d.ts +114 -2
- package/dist/helpers/market-data-preparation/contracts.d.ts +1298 -18
- package/dist/helpers/market-data-preparation/required-clock-qualification.d.ts +43 -0
- package/dist/helpers/market-data-preparation/source-tape-dependencies.d.ts +19 -0
- package/dist/helpers/market-data-preparation/source-tape-operation.d.ts +109 -0
- package/dist/helpers/market-data-source-forensics.d.ts +400 -0
- package/dist/helpers/market-data-vendor-backfill/conformance-fixtures.d.ts +3 -5
- package/dist/helpers/market-data-vendor-backfill/contracts.d.ts +21 -56
- package/dist/helpers/market-data-vendor-backfill/core.d.ts +1 -0
- package/dist/helpers/market-data-vendor-backfill/cryptohftdata.d.ts +44 -5
- package/dist/helpers/market-data-vendor-backfill/manifests.d.ts +33 -1112
- package/dist/helpers/market-data-vendor-backfill/promotion.d.ts +1 -0
- package/dist/helpers/source-tape-sandbox.d.ts +82 -0
- package/dist/helpers/source-tape.d.ts +165 -0
- package/dist/index.js +220 -25
- package/dist/index.js.map +4 -4
- package/dist/market-data-preparation/fixtures/{conformance-v2.json → conformance-v3.json} +253 -56
- package/dist/market-data-preparation/policies/capability-policy.json +4 -4
- package/dist/market-data-preparation/policies/source-tape-capability-v1.json +35 -0
- package/dist/market-data-preparation/schema-manifest.json +30 -10
- package/dist/market-data-preparation/schemas/canonical-orderbook-export-request-v1.schema.json +5 -1
- package/dist/market-data-preparation/schemas/{canonical-orderbook-export-result-v1.schema.json → canonical-orderbook-export-result-v2.schema.json} +20 -6
- package/dist/market-data-preparation/schemas/order-book-depth-summary-parquet-projection-v1.schema.json +256 -0
- package/dist/market-data-preparation/schemas/order-book-levels-parquet-projection-v1.schema.json +220 -0
- package/dist/market-data-preparation/schemas/{preparation-product-pin-v1.schema.json → preparation-product-pin-v2.schema.json} +59 -9
- package/dist/market-data-preparation/schemas/promotion-receipt-v1.schema.json +5 -1
- package/dist/market-data-preparation/schemas/source-forensics-ledger-v1.schema.json +463 -0
- package/dist/market-data-preparation/schemas/source-qualification-record-v1.schema.json +394 -0
- package/dist/market-data-preparation.d.ts +7 -0
- package/dist/market-data-preparation.js +35448 -25240
- package/dist/market-data-preparation.js.map +118 -78
- package/dist/market-data-vendor-backfill.d.ts +7 -4
- package/dist/market-data-vendor-backfill.js +19338 -15503
- package/dist/market-data-vendor-backfill.js.map +65 -60
- package/package.json +1 -5
- package/dist/market-data-preparation/policies/capability-policy-v1.json +0 -28
- package/dist/market-data-preparation/policies/resource-policy-v1.json +0 -16
- package/dist/market-data-vendor-backfill/fixtures/conformance-v1.json +0 -448
- package/dist/market-data-vendor-backfill/policies/capability-policy-v2.json +0 -39
- package/dist/market-data-vendor-backfill/policies/capability-policy.json +0 -28
- package/dist/market-data-vendor-backfill/policies/resource-policy-v2.json +0 -16
- package/dist/market-data-vendor-backfill/policies/resource-policy.json +0 -16
- package/dist/market-data-vendor-backfill/schema-manifest.json +0 -31
- package/dist/market-data-vendor-backfill/schemas/archive-selection.schema.json +0 -224
- package/dist/market-data-vendor-backfill/schemas/promotion-receipt.schema.json +0 -171
- package/dist/market-data-vendor-backfill/schemas/request.schema.json +0 -166
- package/dist/market-data-vendor-backfill/schemas/required-clock.schema.json +0 -47
- package/dist/market-data-vendor-backfill/schemas/result.schema.json +0 -198
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type BackfillArchiveRow, type PromotionReceipt, type PromotionReceiptWire } from "./contracts";
|
|
2
2
|
export type StablePromotionReceipt = Omit<PromotionReceipt, "receiptId" | "verificationTimeMs">;
|
|
3
|
+
export declare function promotionReceiptMatchesCurrentPolicies(receipt: PromotionReceiptWire): boolean;
|
|
3
4
|
export declare function promotionReceiptId(receipt: StablePromotionReceipt): string;
|
|
4
5
|
type UnfinalizedPromotionReceiptWire = Omit<PromotionReceiptWire, "receipt_id" | "promotion_identity_sha256"> & Partial<Pick<PromotionReceiptWire, "receipt_id" | "promotion_identity_sha256">>;
|
|
5
6
|
export declare function finalizePromotionReceipt(receipt: UnfinalizedPromotionReceiptWire): PromotionReceiptWire;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { ArchiveQueryClient } from "./market-data-vendor-backfill/archive-reader";
|
|
2
|
+
import type { ArchiveSelectionWire, ForwarderBatch, MarketDataVendorBackfillRequest, ProviderObjectEvidence } from "./market-data-vendor-backfill/contracts";
|
|
3
|
+
import type { CandidateVerification } from "./market-data-vendor-backfill/core";
|
|
4
|
+
import { SOURCE_TAPE_CONSTRUCTION_MODE, SOURCE_TAPE_SANDBOX_TARGET, type SourceTapeArchiveSinkResult } from "./source-tape";
|
|
5
|
+
export declare function verifySourceTapeArchive(input: {
|
|
6
|
+
request: MarketDataVendorBackfillRequest;
|
|
7
|
+
sinkResult: SourceTapeArchiveSinkResult;
|
|
8
|
+
client: ArchiveQueryClient;
|
|
9
|
+
}): Promise<CandidateVerification>;
|
|
10
|
+
export type SourceTapeExportArtifact = {
|
|
11
|
+
file_name: string;
|
|
12
|
+
rows: number;
|
|
13
|
+
bytes: number;
|
|
14
|
+
sha256: string;
|
|
15
|
+
projection_schema_id: string;
|
|
16
|
+
projection_schema_sha256: string;
|
|
17
|
+
};
|
|
18
|
+
export type SourceTapeExportResult = {
|
|
19
|
+
promotionReceiptIds: string[];
|
|
20
|
+
levels: SourceTapeExportArtifact;
|
|
21
|
+
summary: SourceTapeExportArtifact;
|
|
22
|
+
};
|
|
23
|
+
export type SourceTapeSandboxEvidence = {
|
|
24
|
+
schema_id: "market-data-source-tape-sandbox-evidence/v1";
|
|
25
|
+
archive_target: typeof SOURCE_TAPE_SANDBOX_TARGET;
|
|
26
|
+
construction_mode: typeof SOURCE_TAPE_CONSTRUCTION_MODE;
|
|
27
|
+
normal_archive_path: true;
|
|
28
|
+
tape_capability: {
|
|
29
|
+
policy_id: string;
|
|
30
|
+
policy_sha256: string;
|
|
31
|
+
};
|
|
32
|
+
state_count: number;
|
|
33
|
+
promotion: {
|
|
34
|
+
receipt_id: string;
|
|
35
|
+
promotion_identity_sha256: string;
|
|
36
|
+
qualification_event_id: string;
|
|
37
|
+
};
|
|
38
|
+
selection: {
|
|
39
|
+
selection_sha256: string;
|
|
40
|
+
receipt_ids: string[];
|
|
41
|
+
};
|
|
42
|
+
export: {
|
|
43
|
+
levels: SourceTapeExportArtifact;
|
|
44
|
+
summary: SourceTapeExportArtifact;
|
|
45
|
+
};
|
|
46
|
+
projection_schema_pins: readonly {
|
|
47
|
+
schema_id: string;
|
|
48
|
+
schema_sha256: string;
|
|
49
|
+
}[];
|
|
50
|
+
};
|
|
51
|
+
export declare function promoteAndExportSourceTapeSandbox(input: {
|
|
52
|
+
request: MarketDataVendorBackfillRequest;
|
|
53
|
+
sinkResult: SourceTapeArchiveSinkResult;
|
|
54
|
+
verification: CandidateVerification;
|
|
55
|
+
datasetObjects: ProviderObjectEvidence[];
|
|
56
|
+
vendorSemanticDigest: string;
|
|
57
|
+
verifiedAt: string;
|
|
58
|
+
forwarder: {
|
|
59
|
+
submit(batch: ForwarderBatch): Promise<{
|
|
60
|
+
ok: boolean;
|
|
61
|
+
inserted: number;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
archive: {
|
|
65
|
+
resolveSelection(request: MarketDataVendorBackfillRequest): Promise<ArchiveSelectionWire>;
|
|
66
|
+
};
|
|
67
|
+
exporter: {
|
|
68
|
+
export(request: {
|
|
69
|
+
schema_id: "https://schemas.usher.so/cex-canonical-orderbook-export-request/v1";
|
|
70
|
+
request_id: string;
|
|
71
|
+
target: {
|
|
72
|
+
environment: string;
|
|
73
|
+
cluster: string;
|
|
74
|
+
};
|
|
75
|
+
selection: ArchiveSelectionWire;
|
|
76
|
+
depth: 100;
|
|
77
|
+
construction_mode: typeof SOURCE_TAPE_CONSTRUCTION_MODE;
|
|
78
|
+
canonical_schema_version: string;
|
|
79
|
+
checksum_algorithm: "sha256-canonical-json-v1";
|
|
80
|
+
}): Promise<SourceTapeExportResult>;
|
|
81
|
+
};
|
|
82
|
+
}): Promise<SourceTapeSandboxEvidence>;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { BackfillArchiveRow, ForwarderBatch } from "./market-data-vendor-backfill/contracts";
|
|
2
|
+
import { type PolicyNeutralCryptoHftBookState, type PolicyNeutralTapeSink } from "./market-data-vendor-backfill/cryptohftdata";
|
|
3
|
+
export declare const SOURCE_TAPE_CAPABILITY: Readonly<{
|
|
4
|
+
policy_id: string;
|
|
5
|
+
provider: string;
|
|
6
|
+
adapter_version: string;
|
|
7
|
+
acquisition_policy_id: string;
|
|
8
|
+
exchange: string;
|
|
9
|
+
market_type: string;
|
|
10
|
+
feed: string;
|
|
11
|
+
trading_pairs: string[];
|
|
12
|
+
construction_mode: string;
|
|
13
|
+
canonical_schema_id: string;
|
|
14
|
+
depth: number;
|
|
15
|
+
source_window_scan: string;
|
|
16
|
+
provider_object_inventory: string;
|
|
17
|
+
state_emission: string;
|
|
18
|
+
state_window: string;
|
|
19
|
+
archive_target: {
|
|
20
|
+
environment: string;
|
|
21
|
+
cluster: string;
|
|
22
|
+
};
|
|
23
|
+
archive_path: string;
|
|
24
|
+
submission_bounds: {
|
|
25
|
+
max_states_per_yield: number;
|
|
26
|
+
max_rows_per_batch: number;
|
|
27
|
+
max_bytes_per_batch: number;
|
|
28
|
+
max_in_flight: number;
|
|
29
|
+
};
|
|
30
|
+
clickhouse_image: string;
|
|
31
|
+
clickhouse_server_version: string;
|
|
32
|
+
projection_schema_ids: string[];
|
|
33
|
+
policy_sha256: string;
|
|
34
|
+
}>;
|
|
35
|
+
export declare const SOURCE_TAPE_CAPABILITY_ID: string;
|
|
36
|
+
export declare const SOURCE_TAPE_CONSTRUCTION_MODE: "policy_neutral_top_n_state_change_tape/v1";
|
|
37
|
+
export declare const SOURCE_TAPE_DEPTH: 100;
|
|
38
|
+
export declare const SOURCE_TAPE_MAX_STATES_PER_YIELD: 4;
|
|
39
|
+
export declare const SOURCE_TAPE_MAX_BATCH_ROWS = 1000;
|
|
40
|
+
export declare const SOURCE_TAPE_MAX_BATCH_BYTES: number;
|
|
41
|
+
export declare const SOURCE_TAPE_MAX_IN_FLIGHT: 1;
|
|
42
|
+
export declare const SOURCE_TAPE_SANDBOX_TARGET: Readonly<{
|
|
43
|
+
environment: "sandbox";
|
|
44
|
+
cluster: "cex-archive-local";
|
|
45
|
+
}>;
|
|
46
|
+
export declare const SOURCE_TAPE_PROJECTION_PINS: readonly Readonly<{
|
|
47
|
+
schema_id: string;
|
|
48
|
+
schema_sha256: string;
|
|
49
|
+
}>[];
|
|
50
|
+
export type SourceTapeProviderObjectInventory = {
|
|
51
|
+
expected_identities: string[];
|
|
52
|
+
observed_identities: string[];
|
|
53
|
+
complete: boolean;
|
|
54
|
+
};
|
|
55
|
+
export declare function sourceTapeCaptureBundleId(input: {
|
|
56
|
+
idempotencyKey: string;
|
|
57
|
+
tradingPair: "ARB-USDC" | "ARB-USDT";
|
|
58
|
+
window: {
|
|
59
|
+
startTimeMs: number;
|
|
60
|
+
endTimeMs: number;
|
|
61
|
+
};
|
|
62
|
+
expectedObjectIdentities: readonly string[];
|
|
63
|
+
}): string;
|
|
64
|
+
/**
|
|
65
|
+
* `production` is the stable forwarder mutation-authorization class. It is not
|
|
66
|
+
* an environment assertion: source-tape qualification remains sandbox-local.
|
|
67
|
+
*/
|
|
68
|
+
export declare function assertSourceTapeSandboxAuthorization(input: {
|
|
69
|
+
requestAuthorizationId: string;
|
|
70
|
+
requestTarget: {
|
|
71
|
+
environment: string;
|
|
72
|
+
cluster: string;
|
|
73
|
+
};
|
|
74
|
+
preflight: {
|
|
75
|
+
authorizationId: string;
|
|
76
|
+
scope: "production";
|
|
77
|
+
environment: string;
|
|
78
|
+
cluster: string;
|
|
79
|
+
credentialValidated: boolean;
|
|
80
|
+
};
|
|
81
|
+
}): void;
|
|
82
|
+
export type SourceTapeArchiveSinkResult = {
|
|
83
|
+
capture_bundle_id: string;
|
|
84
|
+
state_count: number;
|
|
85
|
+
level_row_count: number;
|
|
86
|
+
summary_row_count: number;
|
|
87
|
+
forwarder_batch_count: number;
|
|
88
|
+
forwarder_batch_identity_sha256: string;
|
|
89
|
+
initializer: {
|
|
90
|
+
canonical_snapshot_id: string;
|
|
91
|
+
source_time_ms: number;
|
|
92
|
+
sequence: string;
|
|
93
|
+
semantic_stream_position: 0;
|
|
94
|
+
};
|
|
95
|
+
expected_semantic_digest: string;
|
|
96
|
+
first_state_descriptor_sha256: string;
|
|
97
|
+
last_state_descriptor_sha256: string;
|
|
98
|
+
provider_object_inventory_complete: true;
|
|
99
|
+
max_states_per_yield: typeof SOURCE_TAPE_MAX_STATES_PER_YIELD;
|
|
100
|
+
max_batch_rows: typeof SOURCE_TAPE_MAX_BATCH_ROWS;
|
|
101
|
+
max_batch_bytes: typeof SOURCE_TAPE_MAX_BATCH_BYTES;
|
|
102
|
+
max_in_flight_submissions: typeof SOURCE_TAPE_MAX_IN_FLIGHT;
|
|
103
|
+
};
|
|
104
|
+
export type SourceTapeSemanticStateDescriptor = {
|
|
105
|
+
state_kind: "initialization" | "change";
|
|
106
|
+
semantic_stream_position: number;
|
|
107
|
+
canonical_snapshot_id: string;
|
|
108
|
+
source_time_ms: number;
|
|
109
|
+
sequence: string;
|
|
110
|
+
canonical_rows_sha256: string;
|
|
111
|
+
};
|
|
112
|
+
export declare class SourceTapeSemanticDigestAccumulator {
|
|
113
|
+
private readonly hash;
|
|
114
|
+
private count;
|
|
115
|
+
constructor();
|
|
116
|
+
append(descriptor: SourceTapeSemanticStateDescriptor): void;
|
|
117
|
+
digest(): string;
|
|
118
|
+
}
|
|
119
|
+
export declare function sourceTapeSemanticStateDescriptor(input: {
|
|
120
|
+
stateKind: "initialization" | "change";
|
|
121
|
+
semanticStreamPosition: number;
|
|
122
|
+
rows: readonly BackfillArchiveRow[];
|
|
123
|
+
}): SourceTapeSemanticStateDescriptor;
|
|
124
|
+
export type SourceTapeArchiveSink = PolicyNeutralTapeSink & {
|
|
125
|
+
result(): SourceTapeArchiveSinkResult;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Streams canonical tape rows to the existing archive-forwarder admission
|
|
129
|
+
* tables. Promotion, selection and exporter-v2 finalization remain later
|
|
130
|
+
* gates; this sink never creates a receipt or a success manifest by itself.
|
|
131
|
+
*/
|
|
132
|
+
export declare function createSourceTapeArchiveSink(input: {
|
|
133
|
+
captureBundleId: string;
|
|
134
|
+
tradingPair: "ARB-USDC" | "ARB-USDT";
|
|
135
|
+
window: {
|
|
136
|
+
startTimeMs: number;
|
|
137
|
+
endTimeMs: number;
|
|
138
|
+
};
|
|
139
|
+
forwarder: {
|
|
140
|
+
submit(batch: ForwarderBatch): Promise<{
|
|
141
|
+
ok: boolean;
|
|
142
|
+
inserted: number;
|
|
143
|
+
}>;
|
|
144
|
+
};
|
|
145
|
+
}): SourceTapeArchiveSink;
|
|
146
|
+
export declare function providerObjectInventoryIsComplete(inventory: SourceTapeProviderObjectInventory): boolean;
|
|
147
|
+
export declare function evaluateSourceTapeEligibility(input: {
|
|
148
|
+
source_enumeration_eligible: boolean;
|
|
149
|
+
provider_object_inventory: SourceTapeProviderObjectInventory;
|
|
150
|
+
tape_complete: boolean;
|
|
151
|
+
capability_id: string;
|
|
152
|
+
capability_sha256: string;
|
|
153
|
+
construction_mode: string;
|
|
154
|
+
projection_schema_pins: readonly {
|
|
155
|
+
schema_id: string;
|
|
156
|
+
schema_sha256: string;
|
|
157
|
+
}[];
|
|
158
|
+
artifact_sha256s: readonly string[];
|
|
159
|
+
tape_manifest_sha256: string;
|
|
160
|
+
}): boolean;
|
|
161
|
+
export declare function normalizeSourceTapeStates(input: {
|
|
162
|
+
tape: readonly PolicyNeutralCryptoHftBookState[];
|
|
163
|
+
capture_bundle_id: string;
|
|
164
|
+
trading_pair: "ARB-USDC" | "ARB-USDT";
|
|
165
|
+
}): BackfillArchiveRow[];
|
package/dist/index.js
CHANGED
|
@@ -292725,6 +292725,16 @@ function withTimeout(promise, timeoutMs, label) {
|
|
|
292725
292725
|
return Promise.race([promise, expiry]).finally(() => clearTimeout(timer));
|
|
292726
292726
|
}
|
|
292727
292727
|
var ALL_CURRENCIES_CODE = "*";
|
|
292728
|
+
var BINANCE_UNLOCK_PROGRESS_SOURCE = {
|
|
292729
|
+
venue: "binance",
|
|
292730
|
+
endpoint: "GET /sapi/v1/capital/deposit/hisrec",
|
|
292731
|
+
fields: {
|
|
292732
|
+
status: "info.status",
|
|
292733
|
+
confirmTimes: "info.confirmTimes",
|
|
292734
|
+
unlockConfirm: "info.unlockConfirm",
|
|
292735
|
+
completeTime: "info.completeTime"
|
|
292736
|
+
}
|
|
292737
|
+
};
|
|
292728
292738
|
function depositTimestamp(record) {
|
|
292729
292739
|
const observedAt = depositField(record, [
|
|
292730
292740
|
"timestamp",
|
|
@@ -292737,12 +292747,185 @@ function depositTimestamp(record) {
|
|
|
292737
292747
|
const timestamp = typeof observedAt === "number" ? observedAt : typeof observedAt === "string" ? Date.parse(observedAt) : Number.NaN;
|
|
292738
292748
|
return Number.isFinite(timestamp) ? timestamp : undefined;
|
|
292739
292749
|
}
|
|
292740
|
-
function
|
|
292741
|
-
|
|
292742
|
-
|
|
292743
|
-
|
|
292750
|
+
function parseNonNegativeInteger(value) {
|
|
292751
|
+
if (typeof value === "number") {
|
|
292752
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
292753
|
+
}
|
|
292754
|
+
if (typeof value !== "string") {
|
|
292755
|
+
return;
|
|
292756
|
+
}
|
|
292757
|
+
const trimmed = value.trim();
|
|
292758
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
292759
|
+
return;
|
|
292760
|
+
}
|
|
292761
|
+
const parsed = Number(trimmed);
|
|
292762
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : undefined;
|
|
292763
|
+
}
|
|
292764
|
+
function parseConfirmTimes(value) {
|
|
292765
|
+
if (value === undefined || value === null) {
|
|
292766
|
+
return { reason: "missing_confirmTimes" };
|
|
292767
|
+
}
|
|
292768
|
+
let currentValue;
|
|
292769
|
+
let creditRequiredValue;
|
|
292770
|
+
if (typeof value === "string") {
|
|
292771
|
+
const match = /^(\d+)\s*\/\s*(\d+)$/.exec(value.trim());
|
|
292772
|
+
if (!match) {
|
|
292773
|
+
return { reason: "invalid_confirmTimes" };
|
|
292774
|
+
}
|
|
292775
|
+
currentValue = match[1];
|
|
292776
|
+
creditRequiredValue = match[2];
|
|
292777
|
+
} else {
|
|
292778
|
+
const record = asRecord(value);
|
|
292779
|
+
if (!record) {
|
|
292780
|
+
return { reason: "invalid_confirmTimes" };
|
|
292781
|
+
}
|
|
292782
|
+
currentValue = record.current;
|
|
292783
|
+
creditRequiredValue = record.credit_required;
|
|
292784
|
+
}
|
|
292785
|
+
const current = parseNonNegativeInteger(currentValue);
|
|
292786
|
+
const creditRequired = parseNonNegativeInteger(creditRequiredValue);
|
|
292787
|
+
if (current === undefined || creditRequired === undefined) {
|
|
292788
|
+
return { reason: "invalid_confirmTimes" };
|
|
292789
|
+
}
|
|
292790
|
+
return { current, creditRequired, reason: null };
|
|
292791
|
+
}
|
|
292792
|
+
function parseOptionalNonNegativeInteger(value, fieldName) {
|
|
292793
|
+
if (value === undefined || value === null) {
|
|
292794
|
+
return { value: undefined, reason: null };
|
|
292795
|
+
}
|
|
292796
|
+
const parsed = parseNonNegativeInteger(value);
|
|
292797
|
+
return parsed === undefined ? { value: undefined, reason: `invalid_${fieldName}` } : { value: parsed, reason: null };
|
|
292798
|
+
}
|
|
292799
|
+
function parseBinanceUnlockProgress(record) {
|
|
292800
|
+
const info = asRecord(record.info);
|
|
292801
|
+
const nativeStatus = parseNonNegativeInteger(info?.status);
|
|
292802
|
+
const confirmations = parseConfirmTimes(info?.confirmTimes);
|
|
292803
|
+
const unlockRequired = parseOptionalNonNegativeInteger(info?.unlockConfirm, "unlockConfirm");
|
|
292804
|
+
const completeTime = parseOptionalNonNegativeInteger(info?.completeTime, "completeTime");
|
|
292805
|
+
let quality = "valid";
|
|
292806
|
+
let reason = null;
|
|
292807
|
+
if (nativeStatus === undefined) {
|
|
292808
|
+
quality = "unknown";
|
|
292809
|
+
reason = "missing_or_invalid_status";
|
|
292810
|
+
} else if (confirmations.reason !== null) {
|
|
292811
|
+
quality = "unknown";
|
|
292812
|
+
reason = confirmations.reason;
|
|
292813
|
+
} else if (unlockRequired.reason !== null) {
|
|
292814
|
+
quality = "unknown";
|
|
292815
|
+
reason = unlockRequired.reason;
|
|
292816
|
+
} else if (completeTime.reason !== null) {
|
|
292817
|
+
quality = "unknown";
|
|
292818
|
+
reason = completeTime.reason;
|
|
292819
|
+
}
|
|
292820
|
+
let state = "unknown";
|
|
292821
|
+
switch (nativeStatus) {
|
|
292822
|
+
case 0:
|
|
292823
|
+
state = "pending";
|
|
292824
|
+
break;
|
|
292825
|
+
case 1:
|
|
292826
|
+
if (quality === "valid" && confirmations.current !== undefined && unlockRequired.value !== undefined && confirmations.current >= unlockRequired.value) {
|
|
292827
|
+
state = "ok";
|
|
292828
|
+
} else if (quality === "valid") {
|
|
292829
|
+
state = "credited_not_withdrawable";
|
|
292830
|
+
}
|
|
292831
|
+
break;
|
|
292832
|
+
case 2:
|
|
292833
|
+
case 7:
|
|
292834
|
+
state = "failed";
|
|
292835
|
+
break;
|
|
292836
|
+
case 6:
|
|
292837
|
+
state = "credited_not_withdrawable";
|
|
292838
|
+
break;
|
|
292839
|
+
case 8:
|
|
292840
|
+
state = "pending";
|
|
292841
|
+
break;
|
|
292842
|
+
default:
|
|
292843
|
+
quality = "unknown";
|
|
292844
|
+
reason = "unsupported_status";
|
|
292845
|
+
break;
|
|
292846
|
+
}
|
|
292847
|
+
return {
|
|
292848
|
+
version: 1,
|
|
292849
|
+
state,
|
|
292850
|
+
progress_state: quality,
|
|
292851
|
+
reason,
|
|
292852
|
+
native_status: nativeStatus ?? null,
|
|
292853
|
+
current: confirmations.current ?? null,
|
|
292854
|
+
credit_required: confirmations.creditRequired ?? null,
|
|
292855
|
+
unlock_required: unlockRequired.value ?? null,
|
|
292856
|
+
complete_time: completeTime.value ?? null,
|
|
292857
|
+
observed_at: new Date().toISOString(),
|
|
292858
|
+
source: BINANCE_UNLOCK_PROGRESS_SOURCE
|
|
292859
|
+
};
|
|
292860
|
+
}
|
|
292861
|
+
function unlockProgressKey(progress) {
|
|
292862
|
+
return JSON.stringify({
|
|
292863
|
+
version: progress.version,
|
|
292864
|
+
state: progress.state,
|
|
292865
|
+
progress_state: progress.progress_state,
|
|
292866
|
+
reason: progress.reason,
|
|
292867
|
+
native_status: progress.native_status,
|
|
292868
|
+
current: progress.current,
|
|
292869
|
+
credit_required: progress.credit_required,
|
|
292870
|
+
unlock_required: progress.unlock_required,
|
|
292871
|
+
complete_time: progress.complete_time
|
|
292872
|
+
});
|
|
292873
|
+
}
|
|
292874
|
+
function progressWatermark(progress, previous) {
|
|
292875
|
+
if (progress.progress_state !== "valid" || progress.current === null || progress.credit_required === null || progress.unlock_required === null) {
|
|
292876
|
+
return previous;
|
|
292877
|
+
}
|
|
292878
|
+
return {
|
|
292879
|
+
current: Math.max(previous?.current ?? 0, progress.current),
|
|
292880
|
+
credit_required: progress.credit_required,
|
|
292881
|
+
unlock_required: progress.unlock_required
|
|
292882
|
+
};
|
|
292883
|
+
}
|
|
292884
|
+
function classifyBinanceDeposit(record, previous) {
|
|
292885
|
+
let progress = parseBinanceUnlockProgress(record);
|
|
292886
|
+
let highWatermark = previous?.highWatermark;
|
|
292887
|
+
if (progress.progress_state === "valid" && progress.current !== null && progress.credit_required !== null && progress.unlock_required !== null && previous?.highWatermark !== undefined && (progress.current < previous.highWatermark.current || progress.credit_required !== previous.highWatermark.credit_required || progress.unlock_required !== previous.highWatermark.unlock_required)) {
|
|
292888
|
+
progress = {
|
|
292889
|
+
...progress,
|
|
292890
|
+
state: "unknown",
|
|
292891
|
+
progress_state: "contradictory",
|
|
292892
|
+
reason: "confirmation_progress_regressed_or_requirement_changed"
|
|
292893
|
+
};
|
|
292894
|
+
} else {
|
|
292895
|
+
highWatermark = progressWatermark(progress, previous?.highWatermark);
|
|
292896
|
+
}
|
|
292897
|
+
return {
|
|
292898
|
+
archiveStatus: progress.state,
|
|
292899
|
+
holdCursor: progress.state === "pending" || progress.state === "credited_not_withdrawable" || progress.state === "unknown",
|
|
292900
|
+
unlockProgress: progress,
|
|
292901
|
+
progressKey: unlockProgressKey(progress),
|
|
292902
|
+
highWatermark
|
|
292903
|
+
};
|
|
292904
|
+
}
|
|
292905
|
+
function classifyDeposit(exchangeId, record, previous) {
|
|
292906
|
+
if (exchangeId?.toLowerCase() === "binance") {
|
|
292907
|
+
return classifyBinanceDeposit(record, previous);
|
|
292908
|
+
}
|
|
292909
|
+
const archiveStatus = normalizeCcxtTransactionForArchive(record).status ?? "";
|
|
292910
|
+
const status = normalizeDepositStatus(depositField(record, ["status", "state"]));
|
|
292911
|
+
return {
|
|
292912
|
+
archiveStatus,
|
|
292913
|
+
holdCursor: archiveStatus === "credited_not_withdrawable" || status === "pending",
|
|
292914
|
+
progressKey: JSON.stringify({ status: archiveStatus })
|
|
292915
|
+
};
|
|
292916
|
+
}
|
|
292917
|
+
function depositIdentity(input) {
|
|
292918
|
+
if (input.externalId === undefined && input.txid === undefined) {
|
|
292919
|
+
return;
|
|
292744
292920
|
}
|
|
292745
|
-
return
|
|
292921
|
+
return JSON.stringify({
|
|
292922
|
+
exchange: input.exchangeId,
|
|
292923
|
+
account: input.accountSelector,
|
|
292924
|
+
coin: input.coin === undefined ? "" : String(input.coin),
|
|
292925
|
+
network: input.network === undefined ? "" : String(input.network),
|
|
292926
|
+
external_id: input.externalId ?? "",
|
|
292927
|
+
txid: input.txid ?? ""
|
|
292928
|
+
});
|
|
292746
292929
|
}
|
|
292747
292930
|
function nextDepositCursor(deposits, currentSince, depositsLimit, exchangeId) {
|
|
292748
292931
|
if (deposits.length >= depositsLimit) {
|
|
@@ -292756,9 +292939,8 @@ function nextDepositCursor(deposits, currentSince, depositsLimit, exchangeId) {
|
|
|
292756
292939
|
return currentSince;
|
|
292757
292940
|
}
|
|
292758
292941
|
const timestamp = depositTimestamp(record);
|
|
292759
|
-
const
|
|
292760
|
-
const
|
|
292761
|
-
const isPending = archiveStatus === "credited_not_withdrawable" || status === "pending";
|
|
292942
|
+
const classification = classifyDeposit(exchangeId, record);
|
|
292943
|
+
const isPending = classification.holdCursor;
|
|
292762
292944
|
if (timestamp === undefined) {
|
|
292763
292945
|
if (isPending) {
|
|
292764
292946
|
return currentSince;
|
|
@@ -292878,7 +293060,8 @@ class DepositArchivePoller {
|
|
|
292878
293060
|
if (!record) {
|
|
292879
293061
|
continue;
|
|
292880
293062
|
}
|
|
292881
|
-
const
|
|
293063
|
+
const info = asRecord(record.info);
|
|
293064
|
+
const assetSymbol = depositField(record, ["currency", "code", "asset"]) ?? info?.coin;
|
|
292882
293065
|
const amount = depositField(record, ["amount"]);
|
|
292883
293066
|
const address = depositField(record, [
|
|
292884
293067
|
"address",
|
|
@@ -292887,8 +293070,21 @@ class DepositArchivePoller {
|
|
|
292887
293070
|
"destination"
|
|
292888
293071
|
]);
|
|
292889
293072
|
const txid = depositField(record, ["txid", "txId", "tx_hash", "txHash"]);
|
|
292890
|
-
const network = depositField(record, ["network", "chain"]);
|
|
292891
|
-
const
|
|
293073
|
+
const network = depositField(record, ["network", "chain"]) ?? info?.network;
|
|
293074
|
+
const depositTxid = txid === undefined ? undefined : String(txid);
|
|
293075
|
+
const identity = depositIdentity({
|
|
293076
|
+
exchangeId: target.exchangeId,
|
|
293077
|
+
accountSelector: target.account.label,
|
|
293078
|
+
coin: assetSymbol,
|
|
293079
|
+
network,
|
|
293080
|
+
externalId: depositTxid,
|
|
293081
|
+
txid: depositTxid
|
|
293082
|
+
});
|
|
293083
|
+
const lastArchived = identity === undefined ? undefined : this.#lastArchivedByTarget.get(key)?.get(identity);
|
|
293084
|
+
const classification = classifyDeposit(target.exchangeId, record, lastArchived);
|
|
293085
|
+
if (lastArchived && lastArchived.status === classification.archiveStatus && lastArchived.progressKey === classification.progressKey) {
|
|
293086
|
+
continue;
|
|
293087
|
+
}
|
|
292892
293088
|
const creditedAt = depositField(record, [
|
|
292893
293089
|
"creditedAt",
|
|
292894
293090
|
"credited_at",
|
|
@@ -292897,11 +293093,7 @@ class DepositArchivePoller {
|
|
|
292897
293093
|
"timestamp",
|
|
292898
293094
|
"datetime"
|
|
292899
293095
|
]);
|
|
292900
|
-
const
|
|
292901
|
-
const lastArchived = depositTxid === undefined ? undefined : this.#lastArchivedByTarget.get(key)?.get(depositTxid);
|
|
292902
|
-
if (lastArchived && lastArchived.status === archiveStatus) {
|
|
292903
|
-
continue;
|
|
292904
|
-
}
|
|
293096
|
+
const payload = classification.unlockProgress === undefined ? record : { ...record, unlock_progress: classification.unlockProgress };
|
|
292905
293097
|
this.params.archiver.enqueue(buildTransferEventArchiveRow({
|
|
292906
293098
|
tags: buildCommonArchiveTags({
|
|
292907
293099
|
deploymentId: this.params.archiver.getDeploymentId(),
|
|
@@ -292912,25 +293104,27 @@ class DepositArchivePoller {
|
|
|
292912
293104
|
transfer: {
|
|
292913
293105
|
eventKind: "deposit",
|
|
292914
293106
|
lifecycleAction: "observe_deposit",
|
|
292915
|
-
status: archiveStatus,
|
|
293107
|
+
status: classification.archiveStatus,
|
|
292916
293108
|
amount: amount === undefined ? undefined : String(amount),
|
|
292917
293109
|
address: address === undefined ? undefined : String(address),
|
|
292918
293110
|
network: network === undefined ? undefined : String(network),
|
|
292919
293111
|
externalId: depositTxid,
|
|
292920
293112
|
txid: depositTxid,
|
|
292921
293113
|
exchangeTimestamp: normalizeTimestamp(creditedAt),
|
|
292922
|
-
payload
|
|
293114
|
+
payload
|
|
292923
293115
|
}
|
|
292924
293116
|
}));
|
|
292925
|
-
if (
|
|
293117
|
+
if (identity !== undefined) {
|
|
292926
293118
|
let targetDeposits2 = this.#lastArchivedByTarget.get(key);
|
|
292927
293119
|
if (!targetDeposits2) {
|
|
292928
293120
|
targetDeposits2 = new Map;
|
|
292929
293121
|
this.#lastArchivedByTarget.set(key, targetDeposits2);
|
|
292930
293122
|
}
|
|
292931
|
-
targetDeposits2.set(
|
|
292932
|
-
status: archiveStatus,
|
|
292933
|
-
timestamp: depositTimestamp(record)
|
|
293123
|
+
targetDeposits2.set(identity, {
|
|
293124
|
+
status: classification.archiveStatus,
|
|
293125
|
+
timestamp: depositTimestamp(record),
|
|
293126
|
+
progressKey: classification.progressKey,
|
|
293127
|
+
highWatermark: classification.highWatermark
|
|
292934
293128
|
});
|
|
292935
293129
|
}
|
|
292936
293130
|
archived += 1;
|
|
@@ -294125,7 +294319,7 @@ function commonEvidenceFields(context2, rawCapture, input) {
|
|
|
294125
294319
|
source_time_ms: input.eventTimeMs,
|
|
294126
294320
|
received_time_ms: input.receivedTimeMs,
|
|
294127
294321
|
snapshot_id: input.snapshotId,
|
|
294128
|
-
construction_mode:
|
|
294322
|
+
construction_mode: input.constructionMode,
|
|
294129
294323
|
gap_policy: "record_gap",
|
|
294130
294324
|
depth_limit: input.depthLimit,
|
|
294131
294325
|
sequence: input.sequence,
|
|
@@ -294179,7 +294373,8 @@ function buildCanonicalOrderBookRows(input) {
|
|
|
294179
294373
|
sequence,
|
|
294180
294374
|
depthLimit: input.depthLimit,
|
|
294181
294375
|
eventTimeMs,
|
|
294182
|
-
receivedTimeMs
|
|
294376
|
+
receivedTimeMs,
|
|
294377
|
+
constructionMode: input.constructionMode ?? "sampled_top_n_snapshot"
|
|
294183
294378
|
});
|
|
294184
294379
|
const levels = [
|
|
294185
294380
|
["bid", bids],
|
|
@@ -313344,4 +313539,4 @@ export {
|
|
|
313344
313539
|
CEXBroker as default
|
|
313345
313540
|
};
|
|
313346
313541
|
|
|
313347
|
-
//# debugId=
|
|
313542
|
+
//# debugId=72C8C3614857C3F664756E2164756E21
|