diff --git a/.gitignore b/.gitignore index 9da808c..5b62604 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ bin/ vendor .idea - -.vscode \ No newline at end of file +.vscode +*.out +out.svg diff --git a/Makefile b/Makefile index cce8442..e3d81f3 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,9 @@ endif ldflags := -X 'main.appVersion=${VERSION}' GOCMD=go +GOIMPORT=goimports +GOINSTALL=$(GOCMD) install +GOTEST=$(GOCMD) test GORUN=$(GOCMD) run -ldflags="$(ldflags)" GOBUILD=$(GOCMD) build -ldflags="$(ldflags)" @@ -31,7 +34,37 @@ GOBUILD=$(GOCMD) build -ldflags="$(ldflags)" ############################ ### DEMO APP ### ############################ -.PHONY: demo-getAccount demo-transfer demo-createAsset demo.%: DEMO=$* demo.%: $(GORUN) ./cmd/demo/$(DEMO) + +############################ +### TESTS/COVERAGE ### +############################ +.PHONY: dependencies vet test test_coverage + +dependencies: + $(GOINSTALL) github.com/nikolaydubina/go-cover-treemap@latest + $(GOINSTALL) golang.org/x/tools/cmd/goimports@latest + +vet: + $(GOCMD) vet ./... + +imports: + $(eval CHECKFILES = $(shell find . -type f -name '*.go' -not -name '*.pb.go' -not -name '*_setter.go' -not -path './vendor/*')) + $(GOCMD) mod tidy + $(GOIMPORT) -d -w $(CHECKFILES) + +test: + $(GOCMD) clean -testcache + $(GOTEST) ./... + +test_coverage: + $(eval PACKAGES = $(shell go list ./... | grep -v '/proto/')) + $(GOTEST) -coverprofile cover.out $(PACKAGES) + go-cover-treemap -coverprofile cover.out > out.svg + +test_coveragehtml: + $(eval PACKAGES = $(shell go list ./... | grep -v '/proto/')) + $(GOTEST) -coverprofile cover.out $(PACKAGES) + $(GOCMD) tool cover -html=cover.out diff --git a/cmd/demo/createAsset/main.go b/cmd/demo/createAsset/main.go index 91add2e..e21d1e9 100644 --- a/cmd/demo/createAsset/main.go +++ b/cmd/demo/createAsset/main.go @@ -5,6 +5,7 @@ import ( "github.com/klever-io/klever-go-sdk/cmd/demo" "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" ) func main() { @@ -17,7 +18,7 @@ func main() { base := accounts[0].NewBaseTX() tx, err := kc.CreateKDA( base, - models.KDAData_Fungible, + proto.KDAData_Fungible, &models.KDAOptions{ Name: "KleverTest", Ticker: "TST", diff --git a/core/address/address_test.go b/core/address/address_test.go index 8036691..b3ea86b 100644 --- a/core/address/address_test.go +++ b/core/address/address_test.go @@ -11,6 +11,18 @@ import ( func TestAddress_ZeroAddress(t *testing.T) { addr := address.ZeroAddress() assert.Equal(t, addr.Bech32(), "klv1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpgm89z") + assert.Equal(t, "0000000000000000000000000000000000000000000000000000000000000000", hex.EncodeToString(addr.Bytes())) +} + +func TestAddress_InvalidSize(t *testing.T) { + _, err := address.NewAddressFromBytes([]byte("000")) + assert.Contains(t, err.Error(), "decoding address, expected length 32") + + _, err = address.NewAddressFromHex("000") + assert.Contains(t, err.Error(), "encoding/hex: odd length hex string") + + _, err = address.NewAddressFromHex("0000") + assert.Contains(t, err.Error(), "decoding address, expected length") } func TestAddress_Address_ShouldFail(t *testing.T) { @@ -29,6 +41,18 @@ func TestAddress_Address_ShouldFail(t *testing.T) { // invalid bech32 prefix _, err = address.NewAddress("kfi1qy352eufzqg3yyc5z5v3wxqeyqsjygeyy5nzw2pfxqcnyve5x5mq7ze5xk") assert.NotNil(t, err) + + // invalid decoded len + _, err = address.NewAddress("klv1d05ju9jaj6u99zph0ant9jjv3jkq") + assert.Contains(t, err.Error(), "invalid incomplete group") + + _, err = address.NewAddress("klv1xqcrqt6vdma") + assert.Contains(t, err.Error(), "decoding address, expected length 32") + + // invalid checksum + _, err = address.NewAddress("klv1d05ju9jaj6u99zph0ant9jh7gksg") + assert.Contains(t, err.Error(), "invalid checksum") + } func TestAddress_Address_ShouldWork(t *testing.T) { diff --git a/core/wallet/interfaces.go b/core/wallet/interfaces.go index 6c502db..5667330 100644 --- a/core/wallet/interfaces.go +++ b/core/wallet/interfaces.go @@ -7,4 +7,5 @@ type Wallet interface { PublicKey() []byte GetAccount() (account.Account, error) Sign(msg []byte) ([]byte, error) + SignHex(msg string) ([]byte, error) } diff --git a/core/wallet/pem.go b/core/wallet/pem.go index 9b77bea..8740edd 100644 --- a/core/wallet/pem.go +++ b/core/wallet/pem.go @@ -23,7 +23,7 @@ func LoadKey(pemFile string, skIndex int, pwd string) ([]byte, string, error) { encodedSk, pkString, err := LoadSkPkFromPemFile(pemFile, skIndex, pwd) if err != nil { - return nil, "", nil + return nil, "", err } skBytes, err := hex.DecodeString(string(encodedSk)) diff --git a/core/wallet/pem_test.go b/core/wallet/pem_test.go new file mode 100644 index 0000000..2656874 --- /dev/null +++ b/core/wallet/pem_test.go @@ -0,0 +1,159 @@ +package wallet_test + +import ( + "encoding/hex" + "io/ioutil" + "log" + "testing" + + "github.com/klever-io/klever-go-sdk/core/wallet" + "github.com/stretchr/testify/assert" +) + +func tempPemFile() string { + file, err := ioutil.TempFile("", "wallet*.pem") + if err != nil { + log.Fatal(err) + } + defer file.Close() + file.WriteString( + `-----BEGIN PRIVATE KEY for klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy----- +ODczNDA2MmMxMTU4ZjI2YTNjYThhNGEwZGE4N2I1MjdhN2MxNjg2NTNmN2Y0Yzc3 +MDQ1ZTVjZjU3MTQ5N2Q5ZA== +-----END PRIVATE KEY for klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy-----`) + + return file.Name() +} + +func tempPemFileEncrypted() string { + file, err := ioutil.TempFile("", "wallet*.pem") + if err != nil { + log.Fatal(err) + } + defer file.Close() + file.WriteString( + `-----BEGIN PRIVATE KEY for klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-GCM,453eb5c4c21225936c8c27b2 + +RT61xMISJZNsjCeyEiLgO/Nftp5Nk/l1OsGg7jlbnk/YDQ6675Nq82qg3U/IIC6b +Y3osGzZtxlO0KWQ9MOeZ1aRkIDl3Mys15RmXEqBBF+Ukqmcm1K2+oupmSgw= +-----END PRIVATE KEY for klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy-----`) + + return file.Name() +} + +func tempPemFileEncryptedWrong() string { + file, err := ioutil.TempFile("", "wallet*.pem") + if err != nil { + log.Fatal(err) + } + defer file.Close() + file.WriteString( + `-----BEGIN PRIVATE KEY for klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256,453eb5c4c21225936c8c27b2 + +RT61xMISJZNsjCeyEiLgO/Nftp5Nk/l1OsGg7jlbnk/YDQ6675Nq82qg3U/IIC6b +Y3osGzZtxlO0KWQ9MOeZ1aRkIDl3Mys15RmXEqBBF+Ukqmcm1K2+oupmSgw= +-----END PRIVATE KEY for klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy-----`) + + return file.Name() +} + +func tempEmptyPemFile() string { + file, err := ioutil.TempFile("", "wallet*.pem") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + return file.Name() +} + +func tempInvalidPemFile() string { + file, err := ioutil.TempFile("", "wallet*.pem") + if err != nil { + log.Fatal(err) + } + defer file.Close() + file.WriteString(`-----BEGIN PRIVATE KEY for klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy-----`) + + return file.Name() +} + +func TestLoadKey_PemFileNotFound(t *testing.T) { + + _, _, err := wallet.LoadKey("wallet.pem", 0, "") + assert.Contains(t, err.Error(), "no such file or directory") +} + +func TestLoadKey_InvalidPemFile(t *testing.T) { + fileName := tempInvalidPemFile() + + _, _, err := wallet.LoadKey(fileName, 0, "") + assert.Contains(t, err.Error(), "invalid pem file while reading") +} + +func TestLoadKey_EmptyPemFile(t *testing.T) { + fileName := tempEmptyPemFile() + + _, _, err := wallet.LoadKey(fileName, 0, "") + assert.Contains(t, err.Error(), "empty file provided while") +} + +func TestLoadKey_InvalidSKIndex(t *testing.T) { + fileName := tempPemFile() + + _, _, err := wallet.LoadKey(fileName, -1, "") + assert.Equal(t, "invalid index", err.Error()) +} + +func TestLoadKey_ShouldWork(t *testing.T) { + fileName := tempPemFile() + + pk, pub, err := wallet.LoadKey(fileName, 0, "") + assert.Nil(t, err) + assert.Equal(t, "klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy", pub) + assert.Equal(t, "8734062c1158f26a3ca8a4a0da87b527a7c168653f7f4c77045e5cf571497d9d", hex.EncodeToString(pk)) +} + +func TestLoadKey_EncryptedShouldWork(t *testing.T) { + fileName := tempPemFileEncrypted() + + pk, pub, err := wallet.LoadKey(fileName, 0, "123") + assert.Nil(t, err) + assert.Equal(t, "klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy", pub) + assert.Equal(t, "8734062c1158f26a3ca8a4a0da87b527a7c168653f7f4c77045e5cf571497d9d", hex.EncodeToString(pk)) +} + +func TestLoadKey_EncryptedWrongPassword(t *testing.T) { + fileName := tempPemFileEncrypted() + + _, _, err := wallet.LoadKey(fileName, 0, "") + assert.Contains(t, err.Error(), "encrypted key, must provide password") + + _, _, err = wallet.LoadKey(fileName, 0, "1") + assert.Contains(t, err.Error(), "failed PEM decryption") +} + +func TestLoadKey_EncryptedWrong(t *testing.T) { + fileName := tempPemFileEncryptedWrong() + + _, _, err := wallet.LoadKey(fileName, 0, "22") + assert.Contains(t, err.Error(), "invalid encryption mode") +} + +func TestLoadKey_InvalidSKIndexNotFound(t *testing.T) { + fileName := tempPemFile() + + _, _, err := wallet.LoadKey(fileName, 1, "") + assert.Contains(t, err.Error(), "invalid index while reading") +} + +func TestEncryptPEMBlock_ShouldWork(t *testing.T) { + + pem, err := wallet.EncryptPEMBlock("AES-GCM", []byte("8734062c1158f26a3ca8a4a0da87b527a7c168653f7f4c77045e5cf571497d9d"), "123") + assert.Nil(t, err) + assert.Len(t, pem.Bytes, 92) +} diff --git a/core/wallet/wallet.go b/core/wallet/wallet.go index 1979f30..d414e7b 100644 --- a/core/wallet/wallet.go +++ b/core/wallet/wallet.go @@ -172,7 +172,7 @@ func NewWalletFroHex(privateHex string) (Wallet, error) { } func (w *wallet) PrivateKey() []byte { - return append([]byte{}, w.privateKey...) + return w.privateKey[:32] } func (w *wallet) PublicKey() []byte { diff --git a/core/wallet/wallet_test.go b/core/wallet/wallet_test.go index 6128789..a288663 100644 --- a/core/wallet/wallet_test.go +++ b/core/wallet/wallet_test.go @@ -1,12 +1,22 @@ package wallet_test import ( + "encoding/hex" "testing" "github.com/klever-io/klever-go-sdk/core/wallet" "github.com/stretchr/testify/assert" ) +func TestWallet_WalletFromPem(t *testing.T) { + fileName := tempPemFile() + wallet, err := wallet.NewWalletFromPEM(fileName) + assert.Nil(t, err) + + assert.Equal(t, "8734062c1158f26a3ca8a4a0da87b527a7c168653f7f4c77045e5cf571497d9d", hex.EncodeToString(wallet.PrivateKey())) + assert.Equal(t, "e41b323a571fd955e09cd41660ff4465c3f44693c87f2faea4a0fc408727c8ea", hex.EncodeToString(wallet.PublicKey())) +} + func TestWallet_Mnemonic(t *testing.T) { wallet, err := wallet.NewWalletFromMnemonic("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about") assert.Nil(t, err) @@ -24,3 +34,16 @@ func TestWallet_PrivateKey(t *testing.T) { assert.Nil(t, err) assert.Equal(t, acc.Address().Bech32(), "klv1usdnywjhrlv4tcyu6stxpl6yvhplg35nepljlt4y5r7yppe8er4qujlazy") } + +func TestWallet_Sign(t *testing.T) { + wallet, err := wallet.NewWalletFroHex("8734062c1158f26a3ca8a4a0da87b527a7c168653f7f4c77045e5cf571497d9d") + assert.Nil(t, err) + + signature, err := wallet.Sign(make([]byte, 32)) + assert.Nil(t, err) + assert.Equal(t, "e0cb52c1b61916594daefe04aed24620058204a77e95bbbe5bb4ab165a76eda7d0f316d14d10ef184738f149bb5c0bc96ff4a194c25342dc1f6735a35bda0708", hex.EncodeToString(signature)) + + hexSign, err := wallet.SignHex("0000000000000000000000000000000000000000000000000000000000000000") + assert.Nil(t, err) + assert.Equal(t, signature, hexSign) +} diff --git a/models/account_test.go b/models/account_test.go new file mode 100644 index 0000000..d5c06d1 --- /dev/null +++ b/models/account_test.go @@ -0,0 +1,31 @@ +package models_test + +import ( + "testing" + + "github.com/klever-io/klever-go-sdk/models" + "github.com/stretchr/testify/assert" +) + +func TestAccount_ToString(t *testing.T) { + acc := &models.Account{ + AccountInfo: &models.AccountInfo{ + Address: "1234", + }, + } + assert.Equal(t, + "{\n\t\"address\": \"1234\",\n\t\"nonce\": 0,\n\t\"balance\": 0,\n\t\"frozenBalance\": 0,\n\t\"allowance\": 0,\n\t\"permissions\": null,\n\t\"timestamp\": 0,\n\t\"assets\": null\n}", + acc.String(), + ) +} + +func TestAccountAlloance_ToString(t *testing.T) { + acc := &models.AccountAllowance{ + Allowance: 123, + StakingRewards: 456, + } + assert.Equal(t, + "{\n\t\"allowance\": 123,\n\t\"stakingRewards\": 456\n}", + acc.String(), + ) +} diff --git a/models/asset.go b/models/asset.go index d1ba627..eb4b443 100644 --- a/models/asset.go +++ b/models/asset.go @@ -1,6 +1,10 @@ package models -import "encoding/json" +import ( + "encoding/json" + + "github.com/klever-io/klever-go-sdk/models/proto" +) type Bucket struct { ID string `json:"id"` @@ -14,22 +18,22 @@ type Bucket struct { // AccountKDA is a structure that holds information about a kda account type AccountKDA struct { - AccountAddress string `json:"address"` - AssetID string `json:"assetId"` - Collection string `json:"collection,omitempty"` - NFTNonce uint64 `json:"nftNonce,omitempty"` - AssetName string `json:"assetName"` - AssetType KDAData_EnumAssetType `json:"assetType"` - Balance int64 `json:"balance"` - Precision uint32 `json:"precision"` - FrozenBalance int64 `json:"frozenBalance"` - UnfrozenBalance int64 `json:"unfrozenBalance"` - LastClaim UserKDALastClaim `json:"lastClaim"` - Buckets []UserKDABucket `json:"buckets"` - Metadata string `json:"metadata,omitempty"` - MIME string `json:"mime,omitempty"` - MarketplaceID string `json:"marketplaceId,omitempty"` - OrderID string `json:"orderId,omitempty"` + AccountAddress string `json:"address"` + AssetID string `json:"assetId"` + Collection string `json:"collection,omitempty"` + NFTNonce uint64 `json:"nftNonce,omitempty"` + AssetName string `json:"assetName"` + AssetType proto.KDAData_EnumAssetType `json:"assetType"` + Balance int64 `json:"balance"` + Precision uint32 `json:"precision"` + FrozenBalance int64 `json:"frozenBalance"` + UnfrozenBalance int64 `json:"unfrozenBalance"` + LastClaim UserKDALastClaim `json:"lastClaim"` + Buckets []UserKDABucket `json:"buckets"` + Metadata string `json:"metadata,omitempty"` + MIME string `json:"mime,omitempty"` + MarketplaceID string `json:"marketplaceId,omitempty"` + OrderID string `json:"orderId,omitempty"` } // UserKDABucket is a structure that holds information about a kda user buckets diff --git a/models/assets_test.go b/models/assets_test.go new file mode 100644 index 0000000..a49956d --- /dev/null +++ b/models/assets_test.go @@ -0,0 +1,17 @@ +package models_test + +import ( + "testing" + + "github.com/klever-io/klever-go-sdk/models" + "github.com/stretchr/testify/assert" +) + +func TestAssets_ToString(t *testing.T) { + kda := &models.AccountKDA{ + AssetID: "KLV", + } + assert.Equal(t, + "{\n\t\"address\": \"\",\n\t\"assetId\": \"KLV\",\n\t\"assetName\": \"\",\n\t\"assetType\": 0,\n\t\"balance\": 0,\n\t\"precision\": 0,\n\t\"frozenBalance\": 0,\n\t\"unfrozenBalance\": 0,\n\t\"lastClaim\": {\n\t\t\"timestamp\": 0,\n\t\t\"epoch\": 0\n\t},\n\t\"buckets\": null\n}", + kda.String()) +} diff --git a/models/kda.pb.go b/models/proto/kda.pb.go similarity index 99% rename from models/kda.pb.go rename to models/proto/kda.pb.go index 319f9cb..92fe4d5 100644 --- a/models/kda.pb.go +++ b/models/proto/kda.pb.go @@ -1,4 +1,4 @@ -package models +package proto import ( reflect "reflect" diff --git a/models/transaction.go b/models/proto/transaction.go similarity index 97% rename from models/transaction.go rename to models/proto/transaction.go index eeb8bf1..7024677 100644 --- a/models/transaction.go +++ b/models/proto/transaction.go @@ -1,4 +1,4 @@ -package models +package proto func (x *Transaction) AddSignature(s []byte) { if x.Signature == nil { diff --git a/models/transaction.pb.go b/models/proto/transaction.pb.go similarity index 99% rename from models/transaction.pb.go rename to models/proto/transaction.pb.go index 90da1b2..39b3cf6 100644 --- a/models/transaction.pb.go +++ b/models/proto/transaction.pb.go @@ -1,4 +1,4 @@ -package models +package proto import ( reflect "reflect" diff --git a/models/signableMessage.go b/models/signableMessage.go new file mode 100644 index 0000000..c59d30b --- /dev/null +++ b/models/signableMessage.go @@ -0,0 +1,166 @@ +package models + +import ( + "crypto/ed25519" + "encoding/hex" + "encoding/json" + "fmt" + "strings" + + "github.com/klever-io/klever-go-sdk/core/address" + "github.com/klever-io/klever-go-sdk/models/proto" + "golang.org/x/crypto/sha3" +) + +const ( + MESSAGE_PREFIX = "\x17Klever Signed Message:\n" +) + +type SignableMessage interface { + SetAddress(address string) error + SetMessage(message []byte) + + GetSignature() []byte + SetSignature([]byte) + + Verify() bool + Sign(proto.Signer) error + + ToJSON() string + LoadJSON(string) error +} + +type signableMessage struct { + Address address.Address + Message []byte + Signature []byte + Version int + Signer string +} + +func NewSignableMessageFrom(address string) SignableMessage { + sm := NewSignableMessage() + sm.SetAddress(address) + return sm +} + +func NewSM(address string, message []byte) SignableMessage { + sm := NewSignableMessageFrom(address) + sm.SetMessage(message) + return sm +} + +func NewSignableMessage() SignableMessage { + return &signableMessage{ + Version: 1, + Signer: "KleverGO", + } +} + +func (sm *signableMessage) SetAddress(addr string) error { + encoded, err := address.NewAddress(addr) + if err != nil { + return err + } + + sm.Address = encoded + + return nil +} + +func (sm *signableMessage) SetMessage(message []byte) { + sm.Message = make([]byte, len(message)) + copy(sm.Message, message) +} + +func (sm *signableMessage) serializeForSigning() []byte { + messageSize := fmt.Sprintf("%d", len(sm.Message)) + signableMessage := append([]byte(messageSize), sm.Message...) + bytesToHash := append([]byte(MESSAGE_PREFIX), signableMessage...) + + hash := sha3.NewLegacyKeccak256() + hash.Write(bytesToHash) + + return hash.Sum(nil) +} + +func (sm *signableMessage) GetSignature() []byte { + return sm.Signature +} + +func (sm *signableMessage) SetSignature(signature []byte) { + sm.Signature = make([]byte, len(signature)) + copy(sm.Signature, signature) +} + +func (sm *signableMessage) Verify() bool { + hash := sm.serializeForSigning() + + return ed25519.Verify(sm.Address.Bytes(), hash, sm.Signature) +} + +func (sm *signableMessage) Sign(wallet proto.Signer) error { + data := sm.serializeForSigning() + siganture, err := wallet.Sign(data) + if err != nil { + return err + } + + sm.SetSignature(siganture) + + return nil +} + +func (sm *signableMessage) LoadJSON(data string) error { + obj := struct { + Address string `json:"address"` + Message string `json:"message"` + Signature string `json:"signature"` + Version int `json:"version"` + Signer string `json:"signer"` + }{} + + err := json.Unmarshal([]byte(data), &obj) + if err != nil { + return err + } + + sm.Address, err = address.NewAddress(obj.Address) + if err != nil { + return err + } + + sm.Message = decodeHex(obj.Message) + sm.Signature = decodeHex(obj.Signature) + return nil +} + +func decodeHex(data string) []byte { + data = strings.TrimPrefix(data, "0x") + + b, err := hex.DecodeString(data) + if err != nil { + return make([]byte, 0) + } + + return b +} + +func (sm *signableMessage) ToJSON() string { + result := struct { + Address string `json:"address"` + Message string `json:"message"` + Signature string `json:"signature"` + Version int `json:"version"` + Signer string `json:"signer"` + }{ + Address: sm.Address.Bech32(), + Message: "0x" + hex.EncodeToString(sm.Message), + Signature: "0x" + hex.EncodeToString(sm.Signature), + Version: sm.Version, + Signer: sm.Signer, + } + + data, _ := json.Marshal(result) + return string(data) +} diff --git a/models/signableMessage_test.go b/models/signableMessage_test.go new file mode 100644 index 0000000..0edea1d --- /dev/null +++ b/models/signableMessage_test.go @@ -0,0 +1,47 @@ +package models_test + +import ( + "encoding/hex" + "testing" + + "github.com/klever-io/klever-go-sdk/core/wallet" + "github.com/klever-io/klever-go-sdk/models" + "github.com/stretchr/testify/assert" +) + +func TestSignableMessage_SignVerify(t *testing.T) { + w, _ := wallet.NewWalletFroHex("0000000000000000000000000000000000000000000000000000000000000000") + acc, _ := w.GetAccount() + + sm := models.NewSM(acc.Address().Bech32(), []byte("KleverGames Test Message")) + + assert.False(t, sm.Verify()) + + err := sm.Sign(w) + assert.Nil(t, err) + assert.True(t, sm.Verify()) + + assert.Equal(t, "11c33430efd7288d306c9f69473157f4dcd0074bdc29d136b4f12e58ba051b9da0e5d72869fc673a871a9b81ae70a61f1e44e89ccb82bd2ce26486499355bf05", hex.EncodeToString(sm.GetSignature())) +} + +func TestSignableMessage_LoadJson(t *testing.T) { + org := models.NewSM("klv18d4z00xwk6jz6c4r4rgz5mcdwdjny9thrh3y8f36cpy2rz6emg5scllvd2", []byte("Klever")) + message := org.ToJSON() + + sm := models.NewSignableMessage() + err := sm.LoadJSON(message) + assert.Nil(t, err) + + assert.Equal(t, org.ToJSON(), sm.ToJSON()) +} + +func TestSignableMessage_LoadJsonFail(t *testing.T) { + message := "{\"address\":\"klv123\",\"message\":\"0x4b6c6576657247616d65732054657374204d657373616765\",\"signature\":\"0x11c33430efd7288d306c9f69473157f4dcd0074bdc29d136b4f12e58ba051b9da0e5d72869fc673a871a9b81ae70a61f1e44e89ccb82bd2ce26486499355bf05\",\"version\":1,\"signer\":\"KleverGO\"}" + + sm := models.NewSignableMessage() + err := sm.LoadJSON(message) + assert.Contains(t, err.Error(), "invalid bech32 string") + + err = sm.LoadJSON("") + assert.Contains(t, err.Error(), "unexpected end of JSON input") +} diff --git a/models/transactionAPI.go b/models/transactionAPI.go index d0a5432..0ec970f 100644 --- a/models/transactionAPI.go +++ b/models/transactionAPI.go @@ -3,6 +3,8 @@ package models import ( "encoding/json" "time" + + "github.com/klever-io/klever-go-sdk/models/proto" ) type ToAmount struct { @@ -32,7 +34,7 @@ type TransactionAPI struct { Signature []string `json:"signature,omitempty"` SearchOrder uint32 `json:"searchOrder"` Receipts []map[string]interface{} `json:"receipts"` - Contracts []*TXContract `json:"contract"` + Contracts []*proto.TXContract `json:"contract"` } func (t *TransactionAPI) String() string { @@ -45,9 +47,9 @@ func (t *TransactionAPI) String() string { } type TXContractAPI struct { - Type TXContract_ContractType `json:"type"` - TypeString string `json:"typeString"` - Parameter interface{} `json:"parameter,omitempty"` + Type proto.TXContract_ContractType `json:"type"` + TypeString string `json:"typeString"` + Parameter interface{} `json:"parameter,omitempty"` } //-- TransferContract diff --git a/models/transcationAPI_test.go b/models/transcationAPI_test.go new file mode 100644 index 0000000..a156c29 --- /dev/null +++ b/models/transcationAPI_test.go @@ -0,0 +1,18 @@ +package models_test + +import ( + "testing" + + "github.com/klever-io/klever-go-sdk/models" + "github.com/stretchr/testify/assert" +) + +func TestTranscationAPI_ToString(t *testing.T) { + tx := &models.TransactionAPI{ + Hash: "1234", + } + assert.Equal(t, + "{\n\t\"hash\": \"1234\",\n\t\"sender\": \"\",\n\t\"nonce\": 0,\n\t\"kAppFee\": 0,\n\t\"bandwidthFee\": 0,\n\t\"status\": \"\",\n\t\"searchOrder\": 0,\n\t\"receipts\": null,\n\t\"contract\": null\n}", + tx.String(), + ) +} diff --git a/provider/asset.go b/provider/asset.go index 77ee6ab..a681748 100644 --- a/provider/asset.go +++ b/provider/asset.go @@ -7,12 +7,13 @@ import ( "strings" "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" ) -func (kc *kleverChain) GetAsset(assetID string) (*models.KDAData, error) { +func (kc *kleverChain) GetAsset(assetID string) (*proto.KDAData, error) { result := struct { Data struct { - Asset *models.KDAData `json:"asset"` + Asset *proto.KDAData `json:"asset"` } `json:"data"` }{} @@ -47,7 +48,7 @@ func (kc *kleverChain) AssetTrigger( kdaID string, triggerType AssetTriggerType, op *models.AssetTriggerOptions, -) (*models.Transaction, error) { +) (*proto.Transaction, error) { // check if is NFT kda := strings.Split(kdaID, "/") if len(kda) > 2 { @@ -61,7 +62,7 @@ func (kc *kleverChain) AssetTrigger( parsedAmount := op.Amount - if asset.AssetType == models.KDAData_Fungible { + if asset.AssetType == proto.KDAData_Fungible { parsedAmount = parsedAmount * math.Pow10(int(asset.Precision)) } @@ -131,7 +132,7 @@ func (kc *kleverChain) AssetTrigger( Staking: stakingInfo, }) - data, err := kc.buildRequest(models.TXContract_AssetTriggerContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_AssetTriggerContractType, base, contracts) if err != nil { return nil, err } @@ -140,9 +141,9 @@ func (kc *kleverChain) AssetTrigger( func (kc *kleverChain) CreateKDA( base *models.BaseTX, - kdaType models.KDAData_EnumAssetType, + kdaType proto.KDAData_EnumAssetType, op *models.KDAOptions, -) (*models.Transaction, error) { +) (*proto.Transaction, error) { if !IsNameValid(op.Name) { return nil, fmt.Errorf("invalid KDA name") } @@ -186,7 +187,7 @@ func (kc *kleverChain) CreateKDA( Roles: op.Roles, }) - data, err := kc.buildRequest(models.TXContract_CreateAssetContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_CreateAssetContractType, base, contracts) if err != nil { return nil, err } diff --git a/provider/gov.go b/provider/gov.go index 97708e8..8deaa83 100644 --- a/provider/gov.go +++ b/provider/gov.go @@ -1,15 +1,18 @@ package provider -import "github.com/klever-io/klever-go-sdk/models" +import ( + "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" +) -func (kc *kleverChain) Proposal(base *models.BaseTX, description string, parameters map[int32]string, duration uint32) (*models.Transaction, error) { +func (kc *kleverChain) Proposal(base *models.BaseTX, description string, parameters map[int32]string, duration uint32) (*proto.Transaction, error) { contracts := []interface{}{models.ProposalTXRequest{ Parameters: parameters, EpochsDuration: duration, Description: description, }} - data, err := kc.buildRequest(models.TXContract_ProposalContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_ProposalContractType, base, contracts) if err != nil { return nil, err } @@ -17,14 +20,14 @@ func (kc *kleverChain) Proposal(base *models.BaseTX, description string, paramet return kc.PrepareTransaction(data) } -func (kc *kleverChain) Vote(base *models.BaseTX, proposalID uint64, amount float64, voteType uint64) (*models.Transaction, error) { +func (kc *kleverChain) Vote(base *models.BaseTX, proposalID uint64, amount float64, voteType uint64) (*proto.Transaction, error) { contracts := []interface{}{models.VoteTXRequest{ Type: uint32(voteType), ProposalID: proposalID, Amount: int64(amount * 1000000), }} - data, err := kc.buildRequest(models.TXContract_VoteContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_VoteContractType, base, contracts) if err != nil { return nil, err } diff --git a/provider/interfaces.go b/provider/interfaces.go index 529de6d..796969f 100644 --- a/provider/interfaces.go +++ b/provider/interfaces.go @@ -2,6 +2,7 @@ package provider import ( "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" "github.com/klever-io/klever-go-sdk/provider/tools/hasher" "github.com/klever-io/klever-go-sdk/provider/tools/marshal" ) @@ -10,41 +11,41 @@ type KleverChain interface { // Query Account data GetAccount(address string) (*models.Account, error) GetAccountAllowance(address string, kda string) (*models.AccountAllowance, error) - GetAsset(assetID string) (*models.KDAData, error) + GetAsset(assetID string) (*proto.KDAData, error) // Transaction helpers - Decode(tx *models.Transaction) (*models.TransactionAPI, error) + Decode(tx *proto.Transaction) (*models.TransactionAPI, error) GetTransaction(hash string) (*models.TransactionAPI, error) GetHasher() hasher.Hasher GetMarshalizer() marshal.Marshalizer // Transfer actions - Send(base *models.BaseTX, toAddr string, amount float64, kda string) (*models.Transaction, error) - MultiTransfer(base *models.BaseTX, kda string, values []models.ToAmount) (*models.Transaction, error) + Send(base *models.BaseTX, toAddr string, amount float64, kda string) (*proto.Transaction, error) + MultiTransfer(base *models.BaseTX, kda string, values []models.ToAmount) (*proto.Transaction, error) // Asset Actions - CreateKDA(base *models.BaseTX, kdaType models.KDAData_EnumAssetType, op *models.KDAOptions) (*models.Transaction, error) - AssetTrigger(base *models.BaseTX, kdaID string, triggerType AssetTriggerType, op *models.AssetTriggerOptions) (*models.Transaction, error) + CreateKDA(base *models.BaseTX, kdaType proto.KDAData_EnumAssetType, op *models.KDAOptions) (*proto.Transaction, error) + AssetTrigger(base *models.BaseTX, kdaID string, triggerType AssetTriggerType, op *models.AssetTriggerOptions) (*proto.Transaction, error) // Acctount Actions - SetAccountName(base *models.BaseTX, name string) (*models.Transaction, error) - SetPermission(base *models.BaseTX, permissions []models.PermissionTXRequest) (*models.Transaction, error) + SetAccountName(base *models.BaseTX, name string) (*proto.Transaction, error) + SetPermission(base *models.BaseTX, permissions []models.PermissionTXRequest) (*proto.Transaction, error) // Governance Actions - Proposal(base *models.BaseTX, description string, parameters map[int32]string, duration uint32) (*models.Transaction, error) - Vote(base *models.BaseTX, proposalID uint64, amount float64, voteType uint64) (*models.Transaction, error) + Proposal(base *models.BaseTX, description string, parameters map[int32]string, duration uint32) (*proto.Transaction, error) + Vote(base *models.BaseTX, proposalID uint64, amount float64, voteType uint64) (*proto.Transaction, error) // Market&ITO Actions - ConfigITO(base *models.BaseTX, kdaID, receiverAddress string, status int32, maxAmount float64, packs []models.ParsedPack) (*models.Transaction, error) - SetITOPrices(base *models.BaseTX, kdaID string, packs []models.ParsedPack) (*models.Transaction, error) - CreateMarketplace(base *models.BaseTX, name, referralAddr string, referralPercent float64) (*models.Transaction, error) - ConfigMarketplace(base *models.BaseTX, id, name, referralAddr string, referralPercent float64) (*models.Transaction, error) - BuyOrder(base *models.BaseTX, id, currency string, amount float64, buyType int32) (*models.Transaction, error) - SellOrder(base *models.BaseTX, kdaID, currency, mktID string, price, reservePrice float64, endTime int64, mktType int32, message string) (*models.Transaction, error) - CancelMarketOrder(base *models.BaseTX, orderID string) (*models.Transaction, error) - Withdraw(base *models.BaseTX, kda string) (*models.Transaction, error) + ConfigITO(base *models.BaseTX, kdaID, receiverAddress string, status int32, maxAmount float64, packs []models.ParsedPack) (*proto.Transaction, error) + SetITOPrices(base *models.BaseTX, kdaID string, packs []models.ParsedPack) (*proto.Transaction, error) + CreateMarketplace(base *models.BaseTX, name, referralAddr string, referralPercent float64) (*proto.Transaction, error) + ConfigMarketplace(base *models.BaseTX, id, name, referralAddr string, referralPercent float64) (*proto.Transaction, error) + BuyOrder(base *models.BaseTX, id, currency string, amount float64, buyType int32) (*proto.Transaction, error) + SellOrder(base *models.BaseTX, kdaID, currency, mktID string, price, reservePrice float64, endTime int64, mktType int32, message string) (*proto.Transaction, error) + CancelMarketOrder(base *models.BaseTX, orderID string) (*proto.Transaction, error) + Withdraw(base *models.BaseTX, kda string) (*proto.Transaction, error) // Staking Action - Freeze(base *models.BaseTX, amount float64, kda string) (*models.Transaction, error) - Unfreeze(base *models.BaseTX, bucketId, kda string) (*models.Transaction, error) - Delegate(base *models.BaseTX, toAddr, bucketId string) (*models.Transaction, error) - Undelegate(base *models.BaseTX, toAddr, bucketId string) (*models.Transaction, error) + Freeze(base *models.BaseTX, amount float64, kda string) (*proto.Transaction, error) + Unfreeze(base *models.BaseTX, bucketId, kda string) (*proto.Transaction, error) + Delegate(base *models.BaseTX, toAddr, bucketId string) (*proto.Transaction, error) + Undelegate(base *models.BaseTX, toAddr, bucketId string) (*proto.Transaction, error) // Validator Actions - Unjail(base *models.BaseTX) (*models.Transaction, error) - Claim(base *models.BaseTX, id string, claimType int32) (*models.Transaction, error) + Unjail(base *models.BaseTX) (*proto.Transaction, error) + Claim(base *models.BaseTX, id string, claimType int32) (*proto.Transaction, error) // Network Broadcast - BroadcastTransaction(tx *models.Transaction) (string, error) + BroadcastTransaction(tx *proto.Transaction) (string, error) } diff --git a/provider/ito.go b/provider/ito.go index 649e081..0a40a96 100644 --- a/provider/ito.go +++ b/provider/ito.go @@ -4,31 +4,19 @@ import ( "math" "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" ) -func (kc *kleverChain) ConfigITO(base *models.BaseTX, kdaID, receiverAddress string, status int32, maxAmount float64, packs []models.ParsedPack) (*models.Transaction, error) { +func (kc *kleverChain) ConfigITO(base *models.BaseTX, kdaID, receiverAddress string, status int32, maxAmount float64, packs []models.ParsedPack) (*proto.Transaction, error) { kda, err := kc.GetAsset(kdaID) if err != nil { return nil, err } parsedmaxAmount := maxAmount * math.Pow10(int(kda.Precision)) - packInfo := make(map[string]models.PackInfoRequest) - for _, p := range packs { - packPrecision, err := kc.getPrecision(p.Kda) - if err != nil { - return nil, err - } - - packItems := make([]models.PackItemRequest, 0) - for _, pItem := range p.Packs { - parsedItemAmount := pItem.Amount * math.Pow10(int(kda.Precision)) - parsedItemPrice := pItem.Price * math.Pow10(int(packPrecision)) - - packItems = append(packItems, models.PackItemRequest{Amount: int64(parsedItemAmount), Price: int64(parsedItemPrice)}) - } - - packInfo[p.Kda] = models.PackInfoRequest{Packs: packItems} + packInfo, err := kc.createPackInfo(kda.Precision, packs) + if err != nil { + return nil, err } configITO := models.ConfigITOTXRequest{ @@ -39,7 +27,7 @@ func (kc *kleverChain) ConfigITO(base *models.BaseTX, kdaID, receiverAddress str PackInfo: packInfo, } - data, err := kc.buildRequest(models.TXContract_ConfigITOContractType, base, []interface{}{configITO}) + data, err := kc.buildRequest(proto.TXContract_ConfigITOContractType, base, []interface{}{configITO}) if err != nil { return nil, err } @@ -47,13 +35,9 @@ func (kc *kleverChain) ConfigITO(base *models.BaseTX, kdaID, receiverAddress str return kc.PrepareTransaction(data) } -func (kc *kleverChain) SetITOPrices(base *models.BaseTX, kdaID string, packs []models.ParsedPack) (*models.Transaction, error) { - kda, err := kc.GetAsset(kdaID) - if err != nil { - return nil, err - } - +func (kc *kleverChain) createPackInfo(precision uint32, packs []models.ParsedPack) (map[string]models.PackInfoRequest, error) { packInfo := make(map[string]models.PackInfoRequest) + for _, p := range packs { packPrecision, err := kc.getPrecision(p.Kda) if err != nil { @@ -62,7 +46,7 @@ func (kc *kleverChain) SetITOPrices(base *models.BaseTX, kdaID string, packs []m packItems := make([]models.PackItemRequest, 0) for _, pItem := range p.Packs { - parsedItemAmount := pItem.Amount * math.Pow10(int(kda.Precision)) + parsedItemAmount := pItem.Amount * math.Pow10(int(precision)) parsedItemPrice := pItem.Price * math.Pow10(int(packPrecision)) packItems = append(packItems, models.PackItemRequest{Amount: int64(parsedItemAmount), Price: int64(parsedItemPrice)}) @@ -71,12 +55,26 @@ func (kc *kleverChain) SetITOPrices(base *models.BaseTX, kdaID string, packs []m packInfo[p.Kda] = models.PackInfoRequest{Packs: packItems} } + return packInfo, nil +} + +func (kc *kleverChain) SetITOPrices(base *models.BaseTX, kdaID string, packs []models.ParsedPack) (*proto.Transaction, error) { + kda, err := kc.GetAsset(kdaID) + if err != nil { + return nil, err + } + + packInfo, err := kc.createPackInfo(kda.Precision, packs) + if err != nil { + return nil, err + } + setITOPrices := models.SetITOPricesTXRequest{ KDA: kdaID, PackInfo: packInfo, } - data, err := kc.buildRequest(models.TXContract_SetITOPricesContractType, base, []interface{}{setITOPrices}) + data, err := kc.buildRequest(proto.TXContract_SetITOPricesContractType, base, []interface{}{setITOPrices}) if err != nil { return nil, err } diff --git a/provider/market.go b/provider/market.go index 1cf3dc9..a1e1a38 100644 --- a/provider/market.go +++ b/provider/market.go @@ -4,9 +4,10 @@ import ( "math" "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" ) -func (kc *kleverChain) CreateMarketplace(base *models.BaseTX, name, referralAddr string, referralPercent float64) (*models.Transaction, error) { +func (kc *kleverChain) CreateMarketplace(base *models.BaseTX, name, referralAddr string, referralPercent float64) (*proto.Transaction, error) { parsedReferralPercent := referralPercent * math.Pow10(2) createMarketplace := models.CreateMarketplaceTXRequest{ @@ -15,7 +16,7 @@ func (kc *kleverChain) CreateMarketplace(base *models.BaseTX, name, referralAddr ReferralPercentage: uint32(parsedReferralPercent), } - data, err := kc.buildRequest(models.TXContract_CreateMarketplaceContractType, base, []interface{}{createMarketplace}) + data, err := kc.buildRequest(proto.TXContract_CreateMarketplaceContractType, base, []interface{}{createMarketplace}) if err != nil { return nil, err } @@ -23,7 +24,7 @@ func (kc *kleverChain) CreateMarketplace(base *models.BaseTX, name, referralAddr return kc.PrepareTransaction(data) } -func (kc *kleverChain) ConfigMarketplace(base *models.BaseTX, id, name, referralAddr string, referralPercent float64) (*models.Transaction, error) { +func (kc *kleverChain) ConfigMarketplace(base *models.BaseTX, id, name, referralAddr string, referralPercent float64) (*proto.Transaction, error) { parsedReferralPercent := referralPercent * math.Pow10(2) configMarketplace := models.ConfigMarketplaceTXRequest{ @@ -33,7 +34,7 @@ func (kc *kleverChain) ConfigMarketplace(base *models.BaseTX, id, name, referral ReferralPercentage: uint32(parsedReferralPercent), } - data, err := kc.buildRequest(models.TXContract_ConfigMarketplaceContractType, base, []interface{}{configMarketplace}) + data, err := kc.buildRequest(proto.TXContract_ConfigMarketplaceContractType, base, []interface{}{configMarketplace}) if err != nil { return nil, err } @@ -41,7 +42,7 @@ func (kc *kleverChain) ConfigMarketplace(base *models.BaseTX, id, name, referral return kc.PrepareTransaction(data) } -func (kc *kleverChain) BuyOrder(base *models.BaseTX, id, currency string, amount float64, buyType int32) (*models.Transaction, error) { +func (kc *kleverChain) BuyOrder(base *models.BaseTX, id, currency string, amount float64, buyType int32) (*proto.Transaction, error) { parsedAmount := amount precision, err := kc.getPrecision(id) @@ -58,7 +59,7 @@ func (kc *kleverChain) BuyOrder(base *models.BaseTX, id, currency string, amount Amount: int64(parsedAmount), } - data, err := kc.buildRequest(models.TXContract_BuyContractType, base, []interface{}{buyOrder}) + data, err := kc.buildRequest(proto.TXContract_BuyContractType, base, []interface{}{buyOrder}) if err != nil { return nil, err } @@ -66,7 +67,7 @@ func (kc *kleverChain) BuyOrder(base *models.BaseTX, id, currency string, amount return kc.PrepareTransaction(data) } -func (kc *kleverChain) SellOrder(base *models.BaseTX, kdaID, currency, mktID string, price, reservePrice float64, endTime int64, mktType int32, message string) (*models.Transaction, error) { +func (kc *kleverChain) SellOrder(base *models.BaseTX, kdaID, currency, mktID string, price, reservePrice float64, endTime int64, mktType int32, message string) (*proto.Transaction, error) { precision, err := kc.getPrecision(currency) if err != nil { return nil, err @@ -85,7 +86,7 @@ func (kc *kleverChain) SellOrder(base *models.BaseTX, kdaID, currency, mktID str EndTime: endTime, } - data, err := kc.buildRequest(models.TXContract_SellContractType, base, []interface{}{sellOrder}) + data, err := kc.buildRequest(proto.TXContract_SellContractType, base, []interface{}{sellOrder}) if err != nil { return nil, err } @@ -93,12 +94,12 @@ func (kc *kleverChain) SellOrder(base *models.BaseTX, kdaID, currency, mktID str return kc.PrepareTransaction(data) } -func (kc *kleverChain) CancelMarketOrder(base *models.BaseTX, orderID string) (*models.Transaction, error) { +func (kc *kleverChain) CancelMarketOrder(base *models.BaseTX, orderID string) (*proto.Transaction, error) { cancelMarketOrder := models.CancelMarketOrderTXRequest{ OrderID: orderID, } - data, err := kc.buildRequest(models.TXContract_CancelMarketOrderContractType, base, []interface{}{cancelMarketOrder}) + data, err := kc.buildRequest(proto.TXContract_CancelMarketOrderContractType, base, []interface{}{cancelMarketOrder}) if err != nil { return nil, err } diff --git a/provider/permission.go b/provider/permission.go index b750f9e..22c5309 100644 --- a/provider/permission.go +++ b/provider/permission.go @@ -2,28 +2,29 @@ package provider import ( "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" ) -func (kc *kleverChain) SetPermission(base *models.BaseTX, permissions []models.PermissionTXRequest) (*models.Transaction, error) { +func (kc *kleverChain) SetPermission(base *models.BaseTX, permissions []models.PermissionTXRequest) (*proto.Transaction, error) { contracts := []interface{}{models.UpdateAccountPermissionTXRequest{ Permissions: permissions, }} - data, err := kc.buildRequest(models.TXContract_UpdateAccountPermissionContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_UpdateAccountPermissionContractType, base, contracts) if err != nil { return nil, err } return kc.PrepareTransaction(data) } -func (kc *kleverChain) SetAccountName(base *models.BaseTX, name string) (*models.Transaction, error) { +func (kc *kleverChain) SetAccountName(base *models.BaseTX, name string) (*proto.Transaction, error) { contracts := []interface{}{models.SetAccountNameTXRequest{ Name: name, }} - data, err := kc.buildRequest(models.TXContract_SetAccountNameContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_SetAccountNameContractType, base, contracts) if err != nil { return nil, err } diff --git a/provider/stake.go b/provider/stake.go index b156177..ec0305c 100644 --- a/provider/stake.go +++ b/provider/stake.go @@ -4,9 +4,10 @@ import ( "math" "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" ) -func (kc *kleverChain) Freeze(base *models.BaseTX, amount float64, kda string) (*models.Transaction, error) { +func (kc *kleverChain) Freeze(base *models.BaseTX, amount float64, kda string) (*proto.Transaction, error) { precision, err := kc.getPrecision(kda) if err != nil { return nil, err @@ -19,80 +20,80 @@ func (kc *kleverChain) Freeze(base *models.BaseTX, amount float64, kda string) ( KDA: kda, }} - data, err := kc.buildRequest(models.TXContract_FreezeContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_FreezeContractType, base, contracts) if err != nil { return nil, err } return kc.PrepareTransaction(data) } -func (kc *kleverChain) Unfreeze(base *models.BaseTX, bucketId, kda string) (*models.Transaction, error) { +func (kc *kleverChain) Unfreeze(base *models.BaseTX, bucketId, kda string) (*proto.Transaction, error) { contracts := []interface{}{models.UnfreezeTXRequest{ BucketID: bucketId, KDA: kda, }} - data, err := kc.buildRequest(models.TXContract_UnfreezeContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_UnfreezeContractType, base, contracts) if err != nil { return nil, err } return kc.PrepareTransaction(data) } -func (kc *kleverChain) Delegate(base *models.BaseTX, toAddr, bucketId string) (*models.Transaction, error) { +func (kc *kleverChain) Delegate(base *models.BaseTX, toAddr, bucketId string) (*proto.Transaction, error) { contracts := []interface{}{models.DelegateTXRequest{ Receiver: toAddr, BucketID: bucketId, }} - data, err := kc.buildRequest(models.TXContract_DelegateContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_DelegateContractType, base, contracts) if err != nil { return nil, err } return kc.PrepareTransaction(data) } -func (kc *kleverChain) Undelegate(base *models.BaseTX, toAddr, bucketId string) (*models.Transaction, error) { +func (kc *kleverChain) Undelegate(base *models.BaseTX, toAddr, bucketId string) (*proto.Transaction, error) { contracts := []interface{}{models.UndelegateTXRequest{ BucketID: bucketId, }} - data, err := kc.buildRequest(models.TXContract_UndelegateContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_UndelegateContractType, base, contracts) if err != nil { return nil, err } return kc.PrepareTransaction(data) } -func (kc *kleverChain) Withdraw(base *models.BaseTX, kda string) (*models.Transaction, error) { +func (kc *kleverChain) Withdraw(base *models.BaseTX, kda string) (*proto.Transaction, error) { contracts := []interface{}{models.WithdrawTXRequest{ KDA: kda, }} - data, err := kc.buildRequest(models.TXContract_WithdrawContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_WithdrawContractType, base, contracts) if err != nil { return nil, err } return kc.PrepareTransaction(data) } -func (kc *kleverChain) Claim(base *models.BaseTX, id string, claimType int32) (*models.Transaction, error) { +func (kc *kleverChain) Claim(base *models.BaseTX, id string, claimType int32) (*proto.Transaction, error) { contracts := []interface{}{models.ClaimTXRequest{ ClaimType: claimType, ID: id, }} - data, err := kc.buildRequest(models.TXContract_ClaimContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_ClaimContractType, base, contracts) if err != nil { return nil, err } return kc.PrepareTransaction(data) } -func (kc *kleverChain) Unjail(base *models.BaseTX) (*models.Transaction, error) { +func (kc *kleverChain) Unjail(base *models.BaseTX) (*proto.Transaction, error) { contracts := []interface{}{models.UnjailTXRequest{}} - data, err := kc.buildRequest(models.TXContract_UnjailContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_UnjailContractType, base, contracts) if err != nil { return nil, err } diff --git a/provider/tools/hasher/blake2b_test.go b/provider/tools/hasher/blake2b_test.go index d1b85fb..ba997c3 100644 --- a/provider/tools/hasher/blake2b_test.go +++ b/provider/tools/hasher/blake2b_test.go @@ -1,12 +1,23 @@ package hasher_test import ( + "encoding/hex" "testing" "github.com/klever-io/klever-go-sdk/provider/tools/hasher" "github.com/stretchr/testify/assert" ) +func TestBlake2b_NewHasher(t *testing.T) { + t.Parallel() + + hasher, err := hasher.NewHasher() + assert.Nil(t, err) + + resEmpty := hasher.Compute("") + assert.Equal(t, 32, len(resEmpty)) +} + func TestBlake2b_ComputeWithDifferentHashSizes(t *testing.T) { t.Parallel() @@ -36,3 +47,19 @@ func TestBlake2b_Empty(t *testing.T) { assert.Equal(t, resEmpty, resNil) } + +func TestBlake2b_ZeroDefaultSize(t *testing.T) { + hasher := &hasher.Blake2b{HashSize: 0} + assert.Equal(t, 32, hasher.Size()) + + resEmpty := hasher.Compute("") + assert.Equal(t, 32, len(resEmpty)) + + hash := hasher.EmptyHash() + assert.Equal(t, "0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8", hex.EncodeToString(hash)) +} + +func TestBlake2b_NilInterface(t *testing.T) { + var hasher *hasher.Blake2b + assert.True(t, hasher.IsInterfaceNil()) +} diff --git a/provider/tools/marshal/protoMarshalizer_test.go b/provider/tools/marshal/protoMarshalizer_test.go index 70ce5c6..97d34cf 100644 --- a/provider/tools/marshal/protoMarshalizer_test.go +++ b/provider/tools/marshal/protoMarshalizer_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "github.com/klever-io/klever-go-sdk/models/proto" "github.com/klever-io/klever-go-sdk/provider/tools/marshal" "github.com/stretchr/testify/assert" ) @@ -32,3 +33,35 @@ func TestProtoMarshalizer_MarshalWrongObj(t *testing.T) { assert.Nil(t, encNode) assert.NotNil(t, err) } + +func TestProtoMarshalizer_NilMarshalizer(t *testing.T) { + var m *marshal.ProtoMarshalizer + assert.True(t, m.IsInterfaceNil()) +} + +func TestProtoMarshalizer_MarshalNilObj(t *testing.T) { + encNode, err := recovedMarshal(nil) + assert.Nil(t, encNode) + assert.Contains(t, err.Error(), "can not serialize the object") +} + +func TestProtoMarshalizer_ShouldWork(t *testing.T) { + m := marshal.NewProtoMarshalizer() + + tx := &proto.Transaction{ + RawData: &proto.Transaction_Raw{ + Nonce: 10, + Sender: []byte("Klever"), + }, + Block: 1234, + } + data, err := m.Marshal(tx) + assert.Nil(t, err) + + tx2 := &proto.Transaction{} + + err = m.Unmarshal(tx2, data) + assert.Nil(t, err) + assert.Equal(t, tx.RawData.Sender, tx2.RawData.Sender) + assert.Equal(t, tx.Block, tx2.Block) +} diff --git a/provider/transaction.go b/provider/transaction.go index a441897..b52fbe1 100644 --- a/provider/transaction.go +++ b/provider/transaction.go @@ -8,9 +8,10 @@ import ( "github.com/klever-io/klever-go-sdk/core" "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" ) -func (kc *kleverChain) Decode(tx *models.Transaction) (*models.TransactionAPI, error) { +func (kc *kleverChain) Decode(tx *proto.Transaction) (*models.TransactionAPI, error) { result := struct { Data struct { @@ -48,13 +49,13 @@ func (kc *kleverChain) getPrecision(kda string) (uint32, error) { return precision, nil } -func (kc *kleverChain) Send(base *models.BaseTX, toAddr string, amount float64, kda string) (*models.Transaction, error) { +func (kc *kleverChain) Send(base *models.BaseTX, toAddr string, amount float64, kda string) (*proto.Transaction, error) { values := []models.ToAmount{{ToAddress: toAddr, Amount: amount}} return kc.MultiTransfer(base, kda, values) } -func (kc *kleverChain) MultiTransfer(base *models.BaseTX, kda string, values []models.ToAmount) (*models.Transaction, error) { +func (kc *kleverChain) MultiTransfer(base *models.BaseTX, kda string, values []models.ToAmount) (*proto.Transaction, error) { precision, err := kc.getPrecision(kda) if err != nil { return nil, err @@ -70,7 +71,7 @@ func (kc *kleverChain) MultiTransfer(base *models.BaseTX, kda string, values []m }) } - data, err := kc.buildRequest(models.TXContract_TransferContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_TransferContractType, base, contracts) if err != nil { return nil, err } @@ -78,7 +79,7 @@ func (kc *kleverChain) MultiTransfer(base *models.BaseTX, kda string, values []m } func (kc *kleverChain) buildRequest( - txType models.TXContract_ContractType, + txType proto.TXContract_ContractType, base *models.BaseTX, contracts []interface{}, ) (*models.SendTXRequest, error) { @@ -108,14 +109,14 @@ func (kc *kleverChain) buildRequest( }, nil } -func (kc *kleverChain) PrepareTransaction(request *models.SendTXRequest) (*models.Transaction, error) { +func (kc *kleverChain) PrepareTransaction(request *models.SendTXRequest) (*proto.Transaction, error) { result := struct { Data struct { - Transaction *models.Transaction `json:"result"` + Transaction *proto.Transaction `json:"result"` } `json:"data"` }{} - result.Data.Transaction = &models.Transaction{} + result.Data.Transaction = &proto.Transaction{} body, err := json.Marshal(request) if err != nil { @@ -161,9 +162,9 @@ func (kc *kleverChain) GetTransaction(hash string) (*models.TransactionAPI, erro return result.Data.Transaction, err } -func (kc *kleverChain) BroadcastTransaction(tx *models.Transaction) (string, error) { +func (kc *kleverChain) BroadcastTransaction(tx *proto.Transaction) (string, error) { toBroadcast := struct { - TX *models.Transaction `json:"tx"` + TX *proto.Transaction `json:"tx"` }{ TX: tx, } diff --git a/provider/validator.go b/provider/validator.go index d2b77fb..c540bc6 100644 --- a/provider/validator.go +++ b/provider/validator.go @@ -4,9 +4,10 @@ import ( "math" "github.com/klever-io/klever-go-sdk/models" + "github.com/klever-io/klever-go-sdk/models/proto" ) -func (kc *kleverChain) CreateValidator(base *models.BaseTX, blsKey, ownerAddr, rewardAddr, logo string, commission, maxDelegation float64, canDelegate bool, uris map[string]string, name string) (*models.Transaction, error) { +func (kc *kleverChain) CreateValidator(base *models.BaseTX, blsKey, ownerAddr, rewardAddr, logo string, commission, maxDelegation float64, canDelegate bool, uris map[string]string, name string) (*proto.Transaction, error) { parsedCommission := commission * math.Pow10(2) parsedMaxDelegation := maxDelegation * math.Pow10(6) @@ -22,14 +23,14 @@ func (kc *kleverChain) CreateValidator(base *models.BaseTX, blsKey, ownerAddr, r URIs: uris, }} - data, err := kc.buildRequest(models.TXContract_CreateValidatorContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_CreateValidatorContractType, base, contracts) if err != nil { return nil, err } return kc.PrepareTransaction(data) } -func (kc *kleverChain) ValidatorConfig(base *models.BaseTX, blsKey, rewardAddr, logo string, commission, maxDelegation float64, canDelegate bool, uris map[string]string, name string) (*models.Transaction, error) { +func (kc *kleverChain) ValidatorConfig(base *models.BaseTX, blsKey, rewardAddr, logo string, commission, maxDelegation float64, canDelegate bool, uris map[string]string, name string) (*proto.Transaction, error) { parsedCommission := commission * math.Pow10(2) parsedMaxDelegation := maxDelegation * math.Pow10(6) @@ -44,7 +45,7 @@ func (kc *kleverChain) ValidatorConfig(base *models.BaseTX, blsKey, rewardAddr, URIs: uris, }} - data, err := kc.buildRequest(models.TXContract_ValidatorConfigContractType, base, contracts) + data, err := kc.buildRequest(proto.TXContract_ValidatorConfigContractType, base, contracts) if err != nil { return nil, err }