B4J Question Error logging into binance. [Solved]

carlos7000

Well-Known Member
Licensed User
Longtime User
I have written a simple program to get data from my binance account.
When I run the attached program, the binance server responds:
code":-2015,"msg":"Invalid API-key, IP, or permissions for action.
This is the program:
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private TextAreaOut As TextArea
    Private ButtonGet As Button
    Private BinanceApiUrl As String
    Private ApiSecret As String
    Private ApiKey As String
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    BinanceApiUrl = "https://api.binance.com/api/"
    ApiKey        = "VmcKfcJ127jpeGUPAKXnHXJBTSF9iMfHUqptwEb1TCvSLwgNnCJ2BuWsdVwyhsbD"
    ApiSecret    = "xTFh2bqOydbMumZmWcV13ecPYFTHmZa5pg0Xp3rlay5Tyog2VBoEAJQToMURhU1E"
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

'Function in charge of making requests to the Binance API
private Sub SendCommand(work As String, uri As String, Signature As Boolean)
    Try
        'Si se debe firmar
        If (Signature == True)Then        
            Dim timestamp As Long
            timestamp = DateTime.now 'Creamos el timestamp
            Dim queryString As String
            queryString = "timestamp=" & timestamp 'Creamos el Query string          
            Dim Sign() As Byte
            Sign = HashHmac(queryString, ApiSecret) 'Firmamos el Query string
         
            Dim API_Signed As String
            Dim Byte_Conv As ByteConverter
            API_Signed = Byte_Conv.HexFromBytes(Sign) 'convert to HEX
            API_Signed = API_Signed.ToLowerCase
        End If
     
        Dim j As HttpJob
        j.Initialize(work, Me)
     
        Dim Url As String
        Url = BinanceApiUrl & uri & "?" & queryString & "&signature=" & API_Signed 'Creamos la Url
        j.Download(Url)
        Log(Url)
        'Si se debe firmar
        If (Signature == True)Then
            Try
                'Defino el SetHeader basado función "signedRequest()" que encontrará en este post.
                j.GetRequest.SetHeader("User-Agent", "Mozilla/4.0 (compatible; PHP Binance API)")
                j.GetRequest.SetHeader("X-MBX-ApiKey", ApiKey)
                j.GetRequest.SetHeader("Content-Type", "application/x-www-form-urlencoded")            
            Catch
                Log(LastException)
            End Try          
        End If
     
        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            TextAreaOut.Text = j.JobName & CRLF    
            TextAreaOut.Text = TextAreaOut.Text & j.GetString
            Log(j.GetString)
        Else
            TextAreaOut.Text = j.ErrorMessage
        End If
        j.Release
    Catch
        MessageBox(LastException, "Error")
    End Try
End Sub

Sub ButtonGet_Click
    SendCommand("GetBalances", "v3/account", True)
End Sub

'Function in charge of Signing the QueryString
Public Sub HashHmac(data As String, secret As String) As Byte()
    Try
        Dim m As Mac                                         'm As Message Authentication Code
        Dim kg As KeyGenerator                               'kg As KeyGenerator
        kg.Initialize("HmacSHA512")                          'initialize kg using HmacSHA512 algorithm
        kg.KeyFromBytes(secret.GetBytes("UTF8"))             'encode string "secret" to an array of Bytes using UTF8
        m.Initialise("HmacSHA512", kg.Key)                   'initialize m using HmacSHA512 algorithm and the secret key
        m.Update(data.GetBytes("UTF8"))                      'encodes post data to an array of Bytes and loads it to be signed
        Return m.Sign                                        'sign the loaded data using the secret key, return the calc signature data
    Catch    
        MessageBox(LastException, "Error")
    End Try
End Sub

Public Sub MessageBox(Message As String, Title As String )
    Private jxui As XUI
    jxui.MsgboxAsync(Message, Title)
End Sub

The above program is based on this function written in php. This function works correctly.

