Go SDK for the Aster DEX V3 API (Spot + Futures, REST + WebSocket).
Aster V3 replaces the legacy HMAC-SHA256 auth with an API-wallet model based on EIP-712 typed data and ECDSA signatures. The legacy V1 API stopped issuing new keys on 2026-03-25; existing keys still work, but ongoing development happens here on V3. If you need V1, switch to the
V1(Legacy)branch.
- ✅ Spot REST: 24 endpoints — market data, orders, account, transfers, withdrawals
- ✅ Futures REST: ~45 endpoints — market, trading, position, account, MMP, sub-accounts
- ✅ WebSocket Streaming: full Spot & Futures market streams plus user data streams
- ✅ Sub-account Flows: bind / create / update / transfer with master + child signature inputs
- ✅ Flexible Signer: pluggable
SignFnfor HSM, TEE, or remote signing - ✅ TEE Injection:
WithTEEAuthlets the signer's private key stay inside the enclave — the SDK only holds the user/signer addresses and delegates signing viaWithSignRequestFn - ✅ Proxy Support:
WithProxy/WithWebSocketProxyroute REST and WebSocket traffic through HTTP, HTTPS, or SOCKS5 (socks5/socks5h) proxies, with optionaluser:pass@auth in the URL - ✅ Mainnet & Testnet: switch with
WithNetwork(common.Mainnet|common.Testnet)— base URL and chainId both follow
go get -u github.com/UnipayFI/go-aster/v3Module path is
github.com/UnipayFI/go-aster/v3(Go major-version convention). Requires Go 1.21+.
package main
import (
"context"
"fmt"
aster "github.com/UnipayFI/go-aster/v3"
)
func main() {
c := aster.NewSpotClient()
info, err := c.NewGetExchangeInfoService().Do(context.Background())
if err != nil {
panic(err)
}
fmt.Println("symbols:", len(info.Symbols))
}import (
aster "github.com/UnipayFI/go-aster/v3"
"github.com/UnipayFI/go-aster/v3/client"
)
c := aster.NewSpotClient(
client.WithAuth(
"0x...your master wallet address...",
"0x...your API wallet PRIVATE KEY (hex)...",
),
)WithAuth only needs the API wallet private key — the signer address is derived automatically. The first argument is the master wallet address; its private key never touches the client.
aster.NewSpotClient(...) // /api/v3/* REST
aster.NewSpotWebSocketClient(...) // wss://sstream.asterdex.com
aster.NewFuturesClient(...) // /fapi/v3/* REST
aster.NewFuturesWebSocketClient(...) // wss://fstream.asterdex.comclient.WithAuth(userAddress, signerPrivateKeyHex string)
client.WithTEEAuth(userAddress, signerAddress string) // TEE/HSM mode: no local private key
client.WithNetwork(common.Network) // common.Mainnet (default) / common.Testnet — sets base URL + chainId
client.WithBaseURL(string) // override the network's REST base URL (chainId still follows WithNetwork)
client.WithLogger(log.Logger) // slog-compatible interface
client.WithSignRequestFn(client.SignFn) // custom signer (HSM / TEE / remote)
client.WithRecvWindow(int64)
client.WithTimeOffset(int64) // ms; aligns nonce with server clockFor WebSocket clients, use client.WithWebSocketNetwork(common.Network) and client.WithWebSocketBaseURL(string) (the base URL override likewise takes priority over the network default).
import (
"github.com/UnipayFI/go-aster/v3/spot"
"github.com/shopspring/decimal"
)
order, err := c.NewPlaceOrderService("BTCUSDT", spot.SideBuy, spot.OrderTypeLimit).
SetTimeInForce(spot.TimeInForceGTC).
SetQuantity(decimal.NewFromFloat(0.01)).
SetPrice(decimal.NewFromInt(60000)).
Do(context.Background())ws := aster.NewSpotWebSocketClient()
done, stop, err := ws.NewSubscribeAggTradeService("BTCUSDT").
Do(context.Background(), func(ev *spot.WsAggTradeEvent, err error) {
if err != nil {
return
}
fmt.Println(ev.Symbol, ev.Price, ev.Quantity)
})
_, _, _ = done, stop, errspotREST := aster.NewSpotClient(client.WithAuth(user, signerPrivKeyHex))
key, _ := spotREST.NewCreateListenKeyService().Do(context.Background())
wsClient := aster.NewSpotWebSocketClient()
wsClient.NewSubscribeUserDataStreamService(key.ListenKey).
Do(context.Background(), func(ev *spot.WsUserDataEvent, err error) {
switch ev.EventType {
case "executionReport":
fmt.Println("order update:", ev.ExecutionReport.OrderStatus)
case "outboundAccountPosition":
fmt.Println("balances:", ev.AccountUpdate.Balances)
}
})For deployments where the API-wallet private key must stay inside a trusted execution environment, use WithTEEAuth to register the user/signer addresses and delegate the actual signing to your TEE binary via WithSignRequestFn. The SDK never sees the private key.
import (
"os/exec"
"strings"
aster "github.com/UnipayFI/go-aster/v3"
"github.com/UnipayFI/go-aster/v3/client"
)
c := aster.NewFuturesClient(
client.WithTEEAuth(
"0x...master wallet address...",
"0x...API wallet (signer) address...",
),
client.WithSignRequestFn(func(_ /*privateKeyHex*/, msg string, _ /*chainID*/ int64) (string, error) {
// Shell out to the TEE binary. API_KEY is read from the env by the TEE
// process; the private key is sealed inside the enclave.
out, err := exec.Command("./tee",
"--encrypt-type=EIP712-ECDSA",
"--input="+msg,
).Output()
if err != nil {
return "", err
}
return strings.TrimSpace(string(out)), nil
}),
)The companion TEE binary lives at UnipayFI/tee-encrypt. It reads the sealed signer key via the API_KEY env var, computes the EIP-712 digest internally (chainId 1666, the protocol-fixed Aster domain) and returns a 130-char hex signature with v ∈ {27, 28} — byte-compatible with the SDK's local signer.
Sub-account endpoints (Bind, Create, Update, Transfer) require signatures from the master wallet — and sometimes the child wallet — rather than the signer/agent. Because master keys typically live in cold storage, those services accept already-computed signatures as inputs:
import "github.com/UnipayFI/go-aster/v3/request"
// Caller computes signatures via request.SignEIP712V3 with the appropriate
// message body (see godoc on each service for the exact format).
sig, _ := request.SignEIP712V3(masterPrivKeyHex, msgBody, 1666)
c.NewBindSubAccountService(childAddr, name, user, nonce, childSig, sig).
Do(ctx)request.SignEIP712V3(privateKeyHex, msg, chainID) and request.EIP712Digest(msg, chainID) are exposed for callers that need to interact with these flows or implement their own signers.
V3 signing uses a fixed EIP-712 typed-data envelope:
domain.name = "AsterSignTransaction",version = "1",verifyingContract = 0x000...0chainId = 1666(mainnet) /714(testnet) — derived fromWithNetworkprimaryType = "Message", single fieldmsgof typestringmsgvalue = the URL-encoded query string of the request (already includingnonceandsigner)- Output signature has
vadjusted to27/28to matcheth_account.sign_message
See request/sign.go for the implementation and request/sign_test.go for the regression tests (digest stability, ecrecover round-trip, deterministic signatures, chainId sensitivity).
Spot REST (24)
Ping, GetServerTime, Noop, GetExchangeInfo, GetDepth, GetRecentTrades, GetHistoricalTrades, GetAggTrades, GetKlines, Get24hTicker, GetTickerPrice, GetBookTicker, GetCommissionRate, PlaceOrder, CancelOrder, GetOrder, GetOpenOrder, GetOpenOrders, CancelAllOpenOrders, GetAllOrders, GetTransactionHistory, PerpSpotTransfer, GetWithdrawFee, Withdraw, GetAccount, GetUserTrades.
Spot WebSocket
Subscribe{AggTrade,Trade,Kline,MiniTicker,AllMiniTickers,Ticker,AllTickers,BookTicker,AllBookTickers,PartialDepth,DiffDepth,TradePro,UserDataStream}. ListenKey REST: Create/Renew/DeleteListenKey.
Futures REST (~45)
- General:
Ping,Time,Noop - Market data:
ExchangeInfo,Depth,Trades,HistoricalTrades,AggTrades,Klines,IndexPriceKlines,MarkPriceKlines,PremiumIndex,FundingRate,FundingInfo,24hTicker,TickerPrice,BookTicker,IndexReferences - Trading:
PlaceOrder,ModifyOrder,BatchOrders,FuturesSpotTransfer,GetOrder,CancelOrder,CancelAllOpenOrders,CancelMultipleOrders,CountdownCancelAll,GetOpenOrder,GetOpenOrders,GetAllOrders - Position config:
ChangePositionMode,GetPositionMode,ChangeMultiAssetsMode,GetMultiAssetsMode,ChangeLeverage,ChangeMarginType,ModifyIsolatedPositionMargin,GetPositionMarginHistory,PositionRisk,ADLQuantile,ForceOrders - Account:
Balance,Account,UserTrades,IncomeHistory,LeverageBracket,CommissionRate - MMP:
UpdateMMP,GetMMP,DeleteMMP,ResetMMP - Sub-accounts:
Bind,Create,GetList,Update,Transfer
Futures WebSocket
- Market:
AggTrade,MarkPrice,AllMarkPrices,Kline,MiniTicker,AllMiniTickers,Ticker,AllTickers,BookTicker,AllBookTickers,ForceOrder,AllForceOrders,PartialDepth,DiffDepth - User data:
UserDataStream - ListenKey REST:
Create/Renew/DeleteListenKey
Released under the MIT License.