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.
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#
go get github.com/layerhop/layerhop-goQuickstart#
Amounts are integer strings in base units ("100000000" = 100 USDC).
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.
var apiErr *layerhop.APIError
if errors.As(err, &apiErr) && apiErr.Code == "QUOTE_EXPIRED" {
// re-quote
}Webhooks#
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.