Delphi + Binance Api + Limit Order Problem Invalid signatur

Viewed 922
{"code":3702,"msg":"Invalid signature.","timestamp":1623848681308}

i use trbinance.com api. I keep getting the same error

procedure TForm1.Button1Click(Sender: TObject);
var
  url, sign, queryString, nonce: string;
  ST: SystemTime;
  DT: TDateTime;
  uTime: int64;
  sHour, sMin, sSec, sMili: Word;
 
  stream, s_url: string;
  Post: TStringList;
  IdHTTP10 : TIDhttp;
  api_key , api_secret : String;
begin
  api_key := '**';
  api_secret := '**';
 
  GetSystemTime(ST);
  DT := EncodeDate(ST.wYear, ST.wMonth, ST.wDay) +
        EncodeTime(ST.wHour, ST.wMinute, ST.wSecond, ST.wMilliseconds);
  uTime := DateUtils.MilliSecondsBetween(DT, UnixDateDelta);
  nonce:=inttostr(uTime);
 
  url :='https://trbinance.com/open/v1/orders';
  queryString := 'symbol=BTT_TRY&side=0&type=1&quantity=1&price=0.0022&recvWindow=5000&timestamp='+nonce;
  sign := THashSHA2.GetHMAC(queryString, api_secret, SHA256);
 
  IdHTTP10 := TidHTTP.Create(nil);
  IdHTTP10.HandleRedirects := True;
  IdHTTP10.Request.CustomHeaders.Add('X-MBX-APIKEY:'+api_key);
  IdHTTP10.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
 
  Post:=TStringList.Create;
  Post.Add('quantity=1&');
  Post.Add('price=0.0022&');
  Post.Add('recvWindow=5000&');
  Post.Add('timestamp='+nonce+'&');
  Post.Add('signature='+sign);
 
  s_url := url + '?symbol=BTT_TRY&side=0&type=1';
  try
    stream:=IdHTTP10.POST(s_url, Post);
    Memo1.Lines.Add(stream);
  except
    on E: Exception do
      Memo1.Lines.Add(TimeToStr(time)+' <---> [Order] error: '+E.Message);
  end;
  IdHTTP10.Free;
  Post.Free;
end;

Always problem :

{"code":3702,"msg":"Invalid signature.","timestamp":1623848681308}

Normaly Binance Symbol : BTTTRY  
Turkey Api : BTT_TRY
Normaly Binance Order Url :  httpps://api.binance.com/api/v3/order
Turkey Api Order Url : https://trbinance.com/open/v1/orders

Where is the Problem ?

Thank you so much.

3 Answers

There are a number of issues with this code, but the biggest one I see is that you should NOT be including trailing & characters in your TStringList strings, eg:

Post:=TStringList.Create;
Post.Add('quantity=1');
Post.Add('price=0.0022');
Post.Add('recvWindow=5000');
Post.Add('timestamp='+nonce);
Post.Add('signature='+sign); 

TIdHTTP.Post() will insert those & characters into the request body for you, thus the data being transmitted is different than the data you signed.

Thank you for your answers. I made improvements to the code.

Friends in need can use this procedure in delphi. ( for Global Binance Api )

procedure TForm1.Button1Click(Sender: TObject);
const
  Publickey= '***';
  Secretkey= '***';
var
  IdHTTP        : TIdHTTP;
  RBody         : TStringstream;
  QueryString   : String;
  Signature     : String;
  url           : String;
begin

  queryString :=
    'symbol=BTTTRY&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1000&price=0.024400&recvWindow=5000&timestamp='
    + ABDULLAH_GetTimestamp();

  Signature := THashSHA2.GetHMAC(queryString, Secretkey, SHA256);

  Try

    IdHTTP := TIdHTTP.Create();
    RBody := TStringStream.Create(queryString + '&signature=' + Signature);

    IdHTTP.Request.CustomHeaders.Add('X-MBX-APIKEY:' + Publickey);
    IdHTTP.Request.CustomHeaders.UnfoldLines := True;
    IdHTTP.Request.Accept := 'application/json';
    IdHTTP.Request.ContentType := 'application/json';
    IdHTTP.Request.ContentEncoding := 'utf-8';
    IdHTTP.Request.BasicAuthentication := True;
    IdHTTP.HandleRedirects := True;
    IdHTTP.HTTPOptions := [hoKeepOrigProtocol, hoForceEncodeParams,
      hoNoProtocolErrorException, hoWantProtocolErrorContent];

    IdHTTP.iohandler := IdSSLIOHandlerSocketOpenSSL1;

    url := 'https://api.binance.com/api/v3/order?';

    Try
      Memo1.Lines.Add(IdHTTP.Post(url, RBody));
    Except
      ON E: EXCEPTION DO
        Memo1.Lines.Add('Error Message:' + E.Message);
    End;

  Finally
    FreeAndNil(IdHTTP);
    FreeAndNil(RBody);
  End;
end;

This code works for Global Binance Api.

Change Symbol : BTTTRY -> BTT_TRY And Post Url : https://api.binance.com/api/v3/order -> https://trbinance.com/open/v1/orders

İt's not working and Result :

{"code":3702,"msg":"Invalid signature.","timestamp":1723648673412}

This Procedure works in 'Global Binance Api' but not working 'trbinance Api'

Same procedure gives 'invalid signature' error in 'trbinance api'. :(

trbinance api example :

HMAC SHA256 signature:

[linux]$ echo -n "symbol=BTC_USDT&side=0&type=1&quantity=0.16&price=7500&timestamp=1581720670624&recvWindow=5000" | openssl dgst -sha256 -hmac "cfDC92B191b9B3Ca3D842Ae0e01108CBKI6BqEW6xr4NrPus3hoZ9Ze9YrmWwPFV"
(stdin)= 33824b5160daefc34257ab9cd3c3db7a0158a446674f896c9fc3b122ae656bfa

curl command:

(HMAC SHA256)
[linux]$  curl -H "X-MBX-APIKEY: cfDC92B191b9B3Ca3D842Ae0e01108CBKI6BqEW6xr4NrPus3hoZ9Ze9YrmWwPFV" -X POST 'https://www.trbinance.com/open/v1/orders' -d 'symbol=BTC_USDT&side=0&type=1&quantity=0.16&price=7500&timestamp=1581720670624&recvWindow=5000&signature=33824b5160daefc34257ab9cd3c3db7a0158a446674f896c9fc3b122ae656bfa'

According to Binance TR API docs:

Use your secretKey as the key and totalParams as the value for the HMAC operation. totalParams is defined as the query string concatenated with the request body.

Error from API with the text "Invalid signature." could give you a clue that the problem is with your signature algo:

sign := THashSHA2.GetHMAC(queryString, api_secret, SHA256);

Your code here signs only your query string, but according to API docs you must sign query string concatenated with the request body.

So, you need to change your code like this ("Post" variable must be initialized before this line):

sign := THashSHA2.GetHMAC(queryString + Post.text, api_secret, SHA256);
Related