initial commit

initial commit
This commit is contained in:
jiang
2022-09-06 11:03:29 +08:00
parent fa1097d391
commit ecff7d8ec1
38 changed files with 2945 additions and 1 deletions

View File

@@ -1,3 +1,4 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

18
Makefile Normal file
View File

@@ -0,0 +1,18 @@
GOCC = go
GOTEST = GODEBUG=cgocheck=0 $(GOCC) test -v ./... -p 2
default: test
## test: run unit tests with a 60s timeout
test:
$(GOTEST) --timeout 60s
lintci:
@echo "--> Running linter for code"
@./build/bin/golangci-lint run --config ./.golangci.yml
## lintci-deps: (re)installs golangci-lint to build/bin/golangci-lint
lintci-deps:
rm -f ./build/bin/golangci-lint
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./build/bin v1.48.0

94
README.md Normal file
View File

@@ -0,0 +1,94 @@
# Sui-Go-SDK
##
sui-go-sdk is project [Sui]() SDK for Go programming language.
### Notices
+ You don't need to load your `sui.keystore` file if you just want to send some unsigned transactions.
+ File `sui.keystore` in config folder is test-only. Replace and load your own sui.keystore if your need to sign transactions.
+ PRs are open to everyone and let's build useful tools for Sui community!
### Features
+ Load your keystore file and sign your messages with specific address.
+ Provide methods `MoveCallAndExecuteTransaction`/`BatchAndExecuteTransaction`.
+ Customized request method `SuiCall`.
+ Unsigned methods can be executed without loading your keystore file.
* [Quick Start](#Quick-Start)
* [Examples](#Examples)
## Quick Start
### Install
```shell
go get github.com/block-vision/sui-go-sdk
```
### Go Version
| Golang Version |
|----------------|
| \>= 1.18.1 |
## Examples
```go
package main
import (
"context"
"fmt"
"github.com/block-vision/sui-go-sdk/models"
"github.com/block-vision/sui-go-sdk/sui"
)
func main() {
// configure your endpoint here
cli := sui.NewSuiClient("https://gateway.devnet.sui.io:443")
resp, err := cli.GetRecentTransactions(context.Background(), models.GetRecentTransactionRequest{
Count: 5,
})
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(resp)
//If you want to request for original json response, you can use SuiCall().
rsp, err := cli.SuiCall(context.Background(), "sui_getRecentTransactions", 5)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(rsp)
keystoreCli, err := sui.SetAccountKeyStore("../sui.keystore.fortest")
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(keystoreCli.Keys())
fmt.Println(keystoreCli.GetKey("your-address"))
}
```
### Send unsigned transactions
### Send signed transactions
## Contribution
## Resources
+ [SDK Examples]()
+ [Sui](https://github.com/MystenLabs/sui)

BIN
build/bin/golangci-lint Executable file

Binary file not shown.

34
config/config.go Normal file
View File

@@ -0,0 +1,34 @@
package config
import (
"encoding/json"
"io/ioutil"
"os"
)
type KeyStoreConfig struct {
Keys []string
}
var keyStoreConfig KeyStoreConfig
func GetKeyStore(path string) (KeyStoreConfig, error) {
err := loadConfig(path)
return keyStoreConfig, err
}
func loadConfig(dir string) error {
f, err := os.Open(dir)
if err != nil {
return err
}
content, err := ioutil.ReadAll(f)
if err != nil {
return err
}
err = json.Unmarshal(content, &keyStoreConfig.Keys)
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,8 @@
[
"AQOf3sfviz7pkIN+qpZfeVrsidg3o39wCohnNS6hkmCzkRyGeALaqpP2iJ1LqWJsxxY2b6H6HLyPOoOhoiBi7SnZ",
"AF6BUd9nBhR0h6hivei0nwcMe1N/GnrB7YecMu8G4yVp9hpOwpqaoCyxgSrHQsz1U0nlNKNVURrtyjfMoSRGKCw=",
"ACCxbg6Y1dMH02D/RqgzeQLLlOJB6FancLCDSFZ0oe3XgaH5ViyVHCgu3+shKU4OpArSvXSzSSuyjLRd+zDijk0=",
"AEQmSf8ZrgC5wsRKwUwLPxcaMD7TiUjp1SMxopHKY+/GbwLY2gyLSs7wMgwILoCJJbHLsSxHkVGEcka5L/UAe8o=",
"ADNVM7XLQd7bx0YFqY4R6J+581liKIeKQWhETX1IO5aFpR6k8+RV/JkHAHJMnRbZTtmNOrERWHJxOzh4oLWY4i0=",
"AKMI98sBlQLPXtvNKAu/DA7mDJACduEI/zqdIZzv9kBRARz/t75VC7TzR68ez6CYvWDtf7cXC0Ks1R0RuQJOm9c="
]

View File

@@ -0,0 +1,36 @@
package main
import (
"context"
"fmt"
"github.com/block-vision/sui-go-sdk/models"
"github.com/block-vision/sui-go-sdk/sui"
)
func main() {
cli := sui.NewSuiClient("https://gateway.devnet.sui.io:443")
resp, err := cli.GetRecentTransactions(context.Background(), models.GetRecentTransactionRequest{
Count: 5,
})
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(resp)
//If you want to request for original json response, you can use SuiCall().
rsp, err := cli.SuiCall(context.Background(), "sui_getRecentTransactions", 5)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(rsp)
keystoreCli, err := sui.SetAccountKeyStore("../sui.keystore.fortest")
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(keystoreCli.Keys())
fmt.Println(keystoreCli.GetKey("your-address"))
}

18
go.mod Normal file
View File

@@ -0,0 +1,18 @@
module github.com/block-vision/sui-go-sdk
go 1.18
require (
github.com/tidwall/gjson v1.14.3
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
)
require (
github.com/google/go-cmp v0.5.8 // indirect
github.com/ledgerwatch/secp256k1 v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
gotest.tools v2.2.0+incompatible // indirect
)

18
go.sum Normal file
View File

@@ -0,0 +1,18 @@
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/ledgerwatch/secp256k1 v1.0.0 h1:Usvz87YoTG0uePIV8woOof5cQnLXGYa162rFf3YnwaQ=
github.com/ledgerwatch/secp256k1 v1.0.0/go.mod h1:SPmqJFciiF/Q0mPt2jVs2dTr/1TZBTIA+kPMmKgBAak=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=

58
httpconn/httpconn.go Normal file
View File

@@ -0,0 +1,58 @@
package httpconn
import (
"bytes"
"context"
"encoding/json"
"github.com/block-vision/sui-go-sdk/models"
"io/ioutil"
"net/http"
"time"
)
const defaultTimeout = time.Second * 5
type HttpConn struct {
c *http.Client
baseUrl string
timeout time.Duration
}
func NewHttpConn(baseUrl string) *HttpConn {
return &HttpConn{
c: &http.Client{},
baseUrl: baseUrl,
timeout: defaultTimeout,
}
}
func (h *HttpConn) Request(ctx context.Context, op Operation) ([]byte, error) {
jsonRPCReq := models.JsonRPCRequest{
JsonRPC: "2.0",
ID: 1,
Method: op.Method,
Params: op.Params,
}
reqBytes, err := json.Marshal(jsonRPCReq)
if err != nil {
return []byte{}, err
}
request, err := http.NewRequest("POST", h.baseUrl, bytes.NewBuffer(reqBytes))
if err != nil {
return []byte{}, err
}
request = request.WithContext(ctx)
request.Header.Add("Content-Type", "application/json")
rsp, err := h.c.Do(request)
if err != nil {
return []byte{}, err
}
defer rsp.Body.Close()
bodyBytes, err := ioutil.ReadAll(rsp.Body)
if err != nil {
return []byte{}, err
}
return bodyBytes, nil
}

6
httpconn/operation.go Normal file
View File

@@ -0,0 +1,6 @@
package httpconn
type Operation struct {
Method string
Params []interface{}
}

30
keypair/crypto.go Normal file
View File

@@ -0,0 +1,30 @@
package keypair
import (
"encoding/base64"
"encoding/hex"
"golang.org/x/crypto/sha3"
)
func fromPublicKeyBytesToAddress(publicKey []byte, scheme byte) string {
if scheme != Ed25519Flag && scheme != Secp256k1Flag {
return ""
}
tmp := make([]byte, len(publicKey)+1)
tmp[0] = scheme
for i := range publicKey {
tmp[i+1] = publicKey[i]
}
hexHash := sha3.Sum256(tmp)
return "0x" + hexEncode(hexHash[:])[:AccountAddress20Length*2]
}
func hexEncode(b []byte) string {
enc := make([]byte, len(b)*2)
hex.Encode(enc, b)
return string(enc)
}
func encodeBase64(value []byte) string {
return base64.StdEncoding.EncodeToString(value)
}

62
keypair/keypair.go Normal file
View File

@@ -0,0 +1,62 @@
package keypair
import (
"encoding/base64"
"github.com/block-vision/sui-go-sdk/sui_error"
"math"
"github.com/block-vision/sui-go-sdk/models"
)
const (
Ed25519Flag byte = 0
Secp256k1Flag byte = 1
ErrorFlag byte = math.MaxUint8
)
const (
ed25519PublicKeyLength = 32
secp256k1PublicKeyLength = 33
)
const (
DefaultAccountAddressLength = 16
AccountAddress20Length = 20
AccountAddress32Length = 32
)
func FetchKeyPair(value string) (models.SuiKeyPair, error) {
result, err := base64.StdEncoding.DecodeString(value)
if err != nil {
return models.SuiKeyPair{}, err
}
if len(result) == 0 {
return models.SuiKeyPair{}, err
}
switch result[0] {
case Ed25519Flag:
pb := result[1 : ed25519PublicKeyLength+1]
sk := result[1+ed25519PublicKeyLength:]
pbInBase64 := encodeBase64(pb)
return models.SuiKeyPair{
Flag: Ed25519Flag,
PrivateKey: sk,
PublicKeyBase64: pbInBase64,
PublicKey: pb,
Address: fromPublicKeyBytesToAddress(pb, Ed25519Flag),
}, nil
case Secp256k1Flag:
pb := result[1 : secp256k1PublicKeyLength+1]
sk := result[1+secp256k1PublicKeyLength:]
pbInBase64 := encodeBase64(pb)
return models.SuiKeyPair{
Flag: Secp256k1Flag,
PrivateKey: sk,
PublicKey: pb,
PublicKeyBase64: pbInBase64,
Address: fromPublicKeyBytesToAddress(pb, Secp256k1Flag),
}, nil
default:
return models.SuiKeyPair{}, sui_error.ErrInvalidEncryptFlag
}
}

8
models/base.go Normal file
View File

@@ -0,0 +1,8 @@
package models
type JsonRPCRequest struct {
JsonRPC string `json:"jsonrpc"`
ID interface{} `json:"id"`
Method string `json:"method"`
Params []interface{} `json:"params"`
}

1
models/basic_types.go Normal file
View File

@@ -0,0 +1 @@
package models

17
models/feature.go Normal file
View File

@@ -0,0 +1,17 @@
package models
type MoveCallAndExecuteTransactionRequest struct {
MoveCallRequest
}
type MoveCallAndExecuteTransactionResponse struct {
ExecuteTransactionResponse
}
type BatchAndExecuteTransactionRequest struct {
BatchTransactionRequest
}
type BatchAndExecuteTransactionResponse struct {
Result []ExecuteTransactionResponse
}

11
models/keypair.go Normal file
View File

@@ -0,0 +1,11 @@
package models
type SuiKeyPair struct {
Flag byte
Address string
PublicKey []byte
PublicKeyBase64 string
PrivateKey []byte
}

28
models/objects.go Normal file
View File

@@ -0,0 +1,28 @@
package models
import "github.com/block-vision/sui-go-sdk/models/sui_types"
type SuiObjectInfo struct {
sui_types.SuiObjectRef
Type string `json:"type_"`
sui_types.Owner
PreviousTransaction string `json:"previousTransaction"`
}
type SuiMoveObject struct {
Type string
Fields map[string]interface{}
HasPublicTransfer bool
}
type SuiMoveModuleId struct {
Address string
Name string
}
type SuiMoveNormalizedModule struct {
FileFormatVersion uint64
Address string
Name string
Friends []SuiMoveModuleId
}

67
models/read_event.go Normal file
View File

@@ -0,0 +1,67 @@
package models
import "github.com/block-vision/sui-go-sdk/models/sui_json_rpc_types"
type GetEventsByEventTypeRequest struct {
EventType string `json:"eventType"`
Count uint64 `json:"count"`
StartTime uint64 `json:"startTime"`
EndTime uint64 `json:"endTime"`
}
type GetEventsByEventTypeResponse struct {
Result []sui_json_rpc_types.SuiEventEnvelop
}
type GetEventsByModuleRequest struct {
Package string `json:"package"`
Module string `json:"module"`
Count uint64 `json:"count"`
StartTime uint64 `json:"startTime"`
EndTime uint64 `json:"endTime"`
}
type GetEventsByModuleResponse struct {
Result []sui_json_rpc_types.SuiEventEnvelop
}
type GetEventsByObjectRequest struct {
Object string `json:"object"`
Count uint64 `json:"count"`
StartTime uint64 `json:"startTime"`
EndTime uint64 `json:"endTime"`
}
type GetEventsByObjectResponse struct {
Result []sui_json_rpc_types.SuiEventEnvelop
}
type GetEventsByOwnerRequest struct {
Owner string `json:"owner"`
Count uint64 `json:"count"`
StartTime uint64 `json:"startTime"`
EndTime uint64 `json:"endTime"`
}
type GetEventsByOwnerResponse struct {
Result []sui_json_rpc_types.SuiEventEnvelop
}
type GetEventsBySenderRequest struct {
Sender string `json:"sender"`
Count uint64 `json:"count"`
StartTime uint64 `json:"startTime"`
EndTime uint64 `json:"endTime"`
}
type GetEventsBySenderResponse struct {
Result []sui_json_rpc_types.SuiEventEnvelop
}
type GetEventsByTransactionRequest struct {
Digest string `json:"digest"`
}
type GetEventsByTransactionResponse struct {
Result []sui_json_rpc_types.SuiEventEnvelop
}

50
models/read_move.go Normal file
View File

@@ -0,0 +1,50 @@
package models
import "github.com/block-vision/sui-go-sdk/models/sui_json_rpc_types"
type GetMoveFunctionArgTypesRequest struct {
Package string
Module string
Function string
}
type GetMoveFunctionArgTypesResponse struct {
Result []interface{} `json:"result"`
}
type GetNormalizedMoveModulesByPackageRequest struct {
Package string `json:"package"`
}
type GetNormalizedMoveModulesByPackageResponse struct {
Result map[string]sui_json_rpc_types.SuiMoveNormalizedModule
}
type GetNormalizedMoveModuleRequest struct {
Package string `json:"package"`
ModuleName string `json:"moduleName"`
}
type GetNormalizedMoveModuleResponse struct {
Result sui_json_rpc_types.SuiMoveNormalizedModule
}
type GetNormalizedMoveStructRequest struct {
Package string `json:"package"`
ModuleName string `json:"moduleName"`
StructName string `json:"structName"`
}
type GetNormalizedMoveStructResponse struct {
Result sui_json_rpc_types.SuiMoveNormalizedStruct
}
type GetNormalizedMoveFunctionRequest struct {
Package string `json:"package"`
ModuleName string `json:"moduleName"`
FunctionName string `json:"functionName"`
}
type GetNormalizedMoveFunctionResponse struct {
Result sui_json_rpc_types.SuiMoveNormalizedFunction
}

50
models/read_object.go Normal file
View File

@@ -0,0 +1,50 @@
package models
import (
"github.com/block-vision/sui-go-sdk/models/sui_json_rpc_types"
"github.com/block-vision/sui-go-sdk/models/sui_types"
)
type GetObjectRequest struct {
ObjectID string `json:"objectID"`
}
type GetObjectResponse struct {
Details struct {
Data sui_json_rpc_types.SuiParsedMoveObject `json:"data"`
sui_json_rpc_types.OwnedObjectRef
PreviousTransaction string `json:"previousTransaction"`
StorageRebate uint64 `json:"storageRebate"`
Reference sui_types.SuiObjectRef `json:"reference"`
} `json:"details"`
Status string `json:"status"`
}
type GetObjectsOwnedByAddressRequest struct {
Address string `json:"address"`
}
type GetObjectsOwnedByAddressResponse struct {
Result []SuiObjectInfo `json:"result"`
}
type GetObjectsOwnedByObjectRequest struct {
ObjectID string `json:"objectID"`
}
type GetObjectsOwnedByObjectResponse struct {
Result []SuiObjectInfo `json:"result"`
}
type GetRawObjectRequest struct {
ObjectID string `json:"objectID"`
}
type GetRawObjectResponse struct {
Details struct {
Data sui_json_rpc_types.SuiParsedMoveObject `json:"data"`
sui_json_rpc_types.OwnedObjectRef
PreviousTransaction string `json:"previousTransaction"`
StorageRebate uint64 `json:"storageRebate"`
Reference sui_types.SuiObjectRef `json:"reference"`
} `json:"details"`
Status string `json:"status"`
}

View File

@@ -0,0 +1,84 @@
package models
import (
"github.com/block-vision/sui-go-sdk/models/sui_json_rpc_types"
)
type GetRecentTransactionRequest struct {
Count uint64
}
type GetRecentTransactionResponse struct {
Result []GetTransactionMetaData `json:"result"`
}
type GetTransactionMetaData struct {
GatewayTxSeqNumber uint64 `json:"gatewayTxSeqNumber"`
TransactionDigest string `json:"transactionDigest"`
}
type GetTotalTransactionNumberRequest struct{}
type GetTotalTransactionNumberResponse struct {
TotalNumberOfTransaction uint64 `json:"totalNumberOfTransaction"`
}
type GetTransactionRequest struct {
Digest string `json:"digest"`
}
type GetTransactionResponse struct {
Certificate sui_json_rpc_types.SuiCertifiedTransaction `json:"certificate"`
Effects sui_json_rpc_types.SuiTransactionEffects `json:"effects"`
TimestampMs uint64 `json:"timestamp_ms,omitempty"`
// ParserData with Schema
ParsedData interface{} `json:"parsed_data,omitempty"`
}
type GetTransactionsByInputObjectRequest struct {
ObjectID string `json:"objectID"`
}
type GetTransactionsByInputObjectResponse struct {
Result []GetTransactionMetaData `json:"result"`
}
type GetTransactionsByMoveFunctionRequest struct {
Package string `json:"package"`
Module string `json:"module"`
Function string `json:"function"`
}
type GetTransactionsByMoveFunctionResponse struct {
Result []GetTransactionMetaData `json:"result"`
}
type GetTransactionsByMutatedObjectRequest struct {
ObjectID string
}
type GetTransactionsByMutatedObjectResponse struct {
Result []GetTransactionMetaData `json:"result"`
}
type GetTransactionsFromAddressRequest struct {
Addr string `json:"addr"`
}
type GetTransactionsFromAddressResponse struct {
Result []GetTransactionMetaData `json:"result"`
}
type GetTransactionsInRangeRequest struct {
Start uint64 `json:"start"`
End uint64 `json:"end"`
}
type GetTransactionsInRangeResponse struct {
Result []GetTransactionMetaData `json:"result"`
}
type GetTransactionsToAddressRequest struct {
Addr string
}
type GetTransactionsToAddressResponse struct {
Result []GetTransactionMetaData
}

7
models/request.go Normal file
View File

@@ -0,0 +1,7 @@
package models
type Request struct {
Name string
HttpMethod string
HttpPath string
}

View File

@@ -0,0 +1,159 @@
package sui_json_rpc_types
import "github.com/block-vision/sui-go-sdk/models/sui_types"
type SuiCertifiedTransaction struct {
TransactionDigest string `json:"transactionDigest,omitempty"`
Data SuiTransactionData `json:"data,omitempty"`
TxSignature string `json:"txSignature,omitempty"`
AuthSignInfo AuthorityQuorumSignInfo `json:"authSignInfo,omitempty"`
}
type SuiParsedTransactionResponse struct {
Publish SuiParsedPublishResponse `json:"publish,omitempty"`
MergeCoin SuiParsedMergeCoinResponse `json:"mergeCoin,omitempty"`
SplitCoin SuiParsedSplitCoinResponse `json:"splitCoin,omitempty"`
}
type SuiParsedPublishResponse struct {
Package sui_types.SuiObjectRef `json:"package"`
}
type SuiParsedMergeCoinResponse struct {
}
type SuiParsedSplitCoinResponse struct {
}
type SuiTransactionData struct {
Transactions []SuiTransactionKind `json:"transactions,omitempty"`
Sender string `json:"sender,omitempty"`
GasPayment sui_types.SuiObjectRef `json:"gasPayment,omitempty"`
GasBudget uint64 `json:"gasBudget,omitempty"`
}
type AuthorityQuorumSignInfo struct {
Epoch uint64 `json:"epoch,omitempty"`
Signature []string `json:"signature,omitempty"`
SignersMap []uint64 `json:"signers_map,omitempty"`
}
type SuiTransactionKind struct {
TransferObject TransferObject `json:"transferObject,omitempty"`
Publish Publish `json:"publish,omitempty"`
Call Call `json:"call,omitempty"`
TransferSui TransferSui `json:"transferSui,omitempty"`
ChangeEpoch ChangeEpoch `json:"changeEpoch,omitempty"`
}
type TransferObject struct {
Recipient string `json:"recipient,omitempty"`
ObjectRef sui_types.SuiObjectRef `json:"objectRef,omitempty"`
}
type Publish struct {
Modules [][]byte `json:"modules,omitempty"`
}
type Call struct {
Package sui_types.SuiObjectRef `json:"package"`
Module string `json:"module"`
Function string `json:"function"`
TypeArguments []interface{} `json:"typeArguments"`
Arguments []interface{} `json:"arguments"`
}
type TransferSui struct {
Recipient string `json:"recipient,omitempty"`
Amount uint64 `json:"amount,omitempty"`
}
type ChangeEpoch struct {
Epoch uint64 `json:"epoch"`
StorageCharge uint64 `json:"storageCharge"`
ComputationCharge uint64 `json:"computationCharge"`
}
type SuiTransactionEffects struct {
Status SuiExecutionStatus `json:"status"`
GasUsed SuiGasCostSummary `json:"gasUsed"`
ShareObjects []sui_types.SuiObjectRef `json:"shareObjects,omitempty"`
TransactionDigest string `json:"transactionDigest"`
Created []OwnedObjectRef `json:"created,omitempty"`
Mutated []OwnedObjectRef `json:"mutated,omitempty"`
Unwrapped []OwnedObjectRef `json:"unwrapped,omitempty"`
Deleted []sui_types.SuiObjectRef `json:"deleted,omitempty"`
Wrapped []sui_types.SuiObjectRef `json:"wrapped,omitempty"`
GasObject OwnedObjectRef `json:"gasObject,omitempty"`
Events []SuiEvent `json:"events,omitempty"`
Dependencies []string `json:"dependencies,omitempty"`
}
type SuiGasCostSummary struct {
ComputationCost uint64 `json:"computationCost"`
StorageCost uint64 `json:"storageCost"`
StorageRebate uint64 `json:"storageRebate"`
}
type SuiExecutionStatus struct {
Status string `json:"status"`
}
type OwnedObjectRef struct {
Owner sui_types.Owner `json:"owner,omitempty"`
Reference sui_types.SuiObjectRef `json:"reference,omitempty"`
}
type SuiEvent struct {
MoveEvent MoveEvent `json:"moveEvent,omitempty"`
Publish Publish `json:"publish,omitempty"`
}
type MoveEvent struct {
PackageID string `json:"packageID,omitempty"`
}
type SuiParsedMoveObject struct {
DataType string `json:"dataType"`
Type string `json:"type"`
HasPublicTransfer bool `json:"has_public_transfer"`
Fields map[string]interface{} `json:"fields"`
BcsBytes []byte `json:"bcs_bytes,omitempty"`
}
type SuiObjectInfo struct {
OwnedObjectRef `json:"owner"`
}
type SuiEventEnvelop struct {
Timestamp uint64 `json:"timestamp"`
TxDigest string `json:"txDigest,omitempty"`
SuiEvent
}
type SuiMoveModuleId struct {
Address string `json:"address"`
Name string `json:"name"`
}
type SuiMoveNormalizedModule struct {
FileFormatVersion uint32 `json:"fileFormatVersion"`
Address string `json:"address"`
Name string `json:"name"`
Friends []SuiMoveModuleId `json:"friends"`
Structs map[string]interface{} `json:"structs"`
ExposedFunctions map[string]interface{} `json:"exposedFunctions"`
}
type SuiMoveNormalizedStruct struct {
Abilities interface{} `json:"abilities"`
TypeParameters []interface{} `json:"typeParameters"`
Fields []interface{} `json:"fields"`
}
type SuiMoveNormalizedFunction struct {
Visibility interface{} `json:"visibility"`
IsEntry bool `json:"isEntry"`
Parameters []interface{} `json:"parameters"`
Return_ []interface{} `json:"return_"`
}

View File

@@ -0,0 +1,12 @@
package sui_types
type SuiObjectRef struct {
Digest string `json:"digest"`
ObjectId string `json:"objectId"`
Version uint64 `json:"version"`
}
type Owner struct {
AddressOwner string `json:"addressOwner,omitempty"`
ObjectOwner string `json:"objectOwner,omitempty"`
}

145
models/write_transaction.go Normal file
View File

@@ -0,0 +1,145 @@
package models
import (
"github.com/block-vision/sui-go-sdk/models/sui_json_rpc_types"
"github.com/block-vision/sui-go-sdk/models/sui_types"
)
type MoveCallRequest struct {
Signer string `json:"signer"`
PackageObjectId string `json:"packageObjectId"`
Module string `json:"module"`
Function string `json:"function"`
TypeArguments interface{} `json:"typeArguments"`
Arguments []interface{} `json:"arguments"`
Gas string `json:"gas"`
GasBudget uint64 `json:"gasBudget"`
}
type MoveCallResponse struct {
Gas sui_types.SuiObjectRef `json:"gas"`
InputObjects interface{} `json:"inputObjects"`
TxBytes string `json:"txBytes"`
}
type MergeCoinsRequest struct {
Signer string `json:"signer"`
PrimaryCoin string `json:"primaryCoin"`
CoinToMerge string `json:"coinToMerge"`
Gas string `json:"gas"`
GasBudget uint64 `json:"gasBudget"`
}
type MergeCoinsResponse struct {
TransactionBytes string `json:"transactionBytes"`
Gas sui_types.SuiObjectRef `json:"gas"`
InputObject interface{} `json:"inputObject"`
TxBytes string `json:"txBytes"`
}
type SplitCoinRequest struct {
Signer string `json:"signer"`
CoinObjectId string `json:"coinObjectId"`
SplitAmounts []uint64 `json:"splitAmounts"`
Gas string `json:"gas"`
GasBudget uint64
}
type SplitCoinResponse struct {
TransactionBytes string `json:"transactionBytes"`
Gas sui_types.SuiObjectRef `json:"gas"`
InputObject interface{} `json:"inputObject"`
TxBytes string `json:"txBytes"`
}
type SplitCoinEqualRequest struct {
Signer string `json:"signer"`
CoinObjectId string `json:"coinObjectId"`
SplitCount uint64 `json:"splitCount"`
Gas string `json:"gas"`
GasBudget uint64
}
type SplitCoinEqualResponse struct {
TransactionBytes string `json:"transactionBytes"`
Gas sui_types.SuiObjectRef `json:"gas"`
InputObject interface{} `json:"inputObject"`
TxBytes string `json:"txBytes"`
}
type PublishRequest struct {
Sender string `json:"sender"`
CompiledModules []string `json:"compiledModules"`
Gas string `json:"gas"`
GasBudget uint64 `json:"gasBudget"`
}
type PublishResponse struct {
TransactionBytes string `json:"transactionBytes"`
Gas sui_types.SuiObjectRef `json:"gas"`
InputObject interface{} `json:"inputObject"`
TxBytes string `json:"txBytes"`
}
type TransferObjectRequest struct {
Signer string `json:"signer"`
ObjectId string `json:"objectId"`
Gas string `json:"gas"`
GasBudget uint64 `json:"gasBudget"`
Recipient string `json:"recipient"`
}
type TransferObjectResponse struct {
TransactionBytes string `json:"transactionBytes"`
Gas sui_types.SuiObjectRef `json:"gas"`
InputObject interface{} `json:"inputObject"`
TxBytes string `json:"txBytes"`
}
type TransferSuiRequest struct {
Signer string `json:"signer"`
SuiObjectId string `json:"suiObjectId"`
GasBudget uint64 `json:"gasBudget"`
Recipient string `json:"recipient"`
Amount uint64 `json:"amount"`
}
type TransferSuiResponse struct {
TransactionBytes string `json:"transactionBytes"`
Gas sui_types.SuiObjectRef `json:"gas"`
InputObject interface{} `json:"inputObject"`
TxBytes string `json:"txBytes"`
}
type BatchTransactionRequest struct {
Signer string `json:"signer"`
SingleTransactionParams []SingleTransactionParams `json:"singleTransactionParams"`
Gas string `json:"gas"`
GasBudget uint64 `json:"gasBudget"`
}
type BatchTransactionResponse struct {
TransactionBytes string `json:"transactionBytes"`
Gas sui_types.SuiObjectRef `json:"gas"`
InputObject interface{} `json:"inputObject"`
TxBytes string `json:"txBytes"`
}
type SingleTransactionParams struct {
MoveCallRequestParams *MoveCallRequest `json:"moveCallRequestParams,omitempty"`
TransferObjectRequestParams *TransferObjectRequest `json:"transferObjectRequestParams,omitempty"`
}
type ExecuteTransactionRequest struct {
TxBytes string `json:"txBytes"`
SigScheme string `json:"sigScheme"`
Signature string `json:"signature"`
PubKey string `json:"pubKey"`
}
type ExecuteTransactionResponse struct {
Certificate sui_json_rpc_types.SuiCertifiedTransaction `json:"certificate"`
Effects sui_json_rpc_types.SuiTransactionEffects `json:"effects"`
TimestampMs uint64 `json:"timestamp_ms"`
ParsedData interface{} `json:"parsed_data"`
}

48
sui/api.go Normal file
View File

@@ -0,0 +1,48 @@
package sui
import (
"github.com/block-vision/sui-go-sdk/httpconn"
)
type ISuiAPI interface {
IBaseAPI
IWriteTransactionAPI
IReadEventFromSuiAPI
IReadMoveFromSuiAPI
IReadObjectFromSuiAPI
IReadTransactionFromSuiAPI
IFeatureSuiAPI
}
type Client struct {
IBaseAPI
IWriteTransactionAPI
IReadEventFromSuiAPI
IReadMoveFromSuiAPI
IReadObjectFromSuiAPI
IReadTransactionFromSuiAPI
IFeatureSuiAPI
}
func NewSuiClient(dest string) ISuiAPI {
conn := httpconn.NewHttpConn(dest)
return &Client{
IWriteTransactionAPI: &suiWriteTransactionImpl{
conn: conn,
},
IReadEventFromSuiAPI: &suiReadEventFromSuiImpl{
conn: conn,
},
IReadMoveFromSuiAPI: &suiReadMoveFromSuiImpl{
conn: conn,
},
IReadObjectFromSuiAPI: &suiReadObjectFromSuiImpl{
conn: conn,
},
IReadTransactionFromSuiAPI: &suiReadTransactionFromSuiImpl{
conn: conn,
},
IBaseAPI: &suiBaseImpl{conn: conn},
IFeatureSuiAPI: &suiFeatureImpl{conn: conn},
}
}

27
sui/base_api.go Normal file
View File

@@ -0,0 +1,27 @@
package sui
import (
"context"
"github.com/block-vision/sui-go-sdk/httpconn"
"github.com/tidwall/gjson"
)
type IBaseAPI interface {
SuiCall(ctx context.Context, method string, params ...interface{}) (interface{}, error)
}
type suiBaseImpl struct {
conn *httpconn.HttpConn
}
// SuiCall send customized request to Sui Node endpoint.
func (s *suiBaseImpl) SuiCall(ctx context.Context, method string, params ...interface{}) (interface{}, error) {
resp, err := s.conn.Request(ctx, httpconn.Operation{
Method: method,
Params: params,
})
if err != nil {
return nil, err
}
return gjson.ParseBytes(resp).String(), nil
}

181
sui/feature_api.go Normal file
View File

@@ -0,0 +1,181 @@
package sui
import (
"context"
"encoding/base64"
"encoding/json"
"github.com/block-vision/sui-go-sdk/httpconn"
"github.com/block-vision/sui-go-sdk/keypair"
"github.com/block-vision/sui-go-sdk/models"
"github.com/block-vision/sui-go-sdk/sui_error"
"github.com/tidwall/gjson"
)
type IFeatureSuiAPI interface {
MoveCallAndExecuteTransaction(ctx context.Context, req models.MoveCallAndExecuteTransactionRequest, opts ...interface{}) (models.MoveCallAndExecuteTransactionResponse, error)
BatchAndExecuteTransaction(ctx context.Context, req models.BatchAndExecuteTransactionRequest, opts ...interface{}) (models.BatchAndExecuteTransactionResponse, error)
SignWithAddress(ctx context.Context, address string, msg []byte) ([]byte, error)
Sign(ctx context.Context, msg []byte) ([]byte, error)
}
type suiFeatureImpl struct {
conn *httpconn.HttpConn
}
// MoveCallAndExecuteTransaction is a combination of `sui_moveCall` and `sui_executeTransaction`.
// This function free you from setting parameters when you want to execute the transaction of previous `sui_moveCall`
// but you need to `SetAccountKeyStore` first otherwise you cannot sign your transaction
func (s *suiFeatureImpl) MoveCallAndExecuteTransaction(ctx context.Context, req models.MoveCallAndExecuteTransactionRequest, opts ...interface{}) (models.MoveCallAndExecuteTransactionResponse, error) {
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_moveCall",
Params: []interface{}{
req.Signer,
req.PackageObjectId,
req.Module,
req.Function,
req.TypeArguments,
req.Arguments,
req.Gas,
req.GasBudget,
},
})
if err != nil {
return models.MoveCallAndExecuteTransactionResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.MoveCallAndExecuteTransactionResponse{}, sui_error.ErrInvalidJson
}
var moveCallRsp models.MoveCallResponse
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &moveCallRsp)
if err != nil {
return models.MoveCallAndExecuteTransactionResponse{}, err
}
if req.Signer == "" {
req.Signer = accountStore.defaultAddress
}
_keypair, err := accountStore.GetKey(req.Signer)
if err != nil {
return models.MoveCallAndExecuteTransactionResponse{}, err
}
msg, err := base64.StdEncoding.DecodeString(moveCallRsp.TxBytes)
if err != nil {
return models.MoveCallAndExecuteTransactionResponse{}, err
}
signature, err := accountStore.Sign(req.Signer, []byte(msg))
if err != nil {
return models.MoveCallAndExecuteTransactionResponse{}, err
}
var scheme string
if _keypair.Flag == keypair.Ed25519Flag {
scheme = "ED25519"
} else if _keypair.Flag == keypair.Secp256k1Flag {
scheme = "SECP256K1"
} else {
return models.MoveCallAndExecuteTransactionResponse{}, sui_error.ErrUnknownSignatureScheme
}
respBytes, err = s.conn.Request(ctx, httpconn.Operation{
Method: "sui_executeTransaction",
Params: []interface{}{
moveCallRsp.TxBytes,
scheme,
signature,
_keypair.PublicKeyBase64,
},
})
var rsp models.MoveCallAndExecuteTransactionResponse
if err != nil {
return models.MoveCallAndExecuteTransactionResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.MoveCallAndExecuteTransactionResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.MoveCallAndExecuteTransactionResponse{}, err
}
return rsp, nil
}
// BatchAndExecuteTransaction is a combination of `sui_batchTransaction` and `sui_executeTransaction`.
// This function free you from setting parameters when you want to execute the transactions of previous `sui_batchTransaction`
// but you need to `SetAccountKeyStore` first otherwise you cannot sign your transactions
func (s *suiFeatureImpl) BatchAndExecuteTransaction(ctx context.Context, req models.BatchAndExecuteTransactionRequest, opts ...interface{}) (models.BatchAndExecuteTransactionResponse, error) {
var batchTxRsp models.BatchTransactionResponse
batchTxBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_batchTransaction",
Params: []interface{}{
req.Signer,
req.SingleTransactionParams,
req.Gas,
req.GasBudget,
},
})
if err != nil {
return models.BatchAndExecuteTransactionResponse{}, err
}
if !gjson.ValidBytes(batchTxBytes) {
return models.BatchAndExecuteTransactionResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(batchTxBytes).Get("result").String()), &batchTxRsp)
if err != nil {
return models.BatchAndExecuteTransactionResponse{}, err
}
if req.Signer == "" {
req.Signer = accountStore.defaultAddress
}
_keypair, err := accountStore.GetKey(req.Signer)
if err != nil {
return models.BatchAndExecuteTransactionResponse{}, err
}
msg, err := base64.StdEncoding.DecodeString(batchTxRsp.TxBytes)
if err != nil {
return models.BatchAndExecuteTransactionResponse{}, err
}
signature, err := accountStore.Sign(req.Signer, msg)
if err != nil {
return models.BatchAndExecuteTransactionResponse{}, err
}
var scheme string
if _keypair.Flag == keypair.Ed25519Flag {
scheme = "ED25519"
} else if _keypair.Flag == keypair.Secp256k1Flag {
scheme = "SECP256K1"
} else {
return models.BatchAndExecuteTransactionResponse{}, sui_error.ErrUnknownSignatureScheme
}
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_executeTransaction",
Params: []interface{}{
batchTxRsp.TxBytes,
scheme,
signature,
_keypair.PublicKeyBase64,
},
})
var rsp models.BatchAndExecuteTransactionResponse
if err != nil {
return models.BatchAndExecuteTransactionResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.BatchAndExecuteTransactionResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.BatchAndExecuteTransactionResponse{}, err
}
return rsp, nil
}
// SignWithAddress implements Sign method.
// `address` you want to sign with MUST be one of addresses in your `sui.keystore` file you load before.
// Use it after you load the `sui.keystore` file
func (s *suiFeatureImpl) SignWithAddress(ctx context.Context, address string, msg []byte) ([]byte, error) {
return accountStore.Sign(address, msg)
}
// Sign implements Sign Method with default address.
// It will use your first key in `sui.keystore` file as your default address.
// Use it after you load the `sui.keystore` file
func (s *suiFeatureImpl) Sign(ctx context.Context, msg []byte) ([]byte, error) {
return accountStore.Sign(accountStore.defaultAddress, msg)
}

