diff --git a/pkg/loop/internal/pb/ccipocr3/chainaccessor.pb.go b/pkg/loop/internal/pb/ccipocr3/chainaccessor.pb.go index 2ba41826a..762346e21 100644 --- a/pkg/loop/internal/pb/ccipocr3/chainaccessor.pb.go +++ b/pkg/loop/internal/pb/ccipocr3/chainaccessor.pb.go @@ -734,8 +734,8 @@ func (x *GetChainFeePriceUpdateRequest) GetChainSelectors() []uint64 { } type GetChainFeePriceUpdateResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - FeePriceUpdates map[uint64]*TimestampedBig `protobuf:"bytes,1,rep,name=fee_price_updates,json=feePriceUpdates,proto3" json:"fee_price_updates,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key is chain selector + state protoimpl.MessageState `protogen:"open.v1"` + FeePriceUpdates map[uint64]*TimestampedUnixBig `protobuf:"bytes,1,rep,name=fee_price_updates,json=feePriceUpdates,proto3" json:"fee_price_updates,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key is chain selector unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -770,7 +770,7 @@ func (*GetChainFeePriceUpdateResponse) Descriptor() ([]byte, []int) { return file_chainaccessor_proto_rawDescGZIP(), []int{15} } -func (x *GetChainFeePriceUpdateResponse) GetFeePriceUpdates() map[uint64]*TimestampedBig { +func (x *GetChainFeePriceUpdateResponse) GetFeePriceUpdates() map[uint64]*TimestampedUnixBig { if x != nil { return x.FeePriceUpdates } @@ -3147,6 +3147,417 @@ func (x *FeeQuoterDestChainConfig) GetChainFamilySelector() []byte { return nil } +// USDCMessageReader request/response messages +type MessagesByTokenIDRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SourceChainSelector uint64 `protobuf:"varint,1,opt,name=source_chain_selector,json=sourceChainSelector,proto3" json:"source_chain_selector,omitempty"` + DestChainSelector uint64 `protobuf:"varint,2,opt,name=dest_chain_selector,json=destChainSelector,proto3" json:"dest_chain_selector,omitempty"` + Tokens map[string]*RampTokenAmount `protobuf:"bytes,3,rep,name=tokens,proto3" json:"tokens,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key is MessageTokenID string representation + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MessagesByTokenIDRequest) Reset() { + *x = MessagesByTokenIDRequest{} + mi := &file_chainaccessor_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MessagesByTokenIDRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessagesByTokenIDRequest) ProtoMessage() {} + +func (x *MessagesByTokenIDRequest) ProtoReflect() protoreflect.Message { + mi := &file_chainaccessor_proto_msgTypes[58] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessagesByTokenIDRequest.ProtoReflect.Descriptor instead. +func (*MessagesByTokenIDRequest) Descriptor() ([]byte, []int) { + return file_chainaccessor_proto_rawDescGZIP(), []int{58} +} + +func (x *MessagesByTokenIDRequest) GetSourceChainSelector() uint64 { + if x != nil { + return x.SourceChainSelector + } + return 0 +} + +func (x *MessagesByTokenIDRequest) GetDestChainSelector() uint64 { + if x != nil { + return x.DestChainSelector + } + return 0 +} + +func (x *MessagesByTokenIDRequest) GetTokens() map[string]*RampTokenAmount { + if x != nil { + return x.Tokens + } + return nil +} + +type MessagesByTokenIDResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Messages map[string][]byte `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key is MessageTokenID string representation, value is message bytes + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MessagesByTokenIDResponse) Reset() { + *x = MessagesByTokenIDResponse{} + mi := &file_chainaccessor_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MessagesByTokenIDResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessagesByTokenIDResponse) ProtoMessage() {} + +func (x *MessagesByTokenIDResponse) ProtoReflect() protoreflect.Message { + mi := &file_chainaccessor_proto_msgTypes[59] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessagesByTokenIDResponse.ProtoReflect.Descriptor instead. +func (*MessagesByTokenIDResponse) Descriptor() ([]byte, []int) { + return file_chainaccessor_proto_rawDescGZIP(), []int{59} +} + +func (x *MessagesByTokenIDResponse) GetMessages() map[string][]byte { + if x != nil { + return x.Messages + } + return nil +} + +// PriceReader request/response messages +type GetFeedPricesUSDRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tokens []string `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens,omitempty"` // UnknownEncodedAddress + TokenInfo map[string]*TokenInfo `protobuf:"bytes,2,rep,name=token_info,json=tokenInfo,proto3" json:"token_info,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key is UnknownEncodedAddress + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFeedPricesUSDRequest) Reset() { + *x = GetFeedPricesUSDRequest{} + mi := &file_chainaccessor_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFeedPricesUSDRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFeedPricesUSDRequest) ProtoMessage() {} + +func (x *GetFeedPricesUSDRequest) ProtoReflect() protoreflect.Message { + mi := &file_chainaccessor_proto_msgTypes[60] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFeedPricesUSDRequest.ProtoReflect.Descriptor instead. +func (*GetFeedPricesUSDRequest) Descriptor() ([]byte, []int) { + return file_chainaccessor_proto_rawDescGZIP(), []int{60} +} + +func (x *GetFeedPricesUSDRequest) GetTokens() []string { + if x != nil { + return x.Tokens + } + return nil +} + +func (x *GetFeedPricesUSDRequest) GetTokenInfo() map[string]*TokenInfo { + if x != nil { + return x.TokenInfo + } + return nil +} + +type GetFeedPricesUSDResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Prices map[string]*BigInt `protobuf:"bytes,1,rep,name=prices,proto3" json:"prices,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key is UnknownEncodedAddress, value is price + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFeedPricesUSDResponse) Reset() { + *x = GetFeedPricesUSDResponse{} + mi := &file_chainaccessor_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFeedPricesUSDResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFeedPricesUSDResponse) ProtoMessage() {} + +func (x *GetFeedPricesUSDResponse) ProtoReflect() protoreflect.Message { + mi := &file_chainaccessor_proto_msgTypes[61] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFeedPricesUSDResponse.ProtoReflect.Descriptor instead. +func (*GetFeedPricesUSDResponse) Descriptor() ([]byte, []int) { + return file_chainaccessor_proto_rawDescGZIP(), []int{61} +} + +func (x *GetFeedPricesUSDResponse) GetPrices() map[string]*BigInt { + if x != nil { + return x.Prices + } + return nil +} + +type GetFeeQuoterTokenUpdatesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tokens []string `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens,omitempty"` // UnknownEncodedAddress + ChainSelector uint64 `protobuf:"varint,2,opt,name=chain_selector,json=chainSelector,proto3" json:"chain_selector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFeeQuoterTokenUpdatesRequest) Reset() { + *x = GetFeeQuoterTokenUpdatesRequest{} + mi := &file_chainaccessor_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFeeQuoterTokenUpdatesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFeeQuoterTokenUpdatesRequest) ProtoMessage() {} + +func (x *GetFeeQuoterTokenUpdatesRequest) ProtoReflect() protoreflect.Message { + mi := &file_chainaccessor_proto_msgTypes[62] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFeeQuoterTokenUpdatesRequest.ProtoReflect.Descriptor instead. +func (*GetFeeQuoterTokenUpdatesRequest) Descriptor() ([]byte, []int) { + return file_chainaccessor_proto_rawDescGZIP(), []int{62} +} + +func (x *GetFeeQuoterTokenUpdatesRequest) GetTokens() []string { + if x != nil { + return x.Tokens + } + return nil +} + +func (x *GetFeeQuoterTokenUpdatesRequest) GetChainSelector() uint64 { + if x != nil { + return x.ChainSelector + } + return 0 +} + +type GetFeeQuoterTokenUpdatesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + TokenUpdates map[string]*TimestampedUnixBig `protobuf:"bytes,1,rep,name=token_updates,json=tokenUpdates,proto3" json:"token_updates,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key is UnknownEncodedAddress + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFeeQuoterTokenUpdatesResponse) Reset() { + *x = GetFeeQuoterTokenUpdatesResponse{} + mi := &file_chainaccessor_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFeeQuoterTokenUpdatesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFeeQuoterTokenUpdatesResponse) ProtoMessage() {} + +func (x *GetFeeQuoterTokenUpdatesResponse) ProtoReflect() protoreflect.Message { + mi := &file_chainaccessor_proto_msgTypes[63] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFeeQuoterTokenUpdatesResponse.ProtoReflect.Descriptor instead. +func (*GetFeeQuoterTokenUpdatesResponse) Descriptor() ([]byte, []int) { + return file_chainaccessor_proto_rawDescGZIP(), []int{63} +} + +func (x *GetFeeQuoterTokenUpdatesResponse) GetTokenUpdates() map[string]*TimestampedUnixBig { + if x != nil { + return x.TokenUpdates + } + return nil +} + +// Helper message types +type MessageTokenID struct { + state protoimpl.MessageState `protogen:"open.v1"` + SeqNr uint64 `protobuf:"varint,1,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` + Index int32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MessageTokenID) Reset() { + *x = MessageTokenID{} + mi := &file_chainaccessor_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MessageTokenID) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageTokenID) ProtoMessage() {} + +func (x *MessageTokenID) ProtoReflect() protoreflect.Message { + mi := &file_chainaccessor_proto_msgTypes[64] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessageTokenID.ProtoReflect.Descriptor instead. +func (*MessageTokenID) Descriptor() ([]byte, []int) { + return file_chainaccessor_proto_rawDescGZIP(), []int{64} +} + +func (x *MessageTokenID) GetSeqNr() uint64 { + if x != nil { + return x.SeqNr + } + return 0 +} + +func (x *MessageTokenID) GetIndex() int32 { + if x != nil { + return x.Index + } + return 0 +} + +type TokenInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + AggregatorAddress string `protobuf:"bytes,1,opt,name=aggregator_address,json=aggregatorAddress,proto3" json:"aggregator_address,omitempty"` // UnknownEncodedAddress + DeviationPpb *BigInt `protobuf:"bytes,2,opt,name=deviation_ppb,json=deviationPpb,proto3" json:"deviation_ppb,omitempty"` + Decimals uint32 `protobuf:"varint,3,opt,name=decimals,proto3" json:"decimals,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TokenInfo) Reset() { + *x = TokenInfo{} + mi := &file_chainaccessor_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TokenInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TokenInfo) ProtoMessage() {} + +func (x *TokenInfo) ProtoReflect() protoreflect.Message { + mi := &file_chainaccessor_proto_msgTypes[65] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TokenInfo.ProtoReflect.Descriptor instead. +func (*TokenInfo) Descriptor() ([]byte, []int) { + return file_chainaccessor_proto_rawDescGZIP(), []int{65} +} + +func (x *TokenInfo) GetAggregatorAddress() string { + if x != nil { + return x.AggregatorAddress + } + return "" +} + +func (x *TokenInfo) GetDeviationPpb() *BigInt { + if x != nil { + return x.DeviationPpb + } + return nil +} + +func (x *TokenInfo) GetDecimals() uint32 { + if x != nil { + return x.Decimals + } + return 0 +} + var File_chainaccessor_proto protoreflect.FileDescriptor const file_chainaccessor_proto_rawDesc = "" + @@ -3205,12 +3616,12 @@ const file_chainaccessor_proto_rawDesc = "" + "\x03key\x18\x01 \x01(\x04R\x03key\x129\n" + "\x05value\x18\x02 \x01(\v2#.loop.internal.pb.ccipocr3.NonceMapR\x05value:\x028\x01\"H\n" + "\x1dGetChainFeePriceUpdateRequest\x12'\n" + - "\x0fchain_selectors\x18\x01 \x03(\x04R\x0echainSelectors\"\x8b\x02\n" + + "\x0fchain_selectors\x18\x01 \x03(\x04R\x0echainSelectors\"\x8f\x02\n" + "\x1eGetChainFeePriceUpdateResponse\x12z\n" + - "\x11fee_price_updates\x18\x01 \x03(\v2N.loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.FeePriceUpdatesEntryR\x0ffeePriceUpdates\x1am\n" + + "\x11fee_price_updates\x18\x01 \x03(\v2N.loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.FeePriceUpdatesEntryR\x0ffeePriceUpdates\x1aq\n" + "\x14FeePriceUpdatesEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\x04R\x03key\x12?\n" + - "\x05value\x18\x02 \x01(\v2).loop.internal.pb.ccipocr3.TimestampedBigR\x05value:\x028\x01\"4\n" + + "\x03key\x18\x01 \x01(\x04R\x03key\x12C\n" + + "\x05value\x18\x02 \x01(\v2-.loop.internal.pb.ccipocr3.TimestampedUnixBigR\x05value:\x028\x01\"4\n" + "\x1bGetLatestPriceSeqNrResponse\x12\x15\n" + "\x06seq_nr\x18\x01 \x01(\x04R\x05seqNr\"\x97\x01\n" + "\x19MsgsBetweenSeqNumsRequest\x12.\n" + @@ -3381,7 +3792,46 @@ const file_chainaccessor_proto_rawDesc = "" + "\x16network_fee_usdc_cents\x18\x0e \x01(\rR\x13networkFeeUsdcCents\x12A\n" + "\x1dgas_price_staleness_threshold\x18\x13 \x01(\rR\x1agasPriceStalenessThreshold\x12/\n" + "\x14enforce_out_of_order\x18\x0f \x01(\bR\x11enforceOutOfOrder\x122\n" + - "\x15chain_family_selector\x18\x10 \x01(\fR\x13chainFamilySelector2\xe3\x0e\n" + + "\x15chain_family_selector\x18\x10 \x01(\fR\x13chainFamilySelector\"\xbe\x02\n" + + "\x18MessagesByTokenIDRequest\x122\n" + + "\x15source_chain_selector\x18\x01 \x01(\x04R\x13sourceChainSelector\x12.\n" + + "\x13dest_chain_selector\x18\x02 \x01(\x04R\x11destChainSelector\x12W\n" + + "\x06tokens\x18\x03 \x03(\v2?.loop.internal.pb.ccipocr3.MessagesByTokenIDRequest.TokensEntryR\x06tokens\x1ae\n" + + "\vTokensEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12@\n" + + "\x05value\x18\x02 \x01(\v2*.loop.internal.pb.ccipocr3.RampTokenAmountR\x05value:\x028\x01\"\xb8\x01\n" + + "\x19MessagesByTokenIDResponse\x12^\n" + + "\bmessages\x18\x01 \x03(\v2B.loop.internal.pb.ccipocr3.MessagesByTokenIDResponse.MessagesEntryR\bmessages\x1a;\n" + + "\rMessagesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\fR\x05value:\x028\x01\"\xf7\x01\n" + + "\x17GetFeedPricesUSDRequest\x12\x16\n" + + "\x06tokens\x18\x01 \x03(\tR\x06tokens\x12`\n" + + "\n" + + "token_info\x18\x02 \x03(\v2A.loop.internal.pb.ccipocr3.GetFeedPricesUSDRequest.TokenInfoEntryR\ttokenInfo\x1ab\n" + + "\x0eTokenInfoEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12:\n" + + "\x05value\x18\x02 \x01(\v2$.loop.internal.pb.ccipocr3.TokenInfoR\x05value:\x028\x01\"\xd1\x01\n" + + "\x18GetFeedPricesUSDResponse\x12W\n" + + "\x06prices\x18\x01 \x03(\v2?.loop.internal.pb.ccipocr3.GetFeedPricesUSDResponse.PricesEntryR\x06prices\x1a\\\n" + + "\vPricesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x127\n" + + "\x05value\x18\x02 \x01(\v2!.loop.internal.pb.ccipocr3.BigIntR\x05value:\x028\x01\"`\n" + + "\x1fGetFeeQuoterTokenUpdatesRequest\x12\x16\n" + + "\x06tokens\x18\x01 \x03(\tR\x06tokens\x12%\n" + + "\x0echain_selector\x18\x02 \x01(\x04R\rchainSelector\"\x86\x02\n" + + " GetFeeQuoterTokenUpdatesResponse\x12r\n" + + "\rtoken_updates\x18\x01 \x03(\v2M.loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesResponse.TokenUpdatesEntryR\ftokenUpdates\x1an\n" + + "\x11TokenUpdatesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12C\n" + + "\x05value\x18\x02 \x01(\v2-.loop.internal.pb.ccipocr3.TimestampedUnixBigR\x05value:\x028\x01\"=\n" + + "\x0eMessageTokenID\x12\x15\n" + + "\x06seq_nr\x18\x01 \x01(\x04R\x05seqNr\x12\x14\n" + + "\x05index\x18\x02 \x01(\x05R\x05index\"\x9e\x01\n" + + "\tTokenInfo\x12-\n" + + "\x12aggregator_address\x18\x01 \x01(\tR\x11aggregatorAddress\x12F\n" + + "\rdeviation_ppb\x18\x02 \x01(\v2!.loop.internal.pb.ccipocr3.BigIntR\fdeviationPpb\x12\x1a\n" + + "\bdecimals\x18\x03 \x01(\rR\bdecimals2\xf6\x11\n" + "\rChainAccessor\x12\x81\x01\n" + "\x12GetContractAddress\x124.loop.internal.pb.ccipocr3.GetContractAddressRequest\x1a5.loop.internal.pb.ccipocr3.GetContractAddressResponse\x12\x84\x01\n" + "\x13GetAllConfigsLegacy\x125.loop.internal.pb.ccipocr3.GetAllConfigsLegacyRequest\x1a6.loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse\x12i\n" + @@ -3398,7 +3848,10 @@ const file_chainaccessor_proto_rawDesc = "" + "\x0fLatestMessageTo\x121.loop.internal.pb.ccipocr3.LatestMessageToRequest\x1a2.loop.internal.pb.ccipocr3.LatestMessageToResponse\x12\xa2\x01\n" + "\x1dGetExpectedNextSequenceNumber\x12?.loop.internal.pb.ccipocr3.GetExpectedNextSequenceNumberRequest\x1a@.loop.internal.pb.ccipocr3.GetExpectedNextSequenceNumberResponse\x12{\n" + "\x10GetTokenPriceUSD\x122.loop.internal.pb.ccipocr3.GetTokenPriceUSDRequest\x1a3.loop.internal.pb.ccipocr3.GetTokenPriceUSDResponse\x12\x9c\x01\n" + - "\x1bGetFeeQuoterDestChainConfig\x12=.loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigRequest\x1a>.loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigResponseBWZUgithub.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb/ccipocr3;ccipocr3pbb\x06proto3" + "\x1bGetFeeQuoterDestChainConfig\x12=.loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigRequest\x1a>.loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigResponse\x12~\n" + + "\x11MessagesByTokenID\x123.loop.internal.pb.ccipocr3.MessagesByTokenIDRequest\x1a4.loop.internal.pb.ccipocr3.MessagesByTokenIDResponse\x12{\n" + + "\x10GetFeedPricesUSD\x122.loop.internal.pb.ccipocr3.GetFeedPricesUSDRequest\x1a3.loop.internal.pb.ccipocr3.GetFeedPricesUSDResponse\x12\x93\x01\n" + + "\x18GetFeeQuoterTokenUpdates\x12:.loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesRequest\x1a;.loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesResponseBWZUgithub.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb/ccipocr3;ccipocr3pbb\x06proto3" var ( file_chainaccessor_proto_rawDescOnce sync.Once @@ -3412,7 +3865,7 @@ func file_chainaccessor_proto_rawDescGZIP() []byte { return file_chainaccessor_proto_rawDescData } -var file_chainaccessor_proto_msgTypes = make([]protoimpl.MessageInfo, 67) +var file_chainaccessor_proto_msgTypes = make([]protoimpl.MessageInfo, 80) var file_chainaccessor_proto_goTypes = []any{ (*GetContractAddressRequest)(nil), // 0: loop.internal.pb.ccipocr3.GetContractAddressRequest (*GetContractAddressResponse)(nil), // 1: loop.internal.pb.ccipocr3.GetContractAddressResponse @@ -3472,47 +3925,61 @@ var file_chainaccessor_proto_goTypes = []any{ (*CurseInfo)(nil), // 55: loop.internal.pb.ccipocr3.CurseInfo (*SourceChainConfig)(nil), // 56: loop.internal.pb.ccipocr3.SourceChainConfig (*FeeQuoterDestChainConfig)(nil), // 57: loop.internal.pb.ccipocr3.FeeQuoterDestChainConfig - nil, // 58: loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.SourceChainConfigsEntry - nil, // 59: loop.internal.pb.ccipocr3.ExecutedMessagesRequest.RangesEntry - nil, // 60: loop.internal.pb.ccipocr3.ExecutedMessagesResponse.ExecutedMessagesEntry - nil, // 61: loop.internal.pb.ccipocr3.NextSeqNumResponse.NextSeqNumsEntry - nil, // 62: loop.internal.pb.ccipocr3.NoncesRequest.AddressesEntry - nil, // 63: loop.internal.pb.ccipocr3.NoncesResponse.NoncesEntry - nil, // 64: loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.FeePriceUpdatesEntry - nil, // 65: loop.internal.pb.ccipocr3.NonceMap.NoncesEntry - nil, // 66: loop.internal.pb.ccipocr3.CurseInfo.CursedSourceChainsEntry - (*timestamppb.Timestamp)(nil), // 67: google.protobuf.Timestamp - (*SeqNumRange)(nil), // 68: loop.internal.pb.ccipocr3.SeqNumRange - (*Message)(nil), // 69: loop.internal.pb.ccipocr3.Message - (*BigInt)(nil), // 70: loop.internal.pb.ccipocr3.BigInt - (*CommitPluginReport)(nil), // 71: loop.internal.pb.ccipocr3.CommitPluginReport - (*emptypb.Empty)(nil), // 72: google.protobuf.Empty + (*MessagesByTokenIDRequest)(nil), // 58: loop.internal.pb.ccipocr3.MessagesByTokenIDRequest + (*MessagesByTokenIDResponse)(nil), // 59: loop.internal.pb.ccipocr3.MessagesByTokenIDResponse + (*GetFeedPricesUSDRequest)(nil), // 60: loop.internal.pb.ccipocr3.GetFeedPricesUSDRequest + (*GetFeedPricesUSDResponse)(nil), // 61: loop.internal.pb.ccipocr3.GetFeedPricesUSDResponse + (*GetFeeQuoterTokenUpdatesRequest)(nil), // 62: loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesRequest + (*GetFeeQuoterTokenUpdatesResponse)(nil), // 63: loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesResponse + (*MessageTokenID)(nil), // 64: loop.internal.pb.ccipocr3.MessageTokenID + (*TokenInfo)(nil), // 65: loop.internal.pb.ccipocr3.TokenInfo + nil, // 66: loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.SourceChainConfigsEntry + nil, // 67: loop.internal.pb.ccipocr3.ExecutedMessagesRequest.RangesEntry + nil, // 68: loop.internal.pb.ccipocr3.ExecutedMessagesResponse.ExecutedMessagesEntry + nil, // 69: loop.internal.pb.ccipocr3.NextSeqNumResponse.NextSeqNumsEntry + nil, // 70: loop.internal.pb.ccipocr3.NoncesRequest.AddressesEntry + nil, // 71: loop.internal.pb.ccipocr3.NoncesResponse.NoncesEntry + nil, // 72: loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.FeePriceUpdatesEntry + nil, // 73: loop.internal.pb.ccipocr3.NonceMap.NoncesEntry + nil, // 74: loop.internal.pb.ccipocr3.CurseInfo.CursedSourceChainsEntry + nil, // 75: loop.internal.pb.ccipocr3.MessagesByTokenIDRequest.TokensEntry + nil, // 76: loop.internal.pb.ccipocr3.MessagesByTokenIDResponse.MessagesEntry + nil, // 77: loop.internal.pb.ccipocr3.GetFeedPricesUSDRequest.TokenInfoEntry + nil, // 78: loop.internal.pb.ccipocr3.GetFeedPricesUSDResponse.PricesEntry + nil, // 79: loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesResponse.TokenUpdatesEntry + (*timestamppb.Timestamp)(nil), // 80: google.protobuf.Timestamp + (*SeqNumRange)(nil), // 81: loop.internal.pb.ccipocr3.SeqNumRange + (*Message)(nil), // 82: loop.internal.pb.ccipocr3.Message + (*BigInt)(nil), // 83: loop.internal.pb.ccipocr3.BigInt + (*CommitPluginReport)(nil), // 84: loop.internal.pb.ccipocr3.CommitPluginReport + (*RampTokenAmount)(nil), // 85: loop.internal.pb.ccipocr3.RampTokenAmount + (*emptypb.Empty)(nil), // 86: google.protobuf.Empty } var file_chainaccessor_proto_depIdxs = []int32{ 54, // 0: loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.snapshot:type_name -> loop.internal.pb.ccipocr3.ChainConfigSnapshot - 58, // 1: loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.source_chain_configs:type_name -> loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.SourceChainConfigsEntry + 66, // 1: loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.source_chain_configs:type_name -> loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.SourceChainConfigsEntry 27, // 2: loop.internal.pb.ccipocr3.GetChainFeeComponentsResponse.fee_components:type_name -> loop.internal.pb.ccipocr3.ChainFeeComponents - 67, // 3: loop.internal.pb.ccipocr3.CommitReportsGTETimestampRequest.timestamp:type_name -> google.protobuf.Timestamp + 80, // 3: loop.internal.pb.ccipocr3.CommitReportsGTETimestampRequest.timestamp:type_name -> google.protobuf.Timestamp 28, // 4: loop.internal.pb.ccipocr3.CommitReportsGTETimestampResponse.reports:type_name -> loop.internal.pb.ccipocr3.CommitPluginReportWithMeta - 59, // 5: loop.internal.pb.ccipocr3.ExecutedMessagesRequest.ranges:type_name -> loop.internal.pb.ccipocr3.ExecutedMessagesRequest.RangesEntry - 60, // 6: loop.internal.pb.ccipocr3.ExecutedMessagesResponse.executed_messages:type_name -> loop.internal.pb.ccipocr3.ExecutedMessagesResponse.ExecutedMessagesEntry - 61, // 7: loop.internal.pb.ccipocr3.NextSeqNumResponse.next_seq_nums:type_name -> loop.internal.pb.ccipocr3.NextSeqNumResponse.NextSeqNumsEntry - 62, // 8: loop.internal.pb.ccipocr3.NoncesRequest.addresses:type_name -> loop.internal.pb.ccipocr3.NoncesRequest.AddressesEntry - 63, // 9: loop.internal.pb.ccipocr3.NoncesResponse.nonces:type_name -> loop.internal.pb.ccipocr3.NoncesResponse.NoncesEntry - 64, // 10: loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.fee_price_updates:type_name -> loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.FeePriceUpdatesEntry - 68, // 11: loop.internal.pb.ccipocr3.MsgsBetweenSeqNumsRequest.seq_num_range:type_name -> loop.internal.pb.ccipocr3.SeqNumRange - 69, // 12: loop.internal.pb.ccipocr3.MsgsBetweenSeqNumsResponse.messages:type_name -> loop.internal.pb.ccipocr3.Message + 67, // 5: loop.internal.pb.ccipocr3.ExecutedMessagesRequest.ranges:type_name -> loop.internal.pb.ccipocr3.ExecutedMessagesRequest.RangesEntry + 68, // 6: loop.internal.pb.ccipocr3.ExecutedMessagesResponse.executed_messages:type_name -> loop.internal.pb.ccipocr3.ExecutedMessagesResponse.ExecutedMessagesEntry + 69, // 7: loop.internal.pb.ccipocr3.NextSeqNumResponse.next_seq_nums:type_name -> loop.internal.pb.ccipocr3.NextSeqNumResponse.NextSeqNumsEntry + 70, // 8: loop.internal.pb.ccipocr3.NoncesRequest.addresses:type_name -> loop.internal.pb.ccipocr3.NoncesRequest.AddressesEntry + 71, // 9: loop.internal.pb.ccipocr3.NoncesResponse.nonces:type_name -> loop.internal.pb.ccipocr3.NoncesResponse.NoncesEntry + 72, // 10: loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.fee_price_updates:type_name -> loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.FeePriceUpdatesEntry + 81, // 11: loop.internal.pb.ccipocr3.MsgsBetweenSeqNumsRequest.seq_num_range:type_name -> loop.internal.pb.ccipocr3.SeqNumRange + 82, // 12: loop.internal.pb.ccipocr3.MsgsBetweenSeqNumsResponse.messages:type_name -> loop.internal.pb.ccipocr3.Message 30, // 13: loop.internal.pb.ccipocr3.GetTokenPriceUSDResponse.price:type_name -> loop.internal.pb.ccipocr3.TimestampedUnixBig 57, // 14: loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigResponse.config:type_name -> loop.internal.pb.ccipocr3.FeeQuoterDestChainConfig - 70, // 15: loop.internal.pb.ccipocr3.ChainFeeComponents.execution_fee:type_name -> loop.internal.pb.ccipocr3.BigInt - 70, // 16: loop.internal.pb.ccipocr3.ChainFeeComponents.data_availability_fee:type_name -> loop.internal.pb.ccipocr3.BigInt - 71, // 17: loop.internal.pb.ccipocr3.CommitPluginReportWithMeta.report:type_name -> loop.internal.pb.ccipocr3.CommitPluginReport - 67, // 18: loop.internal.pb.ccipocr3.CommitPluginReportWithMeta.timestamp:type_name -> google.protobuf.Timestamp - 67, // 19: loop.internal.pb.ccipocr3.TimestampedBig.timestamp:type_name -> google.protobuf.Timestamp - 70, // 20: loop.internal.pb.ccipocr3.TimestampedBig.value:type_name -> loop.internal.pb.ccipocr3.BigInt - 70, // 21: loop.internal.pb.ccipocr3.TimestampedUnixBig.value:type_name -> loop.internal.pb.ccipocr3.BigInt - 68, // 22: loop.internal.pb.ccipocr3.SequenceNumberRangeList.ranges:type_name -> loop.internal.pb.ccipocr3.SeqNumRange - 65, // 23: loop.internal.pb.ccipocr3.NonceMap.nonces:type_name -> loop.internal.pb.ccipocr3.NonceMap.NoncesEntry + 83, // 15: loop.internal.pb.ccipocr3.ChainFeeComponents.execution_fee:type_name -> loop.internal.pb.ccipocr3.BigInt + 83, // 16: loop.internal.pb.ccipocr3.ChainFeeComponents.data_availability_fee:type_name -> loop.internal.pb.ccipocr3.BigInt + 84, // 17: loop.internal.pb.ccipocr3.CommitPluginReportWithMeta.report:type_name -> loop.internal.pb.ccipocr3.CommitPluginReport + 80, // 18: loop.internal.pb.ccipocr3.CommitPluginReportWithMeta.timestamp:type_name -> google.protobuf.Timestamp + 80, // 19: loop.internal.pb.ccipocr3.TimestampedBig.timestamp:type_name -> google.protobuf.Timestamp + 83, // 20: loop.internal.pb.ccipocr3.TimestampedBig.value:type_name -> loop.internal.pb.ccipocr3.BigInt + 83, // 21: loop.internal.pb.ccipocr3.TimestampedUnixBig.value:type_name -> loop.internal.pb.ccipocr3.BigInt + 81, // 22: loop.internal.pb.ccipocr3.SequenceNumberRangeList.ranges:type_name -> loop.internal.pb.ccipocr3.SeqNumRange + 73, // 23: loop.internal.pb.ccipocr3.NonceMap.nonces:type_name -> loop.internal.pb.ccipocr3.NonceMap.NoncesEntry 36, // 24: loop.internal.pb.ccipocr3.OfframpConfig.commit_latest_ocr_config:type_name -> loop.internal.pb.ccipocr3.OCRConfigResponse 36, // 25: loop.internal.pb.ccipocr3.OfframpConfig.exec_latest_ocr_config:type_name -> loop.internal.pb.ccipocr3.OCRConfigResponse 39, // 26: loop.internal.pb.ccipocr3.OfframpConfig.static_config:type_name -> loop.internal.pb.ccipocr3.OffRampStaticChainConfig @@ -3524,7 +3991,7 @@ var file_chainaccessor_proto_depIdxs = []int32{ 45, // 32: loop.internal.pb.ccipocr3.VersionedConfig.config:type_name -> loop.internal.pb.ccipocr3.RMNConfig 46, // 33: loop.internal.pb.ccipocr3.RMNConfig.signers:type_name -> loop.internal.pb.ccipocr3.SignerInfo 48, // 34: loop.internal.pb.ccipocr3.FeeQuoterConfigStruct.static_config:type_name -> loop.internal.pb.ccipocr3.FeeQuoterStaticConfigStruct - 70, // 35: loop.internal.pb.ccipocr3.FeeQuoterStaticConfigStruct.max_fee_juels_per_msg:type_name -> loop.internal.pb.ccipocr3.BigInt + 83, // 35: loop.internal.pb.ccipocr3.FeeQuoterStaticConfigStruct.max_fee_juels_per_msg:type_name -> loop.internal.pb.ccipocr3.BigInt 50, // 36: loop.internal.pb.ccipocr3.OnRampConfigStruct.dynamic_config:type_name -> loop.internal.pb.ccipocr3.GetOnRampDynamicConfigResponse 52, // 37: loop.internal.pb.ccipocr3.OnRampConfigStruct.dest_chain_config:type_name -> loop.internal.pb.ccipocr3.OnRampDestChainConfig 51, // 38: loop.internal.pb.ccipocr3.GetOnRampDynamicConfigResponse.dynamic_config:type_name -> loop.internal.pb.ccipocr3.OnRampDynamicConfig @@ -3535,48 +4002,64 @@ var file_chainaccessor_proto_depIdxs = []int32{ 49, // 43: loop.internal.pb.ccipocr3.ChainConfigSnapshot.on_ramp:type_name -> loop.internal.pb.ccipocr3.OnRampConfigStruct 53, // 44: loop.internal.pb.ccipocr3.ChainConfigSnapshot.router:type_name -> loop.internal.pb.ccipocr3.RouterConfigStruct 55, // 45: loop.internal.pb.ccipocr3.ChainConfigSnapshot.curse_info:type_name -> loop.internal.pb.ccipocr3.CurseInfo - 66, // 46: loop.internal.pb.ccipocr3.CurseInfo.cursed_source_chains:type_name -> loop.internal.pb.ccipocr3.CurseInfo.CursedSourceChainsEntry - 56, // 47: loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.SourceChainConfigsEntry.value:type_name -> loop.internal.pb.ccipocr3.SourceChainConfig - 31, // 48: loop.internal.pb.ccipocr3.ExecutedMessagesRequest.RangesEntry.value:type_name -> loop.internal.pb.ccipocr3.SequenceNumberRangeList - 32, // 49: loop.internal.pb.ccipocr3.ExecutedMessagesResponse.ExecutedMessagesEntry.value:type_name -> loop.internal.pb.ccipocr3.SequenceNumberList - 33, // 50: loop.internal.pb.ccipocr3.NoncesRequest.AddressesEntry.value:type_name -> loop.internal.pb.ccipocr3.UnknownEncodedAddressList - 34, // 51: loop.internal.pb.ccipocr3.NoncesResponse.NoncesEntry.value:type_name -> loop.internal.pb.ccipocr3.NonceMap - 29, // 52: loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.FeePriceUpdatesEntry.value:type_name -> loop.internal.pb.ccipocr3.TimestampedBig - 0, // 53: loop.internal.pb.ccipocr3.ChainAccessor.GetContractAddress:input_type -> loop.internal.pb.ccipocr3.GetContractAddressRequest - 2, // 54: loop.internal.pb.ccipocr3.ChainAccessor.GetAllConfigsLegacy:input_type -> loop.internal.pb.ccipocr3.GetAllConfigsLegacyRequest - 72, // 55: loop.internal.pb.ccipocr3.ChainAccessor.GetChainFeeComponents:input_type -> google.protobuf.Empty - 5, // 56: loop.internal.pb.ccipocr3.ChainAccessor.Sync:input_type -> loop.internal.pb.ccipocr3.SyncRequest - 6, // 57: loop.internal.pb.ccipocr3.ChainAccessor.CommitReportsGTETimestamp:input_type -> loop.internal.pb.ccipocr3.CommitReportsGTETimestampRequest - 8, // 58: loop.internal.pb.ccipocr3.ChainAccessor.ExecutedMessages:input_type -> loop.internal.pb.ccipocr3.ExecutedMessagesRequest - 10, // 59: loop.internal.pb.ccipocr3.ChainAccessor.NextSeqNum:input_type -> loop.internal.pb.ccipocr3.NextSeqNumRequest - 12, // 60: loop.internal.pb.ccipocr3.ChainAccessor.Nonces:input_type -> loop.internal.pb.ccipocr3.NoncesRequest - 14, // 61: loop.internal.pb.ccipocr3.ChainAccessor.GetChainFeePriceUpdate:input_type -> loop.internal.pb.ccipocr3.GetChainFeePriceUpdateRequest - 72, // 62: loop.internal.pb.ccipocr3.ChainAccessor.GetLatestPriceSeqNr:input_type -> google.protobuf.Empty - 17, // 63: loop.internal.pb.ccipocr3.ChainAccessor.MsgsBetweenSeqNums:input_type -> loop.internal.pb.ccipocr3.MsgsBetweenSeqNumsRequest - 19, // 64: loop.internal.pb.ccipocr3.ChainAccessor.LatestMessageTo:input_type -> loop.internal.pb.ccipocr3.LatestMessageToRequest - 21, // 65: loop.internal.pb.ccipocr3.ChainAccessor.GetExpectedNextSequenceNumber:input_type -> loop.internal.pb.ccipocr3.GetExpectedNextSequenceNumberRequest - 23, // 66: loop.internal.pb.ccipocr3.ChainAccessor.GetTokenPriceUSD:input_type -> loop.internal.pb.ccipocr3.GetTokenPriceUSDRequest - 25, // 67: loop.internal.pb.ccipocr3.ChainAccessor.GetFeeQuoterDestChainConfig:input_type -> loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigRequest - 1, // 68: loop.internal.pb.ccipocr3.ChainAccessor.GetContractAddress:output_type -> loop.internal.pb.ccipocr3.GetContractAddressResponse - 3, // 69: loop.internal.pb.ccipocr3.ChainAccessor.GetAllConfigsLegacy:output_type -> loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse - 4, // 70: loop.internal.pb.ccipocr3.ChainAccessor.GetChainFeeComponents:output_type -> loop.internal.pb.ccipocr3.GetChainFeeComponentsResponse - 72, // 71: loop.internal.pb.ccipocr3.ChainAccessor.Sync:output_type -> google.protobuf.Empty - 7, // 72: loop.internal.pb.ccipocr3.ChainAccessor.CommitReportsGTETimestamp:output_type -> loop.internal.pb.ccipocr3.CommitReportsGTETimestampResponse - 9, // 73: loop.internal.pb.ccipocr3.ChainAccessor.ExecutedMessages:output_type -> loop.internal.pb.ccipocr3.ExecutedMessagesResponse - 11, // 74: loop.internal.pb.ccipocr3.ChainAccessor.NextSeqNum:output_type -> loop.internal.pb.ccipocr3.NextSeqNumResponse - 13, // 75: loop.internal.pb.ccipocr3.ChainAccessor.Nonces:output_type -> loop.internal.pb.ccipocr3.NoncesResponse - 15, // 76: loop.internal.pb.ccipocr3.ChainAccessor.GetChainFeePriceUpdate:output_type -> loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse - 16, // 77: loop.internal.pb.ccipocr3.ChainAccessor.GetLatestPriceSeqNr:output_type -> loop.internal.pb.ccipocr3.GetLatestPriceSeqNrResponse - 18, // 78: loop.internal.pb.ccipocr3.ChainAccessor.MsgsBetweenSeqNums:output_type -> loop.internal.pb.ccipocr3.MsgsBetweenSeqNumsResponse - 20, // 79: loop.internal.pb.ccipocr3.ChainAccessor.LatestMessageTo:output_type -> loop.internal.pb.ccipocr3.LatestMessageToResponse - 22, // 80: loop.internal.pb.ccipocr3.ChainAccessor.GetExpectedNextSequenceNumber:output_type -> loop.internal.pb.ccipocr3.GetExpectedNextSequenceNumberResponse - 24, // 81: loop.internal.pb.ccipocr3.ChainAccessor.GetTokenPriceUSD:output_type -> loop.internal.pb.ccipocr3.GetTokenPriceUSDResponse - 26, // 82: loop.internal.pb.ccipocr3.ChainAccessor.GetFeeQuoterDestChainConfig:output_type -> loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigResponse - 68, // [68:83] is the sub-list for method output_type - 53, // [53:68] is the sub-list for method input_type - 53, // [53:53] is the sub-list for extension type_name - 53, // [53:53] is the sub-list for extension extendee - 0, // [0:53] is the sub-list for field type_name + 74, // 46: loop.internal.pb.ccipocr3.CurseInfo.cursed_source_chains:type_name -> loop.internal.pb.ccipocr3.CurseInfo.CursedSourceChainsEntry + 75, // 47: loop.internal.pb.ccipocr3.MessagesByTokenIDRequest.tokens:type_name -> loop.internal.pb.ccipocr3.MessagesByTokenIDRequest.TokensEntry + 76, // 48: loop.internal.pb.ccipocr3.MessagesByTokenIDResponse.messages:type_name -> loop.internal.pb.ccipocr3.MessagesByTokenIDResponse.MessagesEntry + 77, // 49: loop.internal.pb.ccipocr3.GetFeedPricesUSDRequest.token_info:type_name -> loop.internal.pb.ccipocr3.GetFeedPricesUSDRequest.TokenInfoEntry + 78, // 50: loop.internal.pb.ccipocr3.GetFeedPricesUSDResponse.prices:type_name -> loop.internal.pb.ccipocr3.GetFeedPricesUSDResponse.PricesEntry + 79, // 51: loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesResponse.token_updates:type_name -> loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesResponse.TokenUpdatesEntry + 83, // 52: loop.internal.pb.ccipocr3.TokenInfo.deviation_ppb:type_name -> loop.internal.pb.ccipocr3.BigInt + 56, // 53: loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse.SourceChainConfigsEntry.value:type_name -> loop.internal.pb.ccipocr3.SourceChainConfig + 31, // 54: loop.internal.pb.ccipocr3.ExecutedMessagesRequest.RangesEntry.value:type_name -> loop.internal.pb.ccipocr3.SequenceNumberRangeList + 32, // 55: loop.internal.pb.ccipocr3.ExecutedMessagesResponse.ExecutedMessagesEntry.value:type_name -> loop.internal.pb.ccipocr3.SequenceNumberList + 33, // 56: loop.internal.pb.ccipocr3.NoncesRequest.AddressesEntry.value:type_name -> loop.internal.pb.ccipocr3.UnknownEncodedAddressList + 34, // 57: loop.internal.pb.ccipocr3.NoncesResponse.NoncesEntry.value:type_name -> loop.internal.pb.ccipocr3.NonceMap + 30, // 58: loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse.FeePriceUpdatesEntry.value:type_name -> loop.internal.pb.ccipocr3.TimestampedUnixBig + 85, // 59: loop.internal.pb.ccipocr3.MessagesByTokenIDRequest.TokensEntry.value:type_name -> loop.internal.pb.ccipocr3.RampTokenAmount + 65, // 60: loop.internal.pb.ccipocr3.GetFeedPricesUSDRequest.TokenInfoEntry.value:type_name -> loop.internal.pb.ccipocr3.TokenInfo + 83, // 61: loop.internal.pb.ccipocr3.GetFeedPricesUSDResponse.PricesEntry.value:type_name -> loop.internal.pb.ccipocr3.BigInt + 30, // 62: loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesResponse.TokenUpdatesEntry.value:type_name -> loop.internal.pb.ccipocr3.TimestampedUnixBig + 0, // 63: loop.internal.pb.ccipocr3.ChainAccessor.GetContractAddress:input_type -> loop.internal.pb.ccipocr3.GetContractAddressRequest + 2, // 64: loop.internal.pb.ccipocr3.ChainAccessor.GetAllConfigsLegacy:input_type -> loop.internal.pb.ccipocr3.GetAllConfigsLegacyRequest + 86, // 65: loop.internal.pb.ccipocr3.ChainAccessor.GetChainFeeComponents:input_type -> google.protobuf.Empty + 5, // 66: loop.internal.pb.ccipocr3.ChainAccessor.Sync:input_type -> loop.internal.pb.ccipocr3.SyncRequest + 6, // 67: loop.internal.pb.ccipocr3.ChainAccessor.CommitReportsGTETimestamp:input_type -> loop.internal.pb.ccipocr3.CommitReportsGTETimestampRequest + 8, // 68: loop.internal.pb.ccipocr3.ChainAccessor.ExecutedMessages:input_type -> loop.internal.pb.ccipocr3.ExecutedMessagesRequest + 10, // 69: loop.internal.pb.ccipocr3.ChainAccessor.NextSeqNum:input_type -> loop.internal.pb.ccipocr3.NextSeqNumRequest + 12, // 70: loop.internal.pb.ccipocr3.ChainAccessor.Nonces:input_type -> loop.internal.pb.ccipocr3.NoncesRequest + 14, // 71: loop.internal.pb.ccipocr3.ChainAccessor.GetChainFeePriceUpdate:input_type -> loop.internal.pb.ccipocr3.GetChainFeePriceUpdateRequest + 86, // 72: loop.internal.pb.ccipocr3.ChainAccessor.GetLatestPriceSeqNr:input_type -> google.protobuf.Empty + 17, // 73: loop.internal.pb.ccipocr3.ChainAccessor.MsgsBetweenSeqNums:input_type -> loop.internal.pb.ccipocr3.MsgsBetweenSeqNumsRequest + 19, // 74: loop.internal.pb.ccipocr3.ChainAccessor.LatestMessageTo:input_type -> loop.internal.pb.ccipocr3.LatestMessageToRequest + 21, // 75: loop.internal.pb.ccipocr3.ChainAccessor.GetExpectedNextSequenceNumber:input_type -> loop.internal.pb.ccipocr3.GetExpectedNextSequenceNumberRequest + 23, // 76: loop.internal.pb.ccipocr3.ChainAccessor.GetTokenPriceUSD:input_type -> loop.internal.pb.ccipocr3.GetTokenPriceUSDRequest + 25, // 77: loop.internal.pb.ccipocr3.ChainAccessor.GetFeeQuoterDestChainConfig:input_type -> loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigRequest + 58, // 78: loop.internal.pb.ccipocr3.ChainAccessor.MessagesByTokenID:input_type -> loop.internal.pb.ccipocr3.MessagesByTokenIDRequest + 60, // 79: loop.internal.pb.ccipocr3.ChainAccessor.GetFeedPricesUSD:input_type -> loop.internal.pb.ccipocr3.GetFeedPricesUSDRequest + 62, // 80: loop.internal.pb.ccipocr3.ChainAccessor.GetFeeQuoterTokenUpdates:input_type -> loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesRequest + 1, // 81: loop.internal.pb.ccipocr3.ChainAccessor.GetContractAddress:output_type -> loop.internal.pb.ccipocr3.GetContractAddressResponse + 3, // 82: loop.internal.pb.ccipocr3.ChainAccessor.GetAllConfigsLegacy:output_type -> loop.internal.pb.ccipocr3.GetAllConfigsLegacyResponse + 4, // 83: loop.internal.pb.ccipocr3.ChainAccessor.GetChainFeeComponents:output_type -> loop.internal.pb.ccipocr3.GetChainFeeComponentsResponse + 86, // 84: loop.internal.pb.ccipocr3.ChainAccessor.Sync:output_type -> google.protobuf.Empty + 7, // 85: loop.internal.pb.ccipocr3.ChainAccessor.CommitReportsGTETimestamp:output_type -> loop.internal.pb.ccipocr3.CommitReportsGTETimestampResponse + 9, // 86: loop.internal.pb.ccipocr3.ChainAccessor.ExecutedMessages:output_type -> loop.internal.pb.ccipocr3.ExecutedMessagesResponse + 11, // 87: loop.internal.pb.ccipocr3.ChainAccessor.NextSeqNum:output_type -> loop.internal.pb.ccipocr3.NextSeqNumResponse + 13, // 88: loop.internal.pb.ccipocr3.ChainAccessor.Nonces:output_type -> loop.internal.pb.ccipocr3.NoncesResponse + 15, // 89: loop.internal.pb.ccipocr3.ChainAccessor.GetChainFeePriceUpdate:output_type -> loop.internal.pb.ccipocr3.GetChainFeePriceUpdateResponse + 16, // 90: loop.internal.pb.ccipocr3.ChainAccessor.GetLatestPriceSeqNr:output_type -> loop.internal.pb.ccipocr3.GetLatestPriceSeqNrResponse + 18, // 91: loop.internal.pb.ccipocr3.ChainAccessor.MsgsBetweenSeqNums:output_type -> loop.internal.pb.ccipocr3.MsgsBetweenSeqNumsResponse + 20, // 92: loop.internal.pb.ccipocr3.ChainAccessor.LatestMessageTo:output_type -> loop.internal.pb.ccipocr3.LatestMessageToResponse + 22, // 93: loop.internal.pb.ccipocr3.ChainAccessor.GetExpectedNextSequenceNumber:output_type -> loop.internal.pb.ccipocr3.GetExpectedNextSequenceNumberResponse + 24, // 94: loop.internal.pb.ccipocr3.ChainAccessor.GetTokenPriceUSD:output_type -> loop.internal.pb.ccipocr3.GetTokenPriceUSDResponse + 26, // 95: loop.internal.pb.ccipocr3.ChainAccessor.GetFeeQuoterDestChainConfig:output_type -> loop.internal.pb.ccipocr3.GetFeeQuoterDestChainConfigResponse + 59, // 96: loop.internal.pb.ccipocr3.ChainAccessor.MessagesByTokenID:output_type -> loop.internal.pb.ccipocr3.MessagesByTokenIDResponse + 61, // 97: loop.internal.pb.ccipocr3.ChainAccessor.GetFeedPricesUSD:output_type -> loop.internal.pb.ccipocr3.GetFeedPricesUSDResponse + 63, // 98: loop.internal.pb.ccipocr3.ChainAccessor.GetFeeQuoterTokenUpdates:output_type -> loop.internal.pb.ccipocr3.GetFeeQuoterTokenUpdatesResponse + 81, // [81:99] is the sub-list for method output_type + 63, // [63:81] is the sub-list for method input_type + 63, // [63:63] is the sub-list for extension type_name + 63, // [63:63] is the sub-list for extension extendee + 0, // [0:63] is the sub-list for field type_name } func init() { file_chainaccessor_proto_init() } @@ -3591,7 +4074,7 @@ func file_chainaccessor_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_chainaccessor_proto_rawDesc), len(file_chainaccessor_proto_rawDesc)), NumEnums: 0, - NumMessages: 67, + NumMessages: 80, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/loop/internal/pb/ccipocr3/chainaccessor.proto b/pkg/loop/internal/pb/ccipocr3/chainaccessor.proto index 8b170ec5a..d9faef8e8 100644 --- a/pkg/loop/internal/pb/ccipocr3/chainaccessor.proto +++ b/pkg/loop/internal/pb/ccipocr3/chainaccessor.proto @@ -30,6 +30,13 @@ service ChainAccessor { rpc GetExpectedNextSequenceNumber(GetExpectedNextSequenceNumberRequest) returns (GetExpectedNextSequenceNumberResponse); rpc GetTokenPriceUSD(GetTokenPriceUSDRequest) returns (GetTokenPriceUSDResponse); rpc GetFeeQuoterDestChainConfig(GetFeeQuoterDestChainConfigRequest) returns (GetFeeQuoterDestChainConfigResponse); + + // USDCMessageReader methods + rpc MessagesByTokenID(MessagesByTokenIDRequest) returns (MessagesByTokenIDResponse); + + // PriceReader methods + rpc GetFeedPricesUSD(GetFeedPricesUSDRequest) returns (GetFeedPricesUSDResponse); + rpc GetFeeQuoterTokenUpdates(GetFeeQuoterTokenUpdatesRequest) returns (GetFeeQuoterTokenUpdatesResponse); } // AllAccessors request/response messages @@ -101,7 +108,7 @@ message GetChainFeePriceUpdateRequest { } message GetChainFeePriceUpdateResponse { - map fee_price_updates = 1; // key is chain selector + map fee_price_updates = 1; // key is chain selector } message GetLatestPriceSeqNrResponse { @@ -337,4 +344,46 @@ message FeeQuoterDestChainConfig { uint32 gas_price_staleness_threshold = 19; bool enforce_out_of_order = 15; bytes chain_family_selector = 16; // [4]byte in Go +} + +// USDCMessageReader request/response messages +message MessagesByTokenIDRequest { + uint64 source_chain_selector = 1; + uint64 dest_chain_selector = 2; + map tokens = 3; // key is MessageTokenID string representation +} + +message MessagesByTokenIDResponse { + map messages = 1; // key is MessageTokenID string representation, value is message bytes +} + +// PriceReader request/response messages +message GetFeedPricesUSDRequest { + repeated string tokens = 1; // UnknownEncodedAddress + map token_info = 2; // key is UnknownEncodedAddress +} + +message GetFeedPricesUSDResponse { + map prices = 1; // key is UnknownEncodedAddress, value is price +} + +message GetFeeQuoterTokenUpdatesRequest { + repeated string tokens = 1; // UnknownEncodedAddress + uint64 chain_selector = 2; +} + +message GetFeeQuoterTokenUpdatesResponse { + map token_updates = 1; // key is UnknownEncodedAddress +} + +// Helper message types +message MessageTokenID { + uint64 seq_nr = 1; + int32 index = 2; +} + +message TokenInfo { + string aggregator_address = 1; // UnknownEncodedAddress + BigInt deviation_ppb = 2; + uint32 decimals = 3; } \ No newline at end of file diff --git a/pkg/loop/internal/pb/ccipocr3/chainaccessor_grpc.pb.go b/pkg/loop/internal/pb/ccipocr3/chainaccessor_grpc.pb.go index 540ed4288..96d53631d 100644 --- a/pkg/loop/internal/pb/ccipocr3/chainaccessor_grpc.pb.go +++ b/pkg/loop/internal/pb/ccipocr3/chainaccessor_grpc.pb.go @@ -35,6 +35,9 @@ const ( ChainAccessor_GetExpectedNextSequenceNumber_FullMethodName = "/loop.internal.pb.ccipocr3.ChainAccessor/GetExpectedNextSequenceNumber" ChainAccessor_GetTokenPriceUSD_FullMethodName = "/loop.internal.pb.ccipocr3.ChainAccessor/GetTokenPriceUSD" ChainAccessor_GetFeeQuoterDestChainConfig_FullMethodName = "/loop.internal.pb.ccipocr3.ChainAccessor/GetFeeQuoterDestChainConfig" + ChainAccessor_MessagesByTokenID_FullMethodName = "/loop.internal.pb.ccipocr3.ChainAccessor/MessagesByTokenID" + ChainAccessor_GetFeedPricesUSD_FullMethodName = "/loop.internal.pb.ccipocr3.ChainAccessor/GetFeedPricesUSD" + ChainAccessor_GetFeeQuoterTokenUpdates_FullMethodName = "/loop.internal.pb.ccipocr3.ChainAccessor/GetFeeQuoterTokenUpdates" ) // ChainAccessorClient is the client API for ChainAccessor service. @@ -61,6 +64,11 @@ type ChainAccessorClient interface { GetExpectedNextSequenceNumber(ctx context.Context, in *GetExpectedNextSequenceNumberRequest, opts ...grpc.CallOption) (*GetExpectedNextSequenceNumberResponse, error) GetTokenPriceUSD(ctx context.Context, in *GetTokenPriceUSDRequest, opts ...grpc.CallOption) (*GetTokenPriceUSDResponse, error) GetFeeQuoterDestChainConfig(ctx context.Context, in *GetFeeQuoterDestChainConfigRequest, opts ...grpc.CallOption) (*GetFeeQuoterDestChainConfigResponse, error) + // USDCMessageReader methods + MessagesByTokenID(ctx context.Context, in *MessagesByTokenIDRequest, opts ...grpc.CallOption) (*MessagesByTokenIDResponse, error) + // PriceReader methods + GetFeedPricesUSD(ctx context.Context, in *GetFeedPricesUSDRequest, opts ...grpc.CallOption) (*GetFeedPricesUSDResponse, error) + GetFeeQuoterTokenUpdates(ctx context.Context, in *GetFeeQuoterTokenUpdatesRequest, opts ...grpc.CallOption) (*GetFeeQuoterTokenUpdatesResponse, error) } type chainAccessorClient struct { @@ -221,6 +229,36 @@ func (c *chainAccessorClient) GetFeeQuoterDestChainConfig(ctx context.Context, i return out, nil } +func (c *chainAccessorClient) MessagesByTokenID(ctx context.Context, in *MessagesByTokenIDRequest, opts ...grpc.CallOption) (*MessagesByTokenIDResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(MessagesByTokenIDResponse) + err := c.cc.Invoke(ctx, ChainAccessor_MessagesByTokenID_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chainAccessorClient) GetFeedPricesUSD(ctx context.Context, in *GetFeedPricesUSDRequest, opts ...grpc.CallOption) (*GetFeedPricesUSDResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetFeedPricesUSDResponse) + err := c.cc.Invoke(ctx, ChainAccessor_GetFeedPricesUSD_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chainAccessorClient) GetFeeQuoterTokenUpdates(ctx context.Context, in *GetFeeQuoterTokenUpdatesRequest, opts ...grpc.CallOption) (*GetFeeQuoterTokenUpdatesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetFeeQuoterTokenUpdatesResponse) + err := c.cc.Invoke(ctx, ChainAccessor_GetFeeQuoterTokenUpdates_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // ChainAccessorServer is the server API for ChainAccessor service. // All implementations must embed UnimplementedChainAccessorServer // for forward compatibility. @@ -245,6 +283,11 @@ type ChainAccessorServer interface { GetExpectedNextSequenceNumber(context.Context, *GetExpectedNextSequenceNumberRequest) (*GetExpectedNextSequenceNumberResponse, error) GetTokenPriceUSD(context.Context, *GetTokenPriceUSDRequest) (*GetTokenPriceUSDResponse, error) GetFeeQuoterDestChainConfig(context.Context, *GetFeeQuoterDestChainConfigRequest) (*GetFeeQuoterDestChainConfigResponse, error) + // USDCMessageReader methods + MessagesByTokenID(context.Context, *MessagesByTokenIDRequest) (*MessagesByTokenIDResponse, error) + // PriceReader methods + GetFeedPricesUSD(context.Context, *GetFeedPricesUSDRequest) (*GetFeedPricesUSDResponse, error) + GetFeeQuoterTokenUpdates(context.Context, *GetFeeQuoterTokenUpdatesRequest) (*GetFeeQuoterTokenUpdatesResponse, error) mustEmbedUnimplementedChainAccessorServer() } @@ -300,6 +343,15 @@ func (UnimplementedChainAccessorServer) GetTokenPriceUSD(context.Context, *GetTo func (UnimplementedChainAccessorServer) GetFeeQuoterDestChainConfig(context.Context, *GetFeeQuoterDestChainConfigRequest) (*GetFeeQuoterDestChainConfigResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetFeeQuoterDestChainConfig not implemented") } +func (UnimplementedChainAccessorServer) MessagesByTokenID(context.Context, *MessagesByTokenIDRequest) (*MessagesByTokenIDResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MessagesByTokenID not implemented") +} +func (UnimplementedChainAccessorServer) GetFeedPricesUSD(context.Context, *GetFeedPricesUSDRequest) (*GetFeedPricesUSDResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFeedPricesUSD not implemented") +} +func (UnimplementedChainAccessorServer) GetFeeQuoterTokenUpdates(context.Context, *GetFeeQuoterTokenUpdatesRequest) (*GetFeeQuoterTokenUpdatesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFeeQuoterTokenUpdates not implemented") +} func (UnimplementedChainAccessorServer) mustEmbedUnimplementedChainAccessorServer() {} func (UnimplementedChainAccessorServer) testEmbeddedByValue() {} @@ -591,6 +643,60 @@ func _ChainAccessor_GetFeeQuoterDestChainConfig_Handler(srv interface{}, ctx con return interceptor(ctx, in, info, handler) } +func _ChainAccessor_MessagesByTokenID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MessagesByTokenIDRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChainAccessorServer).MessagesByTokenID(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ChainAccessor_MessagesByTokenID_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChainAccessorServer).MessagesByTokenID(ctx, req.(*MessagesByTokenIDRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ChainAccessor_GetFeedPricesUSD_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFeedPricesUSDRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChainAccessorServer).GetFeedPricesUSD(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ChainAccessor_GetFeedPricesUSD_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChainAccessorServer).GetFeedPricesUSD(ctx, req.(*GetFeedPricesUSDRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ChainAccessor_GetFeeQuoterTokenUpdates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFeeQuoterTokenUpdatesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChainAccessorServer).GetFeeQuoterTokenUpdates(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ChainAccessor_GetFeeQuoterTokenUpdates_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChainAccessorServer).GetFeeQuoterTokenUpdates(ctx, req.(*GetFeeQuoterTokenUpdatesRequest)) + } + return interceptor(ctx, in, info, handler) +} + // ChainAccessor_ServiceDesc is the grpc.ServiceDesc for ChainAccessor service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -658,6 +764,18 @@ var ChainAccessor_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetFeeQuoterDestChainConfig", Handler: _ChainAccessor_GetFeeQuoterDestChainConfig_Handler, }, + { + MethodName: "MessagesByTokenID", + Handler: _ChainAccessor_MessagesByTokenID_Handler, + }, + { + MethodName: "GetFeedPricesUSD", + Handler: _ChainAccessor_GetFeedPricesUSD_Handler, + }, + { + MethodName: "GetFeeQuoterTokenUpdates", + Handler: _ChainAccessor_GetFeeQuoterTokenUpdates_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "chainaccessor.proto", diff --git a/pkg/loop/internal/pb/relayer.pb.go b/pkg/loop/internal/pb/relayer.pb.go index afbfc3f6d..c3a3d8937 100644 --- a/pkg/loop/internal/pb/relayer.pb.go +++ b/pkg/loop/internal/pb/relayer.pb.go @@ -280,6 +280,7 @@ type CCIPProviderArgs struct { ChainWriterConfig []byte `protobuf:"bytes,3,opt,name=chainWriterConfig,proto3" json:"chainWriterConfig,omitempty"` OffRampAddress string `protobuf:"bytes,4,opt,name=OffRampAddress,proto3" json:"OffRampAddress,omitempty"` PluginType uint32 `protobuf:"varint,5,opt,name=pluginType,proto3" json:"pluginType,omitempty"` + SyncedAddresses map[string][]byte `protobuf:"bytes,6,rep,name=synced_addresses,json=syncedAddresses,proto3" json:"synced_addresses,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // map[contract_name]contract_address unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -349,6 +350,13 @@ func (x *CCIPProviderArgs) GetPluginType() uint32 { return 0 } +func (x *CCIPProviderArgs) GetSyncedAddresses() map[string][]byte { + if x != nil { + return x.SyncedAddresses + } + return nil +} + // NewContractWriterRequest has request parameters for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewContractWriter]. type NewContractWriterRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -2715,7 +2723,7 @@ const file_loop_internal_pb_relayer_proto_rawDesc = "" + "\n" + "PluginArgs\x12$\n" + "\rtransmitterID\x18\x01 \x01(\tR\rtransmitterID\x12\"\n" + - "\fpluginConfig\x18\x02 \x01(\fR\fpluginConfig\"\xe2\x01\n" + + "\fpluginConfig\x18\x02 \x01(\fR\fpluginConfig\"\xfe\x02\n" + "\x10CCIPProviderArgs\x12$\n" + "\rexternalJobID\x18\x01 \x01(\fR\rexternalJobID\x122\n" + "\x14contractReaderConfig\x18\x02 \x01(\fR\x14contractReaderConfig\x12,\n" + @@ -2723,7 +2731,11 @@ const file_loop_internal_pb_relayer_proto_rawDesc = "" + "\x0eOffRampAddress\x18\x04 \x01(\tR\x0eOffRampAddress\x12\x1e\n" + "\n" + "pluginType\x18\x05 \x01(\rR\n" + - "pluginType\"N\n" + + "pluginType\x12V\n" + + "\x10synced_addresses\x18\x06 \x03(\v2+.loop.CCIPProviderArgs.SyncedAddressesEntryR\x0fsyncedAddresses\x1aB\n" + + "\x14SyncedAddressesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\fR\x05value:\x028\x01\"N\n" + "\x18NewContractWriterRequest\x122\n" + "\x14contractWriterConfig\x18\x01 \x01(\fR\x14contractWriterConfig\"D\n" + "\x16NewContractWriterReply\x12*\n" + @@ -2899,7 +2911,7 @@ func file_loop_internal_pb_relayer_proto_rawDescGZIP() []byte { return file_loop_internal_pb_relayer_proto_rawDescData } -var file_loop_internal_pb_relayer_proto_msgTypes = make([]protoimpl.MessageInfo, 54) +var file_loop_internal_pb_relayer_proto_msgTypes = make([]protoimpl.MessageInfo, 55) var file_loop_internal_pb_relayer_proto_goTypes = []any{ (*NewRelayerRequest)(nil), // 0: loop.NewRelayerRequest (*NewRelayerReply)(nil), // 1: loop.NewRelayerReply @@ -2954,84 +2966,86 @@ var file_loop_internal_pb_relayer_proto_goTypes = []any{ (*BigInt)(nil), // 50: loop.BigInt (*StarknetSignature)(nil), // 51: loop.StarknetSignature (*StarknetMessageHash)(nil), // 52: loop.StarknetMessageHash - nil, // 53: loop.HealthReportReply.HealthReportEntry - (*Head)(nil), // 54: loop.Head - (*structpb.Struct)(nil), // 55: google.protobuf.Struct - (*emptypb.Empty)(nil), // 56: google.protobuf.Empty + nil, // 53: loop.CCIPProviderArgs.SyncedAddressesEntry + nil, // 54: loop.HealthReportReply.HealthReportEntry + (*Head)(nil), // 55: loop.Head + (*structpb.Struct)(nil), // 56: google.protobuf.Struct + (*emptypb.Empty)(nil), // 57: google.protobuf.Empty } var file_loop_internal_pb_relayer_proto_depIdxs = []int32{ - 2, // 0: loop.NewPluginProviderRequest.relayArgs:type_name -> loop.RelayArgs - 3, // 1: loop.NewPluginProviderRequest.pluginArgs:type_name -> loop.PluginArgs - 2, // 2: loop.NewConfigProviderRequest.relayArgs:type_name -> loop.RelayArgs - 4, // 3: loop.NewCCIPProviderRequest.ccipProviderArgs:type_name -> loop.CCIPProviderArgs - 54, // 4: loop.LatestHeadReply.head:type_name -> loop.Head - 21, // 5: loop.GetChainStatusReply.chain:type_name -> loop.ChainStatus - 22, // 6: loop.GetChainInfoReply.chain_info:type_name -> loop.ChainInfo - 25, // 7: loop.ListNodeStatusesReply.nodes:type_name -> loop.NodeStatus - 55, // 8: loop.ReplayRequest.args:type_name -> google.protobuf.Struct - 50, // 9: loop.TransactionRequest.amount:type_name -> loop.BigInt - 28, // 10: loop.ConfigDigestRequest.contractConfig:type_name -> loop.ContractConfig - 28, // 11: loop.LatestConfigReply.contractConfig:type_name -> loop.ContractConfig - 39, // 12: loop.ReportContext.reportTimestamp:type_name -> loop.ReportTimestamp - 40, // 13: loop.TransmitRequest.reportContext:type_name -> loop.ReportContext - 41, // 14: loop.TransmitRequest.attributedOnchainSignatures:type_name -> loop.AttributedOnchainSignature - 53, // 15: loop.HealthReportReply.healthReport:type_name -> loop.HealthReportReply.HealthReportEntry - 50, // 16: loop.StarknetSignature.x:type_name -> loop.BigInt - 50, // 17: loop.StarknetSignature.y:type_name -> loop.BigInt - 50, // 18: loop.StarknetMessageHash.hash:type_name -> loop.BigInt - 0, // 19: loop.PluginRelayer.NewRelayer:input_type -> loop.NewRelayerRequest - 5, // 20: loop.Relayer.NewContractWriter:input_type -> loop.NewContractWriterRequest - 7, // 21: loop.Relayer.NewContractReader:input_type -> loop.NewContractReaderRequest - 11, // 22: loop.Relayer.NewConfigProvider:input_type -> loop.NewConfigProviderRequest - 9, // 23: loop.Relayer.NewPluginProvider:input_type -> loop.NewPluginProviderRequest - 13, // 24: loop.Relayer.NewCCIPProvider:input_type -> loop.NewCCIPProviderRequest - 15, // 25: loop.Relayer.LatestHead:input_type -> loop.LatestHeadRequest - 17, // 26: loop.Relayer.GetChainStatus:input_type -> loop.GetChainStatusRequest - 19, // 27: loop.Relayer.GetChainInfo:input_type -> loop.GetChainInfoRequest - 23, // 28: loop.Relayer.ListNodeStatuses:input_type -> loop.ListNodeStatusesRequest - 27, // 29: loop.Relayer.Transact:input_type -> loop.TransactionRequest - 26, // 30: loop.Relayer.Replay:input_type -> loop.ReplayRequest - 29, // 31: loop.OffchainConfigDigester.ConfigDigest:input_type -> loop.ConfigDigestRequest - 31, // 32: loop.OffchainConfigDigester.ConfigDigestPrefix:input_type -> loop.ConfigDigestPrefixRequest - 33, // 33: loop.ContractConfigTracker.LatestConfigDetails:input_type -> loop.LatestConfigDetailsRequest - 35, // 34: loop.ContractConfigTracker.LatestConfig:input_type -> loop.LatestConfigRequest - 37, // 35: loop.ContractConfigTracker.LatestBlockHeight:input_type -> loop.LatestBlockHeightRequest - 42, // 36: loop.ContractTransmitter.Transmit:input_type -> loop.TransmitRequest - 44, // 37: loop.ContractTransmitter.LatestConfigDigestAndEpoch:input_type -> loop.LatestConfigDigestAndEpochRequest - 46, // 38: loop.ContractTransmitter.FromAccount:input_type -> loop.FromAccountRequest - 56, // 39: loop.Service.Name:input_type -> google.protobuf.Empty - 56, // 40: loop.Service.Close:input_type -> google.protobuf.Empty - 56, // 41: loop.Service.Ready:input_type -> google.protobuf.Empty - 56, // 42: loop.Service.HealthReport:input_type -> google.protobuf.Empty - 1, // 43: loop.PluginRelayer.NewRelayer:output_type -> loop.NewRelayerReply - 6, // 44: loop.Relayer.NewContractWriter:output_type -> loop.NewContractWriterReply - 8, // 45: loop.Relayer.NewContractReader:output_type -> loop.NewContractReaderReply - 12, // 46: loop.Relayer.NewConfigProvider:output_type -> loop.NewConfigProviderReply - 10, // 47: loop.Relayer.NewPluginProvider:output_type -> loop.NewPluginProviderReply - 14, // 48: loop.Relayer.NewCCIPProvider:output_type -> loop.NewCCIPProviderReply - 16, // 49: loop.Relayer.LatestHead:output_type -> loop.LatestHeadReply - 18, // 50: loop.Relayer.GetChainStatus:output_type -> loop.GetChainStatusReply - 20, // 51: loop.Relayer.GetChainInfo:output_type -> loop.GetChainInfoReply - 24, // 52: loop.Relayer.ListNodeStatuses:output_type -> loop.ListNodeStatusesReply - 56, // 53: loop.Relayer.Transact:output_type -> google.protobuf.Empty - 56, // 54: loop.Relayer.Replay:output_type -> google.protobuf.Empty - 30, // 55: loop.OffchainConfigDigester.ConfigDigest:output_type -> loop.ConfigDigestReply - 32, // 56: loop.OffchainConfigDigester.ConfigDigestPrefix:output_type -> loop.ConfigDigestPrefixReply - 34, // 57: loop.ContractConfigTracker.LatestConfigDetails:output_type -> loop.LatestConfigDetailsReply - 36, // 58: loop.ContractConfigTracker.LatestConfig:output_type -> loop.LatestConfigReply - 38, // 59: loop.ContractConfigTracker.LatestBlockHeight:output_type -> loop.LatestBlockHeightReply - 43, // 60: loop.ContractTransmitter.Transmit:output_type -> loop.TransmitReply - 45, // 61: loop.ContractTransmitter.LatestConfigDigestAndEpoch:output_type -> loop.LatestConfigDigestAndEpochReply - 47, // 62: loop.ContractTransmitter.FromAccount:output_type -> loop.FromAccountReply - 48, // 63: loop.Service.Name:output_type -> loop.NameReply - 56, // 64: loop.Service.Close:output_type -> google.protobuf.Empty - 56, // 65: loop.Service.Ready:output_type -> google.protobuf.Empty - 49, // 66: loop.Service.HealthReport:output_type -> loop.HealthReportReply - 43, // [43:67] is the sub-list for method output_type - 19, // [19:43] is the sub-list for method input_type - 19, // [19:19] is the sub-list for extension type_name - 19, // [19:19] is the sub-list for extension extendee - 0, // [0:19] is the sub-list for field type_name + 53, // 0: loop.CCIPProviderArgs.synced_addresses:type_name -> loop.CCIPProviderArgs.SyncedAddressesEntry + 2, // 1: loop.NewPluginProviderRequest.relayArgs:type_name -> loop.RelayArgs + 3, // 2: loop.NewPluginProviderRequest.pluginArgs:type_name -> loop.PluginArgs + 2, // 3: loop.NewConfigProviderRequest.relayArgs:type_name -> loop.RelayArgs + 4, // 4: loop.NewCCIPProviderRequest.ccipProviderArgs:type_name -> loop.CCIPProviderArgs + 55, // 5: loop.LatestHeadReply.head:type_name -> loop.Head + 21, // 6: loop.GetChainStatusReply.chain:type_name -> loop.ChainStatus + 22, // 7: loop.GetChainInfoReply.chain_info:type_name -> loop.ChainInfo + 25, // 8: loop.ListNodeStatusesReply.nodes:type_name -> loop.NodeStatus + 56, // 9: loop.ReplayRequest.args:type_name -> google.protobuf.Struct + 50, // 10: loop.TransactionRequest.amount:type_name -> loop.BigInt + 28, // 11: loop.ConfigDigestRequest.contractConfig:type_name -> loop.ContractConfig + 28, // 12: loop.LatestConfigReply.contractConfig:type_name -> loop.ContractConfig + 39, // 13: loop.ReportContext.reportTimestamp:type_name -> loop.ReportTimestamp + 40, // 14: loop.TransmitRequest.reportContext:type_name -> loop.ReportContext + 41, // 15: loop.TransmitRequest.attributedOnchainSignatures:type_name -> loop.AttributedOnchainSignature + 54, // 16: loop.HealthReportReply.healthReport:type_name -> loop.HealthReportReply.HealthReportEntry + 50, // 17: loop.StarknetSignature.x:type_name -> loop.BigInt + 50, // 18: loop.StarknetSignature.y:type_name -> loop.BigInt + 50, // 19: loop.StarknetMessageHash.hash:type_name -> loop.BigInt + 0, // 20: loop.PluginRelayer.NewRelayer:input_type -> loop.NewRelayerRequest + 5, // 21: loop.Relayer.NewContractWriter:input_type -> loop.NewContractWriterRequest + 7, // 22: loop.Relayer.NewContractReader:input_type -> loop.NewContractReaderRequest + 11, // 23: loop.Relayer.NewConfigProvider:input_type -> loop.NewConfigProviderRequest + 9, // 24: loop.Relayer.NewPluginProvider:input_type -> loop.NewPluginProviderRequest + 13, // 25: loop.Relayer.NewCCIPProvider:input_type -> loop.NewCCIPProviderRequest + 15, // 26: loop.Relayer.LatestHead:input_type -> loop.LatestHeadRequest + 17, // 27: loop.Relayer.GetChainStatus:input_type -> loop.GetChainStatusRequest + 19, // 28: loop.Relayer.GetChainInfo:input_type -> loop.GetChainInfoRequest + 23, // 29: loop.Relayer.ListNodeStatuses:input_type -> loop.ListNodeStatusesRequest + 27, // 30: loop.Relayer.Transact:input_type -> loop.TransactionRequest + 26, // 31: loop.Relayer.Replay:input_type -> loop.ReplayRequest + 29, // 32: loop.OffchainConfigDigester.ConfigDigest:input_type -> loop.ConfigDigestRequest + 31, // 33: loop.OffchainConfigDigester.ConfigDigestPrefix:input_type -> loop.ConfigDigestPrefixRequest + 33, // 34: loop.ContractConfigTracker.LatestConfigDetails:input_type -> loop.LatestConfigDetailsRequest + 35, // 35: loop.ContractConfigTracker.LatestConfig:input_type -> loop.LatestConfigRequest + 37, // 36: loop.ContractConfigTracker.LatestBlockHeight:input_type -> loop.LatestBlockHeightRequest + 42, // 37: loop.ContractTransmitter.Transmit:input_type -> loop.TransmitRequest + 44, // 38: loop.ContractTransmitter.LatestConfigDigestAndEpoch:input_type -> loop.LatestConfigDigestAndEpochRequest + 46, // 39: loop.ContractTransmitter.FromAccount:input_type -> loop.FromAccountRequest + 57, // 40: loop.Service.Name:input_type -> google.protobuf.Empty + 57, // 41: loop.Service.Close:input_type -> google.protobuf.Empty + 57, // 42: loop.Service.Ready:input_type -> google.protobuf.Empty + 57, // 43: loop.Service.HealthReport:input_type -> google.protobuf.Empty + 1, // 44: loop.PluginRelayer.NewRelayer:output_type -> loop.NewRelayerReply + 6, // 45: loop.Relayer.NewContractWriter:output_type -> loop.NewContractWriterReply + 8, // 46: loop.Relayer.NewContractReader:output_type -> loop.NewContractReaderReply + 12, // 47: loop.Relayer.NewConfigProvider:output_type -> loop.NewConfigProviderReply + 10, // 48: loop.Relayer.NewPluginProvider:output_type -> loop.NewPluginProviderReply + 14, // 49: loop.Relayer.NewCCIPProvider:output_type -> loop.NewCCIPProviderReply + 16, // 50: loop.Relayer.LatestHead:output_type -> loop.LatestHeadReply + 18, // 51: loop.Relayer.GetChainStatus:output_type -> loop.GetChainStatusReply + 20, // 52: loop.Relayer.GetChainInfo:output_type -> loop.GetChainInfoReply + 24, // 53: loop.Relayer.ListNodeStatuses:output_type -> loop.ListNodeStatusesReply + 57, // 54: loop.Relayer.Transact:output_type -> google.protobuf.Empty + 57, // 55: loop.Relayer.Replay:output_type -> google.protobuf.Empty + 30, // 56: loop.OffchainConfigDigester.ConfigDigest:output_type -> loop.ConfigDigestReply + 32, // 57: loop.OffchainConfigDigester.ConfigDigestPrefix:output_type -> loop.ConfigDigestPrefixReply + 34, // 58: loop.ContractConfigTracker.LatestConfigDetails:output_type -> loop.LatestConfigDetailsReply + 36, // 59: loop.ContractConfigTracker.LatestConfig:output_type -> loop.LatestConfigReply + 38, // 60: loop.ContractConfigTracker.LatestBlockHeight:output_type -> loop.LatestBlockHeightReply + 43, // 61: loop.ContractTransmitter.Transmit:output_type -> loop.TransmitReply + 45, // 62: loop.ContractTransmitter.LatestConfigDigestAndEpoch:output_type -> loop.LatestConfigDigestAndEpochReply + 47, // 63: loop.ContractTransmitter.FromAccount:output_type -> loop.FromAccountReply + 48, // 64: loop.Service.Name:output_type -> loop.NameReply + 57, // 65: loop.Service.Close:output_type -> google.protobuf.Empty + 57, // 66: loop.Service.Ready:output_type -> google.protobuf.Empty + 49, // 67: loop.Service.HealthReport:output_type -> loop.HealthReportReply + 44, // [44:68] is the sub-list for method output_type + 20, // [20:44] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_loop_internal_pb_relayer_proto_init() } @@ -3046,7 +3060,7 @@ func file_loop_internal_pb_relayer_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_loop_internal_pb_relayer_proto_rawDesc), len(file_loop_internal_pb_relayer_proto_rawDesc)), NumEnums: 0, - NumMessages: 54, + NumMessages: 55, NumExtensions: 0, NumServices: 6, }, diff --git a/pkg/loop/internal/pb/relayer.proto b/pkg/loop/internal/pb/relayer.proto index 56c959f8d..5ee90a6f2 100644 --- a/pkg/loop/internal/pb/relayer.proto +++ b/pkg/loop/internal/pb/relayer.proto @@ -62,6 +62,7 @@ message CCIPProviderArgs { bytes chainWriterConfig = 3; string OffRampAddress = 4; uint32 pluginType = 5; + map synced_addresses = 6; // map[contract_name]contract_address } // NewContractWriterRequest has request parameters for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewContractWriter]. diff --git a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/ccip_provider.go b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/ccip_provider.go index a705678aa..a8315bdc9 100644 --- a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/ccip_provider.go +++ b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/ccip_provider.go @@ -22,7 +22,7 @@ var ( type CCIPProviderClient struct { *goplugin.ServiceClient - chainAccessor ccipocr3.ChainAccessor + chainAccessor *ChainAccessorClient contractTransmitter ocr3types.ContractTransmitter[[]byte] chainSpecificAddressCodec ccipocr3.ChainSpecificAddressCodec commitPluginCodec ccipocr3.CommitPluginCodec @@ -31,7 +31,7 @@ type CCIPProviderClient struct { sourceChainExtraDataCodec ccipocr3.SourceChainExtraDataCodec } -func NewCCIPProviderClient(b *net.BrokerExt, cc grpc.ClientConnInterface) types.CCIPProvider { +func NewCCIPProviderClient(b *net.BrokerExt, cc grpc.ClientConnInterface) *CCIPProviderClient { c := &CCIPProviderClient{ ServiceClient: goplugin.NewServiceClient(b.WithName("CCIPProviderClient"), cc), } @@ -52,6 +52,15 @@ func NewCCIPProviderClient(b *net.BrokerExt, cc grpc.ClientConnInterface) types. return c } +func (p *CCIPProviderClient) GetSyncRequests() map[string][]byte { + reqs := p.chainAccessor.GetSyncRequests() + convertedSyncs := make(map[string][]byte, len(reqs)) + for contractName, unknownAddr := range reqs { + convertedSyncs[contractName] = unknownAddr[:] + } + return convertedSyncs +} + func (p *CCIPProviderClient) ChainAccessor() ccipocr3.ChainAccessor { return p.chainAccessor } diff --git a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/chainaccessor.go b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/chainaccessor.go index ea402484c..bccd492a9 100644 --- a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/chainaccessor.go +++ b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/chainaccessor.go @@ -2,6 +2,8 @@ package ccipocr3 import ( "context" + "maps" + "sync" "time" "google.golang.org/grpc" @@ -14,22 +16,33 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" ) -var _ ccipocr3.ChainAccessor = (*chainAccessorClient)(nil) +var _ ccipocr3.ChainAccessor = (*ChainAccessorClient)(nil) -type chainAccessorClient struct { +type ChainAccessorClient struct { *net.BrokerExt grpc ccipocr3pb.ChainAccessorClient + + // NOTE: when the feed chain accessor is LOOPified, this will need to support multi-bind addresses (unless we have + // built a more generalized state management solution by then). + mu sync.RWMutex + syncs map[string]ccipocr3.UnknownAddress // contractName -> contractAddress } -func NewChainAccessorClient(broker *net.BrokerExt, cc grpc.ClientConnInterface) ccipocr3.ChainAccessor { - return &chainAccessorClient{ +func NewChainAccessorClient(broker *net.BrokerExt, cc grpc.ClientConnInterface) *ChainAccessorClient { + return &ChainAccessorClient{ BrokerExt: broker, grpc: ccipocr3pb.NewChainAccessorClient(cc), } } +func (c *ChainAccessorClient) GetSyncRequests() map[string]ccipocr3.UnknownAddress { + c.mu.RLock() + defer c.mu.RUnlock() + return maps.Clone(c.syncs) +} + // AllAccessors methods -func (c *chainAccessorClient) GetContractAddress(contractName string) ([]byte, error) { +func (c *ChainAccessorClient) GetContractAddress(contractName string) ([]byte, error) { resp, err := c.grpc.GetContractAddress(context.Background(), &ccipocr3pb.GetContractAddressRequest{ ContractName: contractName, }) @@ -39,7 +52,7 @@ func (c *chainAccessorClient) GetContractAddress(contractName string) ([]byte, e return resp.Address, nil } -func (c *chainAccessorClient) GetAllConfigsLegacy( +func (c *ChainAccessorClient) GetAllConfigsLegacy( ctx context.Context, destChainSelector ccipocr3.ChainSelector, sourceChainSelectors []ccipocr3.ChainSelector, @@ -66,7 +79,7 @@ func (c *chainAccessorClient) GetAllConfigsLegacy( return pbToChainConfigSnapshotDetailed(resp.Snapshot), sourceConfigs, nil } -func (c *chainAccessorClient) GetChainFeeComponents(ctx context.Context) (ccipocr3.ChainFeeComponents, error) { +func (c *ChainAccessorClient) GetChainFeeComponents(ctx context.Context) (ccipocr3.ChainFeeComponents, error) { resp, err := c.grpc.GetChainFeeComponents(ctx, &emptypb.Empty{}) if err != nil { return ccipocr3.ChainFeeComponents{}, err @@ -77,16 +90,21 @@ func (c *chainAccessorClient) GetChainFeeComponents(ctx context.Context) (ccipoc }, nil } -func (c *chainAccessorClient) Sync(ctx context.Context, contractName string, contractAddress ccipocr3.UnknownAddress) error { - _, err := c.grpc.Sync(ctx, &ccipocr3pb.SyncRequest{ - ContractName: contractName, - ContractAddress: contractAddress, - }) +func (c *ChainAccessorClient) Sync(ctx context.Context, contractName string, contractAddress ccipocr3.UnknownAddress) error { + req := &ccipocr3pb.SyncRequest{ContractName: contractName, ContractAddress: contractAddress} + _, err := c.grpc.Sync(ctx, req) + + // If grpc call succeeded, store the most recent address for this given contract address. + if err != nil { + c.mu.Lock() + c.syncs[contractName] = contractAddress + c.mu.Unlock() + } return err } // DestinationAccessor methods -func (c *chainAccessorClient) CommitReportsGTETimestamp( +func (c *ChainAccessorClient) CommitReportsGTETimestamp( ctx context.Context, ts time.Time, confidence primitives.ConfidenceLevel, @@ -112,7 +130,7 @@ func (c *chainAccessorClient) CommitReportsGTETimestamp( return reports, nil } -func (c *chainAccessorClient) ExecutedMessages( +func (c *ChainAccessorClient) ExecutedMessages( ctx context.Context, ranges map[ccipocr3.ChainSelector][]ccipocr3.SeqNumRange, confidence primitives.ConfidenceLevel, @@ -149,7 +167,7 @@ func (c *chainAccessorClient) ExecutedMessages( return result, nil } -func (c *chainAccessorClient) NextSeqNum(ctx context.Context, sources []ccipocr3.ChainSelector) (map[ccipocr3.ChainSelector]ccipocr3.SeqNum, error) { +func (c *ChainAccessorClient) NextSeqNum(ctx context.Context, sources []ccipocr3.ChainSelector) (map[ccipocr3.ChainSelector]ccipocr3.SeqNum, error) { var chainSelectors []uint64 for _, source := range sources { chainSelectors = append(chainSelectors, uint64(source)) @@ -169,7 +187,7 @@ func (c *chainAccessorClient) NextSeqNum(ctx context.Context, sources []ccipocr3 return result, nil } -func (c *chainAccessorClient) Nonces(ctx context.Context, addresses map[ccipocr3.ChainSelector][]ccipocr3.UnknownEncodedAddress) (map[ccipocr3.ChainSelector]map[string]uint64, error) { +func (c *ChainAccessorClient) Nonces(ctx context.Context, addresses map[ccipocr3.ChainSelector][]ccipocr3.UnknownEncodedAddress) (map[ccipocr3.ChainSelector]map[string]uint64, error) { req := &ccipocr3pb.NoncesRequest{ Addresses: make(map[uint64]*ccipocr3pb.UnknownEncodedAddressList), } @@ -194,7 +212,7 @@ func (c *chainAccessorClient) Nonces(ctx context.Context, addresses map[ccipocr3 return result, nil } -func (c *chainAccessorClient) GetChainFeePriceUpdate(ctx context.Context, selectors []ccipocr3.ChainSelector) map[ccipocr3.ChainSelector]ccipocr3.TimestampedBig { +func (c *ChainAccessorClient) GetChainFeePriceUpdate(ctx context.Context, selectors []ccipocr3.ChainSelector) (map[ccipocr3.ChainSelector]ccipocr3.TimestampedUnixBig, error) { var chainSelectors []uint64 for _, sel := range selectors { chainSelectors = append(chainSelectors, uint64(sel)) @@ -204,31 +222,29 @@ func (c *chainAccessorClient) GetChainFeePriceUpdate(ctx context.Context, select ChainSelectors: chainSelectors, }) if err != nil { - // This method returns a map, not error, so we need to handle errors differently - // Return empty map for now - this matches the interface signature - return make(map[ccipocr3.ChainSelector]ccipocr3.TimestampedBig) + return nil, err } - result := make(map[ccipocr3.ChainSelector]ccipocr3.TimestampedBig) - for chainSel, timestampedBig := range resp.FeePriceUpdates { - result[ccipocr3.ChainSelector(chainSel)] = ccipocr3.TimestampedBig{ - Timestamp: timestampedBig.Timestamp.AsTime(), - Value: pbToBigInt(timestampedBig.Value), + result := make(map[ccipocr3.ChainSelector]ccipocr3.TimestampedUnixBig) + for chainSel, timestampedUnixBig := range resp.FeePriceUpdates { + result[ccipocr3.ChainSelector(chainSel)] = ccipocr3.TimestampedUnixBig{ + Value: pbToBigInt(timestampedUnixBig.Value).Int, + Timestamp: timestampedUnixBig.Timestamp, } } - return result + return result, nil } -func (c *chainAccessorClient) GetLatestPriceSeqNr(ctx context.Context) (uint64, error) { +func (c *ChainAccessorClient) GetLatestPriceSeqNr(ctx context.Context) (ccipocr3.SeqNum, error) { resp, err := c.grpc.GetLatestPriceSeqNr(ctx, &emptypb.Empty{}) if err != nil { return 0, err } - return resp.SeqNr, nil + return ccipocr3.SeqNum(resp.SeqNr), nil } // SourceAccessor methods -func (c *chainAccessorClient) MsgsBetweenSeqNums(ctx context.Context, dest ccipocr3.ChainSelector, seqNumRange ccipocr3.SeqNumRange) ([]ccipocr3.Message, error) { +func (c *ChainAccessorClient) MsgsBetweenSeqNums(ctx context.Context, dest ccipocr3.ChainSelector, seqNumRange ccipocr3.SeqNumRange) ([]ccipocr3.Message, error) { resp, err := c.grpc.MsgsBetweenSeqNums(ctx, &ccipocr3pb.MsgsBetweenSeqNumsRequest{ DestChainSelector: uint64(dest), SeqNumRange: &ccipocr3pb.SeqNumRange{ @@ -247,7 +263,7 @@ func (c *chainAccessorClient) MsgsBetweenSeqNums(ctx context.Context, dest ccipo return messages, nil } -func (c *chainAccessorClient) LatestMessageTo(ctx context.Context, dest ccipocr3.ChainSelector) (ccipocr3.SeqNum, error) { +func (c *ChainAccessorClient) LatestMessageTo(ctx context.Context, dest ccipocr3.ChainSelector) (ccipocr3.SeqNum, error) { resp, err := c.grpc.LatestMessageTo(ctx, &ccipocr3pb.LatestMessageToRequest{ DestChainSelector: uint64(dest), }) @@ -257,7 +273,7 @@ func (c *chainAccessorClient) LatestMessageTo(ctx context.Context, dest ccipocr3 return ccipocr3.SeqNum(resp.SeqNum), nil } -func (c *chainAccessorClient) GetExpectedNextSequenceNumber(ctx context.Context, dest ccipocr3.ChainSelector) (ccipocr3.SeqNum, error) { +func (c *ChainAccessorClient) GetExpectedNextSequenceNumber(ctx context.Context, dest ccipocr3.ChainSelector) (ccipocr3.SeqNum, error) { resp, err := c.grpc.GetExpectedNextSequenceNumber(ctx, &ccipocr3pb.GetExpectedNextSequenceNumberRequest{ DestChainSelector: uint64(dest), }) @@ -267,7 +283,7 @@ func (c *chainAccessorClient) GetExpectedNextSequenceNumber(ctx context.Context, return ccipocr3.SeqNum(resp.SeqNum), nil } -func (c *chainAccessorClient) GetTokenPriceUSD(ctx context.Context, address ccipocr3.UnknownAddress) (ccipocr3.TimestampedUnixBig, error) { +func (c *ChainAccessorClient) GetTokenPriceUSD(ctx context.Context, address ccipocr3.UnknownAddress) (ccipocr3.TimestampedUnixBig, error) { resp, err := c.grpc.GetTokenPriceUSD(ctx, &ccipocr3pb.GetTokenPriceUSDRequest{ Address: address, }) @@ -280,7 +296,7 @@ func (c *chainAccessorClient) GetTokenPriceUSD(ctx context.Context, address ccip }, nil } -func (c *chainAccessorClient) GetFeeQuoterDestChainConfig(ctx context.Context, dest ccipocr3.ChainSelector) (ccipocr3.FeeQuoterDestChainConfig, error) { +func (c *ChainAccessorClient) GetFeeQuoterDestChainConfig(ctx context.Context, dest ccipocr3.ChainSelector) (ccipocr3.FeeQuoterDestChainConfig, error) { resp, err := c.grpc.GetFeeQuoterDestChainConfig(ctx, &ccipocr3pb.GetFeeQuoterDestChainConfigRequest{ DestChainSelector: uint64(dest), }) @@ -290,6 +306,52 @@ func (c *chainAccessorClient) GetFeeQuoterDestChainConfig(ctx context.Context, d return pbToFeeQuoterDestChainConfigDetailed(resp.Config), nil } +// USDCMessageReader methods +func (c *ChainAccessorClient) MessagesByTokenID(ctx context.Context, source, dest ccipocr3.ChainSelector, tokens map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount) (map[ccipocr3.MessageTokenID]ccipocr3.Bytes, error) { + resp, err := c.grpc.MessagesByTokenID(ctx, &ccipocr3pb.MessagesByTokenIDRequest{ + SourceChainSelector: uint64(source), + DestChainSelector: uint64(dest), + Tokens: messageTokenIDMapToPb(tokens), + }) + if err != nil { + return nil, err + } + return pbToMessagesByTokenID(resp.Messages) +} + +// PriceReader methods +func (c *ChainAccessorClient) GetFeedPricesUSD(ctx context.Context, tokens []ccipocr3.UnknownEncodedAddress, tokenInfo map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo) (ccipocr3.TokenPriceMap, error) { + var tokenStrs []string + for _, token := range tokens { + tokenStrs = append(tokenStrs, string(token)) + } + + resp, err := c.grpc.GetFeedPricesUSD(ctx, &ccipocr3pb.GetFeedPricesUSDRequest{ + Tokens: tokenStrs, + TokenInfo: tokenInfoMapToPb(tokenInfo), + }) + if err != nil { + return nil, err + } + return pbToTokenPriceMap(resp.Prices), nil +} + +func (c *ChainAccessorClient) GetFeeQuoterTokenUpdates(ctx context.Context, tokens []ccipocr3.UnknownEncodedAddress, chain ccipocr3.ChainSelector) (map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig, error) { + var tokenStrs []string + for _, token := range tokens { + tokenStrs = append(tokenStrs, string(token)) + } + + resp, err := c.grpc.GetFeeQuoterTokenUpdates(ctx, &ccipocr3pb.GetFeeQuoterTokenUpdatesRequest{ + Tokens: tokenStrs, + ChainSelector: uint64(chain), + }) + if err != nil { + return nil, err + } + return pbToTokenUpdatesUnix(resp.TokenUpdates), nil +} + // Server implementation var _ ccipocr3pb.ChainAccessorServer = (*chainAccessorServer)(nil) @@ -353,7 +415,7 @@ func (s *chainAccessorServer) GetChainFeeComponents(ctx context.Context, req *em } func (s *chainAccessorServer) Sync(ctx context.Context, req *ccipocr3pb.SyncRequest) (*emptypb.Empty, error) { - err := s.impl.Sync(ctx, req.ContractName, ccipocr3.UnknownAddress(req.ContractAddress)) + err := s.impl.Sync(ctx, req.ContractName, req.ContractAddress) return &emptypb.Empty{}, err } @@ -470,13 +532,16 @@ func (s *chainAccessorServer) GetChainFeePriceUpdate(ctx context.Context, req *c chainSelectors = append(chainSelectors, ccipocr3.ChainSelector(sel)) } - priceUpdates := s.impl.GetChainFeePriceUpdate(ctx, chainSelectors) + priceUpdates, err := s.impl.GetChainFeePriceUpdate(ctx, chainSelectors) + if err != nil { + return nil, err + } - pbUpdates := make(map[uint64]*ccipocr3pb.TimestampedBig) + pbUpdates := make(map[uint64]*ccipocr3pb.TimestampedUnixBig) for chainSel, update := range priceUpdates { - pbUpdates[uint64(chainSel)] = &ccipocr3pb.TimestampedBig{ - Value: intToPbBigInt(update.Value.Int), - Timestamp: timestamppb.New(update.Timestamp), + pbUpdates[uint64(chainSel)] = &ccipocr3pb.TimestampedUnixBig{ + Value: intToPbBigInt(update.Value), + Timestamp: update.Timestamp, } } @@ -490,7 +555,7 @@ func (s *chainAccessorServer) GetLatestPriceSeqNr(ctx context.Context, req *empt if err != nil { return nil, err } - return &ccipocr3pb.GetLatestPriceSeqNrResponse{SeqNr: seqNr}, nil + return &ccipocr3pb.GetLatestPriceSeqNrResponse{SeqNr: uint64(seqNr)}, nil } // SourceAccessor server methods @@ -555,3 +620,63 @@ func (s *chainAccessorServer) GetFeeQuoterDestChainConfig(ctx context.Context, r Config: feeQuoterDestChainConfigToPb(config), }, nil } + +// USDCMessageReader server methods +func (s *chainAccessorServer) MessagesByTokenID(ctx context.Context, req *ccipocr3pb.MessagesByTokenIDRequest) (*ccipocr3pb.MessagesByTokenIDResponse, error) { + tokens, err := pbToMessageTokenIDMap(req.Tokens) + if err != nil { + return nil, err + } + + messages, err := s.impl.MessagesByTokenID( + ctx, + ccipocr3.ChainSelector(req.SourceChainSelector), + ccipocr3.ChainSelector(req.DestChainSelector), + tokens, + ) + if err != nil { + return nil, err + } + + return &ccipocr3pb.MessagesByTokenIDResponse{ + Messages: messagesByTokenIDToPb(messages), + }, nil +} + +// PriceReader server methods +func (s *chainAccessorServer) GetFeedPricesUSD(ctx context.Context, req *ccipocr3pb.GetFeedPricesUSDRequest) (*ccipocr3pb.GetFeedPricesUSDResponse, error) { + var tokens []ccipocr3.UnknownEncodedAddress + for _, tokenStr := range req.Tokens { + tokens = append(tokens, ccipocr3.UnknownEncodedAddress(tokenStr)) + } + tokenInfo := pbToTokenInfoMap(req.TokenInfo) + + prices, err := s.impl.GetFeedPricesUSD(ctx, tokens, tokenInfo) + if err != nil { + return nil, err + } + + return &ccipocr3pb.GetFeedPricesUSDResponse{ + Prices: tokenPriceMapToPb(prices), + }, nil +} + +func (s *chainAccessorServer) GetFeeQuoterTokenUpdates(ctx context.Context, req *ccipocr3pb.GetFeeQuoterTokenUpdatesRequest) (*ccipocr3pb.GetFeeQuoterTokenUpdatesResponse, error) { + var tokens []ccipocr3.UnknownEncodedAddress + for _, tokenStr := range req.Tokens { + tokens = append(tokens, ccipocr3.UnknownEncodedAddress(tokenStr)) + } + + updates, err := s.impl.GetFeeQuoterTokenUpdates( + ctx, + tokens, + ccipocr3.ChainSelector(req.ChainSelector), + ) + if err != nil { + return nil, err + } + + return &ccipocr3pb.GetFeeQuoterTokenUpdatesResponse{ + TokenUpdates: tokenUpdatesUnixToPb(updates), + }, nil +} diff --git a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/convert.go b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/convert.go index f09a0967c..c930cc165 100644 --- a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/convert.go +++ b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/convert.go @@ -11,9 +11,17 @@ import ( "github.com/smartcontractkit/chainlink-protos/cre/go/values/pb" ) -// Helper function to convert protobuf BigInt to big.Int +// Helper function to convert protobuf BigInt to big.Int, preserves nil func pbBigIntToInt(b *ccipocr3pb.BigInt) *big.Int { - if b == nil || len(b.Value) == 0 { + if b == nil { + return nil + } + + if b.Value == nil { + return nil + } + + if len(b.Value) == 0 { return big.NewInt(0) } return new(big.Int).SetBytes(b.Value) @@ -21,16 +29,24 @@ func pbBigIntToInt(b *ccipocr3pb.BigInt) *big.Int { // Helper function to convert protobuf BigInt to ccipocr3.BigInt, preserving nil func pbToBigInt(b *ccipocr3pb.BigInt) ccipocr3.BigInt { - if b == nil || len(b.Value) == 0 { + if b == nil { return ccipocr3.BigInt{Int: nil} } + + if b.Value == nil { + return ccipocr3.BigInt{Int: nil} + } + + if len(b.Value) == 0 { + return ccipocr3.BigInt{Int: big.NewInt(0)} + } return ccipocr3.NewBigInt(new(big.Int).SetBytes(b.Value)) } // Helper function to convert big.Int to protobuf BigInt func intToPbBigInt(i *big.Int) *ccipocr3pb.BigInt { if i == nil { - return &ccipocr3pb.BigInt{Value: []byte{}} + return nil } return &ccipocr3pb.BigInt{Value: i.Bytes()} } @@ -742,3 +758,170 @@ func pbToCurseInfo(pb *ccipocr3pb.CurseInfo) ccipocr3.CurseInfo { } return result } + +func pbToTokenPriceMap(pbMap map[string]*ccipocr3pb.BigInt) ccipocr3.TokenPriceMap { + if pbMap == nil { + return nil + } + result := make(ccipocr3.TokenPriceMap) + for token, pbPrice := range pbMap { + result[ccipocr3.UnknownEncodedAddress(token)] = pbToBigInt(pbPrice) + } + return result +} + +func tokenPriceMapToPb(priceMap ccipocr3.TokenPriceMap) map[string]*ccipocr3pb.BigInt { + if priceMap == nil { + return nil + } + result := make(map[string]*ccipocr3pb.BigInt) + for token, price := range priceMap { + result[string(token)] = intToPbBigInt(price.Int) + } + return result +} + +func pbToMessageTokenIDMap(pbTokens map[string]*ccipocr3pb.RampTokenAmount) (map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount, error) { + if pbTokens == nil { + return nil, nil + } + result := make(map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount) + for tokenIDStr, pbAmount := range pbTokens { + // Parse MessageTokenID from string (format: "seqNr_index") + var seqNr uint64 + var index int + if _, err := fmt.Sscanf(tokenIDStr, "%d_%d", &seqNr, &index); err != nil { + return nil, fmt.Errorf("failed to parse MessageTokenID from string %s: %w", tokenIDStr, err) + } + + tokenID := ccipocr3.NewMessageTokenID(ccipocr3.SeqNum(seqNr), index) + result[tokenID] = ccipocr3.RampTokenAmount{ + SourcePoolAddress: pbAmount.SourcePoolAddress, + DestTokenAddress: pbAmount.DestTokenAddress, + ExtraData: pbAmount.ExtraData, + Amount: pbToBigInt(pbAmount.Amount), + } + } + return result, nil +} + +func messageTokenIDMapToPb(tokens map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount) map[string]*ccipocr3pb.RampTokenAmount { + if tokens == nil { + return nil + } + result := make(map[string]*ccipocr3pb.RampTokenAmount) + for tokenID, amount := range tokens { + result[tokenID.String()] = &ccipocr3pb.RampTokenAmount{ + SourcePoolAddress: []byte(amount.SourcePoolAddress), + DestTokenAddress: []byte(amount.DestTokenAddress), + ExtraData: []byte(amount.ExtraData), + Amount: intToPbBigInt(amount.Amount.Int), + } + } + return result +} + +func pbToMessagesByTokenID(pbMessages map[string][]byte) (map[ccipocr3.MessageTokenID]ccipocr3.Bytes, error) { + if pbMessages == nil { + return nil, nil + } + result := make(map[ccipocr3.MessageTokenID]ccipocr3.Bytes) + for tokenIDStr, messageBytes := range pbMessages { + // Parse MessageTokenID from string (format: "seqNr_index") + var seqNr uint64 + var index int + if _, err := fmt.Sscanf(tokenIDStr, "%d_%d", &seqNr, &index); err != nil { + return nil, fmt.Errorf("failed to parse MessageTokenID from string %s: %w", tokenIDStr, err) + } + + tokenID := ccipocr3.NewMessageTokenID(ccipocr3.SeqNum(seqNr), index) + result[tokenID] = ccipocr3.Bytes(messageBytes) + } + return result, nil +} + +func messagesByTokenIDToPb(messages map[ccipocr3.MessageTokenID]ccipocr3.Bytes) map[string][]byte { + if messages == nil { + return nil + } + result := make(map[string][]byte) + for tokenID, messageBytes := range messages { + result[tokenID.String()] = []byte(messageBytes) + } + return result +} + +func pbToTokenUpdatesUnix(pbUpdates map[string]*ccipocr3pb.TimestampedUnixBig) map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig { + if pbUpdates == nil { + return nil + } + result := make(map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig) + for token, pbUpdate := range pbUpdates { + var value *big.Int + if pbUpdate.Value != nil && len(pbUpdate.Value.Value) > 0 { + value = new(big.Int).SetBytes(pbUpdate.Value.Value) + } else { + value = big.NewInt(0) + } + result[ccipocr3.UnknownEncodedAddress(token)] = ccipocr3.TimestampedUnixBig{ + Timestamp: pbUpdate.Timestamp, + Value: value, + } + } + return result +} + +func tokenUpdatesUnixToPb(updates map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig) map[string]*ccipocr3pb.TimestampedUnixBig { + if updates == nil { + return nil + } + result := make(map[string]*ccipocr3pb.TimestampedUnixBig) + for token, update := range updates { + result[string(token)] = &ccipocr3pb.TimestampedUnixBig{ + Timestamp: update.Timestamp, + Value: intToPbBigInt(update.Value), + } + } + return result +} + +func pbToTokenInfo(pb *ccipocr3pb.TokenInfo) ccipocr3.TokenInfo { + if pb == nil { + return ccipocr3.TokenInfo{} + } + return ccipocr3.TokenInfo{ + AggregatorAddress: ccipocr3.UnknownEncodedAddress(pb.AggregatorAddress), + DeviationPPB: pbToBigInt(pb.DeviationPpb), + Decimals: uint8(pb.Decimals), + } +} + +func tokenInfoToPb(info ccipocr3.TokenInfo) *ccipocr3pb.TokenInfo { + return &ccipocr3pb.TokenInfo{ + AggregatorAddress: string(info.AggregatorAddress), + DeviationPpb: intToPbBigInt(info.DeviationPPB.Int), + Decimals: uint32(info.Decimals), + } +} + +func pbToTokenInfoMap(pbMap map[string]*ccipocr3pb.TokenInfo) map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo { + if pbMap == nil { + return nil + } + result := make(map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo) + for token, pbInfo := range pbMap { + result[ccipocr3.UnknownEncodedAddress(token)] = pbToTokenInfo(pbInfo) + } + return result +} + +func tokenInfoMapToPb(infoMap map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo) map[string]*ccipocr3pb.TokenInfo { + if infoMap == nil { + return nil + } + result := make(map[string]*ccipocr3pb.TokenInfo) + for token, info := range infoMap { + result[string(token)] = tokenInfoToPb(info) + } + return result +} diff --git a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/convert_test.go b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/convert_test.go index 46e09d779..6f3645e19 100644 --- a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/convert_test.go +++ b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/convert_test.go @@ -1,13 +1,16 @@ package ccipocr3 import ( + "fmt" "math" "math/big" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + ccipocr3pb "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb/ccipocr3" "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-protos/cre/go/values/pb" ) @@ -92,7 +95,17 @@ func TestMessageProtobufFlattening(t *testing.T) { assert.Equal(t, []byte(tc.message.Receiver), pbMessage.Receiver) assert.Equal(t, []byte(tc.message.ExtraArgs), pbMessage.ExtraArgs) assert.Equal(t, []byte(tc.message.FeeToken), pbMessage.FeeToken) - assert.NotNil(t, pbMessage.FeeValueJuels) + // With nil BigInt values, protobuf fields should be nil + if tc.message.FeeTokenAmount.Int == nil { + assert.Nil(t, pbMessage.FeeTokenAmount) + } else { + assert.NotNil(t, pbMessage.FeeTokenAmount) + } + if tc.message.FeeValueJuels.Int == nil { + assert.Nil(t, pbMessage.FeeValueJuels) + } else { + assert.NotNil(t, pbMessage.FeeValueJuels) + } // Convert back to Go struct convertedMessage := pbToMessage(pbMessage) @@ -648,3 +661,936 @@ func TestSourceChainConfigNilHandling(t *testing.T) { assert.Equal(t, []byte(nil), pbConfig.OnRamp) }) } + +// TestTokenPriceMapConversion tests the new TokenPriceMap conversion functions +func TestTokenPriceMapConversion(t *testing.T) { + testCases := []struct { + name string + priceMap ccipocr3.TokenPriceMap + }{ + { + name: "TokenPriceMap with multiple tokens", + priceMap: ccipocr3.TokenPriceMap{ + ccipocr3.UnknownEncodedAddress("token1"): ccipocr3.NewBigInt(big.NewInt(1000000)), + ccipocr3.UnknownEncodedAddress("token2"): ccipocr3.NewBigInt(big.NewInt(2500000)), + ccipocr3.UnknownEncodedAddress("token3"): ccipocr3.NewBigInt(big.NewInt(500000)), + }, + }, + { + name: "Empty TokenPriceMap", + priceMap: ccipocr3.TokenPriceMap{}, + }, + { + name: "TokenPriceMap with zero prices", + priceMap: ccipocr3.TokenPriceMap{ + ccipocr3.UnknownEncodedAddress("zero-token"): ccipocr3.NewBigInt(big.NewInt(0)), + }, + }, + { + name: "TokenPriceMap with large prices", + priceMap: ccipocr3.TokenPriceMap{ + ccipocr3.UnknownEncodedAddress("large-token"): func() ccipocr3.BigInt { + val, _ := new(big.Int).SetString("999999999999999999999999999999", 10) + return ccipocr3.NewBigInt(val) + }(), + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Convert Go -> Protobuf + pbMap := tokenPriceMapToPb(tc.priceMap) + + if tc.priceMap == nil { + assert.Nil(t, pbMap) + return + } + + require.NotNil(t, pbMap) + assert.Equal(t, len(tc.priceMap), len(pbMap)) + + // Verify protobuf values + for token, price := range tc.priceMap { + pbPrice, exists := pbMap[string(token)] + require.True(t, exists, "token %s should exist in protobuf map", string(token)) + require.NotNil(t, pbPrice) + assert.Equal(t, price.Int.Bytes(), pbPrice.Value) + } + + // Convert Protobuf -> Go (round-trip) + convertedMap := pbToTokenPriceMap(pbMap) + + // Verify round-trip conversion + assert.Equal(t, len(tc.priceMap), len(convertedMap)) + for token, originalPrice := range tc.priceMap { + convertedPrice, exists := convertedMap[token] + require.True(t, exists, "token %s should exist in converted map", string(token)) + assert.Equal(t, originalPrice.Int.String(), convertedPrice.Int.String(), "price should survive round-trip for token %s", string(token)) + } + }) + } +} + +func TestTokenPriceMapNilHandling(t *testing.T) { + t.Run("nil TokenPriceMap to protobuf", func(t *testing.T) { + pbMap := tokenPriceMapToPb(nil) + assert.Nil(t, pbMap) + }) + + t.Run("nil protobuf map to TokenPriceMap", func(t *testing.T) { + priceMap := pbToTokenPriceMap(nil) + assert.Nil(t, priceMap) + }) + + t.Run("empty protobuf map to TokenPriceMap", func(t *testing.T) { + emptyPbMap := make(map[string]*ccipocr3pb.BigInt) + priceMap := pbToTokenPriceMap(emptyPbMap) + require.NotNil(t, priceMap) + assert.Equal(t, 0, len(priceMap)) + }) +} + +// TestMessageTokenIDMapConversion tests the MessageTokenID map conversion functions +func TestMessageTokenIDMapConversion(t *testing.T) { + testCases := []struct { + name string + tokenMap map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount + }{ + { + name: "MessageTokenID map with multiple tokens", + tokenMap: map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount{ + ccipocr3.NewMessageTokenID(1, 0): { + SourcePoolAddress: ccipocr3.UnknownAddress("source-pool-1"), + DestTokenAddress: ccipocr3.UnknownAddress("dest-token-1"), + ExtraData: ccipocr3.Bytes("extra-data-1"), + Amount: ccipocr3.NewBigInt(big.NewInt(1000)), + }, + ccipocr3.NewMessageTokenID(2, 1): { + SourcePoolAddress: ccipocr3.UnknownAddress("source-pool-2"), + DestTokenAddress: ccipocr3.UnknownAddress("dest-token-2"), + ExtraData: ccipocr3.Bytes("extra-data-2"), + Amount: ccipocr3.NewBigInt(big.NewInt(2000)), + }, + ccipocr3.NewMessageTokenID(10, 5): { + SourcePoolAddress: ccipocr3.UnknownAddress("source-pool-10"), + DestTokenAddress: ccipocr3.UnknownAddress("dest-token-10"), + ExtraData: ccipocr3.Bytes(""), + Amount: ccipocr3.NewBigInt(big.NewInt(0)), + }, + }, + }, + { + name: "Empty MessageTokenID map", + tokenMap: map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount{}, + }, + { + name: "Single MessageTokenID with large values", + tokenMap: map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount{ + ccipocr3.NewMessageTokenID(999999, 255): { + SourcePoolAddress: ccipocr3.UnknownAddress("very-long-source-pool-address-with-many-characters"), + DestTokenAddress: ccipocr3.UnknownAddress("very-long-dest-token-address-with-many-characters"), + ExtraData: ccipocr3.Bytes("very long extra data with many characters that tests the handling of large data"), + Amount: func() ccipocr3.BigInt { + val, _ := new(big.Int).SetString("123456789012345678901234567890", 10) + return ccipocr3.NewBigInt(val) + }(), + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Convert Go -> Protobuf + pbMap := messageTokenIDMapToPb(tc.tokenMap) + + if tc.tokenMap == nil { + assert.Nil(t, pbMap) + return + } + + require.NotNil(t, pbMap) + assert.Equal(t, len(tc.tokenMap), len(pbMap)) + + // Verify protobuf values + for tokenID, amount := range tc.tokenMap { + tokenIDStr := tokenID.String() + pbAmount, exists := pbMap[tokenIDStr] + require.True(t, exists, "tokenID %s should exist in protobuf map", tokenIDStr) + require.NotNil(t, pbAmount) + assert.Equal(t, []byte(amount.SourcePoolAddress), pbAmount.SourcePoolAddress) + assert.Equal(t, []byte(amount.DestTokenAddress), pbAmount.DestTokenAddress) + assert.Equal(t, []byte(amount.ExtraData), pbAmount.ExtraData) + assert.Equal(t, amount.Amount.Int.Bytes(), pbAmount.Amount.Value) + } + + // Convert Protobuf -> Go (round-trip) + convertedMap, err := pbToMessageTokenIDMap(pbMap) + require.NoError(t, err) + + // Verify round-trip conversion + assert.Equal(t, len(tc.tokenMap), len(convertedMap)) + for tokenID, originalAmount := range tc.tokenMap { + convertedAmount, exists := convertedMap[tokenID] + require.True(t, exists, "tokenID %s should exist in converted map", tokenID.String()) + assert.Equal(t, []byte(originalAmount.SourcePoolAddress), []byte(convertedAmount.SourcePoolAddress)) + assert.Equal(t, []byte(originalAmount.DestTokenAddress), []byte(convertedAmount.DestTokenAddress)) + assert.Equal(t, []byte(originalAmount.ExtraData), []byte(convertedAmount.ExtraData)) + assert.Equal(t, originalAmount.Amount.Int.String(), convertedAmount.Amount.Int.String()) + } + }) + } +} + +func TestMessageTokenIDMapErrorHandling(t *testing.T) { + t.Run("invalid tokenID string should return error", func(t *testing.T) { + pbMap := map[string]*ccipocr3pb.RampTokenAmount{ + "invalid-format": { + SourcePoolAddress: []byte("test"), + DestTokenAddress: []byte("test"), + ExtraData: []byte("test"), + Amount: &ccipocr3pb.BigInt{Value: []byte{0x01}}, + }, + } + + _, err := pbToMessageTokenIDMap(pbMap) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse MessageTokenID") + }) + + t.Run("nil protobuf map should not error", func(t *testing.T) { + result, err := pbToMessageTokenIDMap(nil) + assert.NoError(t, err) + assert.Nil(t, result) + }) + + t.Run("nil Go map should return nil", func(t *testing.T) { + result := messageTokenIDMapToPb(nil) + assert.Nil(t, result) + }) +} + +// TestMessagesByTokenIDConversion tests the messages by token ID conversion functions +func TestMessagesByTokenIDConversion(t *testing.T) { + testCases := []struct { + name string + messages map[ccipocr3.MessageTokenID]ccipocr3.Bytes + }{ + { + name: "Messages with multiple token IDs", + messages: map[ccipocr3.MessageTokenID]ccipocr3.Bytes{ + ccipocr3.NewMessageTokenID(1, 0): ccipocr3.Bytes("usdc-message-data-1"), + ccipocr3.NewMessageTokenID(2, 1): ccipocr3.Bytes("usdc-message-data-2"), + ccipocr3.NewMessageTokenID(5, 3): ccipocr3.Bytes("usdc-message-data-5"), + }, + }, + { + name: "Empty messages map", + messages: map[ccipocr3.MessageTokenID]ccipocr3.Bytes{}, + }, + { + name: "Messages with binary data", + messages: map[ccipocr3.MessageTokenID]ccipocr3.Bytes{ + ccipocr3.NewMessageTokenID(100, 50): ccipocr3.Bytes([]byte{0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD}), + }, + }, + { + name: "Messages with empty data", + messages: map[ccipocr3.MessageTokenID]ccipocr3.Bytes{ + ccipocr3.NewMessageTokenID(0, 0): ccipocr3.Bytes(""), + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Convert Go -> Protobuf + pbMap := messagesByTokenIDToPb(tc.messages) + + if tc.messages == nil { + assert.Nil(t, pbMap) + return + } + + require.NotNil(t, pbMap) + assert.Equal(t, len(tc.messages), len(pbMap)) + + // Verify protobuf values + for tokenID, messageBytes := range tc.messages { + tokenIDStr := tokenID.String() + pbBytes, exists := pbMap[tokenIDStr] + require.True(t, exists, "tokenID %s should exist in protobuf map", tokenIDStr) + assert.Equal(t, []byte(messageBytes), pbBytes) + } + + // Convert Protobuf -> Go (round-trip) + convertedMap, err := pbToMessagesByTokenID(pbMap) + require.NoError(t, err) + + // Verify round-trip conversion + assert.Equal(t, len(tc.messages), len(convertedMap)) + for tokenID, originalBytes := range tc.messages { + convertedBytes, exists := convertedMap[tokenID] + require.True(t, exists, "tokenID %s should exist in converted map", tokenID.String()) + assert.Equal(t, []byte(originalBytes), []byte(convertedBytes)) + } + }) + } +} + +func TestMessagesByTokenIDErrorHandling(t *testing.T) { + t.Run("invalid tokenID string should return error", func(t *testing.T) { + pbMap := map[string][]byte{ + "not-a-valid-format": []byte("test-message"), + } + + _, err := pbToMessagesByTokenID(pbMap) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse MessageTokenID") + }) + + t.Run("nil protobuf map should not error", func(t *testing.T) { + result, err := pbToMessagesByTokenID(nil) + assert.NoError(t, err) + assert.Nil(t, result) + }) + + t.Run("nil Go map should return nil", func(t *testing.T) { + result := messagesByTokenIDToPb(nil) + assert.Nil(t, result) + }) +} + +// TestTokenUpdatesUnixConversion tests the TimestampedUnixBig token updates conversion functions +func TestTokenUpdatesUnixConversion(t *testing.T) { + testTime := time.Date(2024, 1, 15, 12, 0, 0, 0, time.UTC) + + testCases := []struct { + name string + updates map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig + }{ + { + name: "Unix token updates with multiple tokens", + updates: map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig{ + ccipocr3.UnknownEncodedAddress("token1"): { + Timestamp: uint32(testTime.Unix()), + Value: big.NewInt(1500000), + }, + ccipocr3.UnknownEncodedAddress("token2"): { + Timestamp: uint32(testTime.Add(time.Hour).Unix()), + Value: big.NewInt(2500000), + }, + ccipocr3.UnknownEncodedAddress("token3"): { + Timestamp: uint32(testTime.Add(2 * time.Hour).Unix()), + Value: big.NewInt(750000), + }, + }, + }, + { + name: "Empty unix token updates", + updates: map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig{}, + }, + { + name: "Unix token update with zero value", + updates: map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig{ + ccipocr3.UnknownEncodedAddress("zero-token"): { + Timestamp: uint32(testTime.Unix()), + Value: big.NewInt(0), + }, + }, + }, + { + name: "Unix token update with large value", + updates: map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig{ + ccipocr3.UnknownEncodedAddress("large-token"): { + Timestamp: uint32(testTime.Unix()), + Value: func() *big.Int { + val, _ := new(big.Int).SetString("999999999999999999999999999999", 10) + return val + }(), + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Convert Go -> Protobuf + pbMap := tokenUpdatesUnixToPb(tc.updates) + + if tc.updates == nil { + assert.Nil(t, pbMap) + return + } + + require.NotNil(t, pbMap) + assert.Equal(t, len(tc.updates), len(pbMap)) + + // Verify protobuf values + for token, update := range tc.updates { + pbUpdate, exists := pbMap[string(token)] + require.True(t, exists, "token %s should exist in protobuf map", string(token)) + require.NotNil(t, pbUpdate) + require.NotNil(t, pbUpdate.Value) + + assert.Equal(t, update.Timestamp, pbUpdate.Timestamp) + assert.Equal(t, update.Value.Bytes(), pbUpdate.Value.Value) + } + + // Convert Protobuf -> Go (round-trip) + convertedMap := pbToTokenUpdatesUnix(pbMap) + + // Verify round-trip conversion + assert.Equal(t, len(tc.updates), len(convertedMap)) + for token, originalUpdate := range tc.updates { + convertedUpdate, exists := convertedMap[token] + require.True(t, exists, "token %s should exist in converted map", string(token)) + + assert.Equal(t, originalUpdate.Timestamp, convertedUpdate.Timestamp) + assert.Equal(t, originalUpdate.Value.String(), convertedUpdate.Value.String()) + } + }) + } +} + +func TestTokenUpdatesUnixNilHandling(t *testing.T) { + t.Run("nil unix token updates to protobuf", func(t *testing.T) { + pbMap := tokenUpdatesUnixToPb(nil) + assert.Nil(t, pbMap) + }) + + t.Run("nil protobuf map to unix token updates", func(t *testing.T) { + updates := pbToTokenUpdatesUnix(nil) + assert.Nil(t, updates) + }) + + t.Run("empty protobuf map to unix token updates", func(t *testing.T) { + emptyPbMap := make(map[string]*ccipocr3pb.TimestampedUnixBig) + updates := pbToTokenUpdatesUnix(emptyPbMap) + require.NotNil(t, updates) + assert.Equal(t, 0, len(updates)) + }) + + t.Run("protobuf map with nil value", func(t *testing.T) { + pbMap := map[string]*ccipocr3pb.TimestampedUnixBig{ + "test-token": { + Timestamp: 1705320000, // Some valid unix timestamp + Value: nil, + }, + } + + // Should not panic and handle gracefully + updates := pbToTokenUpdatesUnix(pbMap) + require.NotNil(t, updates) + require.Contains(t, updates, ccipocr3.UnknownEncodedAddress("test-token")) + + // When value is nil, should default to zero big.Int + update := updates[("test-token")] + assert.Equal(t, uint32(1705320000), update.Timestamp) + assert.Equal(t, big.NewInt(0), update.Value) + }) +} + +// TestPbBigIntToInt tests the pbBigIntToInt function with various inputs +func TestPbBigIntToInt(t *testing.T) { + testCases := []struct { + name string + input *ccipocr3pb.BigInt + expected *big.Int + }{ + { + name: "nil input", + input: nil, + expected: nil, + }, + { + name: "empty value bytes", // empty bytes are treated as zero + input: &ccipocr3pb.BigInt{Value: []byte{}}, + expected: big.NewInt(0), + }, + { + name: "nil value bytes", + input: &ccipocr3pb.BigInt{Value: nil}, + expected: nil, + }, + { + name: "zero value", + input: &ccipocr3pb.BigInt{Value: big.NewInt(0).Bytes()}, + expected: big.NewInt(0), + }, + { + name: "positive small integer", + input: &ccipocr3pb.BigInt{Value: big.NewInt(42).Bytes()}, + expected: big.NewInt(42), + }, + { + name: "positive large integer", + input: &ccipocr3pb.BigInt{Value: big.NewInt(1234567890).Bytes()}, + expected: big.NewInt(1234567890), + }, + { + name: "very large positive integer", + input: &ccipocr3pb.BigInt{Value: func() []byte { + val := new(big.Int) + val.SetString("999999999999999999999999999999", 10) + return val.Bytes() + }()}, + expected: func() *big.Int { + val := new(big.Int) + val.SetString("999999999999999999999999999999", 10) + return val + }(), + }, + { + name: "maximum uint64 value", + input: &ccipocr3pb.BigInt{Value: func() []byte { + val := new(big.Int) + val.SetUint64(^uint64(0)) // max uint64 + return val.Bytes() + }()}, + expected: func() *big.Int { + val := new(big.Int) + val.SetUint64(^uint64(0)) + return val + }(), + }, + { + name: "256-bit integer (32 bytes)", + input: &ccipocr3pb.BigInt{Value: func() []byte { + // Create a 256-bit integer (all bits set) + bytes := make([]byte, 32) + for i := range bytes { + bytes[i] = 0xFF + } + return bytes + }()}, + expected: func() *big.Int { + bytes := make([]byte, 32) + for i := range bytes { + bytes[i] = 0xFF + } + return new(big.Int).SetBytes(bytes) + }(), + }, + { + name: "single byte value", + input: &ccipocr3pb.BigInt{Value: []byte{0xFF}}, + expected: big.NewInt(255), + }, + { + name: "two byte value", + input: &ccipocr3pb.BigInt{Value: []byte{0x01, 0x00}}, + expected: big.NewInt(256), + }, + { + name: "leading zero bytes (should be handled correctly)", + input: &ccipocr3pb.BigInt{Value: []byte{0x00, 0x00, 0x01, 0x00}}, + expected: big.NewInt(256), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := pbBigIntToInt(tc.input) + + // Handle nil comparisons specially + if tc.expected == nil { + assert.Nil(t, result, "result should be nil when expected is nil") + } else { + assert.NotNil(t, result, "result should not be nil when expected is not nil") + assert.Equal(t, tc.expected.String(), result.String(), "converted big.Int should match expected value") + assert.Equal(t, tc.expected.Cmp(result), 0, "big.Int comparison should be equal") + } + }) + } +} + +// TestPbToBigInt tests the pbToBigInt function with various inputs +func TestPbToBigInt(t *testing.T) { + testCases := []struct { + name string + input *ccipocr3pb.BigInt + expected ccipocr3.BigInt + }{ + { + name: "nil input should preserve nil", + input: nil, + expected: ccipocr3.BigInt{Int: nil}, + }, + { + name: "empty value bytes should return zero BigInt", + input: &ccipocr3pb.BigInt{Value: []byte{}}, + expected: ccipocr3.BigInt{Int: big.NewInt(0)}, + }, + { + name: "nil value bytes should preserve nil", + input: &ccipocr3pb.BigInt{Value: nil}, + expected: ccipocr3.BigInt{Int: nil}, + }, + { + name: "zero value", + input: &ccipocr3pb.BigInt{Value: big.NewInt(0).Bytes()}, + expected: ccipocr3.NewBigInt(big.NewInt(0)), + }, + { + name: "positive small integer", + input: &ccipocr3pb.BigInt{Value: big.NewInt(123).Bytes()}, + expected: ccipocr3.NewBigInt(big.NewInt(123)), + }, + { + name: "positive large integer", + input: &ccipocr3pb.BigInt{Value: big.NewInt(9876543210).Bytes()}, + expected: ccipocr3.NewBigInt(big.NewInt(9876543210)), + }, + { + name: "very large positive integer", + input: &ccipocr3pb.BigInt{Value: func() []byte { + val := new(big.Int) + val.SetString("123456789012345678901234567890", 10) + return val.Bytes() + }()}, + expected: func() ccipocr3.BigInt { + val := new(big.Int) + val.SetString("123456789012345678901234567890", 10) + return ccipocr3.NewBigInt(val) + }(), + }, + { + name: "maximum uint64 value", + input: &ccipocr3pb.BigInt{Value: func() []byte { + val := new(big.Int) + val.SetUint64(^uint64(0)) // max uint64 + return val.Bytes() + }()}, + expected: func() ccipocr3.BigInt { + val := new(big.Int) + val.SetUint64(^uint64(0)) + return ccipocr3.NewBigInt(val) + }(), + }, + { + name: "256-bit integer (32 bytes)", + input: &ccipocr3pb.BigInt{Value: func() []byte { + // Create a 256-bit integer + bytes := make([]byte, 32) + for i := range bytes { + bytes[i] = 0xAA // alternating bit pattern + } + return bytes + }()}, + expected: func() ccipocr3.BigInt { + bytes := make([]byte, 32) + for i := range bytes { + bytes[i] = 0xAA + } + return ccipocr3.NewBigInt(new(big.Int).SetBytes(bytes)) + }(), + }, + { + name: "single byte maximum value", + input: &ccipocr3pb.BigInt{Value: []byte{0xFF}}, + expected: ccipocr3.NewBigInt(big.NewInt(255)), + }, + { + name: "two byte value", + input: &ccipocr3pb.BigInt{Value: []byte{0xFF, 0xFF}}, + expected: ccipocr3.NewBigInt(big.NewInt(65535)), + }, + { + name: "ethereum wei amount (18 decimals)", + input: &ccipocr3pb.BigInt{Value: func() []byte { + // 1 ETH in wei = 10^18 + val := new(big.Int) + val.SetString("1000000000000000000", 10) + return val.Bytes() + }()}, + expected: func() ccipocr3.BigInt { + val := new(big.Int) + val.SetString("1000000000000000000", 10) + return ccipocr3.NewBigInt(val) + }(), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := pbToBigInt(tc.input) + + // Handle nil comparisons specially + if tc.expected.Int == nil { + assert.Nil(t, result.Int, "result.Int should be nil when expected is nil") + } else { + assert.NotNil(t, result.Int, "result.Int should not be nil when expected is not nil") + assert.Equal(t, tc.expected.Int.String(), result.Int.String(), "converted BigInt should match expected value") + assert.Equal(t, tc.expected.Int.Cmp(result.Int), 0, "BigInt comparison should be equal") + } + }) + } +} + +// TestPbBigIntRoundTrip tests round-trip conversion between protobuf BigInt and Go big.Int +func TestPbBigIntRoundTrip(t *testing.T) { + testValues := []*big.Int{ + nil, // Test nil value + big.NewInt(0), + big.NewInt(1), + big.NewInt(42), + big.NewInt(255), + big.NewInt(256), + big.NewInt(65535), + big.NewInt(65536), + big.NewInt(1234567890), + func() *big.Int { + val := new(big.Int) + val.SetString("999999999999999999999999999999", 10) + return val + }(), + func() *big.Int { + val := new(big.Int) + val.SetUint64(^uint64(0)) // max uint64 + return val + }(), + } + + for i, originalValue := range testValues { + t.Run(fmt.Sprintf("round_trip_%d", i), func(t *testing.T) { + // Go big.Int -> protobuf BigInt -> Go big.Int + pbBigInt := intToPbBigInt(originalValue) + convertedValue := pbBigIntToInt(pbBigInt) + + // Handle nil case specially + if originalValue == nil { + assert.Nil(t, convertedValue, "nil should round-trip to nil") + } else { + assert.NotNil(t, convertedValue, "non-nil should round-trip to non-nil") + assert.Equal(t, originalValue.String(), convertedValue.String(), "round-trip conversion should preserve value") + assert.Equal(t, originalValue.Cmp(convertedValue), 0, "round-trip big.Int comparison should be equal") + } + }) + } +} + +// TestPbToBigIntRoundTrip tests round-trip conversion between protobuf BigInt and ccipocr3.BigInt +func TestPbToBigIntRoundTrip(t *testing.T) { + testValues := []ccipocr3.BigInt{ + ccipocr3.NewBigInt(big.NewInt(0)), + ccipocr3.NewBigInt(big.NewInt(1)), + ccipocr3.NewBigInt(big.NewInt(42)), + ccipocr3.NewBigInt(big.NewInt(255)), + ccipocr3.NewBigInt(big.NewInt(256)), + ccipocr3.NewBigInt(big.NewInt(65535)), + ccipocr3.NewBigInt(big.NewInt(65536)), + ccipocr3.NewBigInt(big.NewInt(1234567890)), + func() ccipocr3.BigInt { + val := new(big.Int) + val.SetString("999999999999999999999999999999", 10) + return ccipocr3.NewBigInt(val) + }(), + func() ccipocr3.BigInt { + val := new(big.Int) + val.SetUint64(^uint64(0)) // max uint64 + return ccipocr3.NewBigInt(val) + }(), + // Test nil value specially + ccipocr3.BigInt{Int: nil}, + } + + for i, originalValue := range testValues { + t.Run(fmt.Sprintf("round_trip_%d", i), func(t *testing.T) { + // ccipocr3.BigInt -> protobuf BigInt -> ccipocr3.BigInt + pbBigInt := intToPbBigInt(originalValue.Int) + convertedValue := pbToBigInt(pbBigInt) + + // Handle nil case specially + if originalValue.Int == nil { + assert.Nil(t, convertedValue.Int, "nil should round-trip to nil") + } else { + assert.NotNil(t, convertedValue.Int, "converted value should not be nil for non-nil input") + assert.Equal(t, originalValue.Int.String(), convertedValue.Int.String(), "round-trip conversion should preserve value") + assert.Equal(t, originalValue.Int.Cmp(convertedValue.Int), 0, "round-trip BigInt comparison should be equal") + } + }) + } +} + +// TestPbBigIntEdgeCases tests edge cases and error conditions +func TestPbBigIntEdgeCases(t *testing.T) { + t.Run("empty bytes should not panic", func(t *testing.T) { + input := &ccipocr3pb.BigInt{Value: []byte{}} + + // Should not panic + result1 := pbBigIntToInt(input) + result2 := pbToBigInt(input) + + assert.Equal(t, big.NewInt(0).String(), result1.String()) + assert.Equal(t, big.NewInt(0).String(), result2.Int.String()) + }) + + t.Run("single zero byte should equal zero", func(t *testing.T) { + input := &ccipocr3pb.BigInt{Value: []byte{0x00}} + + result1 := pbBigIntToInt(input) + result2 := pbToBigInt(input) + + assert.Equal(t, big.NewInt(0).String(), result1.String()) + assert.Equal(t, big.NewInt(0).String(), result2.Int.String()) + }) + + t.Run("multiple zero bytes should equal zero", func(t *testing.T) { + input := &ccipocr3pb.BigInt{Value: []byte{0x00, 0x00, 0x00, 0x00}} + + result1 := pbBigIntToInt(input) + result2 := pbToBigInt(input) + + assert.Equal(t, big.NewInt(0).String(), result1.String()) + assert.Equal(t, big.NewInt(0).String(), result2.Int.String()) + }) + + t.Run("large byte array should work correctly", func(t *testing.T) { + // Create a 64-byte array (512 bits) + bytes := make([]byte, 64) + bytes[0] = 0x01 // Set the most significant bit to 1 + + input := &ccipocr3pb.BigInt{Value: bytes} + + result1 := pbBigIntToInt(input) + result2 := pbToBigInt(input) + + expected := new(big.Int).SetBytes(bytes) + + assert.Equal(t, expected.String(), result1.String()) + assert.Equal(t, expected.String(), result2.Int.String()) + }) +} + +// TestPbBigIntConsistency tests that both functions handle the same inputs consistently +func TestPbBigIntConsistency(t *testing.T) { + testInputs := []*ccipocr3pb.BigInt{ + nil, + {Value: nil}, + {Value: []byte{}}, + {Value: []byte{0x00}}, + {Value: []byte{0x01}}, + {Value: []byte{0xFF}}, + {Value: []byte{0x01, 0x00}}, + {Value: []byte{0xFF, 0xFF}}, + {Value: big.NewInt(42).Bytes()}, + {Value: big.NewInt(1234567890).Bytes()}, + } + + for i, input := range testInputs { + t.Run(fmt.Sprintf("consistency_test_%d", i), func(t *testing.T) { + result1 := pbBigIntToInt(input) + result2 := pbToBigInt(input) + + // For non-nil inputs, both functions should produce equivalent numeric results + // (except pbToBigInt may preserve nil differently) + if input != nil { + if result2.Int != nil { + assert.Equal(t, result1.String(), result2.Int.String(), + "pbBigIntToInt and pbToBigInt should produce equivalent numeric results") + } + } + }) + } +} + +// TestTokenInfoConversion tests the TokenInfo conversion functions +func TestTokenInfoConversion(t *testing.T) { + testCases := []struct { + name string + info ccipocr3.TokenInfo + expected ccipocr3.TokenInfo + }{ + { + name: "complete TokenInfo", + info: ccipocr3.TokenInfo{ + AggregatorAddress: ccipocr3.UnknownEncodedAddress("0x1234567890123456789012345678901234567890"), + DeviationPPB: ccipocr3.NewBigInt(big.NewInt(1000000000)), // 1% + Decimals: 18, + }, + expected: ccipocr3.TokenInfo{ + AggregatorAddress: ccipocr3.UnknownEncodedAddress("0x1234567890123456789012345678901234567890"), + DeviationPPB: ccipocr3.NewBigInt(big.NewInt(1000000000)), + Decimals: 18, + }, + }, + { + name: "minimal TokenInfo", + info: ccipocr3.TokenInfo{ + AggregatorAddress: ccipocr3.UnknownEncodedAddress("0xabc"), + DeviationPPB: ccipocr3.NewBigInt(big.NewInt(1)), + Decimals: 6, + }, + expected: ccipocr3.TokenInfo{ + AggregatorAddress: ccipocr3.UnknownEncodedAddress("0xabc"), + DeviationPPB: ccipocr3.NewBigInt(big.NewInt(1)), + Decimals: 6, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Convert to protobuf and back + pbInfo := tokenInfoToPb(tc.info) + convertedInfo := pbToTokenInfo(pbInfo) + + assert.Equal(t, tc.expected.AggregatorAddress, convertedInfo.AggregatorAddress) + assert.Equal(t, tc.expected.DeviationPPB.String(), convertedInfo.DeviationPPB.String()) + assert.Equal(t, tc.expected.Decimals, convertedInfo.Decimals) + }) + } +} + +// TestTokenInfoMapConversion tests the TokenInfo map conversion functions +func TestTokenInfoMapConversion(t *testing.T) { + testMap := map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo{ + "token1": { + AggregatorAddress: ccipocr3.UnknownEncodedAddress("0x1111111111111111111111111111111111111111"), + DeviationPPB: ccipocr3.NewBigInt(big.NewInt(2000000000)), // 2% + Decimals: 18, + }, + "token2": { + AggregatorAddress: ccipocr3.UnknownEncodedAddress("0x2222222222222222222222222222222222222222"), + DeviationPPB: ccipocr3.NewBigInt(big.NewInt(5000000000)), // 5% + Decimals: 6, + }, + } + + // Convert to protobuf and back + pbMap := tokenInfoMapToPb(testMap) + convertedMap := pbToTokenInfoMap(pbMap) + + assert.Len(t, convertedMap, 2) + + for token, expectedInfo := range testMap { + convertedInfo, exists := convertedMap[token] + assert.True(t, exists, "Token %s should exist in converted map", token) + assert.Equal(t, expectedInfo.AggregatorAddress, convertedInfo.AggregatorAddress) + assert.Equal(t, expectedInfo.DeviationPPB.String(), convertedInfo.DeviationPPB.String()) + assert.Equal(t, expectedInfo.Decimals, convertedInfo.Decimals) + } +} + +// TestTokenInfoMapNilHandling tests nil handling for TokenInfo map conversion +func TestTokenInfoMapNilHandling(t *testing.T) { + t.Run("nil map to protobuf", func(t *testing.T) { + result := tokenInfoMapToPb(nil) + assert.Nil(t, result) + }) + + t.Run("nil protobuf map to Go", func(t *testing.T) { + result := pbToTokenInfoMap(nil) + assert.Nil(t, result) + }) + + t.Run("empty map round-trip", func(t *testing.T) { + emptyMap := make(map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo) + pbMap := tokenInfoMapToPb(emptyMap) + convertedMap := pbToTokenInfoMap(pbMap) + assert.NotNil(t, convertedMap) + assert.Len(t, convertedMap, 0) + }) +} diff --git a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/test/chain_accessor.go b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/test/chain_accessor.go index 32b9fe7ec..454220b7b 100644 --- a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/test/chain_accessor.go +++ b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/test/chain_accessor.go @@ -205,14 +205,14 @@ func ChainAccessor(lggr logger.Logger) staticChainAccessor { "sender3": 5, }, }, - chainFeePriceUpdates: map[ccipocr3.ChainSelector]ccipocr3.TimestampedBig{ + chainFeePriceUpdates: map[ccipocr3.ChainSelector]ccipocr3.TimestampedUnixBig{ ccipocr3.ChainSelector(1): { - Timestamp: testTime, - Value: ccipocr3.NewBigInt(big.NewInt(2000000000)), + Timestamp: uint32(testTime.Unix()), + Value: big.NewInt(2000000000), }, ccipocr3.ChainSelector(2): { - Timestamp: testTime.Add(time.Hour), - Value: ccipocr3.NewBigInt(big.NewInt(1800000000)), + Timestamp: uint32(testTime.Add(time.Hour).Unix()), + Value: big.NewInt(1800000000), }, }, latestPriceSeqNr: 42, @@ -294,7 +294,7 @@ type staticChainAccessorConfig struct { executedMessages map[ccipocr3.ChainSelector][]ccipocr3.SeqNum nextSeqNums map[ccipocr3.ChainSelector]ccipocr3.SeqNum nonces map[ccipocr3.ChainSelector]map[string]uint64 - chainFeePriceUpdates map[ccipocr3.ChainSelector]ccipocr3.TimestampedBig + chainFeePriceUpdates map[ccipocr3.ChainSelector]ccipocr3.TimestampedUnixBig latestPriceSeqNr uint64 messages []ccipocr3.Message latestMessageSeqNr ccipocr3.SeqNum @@ -351,12 +351,12 @@ func (s staticChainAccessor) Nonces(ctx context.Context, addresses map[ccipocr3. return s.nonces, nil } -func (s staticChainAccessor) GetChainFeePriceUpdate(ctx context.Context, chains []ccipocr3.ChainSelector) map[ccipocr3.ChainSelector]ccipocr3.TimestampedBig { - return s.chainFeePriceUpdates +func (s staticChainAccessor) GetChainFeePriceUpdate(ctx context.Context, chains []ccipocr3.ChainSelector) (map[ccipocr3.ChainSelector]ccipocr3.TimestampedUnixBig, error) { + return s.chainFeePriceUpdates, nil } -func (s staticChainAccessor) GetLatestPriceSeqNr(ctx context.Context) (uint64, error) { - return s.latestPriceSeqNr, nil +func (s staticChainAccessor) GetLatestPriceSeqNr(ctx context.Context) (ccipocr3.SeqNum, error) { + return ccipocr3.SeqNum(s.latestPriceSeqNr), nil } // SourceAccessor implementation @@ -381,6 +381,45 @@ func (s staticChainAccessor) GetFeeQuoterDestChainConfig(ctx context.Context, de return s.feeQuoterDestChainConfig, nil } +// USDCMessageReader implementation +func (s staticChainAccessor) MessagesByTokenID(ctx context.Context, source, dest ccipocr3.ChainSelector, tokens map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount) (map[ccipocr3.MessageTokenID]ccipocr3.Bytes, error) { + // Return static test data for USDC messages + result := make(map[ccipocr3.MessageTokenID]ccipocr3.Bytes) + for tokenID := range tokens { + // Return some test message bytes + result[tokenID] = ccipocr3.Bytes(fmt.Sprintf("usdc-message-data-for-%s", tokenID.String())) + } + return result, nil +} + +// PriceReader implementation +func (s staticChainAccessor) GetFeedPricesUSD(ctx context.Context, tokens []ccipocr3.UnknownEncodedAddress, tokenInfo map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo) (ccipocr3.TokenPriceMap, error) { + // Return static test prices + result := make(ccipocr3.TokenPriceMap) + for i, token := range tokens { + // Generate different prices for different tokens + price := big.NewInt(1000000 + int64(i)*100000) // $1.00, $1.10, $1.20, etc. in wei units + result[token] = ccipocr3.NewBigInt(price) + } + return result, nil +} + +func (s staticChainAccessor) GetFeeQuoterTokenUpdates(ctx context.Context, tokens []ccipocr3.UnknownEncodedAddress, chain ccipocr3.ChainSelector) (map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig, error) { + // Return static test token updates + result := make(map[ccipocr3.UnknownEncodedAddress]ccipocr3.TimestampedUnixBig) + testTime := time.Date(2024, 1, 15, 12, 0, 0, 0, time.UTC) + + for i, token := range tokens { + // Generate different prices for different tokens + price := big.NewInt(2000000 + int64(i)*50000) // Different prices from GetFeedPricesUSD + result[token] = ccipocr3.TimestampedUnixBig{ + Timestamp: uint32(testTime.Add(time.Duration(i) * time.Minute).Unix()), // Different timestamps + Value: price, + } + } + return result, nil +} + // Evaluate implements ChainAccessorEvaluator. func (s staticChainAccessor) Evaluate(ctx context.Context, other ccipocr3.ChainAccessor) error { // Delegate to individual evaluation functions for better readability @@ -400,6 +439,9 @@ func (s staticChainAccessor) Evaluate(ctx context.Context, other ccipocr3.ChainA s.evaluateGetExpectedNextSequenceNumber, s.evaluateGetTokenPriceUSD, s.evaluateGetFeeQuoterDestChainConfig, + s.evaluateMessagesByTokenID, + s.evaluateGetFeedPricesUSD, + s.evaluateGetFeeQuoterTokenUpdates, } for _, evaluate := range evaluators { @@ -732,8 +774,14 @@ func (s staticChainAccessor) evaluateNonces(ctx context.Context, other ccipocr3. func (s staticChainAccessor) evaluateGetChainFeePriceUpdate(ctx context.Context, other ccipocr3.ChainAccessor) error { chains := []ccipocr3.ChainSelector{1, 2} - otherUpdates := other.GetChainFeePriceUpdate(ctx, chains) - myUpdates := s.GetChainFeePriceUpdate(ctx, chains) + otherUpdates, err := other.GetChainFeePriceUpdate(ctx, chains) + if err != nil { + return fmt.Errorf("GetChainFeePriceUpdate failed: %w", err) + } + myUpdates, err := s.GetChainFeePriceUpdate(ctx, chains) + if err != nil { + return fmt.Errorf("GetChainFeePriceUpdate failed: %w", err) + } if len(otherUpdates) != len(myUpdates) { return fmt.Errorf("GetChainFeePriceUpdate length mismatch: got %d, expected %d", len(otherUpdates), len(myUpdates)) } @@ -742,13 +790,13 @@ func (s staticChainAccessor) evaluateGetChainFeePriceUpdate(ctx context.Context, if !exists { return fmt.Errorf("GetChainFeePriceUpdate missing chain %d in other updates", chainSel) } - if otherUpdate.Value.Cmp(myUpdate.Value.Int) != 0 { + if otherUpdate.Value.Cmp(myUpdate.Value) != 0 { return fmt.Errorf("GetChainFeePriceUpdate chain %d Value mismatch: got %s, expected %s", chainSel, otherUpdate.Value.String(), myUpdate.Value.String()) } - if !otherUpdate.Timestamp.Equal(myUpdate.Timestamp) { - return fmt.Errorf("GetChainFeePriceUpdate chain %d Timestamp mismatch: got %s, expected %s", - chainSel, otherUpdate.Timestamp.Format(time.RFC3339), myUpdate.Timestamp.Format(time.RFC3339)) + if otherUpdate.Timestamp != myUpdate.Timestamp { + return fmt.Errorf("GetChainFeePriceUpdate chain %d Timestamp mismatch: got %d, expected %d", + chainSel, otherUpdate.Timestamp, myUpdate.Timestamp) } } return nil @@ -904,6 +952,108 @@ func (s staticChainAccessor) evaluateGetFeeQuoterDestChainConfig(ctx context.Con return nil } +func (s staticChainAccessor) evaluateMessagesByTokenID(ctx context.Context, other ccipocr3.ChainAccessor) error { + tokens := map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount{ + ccipocr3.NewMessageTokenID(1, 0): { + SourcePoolAddress: ccipocr3.UnknownAddress("test-source-pool"), + DestTokenAddress: ccipocr3.UnknownAddress("test-dest-token"), + ExtraData: ccipocr3.Bytes("test-extra-data"), + Amount: ccipocr3.NewBigInt(big.NewInt(12345)), + }, + } + + otherMessages, err := other.MessagesByTokenID(ctx, ccipocr3.ChainSelector(1), ccipocr3.ChainSelector(2), tokens) + if err != nil { + return fmt.Errorf("MessagesByTokenID failed: %w", err) + } + myMessages, err := s.MessagesByTokenID(ctx, ccipocr3.ChainSelector(1), ccipocr3.ChainSelector(2), tokens) + if err != nil { + return fmt.Errorf("MessagesByTokenID failed: %w", err) + } + + if len(otherMessages) != len(myMessages) { + return fmt.Errorf("MessagesByTokenID length mismatch: got %d, expected %d", len(otherMessages), len(myMessages)) + } + + for tokenID, myMessage := range myMessages { + otherMessage, exists := otherMessages[tokenID] + if !exists { + return fmt.Errorf("MessagesByTokenID missing tokenID %s in other messages", tokenID.String()) + } + if string(otherMessage) != string(myMessage) { + return fmt.Errorf("MessagesByTokenID tokenID %s mismatch: got %s, expected %s", tokenID.String(), string(otherMessage), string(myMessage)) + } + } + return nil +} + +func (s staticChainAccessor) evaluateGetFeedPricesUSD(ctx context.Context, other ccipocr3.ChainAccessor) error { + tokens := []ccipocr3.UnknownEncodedAddress{"token1", "token2", "token3"} + tokenInfo := map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo{ + "token1": { + AggregatorAddress: ccipocr3.UnknownEncodedAddress("0x1234567890123456789012345678901234567890"), + DeviationPPB: ccipocr3.NewBigInt(big.NewInt(1000000000)), // 1% + Decimals: 18, + }, + } + + otherPrices, err := other.GetFeedPricesUSD(ctx, tokens, tokenInfo) + if err != nil { + return fmt.Errorf("GetFeedPricesUSD failed: %w", err) + } + myPrices, err := s.GetFeedPricesUSD(ctx, tokens, tokenInfo) + if err != nil { + return fmt.Errorf("GetFeedPricesUSD failed: %w", err) + } + + if len(otherPrices) != len(myPrices) { + return fmt.Errorf("GetFeedPricesUSD length mismatch: got %d, expected %d", len(otherPrices), len(myPrices)) + } + + for token, myPrice := range myPrices { + otherPrice, exists := otherPrices[token] + if !exists { + return fmt.Errorf("GetFeedPricesUSD missing token %s in other prices", string(token)) + } + if otherPrice.Cmp(myPrice.Int) != 0 { + return fmt.Errorf("GetFeedPricesUSD token %s mismatch: got %s, expected %s", string(token), otherPrice.String(), myPrice.String()) + } + } + return nil +} + +func (s staticChainAccessor) evaluateGetFeeQuoterTokenUpdates(ctx context.Context, other ccipocr3.ChainAccessor) error { + tokens := []ccipocr3.UnknownEncodedAddress{"token1", "token2"} + chain := ccipocr3.ChainSelector(1) + + otherUpdates, err := other.GetFeeQuoterTokenUpdates(ctx, tokens, chain) + if err != nil { + return fmt.Errorf("GetFeeQuoterTokenUpdates failed: %w", err) + } + myUpdates, err := s.GetFeeQuoterTokenUpdates(ctx, tokens, chain) + if err != nil { + return fmt.Errorf("GetFeeQuoterTokenUpdates failed: %w", err) + } + + if len(otherUpdates) != len(myUpdates) { + return fmt.Errorf("GetFeeQuoterTokenUpdates length mismatch: got %d, expected %d", len(otherUpdates), len(myUpdates)) + } + + for token, myUpdate := range myUpdates { + otherUpdate, exists := otherUpdates[token] + if !exists { + return fmt.Errorf("GetFeeQuoterTokenUpdates missing token %s in other updates", string(token)) + } + if otherUpdate.Value.Cmp(myUpdate.Value) != 0 { + return fmt.Errorf("GetFeeQuoterTokenUpdates token %s value mismatch: got %s, expected %s", string(token), otherUpdate.Value.String(), myUpdate.Value.String()) + } + if otherUpdate.Timestamp != myUpdate.Timestamp { + return fmt.Errorf("GetFeeQuoterTokenUpdates token %s timestamp mismatch: got %d, expected %d", string(token), otherUpdate.Timestamp, myUpdate.Timestamp) + } + } + return nil +} + // AssertEqual implements ChainAccessorTester. func (s staticChainAccessor) AssertEqual(ctx context.Context, t *testing.T, other ccipocr3.ChainAccessor) { t.Run("ChainAccessor", func(t *testing.T) { diff --git a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/test/chain_accessor_test.go b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/test/chain_accessor_test.go index e70be47f4..afe704a5c 100644 --- a/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/test/chain_accessor_test.go +++ b/pkg/loop/internal/relayer/pluginprovider/ext/ccipocr3/test/chain_accessor_test.go @@ -2,6 +2,7 @@ package test import ( "context" + "math/big" "testing" "time" @@ -73,14 +74,15 @@ func TestChainAccessor(t *testing.T) { }) t.Run("GetChainFeePriceUpdate", func(t *testing.T) { - updates := chainAccessor.GetChainFeePriceUpdate(ctx, []ccipocr3.ChainSelector{1, 2}) + updates, err := chainAccessor.GetChainFeePriceUpdate(ctx, []ccipocr3.ChainSelector{1, 2}) + assert.NoError(t, err) assert.NotNil(t, updates) }) t.Run("GetLatestPriceSeqNr", func(t *testing.T) { seqNr, err := chainAccessor.GetLatestPriceSeqNr(ctx) assert.NoError(t, err) - assert.Equal(t, uint64(42), seqNr) + assert.Equal(t, ccipocr3.SeqNum(42), seqNr) }) t.Run("MsgsBetweenSeqNums", func(t *testing.T) { @@ -112,6 +114,46 @@ func TestChainAccessor(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, config) }) + + // USDCMessageReader tests + t.Run("MessagesByTokenID", func(t *testing.T) { + tokens := map[ccipocr3.MessageTokenID]ccipocr3.RampTokenAmount{ + ccipocr3.NewMessageTokenID(1, 0): { + SourcePoolAddress: ccipocr3.UnknownAddress("test-source-pool"), + DestTokenAddress: ccipocr3.UnknownAddress("test-dest-token"), + ExtraData: ccipocr3.Bytes("test-extra-data"), + Amount: ccipocr3.NewBigInt(big.NewInt(12345)), + }, + } + messages, err := chainAccessor.MessagesByTokenID(ctx, ccipocr3.ChainSelector(1), ccipocr3.ChainSelector(2), tokens) + assert.NoError(t, err) + assert.NotNil(t, messages) + assert.Len(t, messages, 1) + }) + + // PriceReader tests + t.Run("GetFeedPricesUSD", func(t *testing.T) { + tokens := []ccipocr3.UnknownEncodedAddress{"token1", "token2", "token3"} + tokenInfo := map[ccipocr3.UnknownEncodedAddress]ccipocr3.TokenInfo{ + "token1": { + AggregatorAddress: ccipocr3.UnknownEncodedAddress("0x1234567890123456789012345678901234567890"), + DeviationPPB: ccipocr3.NewBigInt(big.NewInt(1000000000)), // 1% + Decimals: 18, + }, + } + prices, err := chainAccessor.GetFeedPricesUSD(ctx, tokens, tokenInfo) + assert.NoError(t, err) + assert.NotNil(t, prices) + assert.Len(t, prices, 3) + }) + + t.Run("GetFeeQuoterTokenUpdates", func(t *testing.T) { + tokens := []ccipocr3.UnknownEncodedAddress{"token1", "token2"} + updates, err := chainAccessor.GetFeeQuoterTokenUpdates(ctx, tokens, ccipocr3.ChainSelector(1)) + assert.NoError(t, err) + assert.NotNil(t, updates) + assert.Len(t, updates, 2) + }) } func TestChainAccessorEvaluate(t *testing.T) { diff --git a/pkg/loop/internal/relayer/relayer.go b/pkg/loop/internal/relayer/relayer.go index 3c4b7f092..a97a3e801 100644 --- a/pkg/loop/internal/relayer/relayer.go +++ b/pkg/loop/internal/relayer/relayer.go @@ -289,7 +289,9 @@ func (r *relayerClient) NewLLOProvider(ctx context.Context, rargs types.RelayArg } func (r *relayerClient) NewCCIPProvider(ctx context.Context, cargs types.CCIPProviderArgs) (types.CCIPProvider, error) { + var ccipProvider *ccipocr3.CCIPProviderClient cc := r.NewClientConn("CCIPProvider", func(ctx context.Context) (uint32, net.Resources, error) { + persistedSyncs := ccipProvider.GetSyncRequests() reply, err := r.relayer.NewCCIPProvider(ctx, &pb.NewCCIPProviderRequest{ CcipProviderArgs: &pb.CCIPProviderArgs{ ExternalJobID: cargs.ExternalJobID[:], @@ -297,6 +299,7 @@ func (r *relayerClient) NewCCIPProvider(ctx context.Context, cargs types.CCIPPro ChainWriterConfig: cargs.ChainWriterConfig, OffRampAddress: cargs.OffRampAddress, PluginType: cargs.PluginType, + SyncedAddresses: persistedSyncs, }, }) if err != nil { @@ -305,7 +308,8 @@ func (r *relayerClient) NewCCIPProvider(ctx context.Context, cargs types.CCIPPro return reply.CcipProviderID, nil, nil }) - return ccipocr3.NewCCIPProviderClient(r.WithName(cargs.ExternalJobID.String()).WithName("CCIPProviderClient"), cc), nil + ccipProvider = ccipocr3.NewCCIPProviderClient(r.WithName(cargs.ExternalJobID.String()).WithName("CCIPProviderClient"), cc) + return ccipProvider, nil } func (r *relayerClient) LatestHead(ctx context.Context) (types.Head, error) { @@ -735,6 +739,14 @@ func (r *relayerServer) NewCCIPProvider(ctx context.Context, request *pb.NewCCIP return nil, err } + // Sync persisted sync requests after provider has initted accessor + for contractName, addressBytes := range rargs.SyncedAddresses { + err = provider.ChainAccessor().Sync(ctx, contractName, addressBytes) + if err != nil { + return nil, err + } + } + const name = "CCIPProvider" id, _, err := r.ServeNew(name, func(s *grpc.Server) { ccipocr3.RegisterProviderServices(s, provider) diff --git a/pkg/types/ccipocr3/chainaccessor.go b/pkg/types/ccipocr3/chainaccessor.go index 64ae00811..764303929 100644 --- a/pkg/types/ccipocr3/chainaccessor.go +++ b/pkg/types/ccipocr3/chainaccessor.go @@ -3,7 +3,6 @@ package ccipocr3 import ( "context" "math/big" - "sort" "time" "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" @@ -26,6 +25,8 @@ type ChainAccessor interface { AllAccessors SourceAccessor DestinationAccessor + USDCMessageReader + PriceReader } // AllAccessors contains functionality that is available to all types of accessors. @@ -133,7 +134,7 @@ type DestinationAccessor interface { // Access Type: Method(GetChainFeePriceUpdate) // Contract: FeeQuoter // Confidence: Unconfirmed - GetChainFeePriceUpdate(ctx context.Context, selectors []ChainSelector) map[ChainSelector]TimestampedBig + GetChainFeePriceUpdate(ctx context.Context, selectors []ChainSelector) (map[ChainSelector]TimestampedUnixBig, error) // GetLatestPriceSeqNr returns the latest price sequence number for the destination chain. // Not to confuse with the sequence number of the messages. This is the OCR sequence number. @@ -141,7 +142,7 @@ type DestinationAccessor interface { // Access Type: Method(GetLatestPriceSequenceNumber) // Contract: OffRamp // Confidence: Unconfirmed - GetLatestPriceSeqNr(ctx context.Context) (uint64, error) + GetLatestPriceSeqNr(ctx context.Context) (SeqNum, error) } type SourceAccessor interface { @@ -193,132 +194,32 @@ type SourceAccessor interface { GetFeeQuoterDestChainConfig(ctx context.Context, dest ChainSelector) (FeeQuoterDestChainConfig, error) } -//////////////////////////////////////////////////////////////// -// TODO: Find a better location for the types below this line // -// For the purpose of designing these interfaces, the // -// location is not critical. // -//////////////////////////////////////////////////////////////// - -// Random types. These are defined here mainly to bring focus to types which should -// probably be removed or replaced. - -type TimestampedBig struct { - Timestamp time.Time `json:"timestamp"` - Value BigInt `json:"value"` -} - -// TimestampedUnixBig Maps to on-chain struct -// https://github.com/smartcontractkit/chainlink/blob/37f3132362ec90b0b1c12fb1b69b9c16c46b399d/contracts/src/v0.8/ccip/libraries/Internal.sol#L43-L47 -// -//nolint:lll //url -type TimestampedUnixBig struct { - // Value in uint224, can contain several packed fields - Value *big.Int `json:"value"` - // Timestamp in seconds since epoch of most recent update - Timestamp uint32 `json:"timestamp"` -} - -func NewTimestampedBig(value int64, timestamp time.Time) TimestampedBig { - return TimestampedBig{ - Value: BigInt{Int: big.NewInt(value)}, - Timestamp: timestamp, - } -} - -func TimeStampedBigFromUnix(input TimestampedUnixBig) TimestampedBig { - return TimestampedBig{ - Value: NewBigInt(input.Value), - Timestamp: time.Unix(int64(input.Timestamp), 0), - } -} - -type CommitPluginReportWithMeta struct { - Report CommitPluginReport `json:"report"` - Timestamp time.Time `json:"timestamp"` - BlockNum uint64 `json:"blockNum"` -} - -type CommitReportsByConfidenceLevel struct { - Finalized []CommitPluginReportWithMeta `json:"finalized"` - Unfinalized []CommitPluginReportWithMeta `json:"unfinalized"` -} - -// ContractAddresses is a map of contract names across all chain selectors and their address. -// Currently only one contract per chain per name is supported. -type ContractAddresses map[string]map[ChainSelector]UnknownAddress - -func (ca ContractAddresses) Append(contract string, chain ChainSelector, address []byte) ContractAddresses { - resp := ca - if resp == nil { - resp = make(ContractAddresses) - } - if resp[contract] == nil { - resp[contract] = make(map[ChainSelector]UnknownAddress) - } - resp[contract][chain] = address - return resp -} - -// CurseInfo contains cursing information that are fetched from the rmn remote contract. -type CurseInfo struct { - // CursedSourceChains contains the cursed source chains. - CursedSourceChains map[ChainSelector]bool - // CursedDestination indicates that the destination chain is cursed. - CursedDestination bool - // GlobalCurse indicates that all chains are cursed. - GlobalCurse bool -} - -func (ci CurseInfo) NonCursedSourceChains(inputChains []ChainSelector) []ChainSelector { - if ci.GlobalCurse { - return nil - } - - sourceChains := make([]ChainSelector, 0, len(inputChains)) - for _, ch := range inputChains { - if !ci.CursedSourceChains[ch] { - sourceChains = append(sourceChains, ch) - } - } - sort.Slice(sourceChains, func(i, j int) bool { return sourceChains[i] < sourceChains[j] }) - - return sourceChains +// USDCMessageReader retrieves each of the CCTPv1 MessageSent event created +// when a ccipSend is made with USDC token transfer. The events are created +// when the USDC Token pool calls the 3rd party MessageTransmitter contract. +type USDCMessageReader interface { + MessagesByTokenID(ctx context.Context, + source, dest ChainSelector, + tokens map[MessageTokenID]RampTokenAmount, + ) (map[MessageTokenID]Bytes, error) } -// GlobalCurseSubject Defined as a const in RMNRemote.sol -// Docs of RMNRemote: -// An active curse on this subject will cause isCursed() and isCursed(bytes16) to return true. Use this subject -// for issues affecting all of CCIP chains, or pertaining to the chain that this contract is deployed on, instead of -// using the local chain selector as a subject. -var GlobalCurseSubject = [16]byte{ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -} - -// RemoteConfig contains the configuration fetched from the RMNRemote contract. -type RemoteConfig struct { - ContractAddress UnknownAddress `json:"contractAddress"` - ConfigDigest Bytes32 `json:"configDigest"` - Signers []RemoteSignerInfo `json:"signers"` - // F defines the max number of faulty RMN nodes; F+1 signers are required to verify a report. - FSign uint64 `json:"fSign"` // previously: MinSigners - ConfigVersion uint32 `json:"configVersion"` - RmnReportVersion Bytes32 `json:"rmnReportVersion"` // e.g., keccak256("RMN_V1_6_ANY2EVM_REPORT") -} - -func (r RemoteConfig) IsEmpty() bool { - // NOTE: contract address will always be present, since the code auto populates it - return r.ConfigDigest == (Bytes32{}) && - len(r.Signers) == 0 && - r.FSign == 0 && - r.ConfigVersion == 0 && - r.RmnReportVersion == (Bytes32{}) -} +type PriceReader interface { + // GetFeedPricesUSD returns the prices of the provided tokens in USD normalized to e18. + // 1 USDC = 1.00 USD per full token, each full token is 1e6 units -> 1 * 1e18 * 1e18 / 1e6 = 1e30 + // 1 ETH = 2,000 USD per full token, each full token is 1e18 units -> 2000 * 1e18 * 1e18 / 1e18 = 2_000e18 + // 1 LINK = 5.00 USD per full token, each full token is 1e18 units -> 5 * 1e18 * 1e18 / 1e18 = 5e18 + // The order of the returned prices corresponds to the order of the provided tokens. + GetFeedPricesUSD( + ctx context.Context, + tokens []UnknownEncodedAddress, + tokenInfo map[UnknownEncodedAddress]TokenInfo, + ) (TokenPriceMap, error) -// RemoteSignerInfo contains information about a signer from the RMNRemote contract. -type RemoteSignerInfo struct { - // The signer's onchain address, used to verify report signature - OnchainPublicKey UnknownAddress `json:"onchainPublicKey"` - // The index of the node in the RMN config - NodeIndex uint64 `json:"nodeIndex"` + // GetFeeQuoterTokenUpdates returns the latest token prices from the FeeQuoter on the specified chain + GetFeeQuoterTokenUpdates( + ctx context.Context, + tokens []UnknownEncodedAddress, + chain ChainSelector, + ) (map[UnknownEncodedAddress]TimestampedUnixBig, error) } diff --git a/pkg/types/ccipocr3/generic_types.go b/pkg/types/ccipocr3/generic_types.go index 40518e3f4..6564abc4d 100644 --- a/pkg/types/ccipocr3/generic_types.go +++ b/pkg/types/ccipocr3/generic_types.go @@ -1,12 +1,16 @@ package ccipocr3 import ( + "encoding/hex" "encoding/json" + "errors" "fmt" "math" "math/big" "sort" "strconv" + "strings" + "time" ) type TokenPrice struct { @@ -37,6 +41,43 @@ func NewTokenPrice(tokenID UnknownEncodedAddress, price *big.Int) TokenPrice { } } +type TokenInfo struct { + // AggregatorAddress is the address of the price feed TOKEN/USD aggregator on the feed chain. + AggregatorAddress UnknownEncodedAddress `json:"aggregatorAddress"` + + // DeviationPPB is the deviation in parts per billion that the price feed is allowed to deviate + // from the last written price on-chain before we write a new price. + DeviationPPB BigInt `json:"deviationPPB"` + + // Decimals is the number of decimals for the token (NOT the feed). + Decimals uint8 `json:"decimals"` +} + +func (a TokenInfo) Validate() error { + if a.AggregatorAddress == "" { + return errors.New("aggregatorAddress not set") + } + + // aggregator must be an ethereum address + decoded, err := hex.DecodeString(strings.ToLower(strings.TrimPrefix(string(a.AggregatorAddress), "0x"))) + if err != nil { + return fmt.Errorf("aggregatorAddress must be a valid ethereum address (i.e hex encoded 20 bytes): %w", err) + } + if len(decoded) != 20 { + return fmt.Errorf("aggregatorAddress must be a valid ethereum address, got %d bytes expected 20", len(decoded)) + } + + if a.DeviationPPB.Int.Cmp(big.NewInt(0)) <= 0 { + return errors.New("deviationPPB not set or negative, must be positive") + } + + if a.Decimals == 0 { + return fmt.Errorf("tokenDecimals can't be zero") + } + + return nil +} + type GasPriceChain struct { ChainSel ChainSelector `json:"chainSel"` GasPrice BigInt `json:"gasPrice"` @@ -270,3 +311,65 @@ type RampTokenAmount struct { // or hashing it. See Internal._hash(Any2EVMRampMessage) for more details as an example. DestExecData Bytes `json:"destExecData"` } + +// MessageTokenID is a unique identifier for a message token data (per chain selector). It's a composite key of +// the message sequence number and the token index within the message. It's used to easier identify token data for +// messages without having to deal with nested maps. +type MessageTokenID struct { + SeqNr SeqNum + Index int +} + +func NewMessageTokenID(seqNr SeqNum, index int) MessageTokenID { + return MessageTokenID{SeqNr: seqNr, Index: index} +} + +func (mti MessageTokenID) String() string { + return fmt.Sprintf("%d_%d", mti.SeqNr, mti.Index) +} + +type TimestampedBig struct { + Timestamp time.Time `json:"timestamp"` + Value BigInt `json:"value"` +} + +// TimestampedUnixBig Maps to on-chain struct +// https://github.com/smartcontractkit/chainlink/blob/37f3132362ec90b0b1c12fb1b69b9c16c46b399d/contracts/src/v0.8/ccip/libraries/Internal.sol#L43-L47 +// +//nolint:lll //url +type TimestampedUnixBig struct { + // Value in uint224, can contain several packed fields + Value *big.Int `json:"value"` + // Timestamp in seconds since epoch of most recent update + Timestamp uint32 `json:"timestamp"` +} + +func NewTimestampedBig(value int64, timestamp time.Time) TimestampedBig { + return TimestampedBig{ + Value: BigInt{Int: big.NewInt(value)}, + Timestamp: timestamp, + } +} + +func TimeStampedBigFromUnix(input TimestampedUnixBig) TimestampedBig { + return TimestampedBig{ + Value: NewBigInt(input.Value), + Timestamp: time.Unix(int64(input.Timestamp), 0), + } +} + +// ContractAddresses is a map of contract names across all chain selectors and their address. +// Currently only one contract per chain per name is supported. +type ContractAddresses map[string]map[ChainSelector]UnknownAddress + +func (ca ContractAddresses) Append(contract string, chain ChainSelector, address []byte) ContractAddresses { + resp := ca + if resp == nil { + resp = make(ContractAddresses) + } + if resp[contract] == nil { + resp[contract] = make(map[ChainSelector]UnknownAddress) + } + resp[contract][chain] = address + return resp +} diff --git a/pkg/types/ccipocr3/plugin_commit_types.go b/pkg/types/ccipocr3/plugin_commit_types.go index 3557fdbe3..2f68b69ad 100644 --- a/pkg/types/ccipocr3/plugin_commit_types.go +++ b/pkg/types/ccipocr3/plugin_commit_types.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "time" ) // CommitPluginReport contains the necessary information to commit CCIP @@ -105,3 +106,14 @@ func DecodeCommitReportInfo(data []byte) (CommitReportInfo, error) { return CommitReportInfo{}, fmt.Errorf("unknown execute report info version (%d)", data[0]) } } + +type CommitPluginReportWithMeta struct { + Report CommitPluginReport `json:"report"` + Timestamp time.Time `json:"timestamp"` + BlockNum uint64 `json:"blockNum"` +} + +type CommitReportsByConfidenceLevel struct { + Finalized []CommitPluginReportWithMeta `json:"finalized"` + Unfinalized []CommitPluginReportWithMeta `json:"unfinalized"` +} diff --git a/pkg/types/ccipocr3/rmn_types.go b/pkg/types/ccipocr3/rmn_types.go index 8104d76ef..01101999a 100644 --- a/pkg/types/ccipocr3/rmn_types.go +++ b/pkg/types/ccipocr3/rmn_types.go @@ -1,5 +1,9 @@ package ccipocr3 +import ( + "slices" +) + // RMNReport is the payload that is signed by the RMN nodes, transmitted and verified onchain. type RMNReport struct { ReportVersionDigest Bytes32 // e.g. keccak256("RMN_V1_6_ANY2EVM_REPORT") @@ -48,3 +52,64 @@ type RMNECDSASignature struct { R Bytes32 `json:"r"` S Bytes32 `json:"s"` } + +// CurseInfo contains cursing information that are fetched from the rmn remote contract. +type CurseInfo struct { + // CursedSourceChains contains the cursed source chains. + CursedSourceChains map[ChainSelector]bool + // CursedDestination indicates that the destination chain is cursed. + CursedDestination bool + // GlobalCurse indicates that all chains are cursed. + GlobalCurse bool +} + +func (ci CurseInfo) NonCursedSourceChains(inputChains []ChainSelector) []ChainSelector { + if ci.GlobalCurse { + return nil + } + + sourceChains := make([]ChainSelector, 0, len(inputChains)) + for _, ch := range inputChains { + if !ci.CursedSourceChains[ch] { + sourceChains = append(sourceChains, ch) + } + } + slices.Sort(sourceChains) + + return sourceChains +} + +// GlobalCurseSubject Defined as a const in RMNRemote.sol +// Docs of RMNRemote: +// An active curse on this subject will cause isCursed() and isCursed(bytes16) to return true. Use this subject +// for issues affecting all of CCIP chains, or pertaining to the chain that this contract is deployed on, instead of +// using the local chain selector as a subject. +var GlobalCurseSubject = [16]byte{0: 0x01, 15: 0x01} + +// RemoteConfig contains the configuration fetched from the RMNRemote contract. +type RemoteConfig struct { + ContractAddress UnknownAddress `json:"contractAddress"` + ConfigDigest Bytes32 `json:"configDigest"` + Signers []RemoteSignerInfo `json:"signers"` + // F defines the max number of faulty RMN nodes; F+1 signers are required to verify a report. + FSign uint64 `json:"fSign"` // previously: MinSigners + ConfigVersion uint32 `json:"configVersion"` + RmnReportVersion Bytes32 `json:"rmnReportVersion"` // e.g., keccak256("RMN_V1_6_ANY2EVM_REPORT") +} + +func (r RemoteConfig) IsEmpty() bool { + // NOTE: contract address will always be present, since the code auto populates it + return r.ConfigDigest == (Bytes32{}) && + len(r.Signers) == 0 && + r.FSign == 0 && + r.ConfigVersion == 0 && + r.RmnReportVersion == (Bytes32{}) +} + +// RemoteSignerInfo contains information about a signer from the RMNRemote contract. +type RemoteSignerInfo struct { + // The signer's onchain address, used to verify report signature + OnchainPublicKey UnknownAddress `json:"onchainPublicKey"` + // The index of the node in the RMN config + NodeIndex uint64 `json:"nodeIndex"` +} diff --git a/pkg/types/provider_ccip.go b/pkg/types/provider_ccip.go index acf128ca7..461fbbe4c 100644 --- a/pkg/types/provider_ccip.go +++ b/pkg/types/provider_ccip.go @@ -4,10 +4,11 @@ import ( "context" "github.com/google/uuid" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types/ccip" "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ) type CCIPCommitProvider interface {