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) ) type ccipQuoteResponse struct { Fee string `json:"fee"` } // CCIPProvider implements Provider for Chainlink CCIP type CCIPProvider struct { quoteURL string client *http.Client cfg *Config } // NewCCIPProvider creates a new CCIP bridge provider. cfg can be nil (uses DefaultConfig). func NewCCIPProvider(cfg *Config) *CCIPProvider { if cfg == nil { cfg = DefaultConfig() } quoteURL := os.Getenv("CCIP_ROUTER_QUOTE_URL") return &CCIPProvider{ quoteURL: quoteURL, client: &http.Client{Timeout: ccipTimeout}, cfg: cfg, } } func (p *CCIPProvider) Name() string { return "CCIP" } func (p *CCIPProvider) SupportsRoute(fromChain, toChain int) bool { return p.cfg.SupportsCCIPRoute(fromChain, toChain) } 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 }