100
sui/keystore.go Normal file
View File

@@ -0,0 +1,100 @@
package sui
import (
"crypto/sha256"
"github.com/block-vision/sui-go-sdk/sui_error"
"github.com/ledgerwatch/secp256k1"
"sync"
"github.com/block-vision/sui-go-sdk/config"
"github.com/block-vision/sui-go-sdk/keypair"
"github.com/block-vision/sui-go-sdk/models"
"golang.org/x/crypto/ed25519"
)
type IAccountKeyStore interface {
Sign(address string, msg []byte) (signature []byte, err error)
GetKey(address string) (models.SuiKeyPair, error)
AddKey(keypair string) (err error)
Keys() (publicKeys []string)
}
type AccountKeyStoreImpl struct {
defaultAddress string
keystore *sync.Map
}
var accountStore *AccountKeyStoreImpl
func SetAccountKeyStore(configDir string) (IAccountKeyStore, error) {
kpStrs, err := config.GetKeyStore(configDir)
if err != nil {
return accountStore, err
}
accountStore = &AccountKeyStoreImpl{
keystore: new(sync.Map),
}
for i := range kpStrs.Keys {
if i == 0 {
accountStore.defaultAddress = kpStrs.Keys[i]
}
kp, subErr := keypair.FetchKeyPair(kpStrs.Keys[i])
if subErr != nil {
return accountStore, subErr
}
accountStore.keystore.Store(kp.Address, kp)
}
return accountStore, nil
}
func (a *AccountKeyStoreImpl) Sign(address string, msg []byte) (signature []byte, err error) {
if a.keystore == nil {
return []byte{}, sui_error.ErrNoKeyStoreInfo
}
kp, ok := a.keystore.Load(address)
if !ok {
return []byte{}, sui_error.ErrAddressNotInKeyStore
}
_keypair := kp.(models.SuiKeyPair)
if _keypair.Flag == keypair.Ed25519Flag {
return ed25519.Sign(ed25519.NewKeyFromSeed(_keypair.PrivateKey), msg), nil
}
data := sha256.Sum256(msg)
return secp256k1.Sign(data[:], _keypair.PrivateKey)
}
func (a *AccountKeyStoreImpl) GetKey(address string) (models.SuiKeyPair, error) {
if a.keystore == nil {
return models.SuiKeyPair{}, sui_error.ErrNoKeyStoreInfo
}
kp, ok := a.keystore.Load(address)
if !ok {
return models.SuiKeyPair{}, sui_error.ErrInvalidAddress
}
_keypair := kp.(models.SuiKeyPair)
return _keypair, nil
}
func (a *AccountKeyStoreImpl) AddKey(key string) (err error) {
if a.keystore == nil {
return sui_error.ErrNoKeyStoreInfo
}
kp, err := keypair.FetchKeyPair(key)
if err != nil {
return err
}
a.keystore.Store(kp.Address, kp)
return nil
}
func (a *AccountKeyStoreImpl) Keys() (publicKeys []string) {
if a.keystore == nil {
return []string{}
}
a.keystore.Range(func(key, value any) bool {
_kp := value.(models.SuiKeyPair)
publicKeys = append(publicKeys, _kp.PublicKeyBase64)
return true
})
return publicKeys
}

