@usherlabs/cex-broker 0.2.14 → 0.2.16

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.
@@ -119803,7 +119803,7 @@ class binance extends binance_default {
119803
119803
  }
119804
119804
  if (api === "sapi" && path === "asset/dust") {
119805
119805
  query = this.urlencodeWithArrayRepeat(extendedParams);
119806
- } else if (path === "batchOrders" || path.indexOf("sub-account") >= 0 || path === "capital/withdraw/apply" || path.indexOf("staking") >= 0 || path.indexOf("simple-earn") >= 0) {
119806
+ } 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) {
119807
119807
  if (method === "DELETE" && path === "batchOrders") {
119808
119808
  const orderidlist = this.safeList(extendedParams, "orderidlist", []);
119809
119809
  const origclientorderidlist = this.safeList(extendedParams, "origclientorderidlist", []);
@@ -310973,11 +310973,11 @@ var ccxt = Object.assign({ version: version2, Exchange, Precise, exchanges: Obje
310973
310973
  var ccxt_default = ccxt;
310974
310974
 
310975
310975
  // src/index.ts
310976
- var import_joi2 = __toESM(require_lib4(), 1);
310976
+ var import_joi3 = __toESM(require_lib4(), 1);
310977
310977
  import { unwatchFile, watchFile } from "fs";
310978
310978
 
310979
310979
  // src/helpers/index.ts
310980
- var import_joi = __toESM(require_lib4(), 1);
310980
+ var import_joi2 = __toESM(require_lib4(), 1);
310981
310981
  import fs from "fs";
310982
310982
 
310983
310983
  // src/helpers/exchange-credentials.ts
@@ -313531,6 +313531,81 @@ if (process.env.LOG_LEVEL !== "debug") {
313531
313531
  }
313532
313532
  var log = baseLogger;
313533
313533
 
313534
+ // src/helpers/travel-rule.ts
313535
+ var import_joi = __toESM(require_lib4(), 1);
313536
+ var isAnotherBeneficiary = import_joi.default.number().valid(2).required();
313537
+ var isIndividual = import_joi.default.number().valid(0).required();
313538
+ var isCorporate = import_joi.default.number().valid(1).required();
313539
+ var isSendToVasp = import_joi.default.number().valid(2).required();
313540
+ var isVaspOthers = import_joi.default.string().valid("others").required();
313541
+ function requiredWhen(base2, ref, is) {
313542
+ return base2.when(ref, {
313543
+ is,
313544
+ then: import_joi.default.required(),
313545
+ otherwise: import_joi.default.forbidden()
313546
+ });
313547
+ }
313548
+ var australiaQuestionnaireSchema = import_joi.default.object({
313549
+ isAddressOwner: import_joi.default.number().valid(1, 2).required(),
313550
+ sendTo: import_joi.default.number().valid(1, 2).required(),
313551
+ declaration: import_joi.default.boolean().valid(true).required(),
313552
+ bnfType: requiredWhen(import_joi.default.number().valid(0, 1), "isAddressOwner", isAnotherBeneficiary),
313553
+ bnfFirstName: requiredWhen(import_joi.default.string(), "bnfType", isIndividual),
313554
+ bnfLastName: requiredWhen(import_joi.default.string(), "bnfType", isIndividual),
313555
+ country: requiredWhen(import_joi.default.string(), "bnfType", isIndividual),
313556
+ city: requiredWhen(import_joi.default.string(), "bnfType", isIndividual),
313557
+ bnfCorpName: requiredWhen(import_joi.default.string(), "bnfType", isCorporate),
313558
+ bnfCorpCountry: requiredWhen(import_joi.default.string(), "bnfType", isCorporate),
313559
+ bnfCorpCity: requiredWhen(import_joi.default.string(), "bnfType", isCorporate),
313560
+ vasp: requiredWhen(import_joi.default.string(), "sendTo", isSendToVasp),
313561
+ vaspName: requiredWhen(import_joi.default.string(), "vasp", isVaspOthers)
313562
+ });
313563
+ function resolveTravelRuleDecision(policy, exchange, recipientAddress) {
313564
+ const rules = policy.travelRule?.rule ?? [];
313565
+ const exchangeNorm = exchange.trim().toUpperCase();
313566
+ const entry = rules.find((rule) => rule.exchange.trim().toUpperCase() === exchangeNorm);
313567
+ if (!entry || !entry.enabled) {
313568
+ return { mode: "standard" };
313569
+ }
313570
+ const addressNorm = recipientAddress.trim().toLowerCase();
313571
+ const match = Object.entries(entry.addresses).find(([address]) => address.trim().toLowerCase() === addressNorm);
313572
+ if (!match) {
313573
+ return {
313574
+ mode: "denied",
313575
+ error: `no travel-rule questionnaire configured for ${exchangeNorm} address ${recipientAddress}`
313576
+ };
313577
+ }
313578
+ return { mode: "localentity", questionnaire: match[1].questionnaire };
313579
+ }
313580
+ function registerBinanceTravelRuleWithdrawEndpoint(exchange) {
313581
+ if (exchange.id !== "binance") {
313582
+ return;
313583
+ }
313584
+ exchange.defineRestApi({ sapi: { post: { "localentity/withdraw/apply": 4.0002 } } }, "request");
313585
+ }
313586
+ async function withdrawViaLocalEntity(broker, args) {
313587
+ const exchange = broker;
313588
+ if (typeof exchange.sapiPostLocalentityWithdrawApply !== "function") {
313589
+ throw new Error("binance_localentity_withdraw_unavailable: travel-rule withdraw endpoint is not registered on this exchange instance");
313590
+ }
313591
+ broker.checkAddress(args.address);
313592
+ await broker.loadMarkets();
313593
+ const currency = broker.currency(args.code);
313594
+ const networks = broker.safeDict(broker.options, "networks", {});
313595
+ const networkUpper = args.network.trim().toUpperCase();
313596
+ const mappedNetwork = broker.safeString(networks, networkUpper, networkUpper);
313597
+ const request = {
313598
+ ...args.params,
313599
+ coin: currency.id,
313600
+ address: args.address,
313601
+ amount: broker.currencyToPrecision(args.code, args.amount),
313602
+ network: mappedNetwork,
313603
+ questionnaire: JSON.stringify(args.questionnaire)
313604
+ };
313605
+ const response = await exchange.sapiPostLocalentityWithdrawApply(request);
313606
+ return broker.parseTransaction(response, currency);
313607
+ }
313608
+
313534
313609
  // src/helpers/broker.ts
313535
313610
  class BrokerAccountPreconditionError extends Error {
313536
313611
  constructor(message) {
@@ -313555,6 +313630,7 @@ function applyCommonExchangeConfig(exchange) {
313555
313630
  recvWindow: 60000,
313556
313631
  adjustForTimeDifference: true
313557
313632
  });
313633
+ registerBinanceTravelRuleWithdrawEndpoint(exchange);
313558
313634
  }
313559
313635
  function createBroker(cex3, credsOrMetadata) {
313560
313636
  let apiKey;
@@ -313971,36 +314047,47 @@ var verityHttpClientOverridePredicate = ({
313971
314047
  function loadPolicy(policyPath) {
313972
314048
  try {
313973
314049
  const policyData = fs.readFileSync(policyPath, "utf8");
313974
- const withdrawRuleEntrySchema = import_joi.default.object({
313975
- exchange: import_joi.default.string().required(),
313976
- network: import_joi.default.string().required(),
313977
- whitelist: import_joi.default.array().items(import_joi.default.string()).required(),
313978
- coins: import_joi.default.array().items(import_joi.default.string()).optional()
314050
+ const withdrawRuleEntrySchema = import_joi2.default.object({
314051
+ exchange: import_joi2.default.string().required(),
314052
+ network: import_joi2.default.string().required(),
314053
+ whitelist: import_joi2.default.array().items(import_joi2.default.string()).required(),
314054
+ coins: import_joi2.default.array().items(import_joi2.default.string()).optional()
313979
314055
  });
313980
- const depositRuleEntrySchema = import_joi.default.object({
313981
- exchange: import_joi.default.string().required(),
313982
- network: import_joi.default.string().required(),
313983
- coins: import_joi.default.array().items(import_joi.default.string()).optional()
314056
+ const depositRuleEntrySchema = import_joi2.default.object({
314057
+ exchange: import_joi2.default.string().required(),
314058
+ network: import_joi2.default.string().required(),
314059
+ coins: import_joi2.default.array().items(import_joi2.default.string()).optional()
313984
314060
  });
313985
- const orderRuleSchema = import_joi.default.object({
313986
- markets: import_joi.default.array().items(import_joi.default.string()).required(),
313987
- limits: import_joi.default.array().items(import_joi.default.object({
313988
- from: import_joi.default.string().required(),
313989
- to: import_joi.default.string().required(),
313990
- min: import_joi.default.number().required(),
313991
- max: import_joi.default.number().required()
314061
+ const orderRuleSchema = import_joi2.default.object({
314062
+ markets: import_joi2.default.array().items(import_joi2.default.string()).required(),
314063
+ limits: import_joi2.default.array().items(import_joi2.default.object({
314064
+ from: import_joi2.default.string().required(),
314065
+ to: import_joi2.default.string().required(),
314066
+ min: import_joi2.default.number().required(),
314067
+ max: import_joi2.default.number().required()
313992
314068
  })).default([])
313993
314069
  });
313994
- const policyConfigSchema = import_joi.default.object({
313995
- withdraw: import_joi.default.object({
313996
- rule: import_joi.default.array().items(withdrawRuleEntrySchema).min(1).required()
314070
+ const travelRuleEntrySchema = import_joi2.default.object({
314071
+ exchange: import_joi2.default.string().uppercase().valid("BINANCE").required(),
314072
+ enabled: import_joi2.default.boolean().required(),
314073
+ description: import_joi2.default.string().optional(),
314074
+ addresses: import_joi2.default.object().pattern(import_joi2.default.string(), import_joi2.default.object({
314075
+ questionnaire: australiaQuestionnaireSchema.required()
314076
+ })).required()
314077
+ });
314078
+ const policyConfigSchema = import_joi2.default.object({
314079
+ withdraw: import_joi2.default.object({
314080
+ rule: import_joi2.default.array().items(withdrawRuleEntrySchema).min(1).required()
313997
314081
  }).required(),
313998
- deposit: import_joi.default.object({
313999
- rule: import_joi.default.array().items(depositRuleEntrySchema).optional()
314082
+ deposit: import_joi2.default.object({
314083
+ rule: import_joi2.default.array().items(depositRuleEntrySchema).optional()
314000
314084
  }).required(),
314001
- order: import_joi.default.object({
314085
+ order: import_joi2.default.object({
314002
314086
  rule: orderRuleSchema.required()
314003
- }).required()
314087
+ }).required(),
314088
+ travelRule: import_joi2.default.object({
314089
+ rule: import_joi2.default.array().items(travelRuleEntrySchema).required()
314090
+ }).optional()
314004
314091
  });
314005
314092
  const { error, value } = policyConfigSchema.validate(JSON.parse(policyData));
314006
314093
  if (error) {
@@ -330114,8 +330201,22 @@ async function handleWithdraw(ctx) {
330114
330201
  message: `policy_withdrawal_denied: ${transferValidation.error}`
330115
330202
  }, null);
330116
330203
  }
330204
+ const travelRule = resolveTravelRuleDecision(policy, cex3, transferValue.recipientAddress);
330205
+ if (travelRule.mode === "denied") {
330206
+ return ctx.wrappedCallback({
330207
+ code: grpc10.status.FAILED_PRECONDITION,
330208
+ message: `travel_rule_denied: ${travelRule.error}`
330209
+ }, null);
330210
+ }
330117
330211
  try {
330118
- const transaction = await broker.withdraw(symbol2, transferValue.amount, transferValue.recipientAddress, undefined, {
330212
+ const transaction = travelRule.mode === "localentity" ? await withdrawViaLocalEntity(broker, {
330213
+ code: symbol2,
330214
+ amount: transferValue.amount,
330215
+ address: transferValue.recipientAddress,
330216
+ network: withdrawNetwork.exchangeNetworkId,
330217
+ questionnaire: travelRule.questionnaire,
330218
+ params: transferValue.params
330219
+ }) : await broker.withdraw(symbol2, transferValue.amount, transferValue.recipientAddress, undefined, {
330119
330220
  ...transferValue.params ?? {},
330120
330221
  network: withdrawNetwork.exchangeNetworkId
330121
330222
  });
@@ -331262,20 +331363,20 @@ class CEXBroker {
331262
331363
  this.brokers = createBrokerPool(configMap);
331263
331364
  }
331264
331365
  loadExchangeCredentials(creds) {
331265
- const schema = import_joi2.default.object().pattern(import_joi2.default.string().allow(...BrokerList).required(), import_joi2.default.object({
331266
- apiKey: import_joi2.default.string().required(),
331267
- apiSecret: import_joi2.default.string().required(),
331268
- role: import_joi2.default.string().valid("master", "subaccount").optional(),
331269
- email: import_joi2.default.string().optional(),
331270
- subAccountId: import_joi2.default.string().optional(),
331271
- uid: import_joi2.default.string().optional(),
331272
- secondaryKeys: import_joi2.default.array().items(import_joi2.default.object({
331273
- apiKey: import_joi2.default.string().required(),
331274
- apiSecret: import_joi2.default.string().required(),
331275
- role: import_joi2.default.string().valid("master", "subaccount").optional(),
331276
- email: import_joi2.default.string().optional(),
331277
- subAccountId: import_joi2.default.string().optional(),
331278
- uid: import_joi2.default.string().optional()
331366
+ const schema = import_joi3.default.object().pattern(import_joi3.default.string().allow(...BrokerList).required(), import_joi3.default.object({
331367
+ apiKey: import_joi3.default.string().required(),
331368
+ apiSecret: import_joi3.default.string().required(),
331369
+ role: import_joi3.default.string().valid("master", "subaccount").optional(),
331370
+ email: import_joi3.default.string().optional(),
331371
+ subAccountId: import_joi3.default.string().optional(),
331372
+ uid: import_joi3.default.string().optional(),
331373
+ secondaryKeys: import_joi3.default.array().items(import_joi3.default.object({
331374
+ apiKey: import_joi3.default.string().required(),
331375
+ apiSecret: import_joi3.default.string().required(),
331376
+ role: import_joi3.default.string().valid("master", "subaccount").optional(),
331377
+ email: import_joi3.default.string().optional(),
331378
+ subAccountId: import_joi3.default.string().optional(),
331379
+ uid: import_joi3.default.string().optional()
331279
331380
  })).default([])
331280
331381
  })).required();
331281
331382
  const { value, error: error48 } = schema.validate(creds);
@@ -3,6 +3,7 @@ import type { PolicyConfig } from "../types";
3
3
  import { type BrokerAccount } from "./broker";
4
4
  export { authenticateRequest } from "./auth";
5
5
  export { applyCommonExchangeConfig, type BrokerAccount, BrokerAccountPreconditionError, type BrokerPoolEntry, createBroker, createBrokerPool, createPublicBroker, getCurrentBrokerSelector, resolveBrokerAccount, selectBroker, selectBrokerAccount, } from "./broker";
6
+ export { australiaQuestionnaireSchema, registerBinanceTravelRuleWithdrawEndpoint, resolveTravelRuleDecision, type TravelRuleDecision, withdrawViaLocalEntity, } from "./travel-rule";
6
7
  export { buildHttpClientOverrideFromMetadata, createVerityHttpClientOverride, verityHttpClientOverridePredicate, } from "./verity";
7
8
  /**
8
9
  * Loads and validates policy configuration
@@ -0,0 +1,44 @@
1
+ import type { Exchange } from "@usherlabs/ccxt";
2
+ import Joi from "joi";
3
+ import type { PolicyConfig, TravelRuleQuestionnaire } from "../types";
4
+ export declare const australiaQuestionnaireSchema: Joi.ObjectSchema<any>;
5
+ export type TravelRuleDecision = {
6
+ mode: "standard";
7
+ } | {
8
+ mode: "localentity";
9
+ questionnaire: TravelRuleQuestionnaire;
10
+ } | {
11
+ mode: "denied";
12
+ error: string;
13
+ };
14
+ /**
15
+ * Decides whether a withdrawal must use Binance's travel-rule endpoint.
16
+ *
17
+ * Travel rule is opt-in per exchange via the `enabled` flag, so a non-AU account
18
+ * keeps using the standard endpoint. When enabled, the destination address must
19
+ * have a configured questionnaire; if it does not we fail closed rather than fall
20
+ * back to the standard endpoint (which would just reproduce the -4104 rejection).
21
+ */
22
+ export declare function resolveTravelRuleDecision(policy: PolicyConfig, exchange: string, recipientAddress: string): TravelRuleDecision;
23
+ /**
24
+ * Registers Binance's `localentity/withdraw/apply` endpoint on the exchange
25
+ * instance. No-op for non-Binance exchanges. Idempotent — ccxt just reassigns
26
+ * the generated implicit method if called again.
27
+ */
28
+ export declare function registerBinanceTravelRuleWithdrawEndpoint(exchange: Exchange): void;
29
+ type LocalEntityWithdrawArgs = {
30
+ code: string;
31
+ amount: number;
32
+ address: string;
33
+ network: string;
34
+ questionnaire: TravelRuleQuestionnaire;
35
+ params?: Record<string, string | number>;
36
+ };
37
+ /**
38
+ * Mirrors ccxt's `binance.withdraw` currency/network/precision handling, but
39
+ * targets the travel-rule endpoint and attaches the questionnaire. ccxt's
40
+ * `urlencode` applies `encodeURIComponent` to the value, satisfying Binance's
41
+ * requirement that the questionnaire JSON be URL-encoded in the request body.
42
+ */
43
+ export declare function withdrawViaLocalEntity(broker: Exchange, args: LocalEntityWithdrawArgs): Promise<import("@usherlabs/ccxt").Transaction>;
44
+ export {};
package/dist/index.js CHANGED
@@ -78926,7 +78926,7 @@ class binance extends binance_default {
78926
78926
  }
78927
78927
  if (api === "sapi" && path === "asset/dust") {
78928
78928
  query = this.urlencodeWithArrayRepeat(extendedParams);
78929
- } else if (path === "batchOrders" || path.indexOf("sub-account") >= 0 || path === "capital/withdraw/apply" || path.indexOf("staking") >= 0 || path.indexOf("simple-earn") >= 0) {
78929
+ } 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) {
78930
78930
  if (method === "DELETE" && path === "batchOrders") {
78931
78931
  const orderidlist = this.safeList(extendedParams, "orderidlist", []);
78932
78932
  const origclientorderidlist = this.safeList(extendedParams, "origclientorderidlist", []);
@@ -270096,11 +270096,11 @@ var ccxt = Object.assign({ version: version2, Exchange, Precise, exchanges: Obje
270096
270096
  var ccxt_default = ccxt;
270097
270097
 
270098
270098
  // src/index.ts
270099
- var import_joi2 = __toESM(require_lib4(), 1);
270099
+ var import_joi3 = __toESM(require_lib4(), 1);
270100
270100
  import { unwatchFile, watchFile } from "fs";
270101
270101
 
270102
270102
  // src/helpers/index.ts
270103
- var import_joi = __toESM(require_lib4(), 1);
270103
+ var import_joi2 = __toESM(require_lib4(), 1);
270104
270104
  import fs from "fs";
270105
270105
 
270106
270106
  // src/helpers/exchange-credentials.ts
@@ -272784,6 +272784,81 @@ if (process.env.LOG_LEVEL !== "debug") {
272784
272784
  }
272785
272785
  var log = baseLogger;
272786
272786
 
272787
+ // src/helpers/travel-rule.ts
272788
+ var import_joi = __toESM(require_lib4(), 1);
272789
+ var isAnotherBeneficiary = import_joi.default.number().valid(2).required();
272790
+ var isIndividual = import_joi.default.number().valid(0).required();
272791
+ var isCorporate = import_joi.default.number().valid(1).required();
272792
+ var isSendToVasp = import_joi.default.number().valid(2).required();
272793
+ var isVaspOthers = import_joi.default.string().valid("others").required();
272794
+ function requiredWhen(base2, ref, is) {
272795
+ return base2.when(ref, {
272796
+ is,
272797
+ then: import_joi.default.required(),
272798
+ otherwise: import_joi.default.forbidden()
272799
+ });
272800
+ }
272801
+ var australiaQuestionnaireSchema = import_joi.default.object({
272802
+ isAddressOwner: import_joi.default.number().valid(1, 2).required(),
272803
+ sendTo: import_joi.default.number().valid(1, 2).required(),
272804
+ declaration: import_joi.default.boolean().valid(true).required(),
272805
+ bnfType: requiredWhen(import_joi.default.number().valid(0, 1), "isAddressOwner", isAnotherBeneficiary),
272806
+ bnfFirstName: requiredWhen(import_joi.default.string(), "bnfType", isIndividual),
272807
+ bnfLastName: requiredWhen(import_joi.default.string(), "bnfType", isIndividual),
272808
+ country: requiredWhen(import_joi.default.string(), "bnfType", isIndividual),
272809
+ city: requiredWhen(import_joi.default.string(), "bnfType", isIndividual),
272810
+ bnfCorpName: requiredWhen(import_joi.default.string(), "bnfType", isCorporate),
272811
+ bnfCorpCountry: requiredWhen(import_joi.default.string(), "bnfType", isCorporate),
272812
+ bnfCorpCity: requiredWhen(import_joi.default.string(), "bnfType", isCorporate),
272813
+ vasp: requiredWhen(import_joi.default.string(), "sendTo", isSendToVasp),
272814
+ vaspName: requiredWhen(import_joi.default.string(), "vasp", isVaspOthers)
272815
+ });
272816
+ function resolveTravelRuleDecision(policy, exchange, recipientAddress) {
272817
+ const rules = policy.travelRule?.rule ?? [];
272818
+ const exchangeNorm = exchange.trim().toUpperCase();
272819
+ const entry = rules.find((rule) => rule.exchange.trim().toUpperCase() === exchangeNorm);
272820
+ if (!entry || !entry.enabled) {
272821
+ return { mode: "standard" };
272822
+ }
272823
+ const addressNorm = recipientAddress.trim().toLowerCase();
272824
+ const match = Object.entries(entry.addresses).find(([address]) => address.trim().toLowerCase() === addressNorm);
272825
+ if (!match) {
272826
+ return {
272827
+ mode: "denied",
272828
+ error: `no travel-rule questionnaire configured for ${exchangeNorm} address ${recipientAddress}`
272829
+ };
272830
+ }
272831
+ return { mode: "localentity", questionnaire: match[1].questionnaire };
272832
+ }
272833
+ function registerBinanceTravelRuleWithdrawEndpoint(exchange) {
272834
+ if (exchange.id !== "binance") {
272835
+ return;
272836
+ }
272837
+ exchange.defineRestApi({ sapi: { post: { "localentity/withdraw/apply": 4.0002 } } }, "request");
272838
+ }
272839
+ async function withdrawViaLocalEntity(broker, args) {
272840
+ const exchange = broker;
272841
+ if (typeof exchange.sapiPostLocalentityWithdrawApply !== "function") {
272842
+ throw new Error("binance_localentity_withdraw_unavailable: travel-rule withdraw endpoint is not registered on this exchange instance");
272843
+ }
272844
+ broker.checkAddress(args.address);
272845
+ await broker.loadMarkets();
272846
+ const currency = broker.currency(args.code);
272847
+ const networks = broker.safeDict(broker.options, "networks", {});
272848
+ const networkUpper = args.network.trim().toUpperCase();
272849
+ const mappedNetwork = broker.safeString(networks, networkUpper, networkUpper);
272850
+ const request = {
272851
+ ...args.params,
272852
+ coin: currency.id,
272853
+ address: args.address,
272854
+ amount: broker.currencyToPrecision(args.code, args.amount),
272855
+ network: mappedNetwork,
272856
+ questionnaire: JSON.stringify(args.questionnaire)
272857
+ };
272858
+ const response = await exchange.sapiPostLocalentityWithdrawApply(request);
272859
+ return broker.parseTransaction(response, currency);
272860
+ }
272861
+
272787
272862
  // src/helpers/broker.ts
272788
272863
  class BrokerAccountPreconditionError extends Error {
272789
272864
  constructor(message) {
@@ -272808,6 +272883,7 @@ function applyCommonExchangeConfig(exchange) {
272808
272883
  recvWindow: 60000,
272809
272884
  adjustForTimeDifference: true
272810
272885
  });
272886
+ registerBinanceTravelRuleWithdrawEndpoint(exchange);
272811
272887
  }
272812
272888
  function createBroker(cex3, credsOrMetadata) {
272813
272889
  let apiKey;
@@ -273224,36 +273300,47 @@ var verityHttpClientOverridePredicate = ({
273224
273300
  function loadPolicy(policyPath) {
273225
273301
  try {
273226
273302
  const policyData = fs.readFileSync(policyPath, "utf8");
273227
- const withdrawRuleEntrySchema = import_joi.default.object({
273228
- exchange: import_joi.default.string().required(),
273229
- network: import_joi.default.string().required(),
273230
- whitelist: import_joi.default.array().items(import_joi.default.string()).required(),
273231
- coins: import_joi.default.array().items(import_joi.default.string()).optional()
273303
+ const withdrawRuleEntrySchema = import_joi2.default.object({
273304
+ exchange: import_joi2.default.string().required(),
273305
+ network: import_joi2.default.string().required(),
273306
+ whitelist: import_joi2.default.array().items(import_joi2.default.string()).required(),
273307
+ coins: import_joi2.default.array().items(import_joi2.default.string()).optional()
273232
273308
  });
273233
- const depositRuleEntrySchema = import_joi.default.object({
273234
- exchange: import_joi.default.string().required(),
273235
- network: import_joi.default.string().required(),
273236
- coins: import_joi.default.array().items(import_joi.default.string()).optional()
273309
+ const depositRuleEntrySchema = import_joi2.default.object({
273310
+ exchange: import_joi2.default.string().required(),
273311
+ network: import_joi2.default.string().required(),
273312
+ coins: import_joi2.default.array().items(import_joi2.default.string()).optional()
273237
273313
  });
273238
- const orderRuleSchema = import_joi.default.object({
273239
- markets: import_joi.default.array().items(import_joi.default.string()).required(),
273240
- limits: import_joi.default.array().items(import_joi.default.object({
273241
- from: import_joi.default.string().required(),
273242
- to: import_joi.default.string().required(),
273243
- min: import_joi.default.number().required(),
273244
- max: import_joi.default.number().required()
273314
+ const orderRuleSchema = import_joi2.default.object({
273315
+ markets: import_joi2.default.array().items(import_joi2.default.string()).required(),
273316
+ limits: import_joi2.default.array().items(import_joi2.default.object({
273317
+ from: import_joi2.default.string().required(),
273318
+ to: import_joi2.default.string().required(),
273319
+ min: import_joi2.default.number().required(),
273320
+ max: import_joi2.default.number().required()
273245
273321
  })).default([])
273246
273322
  });
273247
- const policyConfigSchema = import_joi.default.object({
273248
- withdraw: import_joi.default.object({
273249
- rule: import_joi.default.array().items(withdrawRuleEntrySchema).min(1).required()
273323
+ const travelRuleEntrySchema = import_joi2.default.object({
273324
+ exchange: import_joi2.default.string().uppercase().valid("BINANCE").required(),
273325
+ enabled: import_joi2.default.boolean().required(),
273326
+ description: import_joi2.default.string().optional(),
273327
+ addresses: import_joi2.default.object().pattern(import_joi2.default.string(), import_joi2.default.object({
273328
+ questionnaire: australiaQuestionnaireSchema.required()
273329
+ })).required()
273330
+ });
273331
+ const policyConfigSchema = import_joi2.default.object({
273332
+ withdraw: import_joi2.default.object({
273333
+ rule: import_joi2.default.array().items(withdrawRuleEntrySchema).min(1).required()
273250
273334
  }).required(),
273251
- deposit: import_joi.default.object({
273252
- rule: import_joi.default.array().items(depositRuleEntrySchema).optional()
273335
+ deposit: import_joi2.default.object({
273336
+ rule: import_joi2.default.array().items(depositRuleEntrySchema).optional()
273253
273337
  }).required(),
273254
- order: import_joi.default.object({
273338
+ order: import_joi2.default.object({
273255
273339
  rule: orderRuleSchema.required()
273256
- }).required()
273340
+ }).required(),
273341
+ travelRule: import_joi2.default.object({
273342
+ rule: import_joi2.default.array().items(travelRuleEntrySchema).required()
273343
+ }).optional()
273257
273344
  });
273258
273345
  const { error, value } = policyConfigSchema.validate(JSON.parse(policyData));
273259
273346
  if (error) {
@@ -293067,8 +293154,22 @@ async function handleWithdraw(ctx) {
293067
293154
  message: `policy_withdrawal_denied: ${transferValidation.error}`
293068
293155
  }, null);
293069
293156
  }
293157
+ const travelRule = resolveTravelRuleDecision(policy, cex3, transferValue.recipientAddress);
293158
+ if (travelRule.mode === "denied") {
293159
+ return ctx.wrappedCallback({
293160
+ code: grpc10.status.FAILED_PRECONDITION,
293161
+ message: `travel_rule_denied: ${travelRule.error}`
293162
+ }, null);
293163
+ }
293070
293164
  try {
293071
- const transaction = await broker.withdraw(symbol2, transferValue.amount, transferValue.recipientAddress, undefined, {
293165
+ const transaction = travelRule.mode === "localentity" ? await withdrawViaLocalEntity(broker, {
293166
+ code: symbol2,
293167
+ amount: transferValue.amount,
293168
+ address: transferValue.recipientAddress,
293169
+ network: withdrawNetwork.exchangeNetworkId,
293170
+ questionnaire: travelRule.questionnaire,
293171
+ params: transferValue.params
293172
+ }) : await broker.withdraw(symbol2, transferValue.amount, transferValue.recipientAddress, undefined, {
293072
293173
  ...transferValue.params ?? {},
293073
293174
  network: withdrawNetwork.exchangeNetworkId
293074
293175
  });
@@ -294216,20 +294317,20 @@ class CEXBroker {
294216
294317
  this.brokers = createBrokerPool(configMap);
294217
294318
  }
294218
294319
  loadExchangeCredentials(creds) {
294219
- const schema = import_joi2.default.object().pattern(import_joi2.default.string().allow(...BrokerList).required(), import_joi2.default.object({
294220
- apiKey: import_joi2.default.string().required(),
294221
- apiSecret: import_joi2.default.string().required(),
294222
- role: import_joi2.default.string().valid("master", "subaccount").optional(),
294223
- email: import_joi2.default.string().optional(),
294224
- subAccountId: import_joi2.default.string().optional(),
294225
- uid: import_joi2.default.string().optional(),
294226
- secondaryKeys: import_joi2.default.array().items(import_joi2.default.object({
294227
- apiKey: import_joi2.default.string().required(),
294228
- apiSecret: import_joi2.default.string().required(),
294229
- role: import_joi2.default.string().valid("master", "subaccount").optional(),
294230
- email: import_joi2.default.string().optional(),
294231
- subAccountId: import_joi2.default.string().optional(),
294232
- uid: import_joi2.default.string().optional()
294320
+ const schema = import_joi3.default.object().pattern(import_joi3.default.string().allow(...BrokerList).required(), import_joi3.default.object({
294321
+ apiKey: import_joi3.default.string().required(),
294322
+ apiSecret: import_joi3.default.string().required(),
294323
+ role: import_joi3.default.string().valid("master", "subaccount").optional(),
294324
+ email: import_joi3.default.string().optional(),
294325
+ subAccountId: import_joi3.default.string().optional(),
294326
+ uid: import_joi3.default.string().optional(),
294327
+ secondaryKeys: import_joi3.default.array().items(import_joi3.default.object({
294328
+ apiKey: import_joi3.default.string().required(),
294329
+ apiSecret: import_joi3.default.string().required(),
294330
+ role: import_joi3.default.string().valid("master", "subaccount").optional(),
294331
+ email: import_joi3.default.string().optional(),
294332
+ subAccountId: import_joi3.default.string().optional(),
294333
+ uid: import_joi3.default.string().optional()
294233
294334
  })).default([])
294234
294335
  })).required();
294235
294336
  const { value, error: error48 } = schema.validate(creds);
@@ -294316,4 +294417,4 @@ export {
294316
294417
  CEXBroker as default
294317
294418
  };
294318
294419
 
294319
- //# debugId=6D0E11DC0BFB633164756E2164756E21
294420
+ //# debugId=5C43863FE4632C1564756E2164756E21