Packages

Elixir SDK for Hyperliquid DEX with DSL-based API endpoints, WebSocket subscriptions, and optional Postgres/Phoenix integration

Current section

Files

Jump to
hyperliquid lib hyperliquid api api.ex
Raw

lib/hyperliquid/api/api.ex

defmodule Hyperliquid.Api do
@moduledoc """
A base API macro for interacting with the Hyperliquid API.
This module provides a macro that sets up common functionality for API interactions,
including signing requests, handling different types of actions, and processing responses.
When used, it imports necessary modules, sets up aliases, and defines several helper functions
for making API calls.
## Usage
Use this module in other API-specific modules like this:
use Hyperliquid.Api, context: "evm"
## Configuration
This module relies on the following application environment variables:
- `:http_url` - The base URL for API requests
- `:is_mainnet` - Boolean indicating whether to use mainnet or testnet
- `:private_key` - The private key used for signing requests
"""
defmacro __using__(opts) do
quote do
import Hyperliquid.{Api, Utils}
alias Hyperliquid.{Config, Signer}
@context unquote(Keyword.get(opts, :context, ""))
@headers [{"Content-Type", "application/json"}]
def api_base, do: Config.api_base()
def mainnet?, do: Config.mainnet?()
def endpoint, do: "#{api_base()}/#{@context}"
defp secret, do: Config.secret()
def post_action(action), do: post_action(action, nil, get_timestamp(), secret())
def post_action(action, vault_address), do: post_action(action, vault_address, get_timestamp(), secret())
def post_action(action, vault_address, nonce), do: post_action(action, vault_address, nonce, secret())
def post_action(%{type: "usdSend"} = action, nil, nonce, secret) do
signature = Signer.sign_usd_transfer_action(action, mainnet?(), secret)
payload = %{
action: action,
nonce: nonce,
signature: signature,
vaultAddress: nil
}
post_signed(payload)
end
def post_action(%{type: "spotSend"} = action, nil, nonce, secret) do
signature = Signer.sign_spot_transfer_action(action, mainnet?(), secret)
payload = %{
action: action,
nonce: nonce,
signature: signature,
vaultAddress: nil
}
post_signed(payload)
end
def post_action(%{type: "withdraw3"} = action, nil, nonce, secret) do
signature = Signer.sign_withdraw_from_bridge_action(action, mainnet?(), secret)
payload = %{
action: action,
nonce: nonce,
signature: signature,
vaultAddress: nil
}
post_signed(payload)
end
def post_action(action, vault_address, nonce, secret) do
signature = Signer.sign_l1_action(action, vault_address, nonce, mainnet?(), secret)
payload = %{
action: action,
nonce: nonce,
signature: signature,
vaultAddress: vault_address
}
post_signed(payload)
end
def post(payload) do
HTTPoison.post(endpoint(), Jason.encode!(payload), @headers)
|> handle_response()
end
def post_signed(payload) do
HTTPoison.post(endpoint(), Jason.encode!(payload), @headers)
|> handle_response()
end
end
end
def handle_response({:ok, %HTTPoison.Response{status_code: 200, body: body}}) do
{:ok, Jason.decode!(body)}
end
def handle_response({:ok, %HTTPoison.Response{status_code: status_code, body: body}}) do
{:error, %{status_code: status_code, message: body}}
end
def handle_response({:error, %HTTPoison.Error{reason: reason}}) do
{:error, %{reason: reason}}
end
end