package bridge import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "strconv" "time" ) const ( squidAPIBase = "https://v2.api.squidrouter.com" squidTimeout = 10 * time.Second squidIntegrator = "explorer-bridge-aggregator" ) var squidSupportedChains = map[int]bool{ 1: true, 10: true, 137: true, 42161: true, 8453: true, 56: true, 43114: true, 100: true, 25: true, 250: true, 324: true, 59144: true, 534352: true, 42220: true, 5000: true, 1111: true, } type squidReq struct { FromAddress string `json:"fromAddress"` FromChain string `json:"fromChain"` FromToken string `json:"fromToken"` FromAmount string `json:"fromAmount"` ToChain string `json:"toChain"` ToToken string `json:"toToken"` ToAddress string `json:"toAddress"` Slippage int `json:"slippage"` } type squidResp struct { Route *struct { Estimate *struct { ToAmount string `json:"toAmount"` ToAmountMin string `json:"toAmountMin"` } `json:"estimate"` } `json:"route"` } type SquidProvider struct { apiBase string client *http.Client } func NewSquidProvider() *SquidProvider { return &SquidProvider{apiBase: squidAPIBase, client: &http.Client{Timeout: squidTimeout}} } func (p *SquidProvider) Name() string { return "Squid" } func (p *SquidProvider) SupportsRoute(fromChain, toChain int) bool { return squidSupportedChains[fromChain] && squidSupportedChains[toChain] } func (p *SquidProvider) GetQuote(ctx context.Context, req *BridgeRequest) (*BridgeQuote, error) { addr := req.Recipient if addr == "" { addr = "0x0000000000000000000000000000000000000000" } bodyReq := squidReq{ FromAddress: addr, FromChain: strconv.Itoa(req.FromChain), FromToken: req.FromToken, FromAmount: req.Amount, ToChain: strconv.Itoa(req.ToChain), ToToken: req.ToToken, ToAddress: addr, Slippage: 1, } jsonBody, _ := json.Marshal(bodyReq) httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, p.apiBase+"/v2/route", bytes.NewReader(jsonBody)) if err != nil { return nil, err } httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-integrator-id", squidIntegrator) resp, err := p.client.Do(httpReq) if err != nil { return nil, err } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("Squid API %d: %s", resp.StatusCode, string(body)) } var r squidResp if err := json.Unmarshal(body, &r); err != nil { return nil, err } if r.Route == nil || r.Route.Estimate == nil { return nil, fmt.Errorf("Squid: no route") } toAmount := r.Route.Estimate.ToAmount if toAmount == "" { toAmount = r.Route.Estimate.ToAmountMin } if toAmount == "" { return nil, fmt.Errorf("Squid: no amount") } return &BridgeQuote{ Provider: "Squid", FromChain: req.FromChain, ToChain: req.ToChain, FromAmount: req.Amount, ToAmount: toAmount, Fee: "0", EstimatedTime: "1-5 min", Route: []BridgeStep{{Provider: "Squid", From: strconv.Itoa(req.FromChain), To: strconv.Itoa(req.ToChain), Type: "bridge"}}, }, nil }