Files

102 lines
2.4 KiB
Go
Raw Permalink Normal View History

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
}