Current section
Files
Jump to
Current section
Files
lib/ccxt/signing/deribit.ex
defmodule CCXT.Signing.Deribit do
@moduledoc """
Deribit-style HMAC-SHA256 signing with custom Authorization header.
Deribit uses a unique authentication format that differs from other exchanges:
## How it works
1. Generate timestamp (milliseconds) and nonce (also milliseconds)
2. Build request data: `METHOD\\npath?query\\nbody\\n`
3. Build auth string: `timestamp\\nnonce\\nrequest_data`
4. Sign with HMAC-SHA256 (hex encoded)
5. Set Authorization header: `deri-hmac-sha256 id={key},ts={ts},sig={sig},nonce={nonce}`
## Configuration
signing: %{
pattern: :deribit
}
No additional configuration needed - the format is fixed.
"""
@behaviour CCXT.Signing.Behaviour
alias CCXT.Credentials
alias CCXT.Signing
@doc """
Signs a request using Deribit's custom HMAC-SHA256 Authorization header format.
"""
@impl true
@spec sign(Signing.request(), Credentials.t(), Signing.config()) :: Signing.signed_request()
def sign(request, credentials, _config) do
timestamp = to_string(Signing.timestamp_ms())
nonce = to_string(Signing.timestamp_ms())
# Build query string
query_string = Signing.urlencode(request.params)
path_with_query =
if query_string == "" do
request.path
else
request.path <> "?" <> query_string
end
# Build auth payload: timestamp\nnonce\nMETHOD\npath\nbody\n
method_upper = request.method |> to_string() |> String.upcase()
# fail-loud:ignore - GET requests have nil body, empty string is correct for signature
body = if request.body, do: request.body, else: ""
request_data = "#{method_upper}\n#{path_with_query}\n#{body}\n"
auth = "#{timestamp}\n#{nonce}\n#{request_data}"
# Sign with HMAC-SHA256
signature =
auth
|> Signing.hmac_sha256(credentials.secret)
|> Signing.encode_hex()
# Build Authorization header
auth_header =
"deri-hmac-sha256 id=#{credentials.api_key},ts=#{timestamp},sig=#{signature},nonce=#{nonce}"
%{
url: path_with_query,
method: request.method,
headers: [{"Authorization", auth_header}],
body: request.body
}
end
end