PHP:
private function signedRequest($url, $params = [], $method = "GET") {
        $params['timestamp'] = number_format(microtime(true)*1000,0,'.','');

        $query = http_build_query($params, '', '&'); // https://www.php.net/manual/es/function.http-build-query.php
        $signature = hash_hmac('sha256', $query, $this->api_secret);
     
        $opt = [
            "http" => [
                "method" => $method,
                "ignore_errors" => true,
                "header" => "User-Agent: Mozilla/4.0 (compatible; PHP Binance API)\r\nX-MBX-APIKEY: {$this->api_key}\r\nContent-type: application/x-www-form-urlencoded\r\n"
            ]
        ];
        if ( $method == 'GET' ) {
            // parameters encoded as query string in URL
            $endpoint = "{$this->base}{$url}?{$query}&signature={$signature}";
        } else {
            // parameters encoded as POST data (in $context)
            $endpoint = "{$this->base}{$url}";
            $postdata = "{$query}&signature={$signature}";
            $opt['http']['content'] = $postdata;
        }
        $context = stream_context_create($opt); // https://www.php.net/manual/es/function.stream-context-create.php
        return json_decode(file_get_contents($endpoint, false, $context), true); // https://www.php.net/manual/es/function.json-decode.php
    }

The ApiKey and ApiSecret included in the program are valid (in case you want to run the program).

I attach the source code
 

Attachments

  • Binance 3.zip
    3.9 KB · Views: 233
Last edited:

alwaysbusy

Expert
Licensed User
Longtime User
Upvote 0

carlos7000

Well-Known Member
Licensed User
Longtime User
Hello.

I made the corrections that you suggested. The error remains the same.

The IP restriction is disabled.

Captura.PNG


The new code with the suggested fixes is this

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 300
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    
    Private TextAreaOut As TextArea
    Private ButtonGet As Button
    
    Private BaseURL As String
    Private ApiSecret As String
    Private ApiKey As String
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    
    BaseURL = "https://api.binance.com/api/"
    ApiKey = "VmcKfcJ127jpeGUPAKXnHXJBTSF9iMfHUqptwEb1TCvSLwgNnCJ2BuWsdVwyhsbD"
    ApiSecret = "xTFh2bqOydbMumZmWcV13ecPYFTHmZa5pg0Xp3rlay5Tyog2VBoEAJQToMURhU1E"
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub ButtonGet_Click
    SendCommand("v3/account")
End Sub

private Sub SendCommand(ApiURL As String)
    Dim Result As String
    
    Dim TimeStamp As String = DateTime.Now
    Dim Sign() As Byte = HashHmac(TimeStamp, ApiSecret)
    
    If Sign.Length = 0 Then Return
    Dim BConv As ByteConverter
    Dim Signature As String = BConv.HexFromBytes(Sign).ToLowerCase 'convert to HEX

    Dim URL As String = BaseURL & ApiURL & "?" & "timestamp=" & TimeStamp & "&" & "signature=" & Signature
    
    Try
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download(URL)
        j.GetRequest.SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0")
        j.GetRequest.SetHeader("Content-Type", "application/x-www-form-urlencoded")
        j.GetRequest.SetHeader("X-MBX-APIKEY", ApiKey)

        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            Result = j.GetString
        Else
            Result = j.ErrorMessage
        End If
        j.Release
    Catch
        Result = LastException.Message
    End Try
    MessageBox($"HttpJob result: ${Result}"$)
    
End Sub

Public Sub HashHmac(data As String, secret As String) As Byte()
    Dim m As Mac 'm As Message Authentication Code
    Dim kg As KeyGenerator 'kg As KeyGenerator
    Dim Result() As Byte 'Result Sign
    Try
        kg.Initialize("HmacSHA256")                          'initialize kg using HmacSHA512 algorithm
        kg.KeyFromBytes(secret.GetBytes("UTF8"))             'encode string "secret" to an array of Bytes using UTF8
        m.Initialise("HmacSHA256", kg.Key)                   'initialize m using HmacSHA512 algorithm and the secret key
        m.Update(data.GetBytes("UTF8"))                      'encodes post data to an array of Bytes and loads it to be signed
        Result = m.Sign                                      'sign the loaded data using the secret key, return the calc signature data
    Catch
        MessageBox($"HashHmac: ${LastException.Message}"$)
    End Try
    Return Result
End Sub

Public Sub MessageBox(Message As String)
    TextAreaOut.Text = TextAreaOut.Text & CRLF & Message
End Sub

I attach project with the implemented suggestions.

Thanks.
 

Attachments

  • Binance 4.zip
    3.9 KB · Views: 204
Upvote 0