128
sui/keystore_test.go Normal file
View File

@@ -0,0 +1,128 @@
package sui
import (
"encoding/base64"
"fmt"
"gotest.tools/assert"
"testing"
)
func TestOnKeyStoreSign(t *testing.T) {
ks, err := SetAccountKeyStore("../config/sui.keystore.fortest")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
t.Run("test on sign with ed25519", func(t *testing.T) {
ed25519Addr := "0x72cffd05deb71fa9b30584cb0f512d680cb08eab"
txDataBytes, err := base64.StdEncoding.DecodeString("VHJhbnNhY3Rpb25EYXRhOjoAAgAAAAAAAAAAAAAAAAAAAAAAAAACAQAAAAAAAAAgf4wCMzbSQGAtJy5c2FShsm5eDefCLIODnSU2sC07IXMKZGV2bmV0X25mdARtaW50AAMADAtibG9ja3Zpc2lvbgAMC2Jsb2NrdmlzaW9uAAgHdGVzdHVybA8VhOvfVMkbhXJ5Oyp54IVRTqbH2I2ztReyGFA+2Q33fyXewleRiQMEAAAAAAAAACBvr7UgN38gsUyCYE9wVOFX6mj20zu+W+y5dUyfsb01EAEAAAAAAAAA6AMAAAAAAAA=")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
expected := []byte("dQ5BbqgrPtbsoHBowT1f8WVxO5trpHHXNs4g0Mj9p2/8oOnzKyd8VnEt6eUUBWLiHnfuDIYxEzwFC89nD+XZDQ==")
actualBytes, err := ks.Sign(ed25519Addr, txDataBytes)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
assert.Equal(t, string(expected), string(base64.StdEncoding.EncodeToString(actualBytes)))
})
t.Run("test on sign with secp256k1", func(t *testing.T) {
secpAddr := "0x4d6f1a54e805038f44ecd3112927af147e9b9ecb"
txDataBytes, err := base64.StdEncoding.DecodeString("VHJhbnNhY3Rpb25EYXRhOjoAAgAAAAAAAAAAAAAAAAAAAAAAAAACAQAAAAAAAAAgf4wCMzbSQGAtJy5c2FShsm5eDefCLIODnSU2sC07IXMKZGV2bmV0X25mdARtaW50AAMADAtibG9ja3Zpc2lvbgAMC2Jsb2NrdmlzaW9uAAgHdGVzdHVybA8VhOvfVMkbhXJ5Oyp54IVRTqbH2I2ztReyGFA+2Q33fyXewleRiQMEAAAAAAAAACBvr7UgN38gsUyCYE9wVOFX6mj20zu+W+y5dUyfsb01EAEAAAAAAAAA6AMAAAAAAAA=")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
expected := []byte("0mkXvSOEq57hJPdd+svJ6CNYXRV9Go9pSTuvHIbRkaZxcKWQSz1U3aKywCDtBZsFIzXP8Wf1g5zbXFcwkt4A/wA=")
actual, err := ks.Sign(secpAddr, txDataBytes)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
assert.Equal(t, string(expected), base64.StdEncoding.EncodeToString(actual))
})
}
func TestOnKeyStoreKeys(t *testing.T) {
ks, err := SetAccountKeyStore("../config/sui.keystore.fortest")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
t.Run("test on get public keys", func(t *testing.T) {
publicKeys := ks.Keys()
if len(publicKeys) != 6 {
t.FailNow()
}
containStr := func(strs []string, str string) bool {
for i := range strs {
if str == strs[i] {
return true
}
}
return false
}
for i := range publicKeys {
if !containStr(publicKeys, publicKeys[i]) {
t.FailNow()
}
}
})
}
func TestOnKeyStoreGetKey(t *testing.T) {
ks, err := SetAccountKeyStore("../config/sui.keystore.fortest")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
t.Run("test on keystore GetKey()", func(t *testing.T) {
_kp, err := ks.GetKey("0x4d6f1a54e805038f44ecd3112927af147e9b9ecb")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
assert.Equal(t, "A5/ex++LPumQg36qll95WuyJ2Dejf3AKiGc1LqGSYLOR", _kp.PublicKeyBase64)
_kp, err = ks.GetKey("0x72cffd05deb71fa9b30584cb0f512d680cb08eab")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
assert.Equal(t, "XoFR32cGFHSHqGK96LSfBwx7U38aesHth5wy7wbjJWk=", _kp.PublicKeyBase64)
_kp, err = ks.GetKey("0x8f3cf7d8ebb187bd655cea775802d0d9c1c5b145")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
assert.Equal(t, "ILFuDpjV0wfTYP9GqDN5AsuU4kHoVqdwsINIVnSh7dc=", _kp.PublicKeyBase64)
_kp, err = ks.GetKey("0xc697e5fdd38d5f63ebeb14c2b49a864d473849db")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
assert.Equal(t, "RCZJ/xmuALnCxErBTAs/FxowPtOJSOnVIzGikcpj78Y=", _kp.PublicKeyBase64)
_kp, err = ks.GetKey("0xf354bb3497c5879d68b49582d3a8887dbd26e3f0")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
assert.Equal(t, "M1UztctB3tvHRgWpjhHon7nzWWIoh4pBaERNfUg7loU=", _kp.PublicKeyBase64)
_kp, err = ks.GetKey("0xfde3698d3e7da3f359e1036078da9cfbfb31f203")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
assert.Equal(t, "owj3ywGVAs9e280oC78MDuYMkAJ24Qj/Op0hnO/2QFE=", _kp.PublicKeyBase64)
})
}

