JKorf/Kraken.Net

socketClient.SpotApi.SubscribeToUserTradeUpdatesAsync requires webSocketToken

Closed this issue · 2 comments

Describe the bug

The webSocketToken could nowhere be found and also the corresponding function GetWebSocketsToken not.

var tickerSubscriptionResult = await _socketClient.SpotApi.SubscribeToUserTradeUpdatesAsync(webSocketToken, (data) =>
{
//TODO: Something
}, CancellationToken.None);

To Reproduce
SpotApi.SubscribeToUserTradeUpdatesAsync

Expected behavior
Please add possibility to get the token or remove it from the signature and do it internally.

Kraken provides example code how to obtain the WebSocketsToken:
https://support.kraken.com/hc/en-us/articles/4407678695316-Example-code-for-C-REST-and-WebSocket-API

    private static readonly string[] separator = ["\"token\":\"", "\"}}"];

        string webSocketRestResponseJSON = await QueryPrivateEndpoint("GetWebSocketsToken", "", _configuration["KrakenApiKey"], _configuration["KrakenSecret"]);
        var splits = webSocketRestResponseJSON.Split(separator, StringSplitOptions.None);
        string webSocketToken = splits[1];



    #region Private REST API Endpoints

    private static async Task<string> QueryPrivateEndpoint(string endpointName,
    string inputParameters,
    string apiPublicKey,
    string apiPrivateKey)
    {
        string baseDomain = "https://api.kraken.com";
        string privatePath = "/0/private/";

        string apiEndpointFullURL = baseDomain + privatePath + endpointName;
        string nonce = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
        if (string.IsNullOrWhiteSpace(inputParameters) == false)
        {
            inputParameters = "&" + inputParameters;
        }
        string apiPostBodyData = "nonce=" + nonce + inputParameters;
        string signature = CreateAuthenticationSignature(apiPrivateKey,
        privatePath,
        endpointName,
        nonce,
        inputParameters);
        string jsonData;
        using (HttpClient client = new())
        {
            client.DefaultRequestHeaders.Clear();
            client.DefaultRequestHeaders.Add("API-Key", apiPublicKey);
            client.DefaultRequestHeaders.Add("API-Sign", signature);
            client.DefaultRequestHeaders.Add("User-Agent", "KrakenDotNet Client");
            StringContent data = new(apiPostBodyData, Encoding.UTF8, "application/x-www-form-urlencoded");
            HttpResponseMessage response = await client.PostAsync(apiEndpointFullURL, data);
            jsonData = response.Content.ReadAsStringAsync().Result;
        }

        return jsonData;
    }

    #endregion

    #region Authentication Algorithm

    public static string CreateAuthenticationSignature(string apiPrivateKey,
    string apiPath,
    string endpointName,
    string nonce,
    string inputParams)
    {
        byte[] sha256Hash = ComputeSha256Hash(nonce, inputParams);
        byte[] sha512Hash = ComputeSha512Hash(apiPrivateKey, sha256Hash, apiPath, endpointName);
        string signatureString = Convert.ToBase64String(sha512Hash);
        return signatureString;
    }

    private static byte[] ComputeSha256Hash(string nonce, string inputParams)
    {
        byte[] sha256Hash;
        string sha256HashData = nonce.ToString() + "nonce=" + nonce.ToString() + inputParams;
        sha256Hash = SHA256.HashData(Encoding.UTF8.GetBytes(sha256HashData));
        return sha256Hash;
    }

    private static byte[] ComputeSha512Hash(string apiPrivateKey,
    byte[] sha256Hash,
    string apiPath,
    string endpointName)
    {

        string apiEndpointPath = apiPath + endpointName;
        byte[] apiEndpointPathBytes = Encoding.UTF8.GetBytes(apiEndpointPath);
        byte[] sha512HashData = [.. apiEndpointPathBytes, .. sha256Hash];
        HMACSHA512 encryptor = new(Convert.FromBase64String(apiPrivateKey));
        byte[] sha512Hash = encryptor.ComputeHash(sha512HashData);
        return sha512Hash;
    }

    #endregion

You can request the token using the rest client and then provide it using the socket client.

// Retrieve the token
var tokenResult = await krakenClient.SpotApi.Account.GetWebsocketTokenAsync();

// Subscribe using the token
await krakenSocketClient.SpotApi.SubscribeToUserTradeUpdatesAsync(tokenResult.Data.Token, data => {
    // Handle update
});

Great that works perfectly well. Many thanks for your fast help!
The Issue can be closed. 👍