Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@usherlabs/cex-broker",
"version": "0.1.11",
"version": "0.1.13",
"description": "Unified gRPC API to CEXs by Usher Labs.",
"repository": "git@gitlab.com:usherlabs/cex-broker.git",
"homepage": "https://usher.so/",
Expand Down
14 changes: 7 additions & 7 deletions src/client.dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ const client = new grpcObj.cex_broker.cex_service(
config();

const broker = new CEXBroker({}, loadPolicy("./policy/policy.json"), {
useVerity: false,
useVerity: true,
});
broker.loadEnvConfig();
broker.run();

const metadata = new grpc.Metadata();
metadata.add("api-key", process.env.BYBIT_API_KEY ?? ""); // Example header
metadata.add("api-secret", process.env.BYBIT_API_SECRET ?? "");
// metadata.add("api-key", process.env.BYBIT_API_KEY ?? ""); // Example header
// metadata.add("api-secret", process.env.BYBIT_API_SECRET ?? "");

const deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 5);
Expand All @@ -54,7 +54,7 @@ function onClientReady() {
// Test ExecuteAction for ticker
client.executeAction(
{
cex: "binance",
cex: "mexc",
symbol: "ETHUSDT",
action: Action.FetchTicker,
},
Expand All @@ -71,10 +71,10 @@ function onClientReady() {
// Test ExecuteAction for balance
client.executeAction(
{
cex: "bybit",
symbol: "USDT",
cex: "binance",
symbol: "USDT,BTC,ETH",
payload: { type: "spot" },
action: Action.FetchBalance,
action: Action.FetchBalances,
},
metadata,
(err, result) => {
Expand Down
17 changes: 9 additions & 8 deletions src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export function authenticateRequest<T, E>(
whitelistIps: string[],
): boolean {
const clientIp = call.getPeer().split(":")[0];
if (whitelistIps.includes("*")){
if (whitelistIps.includes("*")) {
return true
}else if (!clientIp || !whitelistIps.includes(clientIp)) {
} else if (!clientIp || !whitelistIps.includes(clientIp)) {
log.warn(`Blocked access from unauthorized IP: ${clientIp || "unknown"}`);
return false;
}
Expand Down Expand Up @@ -48,20 +48,21 @@ export function createBroker(
recvWindow: 60000,
},
});

if (process.env.CEX_BROKER_SANDBOX_MODE === 'true') {
exchange.setSandboxMode(true);
}
exchange.setSandboxMode(true);
}
exchange.options.recvWindow = 60000;
exchange.redact_exclusion = "key"; //Exclude api-key and apikey
return exchange;
}

export function selectBroker(
brokers:
| {
primary: Exchange;
secondaryBrokers: Exchange[];
}
primary: Exchange;
secondaryBrokers: Exchange[];
}
| undefined,
metadata: Metadata,
): Exchange | null {
Expand Down
6 changes: 5 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export default class CEXBroker {
recvWindow: 60000,
},
});
exchange.redact_exclusion = "key";
Comment thread
rsoury marked this conversation as resolved.
Outdated
secondaryBrokers[+index] = exchange;
} else {
log.warn(
Expand Down Expand Up @@ -229,7 +230,7 @@ export default class CEXBroker {
for (const index of Object.keys(creds.secondaryKeys)) {
const sec = creds.secondaryKeys[+index];
if (!!sec?.apiKey && !!sec?.apiSecret) {
secondaryBroker[+index] = new ExchangeClass({
const exchange = new ExchangeClass({
apiKey: sec.apiKey,
secret: sec.apiSecret,
enableRateLimit: true,
Expand All @@ -242,6 +243,8 @@ export default class CEXBroker {
recvWindow: 60000,
},
});
exchange.redact_exclusion = "key"; //Exclude api-key and apikey
Comment thread
rsoury marked this conversation as resolved.
Outdated
secondaryBroker[+index] = exchange;
} else {
log.warn(
`⚠️ Incomplete secondary credentials for broker "${broker}" at index ${index}`,
Expand Down Expand Up @@ -269,6 +272,7 @@ export default class CEXBroker {
recvWindow: 60000,
},
});
client.redact_exclusion = "key"; //Exclude api-key and apikey
Comment thread
rsoury marked this conversation as resolved.
Outdated

this.brokers[broker] = {
primary: client,
Expand Down
38 changes: 32 additions & 6 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function getServer(
const metadata = call.metadata;
const { action, cex, symbol } = call.request;
// Validate required fields
if (!action || !cex || !symbol) {
if (!action || !cex) {
return callback(
{
code: grpc.status.INVALID_ARGUMENT,
Expand Down Expand Up @@ -160,6 +160,15 @@ export function getServer(
}

case Action.FetchDepositAddresses: {
if (!symbol) {
return callback(
{
code: grpc.status.INVALID_ARGUMENT,
message: `ValidationError: Symbol requied`,
},
null,
);
}
const fetchDepositAddressesSchema = Joi.object({
chain: Joi.string().required(),
params: Joi.object()
Expand Down Expand Up @@ -224,6 +233,15 @@ export function getServer(
break;
}
case Action.Transfer: {
if (!symbol) {
return callback(
{
code: grpc.status.INVALID_ARGUMENT,
message: `ValidationError: Symbol requied`,
},
null,
);
}
const transferSchema = Joi.object({
recipientAddress: Joi.string().required(),
amount: Joi.number().positive().required(), // Must be a positive number
Expand Down Expand Up @@ -482,9 +500,9 @@ export function getServer(
// Fetch balance from the specified CEX
const balance = (await broker.fetchFreeBalance({
...(call.request.payload ?? {}),
// biome-ignore lint/suspicious/noExplicitAny: invalid typing
// biome-ignore lint/suspicious/noExplicitAny: https://github.com/ccxt/ccxt/issues/26327
})) as any;
const currencyBalance = balance[symbol];
const currencyBalance = symbol ? balance[symbol] : balance;

callback(null, {
proof: broker.last_proof || "",
Expand All @@ -508,10 +526,9 @@ export function getServer(
case Action.FetchBalances:
try {
// Fetch balance from the specified CEX
const balance = (await broker.fetchFreeBalance({
const balance = await broker.fetchFreeBalance({

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oddly here, the result of fetchFreeBalance is a Balance struct.
https://github.com/usherlabs/ccxt/blob/cde501ea4d784f2c2b4809c526135719af8ad0e7/js/src/base/Exchange.d.ts#L684

How does this resolve to an array of balances?

Can we add some explaination in comments for this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The balance struct is incorrect
Creating a test bench to show you what I mean

@rsoury rsoury Sep 6, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The referenced Github Issue (ccxt/ccxt#26327) appears to show that FetchBalance can return a mapping.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approval need to correct this
usherlabs/ccxt#7

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix doesn't really solve the root cause of the types issue.

It just moves the any deeper into the tech stack (from CEX Broker to CCXT) — https://github.com/usherlabs/ccxt/pull/7/files#diff-217b1af2b2442a19286fc9dbdd67c6d6e3a71dd5efd78bb489d6fec0e15be25fR7430

As detailed in comment, seems to be reported here: ccxt/ccxt#26327

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that was corrected in usherlabs/ccxt#7

...(call.request.payload ?? {}),
// biome-ignore lint/suspicious/noExplicitAny: invalid typing
})) as any;
});

callback(null, {
proof: broker.last_proof || "",
Expand All @@ -530,6 +547,15 @@ export function getServer(
break;

case Action.FetchTicker:
if (!symbol) {
return callback(
{
code: grpc.status.INVALID_ARGUMENT,
message: `ValidationError: Symbol requied`,
},
null,
);
}
try {
const ticker = await broker.fetchTicker(symbol);
callback(null, {
Expand Down