@usherlabs/cex-broker 0.2.14 → 0.2.15
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 +141 -40
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/travel-rule.d.ts +44 -0
- package/dist/index.js +142 -41
- package/dist/index.js.map +8 -7
- package/dist/types.d.ts +27 -0
- package/package.json +1 -1
package/dist/commands/cli.js
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
313975
|
-
exchange:
|
|
313976
|
-
network:
|
|
313977
|
-
whitelist:
|
|
313978
|
-
coins:
|
|
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 =
|
|
313981
|
-
exchange:
|
|
313982
|
-
network:
|
|
313983
|
-
coins:
|
|
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 =
|
|
313986
|
-
markets:
|
|
313987
|
-
limits:
|
|
313988
|
-
from:
|
|
313989
|
-
to:
|
|
313990
|
-
min:
|
|
313991
|
-
max:
|
|
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
|
|
313995
|
-
|
|
313996
|
-
|
|
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:
|
|
313999
|
-
rule:
|
|
314082
|
+
deposit: import_joi2.default.object({
|
|
314083
|
+
rule: import_joi2.default.array().items(depositRuleEntrySchema).optional()
|
|
314000
314084
|
}).required(),
|
|
314001
|
-
order:
|
|
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 =
|
|
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 =
|
|
331266
|
-
apiKey:
|
|
331267
|
-
apiSecret:
|
|
331268
|
-
role:
|
|
331269
|
-
email:
|
|
331270
|
-
subAccountId:
|
|
331271
|
-
uid:
|
|
331272
|
-
secondaryKeys:
|
|
331273
|
-
apiKey:
|
|
331274
|
-
apiSecret:
|
|
331275
|
-
role:
|
|
331276
|
-
email:
|
|
331277
|
-
subAccountId:
|
|
331278
|
-
uid:
|
|
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);
|
package/dist/helpers/index.d.ts
CHANGED
|
@@ -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
|
@@ -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
|
|
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
|
|
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 =
|
|
273228
|
-
exchange:
|
|
273229
|
-
network:
|
|
273230
|
-
whitelist:
|
|
273231
|
-
coins:
|
|
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 =
|
|
273234
|
-
exchange:
|
|
273235
|
-
network:
|
|
273236
|
-
coins:
|
|
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 =
|
|
273239
|
-
markets:
|
|
273240
|
-
limits:
|
|
273241
|
-
from:
|
|
273242
|
-
to:
|
|
273243
|
-
min:
|
|
273244
|
-
max:
|
|
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
|
|
273248
|
-
|
|
273249
|
-
|
|
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:
|
|
273252
|
-
rule:
|
|
273335
|
+
deposit: import_joi2.default.object({
|
|
273336
|
+
rule: import_joi2.default.array().items(depositRuleEntrySchema).optional()
|
|
273253
273337
|
}).required(),
|
|
273254
|
-
order:
|
|
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 =
|
|
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 =
|
|
294220
|
-
apiKey:
|
|
294221
|
-
apiSecret:
|
|
294222
|
-
role:
|
|
294223
|
-
email:
|
|
294224
|
-
subAccountId:
|
|
294225
|
-
uid:
|
|
294226
|
-
secondaryKeys:
|
|
294227
|
-
apiKey:
|
|
294228
|
-
apiSecret:
|
|
294229
|
-
role:
|
|
294230
|
-
email:
|
|
294231
|
-
subAccountId:
|
|
294232
|
-
uid:
|
|
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=
|
|
294420
|
+
//# debugId=8F76D79C41F9E70764756E2164756E21
|