XChange icon indicating copy to clipboard operation
XChange copied to clipboard

FTX Exchange, Unable to perform authed requests

Open BernatCarbo opened this issue 3 years ago • 8 comments

Hello there,

Looks like there is something wrong with the FTX Exchange signature generation (FTX-SIGN header), I'm trying to perform authed requests with my (US) api key and secret but I always get the next message: Not logged in (HTTP status code: 401) (HTTP status code: 0)

Although if I replicate the request with postman (using the generated params (headers) from the lib) I get the next message: { "success": false, "error": "Not logged in: Invalid signature" }

I'm using the next code to connect to the US FTX Exchange:

val authenticatedClient = ExchangeFactory.INSTANCE.createExchangeWithoutSpecification(FtxExchange::class.java).also {
            val exchangeSpecification = FtxExchange().defaultExchangeSpecification.apply {
                apiKey = "API_KEY"
                secretKey = "API_SECRET"
                sslUri = "https://ftx.us"
                host = "ftx.us"
            }
            it.applySpecification(exchangeSpecification)
        }

EDIT: Looks like the request headers are sent as FTX-KEY, FTX-TS, FTX-SIGN etc, but at the US exchange the headers should be FTXUS-KEY, FTXUS-TS, FTXUS-SIGN, etx, would be good if that can be configured through the exchange specification

BernatCarbo avatar Dec 30 '21 11:12 BernatCarbo

Hello, this implementation is not for the US Ftx, it is for global. You need to change the URL on the FtxExchange class

On Thu, Dec 30, 2021, 1:53 PM BernatCarbo @.***> wrote:

Hello there,

Looks like there is something wrong with the FTX Exchange signature generation (FTX-SIGN header), I'm trying to perform authed requests with my (US) api key and secret but I always get the next message: Not logged in (HTTP status code: 401) (HTTP status code: 0)

Although if I replicate the request with postman (using the generated params (headers) from the lib) I get the next message: { "success": false, "error": "Not logged in: Invalid signature" }

I'm using the next code to connect to the US FTX Exchange:

val authenticatedClient = ExchangeFactory.INSTANCE.createExchangeWithoutSpecification(FtxExchange::class.java).also { val exchangeSpecification = FtxExchange().defaultExchangeSpecification.apply { apiKey = "API_KEY" secretKey = "API_SECRET" sslUri = "https://ftx.us" host = "ftx.us" } it.applySpecification(exchangeSpecification) }

— Reply to this email directly, view it on GitHub https://github.com/knowm/XChange/issues/4374, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHIWQ7YA7FWGCO4MX5YWVNDUTRB3HANCNFSM5K7S4YAA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you are subscribed to this thread.Message ID: @.***>

makarid avatar Dec 30 '21 21:12 makarid

@makarid I change the sslUri and the host as you can see at my code, but what should be configurable are the exchange header names, as you can see at my 'edit' the headers are sent as FTX-KEY, FTX-TS, FTX-SIGN but the US version expects FTXUS-KEY, FTXUS-TS, FTXUS-SIGN, etc

BernatCarbo avatar Dec 30 '21 23:12 BernatCarbo

You need to change these by yourself or implement a new FtxExchangeUS. I haven't done any configuration using FTX US in my mind

On Fri, Dec 31, 2021, 1:41 AM BernatCarbo @.***> wrote:

@makarid https://github.com/makarid I change the sslUri and the host as you can see at my code, but what should be configurable are the exchange header names, as you can see at my 'edit' the headers are sent as FTX-KEY, FTX-TS, FTX-SIGN but the US version expects FTXUS-KEY, FTXUS-TS, FTXUS-SIGN, etc

— Reply to this email directly, view it on GitHub https://github.com/knowm/XChange/issues/4374#issuecomment-1003213761, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHIWQ75QBDPDOD3P45AJOYLUTTU2NANCNFSM5K7S4YAA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you were mentioned.Message ID: @.***>

makarid avatar Dec 31 '21 09:12 makarid

Hope someone finds this helpful.

With no easy way to configure the header names for the US version (host and URI can be customized on the ExchangeSpecification), I used a ResCU interceptor to get around. Here's some sample code from my working setup:

Custom interceptor

