From 0c96357d6b0cb8a252f4cefcf870deb00a276d8e Mon Sep 17 00:00:00 2001 From: ilija Date: Tue, 12 May 2026 21:00:27 +0200 Subject: [PATCH 1/4] Add stellar cap client/server and use xdr scvalues for read contract --- go.mod | 4 +- go.sum | 21 +- .../chain-capabilities/stellar/client.pb.go | 624 ++++++ .../v2/chain-capabilities/stellar/generate.go | 2 + .../stellar/proto_helpers.go | 83 + .../stellar/proto_helpers_test.go | 201 ++ .../stellar/scval/scval.pb.go | 1722 +++++++++++++++++ .../stellar/server/client_server_gen.go | 178 ++ pkg/capabilities/v2/gen/main.go | 48 +- pkg/chains/stellar/generate/main.go | 10 +- pkg/chains/stellar/proto_helpers.go | 272 +++ pkg/chains/stellar/stellar.pb.go | 214 +- pkg/chains/stellar/stellar.proto | 18 + pkg/chains/stellar/stellar_grpc.pb.go | 38 + pkg/loop/internal/relayer/stellar.go | 32 + pkg/loop/internal/relayer/stellar_test.go | 64 + pkg/types/chains/stellar/stellar.go | 34 +- pkg/types/relayer.go | 4 + 18 files changed, 3531 insertions(+), 38 deletions(-) create mode 100644 pkg/capabilities/v2/chain-capabilities/stellar/client.pb.go create mode 100644 pkg/capabilities/v2/chain-capabilities/stellar/generate.go create mode 100644 pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers.go create mode 100644 pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers_test.go create mode 100644 pkg/capabilities/v2/chain-capabilities/stellar/scval/scval.pb.go create mode 100644 pkg/capabilities/v2/chain-capabilities/stellar/server/client_server_gen.go diff --git a/go.mod b/go.mod index ff21096378..d84b45d143 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.89 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260420204255-a3f3bdd56877 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512162638-c38861010453 github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 @@ -51,6 +51,7 @@ require ( github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d + github.com/stellar/go-stellar-sdk v0.5.0 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 go.opentelemetry.io/otel v1.43.0 @@ -138,6 +139,7 @@ require ( github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sanity-io/litter v1.5.5 // indirect + github.com/stellar/go-xdr v0.0.0-20260312225820-cc2b0611aabf // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect diff --git a/go.sum b/go.sum index 0014393c5c..024d277dae 100644 --- a/go.sum +++ b/go.sum @@ -55,6 +55,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= @@ -219,8 +221,14 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= @@ -262,8 +270,9 @@ github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260420204255-a3f3bdd56877 h1:6UueUIbck1Ogarm9rm/9TS6b09mKgMmx+YE8XFg63AQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260420204255-a3f3bdd56877/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260511222622-3dae6143f38a/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512162638-c38861010453 h1:SXsCAHJaW/eXgKDIV1Hq1xIjft/c58r2SQ1nRRmeECM= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512162638-c38861010453/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b h1:36knUpKHHAZ86K4FGWXtx8i/EQftGdk2bqCoEu/Cha8= @@ -278,6 +287,10 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12i github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d h1:LokA9PoCNb8mm8mDT52c3RECPMRsGz1eCQORq+J3n74= github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d/go.mod h1:Acy3BTBxou83ooMESLO90s8PKSu7RvLCzwSTbxxfOK0= +github.com/stellar/go-stellar-sdk v0.5.0 h1:xpOO+ZTyvGz54wTm7pwl2Gf1e6lZl0ExrJ/tKb+Roj4= +github.com/stellar/go-stellar-sdk v0.5.0/go.mod h1:tLKAQPxa2I5UvGMabBbUXcY3fmgYnfDudrMeK7CDX4w= +github.com/stellar/go-xdr v0.0.0-20260312225820-cc2b0611aabf h1:GY1RVbX3Hg7poPXEf6yojjP0hyypvgUgZmCqQU9D0xg= +github.com/stellar/go-xdr v0.0.0-20260312225820-cc2b0611aabf/go.mod h1:If+U9Z1W5xU97VrOgJandQT+2dN7/iOpkCrxBJEyF80= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -299,6 +312,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/ github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xdrpp/goxdr v0.1.1 h1:E1B2c6E8eYhOVyd7yEpOyopzTPirUeF6mVOfXfGyJyc= +github.com/xdrpp/goxdr v0.1.1/go.mod h1:dXo1scL/l6s7iME1gxHWo2XCppbHEKZS7m/KyYWkNzA= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -483,6 +498,8 @@ google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/pkg/capabilities/v2/chain-capabilities/stellar/client.pb.go b/pkg/capabilities/v2/chain-capabilities/stellar/client.pb.go new file mode 100644 index 0000000000..e716aa247f --- /dev/null +++ b/pkg/capabilities/v2/chain-capabilities/stellar/client.pb.go @@ -0,0 +1,624 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v5.29.3 +// source: capabilities/blockchain/stellar/v1alpha/client.proto + +package stellar + +import ( + scval "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar/scval" + sdk "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" + _ "github.com/smartcontractkit/chainlink-protos/cre/go/tools/generator" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type TxStatus int32 + +const ( + TxStatus_TX_STATUS_FATAL TxStatus = 0 + TxStatus_TX_STATUS_REVERTED TxStatus = 1 + TxStatus_TX_STATUS_SUCCESS TxStatus = 2 +) + +// Enum value maps for TxStatus. +var ( + TxStatus_name = map[int32]string{ + 0: "TX_STATUS_FATAL", + 1: "TX_STATUS_REVERTED", + 2: "TX_STATUS_SUCCESS", + } + TxStatus_value = map[string]int32{ + "TX_STATUS_FATAL": 0, + "TX_STATUS_REVERTED": 1, + "TX_STATUS_SUCCESS": 2, + } +) + +func (x TxStatus) Enum() *TxStatus { + p := new(TxStatus) + *p = x + return p +} + +func (x TxStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TxStatus) Descriptor() protoreflect.EnumDescriptor { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_enumTypes[0].Descriptor() +} + +func (TxStatus) Type() protoreflect.EnumType { + return &file_capabilities_blockchain_stellar_v1alpha_client_proto_enumTypes[0] +} + +func (x TxStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TxStatus.Descriptor instead. +func (TxStatus) EnumDescriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP(), []int{0} +} + +type ReceiverContractExecutionStatus int32 + +const ( + ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_SUCCESS ReceiverContractExecutionStatus = 0 + ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED ReceiverContractExecutionStatus = 1 +) + +// Enum value maps for ReceiverContractExecutionStatus. +var ( + ReceiverContractExecutionStatus_name = map[int32]string{ + 0: "RECEIVER_CONTRACT_EXECUTION_STATUS_SUCCESS", + 1: "RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED", + } + ReceiverContractExecutionStatus_value = map[string]int32{ + "RECEIVER_CONTRACT_EXECUTION_STATUS_SUCCESS": 0, + "RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED": 1, + } +) + +func (x ReceiverContractExecutionStatus) Enum() *ReceiverContractExecutionStatus { + p := new(ReceiverContractExecutionStatus) + *p = x + return p +} + +func (x ReceiverContractExecutionStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ReceiverContractExecutionStatus) Descriptor() protoreflect.EnumDescriptor { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_enumTypes[1].Descriptor() +} + +func (ReceiverContractExecutionStatus) Type() protoreflect.EnumType { + return &file_capabilities_blockchain_stellar_v1alpha_client_proto_enumTypes[1] +} + +func (x ReceiverContractExecutionStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ReceiverContractExecutionStatus.Descriptor instead. +func (ReceiverContractExecutionStatus) EnumDescriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP(), []int{1} +} + +type ReadContractRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ContractId string `protobuf:"bytes,1,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + Function string `protobuf:"bytes,2,opt,name=function,proto3" json:"function,omitempty"` + Args []*scval.ScVal `protobuf:"bytes,3,rep,name=args,proto3" json:"args,omitempty"` // Typed Soroban contract arguments (replaces raw XDR bytes) + // Optional: 0 = latest + LedgerSequence uint32 `protobuf:"varint,4,opt,name=ledger_sequence,json=ledgerSequence,proto3" json:"ledger_sequence,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReadContractRequest) Reset() { + *x = ReadContractRequest{} + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadContractRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadContractRequest) ProtoMessage() {} + +func (x *ReadContractRequest) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[0] + 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 ReadContractRequest.ProtoReflect.Descriptor instead. +func (*ReadContractRequest) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP(), []int{0} +} + +func (x *ReadContractRequest) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *ReadContractRequest) GetFunction() string { + if x != nil { + return x.Function + } + return "" +} + +func (x *ReadContractRequest) GetArgs() []*scval.ScVal { + if x != nil { + return x.Args + } + return nil +} + +func (x *ReadContractRequest) GetLedgerSequence() uint32 { + if x != nil { + return x.LedgerSequence + } + return 0 +} + +type ReadContractResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Result []byte `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + // Ledger actually used for simulation + LedgerSequence uint32 `protobuf:"varint,2,opt,name=ledger_sequence,json=ledgerSequence,proto3" json:"ledger_sequence,omitempty"` + // Response + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReadContractResponse) Reset() { + *x = ReadContractResponse{} + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadContractResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadContractResponse) ProtoMessage() {} + +func (x *ReadContractResponse) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[1] + 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 ReadContractResponse.ProtoReflect.Descriptor instead. +func (*ReadContractResponse) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP(), []int{1} +} + +func (x *ReadContractResponse) GetResult() []byte { + if x != nil { + return x.Result + } + return nil +} + +func (x *ReadContractResponse) GetLedgerSequence() uint32 { + if x != nil { + return x.LedgerSequence + } + return 0 +} + +func (x *ReadContractResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +type GetLatestLedgerRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLatestLedgerRequest) Reset() { + *x = GetLatestLedgerRequest{} + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLatestLedgerRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLatestLedgerRequest) ProtoMessage() {} + +func (x *GetLatestLedgerRequest) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[2] + 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 GetLatestLedgerRequest.ProtoReflect.Descriptor instead. +func (*GetLatestLedgerRequest) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP(), []int{2} +} + +type GetLatestLedgerResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` // 32-byte raw ledger hash + ProtocolVersion uint32 `protobuf:"varint,2,opt,name=protocol_version,json=protocolVersion,proto3" json:"protocol_version,omitempty"` + Sequence uint32 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` + LedgerCloseTime int64 `protobuf:"varint,4,opt,name=ledger_close_time,json=ledgerCloseTime,proto3" json:"ledger_close_time,omitempty"` + LedgerHeaderXdr []byte `protobuf:"bytes,5,opt,name=ledger_header_xdr,json=ledgerHeaderXdr,proto3" json:"ledger_header_xdr,omitempty"` // LedgerHeader binary XDR + LedgerMetadataXdr []byte `protobuf:"bytes,6,opt,name=ledger_metadata_xdr,json=ledgerMetadataXdr,proto3" json:"ledger_metadata_xdr,omitempty"` // LedgerCloseMetaV2 binary XDR + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLatestLedgerResponse) Reset() { + *x = GetLatestLedgerResponse{} + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLatestLedgerResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLatestLedgerResponse) ProtoMessage() {} + +func (x *GetLatestLedgerResponse) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[3] + 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 GetLatestLedgerResponse.ProtoReflect.Descriptor instead. +func (*GetLatestLedgerResponse) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP(), []int{3} +} + +func (x *GetLatestLedgerResponse) GetHash() []byte { + if x != nil { + return x.Hash + } + return nil +} + +func (x *GetLatestLedgerResponse) GetProtocolVersion() uint32 { + if x != nil { + return x.ProtocolVersion + } + return 0 +} + +func (x *GetLatestLedgerResponse) GetSequence() uint32 { + if x != nil { + return x.Sequence + } + return 0 +} + +func (x *GetLatestLedgerResponse) GetLedgerCloseTime() int64 { + if x != nil { + return x.LedgerCloseTime + } + return 0 +} + +func (x *GetLatestLedgerResponse) GetLedgerHeaderXdr() []byte { + if x != nil { + return x.LedgerHeaderXdr + } + return nil +} + +func (x *GetLatestLedgerResponse) GetLedgerMetadataXdr() []byte { + if x != nil { + return x.LedgerMetadataXdr + } + return nil +} + +type WriteReportRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ContractId string `protobuf:"bytes,1,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` // Stellar contract address (C… StrKey) + Report *sdk.ReportResponse `protobuf:"bytes,2,opt,name=report,proto3" json:"report,omitempty"` // signed report from consensus + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WriteReportRequest) Reset() { + *x = WriteReportRequest{} + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WriteReportRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteReportRequest) ProtoMessage() {} + +func (x *WriteReportRequest) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[4] + 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 WriteReportRequest.ProtoReflect.Descriptor instead. +func (*WriteReportRequest) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP(), []int{4} +} + +func (x *WriteReportRequest) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *WriteReportRequest) GetReport() *sdk.ReportResponse { + if x != nil { + return x.Report + } + return nil +} + +type WriteReportReply struct { + state protoimpl.MessageState `protogen:"open.v1"` + TxStatus TxStatus `protobuf:"varint,1,opt,name=tx_status,json=txStatus,proto3,enum=capabilities.blockchain.stellar.v1alpha.TxStatus" json:"tx_status,omitempty"` + ReceiverContractExecutionStatus *ReceiverContractExecutionStatus `protobuf:"varint,2,opt,name=receiver_contract_execution_status,json=receiverContractExecutionStatus,proto3,enum=capabilities.blockchain.stellar.v1alpha.ReceiverContractExecutionStatus,oneof" json:"receiver_contract_execution_status,omitempty"` + TxHash *string `protobuf:"bytes,3,opt,name=tx_hash,json=txHash,proto3,oneof" json:"tx_hash,omitempty"` + TransactionFee *uint64 `protobuf:"varint,4,opt,name=transaction_fee,json=transactionFee,proto3,oneof" json:"transaction_fee,omitempty"` // total fee paid in stroops + LedgerSequence *uint32 `protobuf:"varint,5,opt,name=ledger_sequence,json=ledgerSequence,proto3,oneof" json:"ledger_sequence,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WriteReportReply) Reset() { + *x = WriteReportReply{} + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WriteReportReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteReportReply) ProtoMessage() {} + +func (x *WriteReportReply) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[5] + 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 WriteReportReply.ProtoReflect.Descriptor instead. +func (*WriteReportReply) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP(), []int{5} +} + +func (x *WriteReportReply) GetTxStatus() TxStatus { + if x != nil { + return x.TxStatus + } + return TxStatus_TX_STATUS_FATAL +} + +func (x *WriteReportReply) GetReceiverContractExecutionStatus() ReceiverContractExecutionStatus { + if x != nil && x.ReceiverContractExecutionStatus != nil { + return *x.ReceiverContractExecutionStatus + } + return ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_SUCCESS +} + +func (x *WriteReportReply) GetTxHash() string { + if x != nil && x.TxHash != nil { + return *x.TxHash + } + return "" +} + +func (x *WriteReportReply) GetTransactionFee() uint64 { + if x != nil && x.TransactionFee != nil { + return *x.TransactionFee + } + return 0 +} + +func (x *WriteReportReply) GetLedgerSequence() uint32 { + if x != nil && x.LedgerSequence != nil { + return *x.LedgerSequence + } + return 0 +} + +var File_capabilities_blockchain_stellar_v1alpha_client_proto protoreflect.FileDescriptor + +const file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDesc = "" + + "\n" + + "4capabilities/blockchain/stellar/v1alpha/client.proto\x12'capabilities.blockchain.stellar.v1alpha\x1a\x15sdk/v1alpha/sdk.proto\x1a*tools/generator/v1alpha/cre_metadata.proto\x1a3capabilities/blockchain/stellar/v1alpha/scval.proto\"\xbf\x01\n" + + "\x13ReadContractRequest\x12\x1f\n" + + "\vcontract_id\x18\x01 \x01(\tR\n" + + "contractId\x12\x1a\n" + + "\bfunction\x18\x02 \x01(\tR\bfunction\x12B\n" + + "\x04args\x18\x03 \x03(\v2..capabilities.blockchain.stellar.v1alpha.ScValR\x04args\x12'\n" + + "\x0fledger_sequence\x18\x04 \x01(\rR\x0eledgerSequence\"m\n" + + "\x14ReadContractResponse\x12\x16\n" + + "\x06result\x18\x01 \x01(\fR\x06result\x12'\n" + + "\x0fledger_sequence\x18\x02 \x01(\rR\x0eledgerSequence\x12\x14\n" + + "\x05error\x18\x03 \x01(\tR\x05error\"\x18\n" + + "\x16GetLatestLedgerRequest\"\xfc\x01\n" + + "\x17GetLatestLedgerResponse\x12\x12\n" + + "\x04hash\x18\x01 \x01(\fR\x04hash\x12)\n" + + "\x10protocol_version\x18\x02 \x01(\rR\x0fprotocolVersion\x12\x1a\n" + + "\bsequence\x18\x03 \x01(\rR\bsequence\x12*\n" + + "\x11ledger_close_time\x18\x04 \x01(\x03R\x0fledgerCloseTime\x12*\n" + + "\x11ledger_header_xdr\x18\x05 \x01(\fR\x0fledgerHeaderXdr\x12.\n" + + "\x13ledger_metadata_xdr\x18\x06 \x01(\fR\x11ledgerMetadataXdr\"j\n" + + "\x12WriteReportRequest\x12\x1f\n" + + "\vcontract_id\x18\x01 \x01(\tR\n" + + "contractId\x123\n" + + "\x06report\x18\x02 \x01(\v2\x1b.sdk.v1alpha.ReportResponseR\x06report\"\xd4\x03\n" + + "\x10WriteReportReply\x12N\n" + + "\ttx_status\x18\x01 \x01(\x0e21.capabilities.blockchain.stellar.v1alpha.TxStatusR\btxStatus\x12\x9a\x01\n" + + "\"receiver_contract_execution_status\x18\x02 \x01(\x0e2H.capabilities.blockchain.stellar.v1alpha.ReceiverContractExecutionStatusH\x00R\x1freceiverContractExecutionStatus\x88\x01\x01\x12\x1c\n" + + "\atx_hash\x18\x03 \x01(\tH\x01R\x06txHash\x88\x01\x01\x12,\n" + + "\x0ftransaction_fee\x18\x04 \x01(\x04H\x02R\x0etransactionFee\x88\x01\x01\x12,\n" + + "\x0fledger_sequence\x18\x05 \x01(\rH\x03R\x0eledgerSequence\x88\x01\x01B%\n" + + "#_receiver_contract_execution_statusB\n" + + "\n" + + "\b_tx_hashB\x12\n" + + "\x10_transaction_feeB\x12\n" + + "\x10_ledger_sequence*N\n" + + "\bTxStatus\x12\x13\n" + + "\x0fTX_STATUS_FATAL\x10\x00\x12\x16\n" + + "\x12TX_STATUS_REVERTED\x10\x01\x12\x15\n" + + "\x11TX_STATUS_SUCCESS\x10\x02*\x82\x01\n" + + "\x1fReceiverContractExecutionStatus\x12.\n" + + "*RECEIVER_CONTRACT_EXECUTION_STATUS_SUCCESS\x10\x00\x12/\n" + + "+RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED\x10\x012\x9c\x04\n" + + "\x06Client\x12\x94\x01\n" + + "\x0fGetLatestLedger\x12?.capabilities.blockchain.stellar.v1alpha.GetLatestLedgerRequest\x1a@.capabilities.blockchain.stellar.v1alpha.GetLatestLedgerResponse\x12\x8b\x01\n" + + "\fReadContract\x12<.capabilities.blockchain.stellar.v1alpha.ReadContractRequest\x1a=.capabilities.blockchain.stellar.v1alpha.ReadContractResponse\x12\x85\x01\n" + + "\vWriteReport\x12;.capabilities.blockchain.stellar.v1alpha.WriteReportRequest\x1a9.capabilities.blockchain.stellar.v1alpha.WriteReportReply\x1ae\x82\xb5\x18a\b\x01\x12\rstellar@1.0.0\x1aN\n" + + "\rChainSelector\x12=\x12;\n" + + "\x1c\n" + + "\x0fstellar-mainnet\x10\x95\x8c\x83ѫ\xf6\xb1\xe5\xf6\x01\n" + + "\x1b\n" + + "\x0fstellar-testnet\x10\xceۼ\x88\x85\xfd\xf7\xf6Cb\x06proto3" + +var ( + file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescOnce sync.Once + file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescData []byte +) + +func file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescGZIP() []byte { + file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescOnce.Do(func() { + file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDesc), len(file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDesc))) + }) + return file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDescData +} + +var file_capabilities_blockchain_stellar_v1alpha_client_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_capabilities_blockchain_stellar_v1alpha_client_proto_goTypes = []any{ + (TxStatus)(0), // 0: capabilities.blockchain.stellar.v1alpha.TxStatus + (ReceiverContractExecutionStatus)(0), // 1: capabilities.blockchain.stellar.v1alpha.ReceiverContractExecutionStatus + (*ReadContractRequest)(nil), // 2: capabilities.blockchain.stellar.v1alpha.ReadContractRequest + (*ReadContractResponse)(nil), // 3: capabilities.blockchain.stellar.v1alpha.ReadContractResponse + (*GetLatestLedgerRequest)(nil), // 4: capabilities.blockchain.stellar.v1alpha.GetLatestLedgerRequest + (*GetLatestLedgerResponse)(nil), // 5: capabilities.blockchain.stellar.v1alpha.GetLatestLedgerResponse + (*WriteReportRequest)(nil), // 6: capabilities.blockchain.stellar.v1alpha.WriteReportRequest + (*WriteReportReply)(nil), // 7: capabilities.blockchain.stellar.v1alpha.WriteReportReply + (*scval.ScVal)(nil), // 8: capabilities.blockchain.stellar.v1alpha.ScVal + (*sdk.ReportResponse)(nil), // 9: sdk.v1alpha.ReportResponse +} +var file_capabilities_blockchain_stellar_v1alpha_client_proto_depIdxs = []int32{ + 8, // 0: capabilities.blockchain.stellar.v1alpha.ReadContractRequest.args:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 9, // 1: capabilities.blockchain.stellar.v1alpha.WriteReportRequest.report:type_name -> sdk.v1alpha.ReportResponse + 0, // 2: capabilities.blockchain.stellar.v1alpha.WriteReportReply.tx_status:type_name -> capabilities.blockchain.stellar.v1alpha.TxStatus + 1, // 3: capabilities.blockchain.stellar.v1alpha.WriteReportReply.receiver_contract_execution_status:type_name -> capabilities.blockchain.stellar.v1alpha.ReceiverContractExecutionStatus + 4, // 4: capabilities.blockchain.stellar.v1alpha.Client.GetLatestLedger:input_type -> capabilities.blockchain.stellar.v1alpha.GetLatestLedgerRequest + 2, // 5: capabilities.blockchain.stellar.v1alpha.Client.ReadContract:input_type -> capabilities.blockchain.stellar.v1alpha.ReadContractRequest + 6, // 6: capabilities.blockchain.stellar.v1alpha.Client.WriteReport:input_type -> capabilities.blockchain.stellar.v1alpha.WriteReportRequest + 5, // 7: capabilities.blockchain.stellar.v1alpha.Client.GetLatestLedger:output_type -> capabilities.blockchain.stellar.v1alpha.GetLatestLedgerResponse + 3, // 8: capabilities.blockchain.stellar.v1alpha.Client.ReadContract:output_type -> capabilities.blockchain.stellar.v1alpha.ReadContractResponse + 7, // 9: capabilities.blockchain.stellar.v1alpha.Client.WriteReport:output_type -> capabilities.blockchain.stellar.v1alpha.WriteReportReply + 7, // [7:10] is the sub-list for method output_type + 4, // [4:7] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_capabilities_blockchain_stellar_v1alpha_client_proto_init() } +func file_capabilities_blockchain_stellar_v1alpha_client_proto_init() { + if File_capabilities_blockchain_stellar_v1alpha_client_proto != nil { + return + } + file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes[5].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDesc), len(file_capabilities_blockchain_stellar_v1alpha_client_proto_rawDesc)), + NumEnums: 2, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_capabilities_blockchain_stellar_v1alpha_client_proto_goTypes, + DependencyIndexes: file_capabilities_blockchain_stellar_v1alpha_client_proto_depIdxs, + EnumInfos: file_capabilities_blockchain_stellar_v1alpha_client_proto_enumTypes, + MessageInfos: file_capabilities_blockchain_stellar_v1alpha_client_proto_msgTypes, + }.Build() + File_capabilities_blockchain_stellar_v1alpha_client_proto = out.File + file_capabilities_blockchain_stellar_v1alpha_client_proto_goTypes = nil + file_capabilities_blockchain_stellar_v1alpha_client_proto_depIdxs = nil +} diff --git a/pkg/capabilities/v2/chain-capabilities/stellar/generate.go b/pkg/capabilities/v2/chain-capabilities/stellar/generate.go new file mode 100644 index 0000000000..978747ced3 --- /dev/null +++ b/pkg/capabilities/v2/chain-capabilities/stellar/generate.go @@ -0,0 +1,2 @@ +//go:generate go run ../../gen --pkg=github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar --file=capabilities/blockchain/stellar/v1alpha/client.proto --link-and-generate=capabilities/blockchain/stellar/v1alpha/scval.proto=github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar/scval +package stellar diff --git a/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers.go b/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers.go new file mode 100644 index 0000000000..e981e3159f --- /dev/null +++ b/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers.go @@ -0,0 +1,83 @@ +package stellar + +import ( + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + + stellartypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/stellar" +) + +// ConvertGetLatestLedgerResponseFromProto converts a proto GetLatestLedgerResponse to the +// domain type. Hash is returned as lowercase hex; XDR fields are returned as standard base64. +func ConvertGetLatestLedgerResponseFromProto(p *GetLatestLedgerResponse) (stellartypes.GetLatestLedgerResponse, error) { + if p == nil { + return stellartypes.GetLatestLedgerResponse{}, errors.New("GetLatestLedgerResponse is nil") + } + + return stellartypes.GetLatestLedgerResponse{ + Hash: hex.EncodeToString(p.GetHash()), + ProtocolVersion: p.GetProtocolVersion(), + Sequence: p.GetSequence(), + LedgerCloseTime: p.GetLedgerCloseTime(), + LedgerHeaderXDR: base64.StdEncoding.EncodeToString(p.GetLedgerHeaderXdr()), + LedgerMetadataXDR: base64.StdEncoding.EncodeToString(p.GetLedgerMetadataXdr()), + }, nil +} + +// ConvertGetLatestLedgerResponseToProto converts the domain GetLatestLedgerResponse to a proto. +// Hash must be a valid lowercase hex string; XDR fields must be valid standard base64. +func ConvertGetLatestLedgerResponseToProto(r stellartypes.GetLatestLedgerResponse) (*GetLatestLedgerResponse, error) { + hash, err := hex.DecodeString(r.Hash) + if err != nil { + return nil, fmt.Errorf("invalid hex hash %q: %w", r.Hash, err) + } + + headerXDR, err := base64.StdEncoding.DecodeString(r.LedgerHeaderXDR) + if err != nil { + return nil, fmt.Errorf("invalid base64 ledger_header_xdr: %w", err) + } + + metadataXDR, err := base64.StdEncoding.DecodeString(r.LedgerMetadataXDR) + if err != nil { + return nil, fmt.Errorf("invalid base64 ledger_metadata_xdr: %w", err) + } + + return &GetLatestLedgerResponse{ + Hash: hash, + ProtocolVersion: r.ProtocolVersion, + Sequence: r.Sequence, + LedgerCloseTime: r.LedgerCloseTime, + LedgerHeaderXdr: headerXDR, + LedgerMetadataXdr: metadataXDR, + }, nil +} + +// ValidateReadContractRequest checks that required fields are present. +func ValidateReadContractRequest(req *ReadContractRequest) error { + if req == nil { + return errors.New("ReadContractRequest is nil") + } + if req.ContractId == "" { + return errors.New("contract_id is required") + } + if req.Function == "" { + return errors.New("function is required") + } + return nil +} + +// ValidateWriteReportRequest checks that required fields are present. +func ValidateWriteReportRequest(req *WriteReportRequest) error { + if req == nil { + return errors.New("WriteReportRequest is nil") + } + if req.ContractId == "" { + return errors.New("contract_id is required") + } + if req.Report == nil { + return errors.New("report is required") + } + return nil +} diff --git a/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers_test.go b/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers_test.go new file mode 100644 index 0000000000..6cc0e40608 --- /dev/null +++ b/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers_test.go @@ -0,0 +1,201 @@ +package stellar_test + +import ( + "encoding/base64" + "encoding/hex" + "testing" + + "github.com/stretchr/testify/require" + + stellarcap "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar" + stellartypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/stellar" + sdkpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" +) + +func TestConvertGetLatestLedgerResponseRoundtrip(t *testing.T) { + t.Parallel() + + rawHash := []byte{0xde, 0xad, 0xbe, 0xef, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b} + rawHeader := []byte{0xaa, 0xbb, 0xcc} + rawMeta := []byte{0x11, 0x22, 0x33, 0x44} + + protoResp := &stellarcap.GetLatestLedgerResponse{ + Hash: rawHash, + ProtocolVersion: 22, + Sequence: 987654, + LedgerCloseTime: 1_700_000_000, + LedgerHeaderXdr: rawHeader, + LedgerMetadataXdr: rawMeta, + } + + domain, err := stellarcap.ConvertGetLatestLedgerResponseFromProto(protoResp) + require.NoError(t, err) + require.Equal(t, hex.EncodeToString(rawHash), domain.Hash) + require.Equal(t, uint32(22), domain.ProtocolVersion) + require.Equal(t, uint32(987654), domain.Sequence) + require.Equal(t, int64(1_700_000_000), domain.LedgerCloseTime) + require.Equal(t, base64.StdEncoding.EncodeToString(rawHeader), domain.LedgerHeaderXDR) + require.Equal(t, base64.StdEncoding.EncodeToString(rawMeta), domain.LedgerMetadataXDR) + + // Round-trip back to proto. + roundTripped, err := stellarcap.ConvertGetLatestLedgerResponseToProto(domain) + require.NoError(t, err) + require.Equal(t, rawHash, roundTripped.Hash) + require.Equal(t, uint32(22), roundTripped.ProtocolVersion) + require.Equal(t, uint32(987654), roundTripped.Sequence) + require.Equal(t, int64(1_700_000_000), roundTripped.LedgerCloseTime) + require.Equal(t, rawHeader, roundTripped.LedgerHeaderXdr) + require.Equal(t, rawMeta, roundTripped.LedgerMetadataXdr) +} + +func TestConvertGetLatestLedgerResponseFromProto_RejectsNil(t *testing.T) { + t.Parallel() + + _, err := stellarcap.ConvertGetLatestLedgerResponseFromProto(nil) + require.ErrorContains(t, err, "GetLatestLedgerResponse is nil") +} + +func TestConvertGetLatestLedgerResponseFromProto_EmptyFieldsReturnZeroValues(t *testing.T) { + t.Parallel() + + domain, err := stellarcap.ConvertGetLatestLedgerResponseFromProto(&stellarcap.GetLatestLedgerResponse{}) + require.NoError(t, err) + require.Equal(t, "", domain.Hash) // hex.EncodeToString(nil) == "" + require.Equal(t, base64.StdEncoding.EncodeToString(nil), domain.LedgerHeaderXDR) +} + +func TestConvertGetLatestLedgerResponseToProto_RejectsInvalidHexHash(t *testing.T) { + t.Parallel() + + _, err := stellarcap.ConvertGetLatestLedgerResponseToProto(stellartypes.GetLatestLedgerResponse{ + Hash: "not-hex!", + }) + require.ErrorContains(t, err, "invalid hex hash") +} + +func TestConvertGetLatestLedgerResponseToProto_RejectsInvalidBase64Header(t *testing.T) { + t.Parallel() + + _, err := stellarcap.ConvertGetLatestLedgerResponseToProto(stellartypes.GetLatestLedgerResponse{ + Hash: "", + LedgerHeaderXDR: "not-valid-base64!!!", + }) + require.ErrorContains(t, err, "invalid base64 ledger_header_xdr") +} + +func TestConvertGetLatestLedgerResponseToProto_RejectsInvalidBase64Metadata(t *testing.T) { + t.Parallel() + + _, err := stellarcap.ConvertGetLatestLedgerResponseToProto(stellartypes.GetLatestLedgerResponse{ + Hash: "", + LedgerHeaderXDR: "", + LedgerMetadataXDR: "not-valid-base64!!!", + }) + require.ErrorContains(t, err, "invalid base64 ledger_metadata_xdr") +} + +func TestValidateReadContractRequest_AcceptsValidRequest(t *testing.T) { + t.Parallel() + + err := stellarcap.ValidateReadContractRequest(&stellarcap.ReadContractRequest{ + ContractId: "CAHJJJKK7777AAAA1111BBBB2222CCCC3333DDDD4444EEEE5555FFFF6666", + Function: "balance", + Args: [][]byte{{0x01}, {0x02}}, + }) + require.NoError(t, err) +} + +func TestValidateReadContractRequest_RejectsInvalidInputs(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + req *stellarcap.ReadContractRequest + wantErr string + }{ + { + name: "nil request", + req: nil, + wantErr: "ReadContractRequest is nil", + }, + { + name: "empty contract_id", + req: &stellarcap.ReadContractRequest{Function: "balance"}, + wantErr: "contract_id is required", + }, + { + name: "empty function", + req: &stellarcap.ReadContractRequest{ContractId: "CABC"}, + wantErr: "function is required", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + err := stellarcap.ValidateReadContractRequest(tc.req) + require.ErrorContains(t, err, tc.wantErr) + }) + } +} + +func TestValidateReadContractRequest_ZeroLedgerSequenceIsAllowed(t *testing.T) { + t.Parallel() + + // ledger_sequence == 0 means "use latest" and is explicitly allowed. + err := stellarcap.ValidateReadContractRequest(&stellarcap.ReadContractRequest{ + ContractId: "CABC", + Function: "my_fn", + LedgerSequence: 0, + }) + require.NoError(t, err) +} + +func TestValidateWriteReportRequest_AcceptsValidRequest(t *testing.T) { + t.Parallel() + + err := stellarcap.ValidateWriteReportRequest(&stellarcap.WriteReportRequest{ + ContractId: "CAHJJJKK7777AAAA1111BBBB2222CCCC3333DDDD4444EEEE5555FFFF6666", + Report: &sdkpb.ReportResponse{}, + }) + require.NoError(t, err) +} + +func TestValidateWriteReportRequest_RejectsInvalidInputs(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + req *stellarcap.WriteReportRequest + wantErr string + }{ + { + name: "nil request", + req: nil, + wantErr: "WriteReportRequest is nil", + }, + { + name: "empty contract_id", + req: &stellarcap.WriteReportRequest{Report: &sdkpb.ReportResponse{}}, + wantErr: "contract_id is required", + }, + { + name: "nil report", + req: &stellarcap.WriteReportRequest{ContractId: "CABC"}, + wantErr: "report is required", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + err := stellarcap.ValidateWriteReportRequest(tc.req) + require.ErrorContains(t, err, tc.wantErr) + }) + } +} diff --git a/pkg/capabilities/v2/chain-capabilities/stellar/scval/scval.pb.go b/pkg/capabilities/v2/chain-capabilities/stellar/scval/scval.pb.go new file mode 100644 index 0000000000..e18c2e8532 --- /dev/null +++ b/pkg/capabilities/v2/chain-capabilities/stellar/scval/scval.pb.go @@ -0,0 +1,1722 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v5.29.3 +// source: capabilities/blockchain/stellar/v1alpha/scval.proto + +package v1alpha + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ScError_Type int32 + +const ( + ScError_SCE_CONTRACT ScError_Type = 0 + ScError_SCE_WASM_VM ScError_Type = 1 + ScError_SCE_CONTEXT ScError_Type = 2 + ScError_SCE_STORAGE ScError_Type = 3 + ScError_SCE_OBJECT ScError_Type = 4 + ScError_SCE_CRYPTO ScError_Type = 5 + ScError_SCE_EVENTS ScError_Type = 6 + ScError_SCE_BUDGET ScError_Type = 7 + ScError_SCE_VALUE ScError_Type = 8 + ScError_SCE_AUTH ScError_Type = 9 +) + +// Enum value maps for ScError_Type. +var ( + ScError_Type_name = map[int32]string{ + 0: "SCE_CONTRACT", + 1: "SCE_WASM_VM", + 2: "SCE_CONTEXT", + 3: "SCE_STORAGE", + 4: "SCE_OBJECT", + 5: "SCE_CRYPTO", + 6: "SCE_EVENTS", + 7: "SCE_BUDGET", + 8: "SCE_VALUE", + 9: "SCE_AUTH", + } + ScError_Type_value = map[string]int32{ + "SCE_CONTRACT": 0, + "SCE_WASM_VM": 1, + "SCE_CONTEXT": 2, + "SCE_STORAGE": 3, + "SCE_OBJECT": 4, + "SCE_CRYPTO": 5, + "SCE_EVENTS": 6, + "SCE_BUDGET": 7, + "SCE_VALUE": 8, + "SCE_AUTH": 9, + } +) + +func (x ScError_Type) Enum() *ScError_Type { + p := new(ScError_Type) + *p = x + return p +} + +func (x ScError_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ScError_Type) Descriptor() protoreflect.EnumDescriptor { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_enumTypes[0].Descriptor() +} + +func (ScError_Type) Type() protoreflect.EnumType { + return &file_capabilities_blockchain_stellar_v1alpha_scval_proto_enumTypes[0] +} + +func (x ScError_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ScError_Type.Descriptor instead. +func (ScError_Type) EnumDescriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{4, 0} +} + +type ScError_Code int32 + +const ( + ScError_SCEC_ARITH_DOMAIN ScError_Code = 0 + ScError_SCEC_INDEX_BOUNDS ScError_Code = 1 + ScError_SCEC_INVALID_INPUT ScError_Code = 2 + ScError_SCEC_MISSING_VALUE ScError_Code = 3 + ScError_SCEC_EXISTING_VALUE ScError_Code = 4 + ScError_SCEC_EXCEEDED_LIMIT ScError_Code = 5 + ScError_SCEC_INVALID_ACTION ScError_Code = 6 + ScError_SCEC_INTERNAL_ERROR ScError_Code = 7 + ScError_SCEC_UNEXPECTED_TYPE ScError_Code = 8 + ScError_SCEC_UNEXPECTED_SIZE ScError_Code = 9 +) + +// Enum value maps for ScError_Code. +var ( + ScError_Code_name = map[int32]string{ + 0: "SCEC_ARITH_DOMAIN", + 1: "SCEC_INDEX_BOUNDS", + 2: "SCEC_INVALID_INPUT", + 3: "SCEC_MISSING_VALUE", + 4: "SCEC_EXISTING_VALUE", + 5: "SCEC_EXCEEDED_LIMIT", + 6: "SCEC_INVALID_ACTION", + 7: "SCEC_INTERNAL_ERROR", + 8: "SCEC_UNEXPECTED_TYPE", + 9: "SCEC_UNEXPECTED_SIZE", + } + ScError_Code_value = map[string]int32{ + "SCEC_ARITH_DOMAIN": 0, + "SCEC_INDEX_BOUNDS": 1, + "SCEC_INVALID_INPUT": 2, + "SCEC_MISSING_VALUE": 3, + "SCEC_EXISTING_VALUE": 4, + "SCEC_EXCEEDED_LIMIT": 5, + "SCEC_INVALID_ACTION": 6, + "SCEC_INTERNAL_ERROR": 7, + "SCEC_UNEXPECTED_TYPE": 8, + "SCEC_UNEXPECTED_SIZE": 9, + } +) + +func (x ScError_Code) Enum() *ScError_Code { + p := new(ScError_Code) + *p = x + return p +} + +func (x ScError_Code) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ScError_Code) Descriptor() protoreflect.EnumDescriptor { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_enumTypes[1].Descriptor() +} + +func (ScError_Code) Type() protoreflect.EnumType { + return &file_capabilities_blockchain_stellar_v1alpha_scval_proto_enumTypes[1] +} + +func (x ScError_Code) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ScError_Code.Descriptor instead. +func (ScError_Code) EnumDescriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{4, 1} +} + +type UInt128Parts struct { + state protoimpl.MessageState `protogen:"open.v1"` + Hi uint64 `protobuf:"varint,1,opt,name=hi,proto3" json:"hi,omitempty"` + Lo uint64 `protobuf:"varint,2,opt,name=lo,proto3" json:"lo,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UInt128Parts) Reset() { + *x = UInt128Parts{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UInt128Parts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UInt128Parts) ProtoMessage() {} + +func (x *UInt128Parts) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[0] + 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 UInt128Parts.ProtoReflect.Descriptor instead. +func (*UInt128Parts) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{0} +} + +func (x *UInt128Parts) GetHi() uint64 { + if x != nil { + return x.Hi + } + return 0 +} + +func (x *UInt128Parts) GetLo() uint64 { + if x != nil { + return x.Lo + } + return 0 +} + +type Int128Parts struct { + state protoimpl.MessageState `protogen:"open.v1"` + Hi int64 `protobuf:"varint,1,opt,name=hi,proto3" json:"hi,omitempty"` + Lo uint64 `protobuf:"varint,2,opt,name=lo,proto3" json:"lo,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Int128Parts) Reset() { + *x = Int128Parts{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Int128Parts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Int128Parts) ProtoMessage() {} + +func (x *Int128Parts) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[1] + 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 Int128Parts.ProtoReflect.Descriptor instead. +func (*Int128Parts) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{1} +} + +func (x *Int128Parts) GetHi() int64 { + if x != nil { + return x.Hi + } + return 0 +} + +func (x *Int128Parts) GetLo() uint64 { + if x != nil { + return x.Lo + } + return 0 +} + +type UInt256Parts struct { + state protoimpl.MessageState `protogen:"open.v1"` + HiHi uint64 `protobuf:"varint,1,opt,name=hi_hi,json=hiHi,proto3" json:"hi_hi,omitempty"` + HiLo uint64 `protobuf:"varint,2,opt,name=hi_lo,json=hiLo,proto3" json:"hi_lo,omitempty"` + LoHi uint64 `protobuf:"varint,3,opt,name=lo_hi,json=loHi,proto3" json:"lo_hi,omitempty"` + LoLo uint64 `protobuf:"varint,4,opt,name=lo_lo,json=loLo,proto3" json:"lo_lo,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UInt256Parts) Reset() { + *x = UInt256Parts{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UInt256Parts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UInt256Parts) ProtoMessage() {} + +func (x *UInt256Parts) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[2] + 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 UInt256Parts.ProtoReflect.Descriptor instead. +func (*UInt256Parts) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{2} +} + +func (x *UInt256Parts) GetHiHi() uint64 { + if x != nil { + return x.HiHi + } + return 0 +} + +func (x *UInt256Parts) GetHiLo() uint64 { + if x != nil { + return x.HiLo + } + return 0 +} + +func (x *UInt256Parts) GetLoHi() uint64 { + if x != nil { + return x.LoHi + } + return 0 +} + +func (x *UInt256Parts) GetLoLo() uint64 { + if x != nil { + return x.LoLo + } + return 0 +} + +type Int256Parts struct { + state protoimpl.MessageState `protogen:"open.v1"` + HiHi int64 `protobuf:"varint,1,opt,name=hi_hi,json=hiHi,proto3" json:"hi_hi,omitempty"` + HiLo uint64 `protobuf:"varint,2,opt,name=hi_lo,json=hiLo,proto3" json:"hi_lo,omitempty"` + LoHi uint64 `protobuf:"varint,3,opt,name=lo_hi,json=loHi,proto3" json:"lo_hi,omitempty"` + LoLo uint64 `protobuf:"varint,4,opt,name=lo_lo,json=loLo,proto3" json:"lo_lo,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Int256Parts) Reset() { + *x = Int256Parts{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Int256Parts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Int256Parts) ProtoMessage() {} + +func (x *Int256Parts) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[3] + 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 Int256Parts.ProtoReflect.Descriptor instead. +func (*Int256Parts) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{3} +} + +func (x *Int256Parts) GetHiHi() int64 { + if x != nil { + return x.HiHi + } + return 0 +} + +func (x *Int256Parts) GetHiLo() uint64 { + if x != nil { + return x.HiLo + } + return 0 +} + +func (x *Int256Parts) GetLoHi() uint64 { + if x != nil { + return x.LoHi + } + return 0 +} + +func (x *Int256Parts) GetLoLo() uint64 { + if x != nil { + return x.LoLo + } + return 0 +} + +type ScError struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type ScError_Type `protobuf:"varint,1,opt,name=type,proto3,enum=capabilities.blockchain.stellar.v1alpha.ScError_Type" json:"type,omitempty"` + // For SCE_CONTRACT: user-defined numeric code. + // For all other types: one of the well-known SCErrorCode values. + // + // Types that are valid to be assigned to CodeOrContract: + // + // *ScError_ContractCode + // *ScError_Code_ + CodeOrContract isScError_CodeOrContract `protobuf_oneof:"code_or_contract"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScError) Reset() { + *x = ScError{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScError) ProtoMessage() {} + +func (x *ScError) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[4] + 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 ScError.ProtoReflect.Descriptor instead. +func (*ScError) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{4} +} + +func (x *ScError) GetType() ScError_Type { + if x != nil { + return x.Type + } + return ScError_SCE_CONTRACT +} + +func (x *ScError) GetCodeOrContract() isScError_CodeOrContract { + if x != nil { + return x.CodeOrContract + } + return nil +} + +func (x *ScError) GetContractCode() uint32 { + if x != nil { + if x, ok := x.CodeOrContract.(*ScError_ContractCode); ok { + return x.ContractCode + } + } + return 0 +} + +func (x *ScError) GetCode() ScError_Code { + if x != nil { + if x, ok := x.CodeOrContract.(*ScError_Code_); ok { + return x.Code + } + } + return ScError_SCEC_ARITH_DOMAIN +} + +type isScError_CodeOrContract interface { + isScError_CodeOrContract() +} + +type ScError_ContractCode struct { + ContractCode uint32 `protobuf:"varint,2,opt,name=contract_code,json=contractCode,proto3,oneof"` +} + +type ScError_Code_ struct { + Code ScError_Code `protobuf:"varint,3,opt,name=code,proto3,enum=capabilities.blockchain.stellar.v1alpha.ScError_Code,oneof"` +} + +func (*ScError_ContractCode) isScError_CodeOrContract() {} + +func (*ScError_Code_) isScError_CodeOrContract() {} + +type MuxedEd25519Account struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Ed25519 []byte `protobuf:"bytes,2,opt,name=ed25519,proto3" json:"ed25519,omitempty"` // 32-byte Ed25519 public key + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MuxedEd25519Account) Reset() { + *x = MuxedEd25519Account{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MuxedEd25519Account) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MuxedEd25519Account) ProtoMessage() {} + +func (x *MuxedEd25519Account) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[5] + 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 MuxedEd25519Account.ProtoReflect.Descriptor instead. +func (*MuxedEd25519Account) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{5} +} + +func (x *MuxedEd25519Account) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *MuxedEd25519Account) GetEd25519() []byte { + if x != nil { + return x.Ed25519 + } + return nil +} + +// A claimable balance ID is simply a 32-byte hash tagged with a type. +// We encode only the v0 variant (hash bytes) since that is the only +// type in the current protocol. +type ClaimableBalanceId struct { + state protoimpl.MessageState `protogen:"open.v1"` + V0 []byte `protobuf:"bytes,1,opt,name=v0,proto3" json:"v0,omitempty"` // 32-byte SHA-256 hash + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ClaimableBalanceId) Reset() { + *x = ClaimableBalanceId{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClaimableBalanceId) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClaimableBalanceId) ProtoMessage() {} + +func (x *ClaimableBalanceId) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[6] + 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 ClaimableBalanceId.ProtoReflect.Descriptor instead. +func (*ClaimableBalanceId) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{6} +} + +func (x *ClaimableBalanceId) GetV0() []byte { + if x != nil { + return x.V0 + } + return nil +} + +type ScAddress struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Address: + // + // *ScAddress_AccountId + // *ScAddress_ContractId + // *ScAddress_MuxedAccount + // *ScAddress_ClaimableBalanceId + // *ScAddress_LiquidityPoolId + Address isScAddress_Address `protobuf_oneof:"address"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScAddress) Reset() { + *x = ScAddress{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScAddress) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScAddress) ProtoMessage() {} + +func (x *ScAddress) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[7] + 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 ScAddress.ProtoReflect.Descriptor instead. +func (*ScAddress) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{7} +} + +func (x *ScAddress) GetAddress() isScAddress_Address { + if x != nil { + return x.Address + } + return nil +} + +func (x *ScAddress) GetAccountId() []byte { + if x != nil { + if x, ok := x.Address.(*ScAddress_AccountId); ok { + return x.AccountId + } + } + return nil +} + +func (x *ScAddress) GetContractId() []byte { + if x != nil { + if x, ok := x.Address.(*ScAddress_ContractId); ok { + return x.ContractId + } + } + return nil +} + +func (x *ScAddress) GetMuxedAccount() *MuxedEd25519Account { + if x != nil { + if x, ok := x.Address.(*ScAddress_MuxedAccount); ok { + return x.MuxedAccount + } + } + return nil +} + +func (x *ScAddress) GetClaimableBalanceId() *ClaimableBalanceId { + if x != nil { + if x, ok := x.Address.(*ScAddress_ClaimableBalanceId); ok { + return x.ClaimableBalanceId + } + } + return nil +} + +func (x *ScAddress) GetLiquidityPoolId() []byte { + if x != nil { + if x, ok := x.Address.(*ScAddress_LiquidityPoolId); ok { + return x.LiquidityPoolId + } + } + return nil +} + +type isScAddress_Address interface { + isScAddress_Address() +} + +type ScAddress_AccountId struct { + AccountId []byte `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3,oneof"` // 32-byte Ed25519 public key (AccountID) +} + +type ScAddress_ContractId struct { + ContractId []byte `protobuf:"bytes,2,opt,name=contract_id,json=contractId,proto3,oneof"` // 32-byte contract hash (ContractID) +} + +type ScAddress_MuxedAccount struct { + MuxedAccount *MuxedEd25519Account `protobuf:"bytes,3,opt,name=muxed_account,json=muxedAccount,proto3,oneof"` // muxed Ed25519 account +} + +type ScAddress_ClaimableBalanceId struct { + ClaimableBalanceId *ClaimableBalanceId `protobuf:"bytes,4,opt,name=claimable_balance_id,json=claimableBalanceId,proto3,oneof"` +} + +type ScAddress_LiquidityPoolId struct { + LiquidityPoolId []byte `protobuf:"bytes,5,opt,name=liquidity_pool_id,json=liquidityPoolId,proto3,oneof"` // 32-byte pool hash (PoolID) +} + +func (*ScAddress_AccountId) isScAddress_Address() {} + +func (*ScAddress_ContractId) isScAddress_Address() {} + +func (*ScAddress_MuxedAccount) isScAddress_Address() {} + +func (*ScAddress_ClaimableBalanceId) isScAddress_Address() {} + +func (*ScAddress_LiquidityPoolId) isScAddress_Address() {} + +type ContractExecutable struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Type: + // + // *ContractExecutable_WasmHash + // *ContractExecutable_StellarAsset + Type isContractExecutable_Type `protobuf_oneof:"type"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContractExecutable) Reset() { + *x = ContractExecutable{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContractExecutable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractExecutable) ProtoMessage() {} + +func (x *ContractExecutable) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[8] + 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 ContractExecutable.ProtoReflect.Descriptor instead. +func (*ContractExecutable) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{8} +} + +func (x *ContractExecutable) GetType() isContractExecutable_Type { + if x != nil { + return x.Type + } + return nil +} + +func (x *ContractExecutable) GetWasmHash() []byte { + if x != nil { + if x, ok := x.Type.(*ContractExecutable_WasmHash); ok { + return x.WasmHash + } + } + return nil +} + +func (x *ContractExecutable) GetStellarAsset() bool { + if x != nil { + if x, ok := x.Type.(*ContractExecutable_StellarAsset); ok { + return x.StellarAsset + } + } + return false +} + +type isContractExecutable_Type interface { + isContractExecutable_Type() +} + +type ContractExecutable_WasmHash struct { + WasmHash []byte `protobuf:"bytes,1,opt,name=wasm_hash,json=wasmHash,proto3,oneof"` // SHA-256 hash of the WASM module +} + +type ContractExecutable_StellarAsset struct { + StellarAsset bool `protobuf:"varint,2,opt,name=stellar_asset,json=stellarAsset,proto3,oneof"` // true ⇒ CONTRACT_EXECUTABLE_STELLAR_ASSET +} + +func (*ContractExecutable_WasmHash) isContractExecutable_Type() {} + +func (*ContractExecutable_StellarAsset) isContractExecutable_Type() {} + +// Forward-declared via ScMapEntry below; proto3 allows forward references. +type ScContractInstance struct { + state protoimpl.MessageState `protogen:"open.v1"` + Executable *ContractExecutable `protobuf:"bytes,1,opt,name=executable,proto3" json:"executable,omitempty"` + Storage []*ScMapEntry `protobuf:"bytes,2,rep,name=storage,proto3" json:"storage,omitempty"` // empty slice ⇒ no storage map (nil in XDR) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScContractInstance) Reset() { + *x = ScContractInstance{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScContractInstance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScContractInstance) ProtoMessage() {} + +func (x *ScContractInstance) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[9] + 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 ScContractInstance.ProtoReflect.Descriptor instead. +func (*ScContractInstance) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{9} +} + +func (x *ScContractInstance) GetExecutable() *ContractExecutable { + if x != nil { + return x.Executable + } + return nil +} + +func (x *ScContractInstance) GetStorage() []*ScMapEntry { + if x != nil { + return x.Storage + } + return nil +} + +type ScNonceKey struct { + state protoimpl.MessageState `protogen:"open.v1"` + Nonce int64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScNonceKey) Reset() { + *x = ScNonceKey{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScNonceKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScNonceKey) ProtoMessage() {} + +func (x *ScNonceKey) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[10] + 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 ScNonceKey.ProtoReflect.Descriptor instead. +func (*ScNonceKey) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{10} +} + +func (x *ScNonceKey) GetNonce() int64 { + if x != nil { + return x.Nonce + } + return 0 +} + +type ScMapEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Key *ScVal `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Val *ScVal `protobuf:"bytes,2,opt,name=val,proto3" json:"val,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScMapEntry) Reset() { + *x = ScMapEntry{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScMapEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScMapEntry) ProtoMessage() {} + +func (x *ScMapEntry) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[11] + 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 ScMapEntry.ProtoReflect.Descriptor instead. +func (*ScMapEntry) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{11} +} + +func (x *ScMapEntry) GetKey() *ScVal { + if x != nil { + return x.Key + } + return nil +} + +func (x *ScMapEntry) GetVal() *ScVal { + if x != nil { + return x.Val + } + return nil +} + +type ScVec struct { + state protoimpl.MessageState `protogen:"open.v1"` + Values []*ScVal `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScVec) Reset() { + *x = ScVec{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScVec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScVec) ProtoMessage() {} + +func (x *ScVec) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[12] + 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 ScVec.ProtoReflect.Descriptor instead. +func (*ScVec) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{12} +} + +func (x *ScVec) GetValues() []*ScVal { + if x != nil { + return x.Values + } + return nil +} + +type ScMap struct { + state protoimpl.MessageState `protogen:"open.v1"` + Entries []*ScMapEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScMap) Reset() { + *x = ScMap{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScMap) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScMap) ProtoMessage() {} + +func (x *ScMap) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[13] + 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 ScMap.ProtoReflect.Descriptor instead. +func (*ScMap) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{13} +} + +func (x *ScMap) GetEntries() []*ScMapEntry { + if x != nil { + return x.Entries + } + return nil +} + +type Void struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Void) Reset() { + *x = Void{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Void) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Void) ProtoMessage() {} + +func (x *Void) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[14] + 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 Void.ProtoReflect.Descriptor instead. +func (*Void) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{14} +} + +type ScVal struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Value: + // + // *ScVal_B + // *ScVal_VoidVal + // *ScVal_Error + // *ScVal_U32 + // *ScVal_I32 + // *ScVal_U64 + // *ScVal_I64 + // *ScVal_Timepoint + // *ScVal_Duration + // *ScVal_U128 + // *ScVal_I128 + // *ScVal_U256 + // *ScVal_I256 + // *ScVal_BytesVal + // *ScVal_Str + // *ScVal_Sym + // *ScVal_Vec + // *ScVal_Map + // *ScVal_Address + // *ScVal_ContractInstance + // *ScVal_LedgerKeyContractInstance + // *ScVal_NonceKey + Value isScVal_Value `protobuf_oneof:"value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScVal) Reset() { + *x = ScVal{} + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScVal) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScVal) ProtoMessage() {} + +func (x *ScVal) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[15] + 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 ScVal.ProtoReflect.Descriptor instead. +func (*ScVal) Descriptor() ([]byte, []int) { + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP(), []int{15} +} + +func (x *ScVal) GetValue() isScVal_Value { + if x != nil { + return x.Value + } + return nil +} + +func (x *ScVal) GetB() bool { + if x != nil { + if x, ok := x.Value.(*ScVal_B); ok { + return x.B + } + } + return false +} + +func (x *ScVal) GetVoidVal() *Void { + if x != nil { + if x, ok := x.Value.(*ScVal_VoidVal); ok { + return x.VoidVal + } + } + return nil +} + +func (x *ScVal) GetError() *ScError { + if x != nil { + if x, ok := x.Value.(*ScVal_Error); ok { + return x.Error + } + } + return nil +} + +func (x *ScVal) GetU32() uint32 { + if x != nil { + if x, ok := x.Value.(*ScVal_U32); ok { + return x.U32 + } + } + return 0 +} + +func (x *ScVal) GetI32() int32 { + if x != nil { + if x, ok := x.Value.(*ScVal_I32); ok { + return x.I32 + } + } + return 0 +} + +func (x *ScVal) GetU64() uint64 { + if x != nil { + if x, ok := x.Value.(*ScVal_U64); ok { + return x.U64 + } + } + return 0 +} + +func (x *ScVal) GetI64() int64 { + if x != nil { + if x, ok := x.Value.(*ScVal_I64); ok { + return x.I64 + } + } + return 0 +} + +func (x *ScVal) GetTimepoint() uint64 { + if x != nil { + if x, ok := x.Value.(*ScVal_Timepoint); ok { + return x.Timepoint + } + } + return 0 +} + +func (x *ScVal) GetDuration() uint64 { + if x != nil { + if x, ok := x.Value.(*ScVal_Duration); ok { + return x.Duration + } + } + return 0 +} + +func (x *ScVal) GetU128() *UInt128Parts { + if x != nil { + if x, ok := x.Value.(*ScVal_U128); ok { + return x.U128 + } + } + return nil +} + +func (x *ScVal) GetI128() *Int128Parts { + if x != nil { + if x, ok := x.Value.(*ScVal_I128); ok { + return x.I128 + } + } + return nil +} + +func (x *ScVal) GetU256() *UInt256Parts { + if x != nil { + if x, ok := x.Value.(*ScVal_U256); ok { + return x.U256 + } + } + return nil +} + +func (x *ScVal) GetI256() *Int256Parts { + if x != nil { + if x, ok := x.Value.(*ScVal_I256); ok { + return x.I256 + } + } + return nil +} + +func (x *ScVal) GetBytesVal() []byte { + if x != nil { + if x, ok := x.Value.(*ScVal_BytesVal); ok { + return x.BytesVal + } + } + return nil +} + +func (x *ScVal) GetStr() string { + if x != nil { + if x, ok := x.Value.(*ScVal_Str); ok { + return x.Str + } + } + return "" +} + +func (x *ScVal) GetSym() string { + if x != nil { + if x, ok := x.Value.(*ScVal_Sym); ok { + return x.Sym + } + } + return "" +} + +func (x *ScVal) GetVec() *ScVec { + if x != nil { + if x, ok := x.Value.(*ScVal_Vec); ok { + return x.Vec + } + } + return nil +} + +func (x *ScVal) GetMap() *ScMap { + if x != nil { + if x, ok := x.Value.(*ScVal_Map); ok { + return x.Map + } + } + return nil +} + +func (x *ScVal) GetAddress() *ScAddress { + if x != nil { + if x, ok := x.Value.(*ScVal_Address); ok { + return x.Address + } + } + return nil +} + +func (x *ScVal) GetContractInstance() *ScContractInstance { + if x != nil { + if x, ok := x.Value.(*ScVal_ContractInstance); ok { + return x.ContractInstance + } + } + return nil +} + +func (x *ScVal) GetLedgerKeyContractInstance() *Void { + if x != nil { + if x, ok := x.Value.(*ScVal_LedgerKeyContractInstance); ok { + return x.LedgerKeyContractInstance + } + } + return nil +} + +func (x *ScVal) GetNonceKey() *ScNonceKey { + if x != nil { + if x, ok := x.Value.(*ScVal_NonceKey); ok { + return x.NonceKey + } + } + return nil +} + +type isScVal_Value interface { + isScVal_Value() +} + +type ScVal_B struct { + B bool `protobuf:"varint,1,opt,name=b,proto3,oneof"` +} + +type ScVal_VoidVal struct { + VoidVal *Void `protobuf:"bytes,2,opt,name=void_val,json=voidVal,proto3,oneof"` +} + +type ScVal_Error struct { + Error *ScError `protobuf:"bytes,3,opt,name=error,proto3,oneof"` +} + +type ScVal_U32 struct { + U32 uint32 `protobuf:"varint,4,opt,name=u32,proto3,oneof"` +} + +type ScVal_I32 struct { + I32 int32 `protobuf:"varint,5,opt,name=i32,proto3,oneof"` +} + +type ScVal_U64 struct { + U64 uint64 `protobuf:"varint,6,opt,name=u64,proto3,oneof"` +} + +type ScVal_I64 struct { + I64 int64 `protobuf:"varint,7,opt,name=i64,proto3,oneof"` +} + +type ScVal_Timepoint struct { + Timepoint uint64 `protobuf:"varint,8,opt,name=timepoint,proto3,oneof"` +} + +type ScVal_Duration struct { + Duration uint64 `protobuf:"varint,9,opt,name=duration,proto3,oneof"` +} + +type ScVal_U128 struct { + U128 *UInt128Parts `protobuf:"bytes,10,opt,name=u128,proto3,oneof"` +} + +type ScVal_I128 struct { + I128 *Int128Parts `protobuf:"bytes,11,opt,name=i128,proto3,oneof"` +} + +type ScVal_U256 struct { + U256 *UInt256Parts `protobuf:"bytes,12,opt,name=u256,proto3,oneof"` +} + +type ScVal_I256 struct { + I256 *Int256Parts `protobuf:"bytes,13,opt,name=i256,proto3,oneof"` +} + +type ScVal_BytesVal struct { + BytesVal []byte `protobuf:"bytes,14,opt,name=bytes_val,json=bytesVal,proto3,oneof"` +} + +type ScVal_Str struct { + Str string `protobuf:"bytes,15,opt,name=str,proto3,oneof"` +} + +type ScVal_Sym struct { + Sym string `protobuf:"bytes,16,opt,name=sym,proto3,oneof"` +} + +type ScVal_Vec struct { + Vec *ScVec `protobuf:"bytes,17,opt,name=vec,proto3,oneof"` +} + +type ScVal_Map struct { + Map *ScMap `protobuf:"bytes,18,opt,name=map,proto3,oneof"` +} + +type ScVal_Address struct { + Address *ScAddress `protobuf:"bytes,19,opt,name=address,proto3,oneof"` +} + +type ScVal_ContractInstance struct { + ContractInstance *ScContractInstance `protobuf:"bytes,20,opt,name=contract_instance,json=contractInstance,proto3,oneof"` +} + +type ScVal_LedgerKeyContractInstance struct { + LedgerKeyContractInstance *Void `protobuf:"bytes,21,opt,name=ledger_key_contract_instance,json=ledgerKeyContractInstance,proto3,oneof"` +} + +type ScVal_NonceKey struct { + NonceKey *ScNonceKey `protobuf:"bytes,22,opt,name=nonce_key,json=nonceKey,proto3,oneof"` +} + +func (*ScVal_B) isScVal_Value() {} + +func (*ScVal_VoidVal) isScVal_Value() {} + +func (*ScVal_Error) isScVal_Value() {} + +func (*ScVal_U32) isScVal_Value() {} + +func (*ScVal_I32) isScVal_Value() {} + +func (*ScVal_U64) isScVal_Value() {} + +func (*ScVal_I64) isScVal_Value() {} + +func (*ScVal_Timepoint) isScVal_Value() {} + +func (*ScVal_Duration) isScVal_Value() {} + +func (*ScVal_U128) isScVal_Value() {} + +func (*ScVal_I128) isScVal_Value() {} + +func (*ScVal_U256) isScVal_Value() {} + +func (*ScVal_I256) isScVal_Value() {} + +func (*ScVal_BytesVal) isScVal_Value() {} + +func (*ScVal_Str) isScVal_Value() {} + +func (*ScVal_Sym) isScVal_Value() {} + +func (*ScVal_Vec) isScVal_Value() {} + +func (*ScVal_Map) isScVal_Value() {} + +func (*ScVal_Address) isScVal_Value() {} + +func (*ScVal_ContractInstance) isScVal_Value() {} + +func (*ScVal_LedgerKeyContractInstance) isScVal_Value() {} + +func (*ScVal_NonceKey) isScVal_Value() {} + +var File_capabilities_blockchain_stellar_v1alpha_scval_proto protoreflect.FileDescriptor + +const file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDesc = "" + + "\n" + + "3capabilities/blockchain/stellar/v1alpha/scval.proto\x12'capabilities.blockchain.stellar.v1alpha\".\n" + + "\fUInt128Parts\x12\x0e\n" + + "\x02hi\x18\x01 \x01(\x04R\x02hi\x12\x0e\n" + + "\x02lo\x18\x02 \x01(\x04R\x02lo\"-\n" + + "\vInt128Parts\x12\x0e\n" + + "\x02hi\x18\x01 \x01(\x03R\x02hi\x12\x0e\n" + + "\x02lo\x18\x02 \x01(\x04R\x02lo\"b\n" + + "\fUInt256Parts\x12\x13\n" + + "\x05hi_hi\x18\x01 \x01(\x04R\x04hiHi\x12\x13\n" + + "\x05hi_lo\x18\x02 \x01(\x04R\x04hiLo\x12\x13\n" + + "\x05lo_hi\x18\x03 \x01(\x04R\x04loHi\x12\x13\n" + + "\x05lo_lo\x18\x04 \x01(\x04R\x04loLo\"a\n" + + "\vInt256Parts\x12\x13\n" + + "\x05hi_hi\x18\x01 \x01(\x03R\x04hiHi\x12\x13\n" + + "\x05hi_lo\x18\x02 \x01(\x04R\x04hiLo\x12\x13\n" + + "\x05lo_hi\x18\x03 \x01(\x04R\x04loHi\x12\x13\n" + + "\x05lo_lo\x18\x04 \x01(\x04R\x04loLo\"\x86\x05\n" + + "\aScError\x12I\n" + + "\x04type\x18\x01 \x01(\x0e25.capabilities.blockchain.stellar.v1alpha.ScError.TypeR\x04type\x12%\n" + + "\rcontract_code\x18\x02 \x01(\rH\x00R\fcontractCode\x12K\n" + + "\x04code\x18\x03 \x01(\x0e25.capabilities.blockchain.stellar.v1alpha.ScError.CodeH\x00R\x04code\"\xa8\x01\n" + + "\x04Type\x12\x10\n" + + "\fSCE_CONTRACT\x10\x00\x12\x0f\n" + + "\vSCE_WASM_VM\x10\x01\x12\x0f\n" + + "\vSCE_CONTEXT\x10\x02\x12\x0f\n" + + "\vSCE_STORAGE\x10\x03\x12\x0e\n" + + "\n" + + "SCE_OBJECT\x10\x04\x12\x0e\n" + + "\n" + + "SCE_CRYPTO\x10\x05\x12\x0e\n" + + "\n" + + "SCE_EVENTS\x10\x06\x12\x0e\n" + + "\n" + + "SCE_BUDGET\x10\a\x12\r\n" + + "\tSCE_VALUE\x10\b\x12\f\n" + + "\bSCE_AUTH\x10\t\"\xfc\x01\n" + + "\x04Code\x12\x15\n" + + "\x11SCEC_ARITH_DOMAIN\x10\x00\x12\x15\n" + + "\x11SCEC_INDEX_BOUNDS\x10\x01\x12\x16\n" + + "\x12SCEC_INVALID_INPUT\x10\x02\x12\x16\n" + + "\x12SCEC_MISSING_VALUE\x10\x03\x12\x17\n" + + "\x13SCEC_EXISTING_VALUE\x10\x04\x12\x17\n" + + "\x13SCEC_EXCEEDED_LIMIT\x10\x05\x12\x17\n" + + "\x13SCEC_INVALID_ACTION\x10\x06\x12\x17\n" + + "\x13SCEC_INTERNAL_ERROR\x10\a\x12\x18\n" + + "\x14SCEC_UNEXPECTED_TYPE\x10\b\x12\x18\n" + + "\x14SCEC_UNEXPECTED_SIZE\x10\tB\x12\n" + + "\x10code_or_contract\"?\n" + + "\x13MuxedEd25519Account\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x18\n" + + "\aed25519\x18\x02 \x01(\fR\aed25519\"$\n" + + "\x12ClaimableBalanceId\x12\x0e\n" + + "\x02v0\x18\x01 \x01(\fR\x02v0\"\xde\x02\n" + + "\tScAddress\x12\x1f\n" + + "\n" + + "account_id\x18\x01 \x01(\fH\x00R\taccountId\x12!\n" + + "\vcontract_id\x18\x02 \x01(\fH\x00R\n" + + "contractId\x12c\n" + + "\rmuxed_account\x18\x03 \x01(\v2<.capabilities.blockchain.stellar.v1alpha.MuxedEd25519AccountH\x00R\fmuxedAccount\x12o\n" + + "\x14claimable_balance_id\x18\x04 \x01(\v2;.capabilities.blockchain.stellar.v1alpha.ClaimableBalanceIdH\x00R\x12claimableBalanceId\x12,\n" + + "\x11liquidity_pool_id\x18\x05 \x01(\fH\x00R\x0fliquidityPoolIdB\t\n" + + "\aaddress\"b\n" + + "\x12ContractExecutable\x12\x1d\n" + + "\twasm_hash\x18\x01 \x01(\fH\x00R\bwasmHash\x12%\n" + + "\rstellar_asset\x18\x02 \x01(\bH\x00R\fstellarAssetB\x06\n" + + "\x04type\"\xc0\x01\n" + + "\x12ScContractInstance\x12[\n" + + "\n" + + "executable\x18\x01 \x01(\v2;.capabilities.blockchain.stellar.v1alpha.ContractExecutableR\n" + + "executable\x12M\n" + + "\astorage\x18\x02 \x03(\v23.capabilities.blockchain.stellar.v1alpha.ScMapEntryR\astorage\"\"\n" + + "\n" + + "ScNonceKey\x12\x14\n" + + "\x05nonce\x18\x01 \x01(\x03R\x05nonce\"\x90\x01\n" + + "\n" + + "ScMapEntry\x12@\n" + + "\x03key\x18\x01 \x01(\v2..capabilities.blockchain.stellar.v1alpha.ScValR\x03key\x12@\n" + + "\x03val\x18\x02 \x01(\v2..capabilities.blockchain.stellar.v1alpha.ScValR\x03val\"O\n" + + "\x05ScVec\x12F\n" + + "\x06values\x18\x01 \x03(\v2..capabilities.blockchain.stellar.v1alpha.ScValR\x06values\"V\n" + + "\x05ScMap\x12M\n" + + "\aentries\x18\x01 \x03(\v23.capabilities.blockchain.stellar.v1alpha.ScMapEntryR\aentries\"\x06\n" + + "\x04Void\"\xc7\t\n" + + "\x05ScVal\x12\x0e\n" + + "\x01b\x18\x01 \x01(\bH\x00R\x01b\x12J\n" + + "\bvoid_val\x18\x02 \x01(\v2-.capabilities.blockchain.stellar.v1alpha.VoidH\x00R\avoidVal\x12H\n" + + "\x05error\x18\x03 \x01(\v20.capabilities.blockchain.stellar.v1alpha.ScErrorH\x00R\x05error\x12\x12\n" + + "\x03u32\x18\x04 \x01(\rH\x00R\x03u32\x12\x12\n" + + "\x03i32\x18\x05 \x01(\x05H\x00R\x03i32\x12\x12\n" + + "\x03u64\x18\x06 \x01(\x04H\x00R\x03u64\x12\x12\n" + + "\x03i64\x18\a \x01(\x03H\x00R\x03i64\x12\x1e\n" + + "\ttimepoint\x18\b \x01(\x04H\x00R\ttimepoint\x12\x1c\n" + + "\bduration\x18\t \x01(\x04H\x00R\bduration\x12K\n" + + "\x04u128\x18\n" + + " \x01(\v25.capabilities.blockchain.stellar.v1alpha.UInt128PartsH\x00R\x04u128\x12J\n" + + "\x04i128\x18\v \x01(\v24.capabilities.blockchain.stellar.v1alpha.Int128PartsH\x00R\x04i128\x12K\n" + + "\x04u256\x18\f \x01(\v25.capabilities.blockchain.stellar.v1alpha.UInt256PartsH\x00R\x04u256\x12J\n" + + "\x04i256\x18\r \x01(\v24.capabilities.blockchain.stellar.v1alpha.Int256PartsH\x00R\x04i256\x12\x1d\n" + + "\tbytes_val\x18\x0e \x01(\fH\x00R\bbytesVal\x12\x12\n" + + "\x03str\x18\x0f \x01(\tH\x00R\x03str\x12\x12\n" + + "\x03sym\x18\x10 \x01(\tH\x00R\x03sym\x12B\n" + + "\x03vec\x18\x11 \x01(\v2..capabilities.blockchain.stellar.v1alpha.ScVecH\x00R\x03vec\x12B\n" + + "\x03map\x18\x12 \x01(\v2..capabilities.blockchain.stellar.v1alpha.ScMapH\x00R\x03map\x12N\n" + + "\aaddress\x18\x13 \x01(\v22.capabilities.blockchain.stellar.v1alpha.ScAddressH\x00R\aaddress\x12j\n" + + "\x11contract_instance\x18\x14 \x01(\v2;.capabilities.blockchain.stellar.v1alpha.ScContractInstanceH\x00R\x10contractInstance\x12p\n" + + "\x1cledger_key_contract_instance\x18\x15 \x01(\v2-.capabilities.blockchain.stellar.v1alpha.VoidH\x00R\x19ledgerKeyContractInstance\x12R\n" + + "\tnonce_key\x18\x16 \x01(\v23.capabilities.blockchain.stellar.v1alpha.ScNonceKeyH\x00R\bnonceKeyB\a\n" + + "\x05valueB]Z[github.com/smartcontractkit/chainlink-protos/cre/go/capabilities/blockchain/stellar/v1alphab\x06proto3" + +var ( + file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescOnce sync.Once + file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescData []byte +) + +func file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescGZIP() []byte { + file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescOnce.Do(func() { + file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDesc), len(file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDesc))) + }) + return file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDescData +} + +var file_capabilities_blockchain_stellar_v1alpha_scval_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_capabilities_blockchain_stellar_v1alpha_scval_proto_goTypes = []any{ + (ScError_Type)(0), // 0: capabilities.blockchain.stellar.v1alpha.ScError.Type + (ScError_Code)(0), // 1: capabilities.blockchain.stellar.v1alpha.ScError.Code + (*UInt128Parts)(nil), // 2: capabilities.blockchain.stellar.v1alpha.UInt128Parts + (*Int128Parts)(nil), // 3: capabilities.blockchain.stellar.v1alpha.Int128Parts + (*UInt256Parts)(nil), // 4: capabilities.blockchain.stellar.v1alpha.UInt256Parts + (*Int256Parts)(nil), // 5: capabilities.blockchain.stellar.v1alpha.Int256Parts + (*ScError)(nil), // 6: capabilities.blockchain.stellar.v1alpha.ScError + (*MuxedEd25519Account)(nil), // 7: capabilities.blockchain.stellar.v1alpha.MuxedEd25519Account + (*ClaimableBalanceId)(nil), // 8: capabilities.blockchain.stellar.v1alpha.ClaimableBalanceId + (*ScAddress)(nil), // 9: capabilities.blockchain.stellar.v1alpha.ScAddress + (*ContractExecutable)(nil), // 10: capabilities.blockchain.stellar.v1alpha.ContractExecutable + (*ScContractInstance)(nil), // 11: capabilities.blockchain.stellar.v1alpha.ScContractInstance + (*ScNonceKey)(nil), // 12: capabilities.blockchain.stellar.v1alpha.ScNonceKey + (*ScMapEntry)(nil), // 13: capabilities.blockchain.stellar.v1alpha.ScMapEntry + (*ScVec)(nil), // 14: capabilities.blockchain.stellar.v1alpha.ScVec + (*ScMap)(nil), // 15: capabilities.blockchain.stellar.v1alpha.ScMap + (*Void)(nil), // 16: capabilities.blockchain.stellar.v1alpha.Void + (*ScVal)(nil), // 17: capabilities.blockchain.stellar.v1alpha.ScVal +} +var file_capabilities_blockchain_stellar_v1alpha_scval_proto_depIdxs = []int32{ + 0, // 0: capabilities.blockchain.stellar.v1alpha.ScError.type:type_name -> capabilities.blockchain.stellar.v1alpha.ScError.Type + 1, // 1: capabilities.blockchain.stellar.v1alpha.ScError.code:type_name -> capabilities.blockchain.stellar.v1alpha.ScError.Code + 7, // 2: capabilities.blockchain.stellar.v1alpha.ScAddress.muxed_account:type_name -> capabilities.blockchain.stellar.v1alpha.MuxedEd25519Account + 8, // 3: capabilities.blockchain.stellar.v1alpha.ScAddress.claimable_balance_id:type_name -> capabilities.blockchain.stellar.v1alpha.ClaimableBalanceId + 10, // 4: capabilities.blockchain.stellar.v1alpha.ScContractInstance.executable:type_name -> capabilities.blockchain.stellar.v1alpha.ContractExecutable + 13, // 5: capabilities.blockchain.stellar.v1alpha.ScContractInstance.storage:type_name -> capabilities.blockchain.stellar.v1alpha.ScMapEntry + 17, // 6: capabilities.blockchain.stellar.v1alpha.ScMapEntry.key:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 17, // 7: capabilities.blockchain.stellar.v1alpha.ScMapEntry.val:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 17, // 8: capabilities.blockchain.stellar.v1alpha.ScVec.values:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 13, // 9: capabilities.blockchain.stellar.v1alpha.ScMap.entries:type_name -> capabilities.blockchain.stellar.v1alpha.ScMapEntry + 16, // 10: capabilities.blockchain.stellar.v1alpha.ScVal.void_val:type_name -> capabilities.blockchain.stellar.v1alpha.Void + 6, // 11: capabilities.blockchain.stellar.v1alpha.ScVal.error:type_name -> capabilities.blockchain.stellar.v1alpha.ScError + 2, // 12: capabilities.blockchain.stellar.v1alpha.ScVal.u128:type_name -> capabilities.blockchain.stellar.v1alpha.UInt128Parts + 3, // 13: capabilities.blockchain.stellar.v1alpha.ScVal.i128:type_name -> capabilities.blockchain.stellar.v1alpha.Int128Parts + 4, // 14: capabilities.blockchain.stellar.v1alpha.ScVal.u256:type_name -> capabilities.blockchain.stellar.v1alpha.UInt256Parts + 5, // 15: capabilities.blockchain.stellar.v1alpha.ScVal.i256:type_name -> capabilities.blockchain.stellar.v1alpha.Int256Parts + 14, // 16: capabilities.blockchain.stellar.v1alpha.ScVal.vec:type_name -> capabilities.blockchain.stellar.v1alpha.ScVec + 15, // 17: capabilities.blockchain.stellar.v1alpha.ScVal.map:type_name -> capabilities.blockchain.stellar.v1alpha.ScMap + 9, // 18: capabilities.blockchain.stellar.v1alpha.ScVal.address:type_name -> capabilities.blockchain.stellar.v1alpha.ScAddress + 11, // 19: capabilities.blockchain.stellar.v1alpha.ScVal.contract_instance:type_name -> capabilities.blockchain.stellar.v1alpha.ScContractInstance + 16, // 20: capabilities.blockchain.stellar.v1alpha.ScVal.ledger_key_contract_instance:type_name -> capabilities.blockchain.stellar.v1alpha.Void + 12, // 21: capabilities.blockchain.stellar.v1alpha.ScVal.nonce_key:type_name -> capabilities.blockchain.stellar.v1alpha.ScNonceKey + 22, // [22:22] is the sub-list for method output_type + 22, // [22:22] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name +} + +func init() { file_capabilities_blockchain_stellar_v1alpha_scval_proto_init() } +func file_capabilities_blockchain_stellar_v1alpha_scval_proto_init() { + if File_capabilities_blockchain_stellar_v1alpha_scval_proto != nil { + return + } + file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[4].OneofWrappers = []any{ + (*ScError_ContractCode)(nil), + (*ScError_Code_)(nil), + } + file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[7].OneofWrappers = []any{ + (*ScAddress_AccountId)(nil), + (*ScAddress_ContractId)(nil), + (*ScAddress_MuxedAccount)(nil), + (*ScAddress_ClaimableBalanceId)(nil), + (*ScAddress_LiquidityPoolId)(nil), + } + file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[8].OneofWrappers = []any{ + (*ContractExecutable_WasmHash)(nil), + (*ContractExecutable_StellarAsset)(nil), + } + file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes[15].OneofWrappers = []any{ + (*ScVal_B)(nil), + (*ScVal_VoidVal)(nil), + (*ScVal_Error)(nil), + (*ScVal_U32)(nil), + (*ScVal_I32)(nil), + (*ScVal_U64)(nil), + (*ScVal_I64)(nil), + (*ScVal_Timepoint)(nil), + (*ScVal_Duration)(nil), + (*ScVal_U128)(nil), + (*ScVal_I128)(nil), + (*ScVal_U256)(nil), + (*ScVal_I256)(nil), + (*ScVal_BytesVal)(nil), + (*ScVal_Str)(nil), + (*ScVal_Sym)(nil), + (*ScVal_Vec)(nil), + (*ScVal_Map)(nil), + (*ScVal_Address)(nil), + (*ScVal_ContractInstance)(nil), + (*ScVal_LedgerKeyContractInstance)(nil), + (*ScVal_NonceKey)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDesc), len(file_capabilities_blockchain_stellar_v1alpha_scval_proto_rawDesc)), + NumEnums: 2, + NumMessages: 16, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_capabilities_blockchain_stellar_v1alpha_scval_proto_goTypes, + DependencyIndexes: file_capabilities_blockchain_stellar_v1alpha_scval_proto_depIdxs, + EnumInfos: file_capabilities_blockchain_stellar_v1alpha_scval_proto_enumTypes, + MessageInfos: file_capabilities_blockchain_stellar_v1alpha_scval_proto_msgTypes, + }.Build() + File_capabilities_blockchain_stellar_v1alpha_scval_proto = out.File + file_capabilities_blockchain_stellar_v1alpha_scval_proto_goTypes = nil + file_capabilities_blockchain_stellar_v1alpha_scval_proto_depIdxs = nil +} diff --git a/pkg/capabilities/v2/chain-capabilities/stellar/server/client_server_gen.go b/pkg/capabilities/v2/chain-capabilities/stellar/server/client_server_gen.go new file mode 100644 index 0000000000..4bb2ac73fa --- /dev/null +++ b/pkg/capabilities/v2/chain-capabilities/stellar/server/client_server_gen.go @@ -0,0 +1,178 @@ +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/protoc, DO NOT EDIT. + +package server + +import ( + "context" + "fmt" + "strconv" + "time" + + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar" + "google.golang.org/protobuf/types/known/emptypb" + + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + caperrors "github.com/smartcontractkit/chainlink-common/pkg/capabilities/errors" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" +) + +// Avoid unused imports if there is configuration type +var _ = emptypb.Empty{} + +type ClientCapability interface { + GetLatestLedger(ctx context.Context, metadata capabilities.RequestMetadata, input *stellar.GetLatestLedgerRequest) (*capabilities.ResponseAndMetadata[*stellar.GetLatestLedgerResponse], caperrors.Error) + + ReadContract(ctx context.Context, metadata capabilities.RequestMetadata, input *stellar.ReadContractRequest) (*capabilities.ResponseAndMetadata[*stellar.ReadContractResponse], caperrors.Error) + + WriteReport(ctx context.Context, metadata capabilities.RequestMetadata, input *stellar.WriteReportRequest) (*capabilities.ResponseAndMetadata[*stellar.WriteReportReply], caperrors.Error) + + ChainSelector() uint64 + + Start(ctx context.Context) error + Close() error + HealthReport() map[string]error + Name() string + Description() string + Ready() error + Initialise(ctx context.Context, dependencies core.StandardCapabilitiesDependencies) error +} + +func NewClientServer(capability ClientCapability) *ClientServer { + stopCh := make(chan struct{}) + return &ClientServer{ + clientCapability: clientCapability{ClientCapability: capability, stopCh: stopCh}, + stopCh: stopCh, + } +} + +type ClientServer struct { + clientCapability + capabilityRegistry core.CapabilitiesRegistry + stopCh chan struct{} +} + +func (c *ClientServer) Initialise(ctx context.Context, dependencies core.StandardCapabilitiesDependencies) error { + if err := c.ClientCapability.Initialise(ctx, dependencies); err != nil { + return fmt.Errorf("error when initializing capability: %w", err) + } + + c.capabilityRegistry = dependencies.CapabilityRegistry + + if err := dependencies.CapabilityRegistry.Add(ctx, &clientCapability{ + ClientCapability: c.ClientCapability, + }); err != nil { + return fmt.Errorf("error when adding %s to the registry: %w", "stellar"+":ChainSelector:"+strconv.FormatUint(c.ChainSelector(), 10)+"@1.0.0", err) + } + + return nil +} + +func (c *ClientServer) Close() error { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + if c.capabilityRegistry != nil { + if err := c.capabilityRegistry.Remove(ctx, "stellar"+":ChainSelector:"+strconv.FormatUint(c.ChainSelector(), 10)+"@1.0.0"); err != nil { + return err + } + } + + if c.stopCh != nil { + close(c.stopCh) + } + + return c.clientCapability.Close() +} + +func (c *ClientServer) Infos(ctx context.Context) ([]capabilities.CapabilityInfo, error) { + info, err := c.clientCapability.Info(ctx) + if err != nil { + return nil, err + } + return []capabilities.CapabilityInfo{info}, nil +} + +type clientCapability struct { + ClientCapability + stopCh chan struct{} +} + +func (c *clientCapability) Info(ctx context.Context) (capabilities.CapabilityInfo, error) { + // Maybe we do need to split it out, even if the user doesn't see it + return capabilities.NewCapabilityInfo("stellar"+":ChainSelector:"+strconv.FormatUint(c.ChainSelector(), 10)+"@1.0.0", capabilities.CapabilityTypeCombined, c.ClientCapability.Description()) +} + +var _ capabilities.ExecutableAndTriggerCapability = (*clientCapability)(nil) + +const ClientID = "stellar@1.0.0" + +func (c *clientCapability) RegisterTrigger(ctx context.Context, request capabilities.TriggerRegistrationRequest) (<-chan capabilities.TriggerResponse, error) { + return nil, fmt.Errorf("trigger %s not found", request.Method) +} + +func (c *clientCapability) UnregisterTrigger(ctx context.Context, request capabilities.TriggerRegistrationRequest) error { + return fmt.Errorf("trigger %s not found", request.Method) +} + +func (c *clientCapability) AckEvent(ctx context.Context, triggerId string, eventId string, method string) error { + return fmt.Errorf("trigger %s not found", method) +} + +func (c *clientCapability) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error { + return nil +} + +func (c *clientCapability) UnregisterFromWorkflow(ctx context.Context, request capabilities.UnregisterFromWorkflowRequest) error { + return nil +} + +func (c *clientCapability) Execute(ctx context.Context, request capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { + response := capabilities.CapabilityResponse{} + ctx = request.Metadata.ContextWithCRE(ctx) + switch request.Method { + case "GetLatestLedger": + input := &stellar.GetLatestLedgerRequest{} + config := &emptypb.Empty{} + wrapped := func(ctx context.Context, metadata capabilities.RequestMetadata, input *stellar.GetLatestLedgerRequest, _ *emptypb.Empty) (*stellar.GetLatestLedgerResponse, capabilities.ResponseMetadata, *capabilities.OCRAttestation, error) { + output, err := c.ClientCapability.GetLatestLedger(ctx, metadata, input) + if err != nil { + return nil, capabilities.ResponseMetadata{}, nil, err + } + if output == nil { + return nil, capabilities.ResponseMetadata{}, nil, fmt.Errorf("output and error is nil for method GetLatestLedger(..) (if output is nil error must be present)") + } + return output.Response, output.ResponseMetadata, output.OCRAttestation, err + } + return capabilities.Execute(ctx, request, input, config, wrapped) + case "ReadContract": + input := &stellar.ReadContractRequest{} + config := &emptypb.Empty{} + wrapped := func(ctx context.Context, metadata capabilities.RequestMetadata, input *stellar.ReadContractRequest, _ *emptypb.Empty) (*stellar.ReadContractResponse, capabilities.ResponseMetadata, *capabilities.OCRAttestation, error) { + output, err := c.ClientCapability.ReadContract(ctx, metadata, input) + if err != nil { + return nil, capabilities.ResponseMetadata{}, nil, err + } + if output == nil { + return nil, capabilities.ResponseMetadata{}, nil, fmt.Errorf("output and error is nil for method ReadContract(..) (if output is nil error must be present)") + } + return output.Response, output.ResponseMetadata, output.OCRAttestation, err + } + return capabilities.Execute(ctx, request, input, config, wrapped) + case "WriteReport": + input := &stellar.WriteReportRequest{} + config := &emptypb.Empty{} + wrapped := func(ctx context.Context, metadata capabilities.RequestMetadata, input *stellar.WriteReportRequest, _ *emptypb.Empty) (*stellar.WriteReportReply, capabilities.ResponseMetadata, *capabilities.OCRAttestation, error) { + output, err := c.ClientCapability.WriteReport(ctx, metadata, input) + if err != nil { + return nil, capabilities.ResponseMetadata{}, nil, err + } + if output == nil { + return nil, capabilities.ResponseMetadata{}, nil, fmt.Errorf("output and error is nil for method WriteReport(..) (if output is nil error must be present)") + } + return output.Response, output.ResponseMetadata, output.OCRAttestation, err + } + return capabilities.Execute(ctx, request, input, config, wrapped) + default: + return response, fmt.Errorf("method %s not found", request.Method) + } +} diff --git a/pkg/capabilities/v2/gen/main.go b/pkg/capabilities/v2/gen/main.go index ad60118cba..a93eb51b73 100644 --- a/pkg/capabilities/v2/gen/main.go +++ b/pkg/capabilities/v2/gen/main.go @@ -10,17 +10,42 @@ import ( "github.com/smartcontractkit/chainlink-protos/cre/go/installer/pkg" ) +type links []string + +func (l *links) String() string { return strings.Join(*l, ",") } +func (l *links) Set(v string) error { + *l = append(*l, v) + return nil +} + +func parseLink(s string) (proto, goPkg string) { + proto, goPkg, _ = strings.Cut(s, "=") + return +} + func main() { gen := &pkg.ProtocGen{Plugins: []pkg.Plugin{pkg.GoPlugin}} capDir := flag.String("pkg", "", "the go package to generate in") file := flag.String("file", "", "the go file to generate from") defaultPathToV2 := filepath.Join("..", "..") - pathToV2 := flag.String("pathToV2", defaultPathToV2, "How to get to the ") + pathToV2 := flag.String("pathToV2", defaultPathToV2, "path to the v2 directory") + var extraLinks links + var genLinks links + flag.Var(&extraLinks, "link", "proto=gopkg mapping added to the main generation (no separate generation)") + flag.Var(&genLinks, "link-and-generate", "proto=gopkg; add mapping to main generation and also generate the proto into its sub-package dir") flag.Parse() gen.Plugins = []pkg.Plugin{pkg.GoPlugin, {Name: "cre", Path: filepath.Join(*pathToV2, "protoc")}} gen.LinkPackage(pkg.Packages{Go: *capDir, Proto: *file}) + for _, l := range extraLinks { + proto, goPkg := parseLink(l) + gen.LinkPackage(pkg.Packages{Proto: proto, Go: goPkg}) + } + for _, l := range genLinks { + proto, goPkg := parseLink(l) + gen.LinkPackage(pkg.Packages{Proto: proto, Go: goPkg}) + } if err := gen.GenerateFile(*file, "."); err != nil { log.Fatal("Error generating file:", err) @@ -35,4 +60,25 @@ func main() { if err := os.RemoveAll(pathParts[0]); err != nil { log.Fatal("Error removing path:", err) } + + for _, l := range genLinks { + proto, goPkg := parseLink(l) + subGen := &pkg.ProtocGen{Plugins: []pkg.Plugin{pkg.GoPlugin}} + subGen.LinkPackage(pkg.Packages{Proto: proto, Go: goPkg}) + if err := subGen.GenerateFile(proto, "."); err != nil { + log.Fatal("Error generating linked file:", err) + } + relPkg := strings.TrimPrefix(goPkg, *capDir+"/") + subPb := strings.Replace(proto, ".proto", ".pb.go", 1) + if err := os.MkdirAll(relPkg, 0o755); err != nil { + log.Fatal("Error creating sub-package dir:", err) + } + if err := os.Rename(subPb, filepath.Join(relPkg, filepath.Base(subPb))); err != nil { + log.Fatal("Error renaming linked file:", err) + } + subPathParts := strings.Split(proto, string(os.PathSeparator)) + if err := os.RemoveAll(subPathParts[0]); err != nil { + log.Fatal("Error removing path:", err) + } + } } diff --git a/pkg/chains/stellar/generate/main.go b/pkg/chains/stellar/generate/main.go index fa793b94fe..50be7f299d 100644 --- a/pkg/chains/stellar/generate/main.go +++ b/pkg/chains/stellar/generate/main.go @@ -1,10 +1,18 @@ package main -import "github.com/smartcontractkit/chainlink-protos/cre/go/installer/pkg" +import ( + "github.com/smartcontractkit/chainlink-protos/cre/go/installer/pkg" +) + +const scvalGoPackage = "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar/scval" func main() { gen := &pkg.ProtocGen{Plugins: []pkg.Plugin{pkg.GoPlugin, {Name: "go-grpc"}}} gen.AddSourceDirectories("../..", ".") + gen.LinkPackage(pkg.Packages{ + Proto: "capabilities/blockchain/stellar/v1alpha/scval.proto", + Go: scvalGoPackage, + }) if err := gen.GenerateFile("stellar.proto", "."); err != nil { panic(err) } diff --git a/pkg/chains/stellar/proto_helpers.go b/pkg/chains/stellar/proto_helpers.go index 31d87399ea..56b431f9fc 100644 --- a/pkg/chains/stellar/proto_helpers.go +++ b/pkg/chains/stellar/proto_helpers.go @@ -1,11 +1,18 @@ package stellar import ( + "bytes" "encoding/base64" "encoding/hex" "errors" "fmt" + "google.golang.org/protobuf/proto" + + "github.com/stellar/go-stellar-sdk/xdr" + + v1alpha "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar/scval" + "github.com/smartcontractkit/chainlink-common/pkg/types/chains/stellar" ) @@ -172,3 +179,268 @@ func ConvertGetLatestLedgerResponseFromProto(p *GetLatestLedgerResponse) (stella LedgerMetadataXDR: base64.StdEncoding.EncodeToString(p.GetLedgerMetadataXdr()), }, nil } + +// ============================================================ +// ReadContract converters +// ============================================================ + +// xdrScValToProto XDR-encodes an xdr.ScVal to binary, then wraps the bytes in a +// proto ScVal with the bytes_val field (SCV_BYTES transport container). +// Both the LOOP client and server unwrap using protoScValToXDR. +func xdrScValToProto(sv xdr.ScVal) (*v1alpha.ScVal, error) { + var buf bytes.Buffer + if _, err := xdr.Marshal(&buf, sv); err != nil { + return nil, fmt.Errorf("failed to XDR-marshal ScVal: %w", err) + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_BytesVal{BytesVal: buf.Bytes()}}, nil +} + +// protoScValToXDR unwraps a proto ScVal that was produced by xdrScValToProto and +// XDR-decodes the inner bytes back to an xdr.ScVal. +func protoScValToXDR(sv *v1alpha.ScVal) (xdr.ScVal, error) { + if sv == nil { + return xdr.ScVal{}, fmt.Errorf("proto ScVal is nil") + } + bv, ok := sv.Value.(*v1alpha.ScVal_BytesVal) + if !ok { + return xdr.ScVal{}, fmt.Errorf("proto ScVal does not carry bytes_val (got %T)", sv.Value) + } + var out xdr.ScVal + if _, err := xdr.Unmarshal(bytes.NewReader(bv.BytesVal), &out); err != nil { + return xdr.ScVal{}, fmt.Errorf("failed to XDR-unmarshal ScVal: %w", err) + } + return out, nil +} + +// ConvertReadContractRequestToProto converts a domain ReadContractRequest to the +// proto representation. Each xdr.ScVal arg is XDR-encoded and stored as +// bytes_val inside a proto ScVal for transport. +func ConvertReadContractRequestToProto(req stellar.ReadContractRequest) (*ReadContractRequest, error) { + if req.ContractID == "" { + return nil, fmt.Errorf("contract_id is required") + } + if req.Function == "" { + return nil, fmt.Errorf("function is required") + } + args := make([]*v1alpha.ScVal, 0, len(req.Args)) + for i, sv := range req.Args { + psv, err := xdrScValToProto(sv) + if err != nil { + return nil, fmt.Errorf("args[%d]: %w", i, err) + } + args = append(args, psv) + } + return &ReadContractRequest{ + ContractId: req.ContractID, + Function: req.Function, + Args: args, + LedgerSequence: req.LedgerSequence, + }, nil +} + +// ConvertReadContractRequestFromProto converts a proto ReadContractRequest to the +// domain type. Each bytes_val proto ScVal is XDR-decoded back to xdr.ScVal. +func ConvertReadContractRequestFromProto(p *ReadContractRequest) (stellar.ReadContractRequest, error) { + if p == nil { + return stellar.ReadContractRequest{}, fmt.Errorf("ReadContractRequest is nil") + } + if p.GetContractId() == "" { + return stellar.ReadContractRequest{}, fmt.Errorf("contract_id is required") + } + if p.GetFunction() == "" { + return stellar.ReadContractRequest{}, fmt.Errorf("function is required") + } + args := make([]xdr.ScVal, 0, len(p.GetArgs())) + for i, psv := range p.GetArgs() { + sv, err := protoScValToXDR(psv) + if err != nil { + return stellar.ReadContractRequest{}, fmt.Errorf("args[%d]: %w", i, err) + } + args = append(args, sv) + } + return stellar.ReadContractRequest{ + ContractID: p.GetContractId(), + Function: p.GetFunction(), + Args: args, + LedgerSequence: p.GetLedgerSequence(), + }, nil +} + +// ConvertReadContractResponseToProto converts a domain ReadContractResponse to its +// proto representation. If resp.Result is non-nil it is XDR-encoded and stored as +// bytes_val inside a proto ScVal. +func ConvertReadContractResponseToProto(resp stellar.ReadContractResponse) (*ReadContractResponse, error) { + pr := &ReadContractResponse{ + LedgerSequence: resp.LedgerSequence, + Error: resp.Error, + } + if resp.Result != nil { + psv, err := xdrScValToProto(*resp.Result) + if err != nil { + return nil, fmt.Errorf("result: %w", err) + } + pr.Result = psv + } + return pr, nil +} + +// ConvertReadContractResponseFromProto converts a proto ReadContractResponse to the +// domain type. The bytes_val proto ScVal result is XDR-decoded back to xdr.ScVal. +func ConvertReadContractResponseFromProto(p *ReadContractResponse) (stellar.ReadContractResponse, error) { + if p == nil { + return stellar.ReadContractResponse{}, fmt.Errorf("ReadContractResponse is nil") + } + resp := stellar.ReadContractResponse{ + LedgerSequence: p.GetLedgerSequence(), + Error: p.GetError(), + } + if p.GetResult() != nil { + sv, err := protoScValToXDR(p.GetResult()) + if err != nil { + return stellar.ReadContractResponse{}, fmt.Errorf("result: %w", err) + } + resp.Result = &sv + } + return resp, nil +} + +// ============================================================ +// ScVal builder helpers +// +// These helpers produce proto-marshalled ScVal bytes ([]byte) +// suitable for ReadContractRequest.Args / ReadContractResponse.Result. +// ============================================================ + +// MarshalScVal proto-marshals the given ScVal and returns the bytes, or an error. +func MarshalScVal(sv *v1alpha.ScVal) ([]byte, error) { + if sv == nil { + return nil, fmt.Errorf("ScVal is nil") + } + return proto.Marshal(sv) +} + +// UnmarshalScVal unmarshals a proto-encoded ScVal from raw bytes. +func UnmarshalScVal(raw []byte) (*v1alpha.ScVal, error) { + if len(raw) == 0 { + return nil, fmt.Errorf("raw ScVal bytes are empty") + } + sv := &v1alpha.ScVal{} + if err := proto.Unmarshal(raw, sv); err != nil { + return nil, fmt.Errorf("failed to unmarshal ScVal: %w", err) + } + return sv, nil +} + +// ScValBool creates a proto-marshalled SCV_BOOL ScVal. +func ScValBool(v bool) ([]byte, error) { + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_B{B: v}}) +} + +// ScValVoid creates a proto-marshalled SCV_VOID ScVal. +func ScValVoid() ([]byte, error) { + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_VoidVal{VoidVal: &v1alpha.Void{}}}) +} + +// ScValU32 creates a proto-marshalled SCV_U32 ScVal. +func ScValU32(v uint32) ([]byte, error) { + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_U32{U32: v}}) +} + +// ScValI32 creates a proto-marshalled SCV_I32 ScVal. +func ScValI32(v int32) ([]byte, error) { + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_I32{I32: v}}) +} + +// ScValU64 creates a proto-marshalled SCV_U64 ScVal. +func ScValU64(v uint64) ([]byte, error) { + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_U64{U64: v}}) +} + +// ScValI64 creates a proto-marshalled SCV_I64 ScVal. +func ScValI64(v int64) ([]byte, error) { + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_I64{I64: v}}) +} + +// ScValBytes creates a proto-marshalled SCV_BYTES ScVal. +func ScValBytes(v []byte) ([]byte, error) { + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_BytesVal{BytesVal: v}}) +} + +// ScValString creates a proto-marshalled SCV_STRING ScVal. +func ScValString(v string) ([]byte, error) { + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Str{Str: v}}) +} + +// ScValSymbol creates a proto-marshalled SCV_SYMBOL ScVal. +// Stellar symbols are limited to 32 characters. +func ScValSymbol(v string) ([]byte, error) { + if len(v) > 32 { + return nil, fmt.Errorf("symbol %q exceeds 32-character limit (%d chars)", v, len(v)) + } + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Sym{Sym: v}}) +} + +// ScValAddress creates a proto-marshalled SCV_ADDRESS ScVal. +func ScValAddress(addr *v1alpha.ScAddress) ([]byte, error) { + if addr == nil { + return nil, fmt.Errorf("ScAddress is nil") + } + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: addr}}) +} + +// ScValAccountAddress creates a proto-marshalled SCV_ADDRESS ScVal from a 32-byte +// Ed25519 public key (account address). +func ScValAccountAddress(pubKey []byte) ([]byte, error) { + if len(pubKey) != 32 { + return nil, fmt.Errorf("account public key must be 32 bytes, got %d", len(pubKey)) + } + return ScValAddress(&v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_AccountId{AccountId: pubKey}, + }) +} + +// ScValContractAddress creates a proto-marshalled SCV_ADDRESS ScVal from a 32-byte +// contract hash. +func ScValContractAddress(contractHash []byte) ([]byte, error) { + if len(contractHash) != 32 { + return nil, fmt.Errorf("contract hash must be 32 bytes, got %d", len(contractHash)) + } + return ScValAddress(&v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_ContractId{ContractId: contractHash}, + }) +} + +// ScValVec creates a proto-marshalled SCV_VEC ScVal from a slice of already +// proto-marshalled ScVal elements (as returned by the other helpers). +func ScValVec(elements [][]byte) ([]byte, error) { + vals := make([]*v1alpha.ScVal, 0, len(elements)) + for i, raw := range elements { + sv, err := UnmarshalScVal(raw) + if err != nil { + return nil, fmt.Errorf("element[%d]: %w", i, err) + } + vals = append(vals, sv) + } + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Vec{Vec: &v1alpha.ScVec{Values: vals}}}) +} + +// ScValMap creates a proto-marshalled SCV_MAP ScVal. keys and values must be +// slices of the same length, each element being a proto-marshalled ScVal. +func ScValMap(keys, values [][]byte) ([]byte, error) { + if len(keys) != len(values) { + return nil, fmt.Errorf("keys (%d) and values (%d) must have the same length", len(keys), len(values)) + } + entries := make([]*v1alpha.ScMapEntry, 0, len(keys)) + for i := range keys { + k, err := UnmarshalScVal(keys[i]) + if err != nil { + return nil, fmt.Errorf("key[%d]: %w", i, err) + } + v, err := UnmarshalScVal(values[i]) + if err != nil { + return nil, fmt.Errorf("value[%d]: %w", i, err) + } + entries = append(entries, &v1alpha.ScMapEntry{Key: k, Val: v}) + } + return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Map{Map: &v1alpha.ScMap{Entries: entries}}}) +} diff --git a/pkg/chains/stellar/stellar.pb.go b/pkg/chains/stellar/stellar.pb.go index a347ce5540..0044ad7741 100644 --- a/pkg/chains/stellar/stellar.pb.go +++ b/pkg/chains/stellar/stellar.pb.go @@ -7,6 +7,7 @@ package stellar import ( + scval "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar/scval" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" @@ -22,6 +23,137 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// ReadContractRequest invokes a read-only (simulation) Soroban contract function. +type ReadContractRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ContractId string `protobuf:"bytes,1,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` // Stellar contract address (C… StrKey) + Function string `protobuf:"bytes,2,opt,name=function,proto3" json:"function,omitempty"` // Soroban function name + Args []*scval.ScVal `protobuf:"bytes,3,rep,name=args,proto3" json:"args,omitempty"` // Typed Soroban arguments + // Optional: ledger to simulate against; 0 means use the latest. + LedgerSequence uint32 `protobuf:"varint,4,opt,name=ledger_sequence,json=ledgerSequence,proto3" json:"ledger_sequence,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReadContractRequest) Reset() { + *x = ReadContractRequest{} + mi := &file_stellar_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadContractRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadContractRequest) ProtoMessage() {} + +func (x *ReadContractRequest) ProtoReflect() protoreflect.Message { + mi := &file_stellar_proto_msgTypes[0] + 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 ReadContractRequest.ProtoReflect.Descriptor instead. +func (*ReadContractRequest) Descriptor() ([]byte, []int) { + return file_stellar_proto_rawDescGZIP(), []int{0} +} + +func (x *ReadContractRequest) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *ReadContractRequest) GetFunction() string { + if x != nil { + return x.Function + } + return "" +} + +func (x *ReadContractRequest) GetArgs() []*scval.ScVal { + if x != nil { + return x.Args + } + return nil +} + +func (x *ReadContractRequest) GetLedgerSequence() uint32 { + if x != nil { + return x.LedgerSequence + } + return 0 +} + +// ReadContractResponse carries the return value of the simulated call. +type ReadContractResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Result *scval.ScVal `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` // Return value (only valid when error is empty) + LedgerSequence uint32 `protobuf:"varint,2,opt,name=ledger_sequence,json=ledgerSequence,proto3" json:"ledger_sequence,omitempty"` // Ledger actually used for the simulation + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` // Non-empty on failure + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReadContractResponse) Reset() { + *x = ReadContractResponse{} + mi := &file_stellar_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadContractResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadContractResponse) ProtoMessage() {} + +func (x *ReadContractResponse) ProtoReflect() protoreflect.Message { + mi := &file_stellar_proto_msgTypes[1] + 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 ReadContractResponse.ProtoReflect.Descriptor instead. +func (*ReadContractResponse) Descriptor() ([]byte, []int) { + return file_stellar_proto_rawDescGZIP(), []int{1} +} + +func (x *ReadContractResponse) GetResult() *scval.ScVal { + if x != nil { + return x.Result + } + return nil +} + +func (x *ReadContractResponse) GetLedgerSequence() uint32 { + if x != nil { + return x.LedgerSequence + } + return 0 +} + +func (x *ReadContractResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + // GetLedgerEntriesRequest fetches ledger entries by XDR-encoded keys. type GetLedgerEntriesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -32,7 +164,7 @@ type GetLedgerEntriesRequest struct { func (x *GetLedgerEntriesRequest) Reset() { *x = GetLedgerEntriesRequest{} - mi := &file_stellar_proto_msgTypes[0] + mi := &file_stellar_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -44,7 +176,7 @@ func (x *GetLedgerEntriesRequest) String() string { func (*GetLedgerEntriesRequest) ProtoMessage() {} func (x *GetLedgerEntriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_stellar_proto_msgTypes[0] + mi := &file_stellar_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -57,7 +189,7 @@ func (x *GetLedgerEntriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLedgerEntriesRequest.ProtoReflect.Descriptor instead. func (*GetLedgerEntriesRequest) Descriptor() ([]byte, []int) { - return file_stellar_proto_rawDescGZIP(), []int{0} + return file_stellar_proto_rawDescGZIP(), []int{2} } func (x *GetLedgerEntriesRequest) GetKeys() [][]byte { @@ -83,7 +215,7 @@ type LedgerEntryResult struct { func (x *LedgerEntryResult) Reset() { *x = LedgerEntryResult{} - mi := &file_stellar_proto_msgTypes[1] + mi := &file_stellar_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -95,7 +227,7 @@ func (x *LedgerEntryResult) String() string { func (*LedgerEntryResult) ProtoMessage() {} func (x *LedgerEntryResult) ProtoReflect() protoreflect.Message { - mi := &file_stellar_proto_msgTypes[1] + mi := &file_stellar_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -108,7 +240,7 @@ func (x *LedgerEntryResult) ProtoReflect() protoreflect.Message { // Deprecated: Use LedgerEntryResult.ProtoReflect.Descriptor instead. func (*LedgerEntryResult) Descriptor() ([]byte, []int) { - return file_stellar_proto_rawDescGZIP(), []int{1} + return file_stellar_proto_rawDescGZIP(), []int{3} } func (x *LedgerEntryResult) GetKeyXdr() []byte { @@ -164,7 +296,7 @@ type GetLedgerEntriesResponse struct { func (x *GetLedgerEntriesResponse) Reset() { *x = GetLedgerEntriesResponse{} - mi := &file_stellar_proto_msgTypes[2] + mi := &file_stellar_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -176,7 +308,7 @@ func (x *GetLedgerEntriesResponse) String() string { func (*GetLedgerEntriesResponse) ProtoMessage() {} func (x *GetLedgerEntriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_stellar_proto_msgTypes[2] + mi := &file_stellar_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -189,7 +321,7 @@ func (x *GetLedgerEntriesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLedgerEntriesResponse.ProtoReflect.Descriptor instead. func (*GetLedgerEntriesResponse) Descriptor() ([]byte, []int) { - return file_stellar_proto_rawDescGZIP(), []int{2} + return file_stellar_proto_rawDescGZIP(), []int{4} } func (x *GetLedgerEntriesResponse) GetEntries() []*LedgerEntryResult { @@ -221,7 +353,7 @@ type GetLatestLedgerResponse struct { func (x *GetLatestLedgerResponse) Reset() { *x = GetLatestLedgerResponse{} - mi := &file_stellar_proto_msgTypes[3] + mi := &file_stellar_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -233,7 +365,7 @@ func (x *GetLatestLedgerResponse) String() string { func (*GetLatestLedgerResponse) ProtoMessage() {} func (x *GetLatestLedgerResponse) ProtoReflect() protoreflect.Message { - mi := &file_stellar_proto_msgTypes[3] + mi := &file_stellar_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -246,7 +378,7 @@ func (x *GetLatestLedgerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLatestLedgerResponse.ProtoReflect.Descriptor instead. func (*GetLatestLedgerResponse) Descriptor() ([]byte, []int) { - return file_stellar_proto_rawDescGZIP(), []int{3} + return file_stellar_proto_rawDescGZIP(), []int{5} } func (x *GetLatestLedgerResponse) GetHash() []byte { @@ -295,7 +427,17 @@ var File_stellar_proto protoreflect.FileDescriptor const file_stellar_proto_rawDesc = "" + "\n" + - "\rstellar.proto\x12\floop.stellar\x1a\x1bgoogle/protobuf/empty.proto\"-\n" + + "\rstellar.proto\x12\floop.stellar\x1a\x1bgoogle/protobuf/empty.proto\x1a3capabilities/blockchain/stellar/v1alpha/scval.proto\"\xbf\x01\n" + + "\x13ReadContractRequest\x12\x1f\n" + + "\vcontract_id\x18\x01 \x01(\tR\n" + + "contractId\x12\x1a\n" + + "\bfunction\x18\x02 \x01(\tR\bfunction\x12B\n" + + "\x04args\x18\x03 \x03(\v2..capabilities.blockchain.stellar.v1alpha.ScValR\x04args\x12'\n" + + "\x0fledger_sequence\x18\x04 \x01(\rR\x0eledgerSequence\"\x9d\x01\n" + + "\x14ReadContractResponse\x12F\n" + + "\x06result\x18\x01 \x01(\v2..capabilities.blockchain.stellar.v1alpha.ScValR\x06result\x12'\n" + + "\x0fledger_sequence\x18\x02 \x01(\rR\x0eledgerSequence\x12\x14\n" + + "\x05error\x18\x03 \x01(\tR\x05error\"-\n" + "\x17GetLedgerEntriesRequest\x12\x12\n" + "\x04keys\x18\x01 \x03(\fR\x04keys\"\x8b\x02\n" + "\x11LedgerEntryResult\x12\x17\n" + @@ -314,10 +456,11 @@ const file_stellar_proto_rawDesc = "" + "\bsequence\x18\x03 \x01(\rR\bsequence\x12*\n" + "\x11ledger_close_time\x18\x04 \x01(\x03R\x0fledgerCloseTime\x12*\n" + "\x11ledger_header_xdr\x18\x05 \x01(\fR\x0fledgerHeaderXdr\x12.\n" + - "\x13ledger_metadata_xdr\x18\x06 \x01(\fR\x11ledgerMetadataXdr2\xbe\x01\n" + + "\x13ledger_metadata_xdr\x18\x06 \x01(\fR\x11ledgerMetadataXdr2\x95\x02\n" + "\aStellar\x12a\n" + "\x10GetLedgerEntries\x12%.loop.stellar.GetLedgerEntriesRequest\x1a&.loop.stellar.GetLedgerEntriesResponse\x12P\n" + - "\x0fGetLatestLedger\x12\x16.google.protobuf.Empty\x1a%.loop.stellar.GetLatestLedgerResponseBAZ?github.com/smartcontractkit/chainlink-common/pkg/chains/stellarb\x06proto3" + "\x0fGetLatestLedger\x12\x16.google.protobuf.Empty\x1a%.loop.stellar.GetLatestLedgerResponse\x12U\n" + + "\fReadContract\x12!.loop.stellar.ReadContractRequest\x1a\".loop.stellar.ReadContractResponseBAZ?github.com/smartcontractkit/chainlink-common/pkg/chains/stellarb\x06proto3" var ( file_stellar_proto_rawDescOnce sync.Once @@ -331,25 +474,32 @@ func file_stellar_proto_rawDescGZIP() []byte { return file_stellar_proto_rawDescData } -var file_stellar_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_stellar_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_stellar_proto_goTypes = []any{ - (*GetLedgerEntriesRequest)(nil), // 0: loop.stellar.GetLedgerEntriesRequest - (*LedgerEntryResult)(nil), // 1: loop.stellar.LedgerEntryResult - (*GetLedgerEntriesResponse)(nil), // 2: loop.stellar.GetLedgerEntriesResponse - (*GetLatestLedgerResponse)(nil), // 3: loop.stellar.GetLatestLedgerResponse - (*emptypb.Empty)(nil), // 4: google.protobuf.Empty + (*ReadContractRequest)(nil), // 0: loop.stellar.ReadContractRequest + (*ReadContractResponse)(nil), // 1: loop.stellar.ReadContractResponse + (*GetLedgerEntriesRequest)(nil), // 2: loop.stellar.GetLedgerEntriesRequest + (*LedgerEntryResult)(nil), // 3: loop.stellar.LedgerEntryResult + (*GetLedgerEntriesResponse)(nil), // 4: loop.stellar.GetLedgerEntriesResponse + (*GetLatestLedgerResponse)(nil), // 5: loop.stellar.GetLatestLedgerResponse + (*scval.ScVal)(nil), // 6: capabilities.blockchain.stellar.v1alpha.ScVal + (*emptypb.Empty)(nil), // 7: google.protobuf.Empty } var file_stellar_proto_depIdxs = []int32{ - 1, // 0: loop.stellar.GetLedgerEntriesResponse.entries:type_name -> loop.stellar.LedgerEntryResult - 0, // 1: loop.stellar.Stellar.GetLedgerEntries:input_type -> loop.stellar.GetLedgerEntriesRequest - 4, // 2: loop.stellar.Stellar.GetLatestLedger:input_type -> google.protobuf.Empty - 2, // 3: loop.stellar.Stellar.GetLedgerEntries:output_type -> loop.stellar.GetLedgerEntriesResponse - 3, // 4: loop.stellar.Stellar.GetLatestLedger:output_type -> loop.stellar.GetLatestLedgerResponse - 3, // [3:5] is the sub-list for method output_type - 1, // [1:3] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 6, // 0: loop.stellar.ReadContractRequest.args:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 6, // 1: loop.stellar.ReadContractResponse.result:type_name -> capabilities.blockchain.stellar.v1alpha.ScVal + 3, // 2: loop.stellar.GetLedgerEntriesResponse.entries:type_name -> loop.stellar.LedgerEntryResult + 2, // 3: loop.stellar.Stellar.GetLedgerEntries:input_type -> loop.stellar.GetLedgerEntriesRequest + 7, // 4: loop.stellar.Stellar.GetLatestLedger:input_type -> google.protobuf.Empty + 0, // 5: loop.stellar.Stellar.ReadContract:input_type -> loop.stellar.ReadContractRequest + 4, // 6: loop.stellar.Stellar.GetLedgerEntries:output_type -> loop.stellar.GetLedgerEntriesResponse + 5, // 7: loop.stellar.Stellar.GetLatestLedger:output_type -> loop.stellar.GetLatestLedgerResponse + 1, // 8: loop.stellar.Stellar.ReadContract:output_type -> loop.stellar.ReadContractResponse + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_stellar_proto_init() } @@ -363,7 +513,7 @@ func file_stellar_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_stellar_proto_rawDesc), len(file_stellar_proto_rawDesc)), NumEnums: 0, - NumMessages: 4, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/chains/stellar/stellar.proto b/pkg/chains/stellar/stellar.proto index b0bf6d118a..e5e2dbeb01 100644 --- a/pkg/chains/stellar/stellar.proto +++ b/pkg/chains/stellar/stellar.proto @@ -2,12 +2,30 @@ syntax = "proto3"; option go_package = "github.com/smartcontractkit/chainlink-common/pkg/chains/stellar"; import "google/protobuf/empty.proto"; +import "capabilities/blockchain/stellar/v1alpha/scval.proto"; package loop.stellar; service Stellar { rpc GetLedgerEntries(GetLedgerEntriesRequest) returns (GetLedgerEntriesResponse); rpc GetLatestLedger(google.protobuf.Empty) returns (GetLatestLedgerResponse); + rpc ReadContract(ReadContractRequest) returns (ReadContractResponse); +} + +// ReadContractRequest invokes a read-only (simulation) Soroban contract function. +message ReadContractRequest { + string contract_id = 1; // Stellar contract address (C… StrKey) + string function = 2; // Soroban function name + repeated capabilities.blockchain.stellar.v1alpha.ScVal args = 3; // Typed Soroban arguments + // Optional: ledger to simulate against; 0 means use the latest. + uint32 ledger_sequence = 4; +} + +// ReadContractResponse carries the return value of the simulated call. +message ReadContractResponse { + capabilities.blockchain.stellar.v1alpha.ScVal result = 1; // Return value (only valid when error is empty) + uint32 ledger_sequence = 2; // Ledger actually used for the simulation + string error = 3; // Non-empty on failure } // GetLedgerEntriesRequest fetches ledger entries by XDR-encoded keys. diff --git a/pkg/chains/stellar/stellar_grpc.pb.go b/pkg/chains/stellar/stellar_grpc.pb.go index 7f86cc3a6c..6c6da20432 100644 --- a/pkg/chains/stellar/stellar_grpc.pb.go +++ b/pkg/chains/stellar/stellar_grpc.pb.go @@ -22,6 +22,7 @@ const _ = grpc.SupportPackageIsVersion9 const ( Stellar_GetLedgerEntries_FullMethodName = "/loop.stellar.Stellar/GetLedgerEntries" Stellar_GetLatestLedger_FullMethodName = "/loop.stellar.Stellar/GetLatestLedger" + Stellar_ReadContract_FullMethodName = "/loop.stellar.Stellar/ReadContract" ) // StellarClient is the client API for Stellar service. @@ -30,6 +31,7 @@ const ( type StellarClient interface { GetLedgerEntries(ctx context.Context, in *GetLedgerEntriesRequest, opts ...grpc.CallOption) (*GetLedgerEntriesResponse, error) GetLatestLedger(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetLatestLedgerResponse, error) + ReadContract(ctx context.Context, in *ReadContractRequest, opts ...grpc.CallOption) (*ReadContractResponse, error) } type stellarClient struct { @@ -60,12 +62,23 @@ func (c *stellarClient) GetLatestLedger(ctx context.Context, in *emptypb.Empty, return out, nil } +func (c *stellarClient) ReadContract(ctx context.Context, in *ReadContractRequest, opts ...grpc.CallOption) (*ReadContractResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReadContractResponse) + err := c.cc.Invoke(ctx, Stellar_ReadContract_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // StellarServer is the server API for Stellar service. // All implementations must embed UnimplementedStellarServer // for forward compatibility. type StellarServer interface { GetLedgerEntries(context.Context, *GetLedgerEntriesRequest) (*GetLedgerEntriesResponse, error) GetLatestLedger(context.Context, *emptypb.Empty) (*GetLatestLedgerResponse, error) + ReadContract(context.Context, *ReadContractRequest) (*ReadContractResponse, error) mustEmbedUnimplementedStellarServer() } @@ -82,6 +95,9 @@ func (UnimplementedStellarServer) GetLedgerEntries(context.Context, *GetLedgerEn func (UnimplementedStellarServer) GetLatestLedger(context.Context, *emptypb.Empty) (*GetLatestLedgerResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetLatestLedger not implemented") } +func (UnimplementedStellarServer) ReadContract(context.Context, *ReadContractRequest) (*ReadContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReadContract not implemented") +} func (UnimplementedStellarServer) mustEmbedUnimplementedStellarServer() {} func (UnimplementedStellarServer) testEmbeddedByValue() {} @@ -139,6 +155,24 @@ func _Stellar_GetLatestLedger_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Stellar_ReadContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReadContractRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StellarServer).ReadContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Stellar_ReadContract_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StellarServer).ReadContract(ctx, req.(*ReadContractRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Stellar_ServiceDesc is the grpc.ServiceDesc for Stellar service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -154,6 +188,10 @@ var Stellar_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetLatestLedger", Handler: _Stellar_GetLatestLedger_Handler, }, + { + MethodName: "ReadContract", + Handler: _Stellar_ReadContract_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "stellar.proto", diff --git a/pkg/loop/internal/relayer/stellar.go b/pkg/loop/internal/relayer/stellar.go index b534f063da..b8fee1d032 100644 --- a/pkg/loop/internal/relayer/stellar.go +++ b/pkg/loop/internal/relayer/stellar.go @@ -52,6 +52,22 @@ func (sc *StellarClient) GetLatestLedger(ctx context.Context) (stellar.GetLatest return resp, nil } +func (sc *StellarClient) ReadContract(ctx context.Context, req stellar.ReadContractRequest) (stellar.ReadContractResponse, error) { + pReq, err := stelpb.ConvertReadContractRequestToProto(req) + if err != nil { + return stellar.ReadContractResponse{}, fmt.Errorf("invalid ReadContract request: %w", err) + } + pResp, err := sc.grpcClient.ReadContract(ctx, pReq) + if err != nil { + return stellar.ReadContractResponse{}, net.WrapRPCErr(err) + } + resp, err := stelpb.ConvertReadContractResponseFromProto(pResp) + if err != nil { + return stellar.ReadContractResponse{}, fmt.Errorf("invalid ReadContract response: %w", err) + } + return resp, nil +} + // stellarServer wraps types.StellarService and exposes it as a stelpb.StellarServer gRPC endpoint. type stellarServer struct { stelpb.UnimplementedStellarServer @@ -94,3 +110,19 @@ func (s *stellarServer) GetLatestLedger(ctx context.Context, _ *emptypb.Empty) ( } return pResp, nil } + +func (s *stellarServer) ReadContract(ctx context.Context, req *stelpb.ReadContractRequest) (*stelpb.ReadContractResponse, error) { + dReq, err := stelpb.ConvertReadContractRequestFromProto(req) + if err != nil { + return nil, fmt.Errorf("invalid ReadContract request: %w", err) + } + dResp, err := s.impl.ReadContract(ctx, dReq) + if err != nil { + return nil, net.WrapRPCErr(err) + } + pResp, err := stelpb.ConvertReadContractResponseToProto(dResp) + if err != nil { + return nil, fmt.Errorf("invalid ReadContract response: %w", err) + } + return pResp, nil +} diff --git a/pkg/loop/internal/relayer/stellar_test.go b/pkg/loop/internal/relayer/stellar_test.go index f605817d5a..955e71f1a3 100644 --- a/pkg/loop/internal/relayer/stellar_test.go +++ b/pkg/loop/internal/relayer/stellar_test.go @@ -15,6 +15,7 @@ import ( loopnet "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/net" "github.com/smartcontractkit/chainlink-common/pkg/types" stellartypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/stellar" + "github.com/stellar/go-stellar-sdk/xdr" ) func TestStellarDomainRoundTripThroughGRPC(t *testing.T) { @@ -136,12 +137,68 @@ func TestStellarDomainRoundTripThroughGRPC(t *testing.T) { require.Equal(t, uint32(1234), resp.Sequence) require.Equal(t, int64(9876543210), resp.LedgerCloseTime) }) + + t.Run("ReadContract_roundtrip", func(t *testing.T) { + sym := xdr.ScSymbol("transfer") + argVal := xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &sym} + + u32 := xdr.Uint32(42) + resultVal := xdr.ScVal{Type: xdr.ScValTypeScvU32, U32: &u32} + + svc.readContract = func(_ context.Context, req stellartypes.ReadContractRequest) (stellartypes.ReadContractResponse, error) { + require.Equal(t, "CABC123", req.ContractID) + require.Equal(t, "my_fn", req.Function) + require.Equal(t, uint32(100), req.LedgerSequence) + require.Len(t, req.Args, 1) + require.Equal(t, xdr.ScValTypeScvSymbol, req.Args[0].Type) + require.NotNil(t, req.Args[0].Sym) + require.Equal(t, xdr.ScSymbol("transfer"), *req.Args[0].Sym) + return stellartypes.ReadContractResponse{ + Result: &resultVal, + LedgerSequence: 101, + }, nil + } + + resp, err := client.ReadContract(ctx, stellartypes.ReadContractRequest{ + ContractID: "CABC123", + Function: "my_fn", + Args: []xdr.ScVal{argVal}, + LedgerSequence: 100, + }) + require.NoError(t, err) + require.Equal(t, uint32(101), resp.LedgerSequence) + require.Empty(t, resp.Error) + require.NotNil(t, resp.Result) + require.Equal(t, xdr.ScValTypeScvU32, resp.Result.Type) + require.NotNil(t, resp.Result.U32) + require.Equal(t, xdr.Uint32(42), *resp.Result.U32) + }) + + t.Run("ReadContract_noArgs_noResult", func(t *testing.T) { + svc.readContract = func(_ context.Context, req stellartypes.ReadContractRequest) (stellartypes.ReadContractResponse, error) { + require.Empty(t, req.Args) + return stellartypes.ReadContractResponse{ + Error: "contract error: not found", + LedgerSequence: 200, + }, nil + } + + resp, err := client.ReadContract(ctx, stellartypes.ReadContractRequest{ + ContractID: "CXYZ", + Function: "noop", + }) + require.NoError(t, err) + require.Equal(t, "contract error: not found", resp.Error) + require.Nil(t, resp.Result) + require.Equal(t, uint32(200), resp.LedgerSequence) + }) } type staticStellarService struct { types.UnimplementedStellarService getLedgerEntries func(ctx context.Context, req stellartypes.GetLedgerEntriesRequest) (stellartypes.GetLedgerEntriesResponse, error) getLatestLedger func(ctx context.Context) (stellartypes.GetLatestLedgerResponse, error) + readContract func(ctx context.Context, req stellartypes.ReadContractRequest) (stellartypes.ReadContractResponse, error) } func (s *staticStellarService) GetLedgerEntries(ctx context.Context, req stellartypes.GetLedgerEntriesRequest) (stellartypes.GetLedgerEntriesResponse, error) { @@ -157,3 +214,10 @@ func (s *staticStellarService) GetLatestLedger(ctx context.Context) (stellartype } return s.getLatestLedger(ctx) } + +func (s *staticStellarService) ReadContract(ctx context.Context, req stellartypes.ReadContractRequest) (stellartypes.ReadContractResponse, error) { + if s.readContract == nil { + return s.UnimplementedStellarService.ReadContract(ctx, req) + } + return s.readContract(ctx, req) +} diff --git a/pkg/types/chains/stellar/stellar.go b/pkg/types/chains/stellar/stellar.go index 33e0c0b25a..af47fdc26c 100644 --- a/pkg/types/chains/stellar/stellar.go +++ b/pkg/types/chains/stellar/stellar.go @@ -1,6 +1,10 @@ package stellar -import "context" +import ( + "context" + + "github.com/stellar/go-stellar-sdk/xdr" +) // Client wraps Stellar RPC calls via the type/chains/stellar domain types. // Both methods map 1:1 to the Stellar RPC API. @@ -9,6 +13,9 @@ type Client interface { GetLedgerEntries(ctx context.Context, req GetLedgerEntriesRequest) (GetLedgerEntriesResponse, error) // GetLatestLedger returns current ledger info (used for timeout detection). GetLatestLedger(ctx context.Context) (GetLatestLedgerResponse, error) + // ReadContract simulates a read-only Soroban contract function call. + // Each element of Args is a proto-marshalled ScVal (loop.stellar.ScVal). + ReadContract(ctx context.Context, req ReadContractRequest) (ReadContractResponse, error) } // GetLedgerEntriesRequest fetches ledger entries by XDR-encoded keys. @@ -39,6 +46,31 @@ type GetLedgerEntriesResponse struct { LatestLedger uint32 } +// ReadContractRequest is the domain representation of a Soroban read-only call. +// Each element of Args is a proto-marshalled loop.stellar.ScVal message. +// Use the helpers in pkg/chains/stellar to construct ScVal bytes conveniently. +type ReadContractRequest struct { + // ContractID is the Stellar contract address in C… StrKey encoding. + ContractID string + // Function is the Soroban function name to call. + Function string + // Args holds one proto-marshalled ScVal per contract argument. + // An empty slice is valid for zero-argument functions. + Args []xdr.ScVal + // LedgerSequence is the ledger to simulate against; 0 means use the latest. + LedgerSequence uint32 +} + +// ReadContractResponse is the domain representation of a Soroban simulation result. +type ReadContractResponse struct { + // Result is the XDR ScVal returned by the contract (nil when Error is non-empty). + Result *xdr.ScVal + // LedgerSequence is the ledger that was used for the simulation. + LedgerSequence uint32 + // Error is non-empty when the call failed. + Error string +} + // GetLatestLedgerResponse holds the current ledger state. type GetLatestLedgerResponse struct { // Hash is the hex-encoded latest ledger hash. diff --git a/pkg/types/relayer.go b/pkg/types/relayer.go index 8277a47446..c130293ef4 100644 --- a/pkg/types/relayer.go +++ b/pkg/types/relayer.go @@ -649,6 +649,10 @@ var _ StellarService = &UnimplementedStellarService{} // don't immediately break downstream packages on dependency bumps. type UnimplementedStellarService struct{} +func (u *UnimplementedStellarService) ReadContract(ctx context.Context, req stellar.ReadContractRequest) (stellar.ReadContractResponse, error) { + return stellar.ReadContractResponse{}, status.Errorf(codes.Unimplemented, "method StellarReadContract not implemented") +} + func (u *UnimplementedStellarService) GetLedgerEntries(_ context.Context, _ stellar.GetLedgerEntriesRequest) (stellar.GetLedgerEntriesResponse, error) { return stellar.GetLedgerEntriesResponse{}, status.Errorf(codes.Unimplemented, "method GetLedgerEntries not implemented") } From 98cf9c6b1ecab06d6c4e6241f261e637908ce72f Mon Sep 17 00:00:00 2001 From: ilija Date: Tue, 12 May 2026 22:49:54 +0200 Subject: [PATCH 2/4] Add ReadContract proto helpers --- .../stellar/proto_helpers_test.go | 1 - pkg/chains/stellar/proto_helpers.go | 746 +++++++++--- pkg/chains/stellar/proto_helpers_test.go | 1068 +++++++++++++++++ 3 files changed, 1623 insertions(+), 192 deletions(-) create mode 100644 pkg/chains/stellar/proto_helpers_test.go diff --git a/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers_test.go b/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers_test.go index 6cc0e40608..08ee9636d2 100644 --- a/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers_test.go +++ b/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers_test.go @@ -103,7 +103,6 @@ func TestValidateReadContractRequest_AcceptsValidRequest(t *testing.T) { err := stellarcap.ValidateReadContractRequest(&stellarcap.ReadContractRequest{ ContractId: "CAHJJJKK7777AAAA1111BBBB2222CCCC3333DDDD4444EEEE5555FFFF6666", Function: "balance", - Args: [][]byte{{0x01}, {0x02}}, }) require.NoError(t, err) } diff --git a/pkg/chains/stellar/proto_helpers.go b/pkg/chains/stellar/proto_helpers.go index 56b431f9fc..905f5c752b 100644 --- a/pkg/chains/stellar/proto_helpers.go +++ b/pkg/chains/stellar/proto_helpers.go @@ -1,14 +1,11 @@ package stellar import ( - "bytes" "encoding/base64" "encoding/hex" "errors" "fmt" - "google.golang.org/protobuf/proto" - "github.com/stellar/go-stellar-sdk/xdr" v1alpha "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar/scval" @@ -98,18 +95,13 @@ func ConvertLedgerEntryResultFromProto(p *LedgerEntryResult) (stellar.LedgerEntr // ConvertGetLedgerEntriesResponseToProto converts a domain GetLedgerEntriesResponse to its proto representation. func ConvertGetLedgerEntriesResponseToProto(resp stellar.GetLedgerEntriesResponse) (*GetLedgerEntriesResponse, error) { entries := make([]*LedgerEntryResult, 0, len(resp.Entries)) - var errs []error for i, e := range resp.Entries { protoEntry, err := ConvertLedgerEntryResultToProto(e) if err != nil { - errs = append(errs, fmt.Errorf("entry[%d]: %w", i, err)) - continue + return nil, fmt.Errorf("entry[%d]: %w", i, err) } entries = append(entries, protoEntry) } - if len(errs) > 0 { - return nil, errors.Join(errs...) - } return &GetLedgerEntriesResponse{ Entries: entries, LatestLedger: resp.LatestLedger, @@ -121,19 +113,15 @@ func ConvertGetLedgerEntriesResponseFromProto(p *GetLedgerEntriesResponse) (stel if p == nil { return stellar.GetLedgerEntriesResponse{}, fmt.Errorf("get ledger entries response is nil") } - entries := make([]stellar.LedgerEntryResult, 0, len(p.GetEntries())) - var errs []error - for i, pe := range p.GetEntries() { + pEntries := p.GetEntries() + entries := make([]stellar.LedgerEntryResult, 0, len(pEntries)) + for i, pe := range pEntries { e, err := ConvertLedgerEntryResultFromProto(pe) if err != nil { - errs = append(errs, fmt.Errorf("entry[%d]: %w", i, err)) - continue + return stellar.GetLedgerEntriesResponse{}, fmt.Errorf("entry[%d]: %w", i, err) } entries = append(entries, e) } - if len(errs) > 0 { - return stellar.GetLedgerEntriesResponse{}, errors.Join(errs...) - } return stellar.GetLedgerEntriesResponse{ Entries: entries, LatestLedger: p.GetLatestLedger(), @@ -180,55 +168,572 @@ func ConvertGetLatestLedgerResponseFromProto(p *GetLatestLedgerResponse) (stella }, nil } -// ============================================================ -// ReadContract converters -// ============================================================ +func unwrapScVec(v **xdr.ScVec) (xdr.ScVec, error) { + if v == nil || *v == nil { + return nil, fmt.Errorf("vec is nil") + } + return **v, nil +} + +func unwrapScMap(v **xdr.ScMap) (xdr.ScMap, error) { + if v == nil || *v == nil { + return nil, fmt.Errorf("map is nil") + } + return **v, nil +} -// xdrScValToProto XDR-encodes an xdr.ScVal to binary, then wraps the bytes in a -// proto ScVal with the bytes_val field (SCV_BYTES transport container). -// Both the LOOP client and server unwrap using protoScValToXDR. +// xdrScValToProto converts an XDR ScVal to its proto representation. +// Returns an error if nesting depth exceeds 64 levels. func xdrScValToProto(sv xdr.ScVal) (*v1alpha.ScVal, error) { - var buf bytes.Buffer - if _, err := xdr.Marshal(&buf, sv); err != nil { - return nil, fmt.Errorf("failed to XDR-marshal ScVal: %w", err) + return xdrScValToProtoAt(sv, 0) +} + +func xdrScValToProtoAt(sv xdr.ScVal, depth int) (*v1alpha.ScVal, error) { + if depth > 64 { + return nil, fmt.Errorf("ScVal nesting exceeds maximum depth of 64") + } + switch sv.Type { + case xdr.ScValTypeScvBool: + if sv.B == nil { + return nil, fmt.Errorf("scvBool: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_B{B: *sv.B}}, nil + case xdr.ScValTypeScvVoid: + return &v1alpha.ScVal{Value: &v1alpha.ScVal_VoidVal{VoidVal: &v1alpha.Void{}}}, nil + case xdr.ScValTypeScvError: + if sv.Error == nil { + return nil, fmt.Errorf("scvError: nil") + } + pe, err := xdrScErrorToProto(sv.Error) + if err != nil { + return nil, err + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_Error{Error: pe}}, nil + case xdr.ScValTypeScvU32: + if sv.U32 == nil { + return nil, fmt.Errorf("scvU32: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_U32{U32: uint32(*sv.U32)}}, nil + case xdr.ScValTypeScvI32: + if sv.I32 == nil { + return nil, fmt.Errorf("scvI32: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_I32{I32: int32(*sv.I32)}}, nil + case xdr.ScValTypeScvU64: + if sv.U64 == nil { + return nil, fmt.Errorf("scvU64: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_U64{U64: uint64(*sv.U64)}}, nil + case xdr.ScValTypeScvI64: + if sv.I64 == nil { + return nil, fmt.Errorf("scvI64: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_I64{I64: int64(*sv.I64)}}, nil + case xdr.ScValTypeScvTimepoint: + if sv.Timepoint == nil { + return nil, fmt.Errorf("scvTimepoint: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_Timepoint{Timepoint: uint64(*sv.Timepoint)}}, nil + case xdr.ScValTypeScvDuration: + if sv.Duration == nil { + return nil, fmt.Errorf("scvDuration: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_Duration{Duration: uint64(*sv.Duration)}}, nil + case xdr.ScValTypeScvU128: + if sv.U128 == nil { + return nil, fmt.Errorf("scvU128: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_U128{U128: &v1alpha.UInt128Parts{ + Hi: uint64(sv.U128.Hi), + Lo: uint64(sv.U128.Lo), + }}}, nil + case xdr.ScValTypeScvI128: + if sv.I128 == nil { + return nil, fmt.Errorf("scvI128: nil") + } + // Per XDR spec for signed integer types: Hi is signed, Lo is unsigned. + return &v1alpha.ScVal{Value: &v1alpha.ScVal_I128{I128: &v1alpha.Int128Parts{ + Hi: int64(sv.I128.Hi), + Lo: uint64(sv.I128.Lo), + }}}, nil + case xdr.ScValTypeScvU256: + if sv.U256 == nil { + return nil, fmt.Errorf("scvU256: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_U256{U256: &v1alpha.UInt256Parts{ + HiHi: uint64(sv.U256.HiHi), + HiLo: uint64(sv.U256.HiLo), + LoHi: uint64(sv.U256.LoHi), + LoLo: uint64(sv.U256.LoLo), + }}}, nil + case xdr.ScValTypeScvI256: + if sv.I256 == nil { + return nil, fmt.Errorf("scvI256: nil") + } + // Per XDR spec for signed integer types: HiHi is signed, remaining parts are unsigned. + return &v1alpha.ScVal{Value: &v1alpha.ScVal_I256{I256: &v1alpha.Int256Parts{ + HiHi: int64(sv.I256.HiHi), + HiLo: uint64(sv.I256.HiLo), + LoHi: uint64(sv.I256.LoHi), + LoLo: uint64(sv.I256.LoLo), + }}}, nil + case xdr.ScValTypeScvBytes: + if sv.Bytes == nil { + return nil, fmt.Errorf("scvBytes: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_BytesVal{BytesVal: *sv.Bytes}}, nil + case xdr.ScValTypeScvString: + if sv.Str == nil { + return nil, fmt.Errorf("scvString: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_Str{Str: string(*sv.Str)}}, nil + case xdr.ScValTypeScvSymbol: + if sv.Sym == nil { + return nil, fmt.Errorf("scvSymbol: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_Sym{Sym: string(*sv.Sym)}}, nil + case xdr.ScValTypeScvVec: + xVec, err := unwrapScVec(sv.Vec) + if err != nil { + return nil, fmt.Errorf("scvVec: %w", err) + } + pVals := make([]*v1alpha.ScVal, len(xVec)) + for i, elem := range xVec { + pv, err := xdrScValToProtoAt(elem, depth+1) + if err != nil { + return nil, fmt.Errorf("vec[%d]: %w", i, err) + } + pVals[i] = pv + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_Vec{Vec: &v1alpha.ScVec{Values: pVals}}}, nil + case xdr.ScValTypeScvMap: + xMap, err := unwrapScMap(sv.Map) + if err != nil { + return nil, fmt.Errorf("scvMap: %w", err) + } + entries := make([]*v1alpha.ScMapEntry, len(xMap)) + for i, entry := range xMap { + pk, err := xdrScValToProtoAt(entry.Key, depth+1) + if err != nil { + return nil, fmt.Errorf("map[%d].key: %w", i, err) + } + pv, err := xdrScValToProtoAt(entry.Val, depth+1) + if err != nil { + return nil, fmt.Errorf("map[%d].val: %w", i, err) + } + entries[i] = &v1alpha.ScMapEntry{Key: pk, Val: pv} + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_Map{Map: &v1alpha.ScMap{Entries: entries}}}, nil + case xdr.ScValTypeScvAddress: + if sv.Address == nil { + return nil, fmt.Errorf("scvAddress: nil") + } + pa, err := xdrScAddressToProto(sv.Address) + if err != nil { + return nil, err + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: pa}}, nil + case xdr.ScValTypeScvContractInstance: + if sv.Instance == nil { + return nil, fmt.Errorf("scvContractInstance: nil") + } + pi, err := xdrScContractInstanceToProtoAt(sv.Instance, depth+1) + if err != nil { + return nil, err + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_ContractInstance{ContractInstance: pi}}, nil + case xdr.ScValTypeScvLedgerKeyContractInstance: + return &v1alpha.ScVal{Value: &v1alpha.ScVal_LedgerKeyContractInstance{LedgerKeyContractInstance: &v1alpha.Void{}}}, nil + case xdr.ScValTypeScvLedgerKeyNonce: + if sv.NonceKey == nil { + return nil, fmt.Errorf("scvLedgerKeyNonce: nil") + } + return &v1alpha.ScVal{Value: &v1alpha.ScVal_NonceKey{NonceKey: &v1alpha.ScNonceKey{Nonce: int64(sv.NonceKey.Nonce)}}}, nil + default: + return nil, fmt.Errorf("unsupported ScVal type: %d", sv.Type) + } +} + +func xdrScErrorToProto(e *xdr.ScError) (*v1alpha.ScError, error) { + pe := &v1alpha.ScError{Type: v1alpha.ScError_Type(e.Type)} + if e.Type == xdr.ScErrorTypeSceContract { + if e.ContractCode == nil { + return nil, fmt.Errorf("scError.contractCode: nil") + } + pe.CodeOrContract = &v1alpha.ScError_ContractCode{ContractCode: uint32(*e.ContractCode)} + } else { + if e.Code == nil { + return nil, fmt.Errorf("scError type %d: nil code", e.Type) + } + pe.CodeOrContract = &v1alpha.ScError_Code_{Code: v1alpha.ScError_Code(*e.Code)} + } + return pe, nil +} + +func xdrScAddressToProto(a *xdr.ScAddress) (*v1alpha.ScAddress, error) { + switch a.Type { + case xdr.ScAddressTypeScAddressTypeAccount: + if a.AccountId == nil || a.AccountId.Ed25519 == nil { + return nil, fmt.Errorf("scAddress.account: nil accountId or ed25519") + } + return &v1alpha.ScAddress{Address: &v1alpha.ScAddress_AccountId{AccountId: (*a.AccountId.Ed25519)[:]}}, nil + case xdr.ScAddressTypeScAddressTypeContract: + if a.ContractId == nil { + return nil, fmt.Errorf("scAddress.contract: nil contractId") + } + return &v1alpha.ScAddress{Address: &v1alpha.ScAddress_ContractId{ContractId: (*a.ContractId)[:]}}, nil + case xdr.ScAddressTypeScAddressTypeMuxedAccount: + if a.MuxedAccount == nil { + return nil, fmt.Errorf("scAddress.muxed: nil") + } + return &v1alpha.ScAddress{Address: &v1alpha.ScAddress_MuxedAccount{MuxedAccount: &v1alpha.MuxedEd25519Account{ + Id: uint64(a.MuxedAccount.Id), + Ed25519: a.MuxedAccount.Ed25519[:], + }}}, nil + case xdr.ScAddressTypeScAddressTypeClaimableBalance: + if a.ClaimableBalanceId == nil || a.ClaimableBalanceId.V0 == nil { + return nil, fmt.Errorf("scAddress.claimableBalance: nil") + } + return &v1alpha.ScAddress{Address: &v1alpha.ScAddress_ClaimableBalanceId{ClaimableBalanceId: &v1alpha.ClaimableBalanceId{ + V0: (*a.ClaimableBalanceId.V0)[:], + }}}, nil + case xdr.ScAddressTypeScAddressTypeLiquidityPool: + if a.LiquidityPoolId == nil { + return nil, fmt.Errorf("scAddress.liquidityPool: nil poolId") + } + return &v1alpha.ScAddress{Address: &v1alpha.ScAddress_LiquidityPoolId{LiquidityPoolId: (*a.LiquidityPoolId)[:]}}, nil + default: + return nil, fmt.Errorf("unsupported ScAddress type: %d", a.Type) + } +} + +func xdrContractExecutableToProto(exec xdr.ContractExecutable) (*v1alpha.ContractExecutable, error) { + switch exec.Type { + case xdr.ContractExecutableTypeContractExecutableWasm: + if exec.WasmHash == nil { + return nil, fmt.Errorf("contractExecutable.wasm: nil wasmHash") + } + return &v1alpha.ContractExecutable{Type: &v1alpha.ContractExecutable_WasmHash{WasmHash: (*exec.WasmHash)[:]}}, nil + case xdr.ContractExecutableTypeContractExecutableStellarAsset: + return &v1alpha.ContractExecutable{Type: &v1alpha.ContractExecutable_StellarAsset{StellarAsset: true}}, nil + default: + return nil, fmt.Errorf("unsupported ContractExecutable type: %d", exec.Type) + } +} + +func xdrScContractInstanceToProtoAt(inst *xdr.ScContractInstance, depth int) (*v1alpha.ScContractInstance, error) { + pExec, err := xdrContractExecutableToProto(inst.Executable) + if err != nil { + return nil, err + } + pi := &v1alpha.ScContractInstance{Executable: pExec} + if inst.Storage != nil { + xMap := *inst.Storage + entries := make([]*v1alpha.ScMapEntry, len(xMap)) + for i, entry := range xMap { + pk, err := xdrScValToProtoAt(entry.Key, depth+1) + if err != nil { + return nil, fmt.Errorf("instance.storage[%d].key: %w", i, err) + } + pv, err := xdrScValToProtoAt(entry.Val, depth+1) + if err != nil { + return nil, fmt.Errorf("instance.storage[%d].val: %w", i, err) + } + entries[i] = &v1alpha.ScMapEntry{Key: pk, Val: pv} + } + pi.Storage = entries } - return &v1alpha.ScVal{Value: &v1alpha.ScVal_BytesVal{BytesVal: buf.Bytes()}}, nil + return pi, nil } -// protoScValToXDR unwraps a proto ScVal that was produced by xdrScValToProto and -// XDR-decodes the inner bytes back to an xdr.ScVal. +// protoScValToXDR converts a proto ScVal to its XDR representation. +// Returns an error if nesting depth exceeds 64 levels. func protoScValToXDR(sv *v1alpha.ScVal) (xdr.ScVal, error) { + return protoScValToXDRAt(sv, 0) +} + +func protoScValToXDRAt(sv *v1alpha.ScVal, depth int) (xdr.ScVal, error) { + if depth > 64 { + return xdr.ScVal{}, fmt.Errorf("scVal nesting exceeds maximum depth of 64") + } if sv == nil { return xdr.ScVal{}, fmt.Errorf("proto ScVal is nil") } - bv, ok := sv.Value.(*v1alpha.ScVal_BytesVal) - if !ok { - return xdr.ScVal{}, fmt.Errorf("proto ScVal does not carry bytes_val (got %T)", sv.Value) + switch v := sv.Value.(type) { + case *v1alpha.ScVal_B: + b := v.B + return xdr.ScVal{Type: xdr.ScValTypeScvBool, B: &b}, nil + case *v1alpha.ScVal_VoidVal: + return xdr.ScVal{Type: xdr.ScValTypeScvVoid}, nil + case *v1alpha.ScVal_Error: + xe, err := protoScErrorToXDR(v.Error) + if err != nil { + return xdr.ScVal{}, err + } + return xdr.ScVal{Type: xdr.ScValTypeScvError, Error: &xe}, nil + case *v1alpha.ScVal_U32: + u := xdr.Uint32(v.U32) + return xdr.ScVal{Type: xdr.ScValTypeScvU32, U32: &u}, nil + case *v1alpha.ScVal_I32: + i := xdr.Int32(v.I32) + return xdr.ScVal{Type: xdr.ScValTypeScvI32, I32: &i}, nil + case *v1alpha.ScVal_U64: + u := xdr.Uint64(v.U64) + return xdr.ScVal{Type: xdr.ScValTypeScvU64, U64: &u}, nil + case *v1alpha.ScVal_I64: + i := xdr.Int64(v.I64) + return xdr.ScVal{Type: xdr.ScValTypeScvI64, I64: &i}, nil + case *v1alpha.ScVal_Timepoint: + t := xdr.TimePoint(v.Timepoint) + return xdr.ScVal{Type: xdr.ScValTypeScvTimepoint, Timepoint: &t}, nil + case *v1alpha.ScVal_Duration: + d := xdr.Duration(v.Duration) + return xdr.ScVal{Type: xdr.ScValTypeScvDuration, Duration: &d}, nil + case *v1alpha.ScVal_U128: + if v.U128 == nil { + return xdr.ScVal{}, fmt.Errorf("scvU128: nil") + } + u128 := xdr.UInt128Parts{Hi: xdr.Uint64(v.U128.Hi), Lo: xdr.Uint64(v.U128.Lo)} + return xdr.ScVal{Type: xdr.ScValTypeScvU128, U128: &u128}, nil + case *v1alpha.ScVal_I128: + if v.I128 == nil { + return xdr.ScVal{}, fmt.Errorf("scvI128: nil") + } + // Per XDR spec for signed integer types: Hi is signed, Lo is unsigned. + i128 := xdr.Int128Parts{Hi: xdr.Int64(v.I128.Hi), Lo: xdr.Uint64(v.I128.Lo)} + return xdr.ScVal{Type: xdr.ScValTypeScvI128, I128: &i128}, nil + case *v1alpha.ScVal_U256: + if v.U256 == nil { + return xdr.ScVal{}, fmt.Errorf("scvU256: nil") + } + u256 := xdr.UInt256Parts{ + HiHi: xdr.Uint64(v.U256.HiHi), + HiLo: xdr.Uint64(v.U256.HiLo), + LoHi: xdr.Uint64(v.U256.LoHi), + LoLo: xdr.Uint64(v.U256.LoLo), + } + return xdr.ScVal{Type: xdr.ScValTypeScvU256, U256: &u256}, nil + case *v1alpha.ScVal_I256: + if v.I256 == nil { + return xdr.ScVal{}, fmt.Errorf("scvI256: nil") + } + // Per XDR spec for signed integer types: HiHi is signed, remaining parts are unsigned. + i256 := xdr.Int256Parts{ + HiHi: xdr.Int64(v.I256.HiHi), + HiLo: xdr.Uint64(v.I256.HiLo), + LoHi: xdr.Uint64(v.I256.LoHi), + LoLo: xdr.Uint64(v.I256.LoLo), + } + return xdr.ScVal{Type: xdr.ScValTypeScvI256, I256: &i256}, nil + case *v1alpha.ScVal_BytesVal: + xb := xdr.ScBytes(v.BytesVal) + return xdr.ScVal{Type: xdr.ScValTypeScvBytes, Bytes: &xb}, nil + case *v1alpha.ScVal_Str: + xs := xdr.ScString(v.Str) + return xdr.ScVal{Type: xdr.ScValTypeScvString, Str: &xs}, nil + case *v1alpha.ScVal_Sym: + xs := xdr.ScSymbol(v.Sym) + return xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &xs}, nil + case *v1alpha.ScVal_Vec: + if v.Vec == nil { + return xdr.ScVal{}, fmt.Errorf("scvVec: nil") + } + xVec := make(xdr.ScVec, len(v.Vec.Values)) + for i, pv := range v.Vec.Values { + xv, err := protoScValToXDRAt(pv, depth+1) + if err != nil { + return xdr.ScVal{}, fmt.Errorf("vec[%d]: %w", i, err) + } + xVec[i] = xv + } + xVecP := &xVec + return xdr.ScVal{Type: xdr.ScValTypeScvVec, Vec: &xVecP}, nil + case *v1alpha.ScVal_Map: + if v.Map == nil { + return xdr.ScVal{}, fmt.Errorf("scvMap: nil") + } + xMap := make(xdr.ScMap, len(v.Map.Entries)) + for i, pe := range v.Map.Entries { + xk, err := protoScValToXDRAt(pe.Key, depth+1) + if err != nil { + return xdr.ScVal{}, fmt.Errorf("map[%d].key: %w", i, err) + } + xv, err := protoScValToXDRAt(pe.Val, depth+1) + if err != nil { + return xdr.ScVal{}, fmt.Errorf("map[%d].val: %w", i, err) + } + xMap[i] = xdr.ScMapEntry{Key: xk, Val: xv} + } + xMapP := &xMap + return xdr.ScVal{Type: xdr.ScValTypeScvMap, Map: &xMapP}, nil + case *v1alpha.ScVal_Address: + xa, err := protoScAddressToXDR(v.Address) + if err != nil { + return xdr.ScVal{}, err + } + return xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &xa}, nil + case *v1alpha.ScVal_ContractInstance: + xi, err := protoScContractInstanceToXDRAt(v.ContractInstance, depth+1) + if err != nil { + return xdr.ScVal{}, err + } + return xdr.ScVal{Type: xdr.ScValTypeScvContractInstance, Instance: &xi}, nil + case *v1alpha.ScVal_LedgerKeyContractInstance: + return xdr.ScVal{Type: xdr.ScValTypeScvLedgerKeyContractInstance}, nil + case *v1alpha.ScVal_NonceKey: + if v.NonceKey == nil { + return xdr.ScVal{}, fmt.Errorf("scvLedgerKeyNonce: nil") + } + return xdr.ScVal{Type: xdr.ScValTypeScvLedgerKeyNonce, NonceKey: &xdr.ScNonceKey{Nonce: xdr.Int64(v.NonceKey.Nonce)}}, nil + default: + return xdr.ScVal{}, fmt.Errorf("unsupported proto ScVal type: %T", sv.Value) + } +} + +func protoScErrorToXDR(e *v1alpha.ScError) (xdr.ScError, error) { + if e == nil { + return xdr.ScError{}, fmt.Errorf("proto ScError is nil") + } + xe := xdr.ScError{Type: xdr.ScErrorType(e.Type)} + switch v := e.CodeOrContract.(type) { + case *v1alpha.ScError_ContractCode: + cc := xdr.Uint32(v.ContractCode) + xe.ContractCode = &cc + case *v1alpha.ScError_Code_: + code := xdr.ScErrorCode(v.Code) + xe.Code = &code + default: + return xdr.ScError{}, fmt.Errorf("unsupported ScError oneof: %T", e.CodeOrContract) + } + return xe, nil +} + +func protoScAddressToXDR(a *v1alpha.ScAddress) (xdr.ScAddress, error) { + if a == nil { + return xdr.ScAddress{}, fmt.Errorf("proto ScAddress is nil") + } + switch v := a.Address.(type) { + case *v1alpha.ScAddress_AccountId: + if len(v.AccountId) != 32 { + return xdr.ScAddress{}, fmt.Errorf("accountId must be 32 bytes, got %d", len(v.AccountId)) + } + var ed25519 xdr.Uint256 + copy(ed25519[:], v.AccountId) + aid := xdr.AccountId(xdr.PublicKey{Type: xdr.PublicKeyTypePublicKeyTypeEd25519, Ed25519: &ed25519}) + return xdr.ScAddress{Type: xdr.ScAddressTypeScAddressTypeAccount, AccountId: &aid}, nil + case *v1alpha.ScAddress_ContractId: + if len(v.ContractId) != 32 { + return xdr.ScAddress{}, fmt.Errorf("contractId must be 32 bytes, got %d", len(v.ContractId)) + } + var cid xdr.ContractId + copy(cid[:], v.ContractId) + return xdr.ScAddress{Type: xdr.ScAddressTypeScAddressTypeContract, ContractId: &cid}, nil + case *v1alpha.ScAddress_MuxedAccount: + if v.MuxedAccount == nil { + return xdr.ScAddress{}, fmt.Errorf("muxedAccount: nil") + } + if len(v.MuxedAccount.Ed25519) != 32 { + return xdr.ScAddress{}, fmt.Errorf("muxedAccount.ed25519 must be 32 bytes, got %d", len(v.MuxedAccount.Ed25519)) + } + var ed25519 xdr.Uint256 + copy(ed25519[:], v.MuxedAccount.Ed25519) + return xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeMuxedAccount, + MuxedAccount: &xdr.MuxedEd25519Account{ + Id: xdr.Uint64(v.MuxedAccount.Id), + Ed25519: ed25519, + }, + }, nil + case *v1alpha.ScAddress_ClaimableBalanceId: + if v.ClaimableBalanceId == nil { + return xdr.ScAddress{}, fmt.Errorf("claimableBalanceId: nil") + } + if len(v.ClaimableBalanceId.V0) != 32 { + return xdr.ScAddress{}, fmt.Errorf("claimableBalanceId.v0 must be 32 bytes, got %d", len(v.ClaimableBalanceId.V0)) + } + var h xdr.Hash + copy(h[:], v.ClaimableBalanceId.V0) + return xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeClaimableBalance, + ClaimableBalanceId: &xdr.ClaimableBalanceId{ + Type: xdr.ClaimableBalanceIdTypeClaimableBalanceIdTypeV0, + V0: &h, + }, + }, nil + case *v1alpha.ScAddress_LiquidityPoolId: + if len(v.LiquidityPoolId) != 32 { + return xdr.ScAddress{}, fmt.Errorf("liquidityPoolId must be 32 bytes, got %d", len(v.LiquidityPoolId)) + } + var poolId xdr.PoolId + copy(poolId[:], v.LiquidityPoolId) + return xdr.ScAddress{Type: xdr.ScAddressTypeScAddressTypeLiquidityPool, LiquidityPoolId: &poolId}, nil + default: + return xdr.ScAddress{}, fmt.Errorf("unsupported proto ScAddress type: %T", a.Address) + } +} + +func protoContractExecutableToXDR(exec *v1alpha.ContractExecutable) (xdr.ContractExecutable, error) { + if exec == nil { + return xdr.ContractExecutable{}, fmt.Errorf("proto ContractExecutable is nil") + } + switch v := exec.Type.(type) { + case *v1alpha.ContractExecutable_WasmHash: + if len(v.WasmHash) != 32 { + return xdr.ContractExecutable{}, fmt.Errorf("wasmHash must be 32 bytes, got %d", len(v.WasmHash)) + } + var h xdr.Hash + copy(h[:], v.WasmHash) + return xdr.ContractExecutable{Type: xdr.ContractExecutableTypeContractExecutableWasm, WasmHash: &h}, nil + case *v1alpha.ContractExecutable_StellarAsset: + return xdr.ContractExecutable{Type: xdr.ContractExecutableTypeContractExecutableStellarAsset}, nil + default: + return xdr.ContractExecutable{}, fmt.Errorf("unsupported proto ContractExecutable type: %T", exec.Type) + } +} + +func protoScContractInstanceToXDRAt(inst *v1alpha.ScContractInstance, depth int) (xdr.ScContractInstance, error) { + if inst == nil { + return xdr.ScContractInstance{}, fmt.Errorf("proto ScContractInstance is nil") } - var out xdr.ScVal - if _, err := xdr.Unmarshal(bytes.NewReader(bv.BytesVal), &out); err != nil { - return xdr.ScVal{}, fmt.Errorf("failed to XDR-unmarshal ScVal: %w", err) + xExec, err := protoContractExecutableToXDR(inst.Executable) + if err != nil { + return xdr.ScContractInstance{}, err + } + xi := xdr.ScContractInstance{Executable: xExec} + if len(inst.Storage) > 0 { + xMap := make(xdr.ScMap, len(inst.Storage)) + for i, pe := range inst.Storage { + xk, err := protoScValToXDRAt(pe.Key, depth+1) + if err != nil { + return xdr.ScContractInstance{}, fmt.Errorf("instance.storage[%d].key: %w", i, err) + } + xv, err := protoScValToXDRAt(pe.Val, depth+1) + if err != nil { + return xdr.ScContractInstance{}, fmt.Errorf("instance.storage[%d].val: %w", i, err) + } + xMap[i] = xdr.ScMapEntry{Key: xk, Val: xv} + } + xi.Storage = &xMap } - return out, nil + return xi, nil } -// ConvertReadContractRequestToProto converts a domain ReadContractRequest to the -// proto representation. Each xdr.ScVal arg is XDR-encoded and stored as -// bytes_val inside a proto ScVal for transport. +// ConvertReadContractRequestToProto converts a domain ReadContractRequest to its +// proto representation. func ConvertReadContractRequestToProto(req stellar.ReadContractRequest) (*ReadContractRequest, error) { if req.ContractID == "" { - return nil, fmt.Errorf("contract_id is required") + return nil, fmt.Errorf("contractID is required") } if req.Function == "" { return nil, fmt.Errorf("function is required") } - args := make([]*v1alpha.ScVal, 0, len(req.Args)) + args := make([]*v1alpha.ScVal, len(req.Args)) for i, sv := range req.Args { psv, err := xdrScValToProto(sv) if err != nil { return nil, fmt.Errorf("args[%d]: %w", i, err) } - args = append(args, psv) + args[i] = psv } return &ReadContractRequest{ ContractId: req.ContractID, @@ -239,7 +744,7 @@ func ConvertReadContractRequestToProto(req stellar.ReadContractRequest) (*ReadCo } // ConvertReadContractRequestFromProto converts a proto ReadContractRequest to the -// domain type. Each bytes_val proto ScVal is XDR-decoded back to xdr.ScVal. +// domain type. func ConvertReadContractRequestFromProto(p *ReadContractRequest) (stellar.ReadContractRequest, error) { if p == nil { return stellar.ReadContractRequest{}, fmt.Errorf("ReadContractRequest is nil") @@ -250,13 +755,14 @@ func ConvertReadContractRequestFromProto(p *ReadContractRequest) (stellar.ReadCo if p.GetFunction() == "" { return stellar.ReadContractRequest{}, fmt.Errorf("function is required") } - args := make([]xdr.ScVal, 0, len(p.GetArgs())) - for i, psv := range p.GetArgs() { + pArgs := p.GetArgs() + args := make([]xdr.ScVal, len(pArgs)) + for i, psv := range pArgs { sv, err := protoScValToXDR(psv) if err != nil { return stellar.ReadContractRequest{}, fmt.Errorf("args[%d]: %w", i, err) } - args = append(args, sv) + args[i] = sv } return stellar.ReadContractRequest{ ContractID: p.GetContractId(), @@ -267,8 +773,7 @@ func ConvertReadContractRequestFromProto(p *ReadContractRequest) (stellar.ReadCo } // ConvertReadContractResponseToProto converts a domain ReadContractResponse to its -// proto representation. If resp.Result is non-nil it is XDR-encoded and stored as -// bytes_val inside a proto ScVal. +// proto representation. func ConvertReadContractResponseToProto(resp stellar.ReadContractResponse) (*ReadContractResponse, error) { pr := &ReadContractResponse{ LedgerSequence: resp.LedgerSequence, @@ -285,10 +790,10 @@ func ConvertReadContractResponseToProto(resp stellar.ReadContractResponse) (*Rea } // ConvertReadContractResponseFromProto converts a proto ReadContractResponse to the -// domain type. The bytes_val proto ScVal result is XDR-decoded back to xdr.ScVal. +// domain type. func ConvertReadContractResponseFromProto(p *ReadContractResponse) (stellar.ReadContractResponse, error) { if p == nil { - return stellar.ReadContractResponse{}, fmt.Errorf("ReadContractResponse is nil") + return stellar.ReadContractResponse{}, fmt.Errorf("readContractResponse is nil") } resp := stellar.ReadContractResponse{ LedgerSequence: p.GetLedgerSequence(), @@ -303,144 +808,3 @@ func ConvertReadContractResponseFromProto(p *ReadContractResponse) (stellar.Read } return resp, nil } - -// ============================================================ -// ScVal builder helpers -// -// These helpers produce proto-marshalled ScVal bytes ([]byte) -// suitable for ReadContractRequest.Args / ReadContractResponse.Result. -// ============================================================ - -// MarshalScVal proto-marshals the given ScVal and returns the bytes, or an error. -func MarshalScVal(sv *v1alpha.ScVal) ([]byte, error) { - if sv == nil { - return nil, fmt.Errorf("ScVal is nil") - } - return proto.Marshal(sv) -} - -// UnmarshalScVal unmarshals a proto-encoded ScVal from raw bytes. -func UnmarshalScVal(raw []byte) (*v1alpha.ScVal, error) { - if len(raw) == 0 { - return nil, fmt.Errorf("raw ScVal bytes are empty") - } - sv := &v1alpha.ScVal{} - if err := proto.Unmarshal(raw, sv); err != nil { - return nil, fmt.Errorf("failed to unmarshal ScVal: %w", err) - } - return sv, nil -} - -// ScValBool creates a proto-marshalled SCV_BOOL ScVal. -func ScValBool(v bool) ([]byte, error) { - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_B{B: v}}) -} - -// ScValVoid creates a proto-marshalled SCV_VOID ScVal. -func ScValVoid() ([]byte, error) { - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_VoidVal{VoidVal: &v1alpha.Void{}}}) -} - -// ScValU32 creates a proto-marshalled SCV_U32 ScVal. -func ScValU32(v uint32) ([]byte, error) { - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_U32{U32: v}}) -} - -// ScValI32 creates a proto-marshalled SCV_I32 ScVal. -func ScValI32(v int32) ([]byte, error) { - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_I32{I32: v}}) -} - -// ScValU64 creates a proto-marshalled SCV_U64 ScVal. -func ScValU64(v uint64) ([]byte, error) { - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_U64{U64: v}}) -} - -// ScValI64 creates a proto-marshalled SCV_I64 ScVal. -func ScValI64(v int64) ([]byte, error) { - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_I64{I64: v}}) -} - -// ScValBytes creates a proto-marshalled SCV_BYTES ScVal. -func ScValBytes(v []byte) ([]byte, error) { - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_BytesVal{BytesVal: v}}) -} - -// ScValString creates a proto-marshalled SCV_STRING ScVal. -func ScValString(v string) ([]byte, error) { - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Str{Str: v}}) -} - -// ScValSymbol creates a proto-marshalled SCV_SYMBOL ScVal. -// Stellar symbols are limited to 32 characters. -func ScValSymbol(v string) ([]byte, error) { - if len(v) > 32 { - return nil, fmt.Errorf("symbol %q exceeds 32-character limit (%d chars)", v, len(v)) - } - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Sym{Sym: v}}) -} - -// ScValAddress creates a proto-marshalled SCV_ADDRESS ScVal. -func ScValAddress(addr *v1alpha.ScAddress) ([]byte, error) { - if addr == nil { - return nil, fmt.Errorf("ScAddress is nil") - } - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: addr}}) -} - -// ScValAccountAddress creates a proto-marshalled SCV_ADDRESS ScVal from a 32-byte -// Ed25519 public key (account address). -func ScValAccountAddress(pubKey []byte) ([]byte, error) { - if len(pubKey) != 32 { - return nil, fmt.Errorf("account public key must be 32 bytes, got %d", len(pubKey)) - } - return ScValAddress(&v1alpha.ScAddress{ - Address: &v1alpha.ScAddress_AccountId{AccountId: pubKey}, - }) -} - -// ScValContractAddress creates a proto-marshalled SCV_ADDRESS ScVal from a 32-byte -// contract hash. -func ScValContractAddress(contractHash []byte) ([]byte, error) { - if len(contractHash) != 32 { - return nil, fmt.Errorf("contract hash must be 32 bytes, got %d", len(contractHash)) - } - return ScValAddress(&v1alpha.ScAddress{ - Address: &v1alpha.ScAddress_ContractId{ContractId: contractHash}, - }) -} - -// ScValVec creates a proto-marshalled SCV_VEC ScVal from a slice of already -// proto-marshalled ScVal elements (as returned by the other helpers). -func ScValVec(elements [][]byte) ([]byte, error) { - vals := make([]*v1alpha.ScVal, 0, len(elements)) - for i, raw := range elements { - sv, err := UnmarshalScVal(raw) - if err != nil { - return nil, fmt.Errorf("element[%d]: %w", i, err) - } - vals = append(vals, sv) - } - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Vec{Vec: &v1alpha.ScVec{Values: vals}}}) -} - -// ScValMap creates a proto-marshalled SCV_MAP ScVal. keys and values must be -// slices of the same length, each element being a proto-marshalled ScVal. -func ScValMap(keys, values [][]byte) ([]byte, error) { - if len(keys) != len(values) { - return nil, fmt.Errorf("keys (%d) and values (%d) must have the same length", len(keys), len(values)) - } - entries := make([]*v1alpha.ScMapEntry, 0, len(keys)) - for i := range keys { - k, err := UnmarshalScVal(keys[i]) - if err != nil { - return nil, fmt.Errorf("key[%d]: %w", i, err) - } - v, err := UnmarshalScVal(values[i]) - if err != nil { - return nil, fmt.Errorf("value[%d]: %w", i, err) - } - entries = append(entries, &v1alpha.ScMapEntry{Key: k, Val: v}) - } - return MarshalScVal(&v1alpha.ScVal{Value: &v1alpha.ScVal_Map{Map: &v1alpha.ScMap{Entries: entries}}}) -} diff --git a/pkg/chains/stellar/proto_helpers_test.go b/pkg/chains/stellar/proto_helpers_test.go new file mode 100644 index 0000000000..a920f18427 --- /dev/null +++ b/pkg/chains/stellar/proto_helpers_test.go @@ -0,0 +1,1068 @@ +package stellar_test + +import ( + "encoding/base64" + "encoding/hex" + "strings" + "testing" + + "github.com/stellar/go-stellar-sdk/xdr" + "github.com/stretchr/testify/require" + + v1alpha "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/stellar/scval" + conv "github.com/smartcontractkit/chainlink-common/pkg/chains/stellar" + stellartypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/stellar" +) + +func TestConvertGetLedgerEntriesRequest_RoundTrip(t *testing.T) { + key1 := base64.StdEncoding.EncodeToString([]byte("key-one")) + key2 := base64.StdEncoding.EncodeToString([]byte("key-two")) + domain := stellartypes.GetLedgerEntriesRequest{Keys: []string{key1, key2}} + + proto, err := conv.ConvertGetLedgerEntriesRequestToProto(domain) + require.NoError(t, err) + require.Len(t, proto.GetKeys(), 2) + + got, err := conv.ConvertGetLedgerEntriesRequestFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertGetLedgerEntriesRequestToProto_InvalidBase64(t *testing.T) { + domain := stellartypes.GetLedgerEntriesRequest{Keys: []string{"not-valid-base64!!"}} + _, err := conv.ConvertGetLedgerEntriesRequestToProto(domain) + require.Error(t, err) + require.Contains(t, err.Error(), "key[0]") +} + +func TestConvertGetLedgerEntriesRequestFromProto_Nil(t *testing.T) { + _, err := conv.ConvertGetLedgerEntriesRequestFromProto(nil) + require.EqualError(t, err, "get ledger entries request is nil") +} + +func TestConvertGetLedgerEntriesRequestFromProto_EmptyKeys(t *testing.T) { + _, err := conv.ConvertGetLedgerEntriesRequestFromProto(&conv.GetLedgerEntriesRequest{}) + require.EqualError(t, err, "ledger entry keys are empty") +} + +func TestConvertLedgerEntryResult_RoundTrip(t *testing.T) { + liveUntil := uint32(9999) + domain := stellartypes.LedgerEntryResult{ + KeyXDR: base64.StdEncoding.EncodeToString([]byte("key-xdr")), + DataXDR: base64.StdEncoding.EncodeToString([]byte("data-xdr")), + LastModifiedLedger: 42, + LiveUntilLedgerSeq: &liveUntil, + ExtensionXDR: base64.StdEncoding.EncodeToString([]byte("ext-xdr")), + } + + proto, err := conv.ConvertLedgerEntryResultToProto(domain) + require.NoError(t, err) + require.True(t, proto.GetHasLiveUntilLedgerSeq()) + require.Equal(t, uint32(9999), proto.GetLiveUntilLedgerSeq()) + + got, err := conv.ConvertLedgerEntryResultFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertLedgerEntryResult_NoLiveUntil(t *testing.T) { + domain := stellartypes.LedgerEntryResult{ + KeyXDR: base64.StdEncoding.EncodeToString([]byte("k")), + DataXDR: base64.StdEncoding.EncodeToString([]byte("d")), + LastModifiedLedger: 1, + ExtensionXDR: base64.StdEncoding.EncodeToString([]byte("e")), + } + + proto, err := conv.ConvertLedgerEntryResultToProto(domain) + require.NoError(t, err) + require.False(t, proto.GetHasLiveUntilLedgerSeq()) + + got, err := conv.ConvertLedgerEntryResultFromProto(proto) + require.NoError(t, err) + require.Nil(t, got.LiveUntilLedgerSeq) + require.Equal(t, domain, got) +} + +func TestConvertLedgerEntryResultFromProto_Nil(t *testing.T) { + _, err := conv.ConvertLedgerEntryResultFromProto(nil) + require.EqualError(t, err, "ledger entry result is nil") +} + +func TestConvertGetLedgerEntriesResponse_RoundTrip(t *testing.T) { + liveUntil := uint32(500) + domain := stellartypes.GetLedgerEntriesResponse{ + Entries: []stellartypes.LedgerEntryResult{ + {KeyXDR: base64.StdEncoding.EncodeToString([]byte("k1")), DataXDR: base64.StdEncoding.EncodeToString([]byte("d1")), LastModifiedLedger: 10, ExtensionXDR: base64.StdEncoding.EncodeToString(nil)}, + {KeyXDR: base64.StdEncoding.EncodeToString([]byte("k2")), DataXDR: base64.StdEncoding.EncodeToString([]byte("d2")), LastModifiedLedger: 20, LiveUntilLedgerSeq: &liveUntil, ExtensionXDR: base64.StdEncoding.EncodeToString(nil)}, + }, + LatestLedger: 999, + } + + proto, err := conv.ConvertGetLedgerEntriesResponseToProto(domain) + require.NoError(t, err) + require.Len(t, proto.GetEntries(), 2) + + got, err := conv.ConvertGetLedgerEntriesResponseFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertGetLedgerEntriesResponseFromProto_Nil(t *testing.T) { + _, err := conv.ConvertGetLedgerEntriesResponseFromProto(nil) + require.EqualError(t, err, "get ledger entries response is nil") +} + +func TestConvertGetLatestLedgerResponse_RoundTrip(t *testing.T) { + var b [32]byte + for i := range b { + b[i] = 0xAB + } + hash := b + domain := stellartypes.GetLatestLedgerResponse{ + Hash: hex.EncodeToString(hash[:]), + ProtocolVersion: 21, + Sequence: 1234567, + LedgerCloseTime: 1_700_000_000, + LedgerHeaderXDR: base64.StdEncoding.EncodeToString([]byte("header-xdr")), + LedgerMetadataXDR: base64.StdEncoding.EncodeToString([]byte("meta-xdr")), + } + + proto, err := conv.ConvertGetLatestLedgerResponseToProto(domain) + require.NoError(t, err) + + got, err := conv.ConvertGetLatestLedgerResponseFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertGetLatestLedgerResponseFromProto_Nil(t *testing.T) { + _, err := conv.ConvertGetLatestLedgerResponseFromProto(nil) + require.EqualError(t, err, "get latest ledger response is nil") +} + +func TestConvertReadContractRequest_RoundTrip(t *testing.T) { + boolVal := true + u32 := xdr.Uint32(77) + sym := xdr.ScSymbol("hello") + domain := stellartypes.ReadContractRequest{ + ContractID: "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4", + Function: "transfer", + Args: []xdr.ScVal{ + {Type: xdr.ScValTypeScvBool, B: &boolVal}, + {Type: xdr.ScValTypeScvU32, U32: &u32}, + {Type: xdr.ScValTypeScvSymbol, Sym: &sym}, + }, + LedgerSequence: 42, + } + + proto, err := conv.ConvertReadContractRequestToProto(domain) + require.NoError(t, err) + require.Len(t, proto.GetArgs(), 3) + + got, err := conv.ConvertReadContractRequestFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertReadContractRequestFromProto_Nil(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(nil) + require.EqualError(t, err, "ReadContractRequest is nil") +} + +func TestConvertReadContractRequestFromProto_MissingContractID(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(&conv.ReadContractRequest{Function: "fn"}) + require.EqualError(t, err, "contract_id is required") +} + +func TestConvertReadContractRequestFromProto_MissingFunction(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(&conv.ReadContractRequest{ContractId: "C123"}) + require.EqualError(t, err, "function is required") +} + +func TestConvertReadContractResponse_RoundTrip_WithResult(t *testing.T) { + i64 := xdr.Int64(-99) + sv := xdr.ScVal{Type: xdr.ScValTypeScvI64, I64: &i64} + domain := stellartypes.ReadContractResponse{ + Result: &sv, + LedgerSequence: 55, + Error: "", + } + + proto, err := conv.ConvertReadContractResponseToProto(domain) + require.NoError(t, err) + require.NotNil(t, proto.GetResult()) + + got, err := conv.ConvertReadContractResponseFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertReadContractResponse_RoundTrip_WithError(t *testing.T) { + domain := stellartypes.ReadContractResponse{ + Result: nil, + LedgerSequence: 10, + Error: "contract panicked", + } + + proto, err := conv.ConvertReadContractResponseToProto(domain) + require.NoError(t, err) + require.Nil(t, proto.GetResult()) + + got, err := conv.ConvertReadContractResponseFromProto(proto) + require.NoError(t, err) + require.Equal(t, domain, got) +} + +func TestConvertReadContractResponseFromProto_Nil(t *testing.T) { + _, err := conv.ConvertReadContractResponseFromProto(nil) + require.EqualError(t, err, "readContractResponse is nil") +} + +func scValRoundTrip(t *testing.T, sv xdr.ScVal) xdr.ScVal { + t.Helper() + req := stellartypes.ReadContractRequest{ + ContractID: "C_TESTCONTRACT", + Function: "fn", + Args: []xdr.ScVal{sv}, + } + proto, err := conv.ConvertReadContractRequestToProto(req) + require.NoError(t, err) + got, err := conv.ConvertReadContractRequestFromProto(proto) + require.NoError(t, err) + require.Len(t, got.Args, 1) + return got.Args[0] +} + +func TestScVal_Bool(t *testing.T) { + b := true + sv := xdr.ScVal{Type: xdr.ScValTypeScvBool, B: &b} + got := scValRoundTrip(t, sv) + require.Equal(t, sv, got) +} + +func TestScVal_Void(t *testing.T) { + sv := xdr.ScVal{Type: xdr.ScValTypeScvVoid} + got := scValRoundTrip(t, sv) + require.Equal(t, xdr.ScValTypeScvVoid, got.Type) +} + +func TestScVal_Error_ContractCode(t *testing.T) { + cc := xdr.Uint32(42) + sv := xdr.ScVal{Type: xdr.ScValTypeScvError, Error: &xdr.ScError{ + Type: xdr.ScErrorTypeSceContract, + ContractCode: &cc, + }} + got := scValRoundTrip(t, sv) + require.Equal(t, sv, got) +} + +func TestScVal_Error_Code(t *testing.T) { + code := xdr.ScErrorCodeScecArithDomain + sv := xdr.ScVal{Type: xdr.ScValTypeScvError, Error: &xdr.ScError{ + Type: xdr.ScErrorTypeSceWasmVm, + Code: &code, + }} + got := scValRoundTrip(t, sv) + require.Equal(t, sv, got) +} + +func TestScVal_U32(t *testing.T) { + u := xdr.Uint32(0xDEAD) + sv := xdr.ScVal{Type: xdr.ScValTypeScvU32, U32: &u} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_I32(t *testing.T) { + i := xdr.Int32(-1234) + sv := xdr.ScVal{Type: xdr.ScValTypeScvI32, I32: &i} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_U64(t *testing.T) { + u := xdr.Uint64(1 << 40) + sv := xdr.ScVal{Type: xdr.ScValTypeScvU64, U64: &u} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_I64(t *testing.T) { + i := xdr.Int64(-1 << 40) + sv := xdr.ScVal{Type: xdr.ScValTypeScvI64, I64: &i} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Timepoint(t *testing.T) { + tp := xdr.TimePoint(1_700_000_000) + sv := xdr.ScVal{Type: xdr.ScValTypeScvTimepoint, Timepoint: &tp} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Duration(t *testing.T) { + d := xdr.Duration(3600) + sv := xdr.ScVal{Type: xdr.ScValTypeScvDuration, Duration: &d} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_U128(t *testing.T) { + u := xdr.UInt128Parts{Hi: xdr.Uint64(0xAAAA), Lo: xdr.Uint64(0xBBBB)} + sv := xdr.ScVal{Type: xdr.ScValTypeScvU128, U128: &u} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_I128(t *testing.T) { + i := xdr.Int128Parts{Hi: xdr.Int64(-7), Lo: xdr.Uint64(999)} + sv := xdr.ScVal{Type: xdr.ScValTypeScvI128, I128: &i} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_U256(t *testing.T) { + u := xdr.UInt256Parts{ + HiHi: xdr.Uint64(1), HiLo: xdr.Uint64(2), + LoHi: xdr.Uint64(3), LoLo: xdr.Uint64(4), + } + sv := xdr.ScVal{Type: xdr.ScValTypeScvU256, U256: &u} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_I256(t *testing.T) { + i := xdr.Int256Parts{ + HiHi: xdr.Int64(-1), HiLo: xdr.Uint64(2), + LoHi: xdr.Uint64(3), LoLo: xdr.Uint64(4), + } + sv := xdr.ScVal{Type: xdr.ScValTypeScvI256, I256: &i} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Bytes(t *testing.T) { + xb := xdr.ScBytes([]byte{0x01, 0x02, 0x03}) + sv := xdr.ScVal{Type: xdr.ScValTypeScvBytes, Bytes: &xb} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_String(t *testing.T) { + s := xdr.ScString("hello world") + sv := xdr.ScVal{Type: xdr.ScValTypeScvString, Str: &s} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Symbol(t *testing.T) { + sym := xdr.ScSymbol("transfer") + sv := xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &sym} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Vec(t *testing.T) { + u := xdr.Uint32(1) + inner := xdr.ScVal{Type: xdr.ScValTypeScvU32, U32: &u} + vec := xdr.ScVec{inner} + vecp := &vec + sv := xdr.ScVal{Type: xdr.ScValTypeScvVec, Vec: &vecp} + got := scValRoundTrip(t, sv) + require.Equal(t, sv, got) +} + +func TestScVal_Map(t *testing.T) { + sym := xdr.ScSymbol("key") + u := xdr.Uint32(99) + xmap := xdr.ScMap{ + {Key: xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &sym}, Val: xdr.ScVal{Type: xdr.ScValTypeScvU32, U32: &u}}, + } + xmapp := &xmap + sv := xdr.ScVal{Type: xdr.ScValTypeScvMap, Map: &xmapp} + got := scValRoundTrip(t, sv) + require.Equal(t, sv, got) +} + +func TestScVal_Address_Account(t *testing.T) { + var b [32]byte + for i := range b { + b[i] = 0x01 + } + ed := b + ed256 := xdr.Uint256(ed) + aid := xdr.AccountId(xdr.PublicKey{ + Type: xdr.PublicKeyTypePublicKeyTypeEd25519, + Ed25519: &ed256, + }) + sv := xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeAccount, + AccountId: &aid, + }} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Address_Contract(t *testing.T) { + var b [32]byte + for i := range b { + b[i] = 0x02 + } + cid := xdr.ContractId(b) + sv := xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeContract, + ContractId: &cid, + }} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Address_MuxedAccount(t *testing.T) { + var b [32]byte + for i := range b { + b[i] = 0x03 + } + ed := xdr.Uint256(b) + sv := xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeMuxedAccount, + MuxedAccount: &xdr.MuxedEd25519Account{ + Id: xdr.Uint64(777), + Ed25519: ed, + }, + }} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Address_ClaimableBalance(t *testing.T) { + var b [32]byte + for i := range b { + b[i] = 0x04 + } + h := xdr.Hash(b) + sv := xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeClaimableBalance, + ClaimableBalanceId: &xdr.ClaimableBalanceId{ + Type: xdr.ClaimableBalanceIdTypeClaimableBalanceIdTypeV0, + V0: &h, + }, + }} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_Address_LiquidityPool(t *testing.T) { + var b [32]byte + for i := range b { + b[i] = 0x05 + } + pid := xdr.PoolId(b) + sv := xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeLiquidityPool, + LiquidityPoolId: &pid, + }} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_ContractInstance_Wasm(t *testing.T) { + var b [32]byte + for i := range b { + b[i] = 0x06 + } + wh := xdr.Hash(b) + sv := xdr.ScVal{Type: xdr.ScValTypeScvContractInstance, Instance: &xdr.ScContractInstance{ + Executable: xdr.ContractExecutable{ + Type: xdr.ContractExecutableTypeContractExecutableWasm, + WasmHash: &wh, + }, + }} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_ContractInstance_StellarAsset(t *testing.T) { + sv := xdr.ScVal{Type: xdr.ScValTypeScvContractInstance, Instance: &xdr.ScContractInstance{ + Executable: xdr.ContractExecutable{Type: xdr.ContractExecutableTypeContractExecutableStellarAsset}, + }} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_ContractInstance_WithStorage(t *testing.T) { + var b [32]byte + for i := range b { + b[i] = 0x07 + } + wh := xdr.Hash(b) + sym := xdr.ScSymbol("slot") + u := xdr.Uint32(1) + storage := xdr.ScMap{ + {Key: xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &sym}, Val: xdr.ScVal{Type: xdr.ScValTypeScvU32, U32: &u}}, + } + sv := xdr.ScVal{Type: xdr.ScValTypeScvContractInstance, Instance: &xdr.ScContractInstance{ + Executable: xdr.ContractExecutable{ + Type: xdr.ContractExecutableTypeContractExecutableWasm, + WasmHash: &wh, + }, + Storage: &storage, + }} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_LedgerKeyContractInstance(t *testing.T) { + sv := xdr.ScVal{Type: xdr.ScValTypeScvLedgerKeyContractInstance} + got := scValRoundTrip(t, sv) + require.Equal(t, xdr.ScValTypeScvLedgerKeyContractInstance, got.Type) +} + +func TestScVal_LedgerKeyNonce(t *testing.T) { + sv := xdr.ScVal{Type: xdr.ScValTypeScvLedgerKeyNonce, NonceKey: &xdr.ScNonceKey{Nonce: xdr.Int64(12345)}} + require.Equal(t, sv, scValRoundTrip(t, sv)) +} + +func TestScVal_NestedVecMap(t *testing.T) { + // Vec containing a Map: [{sym:"x" -> u32:1}] + sym := xdr.ScSymbol("x") + u := xdr.Uint32(1) + innerMap := xdr.ScMap{{ + Key: xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &sym}, + Val: xdr.ScVal{Type: xdr.ScValTypeScvU32, U32: &u}, + }} + innerMapP := &innerMap + mapVal := xdr.ScVal{Type: xdr.ScValTypeScvMap, Map: &innerMapP} + vec := xdr.ScVec{mapVal} + vecp := &vec + sv := xdr.ScVal{Type: xdr.ScValTypeScvVec, Vec: &vecp} + + got := scValRoundTrip(t, sv) + require.Equal(t, sv, got) +} + +func TestScVal_ExceedsMaxDepth(t *testing.T) { + // Build a ScVal nested 66 levels deep via ReadContract args conversion. + // We construct the nesting bottom-up. + u := xdr.Uint32(0) + leaf := xdr.ScVal{Type: xdr.ScValTypeScvU32, U32: &u} + cur := leaf + for i := 0; i < 66; i++ { + vec := xdr.ScVec{cur} + vecp := &vec + cur = xdr.ScVal{Type: xdr.ScValTypeScvVec, Vec: &vecp} + } + + req := stellartypes.ReadContractRequest{ + ContractID: "C_DEEP", + Function: "fn", + Args: []xdr.ScVal{cur}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.Error(t, err) + require.Contains(t, err.Error(), "nesting exceeds maximum depth") +} + +func TestProtoScVal_NilValue(t *testing.T) { + // A proto ReadContractRequest carrying a nil ScVal should fail gracefully. + p := &conv.ReadContractRequest{ + ContractId: "C_X", + Function: "fn", + Args: []*v1alpha.ScVal{nil}, + } + _, err := conv.ConvertReadContractRequestFromProto(p) + require.Error(t, err) + require.Contains(t, err.Error(), "args[0]") +} + +func TestProtoScVal_AccountId_WrongLength(t *testing.T) { + p := &conv.ReadContractRequest{ + ContractId: "C_X", + Function: "fn", + Args: []*v1alpha.ScVal{ + {Value: &v1alpha.ScVal_Address{Address: &v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_AccountId{AccountId: []byte{0x01, 0x02}}, + }}}, + }, + } + _, err := conv.ConvertReadContractRequestFromProto(p) + require.Error(t, err) + require.Contains(t, err.Error(), "accountId must be 32 bytes") +} + +func TestProtoScVal_ContractId_WrongLength(t *testing.T) { + p := &conv.ReadContractRequest{ + ContractId: "C_X", + Function: "fn", + Args: []*v1alpha.ScVal{ + {Value: &v1alpha.ScVal_Address{Address: &v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_ContractId{ContractId: []byte("short")}, + }}}, + }, + } + _, err := conv.ConvertReadContractRequestFromProto(p) + require.Error(t, err) + require.Contains(t, err.Error(), "contractId must be 32 bytes") +} + +func TestProtoScVal_WasmHash_WrongLength(t *testing.T) { + p := &conv.ReadContractRequest{ + ContractId: "C_X", + Function: "fn", + Args: []*v1alpha.ScVal{ + {Value: &v1alpha.ScVal_ContractInstance{ContractInstance: &v1alpha.ScContractInstance{ + Executable: &v1alpha.ContractExecutable{ + Type: &v1alpha.ContractExecutable_WasmHash{WasmHash: []byte("tooshort")}, + }, + }}}, + }, + } + _, err := conv.ConvertReadContractRequestFromProto(p) + require.Error(t, err) + require.Contains(t, err.Error(), "wasmHash must be 32 bytes") +} + +func TestProtoScVal_ExceedsMaxDepth(t *testing.T) { + // Build proto ScVal nested 66 levels deep. + u := uint32(0) + leaf := &v1alpha.ScVal{Value: &v1alpha.ScVal_U32{U32: u}} + cur := leaf + for i := 0; i < 66; i++ { + cur = &v1alpha.ScVal{Value: &v1alpha.ScVal_Vec{Vec: &v1alpha.ScVec{Values: []*v1alpha.ScVal{cur}}}} + } + p := &conv.ReadContractRequest{ + ContractId: "C_X", + Function: "fn", + Args: []*v1alpha.ScVal{cur}, + } + _, err := conv.ConvertReadContractRequestFromProto(p) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "nesting exceeds maximum depth"), "unexpected error: %v", err) +} + +// ---- ConvertReadContractRequestToProto validation --------------------------- + +func TestConvertReadContractRequestToProto_MissingContractID(t *testing.T) { + _, err := conv.ConvertReadContractRequestToProto(stellartypes.ReadContractRequest{Function: "fn"}) + require.EqualError(t, err, "contractID is required") +} + +func TestConvertReadContractRequestToProto_MissingFunction(t *testing.T) { + _, err := conv.ConvertReadContractRequestToProto(stellartypes.ReadContractRequest{ContractID: "C_X"}) + require.EqualError(t, err, "function is required") +} + +func TestConvertReadContractRequestToProto_BadArg(t *testing.T) { + // A ScVal with a nil arm pointer triggers an error that must be wrapped as args[0]. + _, err := conv.ConvertReadContractRequestToProto(stellartypes.ReadContractRequest{ + ContractID: "C_X", + Function: "fn", + Args: []xdr.ScVal{{Type: xdr.ScValTypeScvBool}}, // B is nil + }) + require.Error(t, err) + require.Contains(t, err.Error(), "args[0]") +} + +// ---- ConvertLedgerEntryResultToProto invalid XDR fields --------------------- + +func TestConvertLedgerEntryResultToProto_InvalidDataXDR(t *testing.T) { + _, err := conv.ConvertLedgerEntryResultToProto(stellartypes.LedgerEntryResult{ + KeyXDR: base64.StdEncoding.EncodeToString([]byte("k")), + DataXDR: "!!!invalid!!!", + ExtensionXDR: base64.StdEncoding.EncodeToString([]byte("e")), + }) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid data xdr") +} + +func TestConvertLedgerEntryResultToProto_InvalidExtensionXDR(t *testing.T) { + _, err := conv.ConvertLedgerEntryResultToProto(stellartypes.LedgerEntryResult{ + KeyXDR: base64.StdEncoding.EncodeToString([]byte("k")), + DataXDR: base64.StdEncoding.EncodeToString([]byte("d")), + ExtensionXDR: "!!!invalid!!!", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid extension xdr") +} + +// ---- GetLedgerEntriesResponse entry error propagation ----------------------- + +func TestConvertGetLedgerEntriesResponseToProto_BadEntry(t *testing.T) { + _, err := conv.ConvertGetLedgerEntriesResponseToProto(stellartypes.GetLedgerEntriesResponse{ + Entries: []stellartypes.LedgerEntryResult{ + {KeyXDR: "!!!bad!!!", DataXDR: "", ExtensionXDR: ""}, + }, + }) + require.Error(t, err) + require.Contains(t, err.Error(), "entry[0]") +} + +func TestConvertGetLedgerEntriesResponseFromProto_NilEntry(t *testing.T) { + _, err := conv.ConvertGetLedgerEntriesResponseFromProto(&conv.GetLedgerEntriesResponse{ + Entries: []*conv.LedgerEntryResult{nil}, + }) + require.Error(t, err) + require.Contains(t, err.Error(), "entry[0]") +} + +// ---- ConvertGetLatestLedgerResponseToProto error cases ---------------------- + +func TestConvertGetLatestLedgerResponseToProto_InvalidHash(t *testing.T) { + _, err := conv.ConvertGetLatestLedgerResponseToProto(stellartypes.GetLatestLedgerResponse{ + Hash: "not-hex!", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid hex hash") +} + +func TestConvertGetLatestLedgerResponseToProto_InvalidHeaderXDR(t *testing.T) { + _, err := conv.ConvertGetLatestLedgerResponseToProto(stellartypes.GetLatestLedgerResponse{ + LedgerHeaderXDR: "!!!bad!!!", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid ledger header xdr") +} + +func TestConvertGetLatestLedgerResponseToProto_InvalidMetadataXDR(t *testing.T) { + _, err := conv.ConvertGetLatestLedgerResponseToProto(stellartypes.GetLatestLedgerResponse{ + LedgerMetadataXDR: "!!!bad!!!", + }) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid ledger metadata xdr") +} + +// ---- ConvertReadContractResponse result error propagation ------------------- + +func TestConvertReadContractResponseToProto_BadResult(t *testing.T) { + sv := xdr.ScVal{Type: xdr.ScValTypeScvBool} // B is nil → error + _, err := conv.ConvertReadContractResponseToProto(stellartypes.ReadContractResponse{Result: &sv}) + require.Error(t, err) + require.Contains(t, err.Error(), "result") +} + +func TestConvertReadContractResponseFromProto_BadResult(t *testing.T) { + _, err := conv.ConvertReadContractResponseFromProto(&conv.ReadContractResponse{ + Result: &v1alpha.ScVal{Value: &v1alpha.ScVal_U128{U128: nil}}, + }) + require.Error(t, err) + require.Contains(t, err.Error(), "result") +} + +// ---- XDR→proto nil arm pointer cases (table-driven) ------------------------ + +func TestXdrScValToProto_NilArmPointers(t *testing.T) { + tests := []struct { + name string + sv xdr.ScVal + wantErr string + }{ + {"bool nil", xdr.ScVal{Type: xdr.ScValTypeScvBool}, "scvBool: nil"}, + {"error nil", xdr.ScVal{Type: xdr.ScValTypeScvError}, "scvError: nil"}, + {"u32 nil", xdr.ScVal{Type: xdr.ScValTypeScvU32}, "scvU32: nil"}, + {"i32 nil", xdr.ScVal{Type: xdr.ScValTypeScvI32}, "scvI32: nil"}, + {"u64 nil", xdr.ScVal{Type: xdr.ScValTypeScvU64}, "scvU64: nil"}, + {"i64 nil", xdr.ScVal{Type: xdr.ScValTypeScvI64}, "scvI64: nil"}, + {"timepoint nil", xdr.ScVal{Type: xdr.ScValTypeScvTimepoint}, "scvTimepoint: nil"}, + {"duration nil", xdr.ScVal{Type: xdr.ScValTypeScvDuration}, "scvDuration: nil"}, + {"u128 nil", xdr.ScVal{Type: xdr.ScValTypeScvU128}, "scvU128: nil"}, + {"i128 nil", xdr.ScVal{Type: xdr.ScValTypeScvI128}, "scvI128: nil"}, + {"u256 nil", xdr.ScVal{Type: xdr.ScValTypeScvU256}, "scvU256: nil"}, + {"i256 nil", xdr.ScVal{Type: xdr.ScValTypeScvI256}, "scvI256: nil"}, + {"bytes nil", xdr.ScVal{Type: xdr.ScValTypeScvBytes}, "scvBytes: nil"}, + {"string nil", xdr.ScVal{Type: xdr.ScValTypeScvString}, "scvString: nil"}, + {"symbol nil", xdr.ScVal{Type: xdr.ScValTypeScvSymbol}, "scvSymbol: nil"}, + {"address nil", xdr.ScVal{Type: xdr.ScValTypeScvAddress}, "scvAddress: nil"}, + {"contractInstance nil", xdr.ScVal{Type: xdr.ScValTypeScvContractInstance}, "scvContractInstance: nil"}, + {"nonceKey nil", xdr.ScVal{Type: xdr.ScValTypeScvLedgerKeyNonce}, "scvLedgerKeyNonce: nil"}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", Args: []xdr.ScVal{tc.sv}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, tc.wantErr) + }) + } +} + +func TestXdrScValToProto_UnsupportedType(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{Type: xdr.ScValType(999)}}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "unsupported ScVal type") +} + +func TestXdrScError_NilContractCode(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvError, + Error: &xdr.ScError{Type: xdr.ScErrorTypeSceContract}, // ContractCode nil + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "scError.contractCode: nil") +} + +func TestXdrScError_NilCode(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvError, + Error: &xdr.ScError{Type: xdr.ScErrorTypeSceWasmVm}, // Code nil + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "nil code") +} + +func TestXdrScAddress_NilAccountId(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvAddress, + Address: &xdr.ScAddress{Type: xdr.ScAddressTypeScAddressTypeAccount}, // AccountId nil + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "scAddress.account") +} + +func TestXdrScAddress_NilContractId(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvAddress, + Address: &xdr.ScAddress{Type: xdr.ScAddressTypeScAddressTypeContract}, // ContractId nil + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "scAddress.contract: nil contractId") +} + +func TestXdrScAddress_NilMuxedAccount(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvAddress, + Address: &xdr.ScAddress{Type: xdr.ScAddressTypeScAddressTypeMuxedAccount}, // MuxedAccount nil + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "scAddress.muxed: nil") +} + +func TestXdrScAddress_NilClaimableBalance(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvAddress, + Address: &xdr.ScAddress{Type: xdr.ScAddressTypeScAddressTypeClaimableBalance}, // ClaimableBalanceId nil + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "scAddress.claimableBalance: nil") +} + +func TestXdrScAddress_NilLiquidityPool(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvAddress, + Address: &xdr.ScAddress{Type: xdr.ScAddressTypeScAddressTypeLiquidityPool}, // LiquidityPoolId nil + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "scAddress.liquidityPool: nil poolId") +} + +func TestXdrScAddress_UnsupportedType(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvAddress, + Address: &xdr.ScAddress{Type: xdr.ScAddressType(999)}, + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "unsupported ScAddress type") +} + +func TestXdrContractExecutable_NilWasmHash(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvContractInstance, + Instance: &xdr.ScContractInstance{ + Executable: xdr.ContractExecutable{Type: xdr.ContractExecutableTypeContractExecutableWasm}, // WasmHash nil + }, + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "contractExecutable.wasm: nil wasmHash") +} + +func TestXdrContractExecutable_UnsupportedType(t *testing.T) { + req := stellartypes.ReadContractRequest{ + ContractID: "C_X", Function: "fn", + Args: []xdr.ScVal{{ + Type: xdr.ScValTypeScvContractInstance, + Instance: &xdr.ScContractInstance{ + Executable: xdr.ContractExecutable{Type: xdr.ContractExecutableType(999)}, + }, + }}, + } + _, err := conv.ConvertReadContractRequestToProto(req) + require.ErrorContains(t, err, "unsupported ContractExecutable type") +} + +// ---- Proto→XDR nil/invalid cases (table-driven) ---------------------------- + +func protoScValArg(val *v1alpha.ScVal) *conv.ReadContractRequest { + return &conv.ReadContractRequest{ + ContractId: "C_X", + Function: "fn", + Args: []*v1alpha.ScVal{val}, + } +} + +func TestProtoScVal_NilInnerFields(t *testing.T) { + tests := []struct { + name string + req *conv.ReadContractRequest + wantErr string + }{ + { + "u128 nil", + protoScValArg(&v1alpha.ScVal{Value: &v1alpha.ScVal_U128{U128: nil}}), + "scvU128: nil", + }, + { + "i128 nil", + protoScValArg(&v1alpha.ScVal{Value: &v1alpha.ScVal_I128{I128: nil}}), + "scvI128: nil", + }, + { + "u256 nil", + protoScValArg(&v1alpha.ScVal{Value: &v1alpha.ScVal_U256{U256: nil}}), + "scvU256: nil", + }, + { + "i256 nil", + protoScValArg(&v1alpha.ScVal{Value: &v1alpha.ScVal_I256{I256: nil}}), + "scvI256: nil", + }, + { + "vec nil", + protoScValArg(&v1alpha.ScVal{Value: &v1alpha.ScVal_Vec{Vec: nil}}), + "scvVec: nil", + }, + { + "map nil", + protoScValArg(&v1alpha.ScVal{Value: &v1alpha.ScVal_Map{Map: nil}}), + "scvMap: nil", + }, + { + "nonceKey nil", + protoScValArg(&v1alpha.ScVal{Value: &v1alpha.ScVal_NonceKey{NonceKey: nil}}), + "scvLedgerKeyNonce: nil", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(tc.req) + require.ErrorContains(t, err, tc.wantErr) + }) + } +} + +func TestProtoScVal_UnsupportedOneof(t *testing.T) { + // A zero-value ScVal (nil Value oneof) hits the default case. + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg(&v1alpha.ScVal{})) + require.ErrorContains(t, err, "unsupported proto ScVal type") +} + +func TestProtoScAddress_Nil(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: nil}}, + )) + require.ErrorContains(t, err, "proto ScAddress is nil") +} + +func TestProtoScAddress_MuxedAccount_Nil(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: &v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_MuxedAccount{MuxedAccount: nil}, + }}}, + )) + require.ErrorContains(t, err, "muxedAccount: nil") +} + +func TestProtoScAddress_MuxedAccount_WrongEd25519Size(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: &v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_MuxedAccount{MuxedAccount: &v1alpha.MuxedEd25519Account{ + Id: 1, + Ed25519: []byte{0x01, 0x02}, // not 32 bytes + }}, + }}}, + )) + require.ErrorContains(t, err, "muxedAccount.ed25519 must be 32 bytes") +} + +func TestProtoScAddress_ClaimableBalanceId_Nil(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: &v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_ClaimableBalanceId{ClaimableBalanceId: nil}, + }}}, + )) + require.ErrorContains(t, err, "claimableBalanceId: nil") +} + +func TestProtoScAddress_ClaimableBalanceId_WrongV0Size(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: &v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_ClaimableBalanceId{ClaimableBalanceId: &v1alpha.ClaimableBalanceId{ + V0: []byte{0x01, 0x02}, // not 32 bytes + }}, + }}}, + )) + require.ErrorContains(t, err, "claimableBalanceId.v0 must be 32 bytes") +} + +func TestProtoScAddress_LiquidityPoolId_WrongSize(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: &v1alpha.ScAddress{ + Address: &v1alpha.ScAddress_LiquidityPoolId{LiquidityPoolId: []byte("short")}, + }}}, + )) + require.ErrorContains(t, err, "liquidityPoolId must be 32 bytes") +} + +func TestProtoScAddress_UnsupportedOneof(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Address{Address: &v1alpha.ScAddress{Address: nil}}}, + )) + require.ErrorContains(t, err, "unsupported proto ScAddress type") +} + +func TestProtoContractExecutable_Nil(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_ContractInstance{ContractInstance: &v1alpha.ScContractInstance{ + Executable: nil, + }}}, + )) + require.ErrorContains(t, err, "proto ContractExecutable is nil") +} + +func TestProtoContractExecutable_UnsupportedOneof(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_ContractInstance{ContractInstance: &v1alpha.ScContractInstance{ + Executable: &v1alpha.ContractExecutable{Type: nil}, + }}}, + )) + require.ErrorContains(t, err, "unsupported proto ContractExecutable type") +} + +func TestProtoScContractInstance_Nil(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_ContractInstance{ContractInstance: nil}}, + )) + require.ErrorContains(t, err, "proto ScContractInstance is nil") +} + +func TestProtoScError_Nil(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Error{Error: nil}}, + )) + require.ErrorContains(t, err, "proto ScError is nil") +} + +func TestProtoScError_UnsupportedOneof(t *testing.T) { + _, err := conv.ConvertReadContractRequestFromProto(protoScValArg( + &v1alpha.ScVal{Value: &v1alpha.ScVal_Error{Error: &v1alpha.ScError{CodeOrContract: nil}}}, + )) + require.ErrorContains(t, err, "unsupported ScError oneof") +} From e24a070c7acd8962405cd2326cf52563881404ff Mon Sep 17 00:00:00 2001 From: ilija Date: Tue, 12 May 2026 23:25:05 +0200 Subject: [PATCH 3/4] bump versions --- go.mod | 2 +- go.sum | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index d84b45d143..da036463d4 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.89 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512162638-c38861010453 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512210850-61ff5a195fdc github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 diff --git a/go.sum b/go.sum index 024d277dae..c88fb762e9 100644 --- a/go.sum +++ b/go.sum @@ -270,9 +270,8 @@ github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260511222622-3dae6143f38a/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512162638-c38861010453 h1:SXsCAHJaW/eXgKDIV1Hq1xIjft/c58r2SQ1nRRmeECM= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512162638-c38861010453/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512210850-61ff5a195fdc h1:55WrjPyIbgyZbMIGZVWBGeN2+KVGZi5tZfYsIviWbEw= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260512210850-61ff5a195fdc/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b h1:36knUpKHHAZ86K4FGWXtx8i/EQftGdk2bqCoEu/Cha8= From e4eef69812b910cfb8acefe552ff06e34bf3f791 Mon Sep 17 00:00:00 2001 From: ilija Date: Tue, 12 May 2026 23:35:48 +0200 Subject: [PATCH 4/4] tidy --- .../stellar/proto_helpers.go | 15 +++-- pkg/loop/internal/relayerset/stellar.go | 24 ++++++++ pkg/types/mocks/stellar_service.go | 57 +++++++++++++++++++ 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers.go b/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers.go index e981e3159f..f12c0e4aaa 100644 --- a/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers.go +++ b/pkg/capabilities/v2/chain-capabilities/stellar/proto_helpers.go @@ -3,7 +3,6 @@ package stellar import ( "encoding/base64" "encoding/hex" - "errors" "fmt" stellartypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/stellar" @@ -13,7 +12,7 @@ import ( // domain type. Hash is returned as lowercase hex; XDR fields are returned as standard base64. func ConvertGetLatestLedgerResponseFromProto(p *GetLatestLedgerResponse) (stellartypes.GetLatestLedgerResponse, error) { if p == nil { - return stellartypes.GetLatestLedgerResponse{}, errors.New("GetLatestLedgerResponse is nil") + return stellartypes.GetLatestLedgerResponse{}, fmt.Errorf("getLatestLedgerResponse is nil") } return stellartypes.GetLatestLedgerResponse{ @@ -57,13 +56,13 @@ func ConvertGetLatestLedgerResponseToProto(r stellartypes.GetLatestLedgerRespons // ValidateReadContractRequest checks that required fields are present. func ValidateReadContractRequest(req *ReadContractRequest) error { if req == nil { - return errors.New("ReadContractRequest is nil") + return fmt.Errorf("readContractRequest is nil") } if req.ContractId == "" { - return errors.New("contract_id is required") + return fmt.Errorf("contract_id is required") } if req.Function == "" { - return errors.New("function is required") + return fmt.Errorf("function is required") } return nil } @@ -71,13 +70,13 @@ func ValidateReadContractRequest(req *ReadContractRequest) error { // ValidateWriteReportRequest checks that required fields are present. func ValidateWriteReportRequest(req *WriteReportRequest) error { if req == nil { - return errors.New("WriteReportRequest is nil") + return fmt.Errorf("writeReportRequest is nil") } if req.ContractId == "" { - return errors.New("contract_id is required") + return fmt.Errorf("contract_id is required") } if req.Report == nil { - return errors.New("report is required") + return fmt.Errorf("report is required") } return nil } diff --git a/pkg/loop/internal/relayerset/stellar.go b/pkg/loop/internal/relayerset/stellar.go index 7f9079f08b..cae6bb33d9 100644 --- a/pkg/loop/internal/relayerset/stellar.go +++ b/pkg/loop/internal/relayerset/stellar.go @@ -29,6 +29,10 @@ func (sc *stellarClient) GetLatestLedger(ctx context.Context, in *emptypb.Empty, return sc.client.GetLatestLedger(appendRelayID(ctx, sc.relayID), in, opts...) } +func (sc *stellarClient) ReadContract(ctx context.Context, in *stelpb.ReadContractRequest, opts ...grpc.CallOption) (*stelpb.ReadContractResponse, error) { + return sc.client.ReadContract(appendRelayID(ctx, sc.relayID), in, opts...) +} + // stellarServer implements stelpb.StellarServer by routing each RPC through the RelayerSet. type stellarServer struct { stelpb.UnimplementedStellarServer @@ -73,6 +77,26 @@ func (ss *stellarServer) GetLatestLedger(ctx context.Context, _ *emptypb.Empty) return pResp, nil } +func (ss *stellarServer) ReadContract(ctx context.Context, req *stelpb.ReadContractRequest) (*stelpb.ReadContractResponse, error) { + svc, err := ss.parent.getStellarService(ctx) + if err != nil { + return nil, err + } + dReq, err := stelpb.ConvertReadContractRequestFromProto(req) + if err != nil { + return nil, fmt.Errorf("invalid ReadContract request: %w", err) + } + dResp, err := svc.ReadContract(ctx, dReq) + if err != nil { + return nil, net.WrapRPCErr(err) + } + pResp, err := stelpb.ConvertReadContractResponseToProto(dResp) + if err != nil { + return nil, fmt.Errorf("invalid ReadContract response: %w", err) + } + return pResp, nil +} + // getStellarService extracts the RelayID from context metadata and returns the StellarService // for the corresponding relayer. func (s *Server) getStellarService(ctx context.Context) (types.StellarService, error) { diff --git a/pkg/types/mocks/stellar_service.go b/pkg/types/mocks/stellar_service.go index cf39019b37..078dc3dc35 100644 --- a/pkg/types/mocks/stellar_service.go +++ b/pkg/types/mocks/stellar_service.go @@ -135,6 +135,63 @@ func (_c *StellarService_GetLedgerEntries_Call) RunAndReturn(run func(context.Co return _c } +// ReadContract provides a mock function with given fields: ctx, req +func (_m *StellarService) ReadContract(ctx context.Context, req stellar.ReadContractRequest) (stellar.ReadContractResponse, error) { + ret := _m.Called(ctx, req) + + if len(ret) == 0 { + panic("no return value specified for ReadContract") + } + + var r0 stellar.ReadContractResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, stellar.ReadContractRequest) (stellar.ReadContractResponse, error)); ok { + return rf(ctx, req) + } + if rf, ok := ret.Get(0).(func(context.Context, stellar.ReadContractRequest) stellar.ReadContractResponse); ok { + r0 = rf(ctx, req) + } else { + r0 = ret.Get(0).(stellar.ReadContractResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, stellar.ReadContractRequest) error); ok { + r1 = rf(ctx, req) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StellarService_ReadContract_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadContract' +type StellarService_ReadContract_Call struct { + *mock.Call +} + +// ReadContract is a helper method to define mock.On call +// - ctx context.Context +// - req stellar.ReadContractRequest +func (_e *StellarService_Expecter) ReadContract(ctx interface{}, req interface{}) *StellarService_ReadContract_Call { + return &StellarService_ReadContract_Call{Call: _e.mock.On("ReadContract", ctx, req)} +} + +func (_c *StellarService_ReadContract_Call) Run(run func(ctx context.Context, req stellar.ReadContractRequest)) *StellarService_ReadContract_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(stellar.ReadContractRequest)) + }) + return _c +} + +func (_c *StellarService_ReadContract_Call) Return(_a0 stellar.ReadContractResponse, _a1 error) *StellarService_ReadContract_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StellarService_ReadContract_Call) RunAndReturn(run func(context.Context, stellar.ReadContractRequest) (stellar.ReadContractResponse, error)) *StellarService_ReadContract_Call { + _c.Call.Return(run) + return _c +} + // NewStellarService creates a new instance of StellarService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewStellarService(t interface {