CCXT.Signing (ccxt_client v0.6.1)

Copy Markdown View Source

Signing pattern library for exchange authentication.

Provides a unified interface for signing API requests across 100+ cryptocurrency exchanges. Instead of per-exchange signing code, 9 parameterized patterns cover 95%+ of all exchanges:

PatternExchangesDescription
:hmac_sha256_query~40Binance-style: sign query string
:hmac_sha256_headers~30Bybit-style: sign body, headers
:hmac_sha256_iso_passphrase~10OKX-style: ISO timestamp + passphrase
:hmac_sha256_passphrase_signed~3KuCoin-style: HMAC-signed passphrase
:hmac_sha512_nonce~3Kraken-style: SHA512 + nonce + base64 secret
:hmac_sha512_gate1Gate.io-style: SHA512 + newline payload
:hmac_sha384_payload~3Bitfinex-style: payload signing
:deribit1Custom Authorization header format
:custom<5%Escape hatch for edge cases

Usage

signed = CCXT.Signing.sign(
  :hmac_sha256_headers,
  %{method: :get, path: "/v5/account/wallet-balance", body: nil, params: %{}},
  credentials,
  signing_config
)

Custom Signing Patterns

Implement CCXT.Signing.Behaviour and use the :custom pattern:

defmodule MyApp.Signing.MyExchange do
  @behaviour CCXT.Signing.Behaviour

  @impl true
  def sign(request, credentials, config) do
    %{url: request.path, method: request.method, headers: [], body: request.body}
  end
end

See CCXT.Signing.Behaviour for the full contract.

Summary

Functions

Decodes a Base64-encoded string. Raises on invalid input.

Base64-encodes a binary.

Lowercase hex-encodes a binary.

HMAC-SHA256 of data with secret.

HMAC-SHA384 of data with secret.

HMAC-SHA512 of data with secret.

Returns the signing module for a given pattern.

Returns config[:nonce_override] when set, otherwise invokes fallback. Fallback is a zero-arity function so callers control nonce semantics (e.g. :erlang.unique_integer vs System.system_time(:microsecond)).

Checks if a pattern is supported.

Returns the list of supported signing patterns.

SHA-256 hash of data.

SHA-512 hash of data.

Signs a request using the specified pattern and configuration.

Current UTC time as ISO 8601 string, truncated to millisecond precision.

Current UTC time in milliseconds.

Returns config[:timestamp_ms_override] when set, otherwise current wall time in milliseconds. Used by pattern modules so fixture replay (T65) can inject the frozen timestamp CCXT JS signed with.

Current UTC time in seconds.

URL-encodes params as a sorted query string.

URL-encodes params as a sorted query string without percent-encoding values.

Types

config()

@type config() :: %{
  optional(:api_key_header) => String.t(),
  optional(:timestamp_header) => String.t(),
  optional(:signature_header) => String.t(),
  optional(:passphrase_header) => String.t(),
  optional(:recv_window_header) => String.t(),
  optional(:recv_window) => non_neg_integer(),
  optional(:signature_encoding) => :hex | :base64,
  optional(:custom_module) => module(),
  optional(atom()) => term()
}

method()

@type method() :: :get | :post | :put | :delete

pattern()

@type pattern() ::
  :hmac_sha256_query
  | :hmac_sha256_headers
  | :hmac_sha256_iso_passphrase
  | :hmac_sha256_passphrase_signed
  | :hmac_sha512_nonce
  | :hmac_sha512_gate
  | :hmac_sha384_payload
  | :deribit
  | :custom

request()

@type request() :: %{
  method: method(),
  path: String.t(),
  body: String.t() | nil,
  params: map()
}

signed_request()

@type signed_request() :: %{
  url: String.t(),
  method: method(),
  headers: [{String.t(), String.t()}],
  body: String.t() | nil
}

Functions

decode_base64(encoded)

@spec decode_base64(String.t()) :: binary()

Decodes a Base64-encoded string. Raises on invalid input.

encode_base64(binary)

@spec encode_base64(binary()) :: String.t()

Base64-encodes a binary.

encode_hex(binary)

@spec encode_hex(binary()) :: String.t()

Lowercase hex-encodes a binary.

hmac_sha256(data, secret)

@spec hmac_sha256(iodata(), iodata()) :: binary()

HMAC-SHA256 of data with secret.

hmac_sha384(data, secret)

@spec hmac_sha384(iodata(), iodata()) :: binary()

HMAC-SHA384 of data with secret.

hmac_sha512(data, secret)

@spec hmac_sha512(iodata(), iodata()) :: binary()

HMAC-SHA512 of data with secret.

module_for_pattern(arg1)

@spec module_for_pattern(pattern()) :: module() | nil

Returns the signing module for a given pattern.

nonce_from_config(config, fallback)

@spec nonce_from_config(map(), (-> integer())) :: integer()

Returns config[:nonce_override] when set, otherwise invokes fallback. Fallback is a zero-arity function so callers control nonce semantics (e.g. :erlang.unique_integer vs System.system_time(:microsecond)).

pattern?(pattern)

@spec pattern?(atom()) :: boolean()

Checks if a pattern is supported.

patterns()

@spec patterns() :: [pattern()]

Returns the list of supported signing patterns.

sha256(data)

@spec sha256(iodata()) :: binary()

SHA-256 hash of data.

sha512(data)

@spec sha512(iodata()) :: binary()

SHA-512 hash of data.

sign(atom, request, credentials, config)

Signs a request using the specified pattern and configuration.

Parameters

  • pattern - The signing pattern atom (e.g., :hmac_sha256_headers)
  • request - Map with :method, :path, :body, and :params
  • credentials - CCXT.Credentials struct with API key and secret
  • config - Pattern-specific configuration from the exchange spec

Returns

A signed request map with :url, :method, :headers, and :body.

timestamp_iso8601()

@spec timestamp_iso8601() :: String.t()

Current UTC time as ISO 8601 string, truncated to millisecond precision.

timestamp_iso8601_from_config(config)

@spec timestamp_iso8601_from_config(map()) :: String.t()

Like timestamp_ms_from_config/1 but rendered as ISO 8601 UTC.

timestamp_ms()

@spec timestamp_ms() :: non_neg_integer()

Current UTC time in milliseconds.

timestamp_ms_from_config(config)

@spec timestamp_ms_from_config(map()) :: non_neg_integer()

Returns config[:timestamp_ms_override] when set, otherwise current wall time in milliseconds. Used by pattern modules so fixture replay (T65) can inject the frozen timestamp CCXT JS signed with.

timestamp_seconds()

@spec timestamp_seconds() :: non_neg_integer()

Current UTC time in seconds.

timestamp_seconds_from_config(config)

@spec timestamp_seconds_from_config(map()) :: non_neg_integer()

Like timestamp_ms_from_config/1 but in seconds.

urlencode(params)

@spec urlencode(map() | nil) :: String.t()

URL-encodes params as a sorted query string.

urlencode_raw(params)

@spec urlencode_raw(map() | nil) :: String.t()

URL-encodes params as a sorted query string without percent-encoding values.