package bridge import ( "bytes" "context" "encoding/json" "fmt" "net/http" "os" "strconv" "time" ) const ( ccipTimeout = 5 * time.Second defaultCCIPFee = "100000000000000000" // ~0.1 LINK (18 decimals) ) // CCIP-supported chain pair: 138 <-> 1 var ccipSupportedPairs = map[string]bool{ "138-1": true, "1-138": true, } type ccipQuoteResponse struct { Fee string `json:"fee"` } // CCIPProvider implements Provider for Chainlink CCIP type CCIPProvider struct { quoteURL string client *http.Client } // NewCCIPProvider creates a new CCIP bridge provider func NewCCIPProvider() *CCIPProvider { quoteURL := os.Getenv("CCIP_ROUTER_QUOTE_URL") return &CCIPProvider{ quoteURL: quoteURL, client: &http.Client{ Timeout: ccipTimeout, }, } } // Name returns the provider name func (p *CCIPProvider) Name() string { return "CCIP" } // SupportsRoute returns true for 138 <-> 1 func (p *CCIPProvider) SupportsRoute(fromChain, toChain int) bool { key := strconv.Itoa(fromChain) + "-" + strconv.Itoa(toChain) return ccipSupportedPairs[key] } // GetQuote returns a bridge quote for 138 <-> 1 func (p *CCIPProvider) GetQuote(ctx context.Context, req *BridgeRequest) (*BridgeQuote, error) { if !p.SupportsRoute(req.FromChain, req.ToChain) { return nil, fmt.Errorf("CCIP: unsupported route %d -> %d", req.FromChain, req.ToChain) } fee := defaultCCIPFee if p.quoteURL != "" { body, err := json.Marshal(map[string]interface{}{ "sourceChain": req.FromChain, "destChain": req.ToChain, "token": req.FromToken, "amount": req.Amount, }) if err == nil { httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, p.quoteURL, bytes.NewReader(body)) if err == nil { httpReq.Header.Set("Content-Type", "application/json") resp, err := p.client.Do(httpReq) if err == nil && resp != nil { defer resp.Body.Close() if resp.StatusCode == http.StatusOK { var r ccipQuoteResponse if json.NewDecoder(resp.Body).Decode(&r) == nil && r.Fee != "" { fee = r.Fee } } } } } } return &BridgeQuote{ Provider: "CCIP", FromChain: req.FromChain, ToChain: req.ToChain, FromAmount: req.Amount, ToAmount: req.Amount, Fee: fee, EstimatedTime: "5-15 min", Route: []BridgeStep{ {Provider: "CCIP", From: strconv.Itoa(req.FromChain), To: strconv.Itoa(req.ToChain), Type: "bridge"}, }, }, nil }