Skip to content

Commit c1fc3cb

Browse files
authored
Merge pull request #53 from usherlabs/feat/binance-travel-rule-deposit
feat(deposit): auto-clear Binance travel-rule frozen deposits (0.2.17)
2 parents 5279fc7 + 0d66a06 commit c1fc3cb

10 files changed

Lines changed: 1639 additions & 10 deletions

.env.sample

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,16 @@ OTEL_SERVICE_NAME=cex-broker
1616
# Or use legacy host/port configuration
1717
# CEX_BROKER_OTEL_HOST=otel-collector
1818
# CEX_BROKER_OTEL_PORT=4318
19-
# CEX_BROKER_OTEL_PROTOCOL=http
19+
# CEX_BROKER_OTEL_PROTOCOL=http
20+
21+
# Travel-rule deposit auto-clear reconciler (only used when a policy has
22+
# travelRule.rule[].deposits.enabled). One RPC URL per Binance network code
23+
# (suffix must match the deposit's `network`, e.g. ARBITRUM), used to prove a
24+
# frozen deposit's on-chain sender before auto-submitting its questionnaire. A
25+
# frozen deposit on a network with no RPC configured is left frozen (fail-closed).
26+
# These are intentionally NOT CEX_BROKER_-prefixed so the credential scan skips them.
27+
# TRAVEL_RULE_RPC_URL_ARBITRUM=https://arb1.arbitrum.io/rpc
28+
# Optional overrides (defaults shown):
29+
# TRAVEL_RULE_DEPOSIT_POLL_ACTIVE_SECS=60
30+
# TRAVEL_RULE_DEPOSIT_POLL_IDLE_SECS=600
31+
# TRAVEL_RULE_QUESTIONNAIRE_COUNTRY=AU

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@usherlabs/cex-broker",
3-
"version": "0.2.16",
3+
"version": "0.2.17",
44
"description": "Unified gRPC API to CEXs by Usher Labs.",
55
"repository": {
66
"type": "git",
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,32 @@
11
diff --git a/node_modules/@usherlabs/ccxt/.bun-tag-a296b4edbb70d359 b/.bun-tag-a296b4edbb70d359
22
new file mode 100644
33
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
4+
diff --git a/node_modules/@usherlabs/ccxt/.bun-tag-e1eca9fb87d1075f b/.bun-tag-e1eca9fb87d1075f
5+
new file mode 100644
6+
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
47
diff --git a/dist/cjs/src/binance.js b/dist/cjs/src/binance.js
5-
index 40b4c4e8989fcbcdc693216cdb0d43bf0f553a88..2d1083354341ee778318c53332c03897558b5137 100644
8+
index 40b4c4e8989fcbcdc693216cdb0d43bf0f553a88..6c7cda095c614de0527fa225ed321671488cbef9 100644
69
--- a/dist/cjs/src/binance.js
710
+++ b/dist/cjs/src/binance.js
811
@@ -12045,7 +12045,7 @@ class binance extends binance$1 {
912
if ((api === 'sapi') && (path === 'asset/dust')) {
1013
query = this.urlencodeWithArrayRepeat(extendedParams);
1114
}
1215
- else if ((path === 'batchOrders') || (path.indexOf('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path.indexOf('staking') >= 0) || (path.indexOf('simple-earn') >= 0)) {
13-
+ else if ((path === 'batchOrders') || (path.indexOf('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path === 'localentity/withdraw/apply') || (path.indexOf('staking') >= 0) || (path.indexOf('simple-earn') >= 0)) {
16+
+ else if ((path === 'batchOrders') || (path.indexOf('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path === 'localentity/withdraw/apply') || (path === 'localentity/deposit/provide-info') || (path.indexOf('staking') >= 0) || (path.indexOf('simple-earn') >= 0)) {
1417
if ((method === 'DELETE') && (path === 'batchOrders')) {
1518
const orderidlist = this.safeList(extendedParams, 'orderidlist', []);
1619
const origclientorderidlist = this.safeList(extendedParams, 'origclientorderidlist', []);
1720
diff --git a/js/src/binance.js b/js/src/binance.js
18-
index 9a472db82ff35f67c16bfde11b34831f503d00f9..70b1cd355fe31be954f0bd673f9b5896081a8ddc 100644
21+
index 9a472db82ff35f67c16bfde11b34831f503d00f9..7e7696cac61e08ac469d4d7c2b9c6fb861c84b3c 100644
1922
--- a/js/src/binance.js
2023
+++ b/js/src/binance.js
2124
@@ -12048,7 +12048,7 @@ export default class binance extends Exchange {
2225
if ((api === 'sapi') && (path === 'asset/dust')) {
2326
query = this.urlencodeWithArrayRepeat(extendedParams);
2427
}
2528
- else if ((path === 'batchOrders') || (path.indexOf('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path.indexOf('staking') >= 0) || (path.indexOf('simple-earn') >= 0)) {
26-
+ else if ((path === 'batchOrders') || (path.indexOf('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path === 'localentity/withdraw/apply') || (path.indexOf('staking') >= 0) || (path.indexOf('simple-earn') >= 0)) {
29+
+ else if ((path === 'batchOrders') || (path.indexOf('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path === 'localentity/withdraw/apply') || (path === 'localentity/deposit/provide-info') || (path.indexOf('staking') >= 0) || (path.indexOf('simple-earn') >= 0)) {
2730
if ((method === 'DELETE') && (path === 'batchOrders')) {
2831
const orderidlist = this.safeList(extendedParams, 'orderidlist', []);
2932
const origclientorderidlist = this.safeList(extendedParams, 'origclientorderidlist', []);

src/helpers/broker.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import ccxt from "@usherlabs/ccxt";
44
import type { BrokerAccountRole, BrokerCredentials } from "../types";
55
import { buildCcxtConfig } from "./exchange-credentials";
66
import { log } from "./logger";
7-
import { registerBinanceTravelRuleWithdrawEndpoint } from "./travel-rule";
7+
import {
8+
registerBinanceTravelRuleDepositEndpoints,
9+
registerBinanceTravelRuleWithdrawEndpoint,
10+
} from "./travel-rule";
811

912
export type BrokerAccount = {
1013
exchange: Exchange;
@@ -52,8 +55,12 @@ export function applyCommonExchangeConfig(exchange: Exchange) {
5255
recvWindow: 60000,
5356
adjustForTimeDifference: true,
5457
});
55-
// Register Binance's travel-rule withdraw endpoint (no-op for other exchanges).
58+
// Register Binance's travel-rule endpoints (no-op for other exchanges): the
59+
// withdraw apply endpoint and the deposit reconciler's read/provide-info
60+
// endpoints. Registered here so every account instance carries them before the
61+
// reconciler's first tick.
5662
registerBinanceTravelRuleWithdrawEndpoint(exchange);
63+
registerBinanceTravelRuleDepositEndpoints(exchange);
5764
}
5865

5966
export function createBroker(

src/helpers/index.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import {
1414
parseMarketPattern,
1515
parseMarketType,
1616
} from "./market-type";
17-
import { australiaQuestionnaireSchema } from "./travel-rule";
17+
import {
18+
australiaDepositQuestionnaireSchema,
19+
australiaQuestionnaireSchema,
20+
} from "./travel-rule";
1821

1922
export { authenticateRequest } from "./auth";
2023
export {
@@ -31,12 +34,21 @@ export {
3134
selectBrokerAccount,
3235
} from "./broker";
3336
export {
37+
australiaDepositQuestionnaireSchema,
3438
australiaQuestionnaireSchema,
39+
getEnabledTravelRuleDepositConfig,
40+
registerBinanceTravelRuleDepositEndpoints,
3541
registerBinanceTravelRuleWithdrawEndpoint,
42+
resolveDepositOriginatorQuestionnaire,
3643
resolveTravelRuleDecision,
3744
type TravelRuleDecision,
3845
withdrawViaLocalEntity,
3946
} from "./travel-rule";
47+
export {
48+
loadTravelRuleDepositReconcilerConfigFromEnv,
49+
resolveOnChainSender,
50+
TravelRuleDepositReconciler,
51+
} from "./travel-rule-deposit-reconciler";
4052
export {
4153
buildHttpClientOverrideFromMetadata,
4254
createVerityHttpClientOverride,
@@ -97,6 +109,21 @@ export function loadPolicy(policyPath: string): PolicyConfig {
97109
}),
98110
)
99111
.required(),
112+
// Deposit auto-clear config, keyed by on-chain sender (originator). Uses
113+
// the deposit questionnaire schema, which is deliberately distinct from
114+
// the withdraw one so a copy-paste of the wrong shape fails at load time.
115+
deposits: Joi.object({
116+
enabled: Joi.boolean().required(),
117+
description: Joi.string().optional(),
118+
originators: Joi.object()
119+
.pattern(
120+
Joi.string(),
121+
Joi.object({
122+
questionnaire: australiaDepositQuestionnaireSchema.required(),
123+
}),
124+
)
125+
.required(),
126+
}).optional(),
100127
});
101128

102129
// Full PolicyConfig schema

0 commit comments

Comments
 (0)