LayerHopdocs

SDKs & tools

Go SDK

github.com/layerhop/layerhop-go — a dependency-free, context-aware Go client with typed models, an iterator-based Watch and webhook verification.

Open in ClaudeOpen in ChatGPT

layerhop-go is a typed client for the REST API that mirrors the TypeScript SDK. It uses only the standard library and needs Go 1.23+ (Watch returns an iter.Seq2). Every method takes a context.Context.

Source: github.com/layerhop/layerhop-go — source repository (opens at launch).

The SDK never holds keys. It returns unsigned transactions; your wallet library (go-ethereum, solana-go, a KMS…) signs and broadcasts them.

Install#

Terminal
go get github.com/layerhop/layerhop-go

Quickstart#

Amounts are integer strings in base units ("100000000" = 100 USDC).

go
lh := layerhop.New(layerhop.Options{APIKey: os.Getenv("LAYERHOP_API_KEY")})

// 1. Quote
q, err := lh.Quote(ctx, layerhop.QuoteParams{
	SrcChain: "base", SrcToken: "USDC", Amount: "100000000",
	DstChain: "solana", DstToken: "SOL",
	Sender: "0xYourEvmAddress", Recipient: "YourSolanaAddress",
})
if err != nil { return err }

// 2. Build the unsigned transaction
tx, err := lh.BuildTx(ctx, q.Best.QuoteID)
if err != nil { return err }

// 3. Sign + send with YOUR wallet library. EVM: send tx.Approval first when set, then
//    {To: tx.To, Data: tx.Data, Value: tx.Value} on tx.ChainID. Solana: sign tx.SerializedTx;
//    when tx.SubmitViaAPI is true, call lh.Submit(ctx, quoteID, signedBase64) instead of an RPC.
txHash := signAndSend(tx)

// 4. Report the broadcast
if _, err := lh.ReportSubmitted(ctx, q.Best.QuoteID, txHash); err != nil { return err }

// 5. Watch until filled / refunded / failed
for st, err := range lh.Watch(ctx, q.Best.Provider, txHash, layerhop.WatchOptions{}) {
	if err != nil { return err }
	fmt.Println(st.State)
}

Methods#

Method Endpoint
Health · Chains · Tokens(ctx, chain) GET /v1/health · /v1/chains · /v1/tokens
Quote(ctx, QuoteParams) GET /v1/quote
BuildTx(ctx, quoteID) POST /v1/orders
Simulate(ctx, quoteID) POST /v1/simulate
Submit(ctx, quoteID, signedTxBase64) POST /v1/orders/submit (Solana SubmitViaAPI only)
ReportSubmitted(ctx, quoteID, txHash) POST /v1/orders/{quoteId}/submitted
Status(ctx, provider, id) GET /v1/orders/{provider}/{id}
Watch(ctx, provider, id, WatchOptions) iter.Seq2[OrderStatus, error], one item per state change; stops when final, on error, or after ErrWatchTimeout (30 min by default)
ListOrders(ctx, ListOrdersParams) GET /v1/orders

Options: BaseURL (default https://api.layerhop.com), APIKey, Channel, Integrator, IntegratorFeeBps, HTTPClient, UserAgent.

Errors#

Non-2xx responses return *layerhop.APIError with Code, Message, Status and RequestID. The Code is one of the stable error codes.

go
var apiErr *layerhop.APIError
if errors.As(err, &apiErr) && apiErr.Code == "QUOTE_EXPIRED" {
	// re-quote
}

Webhooks#

go
body, _ := io.ReadAll(r.Body) // raw bytes
if err := layerhop.VerifyWebhookSignature(secret, body, r.Header.Get("LayerHop-Signature"), 0, time.Time{}); err != nil {
	http.Error(w, "bad signature", http.StatusUnauthorized)
	return
}

The header is t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>. A zero tolerance means the default of 300 s. The errors are ErrWebhookMalformedHeader, ErrWebhookTimestamp and ErrWebhookSignature.