Skip to content

Commit

Permalink
Add skeleton for lbtc attestation API integration
Browse files Browse the repository at this point in the history
  • Loading branch information
NourElRashidy committed Nov 28, 2024
1 parent a677d28 commit e7fd86d
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 5 deletions.
36 changes: 32 additions & 4 deletions core/services/ocr2/plugins/ccip/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func (c *DynamicPriceGetterConfig) Validate() error {
type ExecPluginJobSpecConfig struct {
SourceStartBlock, DestStartBlock uint64 // Only for first time job add.
USDCConfig USDCConfig
LBTCConfig LBTCConfig
}

type USDCConfig struct {
Expand All @@ -119,10 +120,20 @@ type USDCConfig struct {
AttestationAPIIntervalMilliseconds int
}

type LBTCConfig struct {
SourceTokenAddress common.Address
SourceMessageTransmitterAddress common.Address
AttestationAPI string
AttestationAPITimeoutSeconds uint
// AttestationAPIIntervalMilliseconds can be set to -1 to disable or 0 to use a default interval.
AttestationAPIIntervalMilliseconds int
}

type ExecPluginConfig struct {
SourceStartBlock, DestStartBlock uint64 // Only for first time job add.
IsSourceProvider bool
USDCConfig USDCConfig
LBTCConfig LBTCConfig
JobID string
}

Expand All @@ -136,16 +147,33 @@ func (e ExecPluginConfig) Encode() ([]byte, error) {

func (uc *USDCConfig) ValidateUSDCConfig() error {
if uc.AttestationAPI == "" {
return errors.New("AttestationAPI is required")
return errors.New("USDCConfig: AttestationAPI is required")
}
if uc.AttestationAPIIntervalMilliseconds < -1 {
return errors.New("AttestationAPIIntervalMilliseconds must be -1 to disable, 0 for default or greater to define the exact interval")
return errors.New("USDCConfig: AttestationAPIIntervalMilliseconds must be -1 to disable, 0 for default or greater to define the exact interval")
}
if uc.SourceTokenAddress == utils.ZeroAddress {
return errors.New("SourceTokenAddress is required")
return errors.New("USDCConfig: SourceTokenAddress is required")
}
if uc.SourceMessageTransmitterAddress == utils.ZeroAddress {
return errors.New("SourceMessageTransmitterAddress is required")
return errors.New("USDCConfig: SourceMessageTransmitterAddress is required")
}

return nil
}

func (lc *LBTCConfig) ValidateLBTCConfig() error {
if lc.AttestationAPI == "" {
return errors.New("LBTCConfig: AttestationAPI is required")
}
if lc.AttestationAPIIntervalMilliseconds < -1 {
return errors.New("LBTCConfig: AttestationAPIIntervalMilliseconds must be -1 to disable, 0 for default or greater to define the exact interval")
}
if lc.SourceTokenAddress == utils.ZeroAddress {
return errors.New("LBTCConfig: SourceTokenAddress is required")
}
if lc.SourceMessageTransmitterAddress == utils.ZeroAddress {
return errors.New("LBTCConfig: SourceMessageTransmitterAddress is required")
}

return nil
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ccipdata

// TODO: Implement lbtc token reader
type LBTCReader interface {
}
10 changes: 9 additions & 1 deletion core/services/ocr2/plugins/ccip/tokendata/http/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import (
)

type IHttpClient interface {
// Get issue a GET request to the given url and return the response body and status code.
// Get issues a GET request to the given url and returns the response body and status code.
Get(ctx context.Context, url string, timeout time.Duration) ([]byte, int, http.Header, error)

// Post issues a POST request to the given url with the given request data and returns the response body and status code.
Post(ctx context.Context, url string, requestData io.Reader, timeout time.Duration) ([]byte, int, http.Header, error)
}

type HttpClient struct {
Expand Down Expand Up @@ -46,3 +49,8 @@ func (s *HttpClient) Get(ctx context.Context, url string, timeout time.Duration)
body, err := io.ReadAll(res.Body)
return body, res.StatusCode, res.Header, err
}

func (s *HttpClient) Post(ctx context.Context, url string, requestData io.Reader, timeout time.Duration) ([]byte, int, http.Header, error) {
// TODO: Implement
return nil, 0, nil, nil
}
162 changes: 162 additions & 0 deletions core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package lbtc

import (
"context"
"errors"
"net/url"
"sync"
"time"

"github.com/ethereum/go-ethereum/common"
cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata/http"
"golang.org/x/time/rate"
)

// TODO: double check the validty of default values for lombard's API after checking docs
const (
apiVersion = "v1"
attestationPath = "deposits/getByHash"
defaultAttestationTimeout = 5 * time.Second

// defaultCoolDownDurationSec defines the default time to wait after getting rate limited.
// this value is only used if the 429 response does not contain the Retry-After header
defaultCoolDownDuration = 5 * time.Minute

Check failure on line 27 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

const `defaultCoolDownDuration` is unused (unused)

// maxCoolDownDuration defines the maximum duration we can wait till firing the next request
maxCoolDownDuration = 10 * time.Minute

Check failure on line 30 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

const `maxCoolDownDuration` is unused (unused)

// defaultRequestInterval defines the rate in requests per second that the attestation API can be called.
// this is set according to the APIs documentated 10 requests per second rate limit.
defaultRequestInterval = 100 * time.Millisecond

// APIIntervalRateLimitDisabled is a special value to disable the rate limiting.
APIIntervalRateLimitDisabled = -1
// APIIntervalRateLimitDefault is a special value to select the default rate limit interval.
APIIntervalRateLimitDefault = 0
)

type attestationStatus string

Check failure on line 42 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

type `attestationStatus` is unused (unused)

const (
attestationStatusUnspecified attestationStatus = "NOTARIZATION_STATUS_UNSPECIFIED"

Check failure on line 45 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

const `attestationStatusUnspecified` is unused (unused)
attestationStatusPending attestationStatus = "NOTARIZATION_STATUS_PENDING"
attestationStatusSubmitted attestationStatus = "NOTARIZATION_STATUS_SUBMITTED"
attestationStatusSessionApproved attestationStatus = "NOTARIZATION_STATUS_SESSION_APPROVED"
attestationStatusFailed attestationStatus = "NOTARIZATION_STATUS_FAILED"
)

var (
ErrUnknownResponse = errors.New("unexpected response from attestation API")
)

type TokenDataReader struct {
lggr logger.Logger
lbtcReader ccipdata.LBTCReader
httpClient http.IHttpClient
attestationApi *url.URL

Check failure on line 60 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field attestationApi should be attestationAPI (revive)
attestationApiTimeout time.Duration

Check failure on line 61 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field attestationApiTimeout should be attestationAPITimeout (revive)
lbtcTokenAddress common.Address
rate *rate.Limiter

// coolDownUntil defines whether requests are blocked or not.
coolDownUntil time.Time
coolDownMu *sync.RWMutex
}

type messageAttestationResponse struct {
MessageHash string `json:"message_hash"`
Status attestationStatus `json:"status"`
Attestation string `json:"attestation"`
}

// TODO: Adjust after checking API docs
type attestationResponse struct {
Attestations []messageAttestationResponse `json:"attestations"`
}

// TODO: Implement encoding/decoding

var _ tokendata.Reader = &TokenDataReader{}

func NewLBTCTokenDataReader(
lggr logger.Logger,
lbtcReader ccipdata.LBTCReader,
lbtcAttestationApi *url.URL,

Check failure on line 88 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: func parameter lbtcAttestationApi should be lbtcAttestationAPI (revive)
lbtcAttestationApiTimeoutSeconds int,

Check failure on line 89 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: func parameter lbtcAttestationApiTimeoutSeconds should be lbtcAttestationAPITimeoutSeconds (revive)
lbtcTokenAddress common.Address,
requestInterval time.Duration,
) *TokenDataReader {
timeout := time.Duration(lbtcAttestationApiTimeoutSeconds) * time.Second
if lbtcAttestationApiTimeoutSeconds == 0 {
timeout = defaultAttestationTimeout
}

if requestInterval == APIIntervalRateLimitDisabled {
requestInterval = 0
} else if requestInterval == APIIntervalRateLimitDefault {
requestInterval = defaultRequestInterval
}

return &TokenDataReader{
lggr: lggr,
lbtcReader: lbtcReader,
httpClient: http.NewObservedIHttpClient(&http.HttpClient{}),
attestationApi: lbtcAttestationApi,
attestationApiTimeout: timeout,
lbtcTokenAddress: lbtcTokenAddress,
coolDownMu: &sync.RWMutex{},
rate: rate.NewLimiter(rate.Every(requestInterval), 1),
}
}

func NewLBTCTokenDataReaderWithHttpClient(

Check failure on line 116 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: func NewLBTCTokenDataReaderWithHttpClient should be NewLBTCTokenDataReaderWithHTTPClient (revive)
origin TokenDataReader,
httpClient http.IHttpClient,
lbtcTokenAddress common.Address,
requestInterval time.Duration,
) *TokenDataReader {
return &TokenDataReader{
lggr: origin.lggr,
lbtcReader: origin.lbtcReader,
httpClient: httpClient,
attestationApi: origin.attestationApi,
attestationApiTimeout: origin.attestationApiTimeout,
coolDownMu: origin.coolDownMu,
lbtcTokenAddress: lbtcTokenAddress,
rate: rate.NewLimiter(rate.Every(requestInterval), 1),
}
}

// ReadTokenData queries the LBTC attestation API.
func (s *TokenDataReader) ReadTokenData(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int) ([]byte, error) {
// TODO: Implement
return nil, nil
}

func (s *TokenDataReader) callAttestationApi(ctx context.Context, usdcMessageHash [32]byte) (attestationResponse, error) {

Check failure on line 140 in core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: method callAttestationApi should be callAttestationAPI (revive)
// TODO: Implement after checking API docs
return attestationResponse{}, nil
}

func (s *TokenDataReader) setCoolDownPeriod(d time.Duration) {
s.coolDownMu.Lock()
if d > maxCoolDownDuration {
d = maxCoolDownDuration
}
s.coolDownUntil = time.Now().Add(d)
s.coolDownMu.Unlock()
}

func (s *TokenDataReader) inCoolDownPeriod() bool {
s.coolDownMu.RLock()
defer s.coolDownMu.RUnlock()
return time.Now().Before(s.coolDownUntil)
}

func (s *TokenDataReader) Close() error {
return nil
}
5 changes: 5 additions & 0 deletions core/services/relay/evm/exec_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type SrcExecProvider struct {
usdcAttestationAPIIntervalMilliseconds int
usdcSrcMsgTransmitterAddr common.Address

// TODO: Add lbtc reader & api fields

// these values are nil and are updated for Close()
seenOnRampAddress *cciptypes.Address
seenSourceChainSelector *uint64
Expand Down Expand Up @@ -71,6 +73,8 @@ func NewSrcExecProvider(
}
}

// TODO: Initialize lbtc reader

return &SrcExecProvider{
lggr: logger.Named(lggr, "SrcExecProvider"),
versionFinder: versionFinder,
Expand Down Expand Up @@ -188,6 +192,7 @@ func (s *SrcExecProvider) NewPriceRegistryReader(ctx context.Context, addr ccipt
return
}

// TODO: refactor to handle lbtc tokens. Separate methods.
func (s *SrcExecProvider) NewTokenDataReader(ctx context.Context, tokenAddress cciptypes.Address) (tokenDataReader cciptypes.TokenDataReader, err error) {
attestationURI, err2 := url.ParseRequestURI(s.usdcAttestationAPI)
if err2 != nil {
Expand Down

0 comments on commit e7fd86d

Please sign in to comment.