2

I try to send authenticated request to new okex api. part of their documentation:

Creating a Request

All REST requests must contain the following headers:

OK-ACCESS-KEY The api key as a string.

OK-ACCESS-SIGN The base64-encoded signature (see Signing a Message).

OK-ACCESS-TIMESTAMP A timestamp for your request.

OK-ACCESS-PASSPHRASE The passphrase you specified when creating the API key.

All request bodies should have content type application/json and be valid JSON.

Signing a Message

The OK-ACCESS-SIGN header is generated by creating a sha256 HMAC using the base64-decoded secret key on the prehash string timestamp + method + requestPath + body (where + represents string concatenation), secretKey and base64-encode the output. For example: sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(timestamp + 'GET' + '/users/self/verify', secretKey))

The timestamp value is the same as the OK-ACCESS-TIMESTAMP header and nanometer precision.

The method should be UPPER CASE, like GET/POST.

requestPath is the path of requesting an endpoint, such as:/orders?before=2&limit=30.

The body is the request body string or omitted if there is no request body (typically for GET requests). For example:{"product_id":"BTC-USD-0309","order_id":"377454671037440"}

secretKey is generated when a user is subscribing to an Apikey. Prehash string:2018-03-08T10:59:25.789ZPOST/orders?before=2&limit=30{"product_id":"BTC-USD-0309","order_id":"377454671037440"}

So that's what i tried

BASE_URL = 'https://www.okex.com'.freeze

def base_api_endpoint
  url = URI.parse BASE_URL
  "#{url.scheme}://#{url.host}:#{url.port}"
end

def authenticated_request(method, url, options = {}, paginated: false)
  raise Exceptions::InvalidApiKey if @key.blank? || @secret.blank? || @passphrase.blank?
  response = rest_connection.run_request(method, URI.encode(url), nil, nil) do |req|
    if method == :post
      req.body = options.to_json
    else
      req.params.merge! options
    end
  end
def rest_connection
  @conn ||= new_rest_connection
end

TimestampRequestMiddleware = Struct.new(:app) do
  def call(env)
    env[:request_headers].merge!('OK-ACCESS-TIMESTAMP' => Time.now.utc.iso8601(3))
    app.call env
  end
end

SignRequestMiddleware = Struct.new(:app, :key, :secret, :passphrase) do
  def call(env)
    request_path = env[:url].path
    if env[:url].query.present?
      request_path += ('?' + env[:url].query)
    end
    timestamp = env[:request_headers]['OK-ACCESS-TIMESTAMP']
    method = env[:method].to_s.upcase
    what = "#{timestamp} + #{method} + #{request_path} + #{env.body}"
    decoded_secret = Base64.decode64(secret)
    mac  = OpenSSL::HMAC.digest('sha256', decoded_secret, what)
    sign = Base64.strict_encode64(mac)
    env[:request_headers].merge!('OK-ACCESS-KEY' => key, 'OK-ACCESS-SIGN' => sign, 'OK-ACCESS-TIMESTAMP' => timestamp, 'OK-ACCESS-PASSPHRASE' => passphrase)
    app.call env
  end
end

def new_rest_connection
  Faraday.new( base_api_endpoint, { ssl: { verify: false } }) do |conn|
    conn.use Market::OkexMarket::OkexCustomErrors, api_key: @key
    conn.request :json
    conn.response :json, content_type: /\bjson$/
    conn.response :logger, Logger.new(STDOUT) , bodies: true  if Rails.env.development?
    conn.use FaradayMiddleware::ParseJson, :content_type => /\bjson$/
    conn.use TimestampRequestMiddleware
    conn.use SignRequestMiddleware, @key, @secret, @passphrase
    conn.headers['Content-Type'] = 'application/json'
    conn.adapter :net_http
  end
end

def complete_balances
  data = authenticated_request(:get, '/api/spot/v3/accounts')
  data.map do |d|
    [
        d['currency'],
        {'available' => d['available'].to_f, 'onOrders' => d['hold'].to_f}
    ]
  end.to_h
end

But when i call complete_balances method, i got an error from okex response: {"code"=>30013, "message"=>"Invalid Sign"} and i can't recognize where i'm wrong. Can someone help me with that?

Gleb Omarov
  • 45
  • 1
  • 9

1 Answers1

1

"... using the base64-decoded secret key ..." I faced the same problem. After having examined their examples I found out the secret key does not need to be base64-decoded. Maybe we should assume we are already given a base64-decoded key. Anyway, as soon as you stop base64-decoding the secret key your signature generator should start working. Mine did.