package org.knowm.xchange.interceptor;

import com.linus.bitcoin.investments.FtxUsAuthenticated;
import org.knowm.xchange.ftx.FtxAuthenticated;
import si.mazi.rescu.Interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

public class FtxUsAdapterInterceptor implements Interceptor {

    @Override
    public Object aroundInvoke(InvocationHandler h, Object proxy, Method m, Object[] args)
            throws Throwable {
        if (m.getDeclaringClass() != FtxAuthenticated.class) {
            return h.invoke(proxy, m, args);
        }

        // FTX-TS needs to be there too since it's hardcoded in FtxDigest, so replicate FTXUS-TS as FTX-TS
        var adaptedParameterTypes = new java.util.ArrayList<>(Arrays.stream(m.getParameterTypes()).toList());
        adaptedParameterTypes.add(1, adaptedParameterTypes.get(1));
        var adaptedMethod = FtxUsAuthenticated.class.getMethod(m.getName(), adaptedParameterTypes.toArray(new Class<?>[]{}));

        var adaptedArgs = new java.util.ArrayList<>(Arrays.stream(args).toList());
        adaptedArgs.add(1, adaptedArgs.get(1));

        return h.invoke(proxy, adaptedMethod, adaptedArgs.toArray(new Object[]{}));
    }
}

Interceptor service registration (src/main/resources/META-INF/services)

org.knowm.xchange.interceptor.FtxUsAdapterInterceptor

API path resource class

Just copy/paste FtxAuthenticated, rename headers, and add a header parameter annotation for FTX-TS.

package com.linus.bitcoin.investments;

import org.knowm.xchange.ftx.Ftx;
import org.knowm.xchange.ftx.FtxException;
import org.knowm.xchange.ftx.dto.FtxResponse;
import org.knowm.xchange.ftx.dto.account.*;
import org.knowm.xchange.ftx.dto.trade.CancelAllFtxOrdersParams;
import org.knowm.xchange.ftx.dto.trade.FtxModifyOrderRequestPayload;
import org.knowm.xchange.ftx.dto.trade.FtxOrderDto;
import org.knowm.xchange.ftx.dto.trade.FtxOrderRequestPayload;
import si.mazi.rescu.ParamsDigest;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.List;

@Path("/api")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface FtxUsAuthenticated extends Ftx {

  @GET
  @Path("/account")
  FtxResponse<FtxAccountDto> getAccountInformation(
      @HeaderParam("FTXUS-KEY") String apiKey,
      @HeaderParam("FTXUS-TS") Long nonce,
      @HeaderParam("FTX-TS") Long nonce1, // this is needed because FTX-TS is hardcoded in FtxDigest
      @HeaderParam("FTXUS-SIGN") ParamsDigest signature,
      @HeaderParam("FTXUS-SUBACCOUNT") String subaccount)
      throws IOException, FtxException;

  // other operations; above method parameters are the same for all operations
}

mystarrocks avatar Jun 19 '22 02:06 mystarrocks

@mystarrocks That could work.

Sadly we ended by dropping XChange from our project and we made our own exchange implementation from the scratch.

BernatCarbo avatar Jun 19 '22 17:06 BernatCarbo

Interceptor service registration

Hello @mystarrocks, can you explain further the "Interceptor service registration" please? What do I need to do to achieve this?

ricardo-zenki avatar Jun 30 '22 17:06 ricardo-zenki

services

I mean, it is not clear for me how to register the interceptor, I found this explample in ResCu doc: https://github.com/mmazi/rescu/wiki/Interceptors

However I don't know if xchange provides a mechanism to assign the custom RestProxyFactory.

Edit...

After looking around, I just found the following resources: https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html https://www.baeldung.com/java-spi

I didn't know about the SPI in Java so, the solution is to create a file named "si.mazi.rescu.Interceptor" inside resources/META-INF/services directory and add a single line to the file with the implementation class.

ricardo-zenki avatar Jun 30 '22 18:06 ricardo-zenki

Yep, you got that right - just create a file in the META-INF/services, and add the fully qualified name of the custom interceptor implementation class in it as I’ve shown in my working setup.

mystarrocks avatar Jun 30 '22 19:06 mystarrocks