carlos7000

Well-Known Member
Licensed User
Longtime User

Hello.

The capture of the application is not what is expected. The data displayed by the application corresponds to a Binance registration page.

The only valid url to obtain account information in binance is https://api.binance.com/api The url https://testnet.binance.vision/api is for testing, but it also responds that the Apikey is in the wrong format

The response from the production api or the testing api should be:

JSON:
{
  "makerCommission": 15,
  "takerCommission": 15,
  "buyerCommission": 0,
  "sellerCommission": 0,
  "canTrade": true,
  "canWithdraw": true,
  "canDeposit": true,
  "updateTime": 123456789,
  "accountType": "SPOT",
  "balances": [
    {
      "asset": "BTC",
      "free": "4723846.89208129",
      "locked": "0.00000000"
    },
    {
      "asset": "LTC",
      "free": "4763368.68006011",
      "locked": "0.00000000"
    }
  ],
    "permissions": [
    "SPOT"
  ]
}

The urls for futures accounts in my case do not apply because my account is spot type.

In this link there is a superficial explanation of the use of the api, to obtain detailed information of the account

In this link you will find more detailed information about the authentication process

Thanks a lot
 
Upvote 0

carlos7000

Well-Known Member
Licensed User
Longtime User
Hello.

I generated a new key pair, but still the program kept giving problems, I added the parameter "recvWindow=60000" and it worked.

ezgif-6-7c7e69aa9826.gif


This is the code that worked:

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 300
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    
    Private TextAreaOut As TextArea
    Private ButtonGet As Button
    
    Private BaseURL As String
    Private ApiSecret As String
    Private ApiKey As String
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    
    BaseURL      = "https://api.binance.com/api/"
    ApiKey       = "AMSdOtvOoCA4WuAGRzN4StDRqxsy6zpKimrRtCV4JQaI2yUy6jokaCqkQt8LXoBi"
    ApiSecret    = "4gKHpC7UJrXmyOJb4UolRPGBA0XqHXdK3Y0GMtdKYYj1K5GakUaZ70f1BEFrtFpt"
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub ButtonGet_Click
    SendCommand("v3/account")
End Sub

private Sub SendCommand(ApiURL As String)
    Dim Result As String
    Dim Params As String = "recvWindow=60000&timestamp=" & DateTime.Now
    Dim Sign() As Byte = HashHmac(Params, ApiSecret)
    
    If Sign.Length = 0 Then Return
    Dim BConv As ByteConverter
    Dim Signature As String = BConv.HexFromBytes(Sign).ToLowerCase 'convert to HEX
    Dim URL As String = BaseURL & ApiURL & "?" & Params & "&signature=" & Signature     
    
    Try
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download(URL)
        j.GetRequest.SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0")
        j.GetRequest.SetHeader("Content-Type", "application/x-www-form-urlencoded")
        j.GetRequest.SetHeader("X-MBX-APIKEY", ApiKey)

        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            Result = j.GetString
        Else
            Result = j.ErrorMessage
        End If
        j.Release
    Catch
        Result = LastException.Message
    End Try
    MessageBox($"HttpJob result: ${Result}"$)
    
End Sub

Public Sub HashHmac(data As String, secret As String) As Byte()
    Dim m As Mac 'm As Message Authentication Code
    Dim kg As KeyGenerator 'kg As KeyGenerator
    Dim Result() As Byte 'Result Sign
    Try
        kg.Initialize("HmacSHA256")                          'initialize kg using HmacSHA512 algorithm
        kg.KeyFromBytes(secret.GetBytes("UTF8"))             'encode string "secret" to an array of Bytes using UTF8
        m.Initialise("HmacSHA256", kg.Key)                   'initialize m using HmacSHA512 algorithm and the secret key
        m.Update(data.GetBytes("UTF8"))                      'encodes post data to an array of Bytes and loads it to be signed
        Result = m.Sign                                      'sign the loaded data using the secret key, return the calc signature data
    Catch
        MessageBox($"HashHmac: ${LastException.Message}"$)
    End Try
    Return Result
End Sub

Public Sub MessageBox(Message As String)
    TextAreaOut.Text = TextAreaOut.Text & CRLF & Message
End Sub

Mr. Oparra
Thank you, very much.
 
Upvote 0
Top