166
sui/read_event_api.go Normal file
View File

@@ -0,0 +1,166 @@
package sui
import (
"context"
"encoding/json"
"github.com/block-vision/sui-go-sdk/httpconn"
"github.com/block-vision/sui-go-sdk/models"
"github.com/block-vision/sui-go-sdk/sui_error"
"github.com/tidwall/gjson"
)
type IReadEventFromSuiAPI interface {
GetEventsByEventType(ctx context.Context, req models.GetEventsByEventTypeRequest, opts ...interface{}) (models.GetEventsByEventTypeResponse, error)
GetEventsByModule(ctx context.Context, req models.GetEventsByModuleRequest, opts ...interface{}) (models.GetEventsByModuleResponse, error)
GetEventsByObject(ctx context.Context, req models.GetEventsByObjectRequest, opts ...interface{}) (models.GetEventsByObjectResponse, error)
GetEventsByOwner(ctx context.Context, req models.GetEventsByOwnerRequest, opts ...interface{}) (models.GetEventsByOwnerResponse, error)
GetEventsBySender(ctx context.Context, req models.GetEventsBySenderRequest, opts ...interface{}) (models.GetEventsBySenderResponse, error)
GetEventsByTransaction(ctx context.Context, req models.GetEventsByTransactionRequest, opts ...interface{}) (models.GetEventsByTransactionResponse, error)
}
type suiReadEventFromSuiImpl struct {
conn *httpconn.HttpConn
}
//GetEventsByEventType
func (s *suiReadEventFromSuiImpl) GetEventsByEventType(ctx context.Context, req models.GetEventsByEventTypeRequest, opts ...interface{}) (models.GetEventsByEventTypeResponse, error) {
var rsp models.GetEventsByEventTypeResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getEventsByEventType",
Params: []interface{}{
req.EventType,
req.Count,
req.StartTime,
req.EndTime,
},
})
if err != nil {
return models.GetEventsByEventTypeResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetEventsByEventTypeResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetEventsByEventTypeResponse{}, err
}
return rsp, nil
}
func (s *suiReadEventFromSuiImpl) GetEventsByModule(ctx context.Context, req models.GetEventsByModuleRequest, opts ...interface{}) (models.GetEventsByModuleResponse, error) {
var rsp models.GetEventsByModuleResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getEventsByModule",
Params: []interface{}{
req.Package,
req.Module,
req.Count,
req.StartTime,
req.EndTime,
},
})
if err != nil {
return models.GetEventsByModuleResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetEventsByModuleResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetEventsByModuleResponse{}, err
}
return rsp, nil
}
func (s *suiReadEventFromSuiImpl) GetEventsByObject(ctx context.Context, req models.GetEventsByObjectRequest, opts ...interface{}) (models.GetEventsByObjectResponse, error) {
var rsp models.GetEventsByObjectResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getEventsByObject",
Params: []interface{}{
req.Object,
req.Count,
req.StartTime,
req.EndTime,
},
})
if err != nil {
return models.GetEventsByObjectResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetEventsByObjectResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetEventsByObjectResponse{}, err
}
return rsp, nil
}
func (s *suiReadEventFromSuiImpl) GetEventsByOwner(ctx context.Context, req models.GetEventsByOwnerRequest, opts ...interface{}) (models.GetEventsByOwnerResponse, error) {
var rsp models.GetEventsByOwnerResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getEventsByOwner",
Params: []interface{}{
req.Owner,
req.Count,
req.StartTime,
req.EndTime,
},
})
if err != nil {
return models.GetEventsByOwnerResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetEventsByOwnerResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetEventsByOwnerResponse{}, err
}
return rsp, nil
}
func (s *suiReadEventFromSuiImpl) GetEventsBySender(ctx context.Context, req models.GetEventsBySenderRequest, opts ...interface{}) (models.GetEventsBySenderResponse, error) {
var rsp models.GetEventsBySenderResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getEventsBySender",
Params: []interface{}{
req.Sender,
req.Count,
req.StartTime,
req.EndTime,
},
})
if err != nil {
return models.GetEventsBySenderResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetEventsBySenderResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetEventsBySenderResponse{}, err
}
return rsp, nil
}
func (s *suiReadEventFromSuiImpl) GetEventsByTransaction(ctx context.Context, req models.GetEventsByTransactionRequest, opts ...interface{}) (models.GetEventsByTransactionResponse, error) {
var rsp models.GetEventsByTransactionResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getEventsByTransaction",
Params: []interface{}{
req.Digest,
},
})
if err != nil {
return models.GetEventsByTransactionResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetEventsByTransactionResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetEventsByTransactionResponse{}, err
}
return rsp, nil
}

