From 4cab41bdefed9c1ebbc7ec5c86b0cdf9349e8ed4 Mon Sep 17 00:00:00 2001 From: Krish-vemula Date: Tue, 8 Sep 2026 22:26:48 -0700 Subject: [PATCH 1/3] Add Stellar get transaction status fields --- pkg/chains/stellar/proto_helpers.go | 118 +++++++- pkg/chains/stellar/proto_helpers_test.go | 109 ++++++- pkg/chains/stellar/stellar.pb.go | 284 ++++++++++++------ pkg/chains/stellar/stellar.proto | 21 +- pkg/loop/internal/relayer/stellar.go | 6 +- pkg/loop/internal/relayer/stellar_test.go | 20 +- .../internal/relayerset/relayerset_test.go | 12 +- pkg/loop/internal/relayerset/stellar.go | 6 +- pkg/types/chains/stellar/stellar.go | 27 +- 9 files changed, 481 insertions(+), 122 deletions(-) diff --git a/pkg/chains/stellar/proto_helpers.go b/pkg/chains/stellar/proto_helpers.go index b794d27024..797347b50b 100644 --- a/pkg/chains/stellar/proto_helpers.go +++ b/pkg/chains/stellar/proto_helpers.go @@ -781,23 +781,103 @@ func ConvertGetTransactionRequestFromProto(p *GetTransactionRequest) (stellar.Ge return stellar.GetTransactionRequest{TxHash: p.GetTxHash()}, nil } -func ConvertGetTransactionResponseToProto(resp stellar.GetTransactionResponse) *GetTransactionResponse { +func ConvertGetTransactionResponseToProto(resp stellar.GetTransactionResponse) (*GetTransactionResponse, error) { + status, err := convertGetTransactionStatusToProto(resp.Status) + if err != nil { + return nil, fmt.Errorf("status: %w", err) + } + if err := validateGetTransactionResponse(resp); err != nil { + return nil, err + } + + var resultXDR, resultMetaXDR []byte + if resp.ResultXDR != "" { + resultXDR, err = base64.StdEncoding.DecodeString(resp.ResultXDR) + if err != nil { + return nil, fmt.Errorf("invalid result xdr %q: %w", resp.ResultXDR, err) + } + } + if resp.ResultMetaXDR != "" { + resultMetaXDR, err = base64.StdEncoding.DecodeString(resp.ResultMetaXDR) + if err != nil { + return nil, fmt.Errorf("invalid result meta xdr %q: %w", resp.ResultMetaXDR, err) + } + } + return &GetTransactionResponse{ + Status: status, + TxHash: resp.TxHash, + ResultXdr: resultXDR, + ResultMetaXdr: resultMetaXDR, FeeStroops: resp.FeeStroops, LedgerSequence: resp.LedgerSequence, LedgerCloseTime: resp.LedgerCloseTime, + }, nil +} + +func validateGetTransactionResponse(resp stellar.GetTransactionResponse) error { + if resp.TxHash == "" { + return errors.New("txHash is required") + } + + switch resp.Status { + case stellar.GetTransactionStatusNotFound: + switch { + case resp.FeeStroops != nil: + return errors.New("feeStroops must be unset when transaction is not found") + case resp.LedgerSequence != nil: + return errors.New("ledgerSequence must be unset when transaction is not found") + case resp.LedgerCloseTime != nil: + return errors.New("ledgerCloseTime must be unset when transaction is not found") + case resp.ResultXDR != "": + return errors.New("resultXDR must be empty when transaction is not found") + case resp.ResultMetaXDR != "": + return errors.New("resultMetaXDR must be empty when transaction is not found") + } + case stellar.GetTransactionStatusFailed, stellar.GetTransactionStatusSuccess: + switch { + case resp.LedgerSequence == nil: + return errors.New("ledgerSequence is required") + case resp.LedgerCloseTime == nil: + return errors.New("ledgerCloseTime is required") + case resp.ResultXDR == "": + return errors.New("resultXDR is required") + } } + return nil } func ConvertGetTransactionResponseFromProto(p *GetTransactionResponse) (stellar.GetTransactionResponse, error) { if p == nil { return stellar.GetTransactionResponse{}, errors.New("get transaction response is nil") } - return stellar.GetTransactionResponse{ - FeeStroops: p.GetFeeStroops(), - LedgerSequence: p.GetLedgerSequence(), - LedgerCloseTime: p.GetLedgerCloseTime(), - }, nil + status, err := convertGetTransactionStatusFromProto(p.GetStatus()) + if err != nil { + return stellar.GetTransactionResponse{}, fmt.Errorf("status: %w", err) + } + + resp := stellar.GetTransactionResponse{ + Status: status, + TxHash: p.GetTxHash(), + ResultXDR: base64.StdEncoding.EncodeToString(p.GetResultXdr()), + ResultMetaXDR: base64.StdEncoding.EncodeToString(p.GetResultMetaXdr()), + } + if p.FeeStroops != nil { + fee := p.GetFeeStroops() + resp.FeeStroops = &fee + } + if p.LedgerSequence != nil { + ledger := p.GetLedgerSequence() + resp.LedgerSequence = &ledger + } + if p.LedgerCloseTime != nil { + closeTime := p.GetLedgerCloseTime() + resp.LedgerCloseTime = &closeTime + } + if err := validateGetTransactionResponse(resp); err != nil { + return stellar.GetTransactionResponse{}, err + } + return resp, nil } func ConvertGetSigningAccountResponseToProto(resp stellar.GetSigningAccountResponse) *GetSigningAccountResponse { @@ -923,6 +1003,32 @@ func convertTxStatusFromProto(s TxStatus) (stellar.TransactionStatus, error) { } } +func convertGetTransactionStatusToProto(s stellar.GetTransactionStatus) (GetTransactionStatus, error) { + switch s { + case stellar.GetTransactionStatusNotFound: + return GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND, nil + case stellar.GetTransactionStatusFailed: + return GetTransactionStatus_GET_TRANSACTION_STATUS_FAILED, nil + case stellar.GetTransactionStatusSuccess: + return GetTransactionStatus_GET_TRANSACTION_STATUS_SUCCESS, nil + default: + return 0, fmt.Errorf("unsupported get transaction status: %d", s) + } +} + +func convertGetTransactionStatusFromProto(s GetTransactionStatus) (stellar.GetTransactionStatus, error) { + switch s { + case GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND: + return stellar.GetTransactionStatusNotFound, nil + case GetTransactionStatus_GET_TRANSACTION_STATUS_FAILED: + return stellar.GetTransactionStatusFailed, nil + case GetTransactionStatus_GET_TRANSACTION_STATUS_SUCCESS: + return stellar.GetTransactionStatusSuccess, nil + default: + return 0, fmt.Errorf("unsupported proto get transaction status: %d", s) + } +} + func scValsToProto(field string, vals []stellar.ScVal) ([]*scval.ScVal, error) { if len(vals) == 0 { return nil, nil diff --git a/pkg/chains/stellar/proto_helpers_test.go b/pkg/chains/stellar/proto_helpers_test.go index b35f3a0c11..38f235c108 100644 --- a/pkg/chains/stellar/proto_helpers_test.go +++ b/pkg/chains/stellar/proto_helpers_test.go @@ -1352,12 +1352,59 @@ func TestConvertGetTransactionRequestFromProto_EmptyTxHash(t *testing.T) { } func TestConvertGetTransactionResponse_RoundTrip(t *testing.T) { + fee := uint64(42) + ledger := uint32(100) + closeTime := int64(1_700_000_000) domain := stellartypes.GetTransactionResponse{ - FeeStroops: 42, - LedgerSequence: 100, - LedgerCloseTime: 1_700_000_000, + Status: stellartypes.GetTransactionStatusSuccess, + TxHash: "abc123hash", + ResultXDR: base64.StdEncoding.EncodeToString([]byte("result")), + ResultMetaXDR: base64.StdEncoding.EncodeToString([]byte("meta")), + FeeStroops: &fee, + LedgerSequence: &ledger, + LedgerCloseTime: &closeTime, } - proto := conv.ConvertGetTransactionResponseToProto(domain) + proto, err := conv.ConvertGetTransactionResponseToProto(domain) + require.NoError(t, err) + require.Equal(t, conv.GetTransactionStatus_GET_TRANSACTION_STATUS_SUCCESS, proto.GetStatus()) + + got, err := conv.ConvertGetTransactionResponseFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertGetTransactionResponse_RoundTrip_Failed(t *testing.T) { + ledger := uint32(100) + closeTime := int64(1_700_000_000) + domain := stellartypes.GetTransactionResponse{ + Status: stellartypes.GetTransactionStatusFailed, + TxHash: "abc123hash", + ResultXDR: base64.StdEncoding.EncodeToString([]byte("failed-result")), + LedgerSequence: &ledger, + LedgerCloseTime: &closeTime, + } + proto, err := conv.ConvertGetTransactionResponseToProto(domain) + require.NoError(t, err) + require.Equal(t, conv.GetTransactionStatus_GET_TRANSACTION_STATUS_FAILED, proto.GetStatus()) + require.Nil(t, proto.FeeStroops) + + got, err := conv.ConvertGetTransactionResponseFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertGetTransactionResponse_RoundTrip_NotFound(t *testing.T) { + domain := stellartypes.GetTransactionResponse{ + Status: stellartypes.GetTransactionStatusNotFound, + TxHash: "abc123hash", + } + proto, err := conv.ConvertGetTransactionResponseToProto(domain) + require.NoError(t, err) + require.Equal(t, conv.GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND, proto.GetStatus()) + require.Nil(t, proto.FeeStroops) + require.Nil(t, proto.LedgerSequence) + require.Nil(t, proto.LedgerCloseTime) + require.Empty(t, proto.GetResultXdr()) got, err := conv.ConvertGetTransactionResponseFromProto(proto) require.NoError(t, err) @@ -1370,6 +1417,60 @@ func TestConvertGetTransactionResponseFromProto_Nil(t *testing.T) { require.Contains(t, err.Error(), "nil") } +func TestConvertGetTransactionResponseToProto_UnsupportedStatus(t *testing.T) { + _, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{ + Status: stellartypes.GetTransactionStatus(99), + TxHash: "abc123hash", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "status") + require.Contains(t, err.Error(), "unsupported get transaction status") +} + +func TestConvertGetTransactionResponseFromProto_UnsupportedStatus(t *testing.T) { + _, err := conv.ConvertGetTransactionResponseFromProto(&conv.GetTransactionResponse{ + Status: conv.GetTransactionStatus(99), + TxHash: "abc123hash", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "status") + require.Contains(t, err.Error(), "unsupported proto get transaction status") +} + +func TestConvertGetTransactionResponseToProto_SuccessMissingFields(t *testing.T) { + _, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{ + Status: stellartypes.GetTransactionStatusSuccess, + TxHash: "abc123hash", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "ledgerSequence is required") +} + +func TestConvertGetTransactionResponseFromProto_NotFoundWithFoundFields(t *testing.T) { + ledger := uint32(100) + _, err := conv.ConvertGetTransactionResponseFromProto(&conv.GetTransactionResponse{ + Status: conv.GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND, + TxHash: "abc123hash", + LedgerSequence: &ledger, + }) + require.Error(t, err) + require.Contains(t, err.Error(), "ledgerSequence must be unset") +} + +func TestConvertGetTransactionResponseToProto_InvalidResultXDR(t *testing.T) { + ledger := uint32(100) + closeTime := int64(1_700_000_000) + _, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{ + Status: stellartypes.GetTransactionStatusSuccess, + TxHash: "abc123hash", + ResultXDR: "!!!invalid!!!", + LedgerSequence: &ledger, + LedgerCloseTime: &closeTime, + }) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid result xdr") +} + func TestConvertGetSigningAccountResponse_RoundTrip(t *testing.T) { domain := stellartypes.GetSigningAccountResponse{AccountAddress: "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7"} proto := conv.ConvertGetSigningAccountResponseToProto(domain) diff --git a/pkg/chains/stellar/stellar.pb.go b/pkg/chains/stellar/stellar.pb.go index c39a8eb3dc..a840e938f3 100644 --- a/pkg/chains/stellar/stellar.pb.go +++ b/pkg/chains/stellar/stellar.pb.go @@ -23,6 +23,58 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type GetTransactionStatus int32 + +const ( + GetTransactionStatus_GET_TRANSACTION_STATUS_UNSPECIFIED GetTransactionStatus = 0 + GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND GetTransactionStatus = 1 + GetTransactionStatus_GET_TRANSACTION_STATUS_FAILED GetTransactionStatus = 2 + GetTransactionStatus_GET_TRANSACTION_STATUS_SUCCESS GetTransactionStatus = 3 +) + +// Enum value maps for GetTransactionStatus. +var ( + GetTransactionStatus_name = map[int32]string{ + 0: "GET_TRANSACTION_STATUS_UNSPECIFIED", + 1: "GET_TRANSACTION_STATUS_NOT_FOUND", + 2: "GET_TRANSACTION_STATUS_FAILED", + 3: "GET_TRANSACTION_STATUS_SUCCESS", + } + GetTransactionStatus_value = map[string]int32{ + "GET_TRANSACTION_STATUS_UNSPECIFIED": 0, + "GET_TRANSACTION_STATUS_NOT_FOUND": 1, + "GET_TRANSACTION_STATUS_FAILED": 2, + "GET_TRANSACTION_STATUS_SUCCESS": 3, + } +) + +func (x GetTransactionStatus) Enum() *GetTransactionStatus { + p := new(GetTransactionStatus) + *p = x + return p +} + +func (x GetTransactionStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GetTransactionStatus) Descriptor() protoreflect.EnumDescriptor { + return file_stellar_proto_enumTypes[0].Descriptor() +} + +func (GetTransactionStatus) Type() protoreflect.EnumType { + return &file_stellar_proto_enumTypes[0] +} + +func (x GetTransactionStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GetTransactionStatus.Descriptor instead. +func (GetTransactionStatus) EnumDescriptor() ([]byte, []int) { + return file_stellar_proto_rawDescGZIP(), []int{0} +} + type EventType int32 const ( @@ -53,11 +105,11 @@ func (x EventType) String() string { } func (EventType) Descriptor() protoreflect.EnumDescriptor { - return file_stellar_proto_enumTypes[0].Descriptor() + return file_stellar_proto_enumTypes[1].Descriptor() } func (EventType) Type() protoreflect.EnumType { - return &file_stellar_proto_enumTypes[0] + return &file_stellar_proto_enumTypes[1] } func (x EventType) Number() protoreflect.EnumNumber { @@ -66,7 +118,7 @@ func (x EventType) Number() protoreflect.EnumNumber { // Deprecated: Use EventType.Descriptor instead. func (EventType) EnumDescriptor() ([]byte, []int) { - return file_stellar_proto_rawDescGZIP(), []int{0} + return file_stellar_proto_rawDescGZIP(), []int{1} } type TxStatus int32 @@ -102,11 +154,11 @@ func (x TxStatus) String() string { } func (TxStatus) Descriptor() protoreflect.EnumDescriptor { - return file_stellar_proto_enumTypes[1].Descriptor() + return file_stellar_proto_enumTypes[2].Descriptor() } func (TxStatus) Type() protoreflect.EnumType { - return &file_stellar_proto_enumTypes[1] + return &file_stellar_proto_enumTypes[2] } func (x TxStatus) Number() protoreflect.EnumNumber { @@ -115,7 +167,7 @@ func (x TxStatus) Number() protoreflect.EnumNumber { // Deprecated: Use TxStatus.Descriptor instead. func (TxStatus) EnumDescriptor() ([]byte, []int) { - return file_stellar_proto_rawDescGZIP(), []int{1} + return file_stellar_proto_rawDescGZIP(), []int{2} } // SimulateTransactionRequest builds a synthetic single-operation Soroban @@ -939,12 +991,16 @@ func (x *GetTransactionRequest) GetTxHash() string { return "" } -// GetTransactionResponse carries fee and ledger metadata for a confirmed transaction. +// GetTransactionResponse carries the result of looking up a transaction by hash. type GetTransactionResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - FeeStroops uint64 `protobuf:"varint,1,opt,name=fee_stroops,json=feeStroops,proto3" json:"fee_stroops,omitempty"` - LedgerSequence uint32 `protobuf:"varint,2,opt,name=ledger_sequence,json=ledgerSequence,proto3" json:"ledger_sequence,omitempty"` - LedgerCloseTime int64 `protobuf:"varint,3,opt,name=ledger_close_time,json=ledgerCloseTime,proto3" json:"ledger_close_time,omitempty"` + FeeStroops *uint64 `protobuf:"varint,1,opt,name=fee_stroops,json=feeStroops,proto3,oneof" json:"fee_stroops,omitempty"` + LedgerSequence *uint32 `protobuf:"varint,2,opt,name=ledger_sequence,json=ledgerSequence,proto3,oneof" json:"ledger_sequence,omitempty"` + LedgerCloseTime *int64 `protobuf:"varint,3,opt,name=ledger_close_time,json=ledgerCloseTime,proto3,oneof" json:"ledger_close_time,omitempty"` + Status GetTransactionStatus `protobuf:"varint,4,opt,name=status,proto3,enum=loop.stellar.GetTransactionStatus" json:"status,omitempty"` + TxHash string `protobuf:"bytes,5,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` + ResultXdr []byte `protobuf:"bytes,6,opt,name=result_xdr,json=resultXdr,proto3" json:"result_xdr,omitempty"` + ResultMetaXdr []byte `protobuf:"bytes,7,opt,name=result_meta_xdr,json=resultMetaXdr,proto3" json:"result_meta_xdr,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -980,26 +1036,54 @@ func (*GetTransactionResponse) Descriptor() ([]byte, []int) { } func (x *GetTransactionResponse) GetFeeStroops() uint64 { - if x != nil { - return x.FeeStroops + if x != nil && x.FeeStroops != nil { + return *x.FeeStroops } return 0 } func (x *GetTransactionResponse) GetLedgerSequence() uint32 { - if x != nil { - return x.LedgerSequence + if x != nil && x.LedgerSequence != nil { + return *x.LedgerSequence } return 0 } func (x *GetTransactionResponse) GetLedgerCloseTime() int64 { - if x != nil { - return x.LedgerCloseTime + if x != nil && x.LedgerCloseTime != nil { + return *x.LedgerCloseTime } return 0 } +func (x *GetTransactionResponse) GetStatus() GetTransactionStatus { + if x != nil { + return x.Status + } + return GetTransactionStatus_GET_TRANSACTION_STATUS_UNSPECIFIED +} + +func (x *GetTransactionResponse) GetTxHash() string { + if x != nil { + return x.TxHash + } + return "" +} + +func (x *GetTransactionResponse) GetResultXdr() []byte { + if x != nil { + return x.ResultXdr + } + return nil +} + +func (x *GetTransactionResponse) GetResultMetaXdr() []byte { + if x != nil { + return x.ResultMetaXdr + } + return nil +} + // GetSigningAccountResponse is the relayer default TXM signing account. // Exposed so callers can encode contract arguments (e.g. forwarder report's // transmitter parameter) that require require_auth, without hard-coding config. @@ -1909,12 +1993,20 @@ const file_stellar_proto_rawDesc = "" + "\x18latest_ledger_close_time\x18\x05 \x01(\x03R\x15latestLedgerCloseTime\x127\n" + "\x18oldest_ledger_close_time\x18\x06 \x01(\x03R\x15oldestLedgerCloseTime\"0\n" + "\x15GetTransactionRequest\x12\x17\n" + - "\atx_hash\x18\x01 \x01(\tR\x06txHash\"\x8e\x01\n" + - "\x16GetTransactionResponse\x12\x1f\n" + - "\vfee_stroops\x18\x01 \x01(\x04R\n" + - "feeStroops\x12'\n" + - "\x0fledger_sequence\x18\x02 \x01(\rR\x0eledgerSequence\x12*\n" + - "\x11ledger_close_time\x18\x03 \x01(\x03R\x0fledgerCloseTime\"D\n" + + "\atx_hash\x18\x01 \x01(\tR\x06txHash\"\xf3\x02\n" + + "\x16GetTransactionResponse\x12$\n" + + "\vfee_stroops\x18\x01 \x01(\x04H\x00R\n" + + "feeStroops\x88\x01\x01\x12,\n" + + "\x0fledger_sequence\x18\x02 \x01(\rH\x01R\x0eledgerSequence\x88\x01\x01\x12/\n" + + "\x11ledger_close_time\x18\x03 \x01(\x03H\x02R\x0fledgerCloseTime\x88\x01\x01\x12:\n" + + "\x06status\x18\x04 \x01(\x0e2\".loop.stellar.GetTransactionStatusR\x06status\x12\x17\n" + + "\atx_hash\x18\x05 \x01(\tR\x06txHash\x12\x1d\n" + + "\n" + + "result_xdr\x18\x06 \x01(\fR\tresultXdr\x12&\n" + + "\x0fresult_meta_xdr\x18\a \x01(\fR\rresultMetaXdrB\x0e\n" + + "\f_fee_stroopsB\x12\n" + + "\x10_ledger_sequenceB\x14\n" + + "\x12_ledger_close_time\"D\n" + "\x19GetSigningAccountResponse\x12'\n" + "\x0faccount_address\x18\x01 \x01(\tR\x0eaccountAddress\"A\n" + "\x11PaginationOptions\x12\x16\n" + @@ -1980,7 +2072,12 @@ const file_stellar_proto_rawDesc = "" + "\x18latest_ledger_close_time\x18\x03 \x01(\x03R\x15latestLedgerCloseTime\x12#\n" + "\roldest_ledger\x18\x04 \x01(\rR\foldestLedger\x127\n" + "\x18oldest_ledger_close_time\x18\x05 \x01(\x03R\x15oldestLedgerCloseTime\x12\x16\n" + - "\x06cursor\x18\x06 \x01(\tR\x06cursor*;\n" + + "\x06cursor\x18\x06 \x01(\tR\x06cursor*\xab\x01\n" + + "\x14GetTransactionStatus\x12&\n" + + "\"GET_TRANSACTION_STATUS_UNSPECIFIED\x10\x00\x12$\n" + + " GET_TRANSACTION_STATUS_NOT_FOUND\x10\x01\x12!\n" + + "\x1dGET_TRANSACTION_STATUS_FAILED\x10\x02\x12\"\n" + + "\x1eGET_TRANSACTION_STATUS_SUCCESS\x10\x03*;\n" + "\tEventType\x12\x15\n" + "\x11EVENT_TYPE_SYSTEM\x10\x00\x12\x17\n" + "\x13EVENT_TYPE_CONTRACT\x10\x01*L\n" + @@ -2011,78 +2108,80 @@ func file_stellar_proto_rawDescGZIP() []byte { return file_stellar_proto_rawDescData } -var file_stellar_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_stellar_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_stellar_proto_msgTypes = make([]protoimpl.MessageInfo, 24) var file_stellar_proto_goTypes = []any{ - (EventType)(0), // 0: loop.stellar.EventType - (TxStatus)(0), // 1: loop.stellar.TxStatus - (*SimulateTransactionRequest)(nil), // 2: loop.stellar.SimulateTransactionRequest - (*SimulateResourceConfig)(nil), // 3: loop.stellar.SimulateResourceConfig - (*SimulateTransactionResponse)(nil), // 4: loop.stellar.SimulateTransactionResponse - (*SimulateRestorePreamble)(nil), // 5: loop.stellar.SimulateRestorePreamble - (*GetLedgerEntriesRequest)(nil), // 6: loop.stellar.GetLedgerEntriesRequest - (*GetLedgerEntriesResponse)(nil), // 7: loop.stellar.GetLedgerEntriesResponse - (*LedgerEntryResult)(nil), // 8: loop.stellar.LedgerEntryResult - (*GetEventsRequest)(nil), // 9: loop.stellar.GetEventsRequest - (*EventInfo)(nil), // 10: loop.stellar.EventInfo - (*GetEventsResponse)(nil), // 11: loop.stellar.GetEventsResponse - (*GetTransactionRequest)(nil), // 12: loop.stellar.GetTransactionRequest - (*GetTransactionResponse)(nil), // 13: loop.stellar.GetTransactionResponse - (*GetSigningAccountResponse)(nil), // 14: loop.stellar.GetSigningAccountResponse - (*PaginationOptions)(nil), // 15: loop.stellar.PaginationOptions - (*EventFilter)(nil), // 16: loop.stellar.EventFilter - (*TopicFilter)(nil), // 17: loop.stellar.TopicFilter - (*TopicSegment)(nil), // 18: loop.stellar.TopicSegment - (*SubmitTransactionRequest)(nil), // 19: loop.stellar.SubmitTransactionRequest - (*SubmitTransactionResponse)(nil), // 20: loop.stellar.SubmitTransactionResponse - (*GetLatestLedgerResponse)(nil), // 21: loop.stellar.GetLatestLedgerResponse - (*LedgerPaginationOptions)(nil), // 22: loop.stellar.LedgerPaginationOptions - (*GetLedgersRequest)(nil), // 23: loop.stellar.GetLedgersRequest - (*LedgerInfo)(nil), // 24: loop.stellar.LedgerInfo - (*GetLedgersResponse)(nil), // 25: loop.stellar.GetLedgersResponse - (*scval.ScVal)(nil), // 26: capabilities.blockchain.stellar.v1alpha.ScVal - (*emptypb.Empty)(nil), // 27: google.protobuf.Empty + (GetTransactionStatus)(0), // 0: loop.stellar.GetTransactionStatus + (EventType)(0), // 1: loop.stellar.EventType + (TxStatus)(0), // 2: loop.stellar.TxStatus + (*SimulateTransactionRequest)(nil), // 3: loop.stellar.SimulateTransactionRequest + (*SimulateResourceConfig)(nil), // 4: loop.stellar.SimulateResourceConfig + (*SimulateTransactionResponse)(nil), // 5: loop.stellar.SimulateTransactionResponse + (*SimulateRestorePreamble)(nil), // 6: loop.stellar.SimulateRestorePreamble + (*GetLedgerEntriesRequest)(nil), // 7: loop.stellar.GetLedgerEntriesRequest + (*GetLedgerEntriesResponse)(nil), // 8: loop.stellar.GetLedgerEntriesResponse + (*LedgerEntryResult)(nil), // 9: loop.stellar.LedgerEntryResult + (*GetEventsRequest)(nil), // 10: loop.stellar.GetEventsRequest + (*EventInfo)(nil), // 11: loop.stellar.EventInfo + (*GetEventsResponse)(nil), // 12: loop.stellar.GetEventsResponse + (*GetTransactionRequest)(nil), // 13: loop.stellar.GetTransactionRequest + (*GetTransactionResponse)(nil), // 14: loop.stellar.GetTransactionResponse + (*GetSigningAccountResponse)(nil), // 15: loop.stellar.GetSigningAccountResponse + (*PaginationOptions)(nil), // 16: loop.stellar.PaginationOptions + (*EventFilter)(nil), // 17: loop.stellar.EventFilter + (*TopicFilter)(nil), // 18: loop.stellar.TopicFilter + (*TopicSegment)(nil), // 19: loop.stellar.TopicSegment + (*SubmitTransactionRequest)(nil), // 20: loop.stellar.SubmitTransactionRequest + (*SubmitTransactionResponse)(nil), // 21: loop.stellar.SubmitTransactionResponse + (*GetLatestLedgerResponse)(nil), // 22: loop.stellar.GetLatestLedgerResponse + (*LedgerPaginationOptions)(nil), // 23: loop.stellar.LedgerPaginationOptions + (*GetLedgersRequest)(nil), // 24: loop.stellar.GetLedgersRequest + (*LedgerInfo)(nil), // 25: loop.stellar.LedgerInfo + (*GetLedgersResponse)(nil), // 26: loop.stellar.GetLedgersResponse + (*scval.ScVal)(nil), // 27: capabilities.blockchain.stellar.v1alpha.ScVal + (*emptypb.Empty)(nil), // 28: google.protobuf.Empty } var file_stellar_proto_depIdxs = []int32{ - 26, // 0: loop.stellar.SimulateTransactionRequest.args:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal - 3, // 1: loop.stellar.SimulateTransactionRequest.resource_config:type_name -> loop.stellar.SimulateResourceConfig - 5, // 2: loop.stellar.SimulateTransactionResponse.restore_preamble:type_name -> loop.stellar.SimulateRestorePreamble - 8, // 3: loop.stellar.GetLedgerEntriesResponse.entries:type_name -> loop.stellar.LedgerEntryResult - 16, // 4: loop.stellar.GetEventsRequest.filters:type_name -> loop.stellar.EventFilter - 15, // 5: loop.stellar.GetEventsRequest.pagination:type_name -> loop.stellar.PaginationOptions - 0, // 6: loop.stellar.EventInfo.event_type:type_name -> loop.stellar.EventType - 26, // 7: loop.stellar.EventInfo.topics:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal - 26, // 8: loop.stellar.EventInfo.value:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal - 10, // 9: loop.stellar.GetEventsResponse.events:type_name -> loop.stellar.EventInfo - 0, // 10: loop.stellar.EventFilter.event_types:type_name -> loop.stellar.EventType - 17, // 11: loop.stellar.EventFilter.topics:type_name -> loop.stellar.TopicFilter - 18, // 12: loop.stellar.TopicFilter.segments:type_name -> loop.stellar.TopicSegment - 26, // 13: loop.stellar.TopicSegment.scval:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal - 26, // 14: loop.stellar.SubmitTransactionRequest.args:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal - 1, // 15: loop.stellar.SubmitTransactionResponse.tx_status:type_name -> loop.stellar.TxStatus - 22, // 16: loop.stellar.GetLedgersRequest.pagination:type_name -> loop.stellar.LedgerPaginationOptions - 24, // 17: loop.stellar.GetLedgersResponse.ledgers:type_name -> loop.stellar.LedgerInfo - 6, // 18: loop.stellar.Stellar.GetLedgerEntries:input_type -> loop.stellar.GetLedgerEntriesRequest - 27, // 19: loop.stellar.Stellar.GetLatestLedger:input_type -> google.protobuf.Empty - 23, // 20: loop.stellar.Stellar.GetLedgers:input_type -> loop.stellar.GetLedgersRequest - 2, // 21: loop.stellar.Stellar.SimulateTransaction:input_type -> loop.stellar.SimulateTransactionRequest - 9, // 22: loop.stellar.Stellar.GetEvents:input_type -> loop.stellar.GetEventsRequest - 12, // 23: loop.stellar.Stellar.GetTransaction:input_type -> loop.stellar.GetTransactionRequest - 27, // 24: loop.stellar.Stellar.GetSigningAccount:input_type -> google.protobuf.Empty - 19, // 25: loop.stellar.Stellar.SubmitTransaction:input_type -> loop.stellar.SubmitTransactionRequest - 7, // 26: loop.stellar.Stellar.GetLedgerEntries:output_type -> loop.stellar.GetLedgerEntriesResponse - 21, // 27: loop.stellar.Stellar.GetLatestLedger:output_type -> loop.stellar.GetLatestLedgerResponse - 25, // 28: loop.stellar.Stellar.GetLedgers:output_type -> loop.stellar.GetLedgersResponse - 4, // 29: loop.stellar.Stellar.SimulateTransaction:output_type -> loop.stellar.SimulateTransactionResponse - 11, // 30: loop.stellar.Stellar.GetEvents:output_type -> loop.stellar.GetEventsResponse - 13, // 31: loop.stellar.Stellar.GetTransaction:output_type -> loop.stellar.GetTransactionResponse - 14, // 32: loop.stellar.Stellar.GetSigningAccount:output_type -> loop.stellar.GetSigningAccountResponse - 20, // 33: loop.stellar.Stellar.SubmitTransaction:output_type -> loop.stellar.SubmitTransactionResponse - 26, // [26:34] is the sub-list for method output_type - 18, // [18:26] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 27, // 0: loop.stellar.SimulateTransactionRequest.args:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 4, // 1: loop.stellar.SimulateTransactionRequest.resource_config:type_name -> loop.stellar.SimulateResourceConfig + 6, // 2: loop.stellar.SimulateTransactionResponse.restore_preamble:type_name -> loop.stellar.SimulateRestorePreamble + 9, // 3: loop.stellar.GetLedgerEntriesResponse.entries:type_name -> loop.stellar.LedgerEntryResult + 17, // 4: loop.stellar.GetEventsRequest.filters:type_name -> loop.stellar.EventFilter + 16, // 5: loop.stellar.GetEventsRequest.pagination:type_name -> loop.stellar.PaginationOptions + 1, // 6: loop.stellar.EventInfo.event_type:type_name -> loop.stellar.EventType + 27, // 7: loop.stellar.EventInfo.topics:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 27, // 8: loop.stellar.EventInfo.value:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 11, // 9: loop.stellar.GetEventsResponse.events:type_name -> loop.stellar.EventInfo + 0, // 10: loop.stellar.GetTransactionResponse.status:type_name -> loop.stellar.GetTransactionStatus + 1, // 11: loop.stellar.EventFilter.event_types:type_name -> loop.stellar.EventType + 18, // 12: loop.stellar.EventFilter.topics:type_name -> loop.stellar.TopicFilter + 19, // 13: loop.stellar.TopicFilter.segments:type_name -> loop.stellar.TopicSegment + 27, // 14: loop.stellar.TopicSegment.scval:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 27, // 15: loop.stellar.SubmitTransactionRequest.args:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 2, // 16: loop.stellar.SubmitTransactionResponse.tx_status:type_name -> loop.stellar.TxStatus + 23, // 17: loop.stellar.GetLedgersRequest.pagination:type_name -> loop.stellar.LedgerPaginationOptions + 25, // 18: loop.stellar.GetLedgersResponse.ledgers:type_name -> loop.stellar.LedgerInfo + 7, // 19: loop.stellar.Stellar.GetLedgerEntries:input_type -> loop.stellar.GetLedgerEntriesRequest + 28, // 20: loop.stellar.Stellar.GetLatestLedger:input_type -> google.protobuf.Empty + 24, // 21: loop.stellar.Stellar.GetLedgers:input_type -> loop.stellar.GetLedgersRequest + 3, // 22: loop.stellar.Stellar.SimulateTransaction:input_type -> loop.stellar.SimulateTransactionRequest + 10, // 23: loop.stellar.Stellar.GetEvents:input_type -> loop.stellar.GetEventsRequest + 13, // 24: loop.stellar.Stellar.GetTransaction:input_type -> loop.stellar.GetTransactionRequest + 28, // 25: loop.stellar.Stellar.GetSigningAccount:input_type -> google.protobuf.Empty + 20, // 26: loop.stellar.Stellar.SubmitTransaction:input_type -> loop.stellar.SubmitTransactionRequest + 8, // 27: loop.stellar.Stellar.GetLedgerEntries:output_type -> loop.stellar.GetLedgerEntriesResponse + 22, // 28: loop.stellar.Stellar.GetLatestLedger:output_type -> loop.stellar.GetLatestLedgerResponse + 26, // 29: loop.stellar.Stellar.GetLedgers:output_type -> loop.stellar.GetLedgersResponse + 5, // 30: loop.stellar.Stellar.SimulateTransaction:output_type -> loop.stellar.SimulateTransactionResponse + 12, // 31: loop.stellar.Stellar.GetEvents:output_type -> loop.stellar.GetEventsResponse + 14, // 32: loop.stellar.Stellar.GetTransaction:output_type -> loop.stellar.GetTransactionResponse + 15, // 33: loop.stellar.Stellar.GetSigningAccount:output_type -> loop.stellar.GetSigningAccountResponse + 21, // 34: loop.stellar.Stellar.SubmitTransaction:output_type -> loop.stellar.SubmitTransactionResponse + 27, // [27:35] is the sub-list for method output_type + 19, // [19:27] 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 } func init() { file_stellar_proto_init() } @@ -2090,6 +2189,7 @@ func file_stellar_proto_init() { if File_stellar_proto != nil { return } + file_stellar_proto_msgTypes[11].OneofWrappers = []any{} file_stellar_proto_msgTypes[16].OneofWrappers = []any{ (*TopicSegment_Wildcard)(nil), (*TopicSegment_Scval)(nil), @@ -2100,7 +2200,7 @@ func file_stellar_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_stellar_proto_rawDesc), len(file_stellar_proto_rawDesc)), - NumEnums: 2, + NumEnums: 3, NumMessages: 24, NumExtensions: 0, NumServices: 1, diff --git a/pkg/chains/stellar/stellar.proto b/pkg/chains/stellar/stellar.proto index a71cdfd84e..df49f5ba4d 100644 --- a/pkg/chains/stellar/stellar.proto +++ b/pkg/chains/stellar/stellar.proto @@ -156,11 +156,22 @@ message GetTransactionRequest { string tx_hash = 1; } -// GetTransactionResponse carries fee and ledger metadata for a confirmed transaction. +enum GetTransactionStatus { + GET_TRANSACTION_STATUS_UNSPECIFIED = 0; + GET_TRANSACTION_STATUS_NOT_FOUND = 1; + GET_TRANSACTION_STATUS_FAILED = 2; + GET_TRANSACTION_STATUS_SUCCESS = 3; +} + +// GetTransactionResponse carries the result of looking up a transaction by hash. message GetTransactionResponse { - uint64 fee_stroops = 1; - uint32 ledger_sequence = 2; - int64 ledger_close_time = 3; + optional uint64 fee_stroops = 1; + optional uint32 ledger_sequence = 2; + optional int64 ledger_close_time = 3; + GetTransactionStatus status = 4; + string tx_hash = 5; + bytes result_xdr = 6; + bytes result_meta_xdr = 7; } // GetSigningAccountResponse is the relayer default TXM signing account. @@ -271,4 +282,4 @@ message GetLedgersResponse { int64 oldest_ledger_close_time = 5; // Cursor for the next page; pass as pagination.cursor on a subsequent request. string cursor = 6; -} \ No newline at end of file +} diff --git a/pkg/loop/internal/relayer/stellar.go b/pkg/loop/internal/relayer/stellar.go index 80e153a47e..9b9f4cb87c 100644 --- a/pkg/loop/internal/relayer/stellar.go +++ b/pkg/loop/internal/relayer/stellar.go @@ -265,7 +265,11 @@ func (s *stellarServer) GetTransaction(ctx context.Context, req *stelpb.GetTrans if err != nil { return nil, net.WrapRPCErr(err) } - return stelpb.ConvertGetTransactionResponseToProto(dResp), nil + pResp, err := stelpb.ConvertGetTransactionResponseToProto(dResp) + if err != nil { + return nil, fmt.Errorf("invalid GetTransaction response: %w", err) + } + return pResp, nil } func (s *stellarServer) GetSigningAccount(ctx context.Context, _ *emptypb.Empty) (*stelpb.GetSigningAccountResponse, error) { diff --git a/pkg/loop/internal/relayer/stellar_test.go b/pkg/loop/internal/relayer/stellar_test.go index 430e1a98a0..35056be112 100644 --- a/pkg/loop/internal/relayer/stellar_test.go +++ b/pkg/loop/internal/relayer/stellar_test.go @@ -429,20 +429,28 @@ func TestStellarDomainRoundTripThroughGRPC(t *testing.T) { }) t.Run("GetTransaction_roundtrip", func(t *testing.T) { + fee := uint64(42) + ledger := uint32(100) + closeTime := int64(1_700_000_000) svc.getTransaction = func(_ context.Context, req stellartypes.GetTransactionRequest) (stellartypes.GetTransactionResponse, error) { require.Equal(t, "abc123hash", req.TxHash) return stellartypes.GetTransactionResponse{ - FeeStroops: 42, - LedgerSequence: 100, - LedgerCloseTime: 1_700_000_000, + Status: stellartypes.GetTransactionStatusSuccess, + TxHash: "abc123hash", + ResultXDR: base64.StdEncoding.EncodeToString([]byte("result")), + FeeStroops: &fee, + LedgerSequence: &ledger, + LedgerCloseTime: &closeTime, }, nil } resp, err := client.GetTransaction(ctx, stellartypes.GetTransactionRequest{TxHash: "abc123hash"}) require.NoError(t, err) - require.Equal(t, uint64(42), resp.FeeStroops) - require.Equal(t, uint32(100), resp.LedgerSequence) - require.Equal(t, int64(1_700_000_000), resp.LedgerCloseTime) + require.Equal(t, stellartypes.GetTransactionStatusSuccess, resp.Status) + require.Equal(t, "abc123hash", resp.TxHash) + require.Equal(t, uint64(42), *resp.FeeStroops) + require.Equal(t, uint32(100), *resp.LedgerSequence) + require.Equal(t, int64(1_700_000_000), *resp.LedgerCloseTime) }) t.Run("GetTransaction_invalidRequest", func(t *testing.T) { diff --git a/pkg/loop/internal/relayerset/relayerset_test.go b/pkg/loop/internal/relayerset/relayerset_test.go index ca26ef773b..757e04bc4b 100644 --- a/pkg/loop/internal/relayerset/relayerset_test.go +++ b/pkg/loop/internal/relayerset/relayerset_test.go @@ -1748,10 +1748,16 @@ func Test_RelayerSet_StellarService(t *testing.T) { name: "GetTransaction", run: func(t *testing.T, svc types.StellarService, mockSvc *mocks2.StellarService) { req := stellartypes.GetTransactionRequest{TxHash: "abc123hash"} + fee := uint64(42) + ledger := uint32(100) + closeTime := int64(1_700_000_000) expected := stellartypes.GetTransactionResponse{ - FeeStroops: 42, - LedgerSequence: 100, - LedgerCloseTime: 1_700_000_000, + Status: stellartypes.GetTransactionStatusSuccess, + TxHash: "abc123hash", + ResultXDR: "cmVzdWx0", + FeeStroops: &fee, + LedgerSequence: &ledger, + LedgerCloseTime: &closeTime, } mockSvc.EXPECT().GetTransaction(mock.Anything, req).Return(expected, nil) diff --git a/pkg/loop/internal/relayerset/stellar.go b/pkg/loop/internal/relayerset/stellar.go index 8069613cd6..3876b3c0b4 100644 --- a/pkg/loop/internal/relayerset/stellar.go +++ b/pkg/loop/internal/relayerset/stellar.go @@ -190,7 +190,11 @@ func (ss *stellarServer) GetTransaction(ctx context.Context, req *stelpb.GetTran if err != nil { return nil, net.WrapRPCErr(err) } - return stelpb.ConvertGetTransactionResponseToProto(dResp), nil + pResp, err := stelpb.ConvertGetTransactionResponseToProto(dResp) + if err != nil { + return nil, fmt.Errorf("invalid GetTransaction response: %w", err) + } + return pResp, nil } func (ss *stellarServer) GetSigningAccount(ctx context.Context, _ *emptypb.Empty) (*stelpb.GetSigningAccountResponse, error) { diff --git a/pkg/types/chains/stellar/stellar.go b/pkg/types/chains/stellar/stellar.go index baf0cf7bde..c713e810db 100644 --- a/pkg/types/chains/stellar/stellar.go +++ b/pkg/types/chains/stellar/stellar.go @@ -546,9 +546,28 @@ type GetTransactionRequest struct { TxHash string } -// GetTransactionResponse carries fee and ledger metadata for a confirmed transaction. +// GetTransactionStatus is the lookup status returned by Stellar RPC getTransaction. +type GetTransactionStatus int + +const ( + GetTransactionStatusUnspecified GetTransactionStatus = iota + GetTransactionStatusNotFound + GetTransactionStatusFailed + GetTransactionStatusSuccess +) + +// GetTransactionResponse carries the result of looking up a transaction by hash. type GetTransactionResponse struct { - FeeStroops uint64 - LedgerSequence uint32 - LedgerCloseTime int64 // unix seconds + Status GetTransactionStatus + TxHash string + // ResultXDR is the base64-encoded transaction result XDR when status is failed or success. + ResultXDR string + // ResultMetaXDR is the base64-encoded transaction meta XDR when available. + ResultMetaXDR string + // FeeStroops is the fee charged in stroops when available. + FeeStroops *uint64 + // LedgerSequence is the ledger that included the transaction when available. + LedgerSequence *uint32 + // LedgerCloseTime is the unix timestamp of the ledger that included the transaction when available. + LedgerCloseTime *int64 } From 1ad852bbd68f5f3ad90d24546a822cad9e905bd9 Mon Sep 17 00:00:00 2001 From: Krish-vemula Date: Thu, 10 Sep 2026 09:50:16 -0700 Subject: [PATCH 2/3] Clarify missing Stellar transaction status errors --- pkg/chains/stellar/proto_helpers.go | 4 ++++ pkg/chains/stellar/proto_helpers_test.go | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/pkg/chains/stellar/proto_helpers.go b/pkg/chains/stellar/proto_helpers.go index 797347b50b..5e349a2c8f 100644 --- a/pkg/chains/stellar/proto_helpers.go +++ b/pkg/chains/stellar/proto_helpers.go @@ -1005,6 +1005,8 @@ func convertTxStatusFromProto(s TxStatus) (stellar.TransactionStatus, error) { func convertGetTransactionStatusToProto(s stellar.GetTransactionStatus) (GetTransactionStatus, error) { switch s { + case stellar.GetTransactionStatusUnspecified: + return 0, errors.New("get transaction status is required") case stellar.GetTransactionStatusNotFound: return GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND, nil case stellar.GetTransactionStatusFailed: @@ -1018,6 +1020,8 @@ func convertGetTransactionStatusToProto(s stellar.GetTransactionStatus) (GetTran func convertGetTransactionStatusFromProto(s GetTransactionStatus) (stellar.GetTransactionStatus, error) { switch s { + case GetTransactionStatus_GET_TRANSACTION_STATUS_UNSPECIFIED: + return 0, errors.New("get transaction status is required") case GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND: return stellar.GetTransactionStatusNotFound, nil case GetTransactionStatus_GET_TRANSACTION_STATUS_FAILED: diff --git a/pkg/chains/stellar/proto_helpers_test.go b/pkg/chains/stellar/proto_helpers_test.go index 38f235c108..b6ecc325ca 100644 --- a/pkg/chains/stellar/proto_helpers_test.go +++ b/pkg/chains/stellar/proto_helpers_test.go @@ -1417,6 +1417,15 @@ func TestConvertGetTransactionResponseFromProto_Nil(t *testing.T) { require.Contains(t, err.Error(), "nil") } +func TestConvertGetTransactionResponseToProto_UnspecifiedStatus(t *testing.T) { + _, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{ + TxHash: "abc123hash", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "status") + require.Contains(t, err.Error(), "get transaction status is required") +} + func TestConvertGetTransactionResponseToProto_UnsupportedStatus(t *testing.T) { _, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{ Status: stellartypes.GetTransactionStatus(99), @@ -1427,6 +1436,15 @@ func TestConvertGetTransactionResponseToProto_UnsupportedStatus(t *testing.T) { require.Contains(t, err.Error(), "unsupported get transaction status") } +func TestConvertGetTransactionResponseFromProto_UnspecifiedStatus(t *testing.T) { + _, err := conv.ConvertGetTransactionResponseFromProto(&conv.GetTransactionResponse{ + TxHash: "abc123hash", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "status") + require.Contains(t, err.Error(), "get transaction status is required") +} + func TestConvertGetTransactionResponseFromProto_UnsupportedStatus(t *testing.T) { _, err := conv.ConvertGetTransactionResponseFromProto(&conv.GetTransactionResponse{ Status: conv.GetTransactionStatus(99), From ed78d2b5d8dfc56c0fb663da7a91fc69e690db86 Mon Sep 17 00:00:00 2001 From: Krish-vemula Date: Thu, 10 Sep 2026 13:33:09 -0700 Subject: [PATCH 3/3] nit fix --- pkg/chains/stellar/proto_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/chains/stellar/proto_helpers.go b/pkg/chains/stellar/proto_helpers.go index 5e349a2c8f..31a80eed4b 100644 --- a/pkg/chains/stellar/proto_helpers.go +++ b/pkg/chains/stellar/proto_helpers.go @@ -784,7 +784,7 @@ func ConvertGetTransactionRequestFromProto(p *GetTransactionRequest) (stellar.Ge func ConvertGetTransactionResponseToProto(resp stellar.GetTransactionResponse) (*GetTransactionResponse, error) { status, err := convertGetTransactionStatusToProto(resp.Status) if err != nil { - return nil, fmt.Errorf("status: %w", err) + return nil, err } if err := validateGetTransactionResponse(resp); err != nil { return nil, err