Examples
Golang
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/gagliardetto/solana-go"
)
var (
Endpoints = map[string]string{
"fra": "routerfra.systems-echo.com",
"ams": "routerams.systems-echo.com",
"ny": "routerny.systems-echo.com",
}
Endpoint = Endpoints["fra"] // use the closest endpoint to you
URL = fmt.Sprintf("https://%s", Endpoint)
)
type Direction string
const (
DirectionUnspecified Direction = "TRADE_DIRECTION_UNSPECIFIED"
DirectionBuy Direction = "TRADE_DIRECTION_BUY"
DirectionSell Direction = "TRADE_DIRECTION_SELL"
)
type Platform string
const (
PlatformTypeUnspecified Platform = "PLATFORM_UNSPECIFIED"
PlatformTypeRaydium Platform = "PLATFORM_RAYDIUM"
PlatformTypeRaydiumCp Platform = "PLATFORM_RAYDIUM_CP"
PlatformTypeRaydiumClmm Platform = "PLATFORM_RAYDIUM_CLMM"
PlatformTypePumpfun Platform = "PLATFORM_PUMPFUN"
PlatformTypeMoonShot Platform = "PLATFORM_MOONSHOT"
PlatformTypeMeteoraDyn Platform = "PLATFORM_METEORA_DYN"
PlatformTypeMeteoraDlmm Platform = "PLATFORM_METEORA_DLMM"
PlatformTypePamm Platform = "PLATFORM_PAMM"
PlatformTypeRaydiumLaunchpad Platform = "PLATFORM_RAYDIUM_LAUNCHPAD"
PlatformTypeMeteoraDbc Platform = "PLATFORM_METEORA_DBC"
PlatformTypeMeteoraDammV2 Platform = "PLATFORM_METEORA_DAMM_V2"
PlatformTypeHeaven Platform = "PLATFORM_HEAVEN"
)
type SwapSettings struct {
Fee float64 `json:"fee"`
Tip float64 `json:"tip"`
Slippage float64 `json:"slippage"`
}
type TokenInfo struct {
Address string `json:"address"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint32 `json:"decimals"`
IsStable bool `json:"isStable"`
}
type GenerateSwapRequest struct {
User string `json:"user"`
Input string `json:"input"`
Direction Direction `json:"direction"`
Amount string `json:"amount"`
Settings SwapSettings `json:"settings"`
NonceAccount string `json:"nonceAccount,omitempty"`
}
type GenerateSwapResponse struct {
Transactions []*SwapTransaction `json:"transactions"`
}
type SwapTransaction struct {
UnsignedTransaction string `json:"unsignedTransaction"`
}
type SubmitSwapRequest struct {
SignedTransactions []string `json:"signedTransactions"`
}
type SubmitSwapResponse struct {
Results []*SubmitSwapResult `json:"results"`
}
type SubmitSwapResult struct {
TransactionID string `json:"transactionId"`
Slot string `json:"slot"`
PoolID string `json:"poolId"`
Platform Platform `json:"platform"`
TokenIn *TokenInfo `json:"tokenIn"`
TokenOut *TokenInfo `json:"tokenOut"`
TokenInAmount string `json:"tokenInAmount"`
TokenOutAmount string `json:"tokenOutAmount"`
CreatedAt string `json:"createdAt"`
}
type Client struct {
apiKey string
client *http.Client
}
func NewClient(apiKey string) *Client {
return &Client{
apiKey: apiKey,
client: &http.Client{},
}
}
func (c *Client) Close() error {
if c.client != nil {
c.client.CloseIdleConnections()
}
return nil
}
func (c *Client) GenerateSwap(ctx context.Context, in *GenerateSwapRequest) (*GenerateSwapResponse, error) {
var out GenerateSwapResponse
err := c.call(ctx, http.MethodPost, "/api/v1/router/swap/generate", in, &out)
if err != nil {
return nil, err
}
return &out, nil
}
func (c *Client) SubmitSwap(ctx context.Context, in *SubmitSwapRequest) (*SubmitSwapResponse, error) {
var out SubmitSwapResponse
err := c.call(ctx, http.MethodPost, "/api/v1/router/swap/submit", in, &out)
if err != nil {
return nil, err
}
return &out, nil
}
func (c *Client) call(
ctx context.Context,
method, path string,
in, out interface{},
) error {
body, err := json.Marshal(in)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(
ctx,
method,
fmt.Sprintf("%s%s", URL, path),
bytes.NewReader(body),
)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.Header.Set("Echo-Api-Key", c.apiKey)
resp, err := c.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("%d: %s", resp.StatusCode, string(respBody))
}
if err := json.Unmarshal(respBody, out); err != nil {
return err
}
return nil
}
func main() {
apiKey := "YOUR_API_KEY"
user := solana.MustPrivateKeyFromBase58("YOUR_PRIVATE_KEY")
input := "YOUR INPUT" // can be token address or pool address
amount := "0.01" // or "50%" for balance-based"
direction := DirectionBuy
settings := SwapSettings{
Fee: 0.0001,
Tip: 0.001,
Slippage: 10,
}
nonceAccount := "YOUR_NONCE_ACCOUNT" // optional, BUT highly recommended to set
client := NewClient(apiKey)
defer client.Close()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
generateSwapReq := &GenerateSwapRequest{
User: user.PublicKey().String(),
Input: input,
Direction: direction,
Amount: amount,
Settings: settings,
NonceAccount: nonceAccount,
}
genResp, err := client.GenerateSwap(ctx, generateSwapReq)
if err != nil {
fmt.Printf("Error generating swap: %v\n", err)
return
}
fmt.Printf("Got %d transactions\n", len(genResp.Transactions))
signedTransactions := make([]string, len(genResp.Transactions))
for i := range genResp.Transactions {
r := genResp.Transactions[i]
var tx solana.Transaction
if err := tx.UnmarshalBase64(r.UnsignedTransaction); err != nil {
fmt.Printf("Error unmarshaling transaction: %v\n", err)
return
}
if _, err := tx.PartialSign(func(key solana.PublicKey) *solana.PrivateKey {
if user.PublicKey().Equals(key) {
return &user
}
return nil
}); err != nil {
fmt.Printf("Error signing transaction: %v\n", err)
return
}
signedTx, err := tx.ToBase64()
if err != nil {
fmt.Printf("Error marshaling signed transaction: %v\n", err)
return
}
signedTransactions[i] = signedTx
}
fmt.Printf("Signed %d transactions\n", len(signedTransactions))
// since we don't use nonce account in this example, submit only 1st tx
// if u use nonce account -> submit all transactions
txToSubmit := signedTransactions[:1]
submitSwapReq := &SubmitSwapRequest{
SignedTransactions: txToSubmit,
}
submitResp, err := client.SubmitSwap(ctx, submitSwapReq)
if err != nil {
fmt.Printf("Error submitting swap: %v\n", err)
return
}
fmt.Printf("Submitted %d transactions\n", len(submitResp.Results))
// by default, router will wait for 1 confirmation only
// so for now you can expect only 1 result
for i, r := range submitResp.Results {
fmt.Printf("Result %d: %+v\n", i, r)
}
}
Last updated