134
sui/read_move_api.go Normal file
View File

@@ -0,0 +1,134 @@
package sui
import (
"context"
"encoding/json"
"github.com/block-vision/sui-go-sdk/httpconn"
"github.com/block-vision/sui-go-sdk/models"
"github.com/block-vision/sui-go-sdk/sui_error"
"github.com/tidwall/gjson"
)
type IReadMoveFromSuiAPI interface {
GetMoveFunctionArgTypes(ctx context.Context, req models.GetMoveFunctionArgTypesRequest, opts ...interface{}) (models.GetMoveFunctionArgTypesResponse, error)
GetNormalizedMoveModulesByPackage(ctx context.Context, req models.GetNormalizedMoveModulesByPackageRequest, opts ...interface{}) (models.GetNormalizedMoveModulesByPackageResponse, error)
GetNormalizedMoveModule(ctx context.Context, req models.GetNormalizedMoveModuleRequest, opts ...interface{}) (models.GetNormalizedMoveModuleResponse, error)
GetNormalizedMoveStruct(ctx context.Context, req models.GetNormalizedMoveStructRequest, opts ...interface{}) (models.GetNormalizedMoveStructResponse, error)
GetNormalizedMoveFunction(ctx context.Context, req models.GetNormalizedMoveFunctionRequest, opts ...interface{}) (models.GetNormalizedMoveFunctionResponse, error)
}
type suiReadMoveFromSuiImpl struct {
conn *httpconn.HttpConn
}
func (s *suiReadMoveFromSuiImpl) GetMoveFunctionArgTypes(ctx context.Context, req models.GetMoveFunctionArgTypesRequest, opts ...interface{}) (models.GetMoveFunctionArgTypesResponse, error) {
var rsp models.GetMoveFunctionArgTypesResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getMoveFunctionArgTypes",
Params: []interface{}{
req.Package,
req.Module,
req.Function,
},
})
if err != nil {
return models.GetMoveFunctionArgTypesResponse{}, nil
}
if !gjson.ValidBytes(respBytes) {
return models.GetMoveFunctionArgTypesResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetMoveFunctionArgTypesResponse{}, err
}
return rsp, nil
}
func (s *suiReadMoveFromSuiImpl) GetNormalizedMoveModulesByPackage(ctx context.Context, req models.GetNormalizedMoveModulesByPackageRequest, opts ...interface{}) (models.GetNormalizedMoveModulesByPackageResponse, error) {
var rsp models.GetNormalizedMoveModulesByPackageResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getNormalizedMoveModulesByPackage",
Params: []interface{}{
req.Package,
},
})
if err != nil {
return models.GetNormalizedMoveModulesByPackageResponse{}, nil
}
if !gjson.ValidBytes(respBytes) {
return models.GetNormalizedMoveModulesByPackageResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetNormalizedMoveModulesByPackageResponse{}, err
}
return rsp, nil
}
func (s *suiReadMoveFromSuiImpl) GetNormalizedMoveModule(ctx context.Context, req models.GetNormalizedMoveModuleRequest, opts ...interface{}) (models.GetNormalizedMoveModuleResponse, error) {
var rsp models.GetNormalizedMoveModuleResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getNormalizedMoveModule",
Params: []interface{}{
req.Package,
req.ModuleName,
},
})
if err != nil {
return models.GetNormalizedMoveModuleResponse{}, nil
}
if !gjson.ValidBytes(respBytes) {
return models.GetNormalizedMoveModuleResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetNormalizedMoveModuleResponse{}, err
}
return rsp, nil
}
func (s *suiReadMoveFromSuiImpl) GetNormalizedMoveStruct(ctx context.Context, req models.GetNormalizedMoveStructRequest, opts ...interface{}) (models.GetNormalizedMoveStructResponse, error) {
var rsp models.GetNormalizedMoveStructResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getNormalizedMoveStruct",
Params: []interface{}{
req.Package,
req.ModuleName,
req.StructName,
},
})
if err != nil {
return models.GetNormalizedMoveStructResponse{}, nil
}
if !gjson.ValidBytes(respBytes) {
return models.GetNormalizedMoveStructResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetNormalizedMoveStructResponse{}, err
}
return rsp, nil
}
func (s *suiReadMoveFromSuiImpl) GetNormalizedMoveFunction(ctx context.Context, req models.GetNormalizedMoveFunctionRequest, opts ...interface{}) (models.GetNormalizedMoveFunctionResponse, error) {
var rsp models.GetNormalizedMoveFunctionResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getNormalizedMoveFunction",
Params: []interface{}{
req.Package,
req.ModuleName,
req.FunctionName,
},
})
if err != nil {
return models.GetNormalizedMoveFunctionResponse{}, nil
}
if !gjson.ValidBytes(respBytes) {
return models.GetNormalizedMoveFunctionResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetNormalizedMoveFunctionResponse{}, err
}
return rsp, nil
}

105
sui/read_obj_api.go Normal file
View File

