@usherlabs/cex-broker 0.2.9 → 0.2.10
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 +172 -120
- package/dist/helpers/index.d.ts +7 -17
- package/dist/index.js +173 -121
- package/dist/index.js.map +7 -7
- package/dist/proto/cex_broker/Action.d.ts +2 -1
- package/dist/proto/node.descriptor.d.ts +1 -0
- package/dist/proto/node.descriptor.ts +2 -1
- package/dist/proto/node.proto +1 -0
- package/dist/schemas/action-payloads.d.ts +6 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -272748,16 +272748,18 @@ if (process.env.LOG_LEVEL !== "debug") {
|
|
|
272748
272748
|
var log = baseLogger;
|
|
272749
272749
|
|
|
272750
272750
|
// src/helpers/index.ts
|
|
272751
|
-
class
|
|
272752
|
-
|
|
272753
|
-
|
|
272754
|
-
|
|
272755
|
-
}
|
|
272756
|
-
function isMasterBrokerAccount(account) {
|
|
272757
|
-
return account.label === "primary" || account.role === "master";
|
|
272751
|
+
class BrokerAccountPreconditionError extends Error {
|
|
272752
|
+
constructor(message) {
|
|
272753
|
+
super(message);
|
|
272754
|
+
this.name = "BrokerAccountPreconditionError";
|
|
272755
|
+
}
|
|
272758
272756
|
}
|
|
272759
|
-
function
|
|
272760
|
-
|
|
272757
|
+
function requireDestinationEmail(dest, transferType) {
|
|
272758
|
+
const email = dest.email?.trim();
|
|
272759
|
+
if (!email) {
|
|
272760
|
+
throw new BrokerAccountPreconditionError(`Destination account '${dest.label}' requires an email configured for ${transferType} transfers`);
|
|
272761
|
+
}
|
|
272762
|
+
return email;
|
|
272761
272763
|
}
|
|
272762
272764
|
function authenticateRequest(call, whitelistIps) {
|
|
272763
272765
|
const clientIp = call.getPeer().split(":")[0];
|
|
@@ -273079,81 +273081,50 @@ function validateWithdraw(policy, exchange, network, recipientAddress, _amount,
|
|
|
273079
273081
|
}
|
|
273080
273082
|
return { valid: true };
|
|
273081
273083
|
}
|
|
273082
|
-
function
|
|
273083
|
-
const raw = selector2?.trim().toLowerCase() ?? defaultSelector;
|
|
273084
|
-
if (raw === "current") {
|
|
273085
|
-
return getCurrentBrokerSelector(metadata);
|
|
273086
|
-
}
|
|
273087
|
-
if (raw === "primary") {
|
|
273088
|
-
return "primary";
|
|
273089
|
-
}
|
|
273090
|
-
const secondaryMatch = raw.match(/^secondary:(\d+)$/);
|
|
273091
|
-
if (secondaryMatch) {
|
|
273092
|
-
return `secondary:${secondaryMatch[1]}`;
|
|
273093
|
-
}
|
|
273094
|
-
throw new WithdrawRoutingError(`Invalid account selector "${selector2}"`);
|
|
273095
|
-
}
|
|
273096
|
-
async function transferBinanceSubAccountToMaster(source, code, amount) {
|
|
273084
|
+
async function transferBinanceInternal(source, dest, code, amount) {
|
|
273097
273085
|
const exchange = source.exchange;
|
|
273098
|
-
if (typeof exchange.sapiPostSubAccountTransferSubToMaster !== "function") {
|
|
273099
|
-
throw new WithdrawRoutingUnavailableError("Binance sub-account to master transfer is unavailable in this CCXT build");
|
|
273100
|
-
}
|
|
273101
273086
|
await source.exchange.loadMarkets();
|
|
273102
273087
|
const currency = source.exchange.currency(code);
|
|
273103
|
-
|
|
273104
|
-
|
|
273105
|
-
|
|
273106
|
-
|
|
273107
|
-
|
|
273108
|
-
|
|
273109
|
-
|
|
273110
|
-
|
|
273111
|
-
|
|
273112
|
-
|
|
273113
|
-
|
|
273114
|
-
|
|
273115
|
-
|
|
273116
|
-
|
|
273117
|
-
network,
|
|
273118
|
-
params,
|
|
273119
|
-
routeViaMaster,
|
|
273120
|
-
sourceAccount,
|
|
273121
|
-
masterAccount
|
|
273122
|
-
} = args;
|
|
273123
|
-
const withdrawParams = {
|
|
273124
|
-
...params ?? {},
|
|
273125
|
-
network
|
|
273126
|
-
};
|
|
273127
|
-
if (!routeViaMaster) {
|
|
273128
|
-
return await selectedBroker.withdraw(code, amount, recipientAddress, undefined, withdrawParams);
|
|
273129
|
-
}
|
|
273130
|
-
const sourceSelector = normalizeAccountSelector(sourceAccount, metadata, "current");
|
|
273131
|
-
const masterSelector = normalizeAccountSelector(masterAccount, metadata, "primary");
|
|
273132
|
-
if (!brokers) {
|
|
273133
|
-
throw new WithdrawRoutingUnavailableError("Routed withdraw requires configured broker accounts");
|
|
273134
|
-
}
|
|
273135
|
-
const source = resolveBrokerAccount(brokers, sourceSelector);
|
|
273136
|
-
if (!source) {
|
|
273137
|
-
throw new WithdrawRoutingError(`Source account ${sourceSelector} is not configured`);
|
|
273138
|
-
}
|
|
273139
|
-
const master = resolveBrokerAccount(brokers, masterSelector);
|
|
273140
|
-
if (!master) {
|
|
273141
|
-
throw new WithdrawRoutingError(`Master account ${masterSelector} is not configured`);
|
|
273142
|
-
}
|
|
273143
|
-
if (!isMasterBrokerAccount(master)) {
|
|
273144
|
-
throw new WithdrawRoutingError(`Master account ${masterSelector} must resolve to the primary/master account`);
|
|
273145
|
-
}
|
|
273146
|
-
if (source.label === master.label) {
|
|
273147
|
-
return await master.exchange.withdraw(code, amount, recipientAddress, undefined, withdrawParams);
|
|
273088
|
+
const asset = currency.id;
|
|
273089
|
+
const amountStr = source.exchange.currencyToPrecision(code, amount);
|
|
273090
|
+
const isSourceSecondary = source.label.startsWith("secondary:");
|
|
273091
|
+
const isDestPrimary = dest.label === "primary";
|
|
273092
|
+
const isDestSecondary = dest.label.startsWith("secondary:");
|
|
273093
|
+
const isSourcePrimary = source.label === "primary";
|
|
273094
|
+
if (isSourceSecondary && isDestPrimary) {
|
|
273095
|
+
if (typeof exchange.sapiPostSubAccountTransferSubToMaster !== "function") {
|
|
273096
|
+
throw new Error("Binance sub\u2192master transfer is unavailable in this CCXT build");
|
|
273097
|
+
}
|
|
273098
|
+
return await exchange.sapiPostSubAccountTransferSubToMaster({
|
|
273099
|
+
asset,
|
|
273100
|
+
amount: amountStr
|
|
273101
|
+
});
|
|
273148
273102
|
}
|
|
273149
|
-
if (
|
|
273150
|
-
|
|
273103
|
+
if (isSourceSecondary && isDestSecondary) {
|
|
273104
|
+
if (typeof exchange.sapiPostSubAccountTransferSubToSub !== "function") {
|
|
273105
|
+
throw new Error("Binance sub\u2192sub transfer is unavailable in this CCXT build");
|
|
273106
|
+
}
|
|
273107
|
+
const destEmail = requireDestinationEmail(dest, "sub-to-sub");
|
|
273108
|
+
return await exchange.sapiPostSubAccountTransferSubToSub({
|
|
273109
|
+
toEmail: destEmail,
|
|
273110
|
+
asset,
|
|
273111
|
+
amount: amountStr
|
|
273112
|
+
});
|
|
273151
273113
|
}
|
|
273152
|
-
if (
|
|
273153
|
-
|
|
273114
|
+
if (isSourcePrimary && isDestSecondary) {
|
|
273115
|
+
if (typeof exchange.sapiPostSubAccountUniversalTransfer !== "function") {
|
|
273116
|
+
throw new Error("Binance universal transfer is unavailable in this CCXT build");
|
|
273117
|
+
}
|
|
273118
|
+
const destEmail = requireDestinationEmail(dest, "primary-to-sub");
|
|
273119
|
+
return await exchange.sapiPostSubAccountUniversalTransfer({
|
|
273120
|
+
fromAccountType: "SPOT",
|
|
273121
|
+
toAccountType: "SPOT",
|
|
273122
|
+
toEmail: destEmail,
|
|
273123
|
+
asset,
|
|
273124
|
+
amount: amountStr
|
|
273125
|
+
});
|
|
273154
273126
|
}
|
|
273155
|
-
|
|
273156
|
-
return await master.exchange.withdraw(code, amount, recipientAddress, undefined, withdrawParams);
|
|
273127
|
+
throw new Error(`Unsupported transfer direction: ${source.label} \u2192 ${dest.label}`);
|
|
273157
273128
|
}
|
|
273158
273129
|
function isMarketPatternMatch(pattern, broker, fromToken, toToken) {
|
|
273159
273130
|
const normalizedPattern = pattern.toUpperCase().trim();
|
|
@@ -277336,7 +277307,8 @@ var Action = {
|
|
|
277336
277307
|
FetchCurrency: 9,
|
|
277337
277308
|
Call: 10,
|
|
277338
277309
|
FetchAccountId: 11,
|
|
277339
|
-
FetchFees: 12
|
|
277310
|
+
FetchFees: 12,
|
|
277311
|
+
InternalTransfer: 13
|
|
277340
277312
|
};
|
|
277341
277313
|
|
|
277342
277314
|
// src/proto/cex_broker/SubscriptionType.ts
|
|
@@ -277467,7 +277439,8 @@ var descriptor = {
|
|
|
277467
277439
|
FetchCurrency: 9,
|
|
277468
277440
|
Call: 10,
|
|
277469
277441
|
FetchAccountId: 11,
|
|
277470
|
-
FetchFees: 12
|
|
277442
|
+
FetchFees: 12,
|
|
277443
|
+
InternalTransfer: 13
|
|
277471
277444
|
}
|
|
277472
277445
|
}
|
|
277473
277446
|
}
|
|
@@ -291053,11 +291026,13 @@ var WithdrawPayloadSchema = exports_external.object({
|
|
|
291053
291026
|
recipientAddress: exports_external.string().min(1),
|
|
291054
291027
|
amount: exports_external.coerce.number().positive(),
|
|
291055
291028
|
chain: exports_external.string().min(1),
|
|
291056
|
-
routeViaMaster: booleanLikeSchema.optional().default(false),
|
|
291057
|
-
sourceAccount: exports_external.string().min(1).optional(),
|
|
291058
|
-
masterAccount: exports_external.string().min(1).optional(),
|
|
291059
291029
|
params: exports_external.preprocess(parseJsonString, stringNumberRecordSchema).default({})
|
|
291060
291030
|
});
|
|
291031
|
+
var InternalTransferPayloadSchema = exports_external.object({
|
|
291032
|
+
amount: exports_external.coerce.number().positive(),
|
|
291033
|
+
fromAccount: exports_external.string().min(1).optional(),
|
|
291034
|
+
toAccount: exports_external.string().min(1).optional()
|
|
291035
|
+
});
|
|
291061
291036
|
var CreateOrderPayloadSchema = exports_external.object({
|
|
291062
291037
|
orderType: exports_external.enum(["market", "limit"]).default("limit"),
|
|
291063
291038
|
amount: exports_external.coerce.number().positive(),
|
|
@@ -291105,6 +291080,31 @@ function safeLogError(context3, error48) {
|
|
|
291105
291080
|
console.error(context3, error48);
|
|
291106
291081
|
}
|
|
291107
291082
|
}
|
|
291083
|
+
function mapCcxtErrorToGrpcStatus(error48) {
|
|
291084
|
+
if (error48 instanceof ccxt_default.AuthenticationError)
|
|
291085
|
+
return grpc.status.UNAUTHENTICATED;
|
|
291086
|
+
if (error48 instanceof ccxt_default.PermissionDenied)
|
|
291087
|
+
return grpc.status.PERMISSION_DENIED;
|
|
291088
|
+
if (error48 instanceof ccxt_default.InsufficientFunds)
|
|
291089
|
+
return grpc.status.FAILED_PRECONDITION;
|
|
291090
|
+
if (error48 instanceof ccxt_default.InvalidAddress)
|
|
291091
|
+
return grpc.status.INVALID_ARGUMENT;
|
|
291092
|
+
if (error48 instanceof ccxt_default.BadSymbol)
|
|
291093
|
+
return grpc.status.NOT_FOUND;
|
|
291094
|
+
if (error48 instanceof ccxt_default.BadRequest)
|
|
291095
|
+
return grpc.status.INVALID_ARGUMENT;
|
|
291096
|
+
if (error48 instanceof ccxt_default.NotSupported)
|
|
291097
|
+
return grpc.status.UNIMPLEMENTED;
|
|
291098
|
+
if (error48 instanceof ccxt_default.RateLimitExceeded)
|
|
291099
|
+
return grpc.status.RESOURCE_EXHAUSTED;
|
|
291100
|
+
if (error48 instanceof ccxt_default.OnMaintenance)
|
|
291101
|
+
return grpc.status.UNAVAILABLE;
|
|
291102
|
+
if (error48 instanceof ccxt_default.ExchangeNotAvailable)
|
|
291103
|
+
return grpc.status.UNAVAILABLE;
|
|
291104
|
+
if (error48 instanceof ccxt_default.NetworkError)
|
|
291105
|
+
return grpc.status.UNAVAILABLE;
|
|
291106
|
+
return;
|
|
291107
|
+
}
|
|
291108
291108
|
function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, otelMetrics) {
|
|
291109
291109
|
const server = new grpc.Server;
|
|
291110
291110
|
server.addService(cexNode.cex_service.service, {
|
|
@@ -291160,7 +291160,8 @@ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, ot
|
|
|
291160
291160
|
message: "`action` AND `cex` fields are required"
|
|
291161
291161
|
}, null);
|
|
291162
291162
|
}
|
|
291163
|
-
const
|
|
291163
|
+
const normalizedCex = cex3.trim().toLowerCase();
|
|
291164
|
+
const broker = selectBroker(brokers[normalizedCex], metadata) ?? createBroker(normalizedCex, metadata);
|
|
291164
291165
|
if (!broker) {
|
|
291165
291166
|
return wrappedCallback({
|
|
291166
291167
|
code: grpc.status.UNAUTHENTICATED,
|
|
@@ -291498,39 +291499,10 @@ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, ot
|
|
|
291498
291499
|
}, null);
|
|
291499
291500
|
}
|
|
291500
291501
|
try {
|
|
291501
|
-
|
|
291502
|
-
|
|
291503
|
-
|
|
291504
|
-
|
|
291505
|
-
brokers: brokers[cex3],
|
|
291506
|
-
metadata,
|
|
291507
|
-
selectedBroker: broker,
|
|
291508
|
-
code: symbol2,
|
|
291509
|
-
amount: transferValue.amount,
|
|
291510
|
-
recipientAddress: transferValue.recipientAddress,
|
|
291511
|
-
network: transferValue.chain,
|
|
291512
|
-
params: transferValue.params,
|
|
291513
|
-
routeViaMaster: transferValue.routeViaMaster,
|
|
291514
|
-
sourceAccount: transferValue.sourceAccount,
|
|
291515
|
-
masterAccount: transferValue.masterAccount
|
|
291516
|
-
});
|
|
291517
|
-
} catch (error48) {
|
|
291518
|
-
if (error48 instanceof WithdrawRoutingUnavailableError) {
|
|
291519
|
-
log.warn("Withdraw routing unavailable, falling back", {
|
|
291520
|
-
cex: cex3,
|
|
291521
|
-
error: error48.message
|
|
291522
|
-
});
|
|
291523
|
-
if (transferValue.routeViaMaster) {
|
|
291524
|
-
throw error48;
|
|
291525
|
-
}
|
|
291526
|
-
transaction = await broker.withdraw(symbol2, transferValue.amount, transferValue.recipientAddress, undefined, {
|
|
291527
|
-
...transferValue.params ?? {},
|
|
291528
|
-
network: transferValue.chain
|
|
291529
|
-
});
|
|
291530
|
-
} else {
|
|
291531
|
-
throw error48;
|
|
291532
|
-
}
|
|
291533
|
-
}
|
|
291502
|
+
const transaction = await broker.withdraw(symbol2, transferValue.amount, transferValue.recipientAddress, undefined, {
|
|
291503
|
+
...transferValue.params ?? {},
|
|
291504
|
+
network: transferValue.chain
|
|
291505
|
+
});
|
|
291534
291506
|
log.info(`Withdraw Result: ${JSON.stringify(transaction)}`);
|
|
291535
291507
|
wrappedCallback(null, {
|
|
291536
291508
|
proof: verityProof,
|
|
@@ -291538,10 +291510,10 @@ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, ot
|
|
|
291538
291510
|
});
|
|
291539
291511
|
} catch (error48) {
|
|
291540
291512
|
safeLogError("Withdraw failed", error48);
|
|
291541
|
-
const
|
|
291513
|
+
const code = mapCcxtErrorToGrpcStatus(error48) ?? grpc.status.INTERNAL;
|
|
291542
291514
|
wrappedCallback({
|
|
291543
|
-
code
|
|
291544
|
-
message: `Withdraw failed: ${
|
|
291515
|
+
code,
|
|
291516
|
+
message: `Withdraw failed: ${getErrorMessage(error48)}`
|
|
291545
291517
|
}, null);
|
|
291546
291518
|
}
|
|
291547
291519
|
break;
|
|
@@ -291714,6 +291686,86 @@ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, ot
|
|
|
291714
291686
|
}, null);
|
|
291715
291687
|
}
|
|
291716
291688
|
break;
|
|
291689
|
+
case Action.InternalTransfer: {
|
|
291690
|
+
if (!symbol2) {
|
|
291691
|
+
return wrappedCallback({
|
|
291692
|
+
code: grpc.status.INVALID_ARGUMENT,
|
|
291693
|
+
message: `ValidationError: Symbol required`
|
|
291694
|
+
}, null);
|
|
291695
|
+
}
|
|
291696
|
+
const parsedPayload = parsePayload(InternalTransferPayloadSchema, call.request.payload);
|
|
291697
|
+
if (!parsedPayload.success) {
|
|
291698
|
+
return wrappedCallback({
|
|
291699
|
+
code: grpc.status.INVALID_ARGUMENT,
|
|
291700
|
+
message: parsedPayload.message
|
|
291701
|
+
}, null);
|
|
291702
|
+
}
|
|
291703
|
+
const transferPayload = parsedPayload.data;
|
|
291704
|
+
if (normalizedCex !== "binance") {
|
|
291705
|
+
return wrappedCallback({
|
|
291706
|
+
code: grpc.status.UNIMPLEMENTED,
|
|
291707
|
+
message: `InternalTransfer is only supported for Binance`
|
|
291708
|
+
}, null);
|
|
291709
|
+
}
|
|
291710
|
+
const pool = brokers[normalizedCex];
|
|
291711
|
+
if (!pool) {
|
|
291712
|
+
return wrappedCallback({
|
|
291713
|
+
code: grpc.status.FAILED_PRECONDITION,
|
|
291714
|
+
message: `No broker accounts configured for ${normalizedCex}`
|
|
291715
|
+
}, null);
|
|
291716
|
+
}
|
|
291717
|
+
const fromSelector = transferPayload.fromAccount ?? getCurrentBrokerSelector(metadata);
|
|
291718
|
+
const toSelector = transferPayload.toAccount ?? "primary";
|
|
291719
|
+
const sourceAccount = resolveBrokerAccount(pool, fromSelector);
|
|
291720
|
+
if (!sourceAccount) {
|
|
291721
|
+
return wrappedCallback({
|
|
291722
|
+
code: grpc.status.INVALID_ARGUMENT,
|
|
291723
|
+
message: `Source account "${fromSelector}" is not configured`
|
|
291724
|
+
}, null);
|
|
291725
|
+
}
|
|
291726
|
+
const destAccount = resolveBrokerAccount(pool, toSelector);
|
|
291727
|
+
if (!destAccount) {
|
|
291728
|
+
return wrappedCallback({
|
|
291729
|
+
code: grpc.status.INVALID_ARGUMENT,
|
|
291730
|
+
message: `Destination account "${toSelector}" is not configured`
|
|
291731
|
+
}, null);
|
|
291732
|
+
}
|
|
291733
|
+
try {
|
|
291734
|
+
if (useVerity) {
|
|
291735
|
+
sourceAccount.exchange.setHttpClientOverride(buildHttpClientOverrideFromMetadata(metadata, verityProverUrl, (proof, notaryPubKey) => {
|
|
291736
|
+
verityProof = proof;
|
|
291737
|
+
log.debug(`Verity proof:`, { proof, notaryPubKey });
|
|
291738
|
+
}), verityHttpClientOverridePredicate);
|
|
291739
|
+
}
|
|
291740
|
+
const result = await transferBinanceInternal(sourceAccount, destAccount, symbol2, transferPayload.amount);
|
|
291741
|
+
wrappedCallback(null, {
|
|
291742
|
+
proof: verityProof,
|
|
291743
|
+
result: JSON.stringify(result)
|
|
291744
|
+
});
|
|
291745
|
+
} catch (error48) {
|
|
291746
|
+
safeLogError("InternalTransfer failed", error48);
|
|
291747
|
+
if (error48 instanceof BrokerAccountPreconditionError) {
|
|
291748
|
+
return wrappedCallback({
|
|
291749
|
+
code: grpc.status.FAILED_PRECONDITION,
|
|
291750
|
+
message: getErrorMessage(error48)
|
|
291751
|
+
}, null);
|
|
291752
|
+
}
|
|
291753
|
+
const msg = getErrorMessage(error48);
|
|
291754
|
+
let code;
|
|
291755
|
+
if (msg.includes("Unsupported transfer direction")) {
|
|
291756
|
+
code = grpc.status.INVALID_ARGUMENT;
|
|
291757
|
+
} else if (msg.includes("unavailable in this CCXT build")) {
|
|
291758
|
+
code = grpc.status.UNIMPLEMENTED;
|
|
291759
|
+
} else {
|
|
291760
|
+
code = mapCcxtErrorToGrpcStatus(error48) ?? grpc.status.INTERNAL;
|
|
291761
|
+
}
|
|
291762
|
+
wrappedCallback({
|
|
291763
|
+
code,
|
|
291764
|
+
message: `InternalTransfer failed: ${msg}`
|
|
291765
|
+
}, null);
|
|
291766
|
+
}
|
|
291767
|
+
break;
|
|
291768
|
+
}
|
|
291717
291769
|
default:
|
|
291718
291770
|
return wrappedCallback({
|
|
291719
291771
|
code: grpc.status.INVALID_ARGUMENT,
|
|
@@ -292272,4 +292324,4 @@ export {
|
|
|
292272
292324
|
CEXBroker as default
|
|
292273
292325
|
};
|
|
292274
292326
|
|
|
292275
|
-
//# debugId=
|
|
292327
|
+
//# debugId=AC580D825044D41564756E2164756E21
|