@@ -0,0 +1,105 @@
package sui
import (
"context"
"encoding/json"
"github.com/block-vision/sui-go-sdk/httpconn"
"github.com/block-vision/sui-go-sdk/models"
"github.com/block-vision/sui-go-sdk/sui_error"
"github.com/tidwall/gjson"
)
type IReadObjectFromSuiAPI interface {
GetObject(ctx context.Context, req models.GetObjectRequest, opts ...interface{}) (models.GetObjectResponse, error)
GetObjectsOwnedByAddress(ctx context.Context, req models.GetObjectsOwnedByAddressRequest, opts ...interface{}) (models.GetObjectsOwnedByAddressResponse, error)
GetObjectsOwnedByObject(ctx context.Context, req models.GetObjectsOwnedByObjectRequest, opts ...interface{}) (models.GetObjectsOwnedByObjectResponse, error)
GetRawObject(ctx context.Context, req models.GetRawObjectRequest, opts ...interface{}) (models.GetRawObjectResponse, error)
}
type suiReadObjectFromSuiImpl struct {
conn *httpconn.HttpConn
}
func (s *suiReadObjectFromSuiImpl) GetObject(ctx context.Context, req models.GetObjectRequest, opts ...interface{}) (models.GetObjectResponse, error) {
var rsp models.GetObjectResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getObject",
Params: []interface{}{
req.ObjectID,
},
})
if err != nil {
return models.GetObjectResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetObjectResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.GetObjectResponse{}, err
}
return rsp, nil
}
func (s *suiReadObjectFromSuiImpl) GetObjectsOwnedByAddress(ctx context.Context, req models.GetObjectsOwnedByAddressRequest, opts ...interface{}) (models.GetObjectsOwnedByAddressResponse, error) {
var rsp models.GetObjectsOwnedByAddressResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getObjectsOwnedByAddress",
Params: []interface{}{
req.Address,
},
})
if err != nil {
return models.GetObjectsOwnedByAddressResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetObjectsOwnedByAddressResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetObjectsOwnedByAddressResponse{}, err
}
return rsp, nil
}
func (s *suiReadObjectFromSuiImpl) GetObjectsOwnedByObject(ctx context.Context, req models.GetObjectsOwnedByObjectRequest, opts ...interface{}) (models.GetObjectsOwnedByObjectResponse, error) {
var rsp models.GetObjectsOwnedByObjectResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getObjectsOwnedByObject",
Params: []interface{}{
req.ObjectID,
},
})
if err != nil {
return models.GetObjectsOwnedByObjectResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetObjectsOwnedByObjectResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp.Result)
if err != nil {
return models.GetObjectsOwnedByObjectResponse{}, err
}
return rsp, nil
}
func (s *suiReadObjectFromSuiImpl) GetRawObject(ctx context.Context, req models.GetRawObjectRequest, opts ...interface{}) (models.GetRawObjectResponse, error) {
var rsp models.GetRawObjectResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getRawObject",
Params: []interface{}{
req.ObjectID,
},
})
if err != nil {
return models.GetRawObjectResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetRawObjectResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.GetRawObjectResponse{}, err
}
return rsp, nil
}

250
sui/read_transaction_api.go Normal file
View File

@@ -0,0 +1,250 @@
package sui
import (
"context"
"encoding/json"
"github.com/block-vision/sui-go-sdk/httpconn"
"github.com/block-vision/sui-go-sdk/models"
"github.com/block-vision/sui-go-sdk/sui_error"
"github.com/tidwall/gjson"
)
type IReadTransactionFromSuiAPI interface {
GetRecentTransactions(ctx context.Context, req models.GetRecentTransactionRequest, opts ...interface{}) (models.GetRecentTransactionResponse, error)
GetTotalTransactionNumber(ctx context.Context, req models.GetTotalTransactionNumberRequest, opts ...interface{}) (models.GetTotalTransactionNumberResponse, error)
GetTransaction(ctx context.Context, req models.GetTransactionRequest, opts ...interface{}) (models.GetTransactionResponse, error)
GetTransactionsByInputObject(ctx context.Context, req models.GetTransactionsByInputObjectRequest, opts ...interface{}) (models.GetTransactionsByInputObjectResponse, error)
GetTransactionsByMoveFunction(ctx context.Context, req models.GetTransactionsByMoveFunctionRequest, opts ...interface{}) (models.GetTransactionsByMoveFunctionResponse, error)
GetTransactionsByMutatedObject(ctx context.Context, req models.GetTransactionsByMutatedObjectRequest, opts ...interface{}) (models.GetTransactionsByMutatedObjectResponse, error)
GetTransactionsFromAddress(ctx context.Context, req models.GetTransactionsFromAddressRequest, opts ...interface{}) (models.GetTransactionsFromAddressResponse, error)
GetTransactionsInRange(ctx context.Context, req models.GetTransactionsInRangeRequest, opts ...interface{}) (models.GetTransactionsInRangeResponse, error)
GetTransactionsToAddress(ctx context.Context, req models.GetTransactionsToAddressRequest, opts ...interface{}) (models.GetTransactionsToAddressResponse, error)
}
type suiReadTransactionFromSuiImpl struct {
conn *httpconn.HttpConn
}
func (s *suiReadTransactionFromSuiImpl) GetRecentTransactions(ctx context.Context, req models.GetRecentTransactionRequest, opts ...interface{}) (models.GetRecentTransactionResponse, error) {
var rsp models.GetRecentTransactionResponse
reqList := make([]interface{}, 0)
reqList = append(reqList, req.Count)
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getRecentTransactions",
Params: reqList,
})
if err != nil {
return models.GetRecentTransactionResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetRecentTransactionResponse{}, sui_error.ErrInvalidJson
}
results := gjson.ParseBytes(respBytes).Get("result").Array()
for i := range results {
if len(results[i].Array()) < 2 {
continue
}
rsp.Result = append(rsp.Result, models.GetTransactionMetaData{
GatewayTxSeqNumber: results[i].Array()[0].Uint(),
TransactionDigest: results[i].Array()[1].String(),
})
}
return rsp, nil
}
func (s *suiReadTransactionFromSuiImpl) GetTotalTransactionNumber(ctx context.Context, req models.GetTotalTransactionNumberRequest, opts ...interface{}) (models.GetTotalTransactionNumberResponse, error) {
var rsp models.GetTotalTransactionNumberResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getTotalTransactionNumber",
Params: []interface{}{},
})
if err != nil {
return models.GetTotalTransactionNumberResponse{}, err
}
rsp.TotalNumberOfTransaction = gjson.ParseBytes(respBytes).Get("result").Uint()
return rsp, nil
}
func (s *suiReadTransactionFromSuiImpl) GetTransaction(ctx context.Context, req models.GetTransactionRequest, opts ...interface{}) (models.GetTransactionResponse, error) {
var rsp models.GetTransactionResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getTransaction",
Params: []interface{}{
req.Digest,
},
})
if err != nil {
return models.GetTransactionResponse{}, err
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").Raw), &rsp)
if err != nil {
return models.GetTransactionResponse{}, err
}
return rsp, nil
}
func (s *suiReadTransactionFromSuiImpl) GetTransactionsByInputObject(ctx context.Context, req models.GetTransactionsByInputObjectRequest, opts ...interface{}) (models.GetTransactionsByInputObjectResponse, error) {
var rsp models.GetTransactionsByInputObjectResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getTransactionsByInputObject",
Params: []interface{}{
req.ObjectID,
},
})
if err != nil {
return models.GetTransactionsByInputObjectResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetTransactionsByInputObjectResponse{}, sui_error.ErrInvalidJson
}
results := gjson.ParseBytes(respBytes).Get("result").Array()
for i := range results {
if len(results[i].Array()) < 2 {
continue
}
rsp.Result = append(rsp.Result, models.GetTransactionMetaData{
GatewayTxSeqNumber: results[i].Array()[0].Uint(),
TransactionDigest: results[i].Array()[1].String(),
})
}
return rsp, nil
}
func (s *suiReadTransactionFromSuiImpl) GetTransactionsByMoveFunction(ctx context.Context, req models.GetTransactionsByMoveFunctionRequest, opts ...interface{}) (models.GetTransactionsByMoveFunctionResponse, error) {
var rsp models.GetTransactionsByMoveFunctionResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getTransactionsByInputObject",
Params: []interface{}{
req.Package,
req.Module,
req.Function,
},
})
if err != nil {
return models.GetTransactionsByMoveFunctionResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetTransactionsByMoveFunctionResponse{}, sui_error.ErrInvalidJson
}
results := gjson.ParseBytes(respBytes).Get("result").Array()
for i := range results {
if len(results[i].Array()) < 2 {
continue
}
rsp.Result = append(rsp.Result, models.GetTransactionMetaData{
GatewayTxSeqNumber: results[i].Array()[0].Uint(),
TransactionDigest: results[i].Array()[1].String(),
})
}
return rsp, nil
}
func (s *suiReadTransactionFromSuiImpl) GetTransactionsByMutatedObject(ctx context.Context, req models.GetTransactionsByMutatedObjectRequest, opts ...interface{}) (models.GetTransactionsByMutatedObjectResponse, error) {
var rsp models.GetTransactionsByMutatedObjectResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getTransactionsByMutatedObject",
Params: []interface{}{
req.ObjectID,
},
})
if err != nil {
return models.GetTransactionsByMutatedObjectResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetTransactionsByMutatedObjectResponse{}, sui_error.ErrInvalidJson
}
results := gjson.ParseBytes(respBytes).Get("result").Array()
for i := range results {
if len(results[i].Array()) < 2 {
continue
}
rsp.Result = append(rsp.Result, models.GetTransactionMetaData{
GatewayTxSeqNumber: results[i].Array()[0].Uint(),
TransactionDigest: results[i].Array()[1].String(),
})
}
return rsp, nil
}
func (s *suiReadTransactionFromSuiImpl) GetTransactionsFromAddress(ctx context.Context, req models.GetTransactionsFromAddressRequest, opts ...interface{}) (models.GetTransactionsFromAddressResponse, error) {
var rsp models.GetTransactionsFromAddressResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getTransactionsFromAddress",
Params: []interface{}{
req.Addr,
},
})
if err != nil {
return models.GetTransactionsFromAddressResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetTransactionsFromAddressResponse{}, sui_error.ErrInvalidJson
}
results := gjson.ParseBytes(respBytes).Get("result").Array()
for i := range results {
if len(results[i].Array()) < 2 {
continue
}
rsp.Result = append(rsp.Result, models.GetTransactionMetaData{
GatewayTxSeqNumber: results[i].Array()[0].Uint(),
TransactionDigest: results[i].Array()[1].String(),
})
}
return rsp, nil
}
func (s *suiReadTransactionFromSuiImpl) GetTransactionsInRange(ctx context.Context, req models.GetTransactionsInRangeRequest, opts ...interface{}) (models.GetTransactionsInRangeResponse, error) {
var rsp models.GetTransactionsInRangeResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getTransactionsInRange",
Params: []interface{}{
req.Start,
req.End,
},
})
if err != nil {
return models.GetTransactionsInRangeResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetTransactionsInRangeResponse{}, sui_error.ErrInvalidJson
}
results := gjson.ParseBytes(respBytes).Get("result").Array()
for i := range results {
if len(results[i].Array()) < 2 {
continue
}
rsp.Result = append(rsp.Result, models.GetTransactionMetaData{
GatewayTxSeqNumber: results[i].Array()[0].Uint(),
TransactionDigest: results[i].Array()[1].String(),
})
}
return rsp, nil
}
func (s *suiReadTransactionFromSuiImpl) GetTransactionsToAddress(ctx context.Context, req models.GetTransactionsToAddressRequest, opts ...interface{}) (models.GetTransactionsToAddressResponse, error) {
var rsp models.GetTransactionsToAddressResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_getTransactionsToAddress",
Params: []interface{}{
req.Addr,
},
})
if err != nil {
return models.GetTransactionsToAddressResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.GetTransactionsToAddressResponse{}, sui_error.ErrInvalidJson
}
results := gjson.ParseBytes(respBytes).Get("result").Array()
for i := range results {
if len(results[i].Array()) < 2 {
continue
}
rsp.Result = append(rsp.Result, models.GetTransactionMetaData{
GatewayTxSeqNumber: results[i].Array()[0].Uint(),
TransactionDigest: results[i].Array()[1].String(),
})
}
return rsp, nil
}

520
sui/sui_test.go Normal file
View File

@@ -0,0 +1,520 @@
package sui
import (
"context"
"fmt"
"github.com/block-vision/sui-go-sdk/models"
"gotest.tools/assert"
"testing"
)
var cli = NewSuiClient("https://gateway.devnet.sui.io:443")
var ctx = context.Background()
func TestOnGetTransactionFromSui(t *testing.T) {
t.Run("test on sui_call", func(t *testing.T) {
resp, err := cli.SuiCall(ctx, "sui_getTransactionsByInputObject", []interface{}{
"0xaea08f870ce66d89bc4e1cd1d27445c575195c2c",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getRecentTransaction", func(t *testing.T) {
resp, err := cli.GetRecentTransactions(ctx, models.GetRecentTransactionRequest{
Count: 5,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getTotalTransactionNumber", func(t *testing.T) {
resp, err := cli.GetTotalTransactionNumber(ctx, models.GetTotalTransactionNumberRequest{})
if err != nil {
fmt.Println()
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getTransaction", func(t *testing.T) {
resp, err := cli.GetTransaction(ctx, models.GetTransactionRequest{Digest: "dhdxO9moFHP+JI+UnT/RNylhzOXtDT0jjITApWEDVIg="})
if err != nil {
fmt.Println(err)
t.FailNow()
}
fmt.Printf("%+v", resp)
})
t.Run("test on sui_getTransactionByInputObject", func(t *testing.T) {
resp, err := cli.GetTransactionsByInputObject(ctx, models.GetTransactionsByInputObjectRequest{
ObjectID: "0x39377e86154771712b3b8377dafeb0d4e5a0bd96",
})
if err != nil {
fmt.Println(err)
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getTransactionsByMoveFunction", func(t *testing.T) {
resp, err := cli.GetTransactionsByMoveFunction(ctx, models.GetTransactionsByMoveFunctionRequest{
Package: "0x0000000000000000000000000000000000000002",
Module: "devnet_nft",
Function: "mint",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getTransactionsByMutatedObject", func(t *testing.T) {
resp, err := cli.GetTransactionsByMutatedObject(ctx, models.GetTransactionsByMutatedObjectRequest{
ObjectID: "0x9fc486e101f0e9e2703ac8666d06aecc4ddf7e79",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getTransactionsFromAddress", func(t *testing.T) {
resp, err := cli.GetTransactionsFromAddress(ctx, models.GetTransactionsFromAddressRequest{
Addr: "0x6ce471116a8b96f81c47414bae8375c42c23e0fc",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getTransactionsInRange", func(t *testing.T) {
resp, err := cli.GetTransactionsInRange(ctx, models.GetTransactionsInRangeRequest{
Start: 5,
End: 8,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getTransactionsToAddress", func(t *testing.T) {
resp, err := cli.GetTransactionsToAddress(ctx, models.GetTransactionsToAddressRequest{Addr: "0xb6eb9669d0c206d28ed50358dfd45c7f5f8d2669"})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
}
func TestOnReadObjectFromSui(t *testing.T) {
t.Run("test on sui_getObject", func(t *testing.T) {
resp, err := cli.GetObject(ctx, models.GetObjectRequest{ObjectID: "0x869afb00e643e1f09af0e12d4732ccd71dfca6e2"})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
//TODO Mark different results
resp2, err := cli.SuiCall(ctx, "sui_getObject", []interface{}{
"0x869afb00e643e1f09af0e12d4732ccd71dfca6e2",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp2)
})
t.Run("test on sui_getObjectOwnedByAddress", func(t *testing.T) {
resp, err := cli.GetObjectsOwnedByAddress(ctx, models.GetObjectsOwnedByAddressRequest{
Address: "0x425c9e7182bff2b2aea5d31ffc1043e73c9a999d",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getObjectsOwnedByObject", func(t *testing.T) {
resp, err := cli.GetObjectsOwnedByObject(ctx, models.GetObjectsOwnedByObjectRequest{
ObjectID: "0x67b855b694a6a69ae248876e885bb38174b50cf3",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getRawObject", func(t *testing.T) {
resp, err := cli.GetRawObject(ctx, models.GetRawObjectRequest{
ObjectID: "0x67b855b694a6a69ae248876e885bb38174b50cf3",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp.Details.Data.BcsBytes)
})
}
func TestOnReadEventFromSui(t *testing.T) {
t.Run("test on sui_getEventsByEventType", func(t *testing.T) {
resp, err := cli.GetEventsByEventType(ctx, models.GetEventsByEventTypeRequest{
EventType: "0x2::devnet_nft::MintNFTEvent",
Count: 10,
StartTime: 0,
EndTime: 0,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getEventsByModule", func(t *testing.T) {
resp, err := cli.GetEventsByModule(ctx, models.GetEventsByModuleRequest{
Package: "",
Module: "",
Count: 0,
StartTime: 0,
EndTime: 0,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getEventsByObject", func(t *testing.T) {
resp, err := cli.GetEventsByObject(ctx, models.GetEventsByObjectRequest{
Object: "",
Count: 0,
StartTime: 0,
EndTime: 0,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getEventsByOwner", func(t *testing.T) {
resp, err := cli.GetEventsByOwner(ctx, models.GetEventsByOwnerRequest{
Owner: "",
Count: 0,
StartTime: 0,
EndTime: 0,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getEventsBySender", func(t *testing.T) {
resp, err := cli.GetEventsBySender(ctx, models.GetEventsBySenderRequest{
Sender: "",
Count: 0,
StartTime: 0,
EndTime: 0,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_getEventsByTransaction", func(t *testing.T) {
resp, err := cli.GetEventsByTransaction(ctx, models.GetEventsByTransactionRequest{
Digest: "",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
}
//func TestOnReadMoveDataFromSui(t *testing.T) {
// t.Run("test on sui_getMoveFunctionArgTypes", func(t *testing.T) {
// resp, err := cli.GetMoveFunctionArgTypes(ctx, models.GetMoveFunctionArgTypesRequest{
// Package: "0x2",
// Module: "devnet",
// Function: "",
// })
//
// if err != nil {
// fmt.Println(err.Error())
// t.FailNow()
// }
// fmt.Println(resp)
// })
//
// t.Run("test on sui_getNormalizedMoveModulesByPackage", func(t *testing.T) {
// resp, err := cli.GetNormalizedMoveModulesByPackage(ctx, models.GetNormalizedMoveModulesByPackageRequest{
// Package: "",
// })
// if err != nil {
// fmt.Println(err.Error())
// t.FailNow()
// }
// fmt.Println(resp)
// })
//
// t.Run("test on sui_getNormalizedMoveModule", func(t *testing.T) {
// resp, err := cli.GetNormalizedMoveModule(ctx, models.GetNormalizedMoveModuleRequest{
// Package: "",
// ModuleName: "",
// })
// if err != nil {
// fmt.Println(err.Error())
// t.FailNow()
// }
// fmt.Println(resp)
// })
//
// t.Run("test on sui_getNormalizedMoveStruct", func(t *testing.T) {
// resp, err := cli.GetNormalizedMoveStruct(ctx, models.GetNormalizedMoveStructRequest{
// Package: "",
// ModuleName: "",
// StructName: "",
// })
// if err != nil {
// fmt.Println(err.Error())
// t.FailNow()
// }
// fmt.Println(resp)
// })
//
// t.Run("test on sui_getNormalizedMoveFunction", func(t *testing.T) {
// resp, err := cli.GetNormalizedMoveFunction(ctx, models.GetNormalizedMoveFunctionRequest{
// Package: "",
// ModuleName: "",
// FunctionName: "",
// })
// if err != nil {
// fmt.Println(err.Error())
// t.FailNow()
// }
// fmt.Println(resp)
// })
//
//}
func TestOnWriteTransactionToSui(t *testing.T) {
t.Run("test on sui_moveCall", func(t *testing.T) {
resp, err := cli.MoveCall(ctx, models.MoveCallRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
PackageObjectId: "0x0000000000000000000000000000000000000002",
Module: "devnet_nft",
Function: "mint",
TypeArguments: []interface{}{},
Arguments: []interface{}{"blockvision", "blockvision", "testurl"},
Gas: "0xd88db3b517b218503ed90df77f25dec257918903",
GasBudget: 1000,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp.TxBytes)
})
t.Run("test on sui_mergeCoins", func(t *testing.T) {
resp, err := cli.MergeCoins(ctx, models.MergeCoinsRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
PrimaryCoin: "0x0407064f11682317c1e0220ce1f5b23246c91d23",
CoinToMerge: "0x35a8b00aa176337db1dfa9d5681ce18e45183058",
Gas: "0xd88db3b517b218503ed90df77f25dec257918903",
GasBudget: 1000,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_publish", func(t *testing.T) {
resp, err := cli.Publish(ctx, models.PublishRequest{
Sender: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
CompiledModules: []string{
"oRzrCwUAAAALAQAOAg4kAzJZBIsBFgWhAZoBB7sC5wEIogQoBsoECgrUBBoM7gSjAQ2RBgQAAAEBAQIBAwEEAQUBBgAHCAAACAgAAAkIAAIKDAEAAQQLAgAGDAIAAxIEAAEUBAEAAQANAAEAAA4CAQAADwMBAAAQBAEAAhUHCAEAAhYJCgEAARcLDAEAARgNCAEAAxkEDgAGGg8QAAUFEQEBCAEVEwgBAAIbFBUBAAMcDgEAAR0BDAEABR4ZAQEIBAYFBgYGBwYKAwsGDAYKFgoXDgYPGAMHCAEHCwMBCAQHCAUAAwYIAgcIAQcIBQEIAAEHCAUCBwsHAQgECwcBCAQBCAQBBgsDAQkAAQMBBwsDAQkAAQcLBwEJAAIHCwcBCQADAQsHAQkAAgcLBwEJAAsHAQkAAQgGAQYIBQEFAgkABQIDCwMBCAQBBgsHAQkAAwcLBwEJAAMHCAUBCwMBCQABCwMBCAQBCAIBCAEBCQAGZG9udXRzB2JhbGFuY2UEY29pbgZvYmplY3QDc3VpCHRyYW5zZmVyCnR4X2NvbnRleHQFRG9udXQJRG9udXRTaG9wDFNob3BPd25lckNhcARDb2luA1NVSQlUeENvbnRleHQJYnV5X2RvbnV0D2NvbGxlY3RfcHJvZml0cwllYXRfZG9udXQEaW5pdAJpZANVSUQFcHJpY2UHQmFsYW5jZQV2YWx1ZQtiYWxhbmNlX211dAVzcGxpdARqb2luA25ldwZzZW5kZXIEdGFrZQZkZWxldGUEemVybwxzaGFyZV9vYmplY3QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAwgAAAAAAAAAAAACAREIBgECAxEIBhMDAQsHAQgEAgIBEQgGAAEEAAUmCgEuOAAKABAAFCYDEAsAAQsBAQsCAQcAJwsBOAEMAwsDCgAQABQ4AgwECwAPAQsEOAMBCgIRCBIACwIuEQk4BAIBAQQAEhAKARABOAUMAwsBDwELAwoCOAYMBAsECwIuEQk4BwICAQQADgYLABMADAELARENAgMAAAABDgoAEQgSAgoALhEJOAgLABEIBugDAAAAAAAAOAkSATgKAgEBAQIA",
},
Gas: "0xd88db3b517b218503ed90df77f25dec257918903",
GasBudget: 1000,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_splitCoin", func(t *testing.T) {
resp, err := cli.SplitCoin(ctx, models.SplitCoinRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
CoinObjectId: "0x0407064f11682317c1e0220ce1f5b23246c91d23",
SplitAmounts: []uint64{1000, 1000},
Gas: "0xd88db3b517b218503ed90df77f25dec257918903",
GasBudget: 1000,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_splitCoinEqual", func(t *testing.T) {
resp, err := cli.SplitCoinEqual(ctx, models.SplitCoinEqualRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
CoinObjectId: "0x0407064f11682317c1e0220ce1f5b23246c91d23",
SplitCount: 2,
Gas: "0xd88db3b517b218503ed90df77f25dec257918903",
GasBudget: 1000,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_transferObject", func(t *testing.T) {
resp, err := cli.TransferObject(ctx, models.TransferObjectRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
ObjectId: "0xf8da4c3c9d1477e8d2e005ac4d390032b5f81977",
Gas: "0xd88db3b517b218503ed90df77f25dec257918903",
GasBudget: 1000,
Recipient: "0xb6eb9669d0c206d28ed50358dfd45c7f5f8d2669",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_transferSui", func(t *testing.T) {
resp, err := cli.TransferSui(ctx, models.TransferSuiRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
SuiObjectId: "0xf8da4c3c9d1477e8d2e005ac4d390032b5f81977",
GasBudget: 1000,
Recipient: "0xb6eb9669d0c206d28ed50358dfd45c7f5f8d2669",
Amount: 1,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_batchTransaction", func(t *testing.T) {
resp, err := cli.BatchTransaction(ctx, models.BatchTransactionRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
SingleTransactionParams: []models.SingleTransactionParams{
{
MoveCallRequestParams: &models.MoveCallRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
PackageObjectId: "0x0000000000000000000000000000000000000002",
Module: "devnet_nft",
Function: "mint",
TypeArguments: []interface{}{},
Arguments: []interface{}{"blockvision", "blockvision", "testurl"},
Gas: "0x0407064f11682317c1e0220ce1f5b23246c91d23",
GasBudget: 1000,
},
},
{
TransferObjectRequestParams: &models.TransferObjectRequest{
Signer: "0x0f1584ebdf54c91b8572793b2a79e085514ea6c7",
ObjectId: "0xf8da4c3c9d1477e8d2e005ac4d390032b5f81977",
Gas: "0x0407064f11682317c1e0220ce1f5b23246c91d23",
GasBudget: 1000,
Recipient: "0xb6eb9669d0c206d28ed50358dfd45c7f5f8d2669",
},
},
},
Gas: "0x0407064f11682317c1e0220ce1f5b23246c91d23",
GasBudget: 1000,
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
t.Run("test on sui_executeTransaction", func(t *testing.T) {
resp, err := cli.ExecuteTransaction(ctx, models.ExecuteTransactionRequest{
TxBytes: "VHJhbnNhY3Rpb25EYXRhOjoAAgAAAAAAAAAAAAAAAAAAAAAAAAACAQAAAAAAAAAgf4wCMzbSQGAtJy5c2FShsm5eDefCLIODnSU2sC07IXMKZGV2bmV0X25mdARtaW50AAMADAtibG9ja3Zpc2lvbgAMC2Jsb2NrdmlzaW9uAAgHdGVzdHVybAgHEPIa1agDuTeHZVW0qooyQdm42I2ztReyGFA+2Q33fyXewleRiQMDAAAAAAAAACDURxg9juaOxAd9LLAJYPApQ2HE2zvHWehpj/PrXIge0QEAAAAAAAAA6AMAAAAAAAA=",
SigScheme: "ED25519",
Signature: "d3fLEw4f6JB+4NbRmr+Wh5EeyL5xGLnTYLt6a5Wtsh5Kf7ADx7V1WyWaqDehnulrrR4WS+ybSOkGRiRv7mfnCw==",
PubKey: "kslpD84v6KJ8G3J+iiHH+s7bDoHhucTIUAg+Um5sfAo=",
})
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
fmt.Println(resp)
})
}
func TestOnFeatureAPI(t *testing.T) {
kps, err := SetAccountKeyStore("../config/sui.keystorefortest")
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
actualKeys := kps.Keys()
assert.Equal(t, "0x72cffd05deb71fa9b30584cb0f512d680cb08eab", actualKeys[0])
assert.Equal(t, "0x8f3cf7d8ebb187bd655cea775802d0d9c1c5b145", actualKeys[1])
assert.Equal(t, "0xc697e5fdd38d5f63ebeb14c2b49a864d473849db", actualKeys[2])
assert.Equal(t, "0xf354bb3497c5879d68b49582d3a8887dbd26e3f0", actualKeys[3])
assert.Equal(t, "0xfde3698d3e7da3f359e1036078da9cfbfb31f203", actualKeys[4])
t.Run("test on feature API MoveCallAndExecuteTransaction", func(t *testing.T) {
})
t.Run("test on feature API BatchAndExecuteTransaction", func(t *testing.T) {
})
}

View File

@@ -0,0 +1,251 @@
package sui
import (
"context"
"encoding/json"
"github.com/block-vision/sui-go-sdk/httpconn"
"github.com/block-vision/sui-go-sdk/models"
"github.com/block-vision/sui-go-sdk/sui_error"
"github.com/tidwall/gjson"
)
type IWriteTransactionAPI interface {
MoveCall(ctx context.Context, req models.MoveCallRequest, opts ...interface{}) (models.MoveCallResponse, error)
MergeCoins(ctx context.Context, req models.MergeCoinsRequest, opts ...interface{}) (models.MergeCoinsResponse, error)
SplitCoin(ctx context.Context, req models.SplitCoinRequest, opts ...interface{}) (models.SplitCoinResponse, error)
SplitCoinEqual(ctx context.Context, req models.SplitCoinEqualRequest, opt ...interface{}) (models.SplitCoinEqualResponse, error)
Publish(ctx context.Context, req models.PublishRequest, opts ...interface{}) (models.PublishResponse, error)
TransferObject(ctx context.Context, req models.TransferObjectRequest, opts ...interface{}) (models.TransferObjectResponse, error)
TransferSui(ctx context.Context, req models.TransferSuiRequest, opts ...interface{}) (models.TransferSuiResponse, error)
BatchTransaction(ctx context.Context, req models.BatchTransactionRequest, opts ...interface{}) (models.BatchTransactionResponse, error)
ExecuteTransaction(ctx context.Context, req models.ExecuteTransactionRequest, opts ...interface{}) (models.ExecuteTransactionResponse, error)
}
type suiWriteTransactionImpl struct {
conn *httpconn.HttpConn
}
func (s *suiWriteTransactionImpl) MoveCall(ctx context.Context, req models.MoveCallRequest, opts ...interface{}) (models.MoveCallResponse, error) {
var rsp models.MoveCallResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_moveCall",
Params: []interface{}{
req.Signer,
req.PackageObjectId,
req.Module,
req.Function,
req.TypeArguments,
req.Arguments,
req.Gas,
req.GasBudget,
},
})
if err != nil {
return models.MoveCallResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.MoveCallResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.MoveCallResponse{}, err
}
return rsp, nil
}
func (s *suiWriteTransactionImpl) MergeCoins(ctx context.Context, req models.MergeCoinsRequest, opts ...interface{}) (models.MergeCoinsResponse, error) {
var rsp models.MergeCoinsResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_mergeCoins",
Params: []interface{}{
req.Signer,
req.PrimaryCoin,
req.CoinToMerge,
req.Gas,
req.GasBudget,
},
})
if err != nil {
return models.MergeCoinsResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.MergeCoinsResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.MergeCoinsResponse{}, err
}
return rsp, nil
}
func (s *suiWriteTransactionImpl) SplitCoin(ctx context.Context, req models.SplitCoinRequest, opts ...interface{}) (models.SplitCoinResponse, error) {
var rsp models.SplitCoinResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_splitCoin",
Params: []interface{}{
req.Signer,
req.CoinObjectId,
req.SplitAmounts,
req.Gas,
req.GasBudget,
},
})
if err != nil {
return models.SplitCoinResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.SplitCoinResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.SplitCoinResponse{}, err
}
return rsp, nil
}
func (s *suiWriteTransactionImpl) SplitCoinEqual(ctx context.Context, req models.SplitCoinEqualRequest, opts ...interface{}) (models.SplitCoinEqualResponse, error) {
var rsp models.SplitCoinEqualResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_splitCoinEqual",
Params: []interface{}{
req.Signer,
req.CoinObjectId,
req.SplitCount,
req.Gas,
req.GasBudget,
},
})
if err != nil {
return models.SplitCoinEqualResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.SplitCoinEqualResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.SplitCoinEqualResponse{}, err
}
return rsp, nil
}
func (s *suiWriteTransactionImpl) Publish(ctx context.Context, req models.PublishRequest, opts ...interface{}) (models.PublishResponse, error) {
var rsp models.PublishResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_publish",
Params: []interface{}{
req.Sender,
req.CompiledModules,
req.Gas,
req.GasBudget,
},
})
if err != nil {
return models.PublishResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.PublishResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.PublishResponse{}, err
}
return rsp, nil
}
func (s *suiWriteTransactionImpl) TransferObject(ctx context.Context, req models.TransferObjectRequest, opts ...interface{}) (models.TransferObjectResponse, error) {
var rsp models.TransferObjectResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_transferObject",
Params: []interface{}{
req.Signer,
req.ObjectId,
req.Gas,
req.GasBudget,
req.Recipient,
},
})
if err != nil {
return models.TransferObjectResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.TransferObjectResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.TransferObjectResponse{}, err
}
return rsp, nil
}
func (s *suiWriteTransactionImpl) TransferSui(ctx context.Context, req models.TransferSuiRequest, opts ...interface{}) (models.TransferSuiResponse, error) {
var rsp models.TransferSuiResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_transferSui",
Params: []interface{}{
req.Signer,
req.SuiObjectId,
req.GasBudget,
req.Recipient,
req.Amount,
},
})
if err != nil {
return models.TransferSuiResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.TransferSuiResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.TransferSuiResponse{}, err
}
return rsp, nil
}
func (s *suiWriteTransactionImpl) BatchTransaction(ctx context.Context, req models.BatchTransactionRequest, opts ...interface{}) (models.BatchTransactionResponse, error) {
var rsp models.BatchTransactionResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_batchTransaction",
Params: []interface{}{
req.Signer,
req.SingleTransactionParams,
req.Gas,
req.GasBudget,
},
})
if err != nil {
return models.BatchTransactionResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.BatchTransactionResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.BatchTransactionResponse{}, err
}
return rsp, nil
}
func (s *suiWriteTransactionImpl) ExecuteTransaction(ctx context.Context, req models.ExecuteTransactionRequest, opts ...interface{}) (models.ExecuteTransactionResponse, error) {
var rsp models.ExecuteTransactionResponse
respBytes, err := s.conn.Request(ctx, httpconn.Operation{
Method: "sui_executeTransaction",
Params: []interface{}{
req.TxBytes,
req.SigScheme,
req.Signature,
req.PubKey,
},
})
if err != nil {
return models.ExecuteTransactionResponse{}, err
}
if !gjson.ValidBytes(respBytes) {
return models.ExecuteTransactionResponse{}, sui_error.ErrInvalidJson
}
err = json.Unmarshal([]byte(gjson.ParseBytes(respBytes).Get("result").String()), &rsp)
if err != nil {
return models.ExecuteTransactionResponse{}, err
}
return rsp, nil
}

12
sui_error/sui_error.go Normal file
View File

@@ -0,0 +1,12 @@
package sui_error
import "errors"
var (
ErrInvalidJson = errors.New("invalid json response")
ErrUnknownSignatureScheme = errors.New("unknown scheme sign scheme flag")
ErrInvalidEncryptFlag = errors.New("invalid encrypt flag")
ErrNoKeyStoreInfo = errors.New("no keystore info, make sure already loaded sui.keystore")
ErrAddressNotInKeyStore = errors.New("address not in keystore, make sure already loaded sui.keystore")
ErrInvalidAddress = errors.New("invalid address")
)