├── client ├── rpc │ ├── mock │ │ ├── ops.go │ │ ├── status.go │ │ ├── client.go │ │ └── abci.go │ ├── ops_client.go │ ├── validate.go │ ├── types.go │ └── basic_client.go ├── query │ ├── get_time.go │ ├── get_node_info.go │ ├── query.go │ ├── get_tokens.go │ ├── get_mini_tokens.go │ └── get_account.go ├── transaction │ ├── set_uri.go │ ├── vote_proposal.go │ ├── list_mini_pair.go │ ├── list_pair.go │ ├── mint_token.go │ ├── transfer_token_ownership.go │ ├── burn_token.go │ ├── freeze_token.go │ ├── unfreeze_token.go │ ├── send_token.go │ ├── deposit_proposal.go │ ├── cancel_order.go │ ├── create_order.go │ ├── issue_token.go │ ├── set_account_flags.go │ ├── issue_mini_token.go │ ├── issue_tiny_token.go │ ├── submit_proposal.go │ ├── htlc.go │ ├── time_lock.go │ └── transaction.go ├── client.go └── basic │ └── basic.go ├── e2e ├── readme.md ├── e2e_rpc_side_staking_test.go └── e2e_trans_test.go ├── Makefile ├── common ├── types │ ├── time.go │ ├── coins.go │ ├── scripts.go │ ├── int.go │ ├── timelock.go │ ├── tokens.go │ ├── dec.go │ ├── fixed8.go │ ├── delegation.go │ ├── fees.go │ ├── swap.go │ ├── account.go │ ├── wire.go │ ├── query.go │ ├── oracle.go │ ├── stake.go │ ├── address.go │ ├── proposal.go │ └── nodeinfo.go ├── ledger │ ├── ledger.go │ └── ledger_secp256k1.go ├── common.go └── uuid │ ├── uuid.go │ ├── codec.go │ └── generator.go ├── .gitignore ├── types ├── wire.go ├── config.go ├── tx │ ├── result.go │ ├── stdtx.go │ ├── wire.go │ └── option.go └── msg │ ├── utils.go │ ├── wire.go │ ├── types.go │ └── msg.go ├── keys ├── testkeystore.json ├── keystore.go ├── hdpath.go ├── keys.go └── keys_test.go ├── example └── ledger-keys │ ├── README.md │ └── main.go ├── CHANGELOG.md ├── go.mod ├── ReadMe.md └── LICENSE /client/rpc/mock/ops.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | func (c Client) IsActive() bool { 4 | return true 5 | } 6 | -------------------------------------------------------------------------------- /e2e/readme.md: -------------------------------------------------------------------------------- 1 | This package is for bnbchain go-sdk developer. 2 | If you are just a go-sdk user, you can ignore this package. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_TAGS = ledger 2 | BUILD_FLAGS = -tags "${BUILD_TAGS}" 3 | install: 4 | go install $(BUILD_FLAGS) ./example/ledger-keys 5 | -------------------------------------------------------------------------------- /common/types/time.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Time struct { 4 | ApTime string `json:"ap_time"` 5 | BlockTime string `json:"block_time"` 6 | } 7 | -------------------------------------------------------------------------------- /common/types/coins.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/types" 5 | ) 6 | 7 | type ( 8 | Coin = types.Coin 9 | Coins = types.Coins 10 | ) 11 | -------------------------------------------------------------------------------- /common/types/scripts.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/bnb-chain/node/plugins/account/scripts" 4 | 5 | type FlagOption = uint64 6 | 7 | const ( 8 | TransferMemoCheckerFlag = scripts.TransferMemoCheckerFlag 9 | ) 10 | -------------------------------------------------------------------------------- /common/types/int.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/types" 5 | ) 6 | 7 | type Int = types.Int 8 | 9 | var ( 10 | NewInt = types.NewInt 11 | NewIntFromBigInt = types.NewIntFromBigInt 12 | ) 13 | -------------------------------------------------------------------------------- /common/types/timelock.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/bnb-chain/node/plugins/tokens/timelock" 5 | ) 6 | 7 | type ( 8 | TimeLockRecord = timelock.TimeLockRecord 9 | QueryTimeLocksParams = timelock.QueryTimeLocksParams 10 | QueryTimeLockParams = timelock.QueryTimeLockParams 11 | ) 12 | -------------------------------------------------------------------------------- /common/types/tokens.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | nodeTypes "github.com/bnb-chain/node/common/types" 5 | "github.com/bnb-chain/node/plugins/tokens/client/rest" 6 | ) 7 | 8 | type ( 9 | Token = nodeTypes.Token 10 | MiniToken = nodeTypes.MiniToken 11 | TokenBalance = rest.TokenBalance 12 | ) 13 | -------------------------------------------------------------------------------- /common/types/dec.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/types" 5 | ) 6 | 7 | type Dec = types.Dec 8 | 9 | var ( 10 | NewDecFromStr = types.NewDecFromStr 11 | ZeroDec = types.ZeroDec 12 | OneDec = types.OneDec 13 | NewDecWithPrec = types.NewDecWithPrec 14 | NewDec = types.NewDec 15 | ) 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | vendor 3 | .DS_Store 4 | 5 | # Binaries for programs and plugins 6 | *.exe 7 | *.exe~ 8 | *.dll 9 | *.so 10 | *.dylib 11 | 12 | # Test binary, build with `go test -c` 13 | *.test 14 | 15 | # Output of the go coverage tool, specifically when used with LiteIDE 16 | *.out 17 | 18 | # ide files and temp files 19 | .idea/ 20 | *.swp 21 | .vscode/*.json 22 | bnc-go-sdk 23 | -------------------------------------------------------------------------------- /common/types/fixed8.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/bnb-chain/node/common/utils" 5 | ) 6 | 7 | var ( 8 | Fixed8Decimals = utils.Fixed8Decimals 9 | Fixed8One = utils.Fixed8One 10 | Fixed8Zero = utils.NewFixed8(0) 11 | ) 12 | 13 | type Fixed8 = utils.Fixed8 14 | 15 | var ( 16 | NewFixed8 = utils.NewFixed8 17 | Fixed8DecodeString = utils.Fixed8DecodeString 18 | ) 19 | -------------------------------------------------------------------------------- /types/wire.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | ntypes "github.com/bnb-chain/go-sdk/common/types" 5 | "github.com/bnb-chain/go-sdk/types/tx" 6 | "github.com/tendermint/go-amino" 7 | types "github.com/tendermint/tendermint/rpc/core/types" 8 | ) 9 | 10 | func NewCodec() *amino.Codec { 11 | cdc := amino.NewCodec() 12 | types.RegisterAmino(cdc) 13 | ntypes.RegisterWire(cdc) 14 | tx.RegisterCodec(cdc) 15 | return cdc 16 | } 17 | -------------------------------------------------------------------------------- /types/config.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | const ( 4 | DefaultApiSchema = "https" 5 | DefaultWSSchema = "wss" 6 | DefaultAPIVersionPrefix = "/api/v1" 7 | DefaultWSPrefix = "/api/ws" 8 | NativeSymbol = "BNB" 9 | 10 | ProdChainID = "Binance-Chain-Tigris" 11 | TestnetChainID = "Binance-Chain-Ganges" 12 | KongoChainId = "Binance-Chain-Kongo" 13 | GangesChainId = "Binance-Chain-Ganges" 14 | 15 | RialtoNet = "rialto" 16 | ChapelNet = "chapel" 17 | ) 18 | -------------------------------------------------------------------------------- /types/tx/result.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | const ( 4 | CodeOk int32 = 0 5 | ) 6 | 7 | // TxResult def 8 | type TxResult struct { 9 | Hash string `json:"hash"` 10 | Log string `json:"log"` 11 | Data string `json:"data"` 12 | Code int32 `json:"code"` 13 | } 14 | 15 | // TxCommitResult for POST tx results 16 | type TxCommitResult struct { 17 | Ok bool `json:"ok"` 18 | Log string `json:"log"` 19 | Hash string `json:"hash"` 20 | Code int32 `json:"code"` 21 | Data string `json:"data"` 22 | } 23 | -------------------------------------------------------------------------------- /keys/testkeystore.json: -------------------------------------------------------------------------------- 1 | {"version":1,"id":"0b3d7c68-c5e8-4b26-9b20-4690e0f52b73","crypto":{"ciphertext":"fdbaea9fa6672de0d607aa030eb0492a9023e837c82968ddfe374fee6f1e2f5a","cipherparams":{"iv":"5c9a03d8c23dd6bc5e812ebf3a68f425"},"cipher":"aes-256-ctr","kdf":"pbkdf2","kdfparams":{"dklen":32,"salt":"12fcaadc6cd8fab47edfe51017e7ab1d4bda1902219b86ff8d4cbf4661f60134","c":262144,"prf":"hmac-sha256"},"mac":"6bfa9ebdcc83278b7bcc04e53a5837b193cabdf7807116dfc5fff2049779b55531710fb5def1b941f59e18a69679126c2bd85baf2c85a88ce867ac1db2cef2ef"}} -------------------------------------------------------------------------------- /client/query/get_time.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/bnb-chain/go-sdk/common/types" 7 | ) 8 | 9 | // GetTime returns market depth records 10 | func (c *client) GetTime() (*types.Time, error) { 11 | qp := map[string]string{} 12 | resp, _, err := c.baseClient.Get("/time", qp) 13 | if err != nil { 14 | return nil, err 15 | } 16 | 17 | var t types.Time 18 | if err := json.Unmarshal(resp, &t); err != nil { 19 | return nil, err 20 | } 21 | 22 | return &t, nil 23 | } 24 | -------------------------------------------------------------------------------- /client/query/get_node_info.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/bnb-chain/go-sdk/common/types" 7 | ) 8 | 9 | func (c *client) GetNodeInfo() (*types.ResultStatus, error) { 10 | qp := map[string]string{} 11 | resp, _, err := c.baseClient.Get("/node-info", qp) 12 | if err != nil { 13 | return nil, err 14 | } 15 | var resultStatus types.ResultStatus 16 | if err := json.Unmarshal(resp, &resultStatus); err != nil { 17 | return nil, err 18 | } 19 | 20 | return &resultStatus, nil 21 | } 22 | -------------------------------------------------------------------------------- /types/tx/stdtx.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/types" 5 | "github.com/cosmos/cosmos-sdk/x/auth" 6 | context "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" 7 | ) 8 | 9 | const Source int64 = 0 10 | 11 | type ( 12 | Tx = types.Tx 13 | StdTx = auth.StdTx 14 | StdSignDoc = auth.StdSignDoc 15 | StdSignature = auth.StdSignature 16 | StdSignMsg = context.StdSignMsg 17 | ) 18 | 19 | var ( 20 | StdSignBytes = auth.StdSignBytes 21 | NewStdTx = auth.NewStdTx 22 | ) 23 | -------------------------------------------------------------------------------- /example/ledger-keys/README.md: -------------------------------------------------------------------------------- 1 | ## How to run this example 2 | 3 | - Please refer to this [document](https://www.binance.org/static/guides/DEX-Ledger-Documentation.html) to install binance-ledger-app on your ledger device 4 | - Compile this example 5 | ``` 6 | make install 7 | ``` 8 | - Run `ledger-keys` in console. Then you will get similar response like this: 9 | ``` 10 | address: bnb1muezuhetegleh6dp4zeeuj88rqjkkfvtnsuk2x 11 | pubkey: eb5ae9872102439b14d151801e602116b339974977f99ca4f664931a08f03ec642e285315a43 12 | ``` -------------------------------------------------------------------------------- /common/types/delegation.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/x/stake/querier" 5 | stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" 6 | ) 7 | 8 | type ( 9 | Delegation = stakeTypes.Delegation 10 | Redelegation = stakeTypes.Redelegation 11 | DelegationResponse = stakeTypes.DelegationResponse 12 | 13 | QueryDelegatorParams = querier.QueryDelegatorParams 14 | QueryRedelegationParams = querier.QueryRedelegationParams 15 | ) 16 | 17 | var ( 18 | UnmarshalRED = stakeTypes.UnmarshalRED 19 | ) 20 | -------------------------------------------------------------------------------- /types/tx/wire.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "github.com/tendermint/go-amino" 5 | cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" 6 | 7 | "github.com/bnb-chain/go-sdk/types/msg" 8 | ) 9 | 10 | // cdc global variable 11 | var Cdc = amino.NewCodec() 12 | 13 | func RegisterCodec(cdc *amino.Codec) { 14 | cdc.RegisterInterface((*Tx)(nil), nil) 15 | cdc.RegisterConcrete(StdTx{}, "auth/StdTx", nil) 16 | msg.RegisterCodec(cdc) 17 | } 18 | 19 | func init() { 20 | cryptoAmino.RegisterAmino(Cdc) 21 | RegisterCodec(Cdc) 22 | } 23 | -------------------------------------------------------------------------------- /client/transaction/set_uri.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/types/msg" 5 | "github.com/bnb-chain/go-sdk/types/tx" 6 | ) 7 | 8 | type SetUriResult struct { 9 | tx.TxCommitResult 10 | } 11 | 12 | func (c *client) SetURI(symbol, tokenURI string, sync bool, options ...Option) (*SetUriResult, error) { 13 | fromAddr := c.keyManager.GetAddr() 14 | 15 | setURIMsg := msg.NewSetUriMsg(fromAddr, symbol, tokenURI) 16 | commit, err := c.broadcastMsg(setURIMsg, sync, options...) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | return &SetUriResult{*commit}, nil 22 | 23 | } 24 | -------------------------------------------------------------------------------- /common/ledger/ledger.go: -------------------------------------------------------------------------------- 1 | //go:build cgo && ledger 2 | // +build cgo,ledger 3 | 4 | package ledger 5 | 6 | import ( 7 | ledger "github.com/zondax/ledger-cosmos-go" 8 | ) 9 | 10 | // If ledger support (build tag) has been enabled, which implies a CGO dependency, 11 | // set the discoverLedger function which is responsible for loading the Ledger 12 | // device at runtime or returning an error. 13 | func init() { 14 | DiscoverLedger = func() (LedgerSecp256k1, error) { 15 | device, err := ledger.FindLedgerCosmosUserApp() 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | return device, nil 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /common/types/fees.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/types" 5 | paramHubTypes "github.com/cosmos/cosmos-sdk/x/paramHub/types" 6 | ) 7 | 8 | const ( 9 | FeeForProposer = types.FeeForProposer 10 | FeeForAll = types.FeeForAll 11 | FeeFree = types.FeeFree 12 | ) 13 | 14 | type ( 15 | FeeDistributeType = types.FeeDistributeType 16 | 17 | FeeParam = paramHubTypes.FeeParam 18 | DexFeeParam = paramHubTypes.DexFeeParam 19 | DexFeeField = paramHubTypes.DexFeeField 20 | FixedFeeParams = paramHubTypes.FixedFeeParams 21 | TransferFeeParam = paramHubTypes.TransferFeeParam 22 | ) 23 | -------------------------------------------------------------------------------- /client/query/query.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/client/basic" 5 | "github.com/bnb-chain/go-sdk/common/types" 6 | ) 7 | 8 | type QueryClient interface { 9 | GetAccount(string) (*types.BalanceAccount, error) 10 | GetTime() (*types.Time, error) 11 | GetTokens(query *types.TokensQuery) ([]types.Token, error) 12 | GetNodeInfo() (*types.ResultStatus, error) 13 | GetMiniTokens(query *types.TokensQuery) ([]types.MiniToken, error) 14 | } 15 | 16 | type client struct { 17 | baseClient basic.BasicClient 18 | } 19 | 20 | func NewClient(c basic.BasicClient) QueryClient { 21 | return &client{baseClient: c} 22 | } 23 | -------------------------------------------------------------------------------- /client/transaction/vote_proposal.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/types/msg" 5 | "github.com/bnb-chain/go-sdk/types/tx" 6 | ) 7 | 8 | type VoteProposalResult struct { 9 | tx.TxCommitResult 10 | } 11 | 12 | func (c *client) VoteProposal(proposalID int64, option msg.VoteOption, sync bool, options ...Option) (*VoteProposalResult, error) { 13 | fromAddr := c.keyManager.GetAddr() 14 | voteMsg := msg.NewMsgVote(fromAddr, proposalID, option) 15 | commit, err := c.broadcastMsg(voteMsg, sync, options...) 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | return &VoteProposalResult{*commit}, err 21 | 22 | } 23 | -------------------------------------------------------------------------------- /client/query/get_tokens.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/bnb-chain/go-sdk/common" 7 | "github.com/bnb-chain/go-sdk/common/types" 8 | ) 9 | 10 | // GetTokens returns list of tokens 11 | func (c *client) GetTokens(query *types.TokensQuery) ([]types.Token, error) { 12 | qp, err := common.QueryParamToMap(*query) 13 | if err != nil { 14 | return nil, err 15 | } 16 | resp, _, err := c.baseClient.Get("/tokens", qp) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | var tokens []types.Token 22 | if err := json.Unmarshal(resp, &tokens); err != nil { 23 | return nil, err 24 | } 25 | 26 | return tokens, nil 27 | } 28 | -------------------------------------------------------------------------------- /common/types/swap.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/bnb-chain/node/plugins/tokens/swap" 5 | ) 6 | 7 | const ( 8 | NULL = swap.NULL 9 | Open = swap.Open 10 | Completed = swap.Completed 11 | Expired = swap.Expired 12 | ) 13 | 14 | var ( 15 | NewSwapStatusFromString = swap.NewSwapStatusFromString 16 | ) 17 | 18 | type ( 19 | SwapStatus = swap.SwapStatus 20 | SwapBytes = swap.SwapBytes 21 | AtomicSwap = swap.AtomicSwap 22 | QuerySwapByID swap.QuerySwapByID 23 | QuerySwapByCreatorParams = swap.QuerySwapByCreatorParams 24 | QuerySwapByRecipientParams swap.QuerySwapByRecipientParams 25 | ) 26 | -------------------------------------------------------------------------------- /client/query/get_mini_tokens.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/bnb-chain/go-sdk/common" 7 | "github.com/bnb-chain/go-sdk/common/types" 8 | ) 9 | 10 | // GetMiniTokens returns list of mini tokens 11 | func (c *client) GetMiniTokens(query *types.TokensQuery) ([]types.MiniToken, error) { 12 | qp, err := common.QueryParamToMap(*query) 13 | if err != nil { 14 | return nil, err 15 | } 16 | resp, _, err := c.baseClient.Get("/mini/tokens", qp) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | var tokens []types.MiniToken 22 | if err := json.Unmarshal(resp, &tokens); err != nil { 23 | return nil, err 24 | } 25 | 26 | return tokens, nil 27 | } 28 | -------------------------------------------------------------------------------- /client/transaction/list_mini_pair.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/types/msg" 5 | "github.com/bnb-chain/go-sdk/types/tx" 6 | ) 7 | 8 | type ListMiniPairResult struct { 9 | tx.TxCommitResult 10 | } 11 | 12 | func (c *client) ListMiniPair(baseAssetSymbol string, quoteAssetSymbol string, initPrice int64, sync bool, options ...Option) (*ListMiniPairResult, error) { 13 | fromAddr := c.keyManager.GetAddr() 14 | 15 | listMsg := msg.NewListMiniMsg(fromAddr, baseAssetSymbol, quoteAssetSymbol, initPrice) 16 | commit, err := c.broadcastMsg(listMsg, sync, options...) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | return &ListMiniPairResult{*commit}, nil 22 | 23 | } 24 | -------------------------------------------------------------------------------- /client/transaction/list_pair.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/types/msg" 5 | "github.com/bnb-chain/go-sdk/types/tx" 6 | ) 7 | 8 | type ListPairResult struct { 9 | tx.TxCommitResult 10 | } 11 | 12 | func (c *client) ListPair(proposalId int64, baseAssetSymbol string, quoteAssetSymbol string, initPrice int64, sync bool, options ...Option) (*ListPairResult, error) { 13 | fromAddr := c.keyManager.GetAddr() 14 | 15 | burnMsg := msg.NewDexListMsg(fromAddr, proposalId, baseAssetSymbol, quoteAssetSymbol, initPrice) 16 | commit, err := c.broadcastMsg(burnMsg, sync, options...) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | return &ListPairResult{*commit}, nil 22 | 23 | } 24 | -------------------------------------------------------------------------------- /common/types/account.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | nodeTypes "github.com/bnb-chain/node/common/types" 5 | "github.com/cosmos/cosmos-sdk/types" 6 | "github.com/cosmos/cosmos-sdk/x/auth" 7 | ) 8 | 9 | type ( 10 | AppAccount = nodeTypes.AppAccount 11 | BaseAccount = auth.BaseAccount 12 | 13 | Account = types.Account 14 | NamedAccount = nodeTypes.NamedAccount 15 | ) 16 | 17 | // Balance Account definition 18 | type BalanceAccount struct { 19 | Number int64 `json:"account_number"` 20 | Address string `json:"address"` 21 | Balances []TokenBalance `json:"balances"` 22 | PublicKey []uint8 `json:"public_key"` 23 | Sequence int64 `json:"sequence"` 24 | Flags uint64 `json:"flags"` 25 | } 26 | -------------------------------------------------------------------------------- /types/tx/option.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | type Option func(msg *StdSignMsg) *StdSignMsg 4 | 5 | func WithSource(source int64) Option { 6 | return func(txMsg *StdSignMsg) *StdSignMsg { 7 | txMsg.Source = source 8 | return txMsg 9 | } 10 | } 11 | 12 | func WithMemo(memo string) Option { 13 | return func(txMsg *StdSignMsg) *StdSignMsg { 14 | txMsg.Memo = memo 15 | return txMsg 16 | } 17 | } 18 | 19 | func WithAcNumAndSequence(accountNum, seq int64) Option { 20 | return func(txMsg *StdSignMsg) *StdSignMsg { 21 | txMsg.Sequence = seq 22 | txMsg.AccountNumber = accountNum 23 | return txMsg 24 | } 25 | } 26 | 27 | func WithChainID(id string) Option { 28 | return func(txMsg *StdSignMsg) *StdSignMsg { 29 | txMsg.ChainID = id 30 | return txMsg 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/query/get_account.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/bnb-chain/go-sdk/common/types" 8 | ) 9 | 10 | // GetAccount returns list of trading pairs 11 | func (c *client) GetAccount(address string) (*types.BalanceAccount, error) { 12 | if address == "" { 13 | return nil, types.AddressMissingError 14 | } 15 | 16 | qp := map[string]string{} 17 | resp, code, err := c.baseClient.Get("/account/"+address, qp) 18 | if err != nil { 19 | if code == http.StatusNotFound { 20 | return &types.BalanceAccount{}, nil 21 | } 22 | return nil, err 23 | } 24 | var account types.BalanceAccount 25 | if err := json.Unmarshal(resp, &account); err != nil { 26 | return nil, err 27 | } 28 | return &account, nil 29 | } 30 | -------------------------------------------------------------------------------- /client/transaction/mint_token.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/bnb-chain/go-sdk/types/msg" 7 | "github.com/bnb-chain/go-sdk/types/tx" 8 | ) 9 | 10 | type MintTokenResult struct { 11 | tx.TxCommitResult 12 | } 13 | 14 | func (c *client) MintToken(symbol string, amount int64, sync bool, options ...Option) (*MintTokenResult, error) { 15 | if symbol == "" { 16 | return nil, fmt.Errorf("Mint token symbol can't be empty ") 17 | } 18 | fromAddr := c.keyManager.GetAddr() 19 | 20 | mintMsg := msg.NewMintMsg( 21 | fromAddr, 22 | symbol, 23 | amount, 24 | ) 25 | commit, err := c.broadcastMsg(mintMsg, sync, options...) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | return &MintTokenResult{*commit}, nil 31 | 32 | } 33 | -------------------------------------------------------------------------------- /client/transaction/transfer_token_ownership.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/common/types" 5 | "github.com/bnb-chain/go-sdk/types/msg" 6 | "github.com/bnb-chain/go-sdk/types/tx" 7 | ) 8 | 9 | type TransferTokenOwnershipResult struct { 10 | tx.TxCommitResult 11 | } 12 | 13 | func (c *client) TransferTokenOwnership(symbol string, newOwner types.AccAddress, sync bool, options ...Option) (*TransferTokenOwnershipResult, error) { 14 | fromAddr := c.keyManager.GetAddr() 15 | transferOwnershipMsg := msg.NewTransferOwnershipMsg(fromAddr, symbol, newOwner) 16 | commit, err := c.broadcastMsg(transferOwnershipMsg, sync, options...) 17 | if err != nil { 18 | return nil, err 19 | } 20 | return &TransferTokenOwnershipResult{*commit}, nil 21 | } 22 | -------------------------------------------------------------------------------- /client/transaction/burn_token.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/bnb-chain/go-sdk/types/msg" 7 | "github.com/bnb-chain/go-sdk/types/tx" 8 | ) 9 | 10 | type BurnTokenResult struct { 11 | tx.TxCommitResult 12 | } 13 | 14 | func (c *client) BurnToken(symbol string, amount int64, sync bool, options ...Option) (*BurnTokenResult, error) { 15 | if symbol == "" { 16 | return nil, fmt.Errorf("Burn token symbol can't be empty ") 17 | } 18 | fromAddr := c.keyManager.GetAddr() 19 | 20 | burnMsg := msg.NewTokenBurnMsg( 21 | fromAddr, 22 | symbol, 23 | amount, 24 | ) 25 | commit, err := c.broadcastMsg(burnMsg, sync, options...) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | return &BurnTokenResult{*commit}, nil 31 | 32 | } 33 | -------------------------------------------------------------------------------- /client/transaction/freeze_token.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/bnb-chain/go-sdk/types/msg" 7 | "github.com/bnb-chain/go-sdk/types/tx" 8 | ) 9 | 10 | type FreezeTokenResult struct { 11 | tx.TxCommitResult 12 | } 13 | 14 | func (c *client) FreezeToken(symbol string, amount int64, sync bool, options ...Option) (*FreezeTokenResult, error) { 15 | if symbol == "" { 16 | return nil, fmt.Errorf("Freeze token symbol can't be empty ") 17 | } 18 | fromAddr := c.keyManager.GetAddr() 19 | 20 | freezeMsg := msg.NewFreezeMsg( 21 | fromAddr, 22 | symbol, 23 | amount, 24 | ) 25 | commit, err := c.broadcastMsg(freezeMsg, sync, options...) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | return &FreezeTokenResult{*commit}, nil 31 | 32 | } 33 | -------------------------------------------------------------------------------- /client/transaction/unfreeze_token.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/bnb-chain/go-sdk/types/msg" 7 | "github.com/bnb-chain/go-sdk/types/tx" 8 | ) 9 | 10 | type UnfreezeTokenResult struct { 11 | tx.TxCommitResult 12 | } 13 | 14 | func (c *client) UnfreezeToken(symbol string, amount int64, sync bool, options ...Option) (*UnfreezeTokenResult, error) { 15 | if symbol == "" { 16 | return nil, fmt.Errorf("Unfreeze token symbol can't be empty ") 17 | } 18 | fromAddr := c.keyManager.GetAddr() 19 | 20 | unfreezeMsg := msg.NewUnfreezeMsg( 21 | fromAddr, 22 | symbol, 23 | amount, 24 | ) 25 | commit, err := c.broadcastMsg(unfreezeMsg, sync, options...) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | return &UnfreezeTokenResult{*commit}, nil 31 | 32 | } 33 | -------------------------------------------------------------------------------- /client/transaction/send_token.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/common/types" 5 | "github.com/bnb-chain/go-sdk/types/msg" 6 | "github.com/bnb-chain/go-sdk/types/tx" 7 | ) 8 | 9 | type SendTokenResult struct { 10 | tx.TxCommitResult 11 | } 12 | 13 | func (c *client) SendToken(transfers []msg.Transfer, sync bool, options ...Option) (*SendTokenResult, error) { 14 | fromAddr := c.keyManager.GetAddr() 15 | fromCoins := types.Coins{} 16 | for _, t := range transfers { 17 | t.Coins = t.Coins.Sort() 18 | fromCoins = fromCoins.Plus(t.Coins) 19 | } 20 | sendMsg := msg.CreateSendMsg(fromAddr, fromCoins, transfers) 21 | commit, err := c.broadcastMsg(sendMsg, sync, options...) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return &SendTokenResult{*commit}, err 26 | 27 | } 28 | -------------------------------------------------------------------------------- /common/types/wire.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/tendermint/go-amino" 4 | 5 | func RegisterWire(cdc *amino.Codec) { 6 | 7 | cdc.RegisterConcrete(Token{}, "bnbchain/Token", nil) 8 | cdc.RegisterInterface((*Account)(nil), nil) 9 | cdc.RegisterInterface((*NamedAccount)(nil), nil) 10 | cdc.RegisterConcrete(&AppAccount{}, "bnbchain/Account", nil) 11 | 12 | cdc.RegisterInterface((*FeeParam)(nil), nil) 13 | cdc.RegisterConcrete(&FixedFeeParams{}, "params/FixedFeeParams", nil) 14 | cdc.RegisterConcrete(&TransferFeeParam{}, "params/TransferFeeParams", nil) 15 | cdc.RegisterConcrete(&DexFeeParam{}, "params/DexFeeParam", nil) 16 | 17 | cdc.RegisterInterface((*Proposal)(nil), nil) 18 | cdc.RegisterConcrete(&TextProposal{}, "gov/TextProposal", nil) 19 | 20 | cdc.RegisterConcrete(MiniToken{}, "bnbchain/MiniToken", nil) 21 | } 22 | -------------------------------------------------------------------------------- /client/transaction/deposit_proposal.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | ctypes "github.com/bnb-chain/go-sdk/common/types" 5 | "github.com/bnb-chain/go-sdk/types" 6 | "github.com/bnb-chain/go-sdk/types/msg" 7 | "github.com/bnb-chain/go-sdk/types/tx" 8 | ) 9 | 10 | type DepositProposalResult struct { 11 | tx.TxCommitResult 12 | } 13 | 14 | func (c *client) DepositProposal(proposalID int64, amount int64, sync bool, options ...Option) (*DepositProposalResult, error) { 15 | fromAddr := c.keyManager.GetAddr() 16 | coins := ctypes.Coins{ctypes.Coin{Denom: types.NativeSymbol, Amount: amount}} 17 | depositMsg := msg.NewDepositMsg(fromAddr, proposalID, coins) 18 | commit, err := c.broadcastMsg(depositMsg, sync, options...) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | return &DepositProposalResult{*commit}, err 24 | 25 | } 26 | -------------------------------------------------------------------------------- /client/transaction/cancel_order.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/bnb-chain/go-sdk/common" 7 | "github.com/bnb-chain/go-sdk/types/msg" 8 | "github.com/bnb-chain/go-sdk/types/tx" 9 | ) 10 | 11 | type CancelOrderResult struct { 12 | tx.TxCommitResult 13 | } 14 | 15 | // CancelOrder deprecated 16 | func (c *client) CancelOrder(baseAssetSymbol, quoteAssetSymbol, refId string, sync bool, options ...Option) (*CancelOrderResult, error) { 17 | if baseAssetSymbol == "" || quoteAssetSymbol == "" { 18 | return nil, fmt.Errorf("BaseAssetSymbol or QuoteAssetSymbol is missing. ") 19 | } 20 | if refId == "" { 21 | return nil, fmt.Errorf("OrderId or Order RefId is missing. ") 22 | } 23 | 24 | fromAddr := c.keyManager.GetAddr() 25 | 26 | cancelOrderMsg := msg.NewCancelOrderMsg(fromAddr, common.CombineSymbol(baseAssetSymbol, quoteAssetSymbol), refId) 27 | commit, err := c.broadcastMsg(cancelOrderMsg, sync, options...) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | return &CancelOrderResult{*commit}, nil 33 | } 34 | -------------------------------------------------------------------------------- /common/types/query.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | const ( 8 | SideBuy = "BUY" 9 | SideSell = "SELL" 10 | ) 11 | 12 | var ( 13 | // Param error 14 | AddressMissingError = errors.New("Address is required ") 15 | OffsetOutOfRangeError = errors.New("offset out of range ") 16 | LimitOutOfRangeError = errors.New("limit out of range ") 17 | ) 18 | 19 | // TokensQuery definition 20 | type TokensQuery struct { 21 | Offset *uint32 `json:"offset,omitempty,string"` //Option 22 | Limit *uint32 `json:"limit,omitempty,string"` //Option 23 | } 24 | 25 | func NewTokensQuery() *TokensQuery { 26 | return &TokensQuery{} 27 | } 28 | 29 | func (param *TokensQuery) WithOffset(offset uint32) *TokensQuery { 30 | param.Offset = &offset 31 | return param 32 | } 33 | 34 | func (param *TokensQuery) WithLimit(limit uint32) *TokensQuery { 35 | param.Limit = &limit 36 | return param 37 | } 38 | 39 | func (param *TokensQuery) Check() error { 40 | if param.Limit != nil && *param.Limit <= 0 { 41 | return LimitOutOfRangeError 42 | } 43 | if param.Offset != nil && *param.Offset < 0 { 44 | return OffsetOutOfRangeError 45 | } 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/json" 6 | "fmt" 7 | "regexp" 8 | ) 9 | 10 | var ( 11 | isAlphaNumFunc = regexp.MustCompile(`^[[:alnum:]]+$`).MatchString 12 | ) 13 | 14 | func QueryParamToMap(qp interface{}) (map[string]string, error) { 15 | queryMap := make(map[string]string, 0) 16 | bz, err := json.Marshal(qp) 17 | if err != nil { 18 | return nil, err 19 | } 20 | err = json.Unmarshal(bz, &queryMap) 21 | if err != nil { 22 | return nil, err 23 | } 24 | return queryMap, nil 25 | } 26 | 27 | func CombineSymbol(baseAssetSymbol, quoteAssetSymbol string) string { 28 | return fmt.Sprintf("%s_%s", baseAssetSymbol, quoteAssetSymbol) 29 | } 30 | 31 | // GenerateRandomBytes returns securely generated random bytes. 32 | // It will return an error if the system's secure random 33 | // number generator fails to function correctly, in which 34 | // case the caller should not continue. 35 | func GenerateRandomBytes(n int) ([]byte, error) { 36 | b := make([]byte, n) 37 | _, err := rand.Read(b) 38 | // Note that err == nil only if we read len(b) bytes. 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | return b, nil 44 | } 45 | -------------------------------------------------------------------------------- /common/types/oracle.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/binary" 5 | 6 | ctypes "github.com/cosmos/cosmos-sdk/types" 7 | "github.com/cosmos/cosmos-sdk/x/sidechain" 8 | ) 9 | 10 | type IbcChannelID = ctypes.ChannelID 11 | type IbcChainID = ctypes.ChainID 12 | 13 | const ( 14 | prefixLength = 1 15 | destIbcChainIDLength = 2 16 | channelIDLength = 1 17 | ) 18 | 19 | var ( 20 | SideChainStorePrefixByIdKey = sidechain.SideChainStorePrefixByIdKey 21 | 22 | PrefixForSendSequenceKey = sidechain.PrefixForSendSequenceKey 23 | PrefixForReceiveSequenceKey = sidechain.PrefixForReceiveSequenceKey 24 | ) 25 | 26 | func GetReceiveSequenceKey(destIbcChainID IbcChainID, channelID IbcChannelID) []byte { 27 | return buildChannelSequenceKey(destIbcChainID, channelID, PrefixForReceiveSequenceKey) 28 | } 29 | 30 | func buildChannelSequenceKey(destIbcChainID IbcChainID, channelID IbcChannelID, prefix []byte) []byte { 31 | key := make([]byte, prefixLength+destIbcChainIDLength+channelIDLength) 32 | 33 | copy(key[:prefixLength], prefix) 34 | binary.BigEndian.PutUint16(key[prefixLength:prefixLength+destIbcChainIDLength], uint16(destIbcChainID)) 35 | copy(key[prefixLength+destIbcChainIDLength:], []byte{byte(channelID)}) 36 | return key 37 | } 38 | -------------------------------------------------------------------------------- /common/types/stake.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/types" 5 | "github.com/cosmos/cosmos-sdk/x/stake" 6 | stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" 7 | ) 8 | 9 | // nolint 10 | const ( 11 | Unbonded = types.Unbonded 12 | Unbonding = types.Unbonding 13 | Bonded = types.Bonded 14 | ) 15 | 16 | type ( 17 | Commission = stakeTypes.Commission 18 | CommissionMsg = stakeTypes.CommissionMsg 19 | Description = stakeTypes.Description 20 | Validator = stakeTypes.Validator 21 | UnbondingDelegation = stakeTypes.UnbondingDelegation 22 | Pool = stakeTypes.Pool 23 | 24 | ValAddress = types.ValAddress 25 | BondStatus = types.BondStatus 26 | ConsAddress = types.ConsAddress 27 | 28 | QueryTopValidatorsParams = stake.QueryTopValidatorsParams 29 | QueryBondsParams = stake.QueryBondsParams 30 | QueryValidatorParams = stake.QueryValidatorParams 31 | ) 32 | 33 | var ( 34 | NewCommission = stakeTypes.NewCommission 35 | 36 | ValAddressFromBech32 = types.ValAddressFromBech32 37 | ConsAddressFromHex = types.ConsAddressFromHex 38 | ConsAddressFromBech32 = types.ConsAddressFromBech32 39 | GetConsAddress = types.GetConsAddress 40 | 41 | NewBaseParams = stake.NewBaseParams 42 | ) 43 | -------------------------------------------------------------------------------- /client/rpc/mock/status.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import ( 4 | "github.com/tendermint/tendermint/rpc/client" 5 | ctypes "github.com/tendermint/tendermint/rpc/core/types" 6 | ) 7 | 8 | // StatusMock returns the result specified by the Call 9 | type StatusMock struct { 10 | Call 11 | } 12 | 13 | var ( 14 | _ client.StatusClient = (*StatusMock)(nil) 15 | _ client.StatusClient = (*StatusRecorder)(nil) 16 | ) 17 | 18 | func (m *StatusMock) Status() (*ctypes.ResultStatus, error) { 19 | res, err := m.GetResponse(nil) 20 | if err != nil { 21 | return nil, err 22 | } 23 | return res.(*ctypes.ResultStatus), nil 24 | } 25 | 26 | // StatusRecorder can wrap another type (StatusMock, full client) 27 | // and record the status calls 28 | type StatusRecorder struct { 29 | Client client.StatusClient 30 | Calls []Call 31 | } 32 | 33 | func NewStatusRecorder(client client.StatusClient) *StatusRecorder { 34 | return &StatusRecorder{ 35 | Client: client, 36 | Calls: []Call{}, 37 | } 38 | } 39 | 40 | func (r *StatusRecorder) addCall(call Call) { 41 | r.Calls = append(r.Calls, call) 42 | } 43 | 44 | func (r *StatusRecorder) Status() (*ctypes.ResultStatus, error) { 45 | res, err := r.Client.Status() 46 | r.addCall(Call{ 47 | Name: "status", 48 | Response: res, 49 | Error: err, 50 | }) 51 | return res, err 52 | } 53 | -------------------------------------------------------------------------------- /client/transaction/create_order.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/bnb-chain/go-sdk/common" 8 | "github.com/bnb-chain/go-sdk/types/msg" 9 | "github.com/bnb-chain/go-sdk/types/tx" 10 | ) 11 | 12 | type CreateOrderResult struct { 13 | tx.TxCommitResult 14 | OrderId string 15 | } 16 | 17 | // CreateOrder deprecated 18 | func (c *client) CreateOrder(baseAssetSymbol, quoteAssetSymbol string, op int8, price, quantity int64, sync bool, options ...Option) (*CreateOrderResult, error) { 19 | if baseAssetSymbol == "" || quoteAssetSymbol == "" { 20 | return nil, fmt.Errorf("BaseAssetSymbol or QuoteAssetSymbol is missing. ") 21 | } 22 | fromAddr := c.keyManager.GetAddr() 23 | newOrderMsg := msg.NewCreateOrderMsg( 24 | fromAddr, 25 | "", 26 | op, 27 | common.CombineSymbol(baseAssetSymbol, quoteAssetSymbol), 28 | price, 29 | quantity, 30 | ) 31 | commit, err := c.broadcastMsg(newOrderMsg, sync, options...) 32 | if err != nil { 33 | return nil, err 34 | } 35 | type commitData struct { 36 | OrderId string `json:"order_id"` 37 | } 38 | var cdata commitData 39 | if sync { 40 | err = json.Unmarshal([]byte(commit.Data), &cdata) 41 | if err != nil { 42 | return nil, err 43 | } 44 | } 45 | 46 | return &CreateOrderResult{*commit, cdata.OrderId}, nil 47 | } 48 | -------------------------------------------------------------------------------- /client/rpc/ops_client.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import "github.com/bnb-chain/go-sdk/common/types" 4 | 5 | type OpsClient interface { 6 | IsActive() bool 7 | GetStakeValidators() ([]types.Validator, error) 8 | GetDelegatorUnbondingDelegations(delegatorAddr types.AccAddress) ([]types.UnbondingDelegation, error) 9 | } 10 | 11 | func (c *HTTP) IsActive() bool { 12 | return c.WSEvents.IsActive() 13 | } 14 | 15 | func (c *HTTP) GetStakeValidators() ([]types.Validator, error) { 16 | rawVal, err := c.ABCIQuery("custom/stake/validators", nil) 17 | if err != nil { 18 | return nil, err 19 | } 20 | var validators []types.Validator 21 | err = c.cdc.UnmarshalJSON(rawVal.Response.GetValue(), &validators) 22 | return validators, err 23 | 24 | } 25 | 26 | func (c *HTTP) GetDelegatorUnbondingDelegations(delegatorAddr types.AccAddress) ([]types.UnbondingDelegation, error) { 27 | param := struct { 28 | DelegatorAddr types.AccAddress 29 | }{delegatorAddr} 30 | bz, err := c.cdc.MarshalJSON(param) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | rawDel, err := c.ABCIQuery("custom/stake/delegatorUnbondingDelegations", bz) 36 | if err != nil { 37 | return nil, err 38 | } 39 | var unbondingDelegations []types.UnbondingDelegation 40 | err = c.cdc.UnmarshalJSON(rawDel.Response.GetValue(), &unbondingDelegations) 41 | return unbondingDelegations, err 42 | 43 | } 44 | -------------------------------------------------------------------------------- /client/transaction/issue_token.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/bnb-chain/go-sdk/types/msg" 8 | "github.com/bnb-chain/go-sdk/types/tx" 9 | ) 10 | 11 | type IssueTokenResult struct { 12 | tx.TxCommitResult 13 | Symbol string `json:"symbol"` 14 | } 15 | 16 | type IssueTokenValue struct { 17 | Name string `json:"name"` 18 | Symbol string `json:"symbol"` 19 | OrigSymbol string `json:"original_symbol"` 20 | TotalSupply string `json:"total_supply"` 21 | Owner string `json:"owner"` 22 | } 23 | 24 | func (c *client) IssueToken(name, symbol string, supply int64, sync bool, mintable bool, options ...Option) (*IssueTokenResult, error) { 25 | if symbol == "" { 26 | return nil, fmt.Errorf("Issue token symbol can't be empty ") 27 | } 28 | fromAddr := c.keyManager.GetAddr() 29 | 30 | issueMsg := msg.NewTokenIssueMsg( 31 | fromAddr, 32 | name, 33 | symbol, 34 | supply, 35 | mintable, 36 | ) 37 | commit, err := c.broadcastMsg(issueMsg, sync, options...) 38 | if err != nil { 39 | return nil, err 40 | } 41 | var issueTokenValue IssueTokenValue 42 | issueSymbol := symbol 43 | if commit.Ok && sync { 44 | err = json.Unmarshal([]byte(commit.Data), &issueTokenValue) 45 | if err != nil { 46 | return nil, err 47 | } 48 | issueSymbol = issueTokenValue.Symbol 49 | } 50 | 51 | return &IssueTokenResult{*commit, issueSymbol}, nil 52 | 53 | } 54 | -------------------------------------------------------------------------------- /client/transaction/set_account_flags.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/bnb-chain/go-sdk/common/types" 7 | "github.com/bnb-chain/go-sdk/types/msg" 8 | "github.com/bnb-chain/go-sdk/types/tx" 9 | ) 10 | 11 | type SetAccountFlagsResult struct { 12 | tx.TxCommitResult 13 | } 14 | 15 | func (c *client) AddAccountFlags(flagOptions []types.FlagOption, sync bool, options ...Option) (*SetAccountFlagsResult, error) { 16 | fromAddr := c.keyManager.GetAddr() 17 | acc, err := c.queryClient.GetAccount(fromAddr.String()) 18 | if err != nil { 19 | return nil, err 20 | } 21 | if len(flagOptions) == 0 { 22 | return nil, fmt.Errorf("missing flagOptions") 23 | } 24 | flags := acc.Flags 25 | for _, f := range flagOptions { 26 | flags = flags | uint64(f) 27 | } 28 | setAccMsg := msg.NewSetAccountFlagsMsg( 29 | fromAddr, 30 | flags, 31 | ) 32 | commit, err := c.broadcastMsg(setAccMsg, sync, options...) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | return &SetAccountFlagsResult{*commit}, nil 38 | } 39 | 40 | func (c *client) SetAccountFlags(flags uint64, sync bool, options ...Option) (*SetAccountFlagsResult, error) { 41 | fromAddr := c.keyManager.GetAddr() 42 | setAccMsg := msg.NewSetAccountFlagsMsg( 43 | fromAddr, 44 | flags, 45 | ) 46 | commit, err := c.broadcastMsg(setAccMsg, sync, options...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | return &SetAccountFlagsResult{*commit}, nil 52 | } 53 | -------------------------------------------------------------------------------- /common/types/address.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/types" 5 | ) 6 | 7 | type AccAddress = types.AccAddress 8 | 9 | type ChainNetwork uint8 10 | 11 | const ( 12 | TestNetwork ChainNetwork = iota 13 | ProdNetwork 14 | TmpTestNetwork 15 | GangesNetwork 16 | ) 17 | 18 | const ( 19 | AddrLen = types.AddrLen 20 | ) 21 | 22 | var Network = ProdNetwork 23 | 24 | func SetNetwork(network ChainNetwork) { 25 | Network = network 26 | if network != ProdNetwork { 27 | sdkConfig := types.GetConfig() 28 | sdkConfig.SetBech32PrefixForAccount("tbnb", "bnbp") 29 | } 30 | } 31 | 32 | func (this ChainNetwork) Bech32Prefixes() string { 33 | switch this { 34 | case TestNetwork: 35 | return "tbnb" 36 | case TmpTestNetwork: 37 | return "tbnb" 38 | case GangesNetwork: 39 | return "tbnb" 40 | case ProdNetwork: 41 | return "bnb" 42 | default: 43 | panic("Unknown network type") 44 | } 45 | } 46 | 47 | func init() { 48 | sdkConfig := types.GetConfig() 49 | sdkConfig.SetBech32PrefixForAccount("bnb", "bnbp") 50 | sdkConfig.SetBech32PrefixForValidator("bva", "bvap") 51 | sdkConfig.SetBech32PrefixForConsensusNode("bca", "bcap") 52 | } 53 | 54 | var ( 55 | AccAddressFromHex = types.AccAddressFromHex 56 | AccAddressFromBech32 = types.AccAddressFromBech32 57 | GetFromBech32 = types.GetFromBech32 58 | MustBech32ifyConsPub = types.MustBech32ifyConsPub 59 | Bech32ifyConsPub = types.Bech32ifyConsPub 60 | GetConsPubKeyBech32 = types.GetConsPubKeyBech32 61 | ) 62 | -------------------------------------------------------------------------------- /client/transaction/issue_mini_token.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/bnb-chain/go-sdk/types/msg" 8 | "github.com/bnb-chain/go-sdk/types/tx" 9 | ) 10 | 11 | type IssueMiniTokenResult struct { 12 | tx.TxCommitResult 13 | Symbol string `json:"symbol"` 14 | } 15 | 16 | type IssueMiniTokenValue struct { 17 | Name string `json:"name"` 18 | Symbol string `json:"symbol"` 19 | OrigSymbol string `json:"original_symbol"` 20 | TotalSupply string `json:"total_supply"` 21 | TokenURI string `json:"token_uri"` 22 | Owner string `json:"owner"` 23 | } 24 | 25 | func (c *client) IssueMiniToken(name, symbol string, supply int64, sync bool, mintable bool, tokenURI string, options ...Option) (*IssueMiniTokenResult, error) { 26 | if symbol == "" { 27 | return nil, fmt.Errorf("Issue mini token symbol can't be empty ") 28 | } 29 | fromAddr := c.keyManager.GetAddr() 30 | 31 | issueMsg := msg.NewMiniTokenIssueMsg( 32 | fromAddr, 33 | name, 34 | symbol, 35 | supply, 36 | mintable, 37 | tokenURI, 38 | ) 39 | commit, err := c.broadcastMsg(issueMsg, sync, options...) 40 | if err != nil { 41 | return nil, err 42 | } 43 | var issueTokenValue IssueMiniTokenValue 44 | issueSymbol := symbol 45 | if commit.Ok && sync { 46 | err = json.Unmarshal([]byte(commit.Data), &issueTokenValue) 47 | if err != nil { 48 | return nil, err 49 | } 50 | issueSymbol = issueTokenValue.Symbol 51 | } 52 | 53 | return &IssueMiniTokenResult{*commit, issueSymbol}, nil 54 | } 55 | -------------------------------------------------------------------------------- /client/transaction/issue_tiny_token.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/bnb-chain/go-sdk/types/msg" 8 | "github.com/bnb-chain/go-sdk/types/tx" 9 | ) 10 | 11 | type IssueTinyTokenResult struct { 12 | tx.TxCommitResult 13 | Symbol string `json:"symbol"` 14 | } 15 | 16 | type IssueTinyTokenValue struct { 17 | Name string `json:"name"` 18 | Symbol string `json:"symbol"` 19 | OrigSymbol string `json:"original_symbol"` 20 | TotalSupply string `json:"total_supply"` 21 | TokenURI string `json:"token_uri"` 22 | Owner string `json:"owner"` 23 | } 24 | 25 | func (c *client) IssueTinyToken(name, symbol string, supply int64, sync bool, mintable bool, tokenURI string, options ...Option) (*IssueTinyTokenResult, error) { 26 | if symbol == "" { 27 | return nil, fmt.Errorf("Issue mini token symbol can't be empty ") 28 | } 29 | fromAddr := c.keyManager.GetAddr() 30 | 31 | issueMsg := msg.NewMiniTokenIssueMsg( 32 | fromAddr, 33 | name, 34 | symbol, 35 | supply, 36 | mintable, 37 | tokenURI, 38 | ) 39 | commit, err := c.broadcastMsg(issueMsg, sync, options...) 40 | if err != nil { 41 | return nil, err 42 | } 43 | var issueTokenValue IssueMiniTokenValue 44 | issueSymbol := symbol 45 | if commit.Ok && sync { 46 | err = json.Unmarshal([]byte(commit.Data), &issueTokenValue) 47 | if err != nil { 48 | return nil, err 49 | } 50 | issueSymbol = issueTokenValue.Symbol 51 | } 52 | 53 | return &IssueTinyTokenResult{*commit, issueSymbol}, nil 54 | } 55 | -------------------------------------------------------------------------------- /client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "gopkg.in/resty.v1" 5 | 6 | "github.com/bnb-chain/go-sdk/client/basic" 7 | "github.com/bnb-chain/go-sdk/client/query" 8 | "github.com/bnb-chain/go-sdk/client/transaction" 9 | "github.com/bnb-chain/go-sdk/common/types" 10 | "github.com/bnb-chain/go-sdk/keys" 11 | ) 12 | 13 | // dexClient wrapper 14 | type dexClient struct { 15 | query.QueryClient 16 | transaction.TransactionClient 17 | basic.BasicClient 18 | } 19 | 20 | // DexClient methods 21 | type DexClient interface { 22 | basic.BasicClient 23 | query.QueryClient 24 | transaction.TransactionClient 25 | } 26 | 27 | func init() { 28 | resty.DefaultClient.SetRedirectPolicy(resty.FlexibleRedirectPolicy(10)) 29 | } 30 | 31 | func NewDexClientWithApiKey(baseUrl string, network types.ChainNetwork, keyManager keys.KeyManager, apiKey string) (DexClient, error) { 32 | types.SetNetwork(network) 33 | c := basic.NewClient(baseUrl+"/internal", apiKey) 34 | q := query.NewClient(c) 35 | n, err := q.GetNodeInfo() 36 | if err != nil { 37 | return nil, err 38 | } 39 | t := transaction.NewClient(n.NodeInfo.Network, keyManager, q, c) 40 | return &dexClient{BasicClient: c, QueryClient: q, TransactionClient: t}, nil 41 | } 42 | 43 | func NewDexClient(baseUrl string, network types.ChainNetwork, keyManager keys.KeyManager) (DexClient, error) { 44 | types.SetNetwork(network) 45 | c := basic.NewClient(baseUrl, "") 46 | q := query.NewClient(c) 47 | n, err := q.GetNodeInfo() 48 | if err != nil { 49 | return nil, err 50 | } 51 | t := transaction.NewClient(n.NodeInfo.Network, keyManager, q, c) 52 | return &dexClient{BasicClient: c, QueryClient: q, TransactionClient: t}, nil 53 | } 54 | -------------------------------------------------------------------------------- /client/transaction/submit_proposal.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "encoding/json" 5 | "strconv" 6 | "time" 7 | 8 | ctypes "github.com/bnb-chain/go-sdk/common/types" 9 | "github.com/bnb-chain/go-sdk/types" 10 | "github.com/bnb-chain/go-sdk/types/msg" 11 | "github.com/bnb-chain/go-sdk/types/tx" 12 | ) 13 | 14 | type SubmitProposalResult struct { 15 | tx.TxCommitResult 16 | ProposalId int64 `json:"proposal_id"` 17 | } 18 | 19 | func (c *client) SubmitListPairProposal(title string, param msg.ListTradingPairParams, initialDeposit int64, votingPeriod time.Duration, sync bool, options ...Option) (*SubmitProposalResult, error) { 20 | bz, err := json.Marshal(¶m) 21 | if err != nil { 22 | return nil, err 23 | } 24 | return c.SubmitProposal(title, string(bz), msg.ProposalTypeListTradingPair, initialDeposit, votingPeriod, sync, options...) 25 | } 26 | 27 | func (c *client) SubmitProposal(title string, description string, proposalType msg.ProposalKind, initialDeposit int64, votingPeriod time.Duration, sync bool, options ...Option) (*SubmitProposalResult, error) { 28 | fromAddr := c.keyManager.GetAddr() 29 | coins := ctypes.Coins{ctypes.Coin{Denom: types.NativeSymbol, Amount: initialDeposit}} 30 | proposalMsg := msg.NewMsgSubmitProposal(title, description, proposalType, fromAddr, coins, votingPeriod) 31 | commit, err := c.broadcastMsg(proposalMsg, sync, options...) 32 | if err != nil { 33 | return nil, err 34 | } 35 | var proposalId int64 36 | if commit.Ok && sync { 37 | // Todo since ap do not return proposal id now, do not return err 38 | proposalId, err = strconv.ParseInt(string(commit.Data), 10, 64) 39 | if err != nil { 40 | return nil, err 41 | } 42 | } 43 | return &SubmitProposalResult{*commit, proposalId}, err 44 | 45 | } 46 | -------------------------------------------------------------------------------- /common/types/proposal.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/x/gov" 5 | ) 6 | 7 | type ProposalKind = gov.ProposalKind 8 | 9 | // nolint 10 | const ( 11 | ProposalTypeNil = gov.ProposalTypeNil 12 | ProposalTypeText = gov.ProposalTypeText 13 | ProposalTypeParameterChange = gov.ProposalTypeParameterChange 14 | ProposalTypeSoftwareUpgrade = gov.ProposalTypeSoftwareUpgrade 15 | ProposalTypeListTradingPair = gov.ProposalTypeListTradingPair 16 | ProposalTypeFeeChange = gov.ProposalTypeFeeChange 17 | ProposalTypeCreateValidator = gov.ProposalTypeCreateValidator 18 | ProposalTypeRemoveValidator = gov.ProposalTypeRemoveValidator 19 | ProposalTypeDelistTradingPair = gov.ProposalTypeDelistTradingPair 20 | ProposalTypeManageChanPermission = gov.ProposalTypeManageChanPermission 21 | 22 | ProposalTypeSCParamsChange = gov.ProposalTypeSCParamsChange 23 | ProposalTypeCSCParamsChange = gov.ProposalTypeCSCParamsChange 24 | ) 25 | 26 | var ( 27 | ProposalTypeFromString = gov.ProposalTypeFromString 28 | ) 29 | 30 | type ProposalStatus = gov.ProposalStatus 31 | 32 | // nolint 33 | const ( 34 | StatusNil = gov.StatusNil 35 | StatusDepositPeriod = gov.StatusDepositPeriod 36 | StatusVotingPeriod = gov.StatusVotingPeriod 37 | StatusPassed = gov.StatusPassed 38 | StatusRejected = gov.StatusRejected 39 | StatusExecuted = gov.StatusExecuted 40 | ) 41 | 42 | var ( 43 | ProposalStatusFromString = gov.ProposalStatusFromString 44 | ) 45 | 46 | type ( 47 | TallyResult = gov.TallyResult 48 | Proposal = gov.Proposal 49 | TextProposal = gov.TextProposal 50 | BaseParams = gov.BaseParams 51 | QueryProposalsParams = gov.QueryProposalsParams 52 | QueryProposalParams = gov.QueryProposalParams 53 | ) 54 | -------------------------------------------------------------------------------- /common/types/nodeinfo.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/tendermint/tendermint/libs/common" 7 | ) 8 | 9 | type ResultStatus struct { 10 | NodeInfo NodeInfo `json:"node_info"` 11 | SyncInfo SyncInfo `json:"sync_info"` 12 | ValidatorInfo ValidatorInfo `json:"validator_info"` 13 | } 14 | 15 | type NodeInfo struct { 16 | // Authenticate 17 | // TODO: replace with NetAddress 18 | ID string `json:"id"` // authenticated identifier 19 | ListenAddr string `json:"listen_addr"` // accepting incoming 20 | 21 | // Check compatibility. 22 | // Channels are HexBytes so easier to read as JSON 23 | Network string `json:"network"` // network/chain ID 24 | Version string `json:"version"` // major.minor.revision 25 | Channels common.HexBytes `json:"channels"` // channels this node knows about 26 | 27 | // ASCIIText fields 28 | Moniker string `json:"moniker"` // arbitrary moniker 29 | Other NodeInfoOther `json:"other"` // other application specific data 30 | } 31 | 32 | type ValidatorInfo struct { 33 | Address common.HexBytes `json:"address"` 34 | PubKey []uint8 `json:"pub_key"` 35 | VotingPower int64 `json:"voting_power"` 36 | } 37 | type SyncInfo struct { 38 | LatestBlockHash common.HexBytes `json:"latest_block_hash"` 39 | LatestAppHash common.HexBytes `json:"latest_app_hash"` 40 | LatestBlockHeight int64 `json:"latest_block_height"` 41 | LatestBlockTime time.Time `json:"latest_block_time"` 42 | CatchingUp bool `json:"catching_up"` 43 | } 44 | 45 | type NodeInfoOther struct { 46 | AminoVersion string `json:"amino_version"` 47 | P2PVersion string `json:"p2p_version"` 48 | ConsensusVersion string `json:"consensus_version"` 49 | RPCVersion string `json:"rpc_version"` 50 | TxIndex string `json:"tx_index"` 51 | RPCAddress string `json:"rpc_address"` 52 | } 53 | -------------------------------------------------------------------------------- /types/msg/utils.go: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import ( 4 | "fmt" 5 | "github.com/cosmos/cosmos-sdk/bsc/rlp" 6 | 7 | "github.com/bnb-chain/go-sdk/common/types" 8 | "github.com/bnb-chain/node/plugins/tokens/swap" 9 | cTypes "github.com/cosmos/cosmos-sdk/types" 10 | ) 11 | 12 | var ( 13 | SortJSON = cTypes.SortJSON 14 | MustSortJSON = cTypes.MustSortJSON 15 | CalculateRandomHash = swap.CalculateRandomHash 16 | CalculateSwapID = swap.CalculateSwapID 17 | HexAddress = cTypes.HexAddress 18 | HexEncode = cTypes.HexEncode 19 | HexDecode = cTypes.HexDecode 20 | Has0xPrefix = cTypes.Has0xPrefix 21 | ) 22 | 23 | func noneExistPackageProto() interface{} { 24 | panic("should not exist such package") 25 | } 26 | 27 | func ParseClaimPayload(payload []byte) ([]CrossChainPackage, error) { 28 | packages := Packages{} 29 | err := rlp.DecodeBytes(payload, &packages) 30 | if err != nil { 31 | return nil, err 32 | } 33 | decodedPackage := make([]CrossChainPackage, 0, len(packages)) 34 | for _, pack := range packages { 35 | ptype, relayerFee, err := DecodePackageHeader(pack.Payload) 36 | if err != nil { 37 | return nil, err 38 | } 39 | if _, exist := protoMetrics[pack.ChannelId]; !exist { 40 | return nil, fmt.Errorf("channnel id do not exist") 41 | } 42 | proto, exist := protoMetrics[pack.ChannelId][ptype] 43 | if !exist || proto == nil { 44 | return nil, fmt.Errorf("package type do not exist") 45 | } 46 | content := proto() 47 | err = rlp.DecodeBytes(pack.Payload[PackageHeaderLength:], content) 48 | if err != nil { 49 | return nil, err 50 | } 51 | decodedPackage = append(decodedPackage, CrossChainPackage{ 52 | PackageType: ptype, 53 | RelayFee: relayerFee, 54 | Content: content, 55 | }) 56 | } 57 | return decodedPackage, nil 58 | } 59 | 60 | func CreateSendMsg(from types.AccAddress, fromCoins types.Coins, transfers []Transfer) SendMsg { 61 | input := NewInput(from, fromCoins) 62 | 63 | output := make([]Output, 0, len(transfers)) 64 | for _, t := range transfers { 65 | t.Coins = t.Coins.Sort() 66 | output = append(output, NewOutput(t.ToAddr, t.Coins)) 67 | } 68 | msg := NewMsgSend([]Input{input}, output) 69 | return msg 70 | } 71 | -------------------------------------------------------------------------------- /example/ledger-keys/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/bnb-chain/go-sdk/client" 8 | "github.com/bnb-chain/go-sdk/common/ledger" 9 | "github.com/bnb-chain/go-sdk/common/types" 10 | "github.com/bnb-chain/go-sdk/keys" 11 | "github.com/bnb-chain/go-sdk/types/msg" 12 | ) 13 | 14 | // To run this example, please make sure your key address have more than 1:BNB on testnet 15 | func main() { 16 | types.SetNetwork(types.TestNetwork) 17 | 18 | //Check whether there are variable ledger devices 19 | ledgerDevice, err := ledger.DiscoverLedger() 20 | if err != nil { 21 | fmt.Println(fmt.Sprintf("Failed to find ledger device: %s", err.Error())) 22 | return 23 | } 24 | err = ledgerDevice.Close() 25 | if err != nil { 26 | fmt.Println(fmt.Sprintf("Failed to find ledger device: %s", err.Error())) 27 | return 28 | } 29 | 30 | bip44Params := keys.NewBinanceBIP44Params(0, 0) 31 | keyManager, err := keys.NewLedgerKeyManager(bip44Params.DerivationPath()) 32 | if err != nil { 33 | fmt.Println(err.Error()) 34 | return 35 | } 36 | 37 | receiverAddr, err := types.AccAddressFromBech32("tbnb15339dcwlq5nza4atfmqxfx6mhamywz35he2cvv") 38 | if err != nil { 39 | fmt.Println(err.Error()) 40 | return 41 | } 42 | 43 | dexClient, err := client.NewDexClient("testnet-dex.binance.org:443", types.TestNetwork, keyManager) 44 | if err != nil { 45 | fmt.Println(err.Error()) 46 | return 47 | } 48 | 49 | account, err := dexClient.GetAccount(keyManager.GetAddr().String()) 50 | if err != nil { 51 | fmt.Println(err.Error()) 52 | return 53 | } 54 | 55 | floatAmount := 0.0 56 | for _, coin := range account.Balances { 57 | if coin.Symbol == "BNB" { 58 | fmt.Println(fmt.Sprintf("Your account has %s:BNB", coin.Free)) 59 | floatAmount, err = strconv.ParseFloat(coin.Free.String(), 64) 60 | if err != nil { 61 | fmt.Println(err.Error()) 62 | return 63 | } 64 | break 65 | } 66 | } 67 | if floatAmount <= 1.0 { 68 | fmt.Println("Your account doesn't have enough bnb") 69 | } 70 | 71 | fmt.Println(fmt.Sprintf("Please verify sign key address (%s) and transaction data", types.AccAddress(keyManager.GetAddr()).String())) 72 | sendResult, err := dexClient.SendToken([]msg.Transfer{{receiverAddr, types.Coins{types.Coin{Denom: "BNB", Amount: 10000000}}}}, true) 73 | if err != nil { 74 | fmt.Println(err.Error()) 75 | return 76 | } 77 | fmt.Println(fmt.Sprintf("Send result: %t", sendResult.Ok)) 78 | } 79 | -------------------------------------------------------------------------------- /client/transaction/htlc.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/common/types" 5 | "github.com/bnb-chain/go-sdk/types/msg" 6 | "github.com/bnb-chain/go-sdk/types/tx" 7 | ) 8 | 9 | type HTLTResult struct { 10 | tx.TxCommitResult 11 | } 12 | 13 | func (c *client) HTLT(recipient types.AccAddress, recipientOtherChain, senderOtherChain string, randomNumberHash []byte, timestamp int64, 14 | amount types.Coins, expectedIncome string, heightSpan int64, crossChain bool, sync bool, options ...Option) (*HTLTResult, error) { 15 | fromAddr := c.keyManager.GetAddr() 16 | htltMsg := msg.NewHTLTMsg( 17 | fromAddr, 18 | recipient, 19 | recipientOtherChain, 20 | senderOtherChain, 21 | randomNumberHash, 22 | timestamp, 23 | amount, 24 | expectedIncome, 25 | heightSpan, 26 | crossChain, 27 | ) 28 | commit, err := c.broadcastMsg(htltMsg, sync, options...) 29 | if err != nil { 30 | return nil, err 31 | } 32 | return &HTLTResult{*commit}, nil 33 | } 34 | 35 | type DepositHTLTResult struct { 36 | tx.TxCommitResult 37 | } 38 | 39 | func (c *client) DepositHTLT(swapID []byte, amount types.Coins, 40 | sync bool, options ...Option) (*DepositHTLTResult, error) { 41 | fromAddr := c.keyManager.GetAddr() 42 | depositHTLTMsg := msg.NewDepositHTLTMsg( 43 | fromAddr, 44 | amount, 45 | swapID, 46 | ) 47 | commit, err := c.broadcastMsg(depositHTLTMsg, sync, options...) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return &DepositHTLTResult{*commit}, nil 52 | } 53 | 54 | type ClaimHTLTResult struct { 55 | tx.TxCommitResult 56 | } 57 | 58 | func (c *client) ClaimHTLT(swapID []byte, randomNumber []byte, sync bool, options ...Option) (*ClaimHTLTResult, error) { 59 | fromAddr := c.keyManager.GetAddr() 60 | claimHTLTMsg := msg.NewClaimHTLTMsg( 61 | fromAddr, 62 | swapID, 63 | randomNumber, 64 | ) 65 | commit, err := c.broadcastMsg(claimHTLTMsg, sync, options...) 66 | if err != nil { 67 | return nil, err 68 | } 69 | return &ClaimHTLTResult{*commit}, nil 70 | } 71 | 72 | type RefundHTLTResult struct { 73 | tx.TxCommitResult 74 | } 75 | 76 | func (c *client) RefundHTLT(swapID []byte, sync bool, options ...Option) (*RefundHTLTResult, error) { 77 | fromAddr := c.keyManager.GetAddr() 78 | refundHTLTMsg := msg.NewRefundHTLTMsg( 79 | fromAddr, 80 | swapID, 81 | ) 82 | commit, err := c.broadcastMsg(refundHTLTMsg, sync, options...) 83 | if err != nil { 84 | return nil, err 85 | } 86 | return &RefundHTLTResult{*commit}, nil 87 | } 88 | -------------------------------------------------------------------------------- /client/transaction/time_lock.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/bnb-chain/go-sdk/common/types" 7 | "github.com/bnb-chain/go-sdk/types/msg" 8 | "github.com/bnb-chain/go-sdk/types/tx" 9 | ) 10 | 11 | type TimeLockResult struct { 12 | tx.TxCommitResult 13 | LockId int64 `json:"lock_id"` 14 | } 15 | 16 | func (c *client) TimeLock(description string, amount types.Coins, lockTime int64, sync bool, options ...Option) (*TimeLockResult, error) { 17 | fromAddr := c.keyManager.GetAddr() 18 | 19 | lockMsg := msg.NewTimeLockMsg(fromAddr, description, amount, lockTime) 20 | commit, err := c.broadcastMsg(lockMsg, sync, options...) 21 | if err != nil { 22 | return nil, err 23 | } 24 | var lockId int64 25 | if commit.Ok && sync { 26 | lockId, err = strconv.ParseInt(string(commit.Data), 10, 64) 27 | if err != nil { 28 | return nil, err 29 | } 30 | } 31 | return &TimeLockResult{*commit, lockId}, err 32 | } 33 | 34 | type TimeUnLockResult struct { 35 | tx.TxCommitResult 36 | LockId int64 `json:"lock_id"` 37 | } 38 | 39 | func (c *client) TimeUnLock(id int64, sync bool, options ...Option) (*TimeUnLockResult, error) { 40 | fromAddr := c.keyManager.GetAddr() 41 | 42 | unlockMsg := msg.NewTimeUnlockMsg(fromAddr, id) 43 | err := unlockMsg.ValidateBasic() 44 | if err != nil { 45 | return nil, err 46 | } 47 | commit, err2 := c.broadcastMsg(unlockMsg, sync, options...) 48 | if err2 != nil { 49 | return nil, err2 50 | } 51 | var lockId int64 52 | if commit.Ok && sync { 53 | lockId, err2 = strconv.ParseInt(string(commit.Data), 10, 64) 54 | if err2 != nil { 55 | return nil, err2 56 | } 57 | } 58 | return &TimeUnLockResult{*commit, lockId}, nil 59 | } 60 | 61 | type TimeReLockResult struct { 62 | tx.TxCommitResult 63 | LockId int64 `json:"lock_id"` 64 | } 65 | 66 | func (c *client) TimeReLock(id int64, description string, amount types.Coins, lockTime int64, sync bool, options ...Option) (*TimeReLockResult, error) { 67 | fromAddr := c.keyManager.GetAddr() 68 | 69 | relockMsg := msg.NewTimeRelockMsg(fromAddr, id, description, amount, lockTime) 70 | err := relockMsg.ValidateBasic() 71 | if err != nil { 72 | return nil, err 73 | } 74 | commit, err2 := c.broadcastMsg(relockMsg, sync, options...) 75 | if err2 != nil { 76 | return nil, err2 77 | } 78 | var lockId int64 79 | if commit.Ok && sync { 80 | lockId, err2 = strconv.ParseInt(string(commit.Data), 10, 64) 81 | if err2 != nil { 82 | return nil, err2 83 | } 84 | } 85 | return &TimeReLockResult{*commit, lockId}, nil 86 | } 87 | -------------------------------------------------------------------------------- /common/uuid/uuid.go: -------------------------------------------------------------------------------- 1 | package uuid 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | ) 7 | 8 | // Size of a UUID in bytes. 9 | const Size = 16 10 | 11 | // UUID representation compliant with specification 12 | // described in RFC 4122. 13 | type UUID [Size]byte 14 | 15 | // UUID versions 16 | const ( 17 | _ byte = iota 18 | V1 19 | V2 20 | V3 21 | V4 22 | V5 23 | ) 24 | 25 | // UUID layout variants. 26 | const ( 27 | VariantNCS byte = iota 28 | VariantRFC4122 29 | VariantMicrosoft 30 | VariantFuture 31 | ) 32 | 33 | // UUID DCE domains. 34 | const ( 35 | DomainPerson = iota 36 | DomainGroup 37 | DomainOrg 38 | ) 39 | 40 | // String parse helpers. 41 | var ( 42 | urnPrefix = []byte("urn:uuid:") 43 | byteGroups = []int{8, 4, 4, 4, 12} 44 | ) 45 | 46 | // Nil is special form of UUID that is specified to have all 47 | // 128 bits set to zero. 48 | var Nil = UUID{} 49 | 50 | // Predefined namespace UUIDs. 51 | var ( 52 | NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) 53 | NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) 54 | NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) 55 | NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) 56 | ) 57 | 58 | // Equal returns true if u1 and u2 equals, otherwise returns false. 59 | func Equal(u1 UUID, u2 UUID) bool { 60 | return bytes.Equal(u1[:], u2[:]) 61 | } 62 | 63 | // Version returns algorithm version used to generate UUID. 64 | func (u UUID) Version() byte { 65 | return u[6] >> 4 66 | } 67 | 68 | // Variant returns UUID layout variant. 69 | func (u UUID) Variant() byte { 70 | switch { 71 | case (u[8] >> 7) == 0x00: 72 | return VariantNCS 73 | case (u[8] >> 6) == 0x02: 74 | return VariantRFC4122 75 | case (u[8] >> 5) == 0x06: 76 | return VariantMicrosoft 77 | case (u[8] >> 5) == 0x07: 78 | fallthrough 79 | default: 80 | return VariantFuture 81 | } 82 | } 83 | 84 | // Bytes returns bytes slice representation of UUID. 85 | func (u UUID) Bytes() []byte { 86 | return u[:] 87 | } 88 | 89 | // Returns canonical string representation of UUID: 90 | // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. 91 | func (u UUID) String() string { 92 | buf := make([]byte, 36) 93 | 94 | hex.Encode(buf[0:8], u[0:4]) 95 | buf[8] = '-' 96 | hex.Encode(buf[9:13], u[4:6]) 97 | buf[13] = '-' 98 | hex.Encode(buf[14:18], u[6:8]) 99 | buf[18] = '-' 100 | hex.Encode(buf[19:23], u[8:10]) 101 | buf[23] = '-' 102 | hex.Encode(buf[24:], u[10:]) 103 | 104 | return string(buf) 105 | } 106 | 107 | // SetVersion sets version bits. 108 | func (u *UUID) SetVersion(v byte) { 109 | u[6] = (u[6] & 0x0f) | (v << 4) 110 | } 111 | 112 | // SetVariant sets variant bits. 113 | func (u *UUID) SetVariant(v byte) { 114 | switch v { 115 | case VariantNCS: 116 | u[8] = (u[8]&(0xff>>1) | (0x00 << 7)) 117 | case VariantRFC4122: 118 | u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) 119 | case VariantMicrosoft: 120 | u[8] = (u[8]&(0xff>>3) | (0x06 << 5)) 121 | case VariantFuture: 122 | fallthrough 123 | default: 124 | u[8] = (u[8]&(0xff>>3) | (0x07 << 5)) 125 | } 126 | } 127 | 128 | // Must is a helper that wraps a call to a function returning (UUID, error) 129 | // and panics if the error is non-nil. It is intended for use in variable 130 | // initializations such as 131 | // var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")); 132 | func Must(u UUID, err error) UUID { 133 | if err != nil { 134 | panic(err) 135 | } 136 | return u 137 | } 138 | -------------------------------------------------------------------------------- /common/ledger/ledger_secp256k1.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "github.com/btcsuite/btcd/btcec/v2" 5 | "github.com/btcsuite/btcd/btcec/v2/ecdsa" 6 | stypes "github.com/cosmos/cosmos-sdk/types" 7 | tmbtcec "github.com/tendermint/btcd/btcec" 8 | "github.com/tendermint/tendermint/crypto" 9 | "github.com/tendermint/tendermint/crypto/secp256k1" 10 | ledgergo "github.com/zondax/ledger-cosmos-go" 11 | "math/big" 12 | ) 13 | 14 | var ( 15 | // discoverLedger defines a function to be invoked at runtime for discovering 16 | // a connected Ledger device. 17 | DiscoverLedger discoverLedgerFn 18 | ) 19 | 20 | type ( 21 | 22 | // discoverLedgerFn defines a Ledger discovery function that returns a 23 | // connected device or an error upon failure. Its allows a method to avoid CGO 24 | // dependencies when Ledger support is potentially not enabled. 25 | discoverLedgerFn func() (LedgerSecp256k1, error) 26 | 27 | // DerivationPath represents a Ledger derivation path. 28 | DerivationPath []uint32 29 | 30 | // LedgerSecp256k1 reflects an interface a Ledger API must implement for 31 | // the SECP256K1 scheme. 32 | LedgerSecp256k1 interface { 33 | GetPublicKeySECP256K1([]uint32) ([]byte, error) 34 | ShowAddressSECP256K1([]uint32, string) error 35 | SignSECP256K1([]uint32, []byte) ([]byte, error) 36 | GetVersion() (*ledgergo.VersionInfo, error) 37 | Close() error 38 | } 39 | 40 | // PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano we 41 | // cache the PubKey from the first call to use it later. 42 | PrivKeyLedgerSecp256k1 struct { 43 | crypto.PrivKey 44 | pubkey secp256k1.PubKeySecp256k1 45 | path DerivationPath 46 | ledger LedgerSecp256k1 47 | } 48 | ) 49 | 50 | func GenLedgerSecp256k1Key(path DerivationPath, device LedgerSecp256k1) (*PrivKeyLedgerSecp256k1, error) { 51 | var pk secp256k1.PubKeySecp256k1 52 | pubkey, err := device.GetPublicKeySECP256K1(path) 53 | if err != nil { 54 | return nil, err 55 | } 56 | // re-serialize in the 33-byte compressed format 57 | cmp, err := btcec.ParsePubKey(pubkey[:]) 58 | if err != nil { 59 | return nil, err 60 | } 61 | copy(pk[:], cmp.SerializeCompressed()) 62 | 63 | privKey := PrivKeyLedgerSecp256k1{path: path, ledger: device, pubkey: pk} 64 | return &privKey, nil 65 | } 66 | 67 | func (pkl PrivKeyLedgerSecp256k1) Bytes() []byte { 68 | return nil 69 | } 70 | 71 | func (pkl PrivKeyLedgerSecp256k1) ShowSignAddr() error { 72 | return pkl.ledger.ShowAddressSECP256K1(pkl.path, stypes.GetConfig().GetBech32AccountAddrPrefix()) 73 | } 74 | 75 | func (pkl PrivKeyLedgerSecp256k1) Sign(msg []byte) ([]byte, error) { 76 | err := pkl.ShowSignAddr() 77 | if err != nil { 78 | return nil, err 79 | } 80 | sig, err := pkl.ledger.SignSECP256K1(pkl.path, msg) 81 | if err != nil { 82 | return nil, err 83 | } 84 | return convertDERtoBER(sig) 85 | } 86 | 87 | func (pkl PrivKeyLedgerSecp256k1) PubKey() crypto.PubKey { 88 | return pkl.pubkey 89 | } 90 | 91 | func (pkl PrivKeyLedgerSecp256k1) Equals(other crypto.PrivKey) bool { 92 | if ledger, ok := other.(*PrivKeyLedgerSecp256k1); ok { 93 | return pkl.PubKey().Equals(ledger.PubKey()) 94 | } 95 | 96 | return false 97 | } 98 | 99 | func convertDERtoBER(signatureDER []byte) ([]byte, error) { 100 | sigDER, err := ecdsa.ParseDERSignature(signatureDER[:]) 101 | if err != nil { 102 | return nil, err 103 | } 104 | sig := sigDER.Serialize() // 0x30 0x02 0x02 105 | r := new(big.Int).SetBytes(sig[4:36]) 106 | s := new(big.Int).SetBytes(sig[38:70]) 107 | sigBER := tmbtcec.Signature{R: r, S: s} 108 | return sigBER.Serialize(), nil 109 | } 110 | -------------------------------------------------------------------------------- /keys/keystore.go: -------------------------------------------------------------------------------- 1 | package keys 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "crypto/sha256" 8 | "encoding/hex" 9 | "errors" 10 | "fmt" 11 | "golang.org/x/crypto/pbkdf2" 12 | "golang.org/x/crypto/sha3" 13 | ) 14 | 15 | var ( 16 | ErrDecrypt = errors.New("could not decrypt key with given passphrase") 17 | ) 18 | 19 | type PlainKeyJSON struct { 20 | Address string `json:"address"` 21 | PrivateKey string `json:"privatekey"` 22 | Id string `json:"id"` 23 | Version int `json:"version"` 24 | } 25 | 26 | type EncryptedKeyJSON struct { 27 | Address string `json:"address"` 28 | Crypto CryptoJSON `json:"crypto"` 29 | Id string `json:"id"` 30 | Version int `json:"version"` 31 | } 32 | type CryptoJSON struct { 33 | Cipher string `json:"cipher"` 34 | CipherText string `json:"ciphertext"` 35 | CipherParams cipherparamsJSON `json:"cipherparams"` 36 | KDF string `json:"kdf"` 37 | KDFParams map[string]interface{} `json:"kdfparams"` 38 | MAC string `json:"mac"` 39 | } 40 | 41 | type cipherparamsJSON struct { 42 | IV string `json:"iv"` 43 | } 44 | 45 | func decryptKey(keyProtected *EncryptedKeyJSON, auth string) ([]byte, error) { 46 | mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 57 | if err != nil { 58 | return nil, err 59 | } 60 | derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | bufferValue := make([]byte, len(cipherText)+16) 66 | copy(bufferValue[0:16], derivedKey[16:32]) 67 | copy(bufferValue[16:], cipherText[:]) 68 | hasher := sha3.NewLegacyKeccak512() 69 | _, err = hasher.Write([]byte(bufferValue)) 70 | if err != nil { 71 | return nil, err 72 | } 73 | calculatedMAC := hasher.Sum(nil) 74 | if !bytes.Equal(calculatedMAC[:], mac) { 75 | // to compatible previous sha256 algorithm 76 | calculatedMAC256 := sha256.Sum256([]byte((bufferValue))) 77 | if !bytes.Equal(calculatedMAC256[:], mac) { 78 | return nil, ErrDecrypt 79 | } 80 | calculatedMAC = calculatedMAC256[:] 81 | } 82 | plainText, err := aesCTRXOR(derivedKey[:32], cipherText, iv) 83 | if err != nil { 84 | return nil, err 85 | } 86 | return plainText, err 87 | } 88 | 89 | func getKDFKey(cryptoJSON CryptoJSON, auth string) ([]byte, error) { 90 | authArray := []byte(auth) 91 | salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) 92 | if err != nil { 93 | return nil, err 94 | } 95 | dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) 96 | 97 | if cryptoJSON.KDF == "pbkdf2" { 98 | c := ensureInt(cryptoJSON.KDFParams["c"]) 99 | prf := cryptoJSON.KDFParams["prf"].(string) 100 | if prf != "hmac-sha256" { 101 | return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) 102 | } 103 | key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) 104 | return key, nil 105 | } 106 | return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) 107 | } 108 | 109 | func ensureInt(x interface{}) int { 110 | res, ok := x.(int) 111 | if !ok { 112 | res = int(x.(float64)) 113 | } 114 | return res 115 | } 116 | 117 | func aesCTRXOR(key, inText, iv []byte) ([]byte, error) { 118 | // AES-128 is selected due to size of encryptKey. 119 | aesBlock, err := aes.NewCipher(key) 120 | if err != nil { 121 | return nil, err 122 | } 123 | stream := cipher.NewCTR(aesBlock, iv) 124 | outText := make([]byte, len(inText)) 125 | stream.XORKeyStream(outText, inText) 126 | return outText, err 127 | } 128 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.3.2 4 | FEATURE 5 | * [\#183](https://github.com/bnb-chain/go-sdk/pull/183) feat: implement bep126 queries 6 | 7 | ## 1.3.1 8 | IMPROVEMENT 9 | * [\#178](https://github.com/bnb-chain/go-sdk/pull/178) dep: bump the version of btcd to v2.3.2 10 | 11 | 12 | ## 1.3.0 13 | IMPROVEMENT 14 | * [\#170](https://github.com/bnb-chain/go-sdk/pull/170) types: set the types to the origin package alias and remove trade client 15 | 16 | ## 1.2.9 17 | IMPROVEMENT 18 | * [\#168](https://github.com/bnb-chain/go-sdk/pull/168) type: add more oracle claim type 19 | 20 | ## 1.2.8 21 | FEATURE 22 | * [\#164](https://github.com/bnb-chain/go-sdk/pull/164) feat: impl bep159 txs cli and queries 23 | 24 | ## 1.2.7 25 | * [\#160](https://github.com/bnb-chain/go-sdk/pull/160) [RPC] Support minimal 0.1 BNB staking 26 | 27 | ## 1.2.6 28 | CHAIN UPGRADE 29 | * [\#144](https://github.com/bnb-chain/go-sdk/pull/144) [RPC] [API] Support for the transfer of token ownership, and change the minimum token symbol length 30 | 31 | ## 1.2.5 32 | IMPROVEMENT 33 | * [\#142](https://github.com/bnb-chain/go-sdk/pull/142) [RPC] [API] add contract info for a token if there is any 34 | 35 | ## 1.2.4 36 | CHAIN UPGRADE 37 | * [\#132](https://github.com/bnb-chain/go-sdk/pull/132) [RPC] [API] enable side chain governance transaction 38 | * [\#133](https://github.com/bnb-chain/go-sdk/pull/133) [RPC] [API] enable side chain unbind transaction, and modify the structure of claimMsg 39 | * [\#136](https://github.com/bnb-chain/go-sdk/pull/136) [TX] [TOOL] add utils to parse Claim payload to human readable interface 40 | 41 | ## 1.2.3 42 | CHAIN UPGRADE 43 | * [\#110](https://github.com/bnb-chain/go-sdk/pull/110) [RPC] [API] Add pending_match flag 44 | * [\#130](https://github.com/bnb-chain/go-sdk/pull/130) [RPC] [API] Support Mini Token 45 | ## 1.2.2 46 | * [\#106](https://github.com/bnb-chain/go-sdk/pull/106) [RPC] fix nil point error in getBalance rpc call 47 | * [\#103](https://github.com/bnb-chain/go-sdk/pull/103) [RPC] change the default timeout of RPC client as 5 seconds 48 | * [\#102](https://github.com/bnb-chain/go-sdk/pull/102) [FIX] Some typos only (managr/manger) 49 | 50 | ## 1.2.1 51 | * [\#99](https://github.com/bnb-chain/go-sdk/pull/99) [BUILD] upgrade version of btcd to avoid retag issue 52 | 53 | ## v1.2.0 54 | * [\#93](https://github.com/bnb-chain/go-sdk/pull/93) [BREAKING] uprade to BNB Chain release 0.6.3 55 | 56 | ## v1.1.3 57 | * [\#81](https://github.com/bnb-chain/go-sdk/pull/81) [TX] support swap on a single chain 58 | 59 | 60 | ## v1.1.2 61 | * [\#88](https://github.com/bnb-chain/go-sdk/pull/88) [RPC] wrap error for abci query when abci code is not 0 62 | 63 | ## v1.1.1 64 | IMPROVEMENT 65 | * [\#87](https://github.com/bnb-chain/go-sdk/pull/87) [RPC] distinguish not found error for get timelock rpc 66 | * [\#84](https://github.com/bnb-chain/go-sdk/pull/84) [RPC] change interface of get timelock 67 | 68 | 69 | ## v1.1.0 70 | IMPROVEMENT 71 | * [\#82](https://github.com/bnb-chain/go-sdk/pull/82) [RPC] refactor reconnection 72 | 73 | ## v1.0.9 74 | 75 | FEATURES 76 | * [\#71](https://github.com/bnb-chain/go-sdk/pull/71) [RPC] add timelock query support 77 | * [\#73](https://github.com/bnb-chain/go-sdk/pull/73) [RPC] add limit param to get depth api for RPC 78 | 79 | 80 | ## v1.0.8 81 | IMPROVEMENTS 82 | * [\#53](https://github.com/bnb-chain/go-sdk/pull/53) [SOURCE] change the default source into 0 83 | * [\#56](https://github.com/bnb-chain/go-sdk/pull/56) [RPC] add reconnect strategy when timeout to receive response 84 | * [\#61](https://github.com/bnb-chain/go-sdk/pull/61) [KEY] support bip44 to derive many address from same seed phase 85 | 86 | FEATURES 87 | * [\#66](https://github.com/bnb-chain/go-sdk/pull/66) [API] support set account flag transaction 88 | * [\#70](https://github.com/bnb-chain/go-sdk/pull/70) [API] support atomic swap transactions 89 | 90 | BREAKING 91 | * [\#57](https://github.com/bnb-chain/go-sdk/pull/57) [API] add query option to getTokens api 92 | -------------------------------------------------------------------------------- /types/msg/wire.go: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import ( 4 | "github.com/tendermint/go-amino" 5 | ) 6 | 7 | var MsgCdc = amino.NewCodec() 8 | 9 | func RegisterCodec(cdc *amino.Codec) { 10 | 11 | cdc.RegisterInterface((*Msg)(nil), nil) 12 | 13 | cdc.RegisterConcrete(SideChainSubmitProposalMsg{}, "cosmos-sdk/MsgSideChainSubmitProposal", nil) 14 | cdc.RegisterConcrete(SideChainDepositMsg{}, "cosmos-sdk/MsgSideChainDeposit", nil) 15 | cdc.RegisterConcrete(SideChainVoteMsg{}, "cosmos-sdk/MsgSideChainVote", nil) 16 | 17 | cdc.RegisterInterface((*SCParam)(nil), nil) 18 | cdc.RegisterConcrete(&OracleParams{}, "params/OracleParamSet", nil) 19 | cdc.RegisterConcrete(&StakeParams{}, "params/StakeParamSet", nil) 20 | cdc.RegisterConcrete(&SlashParams{}, "params/SlashParamSet", nil) 21 | cdc.RegisterConcrete(&IbcParams{}, "params/IbcParamSet", nil) 22 | 23 | cdc.RegisterConcrete(CreateOrderMsg{}, "dex/NewOrder", nil) 24 | cdc.RegisterConcrete(CancelOrderMsg{}, "dex/CancelOrder", nil) 25 | cdc.RegisterConcrete(TokenIssueMsg{}, "tokens/IssueMsg", nil) 26 | cdc.RegisterConcrete(TokenBurnMsg{}, "tokens/BurnMsg", nil) 27 | cdc.RegisterConcrete(TransferOwnershipMsg{}, "tokens/TransferOwnershipMsg", nil) 28 | 29 | cdc.RegisterConcrete(TimeLockMsg{}, "tokens/TimeLockMsg", nil) 30 | cdc.RegisterConcrete(TokenFreezeMsg{}, "tokens/FreezeMsg", nil) 31 | cdc.RegisterConcrete(TokenUnfreezeMsg{}, "tokens/UnfreezeMsg", nil) 32 | 33 | cdc.RegisterConcrete(TimeUnlockMsg{}, "tokens/TimeUnlockMsg", nil) 34 | cdc.RegisterConcrete(TimeRelockMsg{}, "tokens/TimeRelockMsg", nil) 35 | 36 | cdc.RegisterConcrete(HTLTMsg{}, "tokens/HTLTMsg", nil) 37 | cdc.RegisterConcrete(DepositHTLTMsg{}, "tokens/DepositHTLTMsg", nil) 38 | cdc.RegisterConcrete(ClaimHTLTMsg{}, "tokens/ClaimHTLTMsg", nil) 39 | cdc.RegisterConcrete(RefundHTLTMsg{}, "tokens/RefundHTLTMsg", nil) 40 | 41 | cdc.RegisterConcrete(DexListMsg{}, "dex/ListMsg", nil) 42 | cdc.RegisterConcrete(MintMsg{}, "tokens/MintMsg", nil) 43 | //Must use cosmos-sdk. 44 | cdc.RegisterConcrete(SendMsg{}, "cosmos-sdk/Send", nil) 45 | 46 | cdc.RegisterConcrete(SubmitProposalMsg{}, "cosmos-sdk/MsgSubmitProposal", nil) 47 | cdc.RegisterConcrete(DepositMsg{}, "cosmos-sdk/MsgDeposit", nil) 48 | cdc.RegisterConcrete(VoteMsg{}, "cosmos-sdk/MsgVote", nil) 49 | 50 | cdc.RegisterConcrete(SetAccountFlagsMsg{}, "scripts/SetAccountFlagsMsg", nil) 51 | 52 | cdc.RegisterConcrete(MsgCreateValidatorOpen{}, "cosmos-sdk/MsgCreateValidatorOpen", nil) 53 | cdc.RegisterConcrete(MsgRemoveValidator{}, "cosmos-sdk/MsgRemoveValidator", nil) 54 | cdc.RegisterConcrete(MsgEditValidator{}, "cosmos-sdk/MsgEditValidator", nil) 55 | cdc.RegisterConcrete(MsgDelegate{}, "cosmos-sdk/MsgDelegate", nil) 56 | cdc.RegisterConcrete(MsgRedelegate{}, "cosmos-sdk/MsgRedelegate", nil) 57 | cdc.RegisterConcrete(MsgUndelegate{}, "cosmos-sdk/MsgUndelegate", nil) 58 | cdc.RegisterConcrete(MsgSideChainStakeMigration{}, "cosmos-sdk/MsgSideChainStakeMigration", nil) 59 | 60 | cdc.RegisterConcrete(CreateSideChainValidatorMsg{}, "cosmos-sdk/MsgCreateSideChainValidator", nil) 61 | cdc.RegisterConcrete(MsgCreateSideChainValidatorWithVoteAddr{}, "cosmos-sdk/MsgCreateSideChainValidatorWithVoteAddr", nil) 62 | cdc.RegisterConcrete(EditSideChainValidatorMsg{}, "cosmos-sdk/MsgEditSideChainValidator", nil) 63 | cdc.RegisterConcrete(MsgEditSideChainValidatorWithVoteAddr{}, "cosmos-sdk/MsgEditSideChainValidatorWithVoteAddr", nil) 64 | cdc.RegisterConcrete(SideChainDelegateMsg{}, "cosmos-sdk/MsgSideChainDelegate", nil) 65 | cdc.RegisterConcrete(SideChainRedelegateMsg{}, "cosmos-sdk/MsgSideChainRedelegate", nil) 66 | cdc.RegisterConcrete(SideChainUndelegateMsg{}, "cosmos-sdk/MsgSideChainUndelegate", nil) 67 | cdc.RegisterConcrete(MsgSideChainUnjail{}, "cosmos-sdk/MsgSideChainUnjail", nil) 68 | cdc.RegisterConcrete(MsgUnjail{}, "cosmos-sdk/MsgUnjail", nil) 69 | 70 | cdc.RegisterConcrete(BindMsg{}, "bridge/BindMsg", nil) 71 | cdc.RegisterConcrete(TransferOutMsg{}, "bridge/TransferOutMsg", nil) 72 | cdc.RegisterConcrete(Claim{}, "oracle/Claim", nil) 73 | cdc.RegisterConcrete(Prophecy{}, "oracle/Prophecy", nil) 74 | cdc.RegisterConcrete(Status{}, "oracle/Status", nil) 75 | cdc.RegisterConcrete(DBProphecy{}, "oracle/DBProphecy", nil) 76 | cdc.RegisterConcrete(ClaimMsg{}, "oracle/ClaimMsg", nil) 77 | 78 | cdc.RegisterConcrete(MiniTokenIssueMsg{}, "tokens/IssueMiniMsg", nil) 79 | cdc.RegisterConcrete(TinyTokenIssueMsg{}, "tokens/IssueTinyMsg", nil) 80 | cdc.RegisterConcrete(SetURIMsg{}, "tokens/SetURIMsg", nil) 81 | cdc.RegisterConcrete(ListMiniMsg{}, "dex/ListMiniMsg", nil) 82 | } 83 | 84 | func init() { 85 | RegisterCodec(MsgCdc) 86 | } 87 | -------------------------------------------------------------------------------- /client/rpc/mock/client.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/bnb-chain/go-sdk/client/rpc" 7 | 8 | cmn "github.com/tendermint/tendermint/libs/common" 9 | "github.com/tendermint/tendermint/libs/log" 10 | "github.com/tendermint/tendermint/rpc/client" 11 | "github.com/tendermint/tendermint/rpc/core" 12 | ctypes "github.com/tendermint/tendermint/rpc/core/types" 13 | rpctypes "github.com/tendermint/tendermint/rpc/lib/types" 14 | "github.com/tendermint/tendermint/types" 15 | ) 16 | 17 | // Client wraps arbitrary implementations of the various interfaces. 18 | // 19 | // We provide a few choices to mock out each one in this package. 20 | // Nothing hidden here, so no New function, just construct it from 21 | // some parts, and swap them out them during the tests. 22 | type Client struct { 23 | cmn.Service 24 | rpc.ABCIClient 25 | rpc.SignClient 26 | client.HistoryClient 27 | client.StatusClient 28 | rpc.EventsClient 29 | rpc.DexClient 30 | rpc.OpsClient 31 | rpc.StakingClient 32 | } 33 | 34 | var _ rpc.Client = Client{} 35 | 36 | // Call is used by recorders to save a call and response. 37 | // It can also be used to configure mock responses. 38 | // 39 | type Call struct { 40 | Name string 41 | Args interface{} 42 | Response interface{} 43 | Error error 44 | } 45 | 46 | // GetResponse will generate the apporiate response for us, when 47 | // using the Call struct to configure a Mock handler. 48 | // 49 | // When configuring a response, if only one of Response or Error is 50 | // set then that will always be returned. If both are set, then 51 | // we return Response if the Args match the set args, Error otherwise. 52 | func (c Call) GetResponse(args interface{}) (interface{}, error) { 53 | // handle the case with no response 54 | if c.Response == nil { 55 | if c.Error == nil { 56 | panic("Misconfigured call, you must set either Response or Error") 57 | } 58 | return nil, c.Error 59 | } 60 | // response without error 61 | if c.Error == nil { 62 | return c.Response, nil 63 | } 64 | // have both, we must check args.... 65 | if reflect.DeepEqual(args, c.Args) { 66 | return c.Response, nil 67 | } 68 | return nil, c.Error 69 | } 70 | 71 | func (c Client) Status() (*ctypes.ResultStatus, error) { 72 | return core.Status(&rpctypes.Context{}) 73 | } 74 | 75 | func (c Client) ABCIInfo() (*ctypes.ResultABCIInfo, error) { 76 | return core.ABCIInfo(&rpctypes.Context{}) 77 | } 78 | 79 | func (c Client) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) { 80 | return c.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions) 81 | } 82 | 83 | func (c Client) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 84 | return core.ABCIQuery(&rpctypes.Context{}, path, data, opts.Height, opts.Prove) 85 | } 86 | 87 | func (c Client) BroadcastTxCommit(tx types.Tx) (*rpc.ResultBroadcastTxCommit, error) { 88 | return &rpc.ResultBroadcastTxCommit{}, nil 89 | } 90 | 91 | func (c Client) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 92 | return core.BroadcastTxAsync(&rpctypes.Context{}, tx) 93 | } 94 | 95 | func (c Client) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 96 | return core.BroadcastTxSync(&rpctypes.Context{}, tx) 97 | } 98 | 99 | func (c Client) NetInfo() (*ctypes.ResultNetInfo, error) { 100 | return core.NetInfo(&rpctypes.Context{}) 101 | } 102 | 103 | func (c Client) ConsensusState() (*ctypes.ResultConsensusState, error) { 104 | return core.ConsensusState(&rpctypes.Context{}) 105 | } 106 | 107 | func (c Client) DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) { 108 | return core.DumpConsensusState(&rpctypes.Context{}) 109 | } 110 | 111 | func (c Client) Health() (*ctypes.ResultHealth, error) { 112 | return core.Health(&rpctypes.Context{}) 113 | } 114 | 115 | func (c Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) { 116 | return core.BlockchainInfo(&rpctypes.Context{}, minHeight, maxHeight) 117 | } 118 | 119 | func (c Client) Genesis() (*ctypes.ResultGenesis, error) { 120 | return core.Genesis(&rpctypes.Context{}) 121 | } 122 | 123 | func (c Client) Block(height *int64) (*ctypes.ResultBlock, error) { 124 | return core.Block(&rpctypes.Context{}, height) 125 | } 126 | 127 | func (c Client) Commit(height *int64) (*ctypes.ResultCommit, error) { 128 | return core.Commit(&rpctypes.Context{}, height) 129 | } 130 | 131 | func (c Client) Validators(height *int64) (*ctypes.ResultValidators, error) { 132 | return core.Validators(&rpctypes.Context{}, height) 133 | } 134 | 135 | func (c Client) SetLogger(log.Logger) { 136 | return 137 | } 138 | -------------------------------------------------------------------------------- /client/rpc/validate.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "crypto/sha256" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/tendermint/tendermint/libs/common" 9 | "github.com/tendermint/tendermint/types" 10 | ) 11 | 12 | const ( 13 | maxABCIPathLength = 1024 14 | maxABCIDataLength = 1024 * 1024 15 | maxTxLength = 1024 * 1024 16 | maxABCIQueryStrLength = 1024 17 | maxTxSearchStrLength = 1024 18 | maxUnConfirmedTxs = 100 19 | maxDepthLevel = 1000 20 | 21 | tokenSymbolMaxLen = 14 22 | tokenSymbolMinLen = 3 23 | ) 24 | 25 | var ( 26 | ExceedABCIPathLengthError = fmt.Errorf("the abci path exceed max length %d ", maxABCIPathLength) 27 | ExceedABCIDataLengthError = fmt.Errorf("the abci data exceed max length %d ", maxABCIDataLength) 28 | ExceedTxLengthError = fmt.Errorf("the tx data exceed max length %d ", maxTxLength) 29 | LimitNegativeError = fmt.Errorf("the limit can't be negative") 30 | ExceedMaxUnConfirmedTxsNumError = fmt.Errorf("the limit of unConfirmed tx exceed max limit %d ", maxUnConfirmedTxs) 31 | HeightNegativeError = fmt.Errorf("the height can't be negative") 32 | MaxMinHeightConflictError = fmt.Errorf("the min height can't be larger than max height") 33 | HashLengthError = fmt.Errorf("the length of hash is not 32") 34 | ExceedABCIQueryStrLengthError = fmt.Errorf("the query string exceed max length %d ", maxABCIPathLength) 35 | ExceedTxSearchQueryStrLengthError = fmt.Errorf("the query string exceed max length %d ", maxTxSearchStrLength) 36 | OffsetNegativeError = fmt.Errorf("offset can't be less than 0") 37 | SymbolLengthExceedRangeError = fmt.Errorf("length of symbol should be in range [%d,%d]", tokenSymbolMinLen, tokenSymbolMaxLen) 38 | PairFormatError = fmt.Errorf("the pair should in format 'symbol1_symbol2'") 39 | DepthLevelExceedRangeError = fmt.Errorf("the level is out of range [%d, %d]", 0, maxDepthLevel) 40 | KeyMissingError = fmt.Errorf("keymanager is missing, use SetKeyManager to set key") 41 | EmptyResultError = fmt.Errorf("Empty result ") 42 | ) 43 | 44 | func ValidateABCIPath(path string) error { 45 | if len(path) > maxABCIPathLength { 46 | return ExceedABCIPathLengthError 47 | } 48 | return nil 49 | } 50 | 51 | func ValidateABCIData(data common.HexBytes) error { 52 | if len(data) > maxABCIDataLength { 53 | return ExceedABCIPathLengthError 54 | } 55 | return nil 56 | } 57 | 58 | func ValidateTx(tx types.Tx) error { 59 | if len(tx) > maxTxLength { 60 | return ExceedTxLengthError 61 | } 62 | return nil 63 | } 64 | 65 | func ValidateUnConfirmedTxsLimit(limit int) error { 66 | if limit < 0 { 67 | return LimitNegativeError 68 | } else if limit > maxUnConfirmedTxs { 69 | return ExceedMaxUnConfirmedTxsNumError 70 | } 71 | return nil 72 | } 73 | 74 | func ValidateHeightRange(from int64, to int64) error { 75 | if from < 0 || to < 0 { 76 | return HeightNegativeError 77 | } 78 | if from > to { 79 | return MaxMinHeightConflictError 80 | } 81 | return nil 82 | } 83 | 84 | func ValidateHeight(height *int64) error { 85 | if height != nil && *height < 0 { 86 | return HeightNegativeError 87 | } 88 | return nil 89 | } 90 | 91 | func ValidateHash(hash []byte) error { 92 | if len(hash) != sha256.Size { 93 | return HashLengthError 94 | } 95 | return nil 96 | } 97 | 98 | func ValidateABCIQueryStr(query string) error { 99 | if len(query) > maxABCIQueryStrLength { 100 | return ExceedABCIQueryStrLengthError 101 | } 102 | return nil 103 | } 104 | 105 | func ValidateTxSearchQueryStr(query string) error { 106 | if len(query) > maxTxSearchStrLength { 107 | return ExceedTxSearchQueryStrLengthError 108 | } 109 | return nil 110 | } 111 | 112 | func ValidateOffset(offset int) error { 113 | if offset < 0 { 114 | return OffsetNegativeError 115 | } 116 | return nil 117 | } 118 | 119 | func ValidateLimit(limit int) error { 120 | if limit < 0 { 121 | return LimitNegativeError 122 | } 123 | return nil 124 | } 125 | 126 | func ValidateSymbol(symbol string) error { 127 | if len(symbol) > tokenSymbolMaxLen || len(symbol) < tokenSymbolMinLen { 128 | return SymbolLengthExceedRangeError 129 | } 130 | return nil 131 | } 132 | 133 | func ValidatePair(pair string) error { 134 | symbols := strings.Split(pair, "_") 135 | if len(symbols) != 2 { 136 | return PairFormatError 137 | } 138 | if err := ValidateSymbol(symbols[0]); err != nil { 139 | return err 140 | } 141 | if err := ValidateSymbol(symbols[1]); err != nil { 142 | return err 143 | } 144 | return nil 145 | } 146 | 147 | func ValidateDepthLevel(level int) error { 148 | if level < 0 || level > maxDepthLevel { 149 | return DepthLevelExceedRangeError 150 | } 151 | return nil 152 | } 153 | -------------------------------------------------------------------------------- /client/rpc/types.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/types/tx" 5 | "github.com/tendermint/tendermint/abci/types" 6 | cmn "github.com/tendermint/tendermint/libs/common" 7 | abci "github.com/tendermint/tendermint/types" 8 | ) 9 | 10 | type ResultBroadcastTxCommit struct { 11 | CheckTx ResponseCheckTx `json:"check_tx"` 12 | DeliverTx ResponseDeliverTx `json:"deliver_tx"` 13 | Hash cmn.HexBytes `json:"hash"` 14 | Height int64 `json:"height"` 15 | } 16 | 17 | func (r ResponseCheckTx) IsErr() bool { 18 | return r.Code != types.CodeTypeOK 19 | } 20 | 21 | func (r *ResultBroadcastTxCommit) complement() { 22 | r.CheckTx.complement() 23 | r.DeliverTx.complement() 24 | } 25 | 26 | type ResponseCheckTx struct { 27 | Code uint32 `json:"code,omitempty"` 28 | Data []byte `json:"data,omitempty"` 29 | Log string `json:"log,omitempty"` 30 | Info string `json:"info,omitempty"` 31 | GasWanted int64 `json:"gas_wanted,omitempty"` 32 | GasUsed int64 `json:"gas_used,omitempty"` 33 | Events []types.Event `json:"events,omitempty"` 34 | Tags []cmn.KVPair `json:"tags,omitempty"` 35 | Codespace string `json:"codespace,omitempty"` 36 | } 37 | 38 | func (r *ResponseCheckTx) complement() { 39 | if len(r.Tags) > 0 { 40 | r.Events = []types.Event{{Attributes: r.Tags}} 41 | } else if len(r.Events) > 0 { 42 | r.Tags = r.Events[0].Attributes 43 | } 44 | } 45 | 46 | type ResponseDeliverTx struct { 47 | Code uint32 `json:"code,omitempty"` 48 | Data []byte `json:"data,omitempty"` 49 | Log string `json:"log,omitempty"` 50 | Info string `json:"info,omitempty"` 51 | GasWanted int64 `json:"gas_wanted,omitempty"` 52 | GasUsed int64 `json:"gas_used,omitempty"` 53 | Events []types.Event `json:"events,omitempty"` 54 | Tags []cmn.KVPair `json:"tags,omitempty"` 55 | Codespace string `json:"codespace,omitempty"` 56 | } 57 | 58 | func (r *ResponseDeliverTx) complement() { 59 | if len(r.Tags) > 0 { 60 | r.Events = []types.Event{{Attributes: r.Tags}} 61 | } else if len(r.Events) > 0 { 62 | r.Tags = r.Events[0].Attributes 63 | } 64 | } 65 | 66 | type ResultBlockResults struct { 67 | Height int64 `json:"height"` 68 | Results *ABCIResponses `json:"results"` 69 | } 70 | 71 | func (r *ResultBlockResults) complement() { 72 | if r.Results != nil { 73 | r.Results.complement() 74 | } 75 | } 76 | 77 | type ABCIResponses struct { 78 | DeliverTx []*ResponseDeliverTx `json:"DeliverTx"` 79 | EndBlock *ResponseEndBlock `json:"EndBlock"` 80 | BeginBlock *ResponseBeginBlock `json:"BeginBlock"` 81 | } 82 | 83 | func (r *ABCIResponses) complement() { 84 | for _, d := range r.DeliverTx { 85 | d.complement() 86 | } 87 | if r.EndBlock != nil { 88 | r.EndBlock.complement() 89 | } 90 | if r.BeginBlock != nil { 91 | r.BeginBlock.complement() 92 | } 93 | } 94 | 95 | type ResponseEndBlock struct { 96 | ValidatorUpdates []types.ValidatorUpdate `json:"validator_updates"` 97 | ConsensusParamUpdates *types.ConsensusParams `json:"consensus_param_updates,omitempty"` 98 | Events []types.Event `json:"events,omitempty"` 99 | Tags []cmn.KVPair `json:"tags,omitempty"` 100 | } 101 | 102 | func (r *ResponseEndBlock) complement() { 103 | if len(r.Tags) > 0 { 104 | r.Events = []types.Event{{Attributes: r.Tags}} 105 | } else if len(r.Events) > 0 { 106 | r.Tags = r.Events[0].Attributes 107 | } 108 | } 109 | 110 | type ResponseBeginBlock struct { 111 | Events []types.Event `json:"events,omitempty"` 112 | Tags []cmn.KVPair `json:"tags,omitempty"` 113 | } 114 | 115 | func (r *ResponseBeginBlock) complement() { 116 | if len(r.Tags) > 0 { 117 | r.Events = []types.Event{{Attributes: r.Tags}} 118 | } else if len(r.Events) > 0 { 119 | r.Tags = r.Events[0].Attributes 120 | } 121 | } 122 | 123 | type ResultTx struct { 124 | Hash cmn.HexBytes `json:"hash"` 125 | Height int64 `json:"height"` 126 | Index uint32 `json:"index"` 127 | TxResult ResponseDeliverTx `json:"tx_result"` 128 | Tx abci.Tx `json:"tx"` 129 | Proof abci.TxProof `json:"proof,omitempty"` 130 | } 131 | 132 | func (r *ResultTx) complement() { 133 | r.TxResult.complement() 134 | } 135 | 136 | // Result of searching for txs 137 | type ResultTxSearch struct { 138 | Txs []*ResultTx `json:"txs"` 139 | TotalCount int `json:"total_count"` 140 | } 141 | 142 | func (r *ResultTxSearch) complement() { 143 | for _, t := range r.Txs { 144 | t.TxResult.complement() 145 | } 146 | } 147 | 148 | type Info struct { 149 | Hash cmn.HexBytes `json:"hash"` 150 | Height int64 `json:"height"` 151 | Tx tx.Tx `json:"tx"` 152 | Result ResponseDeliverTx `json:"result"` 153 | } 154 | 155 | func (r *Info) complement() { 156 | r.Result.complement() 157 | } 158 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bnb-chain/go-sdk 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/bnb-chain/node v0.10.16 7 | github.com/btcsuite/btcd/btcec/v2 v2.3.2 8 | github.com/btcsuite/btcd/btcutil v1.1.3 // indirect; indirect github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d 9 | github.com/cosmos/cosmos-sdk v0.25.0 10 | github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d 11 | github.com/gorilla/websocket v1.5.0 12 | github.com/pkg/errors v0.9.1 13 | github.com/stretchr/testify v1.8.2 14 | github.com/tendermint/btcd v0.1.1 15 | github.com/tendermint/go-amino v0.15.0 16 | github.com/tendermint/tendermint v0.35.9 17 | github.com/zondax/ledger-cosmos-go v0.9.9 18 | golang.org/x/crypto v0.10.0 19 | gopkg.in/resty.v1 v1.12.0 20 | ) 21 | 22 | require ( 23 | github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d // indirect 24 | github.com/beorn7/perks v1.0.1 // indirect 25 | github.com/bgentry/speakeasy v0.1.0 // indirect 26 | github.com/bnb-chain/ics23 v0.1.0 // indirect 27 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 28 | github.com/cosmos/ledger-go v0.9.2 // indirect 29 | github.com/davecgh/go-spew v1.1.1 // indirect 30 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect 31 | github.com/etcd-io/bbolt v1.3.3 // indirect 32 | github.com/ethereum/go-ethereum v1.11.3 // indirect 33 | github.com/fsnotify/fsnotify v1.6.0 // indirect 34 | github.com/go-kit/kit v0.10.0 // indirect 35 | github.com/go-logfmt/logfmt v0.5.1 // indirect 36 | github.com/gogo/protobuf v1.3.2 // indirect 37 | github.com/golang/protobuf v1.5.3 // indirect 38 | github.com/golang/snappy v0.0.4 // indirect 39 | github.com/google/btree v1.0.0 // indirect 40 | github.com/gorilla/mux v1.8.0 // indirect 41 | github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect 42 | github.com/hashicorp/hcl v1.0.0 // indirect 43 | github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect 44 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 45 | github.com/jcmturner/gofork v1.7.6 // indirect 46 | github.com/jmhodges/levigo v1.0.0 // indirect 47 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 48 | github.com/libp2p/go-buffer-pool v0.1.0 // indirect 49 | github.com/magiconair/properties v1.8.5 // indirect 50 | github.com/mattn/go-isatty v0.0.18 // indirect 51 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect 52 | github.com/minio/sha256-simd v1.0.0 // indirect 53 | github.com/mitchellh/go-homedir v1.1.0 // indirect 54 | github.com/mitchellh/mapstructure v1.4.1 // indirect 55 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect 56 | github.com/pelletier/go-toml v1.9.3 // indirect 57 | github.com/pmezard/go-difflib v1.0.0 // indirect 58 | github.com/prometheus/client_golang v1.14.0 // indirect 59 | github.com/prometheus/client_model v0.3.0 // indirect 60 | github.com/prometheus/common v0.42.0 // indirect 61 | github.com/prometheus/procfs v0.9.0 // indirect 62 | github.com/prysmaticlabs/fastssz v0.0.0-20220628121656-93dfe28febab // indirect 63 | github.com/prysmaticlabs/gohashtree v0.0.3-alpha // indirect 64 | github.com/prysmaticlabs/prysm/v4 v4.0.2 // indirect 65 | github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 // indirect 66 | github.com/rs/cors v1.7.0 // indirect 67 | github.com/sirupsen/logrus v1.9.0 // indirect 68 | github.com/spf13/afero v1.6.0 // indirect 69 | github.com/spf13/cast v1.3.1 // indirect 70 | github.com/spf13/cobra v1.5.0 // indirect 71 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 72 | github.com/spf13/pflag v1.0.5 // indirect 73 | github.com/spf13/viper v1.8.1 // indirect 74 | github.com/subosito/gotenv v1.2.0 // indirect 75 | github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 // indirect 76 | github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect 77 | github.com/tendermint/iavl v0.12.4 // indirect 78 | github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect 79 | github.com/zondax/hid v0.9.0 // indirect 80 | golang.org/x/net v0.11.0 // indirect 81 | golang.org/x/sys v0.9.0 // indirect 82 | golang.org/x/text v0.10.0 // indirect 83 | google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84 // indirect 84 | google.golang.org/grpc v1.40.0 // indirect 85 | google.golang.org/protobuf v1.30.0 // indirect 86 | gopkg.in/ini.v1 v1.67.0 // indirect 87 | gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect 88 | gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect 89 | gopkg.in/jcmturner/gokrb5.v7 v7.5.0 // indirect 90 | gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect 91 | gopkg.in/yaml.v2 v2.4.0 // indirect 92 | gopkg.in/yaml.v3 v3.0.1 // indirect 93 | ) 94 | 95 | replace ( 96 | github.com/cosmos/cosmos-sdk => github.com/bnb-chain/bnc-cosmos-sdk v0.26.7 97 | github.com/tendermint/go-amino => github.com/bnb-chain/bnc-go-amino v0.14.1-binance.2 98 | github.com/tendermint/iavl => github.com/bnb-chain/bnc-tendermint-iavl v0.12.0-binance.5 99 | github.com/tendermint/tendermint => github.com/bnb-chain/bnc-tendermint v0.32.3-bc.10 100 | github.com/zondax/ledger-cosmos-go => github.com/bnb-chain/ledger-cosmos-go v0.9.10-0.20230201065744-d644bede1667 101 | github.com/zondax/ledger-go => github.com/bnb-chain/ledger-go v0.9.1 102 | golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae 103 | ) 104 | -------------------------------------------------------------------------------- /common/uuid/codec.go: -------------------------------------------------------------------------------- 1 | package uuid 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "fmt" 7 | ) 8 | 9 | // FromBytes returns UUID converted from raw byte slice input. 10 | // It will return error if the slice isn't 16 bytes long. 11 | func FromBytes(input []byte) (u UUID, err error) { 12 | err = u.UnmarshalBinary(input) 13 | return 14 | } 15 | 16 | // FromBytesOrNil returns UUID converted from raw byte slice input. 17 | // Same behavior as FromBytes, but returns a Nil UUID on error. 18 | func FromBytesOrNil(input []byte) UUID { 19 | uuid, err := FromBytes(input) 20 | if err != nil { 21 | return Nil 22 | } 23 | return uuid 24 | } 25 | 26 | // FromString returns UUID parsed from string input. 27 | // Input is expected in a form accepted by UnmarshalText. 28 | func FromString(input string) (u UUID, err error) { 29 | err = u.UnmarshalText([]byte(input)) 30 | return 31 | } 32 | 33 | // FromStringOrNil returns UUID parsed from string input. 34 | // Same behavior as FromString, but returns a Nil UUID on error. 35 | func FromStringOrNil(input string) UUID { 36 | uuid, err := FromString(input) 37 | if err != nil { 38 | return Nil 39 | } 40 | return uuid 41 | } 42 | 43 | // MarshalText implements the encoding.TextMarshaler interface. 44 | // The encoding is the same as returned by String. 45 | func (u UUID) MarshalText() (text []byte, err error) { 46 | text = []byte(u.String()) 47 | return 48 | } 49 | 50 | // UnmarshalText implements the encoding.TextUnmarshaler interface. 51 | // Following formats are supported: 52 | // "6ba7b810-9dad-11d1-80b4-00c04fd430c8", 53 | // "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", 54 | // "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" 55 | // "6ba7b8109dad11d180b400c04fd430c8" 56 | // ABNF for supported UUID text representation follows: 57 | // uuid := canonical | hashlike | braced | urn 58 | // plain := canonical | hashlike 59 | // canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct 60 | // hashlike := 12hexoct 61 | // braced := '{' plain '}' 62 | // urn := URN ':' UUID-NID ':' plain 63 | // URN := 'urn' 64 | // UUID-NID := 'uuid' 65 | // 12hexoct := 6hexoct 6hexoct 66 | // 6hexoct := 4hexoct 2hexoct 67 | // 4hexoct := 2hexoct 2hexoct 68 | // 2hexoct := hexoct hexoct 69 | // hexoct := hexdig hexdig 70 | // hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 71 | // 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 72 | // 'A' | 'B' | 'C' | 'D' | 'E' | 'F' 73 | func (u *UUID) UnmarshalText(text []byte) (err error) { 74 | switch len(text) { 75 | case 32: 76 | return u.decodeHashLike(text) 77 | case 36: 78 | return u.decodeCanonical(text) 79 | case 38: 80 | return u.decodeBraced(text) 81 | case 41: 82 | fallthrough 83 | case 45: 84 | return u.decodeURN(text) 85 | default: 86 | return fmt.Errorf("uuid: incorrect UUID length: %s", text) 87 | } 88 | } 89 | 90 | // decodeCanonical decodes UUID string in format 91 | // "6ba7b810-9dad-11d1-80b4-00c04fd430c8". 92 | func (u *UUID) decodeCanonical(t []byte) (err error) { 93 | if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' { 94 | return fmt.Errorf("uuid: incorrect UUID format %s", t) 95 | } 96 | 97 | src := t[:] 98 | dst := u[:] 99 | 100 | for i, byteGroup := range byteGroups { 101 | if i > 0 { 102 | src = src[1:] // skip dash 103 | } 104 | _, err = hex.Decode(dst[:byteGroup/2], src[:byteGroup]) 105 | if err != nil { 106 | return 107 | } 108 | src = src[byteGroup:] 109 | dst = dst[byteGroup/2:] 110 | } 111 | 112 | return 113 | } 114 | 115 | // decodeHashLike decodes UUID string in format 116 | // "6ba7b8109dad11d180b400c04fd430c8". 117 | func (u *UUID) decodeHashLike(t []byte) (err error) { 118 | src := t[:] 119 | dst := u[:] 120 | 121 | if _, err = hex.Decode(dst, src); err != nil { 122 | return err 123 | } 124 | return 125 | } 126 | 127 | // decodeBraced decodes UUID string in format 128 | // "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" or in format 129 | // "{6ba7b8109dad11d180b400c04fd430c8}". 130 | func (u *UUID) decodeBraced(t []byte) (err error) { 131 | l := len(t) 132 | 133 | if t[0] != '{' || t[l-1] != '}' { 134 | return fmt.Errorf("uuid: incorrect UUID format %s", t) 135 | } 136 | 137 | return u.decodePlain(t[1 : l-1]) 138 | } 139 | 140 | // decodeURN decodes UUID string in format 141 | // "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in format 142 | // "urn:uuid:6ba7b8109dad11d180b400c04fd430c8". 143 | func (u *UUID) decodeURN(t []byte) (err error) { 144 | total := len(t) 145 | 146 | urn_uuid_prefix := t[:9] 147 | 148 | if !bytes.Equal(urn_uuid_prefix, urnPrefix) { 149 | return fmt.Errorf("uuid: incorrect UUID format: %s", t) 150 | } 151 | 152 | return u.decodePlain(t[9:total]) 153 | } 154 | 155 | // decodePlain decodes UUID string in canonical format 156 | // "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format 157 | // "6ba7b8109dad11d180b400c04fd430c8". 158 | func (u *UUID) decodePlain(t []byte) (err error) { 159 | switch len(t) { 160 | case 32: 161 | return u.decodeHashLike(t) 162 | case 36: 163 | return u.decodeCanonical(t) 164 | default: 165 | return fmt.Errorf("uuid: incorrrect UUID length: %s", t) 166 | } 167 | } 168 | 169 | // MarshalBinary implements the encoding.BinaryMarshaler interface. 170 | func (u UUID) MarshalBinary() (data []byte, err error) { 171 | data = u.Bytes() 172 | return 173 | } 174 | 175 | // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. 176 | // It will return error if the slice isn't 16 bytes long. 177 | func (u *UUID) UnmarshalBinary(data []byte) (err error) { 178 | if len(data) != Size { 179 | err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data)) 180 | return 181 | } 182 | copy(u[:], data) 183 | 184 | return 185 | } 186 | -------------------------------------------------------------------------------- /keys/hdpath.go: -------------------------------------------------------------------------------- 1 | package keys 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha512" 6 | "encoding/binary" 7 | "errors" 8 | "fmt" 9 | "math/big" 10 | "strconv" 11 | "strings" 12 | 13 | "github.com/btcsuite/btcd/btcec/v2" 14 | ) 15 | 16 | const ( 17 | BIPPurpose = 44 18 | BIPCoinType = 714 19 | BIPChange = false 20 | BIP44Prefix = "44'/714'/" 21 | PartialPath = "0'/0/0" 22 | FullPath = BIP44Prefix + PartialPath 23 | ) 24 | 25 | // BIP44Params wraps BIP 44 params (5 level BIP 32 path). 26 | // To receive a canonical string representation ala 27 | // m / purpose' / coin_type' / account' / change / address_index 28 | // call String() on a BIP44Params instance. 29 | type BIP44Params struct { 30 | purpose uint32 31 | coinType uint32 32 | account uint32 33 | change bool 34 | addressIdx uint32 35 | } 36 | 37 | // NewParams creates a BIP 44 parameter object from the params: 38 | // m / purpose' / coin_type' / account' / change / address_index 39 | func NewParams(purpose, coinType, account uint32, change bool, addressIdx uint32) *BIP44Params { 40 | return &BIP44Params{ 41 | purpose: purpose, 42 | coinType: coinType, 43 | account: account, 44 | change: change, 45 | addressIdx: addressIdx, 46 | } 47 | } 48 | 49 | // NewBinanceBIP44Params creates a BIP 44 parameter object from the params: 50 | // m / 44' / 714' / account' / 0 / address_index 51 | // The fixed parameters (purpose', coin_type', and change) are determined by what was used in the binance ledger app. 52 | func NewBinanceBIP44Params(account uint32, addressIdx uint32) *BIP44Params { 53 | return NewParams(BIPPurpose, BIPCoinType, account, BIPChange, addressIdx) 54 | } 55 | 56 | // Return the BIP44 fields as an array. 57 | func (p BIP44Params) DerivationPath() []uint32 { 58 | change := uint32(0) 59 | if p.change { 60 | change = 1 61 | } 62 | return []uint32{ 63 | p.purpose, 64 | p.coinType, 65 | p.account, 66 | change, 67 | p.addressIdx, 68 | } 69 | } 70 | 71 | func (p BIP44Params) String() string { 72 | var changeStr string 73 | if p.change { 74 | changeStr = "1" 75 | } else { 76 | changeStr = "0" 77 | } 78 | // m / purpose' / coin_type' / account' / change / address_index 79 | return fmt.Sprintf("%d'/%d'/%d'/%s/%d", 80 | p.purpose, 81 | p.coinType, 82 | p.account, 83 | changeStr, 84 | p.addressIdx) 85 | } 86 | 87 | // ComputeMastersFromSeed returns the master public key, master secret, and chain code in hex. 88 | func ComputeMastersFromSeed(seed []byte) (secret [32]byte, chainCode [32]byte) { 89 | masterSecret := []byte("Bitcoin seed") 90 | secret, chainCode = i64(masterSecret, seed) 91 | 92 | return 93 | } 94 | 95 | // DerivePrivateKeyForPath derives the private key by following the BIP 32/44 path from privKeyBytes, 96 | // using the given chainCode. 97 | func DerivePrivateKeyForPath(privKeyBytes [32]byte, chainCode [32]byte, path string) ([32]byte, error) { 98 | data := privKeyBytes 99 | parts := strings.Split(path, "/") 100 | for _, part := range parts { 101 | // do we have an apostrophe? 102 | harden := part[len(part)-1:] == "'" 103 | // harden == private derivation, else public derivation: 104 | if harden { 105 | part = part[:len(part)-1] 106 | } 107 | idx, err := strconv.Atoi(part) 108 | if err != nil { 109 | return [32]byte{}, fmt.Errorf("invalid BIP 32 path: %s", err) 110 | } 111 | if idx < 0 { 112 | return [32]byte{}, errors.New("invalid BIP 32 path: index negative ot too large") 113 | } 114 | data, chainCode = derivePrivateKey(data, chainCode, uint32(idx), harden) 115 | } 116 | var derivedKey [32]byte 117 | n := copy(derivedKey[:], data[:]) 118 | if n != 32 || len(data) != 32 { 119 | return [32]byte{}, fmt.Errorf("expected a (secp256k1) key of length 32, got length: %v", len(data)) 120 | } 121 | 122 | return derivedKey, nil 123 | } 124 | 125 | // derivePrivateKey derives the private key with index and chainCode. 126 | // If harden is true, the derivation is 'hardened'. 127 | // It returns the new private key and new chain code. 128 | // For more information on hardened keys see: 129 | // - https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki 130 | func derivePrivateKey(privKeyBytes [32]byte, chainCode [32]byte, index uint32, harden bool) ([32]byte, [32]byte) { 131 | var data []byte 132 | if harden { 133 | index = index | 0x80000000 134 | data = append([]byte{byte(0)}, privKeyBytes[:]...) 135 | } else { 136 | // this can't return an error: 137 | _, ecPub := btcec.PrivKeyFromBytes(privKeyBytes[:]) 138 | pubkeyBytes := ecPub.SerializeCompressed() 139 | data = pubkeyBytes 140 | 141 | /* By using btcec, we can remove the dependency on tendermint/crypto/secp256k1 142 | pubkey := secp256k1.PrivKeySecp256k1(privKeyBytes).PubKey() 143 | public := pubkey.(secp256k1.PubKeySecp256k1) 144 | data = public[:] 145 | */ 146 | } 147 | data = append(data, uint32ToBytes(index)...) 148 | data2, chainCode2 := i64(chainCode[:], data) 149 | x := addScalars(privKeyBytes[:], data2[:]) 150 | return x, chainCode2 151 | } 152 | 153 | // modular big endian addition 154 | func addScalars(a []byte, b []byte) [32]byte { 155 | aInt := new(big.Int).SetBytes(a) 156 | bInt := new(big.Int).SetBytes(b) 157 | sInt := new(big.Int).Add(aInt, bInt) 158 | x := sInt.Mod(sInt, btcec.S256().N).Bytes() 159 | x2 := [32]byte{} 160 | copy(x2[32-len(x):], x) 161 | return x2 162 | } 163 | 164 | func uint32ToBytes(i uint32) []byte { 165 | b := [4]byte{} 166 | binary.BigEndian.PutUint32(b[:], i) 167 | return b[:] 168 | } 169 | 170 | // i64 returns the two halfs of the SHA512 HMAC of key and data. 171 | func i64(key []byte, data []byte) (IL [32]byte, IR [32]byte) { 172 | mac := hmac.New(sha512.New, key) 173 | // sha512 does not err 174 | _, _ = mac.Write(data) 175 | I := mac.Sum(nil) 176 | copy(IL[:], I[:32]) 177 | copy(IR[:], I[32:]) 178 | return 179 | } 180 | -------------------------------------------------------------------------------- /client/basic/basic.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "time" 9 | 10 | "gopkg.in/resty.v1" 11 | 12 | "github.com/bnb-chain/go-sdk/types" 13 | "github.com/bnb-chain/go-sdk/types/tx" 14 | "github.com/gorilla/websocket" 15 | ) 16 | 17 | const ( 18 | MaxReadWaitTime = 30 * time.Second 19 | ) 20 | 21 | type BasicClient interface { 22 | Get(path string, qp map[string]string) ([]byte, int, error) 23 | Post(path string, body interface{}, param map[string]string) ([]byte, error) 24 | 25 | GetTx(txHash string) (*tx.TxResult, error) 26 | PostTx(hexTx []byte, param map[string]string) ([]tx.TxCommitResult, error) 27 | WsGet(path string, constructMsg func([]byte) (interface{}, error), closeCh <-chan struct{}) (<-chan interface{}, error) 28 | } 29 | 30 | type client struct { 31 | baseUrl string 32 | apiUrl string 33 | apiKey string 34 | } 35 | 36 | func NewClient(baseUrl string, apiKey string) BasicClient { 37 | return &client{baseUrl: baseUrl, apiUrl: fmt.Sprintf("%s://%s", types.DefaultApiSchema, baseUrl+types.DefaultAPIVersionPrefix), apiKey: apiKey} 38 | } 39 | 40 | func (c *client) Get(path string, qp map[string]string) ([]byte, int, error) { 41 | request := resty.R().SetQueryParams(qp) 42 | if c.apiKey != "" { 43 | request.SetHeader("apikey", c.apiKey) 44 | } 45 | resp, err := request.Get(c.apiUrl + path) 46 | if err != nil { 47 | return nil, 0, err 48 | } 49 | if resp.StatusCode() >= http.StatusMultipleChoices || resp.StatusCode() < http.StatusOK { 50 | err = fmt.Errorf("bad response, status code %d, response: %s", resp.StatusCode(), string(resp.Body())) 51 | } 52 | return resp.Body(), resp.StatusCode(), err 53 | } 54 | 55 | // Post generic method 56 | func (c *client) Post(path string, body interface{}, param map[string]string) ([]byte, error) { 57 | request := resty.R(). 58 | SetHeader("Content-Type", "text/plain"). 59 | SetBody(body). 60 | SetQueryParams(param) 61 | if c.apiKey != "" { 62 | request.SetHeader("apikey", c.apiKey) 63 | } 64 | resp, err := request.Post(c.apiUrl + path) 65 | 66 | if err != nil { 67 | return nil, err 68 | } 69 | if resp.StatusCode() >= http.StatusMultipleChoices { 70 | err = fmt.Errorf("bad response, status code %d, response: %s", resp.StatusCode(), string(resp.Body())) 71 | } 72 | return resp.Body(), err 73 | } 74 | 75 | // GetTx returns transaction details 76 | func (c *client) GetTx(txHash string) (*tx.TxResult, error) { 77 | if txHash == "" { 78 | return nil, fmt.Errorf("Invalid tx hash %s ", txHash) 79 | } 80 | 81 | qp := map[string]string{} 82 | resp, _, err := c.Get("/tx/"+txHash, qp) 83 | if err != nil { 84 | return nil, err 85 | } 86 | 87 | var txResult tx.TxResult 88 | if err := json.Unmarshal(resp, &txResult); err != nil { 89 | return nil, err 90 | } 91 | 92 | return &txResult, nil 93 | } 94 | 95 | // PostTx returns transaction details 96 | func (c *client) PostTx(hexTx []byte, param map[string]string) ([]tx.TxCommitResult, error) { 97 | if len(hexTx) == 0 { 98 | return nil, fmt.Errorf("Invalid tx %s", hexTx) 99 | } 100 | 101 | body := hexTx 102 | resp, err := c.Post("/broadcast", body, param) 103 | if err != nil { 104 | return nil, err 105 | } 106 | txResult := make([]tx.TxCommitResult, 0) 107 | if err := json.Unmarshal(resp, &txResult); err != nil { 108 | return nil, err 109 | } 110 | 111 | return txResult, nil 112 | } 113 | 114 | func (c *client) WsGet(path string, constructMsg func([]byte) (interface{}, error), closeCh <-chan struct{}) (<-chan interface{}, error) { 115 | u := url.URL{Scheme: types.DefaultWSSchema, Host: c.baseUrl, Path: fmt.Sprintf("%s/%s", types.DefaultWSPrefix, path)} 116 | conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil) 117 | if err != nil { 118 | return nil, err 119 | } 120 | conn.SetPingHandler(nil) 121 | conn.SetPongHandler( 122 | func(string) error { 123 | conn.SetReadDeadline(time.Now().Add(MaxReadWaitTime)) 124 | return nil 125 | }) 126 | messages := make(chan interface{}, 0) 127 | finish := make(chan struct{}, 0) 128 | keepAliveCh := time.NewTicker(30 * time.Minute) 129 | pingTicker := time.NewTicker(10 * time.Second) 130 | go func() { 131 | defer conn.Close() 132 | defer close(messages) 133 | defer keepAliveCh.Stop() 134 | defer pingTicker.Stop() 135 | select { 136 | case <-closeCh: 137 | return 138 | case <-finish: 139 | return 140 | } 141 | }() 142 | go func() { 143 | writeMsg := func(m interface{}) bool { 144 | select { 145 | case <-closeCh: 146 | // already closed by user 147 | return true 148 | default: 149 | } 150 | messages <- m 151 | return false 152 | } 153 | for { 154 | select { 155 | case <-closeCh: 156 | conn.WriteControl(websocket.CloseMessage, nil, time.Now().Add(time.Second)) 157 | return 158 | case <-keepAliveCh.C: 159 | conn.WriteJSON(&struct { 160 | Method string 161 | }{"keepAlive"}) 162 | case <-pingTicker.C: 163 | conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(time.Second)) 164 | default: 165 | response := WSResponse{} 166 | err := conn.ReadJSON(&response) 167 | if err != nil { 168 | if closed := writeMsg(err); !closed { 169 | close(finish) 170 | } 171 | return 172 | } 173 | bz, err := json.Marshal(response.Data) 174 | if err != nil { 175 | if closed := writeMsg(err); !closed { 176 | close(finish) 177 | } 178 | return 179 | } 180 | msg, err := constructMsg(bz) 181 | if err != nil { 182 | if closed := writeMsg(err); !closed { 183 | close(finish) 184 | } 185 | return 186 | } 187 | //Todo delete condition when ws do not return account and order in the same time. 188 | if msg != nil { 189 | if closed := writeMsg(msg); closed { 190 | return 191 | } 192 | } 193 | } 194 | } 195 | }() 196 | return messages, nil 197 | } 198 | 199 | type WSResponse struct { 200 | Stream string 201 | Data interface{} 202 | } 203 | -------------------------------------------------------------------------------- /client/transaction/transaction.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/bnb-chain/go-sdk/client/basic" 9 | "github.com/bnb-chain/go-sdk/client/query" 10 | "github.com/bnb-chain/go-sdk/common/types" 11 | "github.com/bnb-chain/go-sdk/keys" 12 | "github.com/bnb-chain/go-sdk/types/msg" 13 | "github.com/bnb-chain/go-sdk/types/tx" 14 | ) 15 | 16 | type Option = tx.Option 17 | 18 | var ( 19 | WithSource = tx.WithSource 20 | WithMemo = tx.WithMemo 21 | WithAcNumAndSequence = tx.WithAcNumAndSequence 22 | ) 23 | 24 | type TransactionClient interface { 25 | // CreateOrder deprecated 26 | CreateOrder(baseAssetSymbol, quoteAssetSymbol string, op int8, price, quantity int64, sync bool, options ...Option) (*CreateOrderResult, error) 27 | // CancelOrder deprecated 28 | CancelOrder(baseAssetSymbol, quoteAssetSymbol, refId string, sync bool, options ...Option) (*CancelOrderResult, error) 29 | BurnToken(symbol string, amount int64, sync bool, options ...Option) (*BurnTokenResult, error) 30 | ListPair(proposalId int64, baseAssetSymbol string, quoteAssetSymbol string, initPrice int64, sync bool, options ...Option) (*ListPairResult, error) 31 | FreezeToken(symbol string, amount int64, sync bool, options ...Option) (*FreezeTokenResult, error) 32 | UnfreezeToken(symbol string, amount int64, sync bool, options ...Option) (*UnfreezeTokenResult, error) 33 | IssueToken(name, symbol string, supply int64, sync bool, mintable bool, options ...Option) (*IssueTokenResult, error) 34 | SendToken(transfers []msg.Transfer, sync bool, options ...Option) (*SendTokenResult, error) 35 | MintToken(symbol string, amount int64, sync bool, options ...Option) (*MintTokenResult, error) 36 | TransferTokenOwnership(symbol string, newOwner types.AccAddress, sync bool, options ...Option) (*TransferTokenOwnershipResult, error) 37 | TimeLock(description string, amount types.Coins, lockTime int64, sync bool, options ...Option) (*TimeLockResult, error) 38 | TimeUnLock(id int64, sync bool, options ...Option) (*TimeUnLockResult, error) 39 | TimeReLock(id int64, description string, amount types.Coins, lockTime int64, sync bool, options ...Option) (*TimeReLockResult, error) 40 | SetAccountFlags(flags uint64, sync bool, options ...Option) (*SetAccountFlagsResult, error) 41 | AddAccountFlags(flagOptions []types.FlagOption, sync bool, options ...Option) (*SetAccountFlagsResult, error) 42 | HTLT(recipient types.AccAddress, recipientOtherChain, senderOtherChain string, randomNumberHash []byte, timestamp int64, amount types.Coins, expectedIncome string, heightSpan int64, crossChain bool, sync bool, options ...Option) (*HTLTResult, error) 43 | DepositHTLT(swapID []byte, amount types.Coins, sync bool, options ...Option) (*DepositHTLTResult, error) 44 | ClaimHTLT(swapID []byte, randomNumber []byte, sync bool, options ...Option) (*ClaimHTLTResult, error) 45 | RefundHTLT(swapID []byte, sync bool, options ...Option) (*RefundHTLTResult, error) 46 | 47 | SubmitListPairProposal(title string, param msg.ListTradingPairParams, initialDeposit int64, votingPeriod time.Duration, sync bool, options ...Option) (*SubmitProposalResult, error) 48 | SubmitProposal(title string, description string, proposalType msg.ProposalKind, initialDeposit int64, votingPeriod time.Duration, sync bool, options ...Option) (*SubmitProposalResult, error) 49 | DepositProposal(proposalID int64, amount int64, sync bool, options ...Option) (*DepositProposalResult, error) 50 | VoteProposal(proposalID int64, option msg.VoteOption, sync bool, options ...Option) (*VoteProposalResult, error) 51 | 52 | IssueMiniToken(name, symbol string, supply int64, sync bool, mintable bool, tokenURI string, options ...Option) (*IssueMiniTokenResult, error) 53 | IssueTinyToken(name, symbol string, supply int64, sync bool, mintable bool, tokenURI string, options ...Option) (*IssueTinyTokenResult, error) 54 | ListMiniPair(baseAssetSymbol string, quoteAssetSymbol string, initPrice int64, sync bool, options ...Option) (*ListMiniPairResult, error) 55 | SetURI(symbol, tokenURI string, sync bool, options ...Option) (*SetUriResult, error) 56 | 57 | GetKeyManager() keys.KeyManager 58 | } 59 | 60 | type client struct { 61 | basicClient basic.BasicClient 62 | queryClient query.QueryClient 63 | keyManager keys.KeyManager 64 | chainId string 65 | } 66 | 67 | func NewClient(chainId string, keyManager keys.KeyManager, queryClient query.QueryClient, basicClient basic.BasicClient) TransactionClient { 68 | return &client{basicClient, queryClient, keyManager, chainId} 69 | } 70 | 71 | func (c *client) GetKeyManager() keys.KeyManager { 72 | return c.keyManager 73 | } 74 | 75 | func (c *client) broadcastMsg(m msg.Msg, sync bool, options ...Option) (*tx.TxCommitResult, error) { 76 | // prepare message to sign 77 | signMsg := &tx.StdSignMsg{ 78 | ChainID: c.chainId, 79 | AccountNumber: -1, 80 | Sequence: -1, 81 | Memo: "", 82 | Msgs: []msg.Msg{m}, 83 | Source: tx.Source, 84 | } 85 | 86 | for _, op := range options { 87 | signMsg = op(signMsg) 88 | } 89 | 90 | if signMsg.Sequence == -1 || signMsg.AccountNumber == -1 { 91 | fromAddr := c.keyManager.GetAddr() 92 | acc, err := c.queryClient.GetAccount(fromAddr.String()) 93 | if err != nil { 94 | return nil, err 95 | } 96 | signMsg.Sequence = acc.Sequence 97 | signMsg.AccountNumber = acc.Number 98 | } 99 | 100 | // special logic for createOrder, to save account query 101 | if orderMsg, ok := m.(msg.CreateOrderMsg); ok { 102 | orderMsg.Id = msg.GenerateOrderID(signMsg.Sequence+1, c.keyManager.GetAddr()) 103 | signMsg.Msgs[0] = orderMsg 104 | } 105 | 106 | for _, m := range signMsg.Msgs { 107 | if err := m.ValidateBasic(); err != nil { 108 | return nil, err 109 | } 110 | } 111 | 112 | rawBz, err := c.keyManager.Sign(*signMsg) 113 | if err != nil { 114 | return nil, err 115 | } 116 | // Hex encoded signed transaction, ready to be posted to BncChain API 117 | hexTx := []byte(hex.EncodeToString(rawBz)) 118 | param := map[string]string{} 119 | if sync { 120 | param["sync"] = "true" 121 | } 122 | commits, err := c.basicClient.PostTx(hexTx, param) 123 | if err != nil { 124 | return nil, err 125 | } 126 | if len(commits) < 1 { 127 | return nil, fmt.Errorf("Len of tx Commit result is less than 1 ") 128 | } 129 | return &commits[0], nil 130 | } 131 | -------------------------------------------------------------------------------- /common/uuid/generator.go: -------------------------------------------------------------------------------- 1 | package uuid 2 | 3 | import ( 4 | "crypto/md5" 5 | "crypto/rand" 6 | "crypto/sha1" 7 | "encoding/binary" 8 | "fmt" 9 | "hash" 10 | "io" 11 | "net" 12 | "os" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | // Difference in 100-nanosecond intervals between 18 | // UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). 19 | const epochStart = 122192928000000000 20 | 21 | type epochFunc func() time.Time 22 | type hwAddrFunc func() (net.HardwareAddr, error) 23 | 24 | var ( 25 | global = newRFC4122Generator() 26 | 27 | posixUID = uint32(os.Getuid()) 28 | posixGID = uint32(os.Getgid()) 29 | ) 30 | 31 | // NewV1 returns UUID based on current timestamp and MAC address. 32 | func NewV1() (UUID, error) { 33 | return global.NewV1() 34 | } 35 | 36 | // NewV2 returns DCE Security UUID based on POSIX UID/GID. 37 | func NewV2(domain byte) (UUID, error) { 38 | return global.NewV2(domain) 39 | } 40 | 41 | // NewV3 returns UUID based on MD5 hash of namespace UUID and name. 42 | func NewV3(ns UUID, name string) UUID { 43 | return global.NewV3(ns, name) 44 | } 45 | 46 | // NewV4 returns random generated UUID. 47 | func NewV4() (UUID, error) { 48 | return global.NewV4() 49 | } 50 | 51 | // NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. 52 | func NewV5(ns UUID, name string) UUID { 53 | return global.NewV5(ns, name) 54 | } 55 | 56 | // Generator provides interface for generating UUIDs. 57 | type Generator interface { 58 | NewV1() (UUID, error) 59 | NewV2(domain byte) (UUID, error) 60 | NewV3(ns UUID, name string) UUID 61 | NewV4() (UUID, error) 62 | NewV5(ns UUID, name string) UUID 63 | } 64 | 65 | // Default generator implementation. 66 | type rfc4122Generator struct { 67 | clockSequenceOnce sync.Once 68 | hardwareAddrOnce sync.Once 69 | storageMutex sync.Mutex 70 | 71 | rand io.Reader 72 | 73 | epochFunc epochFunc 74 | hwAddrFunc hwAddrFunc 75 | lastTime uint64 76 | clockSequence uint16 77 | hardwareAddr [6]byte 78 | } 79 | 80 | func newRFC4122Generator() Generator { 81 | return &rfc4122Generator{ 82 | epochFunc: time.Now, 83 | hwAddrFunc: defaultHWAddrFunc, 84 | rand: rand.Reader, 85 | } 86 | } 87 | 88 | // NewV1 returns UUID based on current timestamp and MAC address. 89 | func (g *rfc4122Generator) NewV1() (UUID, error) { 90 | u := UUID{} 91 | 92 | timeNow, clockSeq, err := g.getClockSequence() 93 | if err != nil { 94 | return Nil, err 95 | } 96 | binary.BigEndian.PutUint32(u[0:], uint32(timeNow)) 97 | binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) 98 | binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) 99 | binary.BigEndian.PutUint16(u[8:], clockSeq) 100 | 101 | hardwareAddr, err := g.getHardwareAddr() 102 | if err != nil { 103 | return Nil, err 104 | } 105 | copy(u[10:], hardwareAddr) 106 | 107 | u.SetVersion(V1) 108 | u.SetVariant(VariantRFC4122) 109 | 110 | return u, nil 111 | } 112 | 113 | // NewV2 returns DCE Security UUID based on POSIX UID/GID. 114 | func (g *rfc4122Generator) NewV2(domain byte) (UUID, error) { 115 | u, err := g.NewV1() 116 | if err != nil { 117 | return Nil, err 118 | } 119 | 120 | switch domain { 121 | case DomainPerson: 122 | binary.BigEndian.PutUint32(u[:], posixUID) 123 | case DomainGroup: 124 | binary.BigEndian.PutUint32(u[:], posixGID) 125 | } 126 | 127 | u[9] = domain 128 | 129 | u.SetVersion(V2) 130 | u.SetVariant(VariantRFC4122) 131 | 132 | return u, nil 133 | } 134 | 135 | // NewV3 returns UUID based on MD5 hash of namespace UUID and name. 136 | func (g *rfc4122Generator) NewV3(ns UUID, name string) UUID { 137 | u := newFromHash(md5.New(), ns, name) 138 | u.SetVersion(V3) 139 | u.SetVariant(VariantRFC4122) 140 | 141 | return u 142 | } 143 | 144 | // NewV4 returns random generated UUID. 145 | func (g *rfc4122Generator) NewV4() (UUID, error) { 146 | u := UUID{} 147 | if _, err := io.ReadFull(g.rand, u[:]); err != nil { 148 | return Nil, err 149 | } 150 | u.SetVersion(V4) 151 | u.SetVariant(VariantRFC4122) 152 | 153 | return u, nil 154 | } 155 | 156 | // NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. 157 | func (g *rfc4122Generator) NewV5(ns UUID, name string) UUID { 158 | u := newFromHash(sha1.New(), ns, name) 159 | u.SetVersion(V5) 160 | u.SetVariant(VariantRFC4122) 161 | 162 | return u 163 | } 164 | 165 | // Returns epoch and clock sequence. 166 | func (g *rfc4122Generator) getClockSequence() (uint64, uint16, error) { 167 | var err error 168 | g.clockSequenceOnce.Do(func() { 169 | buf := make([]byte, 2) 170 | if _, err = io.ReadFull(g.rand, buf); err != nil { 171 | return 172 | } 173 | g.clockSequence = binary.BigEndian.Uint16(buf) 174 | }) 175 | if err != nil { 176 | return 0, 0, err 177 | } 178 | 179 | g.storageMutex.Lock() 180 | defer g.storageMutex.Unlock() 181 | 182 | timeNow := g.getEpoch() 183 | // Clock didn't change since last UUID generation. 184 | // Should increase clock sequence. 185 | if timeNow <= g.lastTime { 186 | g.clockSequence++ 187 | } 188 | g.lastTime = timeNow 189 | 190 | return timeNow, g.clockSequence, nil 191 | } 192 | 193 | // Returns hardware address. 194 | func (g *rfc4122Generator) getHardwareAddr() ([]byte, error) { 195 | var err error 196 | g.hardwareAddrOnce.Do(func() { 197 | if hwAddr, err := g.hwAddrFunc(); err == nil { 198 | copy(g.hardwareAddr[:], hwAddr) 199 | return 200 | } 201 | 202 | // Initialize hardwareAddr randomly in case 203 | // of real network interfaces absence. 204 | if _, err = io.ReadFull(g.rand, g.hardwareAddr[:]); err != nil { 205 | return 206 | } 207 | // Set multicast bit as recommended by RFC 4122 208 | g.hardwareAddr[0] |= 0x01 209 | }) 210 | if err != nil { 211 | return []byte{}, err 212 | } 213 | return g.hardwareAddr[:], nil 214 | } 215 | 216 | // Returns difference in 100-nanosecond intervals between 217 | // UUID epoch (October 15, 1582) and current time. 218 | func (g *rfc4122Generator) getEpoch() uint64 { 219 | return epochStart + uint64(g.epochFunc().UnixNano()/100) 220 | } 221 | 222 | // Returns UUID based on hashing of namespace UUID and name. 223 | func newFromHash(h hash.Hash, ns UUID, name string) UUID { 224 | u := UUID{} 225 | h.Write(ns[:]) 226 | h.Write([]byte(name)) 227 | copy(u[:], h.Sum(nil)) 228 | 229 | return u 230 | } 231 | 232 | // Returns hardware address. 233 | func defaultHWAddrFunc() (net.HardwareAddr, error) { 234 | ifaces, err := net.Interfaces() 235 | if err != nil { 236 | return []byte{}, err 237 | } 238 | for _, iface := range ifaces { 239 | if len(iface.HardwareAddr) >= 6 { 240 | return iface.HardwareAddr, nil 241 | } 242 | } 243 | return []byte{}, fmt.Errorf("uuid: no HW address found") 244 | } 245 | -------------------------------------------------------------------------------- /client/rpc/mock/abci.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import ( 4 | "github.com/bnb-chain/go-sdk/client/rpc" 5 | abci "github.com/tendermint/tendermint/abci/types" 6 | cmn "github.com/tendermint/tendermint/libs/common" 7 | "github.com/tendermint/tendermint/proxy" 8 | "github.com/tendermint/tendermint/rpc/client" 9 | ctypes "github.com/tendermint/tendermint/rpc/core/types" 10 | "github.com/tendermint/tendermint/types" 11 | ) 12 | 13 | // ABCIApp will send all abci related request to the named app, 14 | // so you can test app behavior from a client without needing 15 | // an entire tendermint node 16 | type ABCIApp struct { 17 | App abci.Application 18 | } 19 | 20 | var ( 21 | _ rpc.ABCIClient = ABCIApp{} 22 | _ rpc.ABCIClient = ABCIMock{} 23 | _ rpc.ABCIClient = (*ABCIRecorder)(nil) 24 | ) 25 | 26 | func (a ABCIApp) ABCIInfo() (*ctypes.ResultABCIInfo, error) { 27 | return &ctypes.ResultABCIInfo{Response: a.App.Info(proxy.RequestInfo)}, nil 28 | } 29 | 30 | func (a ABCIApp) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) { 31 | return a.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions) 32 | } 33 | 34 | func (a ABCIApp) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 35 | q := a.App.Query(abci.RequestQuery{ 36 | Data: data, 37 | Path: path, 38 | Height: opts.Height, 39 | Prove: opts.Prove, 40 | }) 41 | return &ctypes.ResultABCIQuery{Response: q}, nil 42 | } 43 | 44 | // NOTE: Caller should call a.App.Commit() separately, 45 | // this function does not actually wait for a commit. 46 | // TODO: Make it wait for a commit and set res.Height appropriately. 47 | func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*rpc.ResultBroadcastTxCommit, error) { 48 | return &rpc.ResultBroadcastTxCommit{}, nil 49 | } 50 | 51 | func (a ABCIApp) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 52 | c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx}) 53 | // and this gets written in a background thread... 54 | if !c.IsErr() { 55 | go func() { a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx}) }() // nolint: errcheck 56 | } 57 | return &ctypes.ResultBroadcastTx{Code: c.Code, Data: c.Data, Log: c.Log, Hash: tx.Hash()}, nil 58 | } 59 | 60 | func (a ABCIApp) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 61 | c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx}) 62 | // and this gets written in a background thread... 63 | if !c.IsErr() { 64 | go func() { a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx}) }() // nolint: errcheck 65 | } 66 | return &ctypes.ResultBroadcastTx{Code: c.Code, Data: c.Data, Log: c.Log, Hash: tx.Hash()}, nil 67 | } 68 | 69 | // ABCIMock will send all abci related request to the named app, 70 | // so you can test app behavior from a client without needing 71 | // an entire tendermint node 72 | type ABCIMock struct { 73 | Info Call 74 | Query Call 75 | BroadcastCommit Call 76 | Broadcast Call 77 | } 78 | 79 | func (m ABCIMock) ABCIInfo() (*ctypes.ResultABCIInfo, error) { 80 | res, err := m.Info.GetResponse(nil) 81 | if err != nil { 82 | return nil, err 83 | } 84 | return &ctypes.ResultABCIInfo{Response: res.(abci.ResponseInfo)}, nil 85 | } 86 | 87 | func (m ABCIMock) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) { 88 | return m.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions) 89 | } 90 | 91 | func (m ABCIMock) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 92 | res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Prove}) 93 | if err != nil { 94 | return nil, err 95 | } 96 | resQuery := res.(abci.ResponseQuery) 97 | return &ctypes.ResultABCIQuery{Response: resQuery}, nil 98 | } 99 | 100 | func (m ABCIMock) BroadcastTxCommit(tx types.Tx) (*rpc.ResultBroadcastTxCommit, error) { 101 | return &rpc.ResultBroadcastTxCommit{}, nil 102 | } 103 | 104 | func (m ABCIMock) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 105 | res, err := m.Broadcast.GetResponse(tx) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return res.(*ctypes.ResultBroadcastTx), nil 110 | } 111 | 112 | func (m ABCIMock) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 113 | res, err := m.Broadcast.GetResponse(tx) 114 | if err != nil { 115 | return nil, err 116 | } 117 | return res.(*ctypes.ResultBroadcastTx), nil 118 | } 119 | 120 | // ABCIRecorder can wrap another type (ABCIApp, ABCIMock, or Client) 121 | // and record all ABCI related calls. 122 | type ABCIRecorder struct { 123 | Client rpc.ABCIClient 124 | Calls []Call 125 | } 126 | 127 | func NewABCIRecorder(client rpc.ABCIClient) *ABCIRecorder { 128 | return &ABCIRecorder{ 129 | Client: client, 130 | Calls: []Call{}, 131 | } 132 | } 133 | 134 | type QueryArgs struct { 135 | Path string 136 | Data cmn.HexBytes 137 | Height int64 138 | Prove bool 139 | } 140 | 141 | func (r *ABCIRecorder) addCall(call Call) { 142 | r.Calls = append(r.Calls, call) 143 | } 144 | 145 | func (r *ABCIRecorder) ABCIInfo() (*ctypes.ResultABCIInfo, error) { 146 | res, err := r.Client.ABCIInfo() 147 | r.addCall(Call{ 148 | Name: "abci_info", 149 | Response: res, 150 | Error: err, 151 | }) 152 | return res, err 153 | } 154 | 155 | func (r *ABCIRecorder) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) { 156 | return r.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions) 157 | } 158 | 159 | func (r *ABCIRecorder) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 160 | res, err := r.Client.ABCIQueryWithOptions(path, data, opts) 161 | r.addCall(Call{ 162 | Name: "abci_query", 163 | Args: QueryArgs{path, data, opts.Height, opts.Prove}, 164 | Response: res, 165 | Error: err, 166 | }) 167 | return res, err 168 | } 169 | 170 | func (r *ABCIRecorder) BroadcastTxCommit(tx types.Tx) (*rpc.ResultBroadcastTxCommit, error) { 171 | return &rpc.ResultBroadcastTxCommit{}, nil 172 | } 173 | 174 | func (r *ABCIRecorder) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 175 | res, err := r.Client.BroadcastTxAsync(tx) 176 | r.addCall(Call{ 177 | Name: "broadcast_tx_async", 178 | Args: tx, 179 | Response: res, 180 | Error: err, 181 | }) 182 | return res, err 183 | } 184 | 185 | func (r *ABCIRecorder) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 186 | res, err := r.Client.BroadcastTxSync(tx) 187 | r.addCall(Call{ 188 | Name: "broadcast_tx_sync", 189 | Args: tx, 190 | Response: res, 191 | Error: err, 192 | }) 193 | return res, err 194 | } 195 | -------------------------------------------------------------------------------- /types/msg/types.go: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import ( 4 | "math/big" 5 | 6 | sdk "github.com/bnb-chain/go-sdk/common/types" 7 | bridgeTypes "github.com/bnb-chain/node/plugins/bridge/types" 8 | "github.com/bnb-chain/node/plugins/dex/order" 9 | cTypes "github.com/cosmos/cosmos-sdk/types" 10 | "github.com/cosmos/cosmos-sdk/x/bank" 11 | "github.com/cosmos/cosmos-sdk/x/gov" 12 | "github.com/cosmos/cosmos-sdk/x/ibc" 13 | oracleTypes "github.com/cosmos/cosmos-sdk/x/oracle/types" 14 | paramHubTypes "github.com/cosmos/cosmos-sdk/x/paramHub/types" 15 | sidechainTypes "github.com/cosmos/cosmos-sdk/x/sidechain/types" 16 | slashingTypes "github.com/cosmos/cosmos-sdk/x/slashing" 17 | "github.com/cosmos/cosmos-sdk/x/stake" 18 | crossStake "github.com/cosmos/cosmos-sdk/x/stake/cross_stake" 19 | stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" 20 | ) 21 | 22 | type ( 23 | Msg = cTypes.Msg 24 | ) 25 | 26 | // =================== gov module ==================== 27 | const ( 28 | OptionEmpty = gov.OptionEmpty 29 | OptionYes = gov.OptionYes 30 | OptionAbstain = gov.OptionAbstain 31 | OptionNo = gov.OptionNo 32 | OptionNoWithVeto = gov.OptionNoWithVeto 33 | 34 | ProposalTypeNil = gov.ProposalTypeNil 35 | ProposalTypeText = gov.ProposalTypeText 36 | ProposalTypeParameterChange = gov.ProposalTypeParameterChange 37 | ProposalTypeSoftwareUpgrade = gov.ProposalTypeSoftwareUpgrade 38 | ProposalTypeListTradingPair = gov.ProposalTypeListTradingPair 39 | ProposalTypeFeeChange = gov.ProposalTypeFeeChange 40 | 41 | ProposalTypeSCParamsChange = gov.ProposalTypeSCParamsChange 42 | ProposalTypeCSCParamsChange = gov.ProposalTypeCSCParamsChange 43 | ) 44 | 45 | type ( 46 | VoteOption = gov.VoteOption 47 | ProposalKind = gov.ProposalKind 48 | 49 | ListTradingPairParams = gov.ListTradingPairParams 50 | ) 51 | 52 | type ( 53 | SCParam = paramHubTypes.SCParam 54 | SCChangeParams = paramHubTypes.SCChangeParams 55 | CSCParamChange = paramHubTypes.CSCParamChange 56 | IbcParams = ibc.Params 57 | OracleParams = oracleTypes.Params 58 | SlashParams = slashingTypes.Params 59 | StakeParams = stake.Params 60 | ) 61 | 62 | // =================== trade module ==================== 63 | var ( 64 | OrderSide = order.Side 65 | GenerateOrderID = order.GenerateOrderID 66 | ) 67 | 68 | // =================== oracle module ==================== 69 | const ( 70 | OracleChannelId = oracleTypes.RelayPackagesChannelId 71 | PackageHeaderLength = sidechainTypes.PackageHeaderLength 72 | 73 | SynCrossChainPackageType = cTypes.SynCrossChainPackageType 74 | AckCrossChainPackageType = cTypes.AckCrossChainPackageType 75 | FailAckCrossChainPackageType = cTypes.FailAckCrossChainPackageType 76 | ) 77 | 78 | var ( 79 | GetClaimId = oracleTypes.GetClaimId 80 | DecodePackageHeader = sidechainTypes.DecodePackageHeader 81 | ) 82 | 83 | type ( 84 | Package = oracleTypes.Package 85 | Packages = oracleTypes.Packages 86 | 87 | CrossChainPackageType = cTypes.CrossChainPackageType 88 | ) 89 | 90 | type ( 91 | Status = oracleTypes.Status 92 | Prophecy = oracleTypes.Prophecy 93 | DBProphecy = oracleTypes.DBProphecy 94 | OracleRelayer = stakeTypes.OracleRelayer 95 | ) 96 | 97 | type ( 98 | ApproveBindSynPackage = bridgeTypes.ApproveBindSynPackage 99 | BindSynPackage = bridgeTypes.BindSynPackage 100 | TransferOutRefundPackage = bridgeTypes.TransferOutRefundPackage 101 | TransferOutSynPackage = bridgeTypes.TransferOutSynPackage 102 | TransferInSynPackage = bridgeTypes.TransferInSynPackage 103 | MirrorSynPackage = bridgeTypes.MirrorSynPackage 104 | MirrorSyncSynPackage = bridgeTypes.MirrorSyncSynPackage 105 | CommonAckPackage = sidechainTypes.CommonAckPackage 106 | IbcValidatorSetPackage = stakeTypes.IbcValidatorSetPackage 107 | IbcValidator = stakeTypes.IbcValidator 108 | CrossParamChange = paramHubTypes.CSCParamChange 109 | SideDowntimeSlashPackage = slashingTypes.SideSlashPackage 110 | CrossStakeSynPackageFromBSC = crossStake.CrossStakeSynPackageFromBSC 111 | CrossStakeRefundPackage = stakeTypes.CrossStakeRefundPackage 112 | ) 113 | 114 | type CrossChainPackage struct { 115 | PackageType CrossChainPackageType 116 | RelayFee big.Int 117 | Content interface{} 118 | } 119 | 120 | // package type 121 | var protoMetrics = map[sdk.IbcChannelID]map[CrossChainPackageType]func() interface{}{ 122 | sdk.IbcChannelID(1): { 123 | SynCrossChainPackageType: func() interface{} { 124 | return new(ApproveBindSynPackage) 125 | }, 126 | AckCrossChainPackageType: noneExistPackageProto, 127 | FailAckCrossChainPackageType: func() interface{} { 128 | return new(BindSynPackage) 129 | }, 130 | }, 131 | sdk.IbcChannelID(2): { 132 | SynCrossChainPackageType: noneExistPackageProto, 133 | AckCrossChainPackageType: func() interface{} { 134 | return new(TransferOutRefundPackage) 135 | }, 136 | FailAckCrossChainPackageType: func() interface{} { 137 | return new(TransferOutSynPackage) 138 | }, 139 | }, 140 | sdk.IbcChannelID(3): { 141 | SynCrossChainPackageType: func() interface{} { 142 | return new(TransferInSynPackage) 143 | }, 144 | AckCrossChainPackageType: noneExistPackageProto, 145 | FailAckCrossChainPackageType: noneExistPackageProto, 146 | }, 147 | sdk.IbcChannelID(4): { 148 | SynCrossChainPackageType: func() interface{} { 149 | return new(MirrorSynPackage) 150 | }, 151 | AckCrossChainPackageType: noneExistPackageProto, 152 | FailAckCrossChainPackageType: noneExistPackageProto, 153 | }, 154 | sdk.IbcChannelID(5): { 155 | SynCrossChainPackageType: func() interface{} { 156 | return new(MirrorSyncSynPackage) 157 | }, 158 | AckCrossChainPackageType: noneExistPackageProto, 159 | FailAckCrossChainPackageType: noneExistPackageProto, 160 | }, 161 | sdk.IbcChannelID(8): { 162 | SynCrossChainPackageType: noneExistPackageProto, 163 | AckCrossChainPackageType: func() interface{} { 164 | return new(CommonAckPackage) 165 | }, 166 | FailAckCrossChainPackageType: func() interface{} { 167 | return new(IbcValidatorSetPackage) 168 | }, 169 | }, 170 | sdk.IbcChannelID(9): { 171 | SynCrossChainPackageType: noneExistPackageProto, 172 | AckCrossChainPackageType: func() interface{} { 173 | return new(CommonAckPackage) 174 | }, 175 | FailAckCrossChainPackageType: func() interface{} { 176 | return new(CrossParamChange) 177 | }, 178 | }, 179 | sdk.IbcChannelID(11): { 180 | SynCrossChainPackageType: func() interface{} { 181 | return new(SideDowntimeSlashPackage) 182 | }, 183 | AckCrossChainPackageType: noneExistPackageProto, 184 | FailAckCrossChainPackageType: noneExistPackageProto, 185 | }, 186 | sdk.IbcChannelID(16): { 187 | SynCrossChainPackageType: func() interface{} { 188 | return new(CrossStakeSynPackageFromBSC) 189 | }, 190 | AckCrossChainPackageType: func() interface{} { 191 | return new(CrossStakeRefundPackage) 192 | }, 193 | FailAckCrossChainPackageType: noneExistPackageProto, 194 | }, 195 | } 196 | 197 | // =================== bank module ==================== 198 | type ( 199 | Input = bank.Input 200 | Output = bank.Output 201 | ) 202 | 203 | var ( 204 | NewInput = bank.NewInput 205 | NewOutput = bank.NewOutput 206 | ) 207 | 208 | type Transfer struct { 209 | ToAddr cTypes.AccAddress 210 | Coins cTypes.Coins 211 | } 212 | 213 | // =================== staking module ==================== 214 | type ( 215 | Description = stakeTypes.Description 216 | ) 217 | -------------------------------------------------------------------------------- /types/msg/msg.go: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import ( 4 | "github.com/bnb-chain/node/plugins/account" 5 | bTypes "github.com/bnb-chain/node/plugins/bridge/types" 6 | "github.com/bnb-chain/node/plugins/dex/order" 7 | dexTypes "github.com/bnb-chain/node/plugins/dex/types" 8 | "github.com/bnb-chain/node/plugins/tokens/burn" 9 | "github.com/bnb-chain/node/plugins/tokens/freeze" 10 | "github.com/bnb-chain/node/plugins/tokens/issue" 11 | "github.com/bnb-chain/node/plugins/tokens/ownership" 12 | "github.com/bnb-chain/node/plugins/tokens/seturi" 13 | "github.com/bnb-chain/node/plugins/tokens/swap" 14 | "github.com/bnb-chain/node/plugins/tokens/timelock" 15 | cTypes "github.com/cosmos/cosmos-sdk/types" 16 | "github.com/cosmos/cosmos-sdk/x/bank" 17 | "github.com/cosmos/cosmos-sdk/x/gov" 18 | oracleTypes "github.com/cosmos/cosmos-sdk/x/oracle/types" 19 | "github.com/cosmos/cosmos-sdk/x/slashing" 20 | stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" 21 | ) 22 | 23 | // Msg definition 24 | type ( 25 | SmartChainAddress = cTypes.SmartChainAddress 26 | 27 | // bridge module 28 | BindMsg = bTypes.BindMsg 29 | TransferOutMsg = bTypes.TransferOutMsg 30 | UnbindMsg = bTypes.UnbindMsg 31 | 32 | // token module 33 | TokenBurnMsg = burn.BurnMsg 34 | DexListMsg = dexTypes.ListMsg 35 | ListMiniMsg = dexTypes.ListMiniMsg 36 | TokenFreezeMsg = freeze.FreezeMsg 37 | TokenUnfreezeMsg = freeze.UnfreezeMsg 38 | TokenIssueMsg = issue.IssueMsg 39 | MiniTokenIssueMsg = issue.IssueMiniMsg 40 | TinyTokenIssueMsg = issue.IssueTinyMsg 41 | MintMsg = issue.MintMsg 42 | SendMsg = bank.MsgSend 43 | SetURIMsg = seturi.SetURIMsg 44 | TimeLockMsg = timelock.TimeLockMsg 45 | TimeRelockMsg = timelock.TimeRelockMsg 46 | TimeUnlockMsg = timelock.TimeUnlockMsg 47 | TransferOwnershipMsg = ownership.TransferOwnershipMsg 48 | 49 | // gov module 50 | SubmitProposalMsg = gov.MsgSubmitProposal 51 | DepositMsg = gov.MsgDeposit 52 | VoteMsg = gov.MsgVote 53 | SideChainSubmitProposalMsg = gov.MsgSideChainSubmitProposal 54 | SideChainDepositMsg = gov.MsgSideChainDeposit 55 | SideChainVoteMsg = gov.MsgSideChainVote 56 | 57 | // atomic swap module 58 | HTLTMsg = swap.HTLTMsg 59 | DepositHTLTMsg = swap.DepositHTLTMsg 60 | ClaimHTLTMsg = swap.ClaimHTLTMsg 61 | RefundHTLTMsg = swap.RefundHTLTMsg 62 | 63 | // oracle claim module 64 | Claim = oracleTypes.Claim 65 | ClaimMsg = oracleTypes.ClaimMsg 66 | 67 | // trade module 68 | CreateOrderMsg = order.NewOrderMsg 69 | CancelOrderMsg = order.CancelOrderMsg 70 | 71 | // account module 72 | SetAccountFlagsMsg = account.SetAccountFlagsMsg 73 | 74 | // slash module 75 | MsgSideChainUnjail = slashing.MsgSideChainUnjail 76 | MsgUnjail = slashing.MsgUnjail 77 | 78 | // stake module 79 | CreateSideChainValidatorMsg = stakeTypes.MsgCreateSideChainValidator 80 | MsgCreateSideChainValidatorWithVoteAddr = stakeTypes.MsgCreateSideChainValidatorWithVoteAddr 81 | EditSideChainValidatorMsg = stakeTypes.MsgEditSideChainValidator 82 | MsgEditSideChainValidatorWithVoteAddr = stakeTypes.MsgEditSideChainValidatorWithVoteAddr 83 | SideChainDelegateMsg = stakeTypes.MsgSideChainDelegate 84 | SideChainRedelegateMsg = stakeTypes.MsgSideChainRedelegate 85 | SideChainUndelegateMsg = stakeTypes.MsgSideChainUndelegate 86 | MsgCreateValidatorOpen = stakeTypes.MsgCreateValidatorOpen 87 | MsgRemoveValidator = stakeTypes.MsgRemoveValidator 88 | MsgEditValidator = stakeTypes.MsgEditValidator 89 | MsgDelegate = stakeTypes.MsgDelegate 90 | MsgRedelegate = stakeTypes.MsgRedelegate 91 | MsgUndelegate = stakeTypes.MsgUndelegate 92 | MsgSideChainStakeMigration = stakeTypes.MsgSideChainStakeMigration 93 | ) 94 | 95 | var ( 96 | NewSmartChainAddress = cTypes.NewSmartChainAddress 97 | 98 | // bridge module 99 | NewBindMsg = bTypes.NewBindMsg 100 | NewTransferOutMsg = bTypes.NewTransferOutMsg 101 | NewUnbindMsg = bTypes.NewUnbindMsg 102 | 103 | // token module 104 | NewTokenBurnMsg = burn.NewMsg 105 | NewDexListMsg = dexTypes.NewListMsg 106 | NewListMiniMsg = dexTypes.NewListMiniMsg 107 | NewFreezeMsg = freeze.NewFreezeMsg 108 | NewUnfreezeMsg = freeze.NewUnfreezeMsg 109 | NewTokenIssueMsg = issue.NewIssueMsg 110 | NewMiniTokenIssueMsg = issue.NewIssueMiniMsg 111 | NewTinyTokenIssueMsg = issue.NewIssueTinyMsg 112 | NewMintMsg = issue.NewMintMsg 113 | NewMsgSend = bank.NewMsgSend 114 | NewSetUriMsg = seturi.NewSetUriMsg 115 | NewTimeLockMsg = timelock.NewTimeLockMsg 116 | NewTimeRelockMsg = timelock.NewTimeRelockMsg 117 | NewTimeUnlockMsg = timelock.NewTimeUnlockMsg 118 | NewTransferOwnershipMsg = ownership.NewTransferOwnershipMsg 119 | 120 | // gov module 121 | NewDepositMsg = gov.NewMsgDeposit 122 | NewMsgVote = gov.NewMsgVote 123 | NewMsgSubmitProposal = gov.NewMsgSubmitProposal 124 | NewSideChainSubmitProposalMsg = gov.NewMsgSideChainSubmitProposal 125 | NewSideChainDepositMsg = gov.NewMsgSideChainDeposit 126 | NewSideChainVoteMsg = gov.NewMsgSideChainVote 127 | 128 | // atomic swap module 129 | NewHTLTMsg = swap.NewHTLTMsg 130 | NewDepositHTLTMsg = swap.NewDepositHTLTMsg 131 | NewClaimHTLTMsg = swap.NewClaimHTLTMsg 132 | NewRefundHTLTMsg = swap.NewRefundHTLTMsg 133 | 134 | // oracle claim module 135 | NewClaim = oracleTypes.NewClaim 136 | NewClaimMsg = oracleTypes.NewClaimMsg 137 | 138 | // trade module 139 | NewCreateOrderMsg = order.NewNewOrderMsg 140 | NewCancelOrderMsg = order.NewCancelOrderMsg 141 | 142 | // account module 143 | NewSetAccountFlagsMsg = account.NewSetAccountFlagsMsg 144 | 145 | // slash module 146 | NewMsgSideChainUnjail = slashing.NewMsgSideChainUnjail 147 | NewMsgUnjail = slashing.NewMsgUnjail 148 | 149 | // stake module 150 | NewCreateSideChainValidatorMsg = stakeTypes.NewMsgCreateSideChainValidator 151 | NewCreateSideChainValidatorMsgWithVoteAddr = stakeTypes.NewMsgCreateSideChainValidatorWithVoteAddr 152 | NewMsgCreateSideChainValidatorOnBehalfOf = stakeTypes.NewMsgCreateSideChainValidatorOnBehalfOf 153 | NewMsgCreateSideChainValidatorOnBehalfOfWithVoteAddr = stakeTypes.NewMsgCreateSideChainValidatorWithVoteAddrOnBehalfOf 154 | NewEditSideChainValidatorMsg = stakeTypes.NewMsgEditSideChainValidator 155 | NewEditSideChainValidatorMsgWithVoteAddr = stakeTypes.NewMsgEditSideChainValidatorWithVoteAddr 156 | NewSideChainDelegateMsg = stakeTypes.NewMsgSideChainDelegate 157 | NewSideChainRedelegateMsg = stakeTypes.NewMsgSideChainRedelegate 158 | NewSideChainUndelegateMsg = stakeTypes.NewMsgSideChainUndelegate 159 | NewMsgCreateValidatorOpen = stakeTypes.NewMsgRemoveValidator 160 | NewMsgRemoveValidator = stakeTypes.NewMsgRemoveValidator 161 | NewMsgEditValidator = stakeTypes.NewMsgEditValidator 162 | NewMsgDelegate = stakeTypes.NewMsgDelegate 163 | NewMsgRedelegate = stakeTypes.NewMsgRedelegate 164 | NewMsgUndelegate = stakeTypes.NewMsgUndelegate 165 | ) 166 | -------------------------------------------------------------------------------- /client/rpc/basic_client.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/pkg/errors" 8 | cmn "github.com/tendermint/tendermint/libs/common" 9 | "github.com/tendermint/tendermint/rpc/client" 10 | ctypes "github.com/tendermint/tendermint/rpc/core/types" 11 | rpcclient "github.com/tendermint/tendermint/rpc/lib/client" 12 | "github.com/tendermint/tendermint/types" 13 | 14 | ntypes "github.com/bnb-chain/go-sdk/common/types" 15 | "github.com/bnb-chain/go-sdk/keys" 16 | "github.com/bnb-chain/go-sdk/types/tx" 17 | ) 18 | 19 | var DefaultTimeout = 5 * time.Second 20 | 21 | type ABCIClient interface { 22 | // Reading from abci app 23 | ABCIInfo() (*ctypes.ResultABCIInfo, error) 24 | ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) 25 | ABCIQueryWithOptions(path string, data cmn.HexBytes, 26 | opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) 27 | 28 | // Writing to abci app 29 | BroadcastTxCommit(tx types.Tx) (*ResultBroadcastTxCommit, error) 30 | BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) 31 | BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) 32 | } 33 | 34 | type SignClient interface { 35 | Block(height *int64) (*ctypes.ResultBlock, error) 36 | BlockResults(height *int64) (*ResultBlockResults, error) 37 | Commit(height *int64) (*ctypes.ResultCommit, error) 38 | Validators(height *int64) (*ctypes.ResultValidators, error) 39 | Tx(hash []byte, prove bool) (*ResultTx, error) 40 | TxSearch(query string, prove bool, page, perPage int) (*ResultTxSearch, error) 41 | } 42 | 43 | type Client interface { 44 | cmn.Service 45 | ABCIClient 46 | SignClient 47 | client.HistoryClient 48 | client.StatusClient 49 | EventsClient 50 | DexClient 51 | OpsClient 52 | StakingClient 53 | } 54 | 55 | type EventsClient interface { 56 | Subscribe(query string, outCapacity ...int) (out chan ctypes.ResultEvent, err error) 57 | Unsubscribe(query string) error 58 | UnsubscribeAll() error 59 | } 60 | 61 | func NewRPCClient(nodeURI string, network ntypes.ChainNetwork) *HTTP { 62 | ntypes.SetNetwork(network) 63 | return NewHTTP(nodeURI, "/websocket") 64 | } 65 | 66 | type HTTP struct { 67 | *WSEvents 68 | 69 | key keys.KeyManager 70 | } 71 | 72 | // NewHTTP takes a remote endpoint in the form tcp://: 73 | // and the websocket path (which always seems to be "/websocket") 74 | func NewHTTP(remote, wsEndpoint string) *HTTP { 75 | rc := rpcclient.NewJSONRPCClient(remote) 76 | cdc := rc.Codec() 77 | ctypes.RegisterAmino(cdc) 78 | ntypes.RegisterWire(cdc) 79 | tx.RegisterCodec(cdc) 80 | 81 | rc.SetCodec(cdc) 82 | wsEvent := newWSEvents(cdc, remote, wsEndpoint) 83 | client := &HTTP{ 84 | WSEvents: wsEvent, 85 | } 86 | client.Start() 87 | return client 88 | } 89 | 90 | func (c *HTTP) Status() (*ctypes.ResultStatus, error) { 91 | return c.WSEvents.Status() 92 | } 93 | 94 | func (c *HTTP) ABCIInfo() (*ctypes.ResultABCIInfo, error) { 95 | return c.WSEvents.ABCIInfo() 96 | } 97 | 98 | func (c *HTTP) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) { 99 | return c.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions) 100 | } 101 | 102 | func (c *HTTP) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 103 | if err := ValidateABCIPath(path); err != nil { 104 | return nil, err 105 | } 106 | if err := ValidateABCIData(data); err != nil { 107 | return nil, err 108 | } 109 | return c.WSEvents.ABCIQueryWithOptions(path, data, opts) 110 | } 111 | 112 | func (c *HTTP) BroadcastTxCommit(tx types.Tx) (*ResultBroadcastTxCommit, error) { 113 | if err := ValidateTx(tx); err != nil { 114 | return nil, err 115 | } 116 | return c.WSEvents.BroadcastTxCommit(tx) 117 | } 118 | 119 | func (c *HTTP) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 120 | if err := ValidateTx(tx); err != nil { 121 | return nil, err 122 | } 123 | return c.WSEvents.BroadcastTx("broadcast_tx_async", tx) 124 | } 125 | 126 | func (c *HTTP) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 127 | if err := ValidateTx(tx); err != nil { 128 | return nil, err 129 | } 130 | return c.WSEvents.BroadcastTx("broadcast_tx_sync", tx) 131 | } 132 | 133 | func (c *HTTP) UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error) { 134 | if err := ValidateUnConfirmedTxsLimit(limit); err != nil { 135 | return nil, err 136 | } 137 | return c.WSEvents.UnconfirmedTxs(limit) 138 | } 139 | 140 | func (c *HTTP) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) { 141 | return c.WSEvents.NumUnconfirmedTxs() 142 | } 143 | 144 | func (c *HTTP) NetInfo() (*ctypes.ResultNetInfo, error) { 145 | return c.WSEvents.NetInfo() 146 | } 147 | 148 | func (c *HTTP) DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) { 149 | return c.WSEvents.DumpConsensusState() 150 | } 151 | 152 | func (c *HTTP) ConsensusState() (*ctypes.ResultConsensusState, error) { 153 | return c.WSEvents.ConsensusState() 154 | } 155 | 156 | func (c *HTTP) Health() (*ctypes.ResultHealth, error) { 157 | return c.WSEvents.Health() 158 | } 159 | 160 | func (c *HTTP) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) { 161 | if err := ValidateHeightRange(minHeight, maxHeight); err != nil { 162 | return nil, err 163 | } 164 | return c.WSEvents.BlockchainInfo(minHeight, maxHeight) 165 | } 166 | 167 | func (c *HTTP) Genesis() (*ctypes.ResultGenesis, error) { 168 | return c.WSEvents.Genesis() 169 | } 170 | 171 | func (c *HTTP) Block(height *int64) (*ctypes.ResultBlock, error) { 172 | if err := ValidateHeight(height); err != nil { 173 | return nil, err 174 | } 175 | return c.WSEvents.Block(height) 176 | } 177 | 178 | func (c *HTTP) BlockResults(height *int64) (*ResultBlockResults, error) { 179 | if err := ValidateHeight(height); err != nil { 180 | return nil, err 181 | } 182 | return c.WSEvents.BlockResults(height) 183 | } 184 | 185 | func (c *HTTP) Commit(height *int64) (*ctypes.ResultCommit, error) { 186 | if err := ValidateHeight(height); err != nil { 187 | return nil, err 188 | } 189 | return c.WSEvents.Commit(height) 190 | } 191 | 192 | func (c *HTTP) Tx(hash []byte, prove bool) (*ResultTx, error) { 193 | if err := ValidateHash(hash); err != nil { 194 | return nil, err 195 | } 196 | return c.WSEvents.Tx(hash, prove) 197 | } 198 | 199 | func (c *HTTP) TxSearch(query string, prove bool, page, perPage int) (*ResultTxSearch, error) { 200 | if err := ValidateABCIQueryStr(query); err != nil { 201 | return nil, err 202 | } 203 | return c.WSEvents.TxSearch(query, prove, page, perPage) 204 | } 205 | 206 | func (c *HTTP) Validators(height *int64) (*ctypes.ResultValidators, error) { 207 | if err := ValidateHeight(height); err != nil { 208 | return nil, err 209 | } 210 | return c.WSEvents.Validators(height) 211 | } 212 | 213 | func (c *HTTP) QueryWithData(path string, data cmn.HexBytes) ([]byte, error) { 214 | result, err := c.ABCIQuery(path, data) 215 | 216 | if err != nil { 217 | return nil, err 218 | } 219 | 220 | resp := result.Response 221 | if !resp.IsOK() { 222 | return nil, errors.Errorf(resp.Log) 223 | } 224 | 225 | return resp.Value, nil 226 | } 227 | 228 | func (c *HTTP) QueryStore(key cmn.HexBytes, storeName string) ([]byte, error) { 229 | path := fmt.Sprintf("/store/%s/%s", storeName, "key") 230 | result, err := c.ABCIQuery(path, key) 231 | if err != nil { 232 | return nil, err 233 | } 234 | resp := result.Response 235 | if !resp.IsOK() { 236 | return nil, errors.Errorf(resp.Log) 237 | } 238 | return resp.Value, nil 239 | } 240 | 241 | func (c *HTTP) QueryStoreSubspace(key cmn.HexBytes, storeName string) (res []cmn.KVPair, err error) { 242 | path := fmt.Sprintf("/store/%s/subspace", storeName) 243 | result, err := c.ABCIQuery(path, key) 244 | if err != nil { 245 | return res, err 246 | } 247 | 248 | resp := result.Response 249 | if !resp.IsOK() { 250 | return nil, errors.Errorf(resp.Log) 251 | } 252 | 253 | if len(resp.Value) == 0 { 254 | return nil, EmptyResultError 255 | } 256 | 257 | err = c.cdc.UnmarshalBinaryLengthPrefixed(resp.Value, &res) 258 | 259 | if err != nil { 260 | return nil, err 261 | } 262 | 263 | return 264 | } 265 | 266 | func (c *HTTP) SetKeyManager(k keys.KeyManager) { 267 | c.key = k 268 | } 269 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # BNB Beacon Chain Go SDK 2 | 3 | The BNB Beacon Chain GO SDK provides a thin wrapper around the BNB Beacon Chain API for readonly endpoints, in addition to creating and submitting different transactions. 4 | It includes the following core components: 5 | 6 | * **client** - implementations of BNB Beacon Chain transaction types and query, such as for transfers and trading. 7 | * **common** - core cryptographic functions, uuid functions and other useful functions. 8 | * **e2e** - end-to-end test package for go-sdk developer. For common users, it is also a good reference to use go-sdk. 9 | * **keys** - implement `KeyManage` to manage private key and accounts. 10 | * **types** - core type of BNB Beacon Chain, such as `coin`, `account`, `tx` and `msg`. 11 | 12 | ## Install 13 | 14 | ### Requirement 15 | 16 | Go version above 1.17 17 | 18 | ### Use go mod 19 | 20 | Add "github.com/bnb-chain/go-sdk" dependency into your go.mod file. Example: 21 | ```go 22 | require ( 23 | github.com/bnb-chain/go-sdk latest 24 | ) 25 | 26 | // Copy the same replace dep from https://github.com/bnb-chain/go-sdk/blob/master/go.mod 27 | replace ( 28 | github.com/cosmos/cosmos-sdk => github.com/bnb-chain/bnc-cosmos-sdk v0.25.4-0.20221221115251-f9e69ff1b273 29 | github.com/tendermint/go-amino => github.com/bnb-chain/bnc-go-amino v0.14.1-binance.2 30 | github.com/tendermint/iavl => github.com/bnb-chain/bnc-tendermint-iavl v0.12.0-binance.4 31 | github.com/tendermint/tendermint => github.com/bnb-chain/bnc-tendermint v0.32.3-binance.3.0.20221109023026-379ddbab19d1 32 | github.com/zondax/ledger-cosmos-go => github.com/bnb-chain/ledger-cosmos-go v0.9.9-binance.3 33 | github.com/zondax/ledger-go => github.com/bnb-chain/ledger-go v0.9.1 34 | golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae 35 | ) 36 | ``` 37 | 38 | **NOTE**: Please make sure you have the same replace dep as [go.mod](https://github.com/bnb-chain/go-sdk/blob/master/go.mod). 39 | 40 | ## Usage 41 | 42 | ### Key Manager 43 | 44 | Before start using API, you should construct a Key Manager to help sign the transaction msg or verify signature. 45 | Key Manager is an Identity Manager to define who you are in the bnbchain. It provide following interface: 46 | 47 | ```go 48 | type KeyManager interface { 49 | Sign(tx.StdSignMsg) ([]byte, error) 50 | GetPrivKey() crypto.PrivKey 51 | GetAddr() txmsg.AccAddress 52 | 53 | ExportAsMnemonic() (string, error) 54 | ExportAsPrivateKey() (string, error) 55 | ExportAsKeyStore(password string) (*EncryptedKeyJSON, error) 56 | } 57 | ``` 58 | 59 | We provide four construct functions to generate Key Manager: 60 | ```go 61 | NewKeyManager() (KeyManager, error) 62 | 63 | NewMnemonicKeyManager(mnemonic string) (KeyManager, error) 64 | 65 | NewMnemonicPathKeyManager(mnemonic, keyPath string) (KeyManager, error) 66 | 67 | NewKeyStoreKeyManager(file string, auth string) (KeyManager, error) 68 | 69 | NewPrivateKeyManager(priKey string) (KeyManager, error) 70 | 71 | NewLedgerKeyManager(path ledger.DerivationPath) (KeyManager, error) 72 | 73 | ``` 74 | - NewKeyManager. You will get a new private key without provide anything, you can export and save this `KeyManager`. 75 | - NewMnemonicKeyManager. You should provide your mnemonic, usually is a string of 24 words. 76 | - NewMnemonicPathKeyManager. The difference between `NewMnemonicKeyManager` is that you can use custom keypath to generate different `keyManager` while using the same mnemonic. 5 levels in BIP44 path: "purpose' / coin_type' / account' / change / address_index", "purpose' / coin_type'" is fixed as "44'/714'/", you can customize the rest part. 77 | - NewKeyStoreKeyManager. You should provide a keybase json file and you password, you can download the key base json file when your create a wallet account. 78 | - NewPrivateKeyManager. You should provide a Hex encoded string of your private key. 79 | - NewLedgerKeyManager. You must have a ledger device with BNB Beacon Chain ledger app and connect it to your machine. 80 | 81 | Examples: 82 | 83 | From mnemonic: 84 | ```Go 85 | mnemonic := "lock globe panda armed mandate fabric couple dove climb step stove price recall decrease fire sail ring media enhance excite deny valid ceiling arm" 86 | keyManager, _ := keys.NewMnemonicKeyManager(mnemonic) 87 | ``` 88 | 89 | From key base file: 90 | ```GO 91 | file := "testkeystore.json" 92 | keyManager, err := NewKeyStoreKeyManager(file, "your password") 93 | 94 | ``` 95 | 96 | From raw private key string: 97 | ```GO 98 | priv := "9579fff0cab07a4379e845a890105004ba4c8276f8ad9d22082b2acbf02d884b" 99 | keyManager, err := NewPrivateKeyManager(priv) 100 | ``` 101 | 102 | From ledger device: 103 | ```GO 104 | bip44Params := keys.NewBinanceBIP44Params(0, 0) 105 | keyManager, err := NewLedgerKeyManager(bip44Params.DerivationPath()) 106 | ``` 107 | 108 | We provide three export functions to persistent a Key Manager: 109 | 110 | ```go 111 | ExportAsMnemonic() (string, error) 112 | 113 | ExportAsPrivateKey() (string, error) 114 | 115 | ExportAsKeyStore(password string) (*EncryptedKeyJSON, error) 116 | ``` 117 | 118 | Examples: 119 | ```go 120 | km, _ := NewKeyManager() 121 | encryPlain1, _ := km.GetPrivKey().Sign([]byte("test plain")) 122 | keyJSONV1, err := km.ExportAsKeyStore("testpassword") 123 | bz, _ := json.Marshal(keyJSONV1) 124 | ioutil.WriteFile("TestGenerateKeyStoreNoError.json", bz, 0660) 125 | newkm, _ := NewKeyStoreKeyManager("TestGenerateKeyStoreNoError.json", "testpassword") 126 | encryPlain2, _ := newkm.GetPrivKey().Sign([]byte("test plain")) 127 | assert.True(t, bytes.Equal(encryPlain1, encryPlain2)) 128 | ``` 129 | **As for ledger key, it can't be exported. Because its private key is saved on ledger device and no one can directly access it outside.** 130 | 131 | ### Init Client 132 | 133 | ```GO 134 | import sdk "https://github.com/bnb-chain/go-sdk/tree/master/client" 135 | 136 | mnemonic := "lock globe panda armed mandate fabric couple dove climb step stove price recall decrease fire sail ring media enhance excite deny valid ceiling arm" 137 | //----- Init KeyManager ------------- 138 | keyManager, _ := keys.NewMnemonicKeyManager(mnemonic) 139 | 140 | //----- Init sdk ------------- 141 | client, err := sdk.NewDexClient("testnet-dex.binance.org", types.TestNetwork, keyManager) 142 | 143 | ``` 144 | For sdk init, you should know the famous api address. Besides, you should know what kind of network the api gateway is in, since we have different configurations for 145 | test network and production network. 146 | 147 | | ChainNetwork | ApiAddr | 148 | |-------------- |----------------------------------| 149 | | TestNetwork | testnet-dex.binance.org | 150 | | ProdNetwork | dex.binance.org | | 151 | 152 | If you want broadcast some transactions, like send coins, create orders or cancel orders, you should construct a key manager. 153 | 154 | 155 | ### Example 156 | 157 | Create a `SendToken` transaction: 158 | ```go 159 | client.SendToken([]msg.Transfer{{testAccount, []ctypes.Coin{{nativeSymbol, 100000000}}}}, true) 160 | ``` 161 | 162 | If want to attach memo or source to the transaction, more `WithSource` and `WithMemo` options are required: 163 | ```go 164 | client.SendToken([]msg.Transfer{{testAccount, []ctypes.Coin{{nativeSymbol, 100000000}}}}, true, transaction.WithSource(100),transaction.WithMemo("test memo")) 165 | ``` 166 | 167 | In some scenarios, continuously send multi transactions very fast. Before the previous transaction being included in the chain, the next transaction is being sent, to avoid sequence mismatch error, option `WithAcNumAndSequence` is required: 168 | ``` 169 | acc,err:=client.GetAccount(client.GetKeyManager().GetAddr().String()) 170 | _, err = client.SendToken([]msg.Transfer{{testAccount, []ctypes.Coin{{nativeSymbol, 100000000}}}}, true, transaction.WithAcNumAndSequence(acc.Number,acc.Sequence)) 171 | _, err = client.SendToken([]msg.Transfer{{testAccount, []ctypes.Coin{{nativeSymbol, 100000000}}}}, true, transaction.WithAcNumAndSequence(acc.Number,acc.Sequence+1)) 172 | _, err = client.SendToken([]msg.Transfer{{testAccount, []ctypes.Coin{{nativeSymbol, 100000000}}}}, true, transaction.WithAcNumAndSequence(acc.Number,acc.Sequence+2)) 173 | ``` 174 | 175 | For more API usage documentation, please check the [wiki](https://github.com/bnb-chain/go-sdk/wiki).. 176 | 177 | ## RPC Client 178 | RPC endpoints may be used to interact with a node directly over HTTP or websockets. Using RPC, you may perform low-level 179 | operations like executing ABCI queries, viewing network/consensus state or broadcasting a transaction against full node or 180 | light client. 181 | 182 | ### Example 183 | ```go 184 | nodeAddr := "tcp://127.0.0.1:27147" 185 | testClientInstance := rpc.NewRPCClient(nodeAddr,types.TestNetwork) 186 | status, err := c.Status() 187 | ``` 188 | -------------------------------------------------------------------------------- /keys/keys.go: -------------------------------------------------------------------------------- 1 | package keys 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/hex" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "strings" 10 | 11 | "github.com/cosmos/go-bip39" 12 | "golang.org/x/crypto/pbkdf2" 13 | "golang.org/x/crypto/sha3" 14 | 15 | "github.com/tendermint/tendermint/crypto/secp256k1" 16 | 17 | "github.com/bnb-chain/go-sdk/common" 18 | "github.com/bnb-chain/go-sdk/common/ledger" 19 | "github.com/bnb-chain/go-sdk/common/types" 20 | ctypes "github.com/bnb-chain/go-sdk/common/types" 21 | "github.com/bnb-chain/go-sdk/common/uuid" 22 | "github.com/bnb-chain/go-sdk/types/tx" 23 | "github.com/tendermint/tendermint/crypto" 24 | ) 25 | 26 | const ( 27 | defaultBIP39Passphrase = "" 28 | ) 29 | 30 | type KeyManager interface { 31 | Sign(msg tx.StdSignMsg) ([]byte, error) 32 | GetPrivKey() crypto.PrivKey 33 | GetAddr() ctypes.AccAddress 34 | 35 | ExportAsMnemonic() (string, error) 36 | ExportAsPrivateKey() (string, error) 37 | ExportAsKeyStore(password string) (*EncryptedKeyJSON, error) 38 | } 39 | 40 | func NewMnemonicKeyManager(mnemonic string) (KeyManager, error) { 41 | k := keyManager{} 42 | err := k.recoveryFromMnemonic(mnemonic, FullPath) 43 | return &k, err 44 | } 45 | 46 | // The full path is "purpose' / coin_type' / account' / change / address_index". 47 | // "purpose' / coin_type'" is fixed as "44'/714'/", user can customize the rest part. 48 | func NewMnemonicPathKeyManager(mnemonic, keyPath string) (KeyManager, error) { 49 | k := keyManager{} 50 | err := k.recoveryFromMnemonic(mnemonic, BIP44Prefix+keyPath) 51 | return &k, err 52 | } 53 | 54 | func NewKeyStoreKeyManager(file string, auth string) (KeyManager, error) { 55 | k := keyManager{} 56 | err := k.recoveryFromKeyStore(file, auth) 57 | return &k, err 58 | } 59 | 60 | func NewPrivateKeyManager(priKey string) (KeyManager, error) { 61 | k := keyManager{} 62 | err := k.recoveryFromPrivateKey(priKey) 63 | return &k, err 64 | } 65 | 66 | func NewLedgerKeyManager(path ledger.DerivationPath) (KeyManager, error) { 67 | k := keyManager{} 68 | err := k.recoveryFromLedgerKey(path) 69 | return &k, err 70 | } 71 | 72 | type keyManager struct { 73 | privKey crypto.PrivKey 74 | addr ctypes.AccAddress 75 | mnemonic string 76 | } 77 | 78 | func (m *keyManager) ExportAsMnemonic() (string, error) { 79 | if m.mnemonic == "" { 80 | return "", fmt.Errorf("This key manager is not recover from mnemonic or anto generated ") 81 | } 82 | return m.mnemonic, nil 83 | } 84 | 85 | func (m *keyManager) ExportAsPrivateKey() (string, error) { 86 | secpPrivateKey, ok := m.privKey.(secp256k1.PrivKeySecp256k1) 87 | if !ok { 88 | return "", fmt.Errorf(" Only PrivKeySecp256k1 key is supported ") 89 | } 90 | return hex.EncodeToString(secpPrivateKey[:]), nil 91 | } 92 | 93 | func (m *keyManager) ExportAsKeyStore(password string) (*EncryptedKeyJSON, error) { 94 | return generateKeyStore(m.GetPrivKey(), password) 95 | } 96 | 97 | func NewKeyManager() (KeyManager, error) { 98 | entropy, err := bip39.NewEntropy(256) 99 | if err != nil { 100 | return nil, err 101 | } 102 | mnemonic, err := bip39.NewMnemonic(entropy) 103 | if err != nil { 104 | return nil, err 105 | } 106 | return NewMnemonicKeyManager(mnemonic) 107 | } 108 | 109 | func (m *keyManager) recoveryFromMnemonic(mnemonic, keyPath string) error { 110 | words := strings.Split(mnemonic, " ") 111 | if len(words) != 12 && len(words) != 24 { 112 | return fmt.Errorf("mnemonic length should either be 12 or 24") 113 | } 114 | seed, err := bip39.NewSeedWithErrorChecking(mnemonic, defaultBIP39Passphrase) 115 | if err != nil { 116 | return err 117 | } 118 | // create master key and derive first key: 119 | masterPriv, ch := ComputeMastersFromSeed(seed) 120 | derivedPriv, err := DerivePrivateKeyForPath(masterPriv, ch, keyPath) 121 | if err != nil { 122 | return err 123 | } 124 | priKey := secp256k1.PrivKeySecp256k1(derivedPriv[:]) 125 | addr := ctypes.AccAddress(priKey.PubKey().Address()) 126 | if err != nil { 127 | return err 128 | } 129 | m.addr = addr 130 | m.privKey = priKey 131 | m.mnemonic = mnemonic 132 | return nil 133 | } 134 | 135 | func (m *keyManager) recoveryFromKeyStore(keystoreFile string, auth string) error { 136 | if auth == "" { 137 | return fmt.Errorf("Password is missing ") 138 | } 139 | keyJson, err := ioutil.ReadFile(keystoreFile) 140 | if err != nil { 141 | return err 142 | } 143 | var encryptedKey EncryptedKeyJSON 144 | err = json.Unmarshal(keyJson, &encryptedKey) 145 | if err != nil { 146 | return err 147 | } 148 | keyBytes, err := decryptKey(&encryptedKey, auth) 149 | if err != nil { 150 | return err 151 | } 152 | if len(keyBytes) != 32 { 153 | return fmt.Errorf("Len of Keybytes is not equal to 32 ") 154 | } 155 | var keyBytesArray [32]byte 156 | copy(keyBytesArray[:], keyBytes[:32]) 157 | priKey := secp256k1.PrivKeySecp256k1(keyBytesArray[:]) 158 | addr := ctypes.AccAddress(priKey.PubKey().Address()) 159 | m.addr = addr 160 | m.privKey = priKey 161 | return nil 162 | } 163 | 164 | func (m *keyManager) recoveryFromPrivateKey(privateKey string) error { 165 | priBytes, err := hex.DecodeString(privateKey) 166 | if err != nil { 167 | return err 168 | } 169 | 170 | if len(priBytes) != 32 { 171 | return fmt.Errorf("Len of Keybytes is not equal to 32 ") 172 | } 173 | var keyBytesArray [32]byte 174 | copy(keyBytesArray[:], priBytes[:32]) 175 | priKey := secp256k1.PrivKeySecp256k1(keyBytesArray[:]) 176 | addr := ctypes.AccAddress(priKey.PubKey().Address()) 177 | m.addr = addr 178 | m.privKey = priKey 179 | return nil 180 | } 181 | 182 | func (m *keyManager) recoveryFromLedgerKey(path ledger.DerivationPath) error { 183 | if ledger.DiscoverLedger == nil { 184 | return fmt.Errorf("no Ledger discovery function defined, please make sure you have added ledger to build tags and cgo is enabled") 185 | } 186 | 187 | device, err := ledger.DiscoverLedger() 188 | if err != nil { 189 | return fmt.Errorf("failed to find ledger device: %s", err.Error()) 190 | } 191 | 192 | pkl, err := ledger.GenLedgerSecp256k1Key(path, device) 193 | if err != nil { 194 | return fmt.Errorf("failed to create PrivKeyLedgerSecp256k1: %s", err.Error()) 195 | } 196 | 197 | addr := types.AccAddress(pkl.PubKey().Address()) 198 | m.addr = addr 199 | m.privKey = pkl 200 | return nil 201 | } 202 | 203 | func (m *keyManager) Sign(msg tx.StdSignMsg) ([]byte, error) { 204 | sig, err := m.makeSignature(msg) 205 | if err != nil { 206 | return nil, err 207 | } 208 | newTx := tx.NewStdTx(msg.Msgs, []tx.StdSignature{sig}, msg.Memo, msg.Source, msg.Data) 209 | bz, err := tx.Cdc.MarshalBinaryLengthPrefixed(&newTx) 210 | if err != nil { 211 | return nil, err 212 | } 213 | return bz, nil 214 | } 215 | 216 | func (m *keyManager) GetPrivKey() crypto.PrivKey { 217 | return m.privKey 218 | } 219 | 220 | func (m *keyManager) GetAddr() ctypes.AccAddress { 221 | return m.addr 222 | } 223 | 224 | func (m *keyManager) makeSignature(msg tx.StdSignMsg) (sig tx.StdSignature, err error) { 225 | if err != nil { 226 | return 227 | } 228 | sigBytes, err := m.privKey.Sign(msg.Bytes()) 229 | if err != nil { 230 | return 231 | } 232 | return tx.StdSignature{ 233 | AccountNumber: msg.AccountNumber, 234 | Sequence: msg.Sequence, 235 | PubKey: m.privKey.PubKey(), 236 | Signature: sigBytes, 237 | }, nil 238 | } 239 | 240 | func generateKeyStore(privateKey crypto.PrivKey, password string) (*EncryptedKeyJSON, error) { 241 | addr := ctypes.AccAddress(privateKey.PubKey().Address()) 242 | salt, err := common.GenerateRandomBytes(32) 243 | if err != nil { 244 | return nil, err 245 | } 246 | iv, err := common.GenerateRandomBytes(16) 247 | if err != nil { 248 | return nil, err 249 | } 250 | scryptParamsJSON := make(map[string]interface{}, 4) 251 | scryptParamsJSON["prf"] = "hmac-sha256" 252 | scryptParamsJSON["dklen"] = 32 253 | scryptParamsJSON["salt"] = hex.EncodeToString(salt) 254 | scryptParamsJSON["c"] = 262144 255 | 256 | cipherParamsJSON := cipherparamsJSON{IV: hex.EncodeToString(iv)} 257 | derivedKey := pbkdf2.Key([]byte(password), salt, 262144, 32, sha256.New) 258 | encryptKey := derivedKey[:32] 259 | secpPrivateKey, ok := privateKey.(secp256k1.PrivKeySecp256k1) 260 | if !ok { 261 | return nil, fmt.Errorf(" Only PrivKeySecp256k1 key is supported ") 262 | } 263 | cipherText, err := aesCTRXOR(encryptKey, secpPrivateKey[:], iv) 264 | if err != nil { 265 | return nil, err 266 | } 267 | 268 | hasher := sha3.NewLegacyKeccak512() 269 | hasher.Write(derivedKey[16:32]) 270 | hasher.Write(cipherText) 271 | mac := hasher.Sum(nil) 272 | 273 | id, err := uuid.NewV4() 274 | if err != nil { 275 | return nil, err 276 | } 277 | cryptoStruct := CryptoJSON{ 278 | Cipher: "aes-256-ctr", 279 | CipherText: hex.EncodeToString(cipherText), 280 | CipherParams: cipherParamsJSON, 281 | KDF: "pbkdf2", 282 | KDFParams: scryptParamsJSON, 283 | MAC: hex.EncodeToString(mac), 284 | } 285 | return &EncryptedKeyJSON{ 286 | Address: addr.String(), 287 | Crypto: cryptoStruct, 288 | Id: id.String(), 289 | Version: 1, 290 | }, nil 291 | } 292 | -------------------------------------------------------------------------------- /e2e/e2e_rpc_side_staking_test.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "encoding/hex" 5 | "sync" 6 | "testing" 7 | 8 | "github.com/bnb-chain/go-sdk/client/rpc" 9 | ctypes "github.com/bnb-chain/go-sdk/common/types" 10 | "github.com/bnb-chain/go-sdk/keys" 11 | "github.com/bnb-chain/go-sdk/types" 12 | "github.com/bnb-chain/go-sdk/types/msg" 13 | "github.com/bnb-chain/go-sdk/types/tx" 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | var ( 18 | sNodeAddr = "tcp://127.0.0.1:26657" 19 | sOnceClient = sync.Once{} 20 | sTestClientInstance *rpc.HTTP 21 | 22 | jackAddress = "bnb1lrzg56jhtkqu7fmca3394vdx00r7apx4gwvj6w" 23 | jackMnemonic = "orphan thing pelican flee spray sense sketch dutch opinion vessel fringe surround hurt theory hospital provide foil love stock vast shrug detail harbor pattern" 24 | 25 | roseAddress = "bnb1rxnydtfjccaz2tck7wrentntdylrnnqzmvqvwn" 26 | roseMnemonic = "earth hamster near become enlist degree foil crucial weapon poverty mad purity chest lucky equal jazz pony either knee cloud drive badge jacket caught" 27 | 28 | markAddress = "bnb1sh4cfzvcut9nywffs6gs5zkyt4pzeej6k84klt" 29 | markMnemonic = "depend water drink monitor earn praise permit autumn board cable impact wink wolf sting middle misery bridge stamp close very robust slam annual verify" 30 | 31 | chainId = "test-chain-qUlw6e" 32 | valAddress = "bva1lrzg56jhtkqu7fmca3394vdx00r7apx4gjdzy2" 33 | valAddress2 = "bva1rxnydtfjccaz2tck7wrentntdylrnnqzmspush" 34 | ) 35 | 36 | func rpcClient() *rpc.HTTP { 37 | sOnceClient.Do(func() { 38 | sTestClientInstance = rpc.NewRPCClient(sNodeAddr, ctypes.ProdNetwork) 39 | }) 40 | return sTestClientInstance 41 | } 42 | 43 | func getRpcClientWithKeyManager() *rpc.HTTP { 44 | c := rpcClient() 45 | ctypes.SetNetwork(ctypes.ProdNetwork) 46 | keyManager, _ := keys.NewMnemonicKeyManager(jackMnemonic) 47 | c.SetKeyManager(keyManager) 48 | return c 49 | } 50 | 51 | // FromHex returns the bytes represented by the hexadecimal string s. 52 | // s may be prefixed with "0x". 53 | func FromHex(s string) []byte { 54 | if has0xPrefix(s) { 55 | s = s[2:] 56 | } 57 | if len(s)%2 == 1 { 58 | s = "0" + s 59 | } 60 | return Hex2Bytes(s) 61 | } 62 | 63 | // Hex2Bytes returns the bytes represented by the hexadecimal string str. 64 | func Hex2Bytes(str string) []byte { 65 | h, _ := hex.DecodeString(str) 66 | return h 67 | } 68 | 69 | // has0xPrefix validates str begins with '0x' or '0X'. 70 | func has0xPrefix(str string) bool { 71 | return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') 72 | } 73 | 74 | func TestCreateSideChainValidator(t *testing.T) { 75 | c := getRpcClientWithKeyManager() 76 | 77 | amount := ctypes.Coin{Denom: "BNB", Amount: 100000000} 78 | des := msg.Description{Moniker: "mchain"} 79 | 80 | rate, _ := ctypes.NewDecFromStr("1") 81 | maxRate, _ := ctypes.NewDecFromStr("1") 82 | maxChangeRate, _ := ctypes.NewDecFromStr("1") 83 | 84 | commissionMsg := ctypes.CommissionMsg{Rate: rate, MaxRate: maxRate, MaxChangeRate: maxChangeRate} 85 | 86 | sideChainId := types.RialtoNet 87 | sideConsAddr := FromHex("0x9fB29AAc15b9A4B7F17c3385939b007540f4d791") 88 | sideFeeAddr := FromHex("0xd1B22dCC24C55f4d728E7aaA5c9b5a22e1512C08") 89 | 90 | res, err := c.CreateSideChainValidator(amount, des, commissionMsg, sideChainId, sideConsAddr, sideFeeAddr, rpc.Sync, tx.WithChainID(chainId)) 91 | 92 | assert.NotNil(t, res) 93 | assert.Nil(t, err) 94 | } 95 | 96 | func TestEditSideChainValidator(t *testing.T) { 97 | c := getRpcClientWithKeyManager() 98 | 99 | des := msg.Description{Moniker: "mchain"} 100 | 101 | rate, _ := ctypes.NewDecFromStr("2") 102 | 103 | sideFeeAddr := FromHex("0xd1B22dCC24C55f4d728E7aaA5c9b5a22e1512C08") 104 | consAddr := FromHex("0xd1B22dCC24C55f4d728E7aaA5c9b5a22e1512C08") 105 | res, err := c.EditSideChainValidator(types.RialtoNet, des, &rate, sideFeeAddr, consAddr, rpc.Sync, tx.WithChainID(chainId)) 106 | 107 | assert.NotNil(t, res) 108 | assert.Nil(t, err) 109 | } 110 | 111 | func TestDelegate(t *testing.T) { 112 | c := getRpcClientWithKeyManager() 113 | 114 | valAddr, err := ctypes.ValAddressFromBech32(valAddress) 115 | 116 | assert.NoError(t, err) 117 | 118 | amount := ctypes.Coin{Denom: "BNB", Amount: 100000000} 119 | 120 | res, err := c.SideChainDelegate(types.RialtoNet, valAddr, amount, rpc.Sync, tx.WithChainID(chainId)) 121 | 122 | assert.NotNil(t, res) 123 | assert.Nil(t, err) 124 | } 125 | 126 | func TestRedelegate(t *testing.T) { 127 | c := getRpcClientWithKeyManager() 128 | 129 | srcValAddr, err := ctypes.ValAddressFromBech32(valAddress) 130 | 131 | assert.NoError(t, err) 132 | 133 | dstValAddr, err := ctypes.ValAddressFromBech32(valAddress2) 134 | 135 | assert.NoError(t, err) 136 | 137 | amount := ctypes.Coin{Denom: "BNB", Amount: 100000000} 138 | 139 | res, err := c.SideChainRedelegate(types.RialtoNet, srcValAddr, dstValAddr, amount, rpc.Sync, tx.WithChainID(chainId)) 140 | 141 | assert.NotNil(t, res) 142 | assert.Nil(t, err) 143 | } 144 | 145 | func TestUnbond(t *testing.T) { 146 | c := getRpcClientWithKeyManager() 147 | 148 | valAddr, err := ctypes.ValAddressFromBech32(valAddress) 149 | 150 | assert.NoError(t, err) 151 | 152 | amount := ctypes.Coin{Denom: "BNB", Amount: 100000000} 153 | 154 | res, err := c.SideChainUnbond(types.RialtoNet, valAddr, amount, rpc.Sync, tx.WithChainID(chainId)) 155 | 156 | assert.NotNil(t, res) 157 | assert.Nil(t, err) 158 | } 159 | 160 | func TestQuerySideChainValidator(t *testing.T) { 161 | c := getRpcClientWithKeyManager() 162 | 163 | valAddr, err := ctypes.ValAddressFromBech32(valAddress) 164 | 165 | assert.Nil(t, err) 166 | 167 | res, err := c.QuerySideChainValidator(types.RialtoNet, valAddr) 168 | 169 | if res == nil { 170 | assert.Equal(t, rpc.EmptyResultError, err) 171 | } else { 172 | assert.NotNil(t, res.OperatorAddr) 173 | } 174 | } 175 | 176 | func TestQuerySideChainTopValidators(t *testing.T) { 177 | c := getRpcClientWithKeyManager() 178 | _, err := c.QuerySideChainTopValidators(types.RialtoNet, 5) 179 | assert.NoError(t, err) 180 | } 181 | 182 | func TestQuerySideChainDelegation(t *testing.T) { 183 | c := getRpcClientWithKeyManager() 184 | 185 | delAddr, _ := ctypes.AccAddressFromBech32(jackAddress) 186 | valAddr, _ := ctypes.ValAddressFromBech32(valAddress) 187 | 188 | res, err := c.QuerySideChainDelegation(types.RialtoNet, delAddr, valAddr) 189 | 190 | if res == nil { 191 | assert.Equal(t, rpc.EmptyResultError, err) 192 | } else { 193 | assert.NotNil(t, res.ValidatorAddr) 194 | } 195 | } 196 | 197 | func TestQuerySideChainDelegations(t *testing.T) { 198 | c := rpcClient() 199 | 200 | delAddr, _ := ctypes.AccAddressFromBech32(jackAddress) 201 | 202 | _, err := c.QuerySideChainDelegations(types.RialtoNet, delAddr) 203 | assert.Nil(t, err) 204 | } 205 | 206 | func TestQuerySideChainRelegation(t *testing.T) { 207 | c := rpcClient() 208 | 209 | delAddr, _ := ctypes.AccAddressFromBech32(jackAddress) 210 | valSrcAddr, _ := ctypes.ValAddressFromBech32(valAddress) 211 | valDstAddr, _ := ctypes.ValAddressFromBech32(valAddress2) 212 | 213 | res, err := c.QuerySideChainRedelegation(types.RialtoNet, delAddr, valSrcAddr, valDstAddr) 214 | 215 | if res == nil { 216 | assert.Equal(t, rpc.EmptyResultError, err) 217 | } else { 218 | assert.NotNil(t, res.DelegatorAddr) 219 | } 220 | } 221 | 222 | func TestQuerySideChainRelegations(t *testing.T) { 223 | c := rpcClient() 224 | delAddr, err := ctypes.AccAddressFromBech32(jackAddress) 225 | assert.Nil(t, err) 226 | _, err = c.QuerySideChainRedelegations(types.RialtoNet, delAddr) 227 | assert.Nil(t, err) 228 | } 229 | 230 | func TestQuerySideChainUnbondingDelegation(t *testing.T) { 231 | c := rpcClient() 232 | 233 | delAddr, _ := ctypes.AccAddressFromBech32(jackAddress) 234 | valAddr, _ := ctypes.ValAddressFromBech32(valAddress) 235 | 236 | res, err := c.QuerySideChainUnbondingDelegation(types.RialtoNet, valAddr, delAddr) 237 | 238 | if res == nil { 239 | assert.Equal(t, rpc.EmptyResultError, err) 240 | } else { 241 | assert.NotNil(t, res.DelegatorAddr) 242 | } 243 | } 244 | 245 | func TestQuerySideChainUnbondingDelegations(t *testing.T) { 246 | c := rpcClient() 247 | delAddr, _ := ctypes.AccAddressFromBech32(jackAddress) 248 | _, err := c.QuerySideChainUnbondingDelegations(types.RialtoNet, delAddr) 249 | assert.Nil(t, err) 250 | } 251 | 252 | func TestGetSideChainUnBondingDelegationsByValidator(t *testing.T) { 253 | c := getRpcClientWithKeyManager() 254 | valAddr, _ := ctypes.ValAddressFromBech32(jackAddress) 255 | _, err := c.GetSideChainUnBondingDelegationsByValidator(types.RialtoNet, valAddr) 256 | assert.Nil(t, err) 257 | } 258 | 259 | func TestGetSideChainRedelegationsByValidator(t *testing.T) { 260 | c := getRpcClientWithKeyManager() 261 | valAddr, _ := ctypes.ValAddressFromBech32(jackAddress) 262 | _, err := c.GetSideChainRedelegationsByValidator(types.RialtoNet, valAddr) 263 | assert.Nil(t, err) 264 | } 265 | 266 | func TestGetSideChainId(t *testing.T) { 267 | c := getRpcClientWithKeyManager() 268 | _, err := c.GetSideChainPool(types.RialtoNet) 269 | assert.Nil(t, err) 270 | } 271 | 272 | func TestGetSideChainAllValidatorsCount(t *testing.T) { 273 | c := getRpcClientWithKeyManager() 274 | _, err := c.GetSideChainAllValidatorsCount(types.RialtoNet, false) 275 | assert.Nil(t, err) 276 | } 277 | -------------------------------------------------------------------------------- /e2e/e2e_trans_test.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "fmt" 5 | "github.com/bnb-chain/go-sdk/types" 6 | "strings" 7 | "testing" 8 | time2 "time" 9 | 10 | "github.com/bnb-chain/go-sdk/client/rpc" 11 | "github.com/tendermint/tendermint/crypto" 12 | 13 | "github.com/stretchr/testify/assert" 14 | 15 | "github.com/tendermint/tendermint/types/time" 16 | 17 | sdk "github.com/bnb-chain/go-sdk/client" 18 | ctypes "github.com/bnb-chain/go-sdk/common/types" 19 | "github.com/bnb-chain/go-sdk/keys" 20 | "github.com/bnb-chain/go-sdk/types/msg" 21 | txtype "github.com/bnb-chain/go-sdk/types/tx" 22 | ) 23 | 24 | // After bnbchain integration_test.sh has runned 25 | func TestTransProcess(t *testing.T) { 26 | //----- Recover account --------- 27 | mnemonic := "test mnemonic" 28 | baeUrl := "testnet-dex.binance.org" 29 | keyManager, err := keys.NewMnemonicKeyManager(mnemonic) 30 | assert.NoError(t, err) 31 | testAccount1 := keyManager.GetAddr() 32 | testKeyManager2, _ := keys.NewKeyManager() 33 | testAccount2 := testKeyManager2.GetAddr() 34 | testKeyManager3, _ := keys.NewKeyManager() 35 | testAccount3 := testKeyManager3.GetAddr() 36 | 37 | //----- Init sdk ------------- 38 | client, err := sdk.NewDexClient(baeUrl, ctypes.TestNetwork, keyManager) 39 | 40 | assert.NoError(t, err) 41 | nativeSymbol := types.NativeSymbol 42 | 43 | //---- set Account flags 44 | addFlags, err := client.AddAccountFlags([]ctypes.FlagOption{ctypes.TransferMemoCheckerFlag}, true) 45 | assert.NoError(t, err) 46 | fmt.Printf("Set account flags: %v \n", addFlags) 47 | accn, _ := client.GetAccount(client.GetKeyManager().GetAddr().String()) 48 | fmt.Println(accn) 49 | setFlags, err := client.SetAccountFlags(0, true) 50 | assert.NoError(t, err) 51 | fmt.Printf("Set account flags: %v \n", setFlags) 52 | 53 | //----- Get account ----------- 54 | account, err := client.GetAccount(testAccount1.String()) 55 | assert.NoError(t, err) 56 | assert.NotNil(t, account) 57 | assert.True(t, len(account.Balances) > 0) 58 | 59 | //----- Get Tokens ----------- 60 | tokens, err := client.GetTokens(ctypes.NewTokensQuery().WithLimit(101)) 61 | assert.NoError(t, err) 62 | fmt.Printf("GetTokens: %v \n", tokens) 63 | 64 | //----- Get Time ----------- 65 | time, err := client.GetTime() 66 | assert.NoError(t, err) 67 | fmt.Printf("Get time: %v \n", time) 68 | 69 | //----- time lock ----------- 70 | lockResult, err := client.TimeLock("test lock", ctypes.Coins{{"BNB", 100000000}}, int64(time2.Now().Add(65*time2.Second).Unix()), true) 71 | assert.NoError(t, err) 72 | fmt.Printf("timelock %d \n", lockResult.LockId) 73 | 74 | //----- time relock --------- 75 | relockResult, err := client.TimeReLock(lockResult.LockId, "test lock", ctypes.Coins{{"BNB", 200000000}}, int64(time2.Now().Add(70*time2.Second).Unix()), true) 76 | assert.NoError(t, err) 77 | fmt.Printf("timelock %d \n", relockResult.LockId) 78 | 79 | //------ time unlock -------- 80 | time2.Sleep(75 * time2.Second) 81 | unlockResult, err := client.TimeUnLock(relockResult.LockId, true) 82 | assert.NoError(t, err) 83 | fmt.Printf("timelock %d \n", unlockResult.LockId) 84 | 85 | //---- Send tx ----------- 86 | send, err := client.SendToken([]msg.Transfer{{testAccount2, []ctypes.Coin{{nativeSymbol, 100000000}}}, {testAccount3, []ctypes.Coin{{nativeSymbol, 100000000}}}}, true) 87 | assert.NoError(t, err) 88 | assert.True(t, send.Ok) 89 | fmt.Printf("Send token: %v\n", send) 90 | 91 | //--- Get test2 account----- 92 | newTestAccout2, err := client.GetAccount(testAccount2.String()) 93 | assert.NoError(t, err) 94 | for _, c := range newTestAccout2.Balances { 95 | if c.Symbol == nativeSymbol { 96 | fmt.Printf("test account BNB: %s \n", c.Free) 97 | } 98 | } 99 | 100 | //---- Freeze Token --------- 101 | freeze, err := client.FreezeToken(nativeSymbol, 100, true) 102 | assert.NoError(t, err) 103 | assert.True(t, freeze.Ok) 104 | fmt.Printf("freeze token: %v\n", freeze) 105 | 106 | //---- Unfreeze Token --------- 107 | unfreeze, err := client.UnfreezeToken(nativeSymbol, 100, true) 108 | assert.NoError(t, err) 109 | assert.True(t, unfreeze.Ok) 110 | fmt.Printf("Unfreeze token: %v\n", unfreeze) 111 | 112 | //---- issue token --------- 113 | issue, err := client.IssueToken("Client-Token", "sdk", 10000000000, true, true) 114 | assert.NoError(t, err) 115 | fmt.Printf("Issue token: %v\n", issue) 116 | 117 | //--- check issue success --- 118 | time2.Sleep(4 * time2.Second) 119 | issueresult, err := client.GetTx(issue.Hash) 120 | assert.NoError(t, err) 121 | assert.True(t, issueresult.Code == txtype.CodeOk) 122 | 123 | //--- mint token ----------- 124 | mint, err := client.MintToken(issue.Symbol, 100000000, true) 125 | assert.NoError(t, err) 126 | fmt.Printf("Mint token: %v\n", mint) 127 | 128 | //---- Submit Proposal ------ 129 | time2.Sleep(4 * time2.Second) 130 | listTradingProposal, err := client.SubmitListPairProposal("New trading pair", msg.ListTradingPairParams{issue.Symbol, nativeSymbol, 1000000000, "my trade", time2.Now().Add(1 * time2.Hour)}, 200000000000, 20*time2.Second, true) 131 | assert.NoError(t, err) 132 | fmt.Printf("Submit list trading pair: %v\n", listTradingProposal) 133 | 134 | //--- check submit proposal success --- 135 | time2.Sleep(4 * time2.Second) 136 | submitPorposalStatus, err := client.GetTx(listTradingProposal.Hash) 137 | assert.NoError(t, err) 138 | assert.True(t, submitPorposalStatus.Code == txtype.CodeOk) 139 | 140 | //---- issue mini token --------- 141 | time2.Sleep(4 * time2.Second) 142 | miniIssue, err := client.IssueMiniToken("Mini-Client-Token", "msdk", 10000000000, true, true, "http://test.sdk") 143 | assert.NoError(t, err) 144 | fmt.Printf("Issue mini token: %v\n", miniIssue) 145 | 146 | //---- issue tiny token --------- 147 | time2.Sleep(4 * time2.Second) 148 | tinyIssue, err := client.IssueMiniToken("Tiny-Client-Token", "tsdk", 10000000000, true, true, "http://test.sdk") 149 | assert.NoError(t, err) 150 | fmt.Printf("Issue tiny token: %v\n", tinyIssue) 151 | 152 | //---- set mini token uri --------- 153 | time2.Sleep(4 * time2.Second) 154 | setUri, err := client.SetURI(miniIssue.Symbol, "http://test-uri.sdk", true) 155 | assert.NoError(t, err) 156 | fmt.Printf("Set mini token uri: %v\n", setUri) 157 | 158 | //----- Get Mini Tokens ----------- 159 | time2.Sleep(4 * time2.Second) 160 | miniTokens, err := client.GetMiniTokens(ctypes.NewTokensQuery().WithLimit(101)) 161 | assert.NoError(t, err) 162 | fmt.Printf("Get Mini Tokens: %v \n", miniTokens) 163 | } 164 | 165 | func TestAtomicSwap(t *testing.T) { 166 | mnemonic1 := "test mnemonic1" 167 | mnemonic2 := "test mnemonic2" 168 | baeUrl := "testnet-dex.binance.org" 169 | keyManager, err := keys.NewMnemonicKeyManager(mnemonic1) 170 | assert.NoError(t, err) 171 | testAccount1 := keyManager.GetAddr() 172 | testKeyManager2, err := keys.NewMnemonicKeyManager(mnemonic2) 173 | assert.NoError(t, err) 174 | testAccount2 := testKeyManager2.GetAddr() 175 | 176 | client, err := sdk.NewDexClient(baeUrl, ctypes.TestNetwork, keyManager) 177 | assert.NoError(t, err) 178 | 179 | randomNumber := crypto.CRandBytes(32) 180 | timestamp := int64(time.Now().Unix()) 181 | randomNumberHash := msg.CalculateRandomHash(randomNumber, timestamp) 182 | recipientOtherChain := "0x491e71b619878c083eaf2894718383c7eb15eb17" 183 | senderOtherChain := "0x833914c3A745d924bf71d98F9F9Ae126993E3C88" 184 | amount := ctypes.Coins{ctypes.Coin{"BNB", 10000}} 185 | expetedIncome := "10000:BNB" 186 | heightSpan := int64(1000) 187 | _, err = client.HTLT(testAccount2, recipientOtherChain, senderOtherChain, randomNumberHash, timestamp, amount, expetedIncome, heightSpan, true, true) 188 | assert.NoError(t, err) 189 | time2.Sleep(4 * time2.Second) 190 | swapID := msg.CalculateSwapID(randomNumberHash, testAccount1, senderOtherChain) 191 | _, err = client.ClaimHTLT(swapID, randomNumber, true) 192 | assert.NoError(t, err) 193 | time2.Sleep(4 * time2.Second) 194 | 195 | randomNumber = crypto.CRandBytes(32) 196 | timestamp = int64(time.Now().Unix()) 197 | randomNumberHash = msg.CalculateRandomHash(randomNumber, timestamp) 198 | heightSpan = int64(360) 199 | _, err = client.HTLT(testAccount2, recipientOtherChain, senderOtherChain, randomNumberHash, timestamp, amount, expetedIncome, heightSpan, true, true) 200 | assert.NoError(t, err) 201 | time2.Sleep(4 * time2.Second) 202 | swapID1 := msg.CalculateSwapID(randomNumberHash, testAccount1, senderOtherChain) 203 | _, err = client.RefundHTLT(swapID1, true) 204 | assert.Error(t, err) 205 | time2.Sleep(4 * time2.Second) 206 | assert.True(t, strings.Contains(err.Error(), "is still not reached")) 207 | 208 | randomNumber = crypto.CRandBytes(32) 209 | timestamp = int64(time.Now().Unix()) 210 | randomNumberHash = msg.CalculateRandomHash(randomNumber, timestamp) 211 | amount = ctypes.Coins{ctypes.Coin{"BNB", 10000}} 212 | expetedIncome = "1000:BTC-271" 213 | heightSpan = int64(1000) 214 | _, err = client.HTLT(testAccount2, "", "", randomNumberHash, timestamp, amount, expetedIncome, heightSpan, false, true) 215 | assert.NoError(t, err) 216 | time2.Sleep(4 * time2.Second) 217 | swapID2 := msg.CalculateSwapID(randomNumberHash, testAccount1, "") 218 | depositAmount := ctypes.Coins{ctypes.Coin{"BTC-271", 1000}} 219 | client1, err := sdk.NewDexClient(baeUrl, ctypes.TestNetwork, testKeyManager2) 220 | assert.NoError(t, err) 221 | _, err = client1.DepositHTLT(swapID2, depositAmount, true) 222 | assert.NoError(t, err) 223 | time2.Sleep(4 * time2.Second) 224 | _, err = client.ClaimHTLT(swapID2, randomNumber, true) 225 | assert.NoError(t, err) 226 | time2.Sleep(4 * time2.Second) 227 | 228 | c := rpc.NewRPCClient("tcp://seed-pre-s3.binance.org:80", ctypes.TestNetwork) 229 | swap, err := c.GetSwapByID(swapID) 230 | assert.NoError(t, err) 231 | 232 | randomNumberHashList, err := c.GetSwapByCreator(swap.From.String(), 0, 100) 233 | assert.NoError(t, err) 234 | assert.True(t, len(randomNumberHashList) > 0) 235 | 236 | randomNumberHashList, err = c.GetSwapByRecipient(swap.To.String(), 0, 100) 237 | assert.NoError(t, err) 238 | assert.True(t, len(randomNumberHashList) > 0) 239 | } 240 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018-2019 All BNB Chain Developers 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /keys/keys_test.go: -------------------------------------------------------------------------------- 1 | package keys 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "encoding/json" 7 | "io/ioutil" 8 | "os" 9 | "testing" 10 | "time" 11 | 12 | "github.com/stretchr/testify/assert" 13 | 14 | ctypes "github.com/bnb-chain/go-sdk/common/types" 15 | "github.com/bnb-chain/go-sdk/types/msg" 16 | "github.com/bnb-chain/go-sdk/types/tx" 17 | ) 18 | 19 | func TestRecoveryFromKeyWordsNoError(t *testing.T) { 20 | mnemonic := "bottom quick strong ranch section decide pepper broken oven demand coin run jacket curious business achieve mule bamboo remain vote kid rigid bench rubber" 21 | keyManager, err := NewMnemonicKeyManager(mnemonic) 22 | assert.NoError(t, err) 23 | acc := keyManager.GetAddr() 24 | key := keyManager.GetPrivKey() 25 | assert.Equal(t, "bnb1ddt3ls9fjcd8mh69ujdg3fxc89qle2a7km33aa", acc.String()) 26 | assert.NotNil(t, key) 27 | customPathKey, err := NewMnemonicPathKeyManager(mnemonic, "1'/1/1") 28 | assert.NoError(t, err) 29 | assert.Equal(t, "bnb1c67nwp7u5adl7gw0ffn3d47kttcm4crjy9mrye", customPathKey.GetAddr().String()) 30 | } 31 | 32 | func TestRecoveryFromKeyBaseNoError(t *testing.T) { 33 | file := "testkeystore.json" 34 | planText := []byte("Test msg") 35 | keyManager, err := NewKeyStoreKeyManager(file, "Zjubfd@123") 36 | assert.NoError(t, err) 37 | sigs, err := keyManager.GetPrivKey().Sign(planText) 38 | assert.NoError(t, err) 39 | valid := keyManager.GetPrivKey().PubKey().VerifyBytes(planText, sigs) 40 | assert.True(t, valid) 41 | } 42 | 43 | func TestRecoveryPrivateKeyNoError(t *testing.T) { 44 | planText := []byte("Test msg") 45 | priv := "9579fff0cab07a4379e845a890105004ba4c8276f8ad9d22082b2acbf02d884b" 46 | keyManager, err := NewPrivateKeyManager(priv) 47 | assert.NoError(t, err) 48 | sigs, err := keyManager.GetPrivKey().Sign(planText) 49 | assert.NoError(t, err) 50 | valid := keyManager.GetPrivKey().PubKey().VerifyBytes(planText, sigs) 51 | assert.True(t, valid) 52 | } 53 | 54 | func TestSignTxNoError(t *testing.T) { 55 | 56 | test1Mnemonic := "swift slam quote sail high remain mandate sample now stamp title among fiscal captain joy puppy ghost arrow attract ozone situate install gain mean" 57 | test2Mnemonic := "bottom quick strong ranch section decide pepper broken oven demand coin run jacket curious business achieve mule bamboo remain vote kid rigid bench rubber" 58 | 59 | test1KeyManager, err := NewMnemonicKeyManager(test1Mnemonic) 60 | assert.NoError(t, err) 61 | test2KeyManager, err := NewMnemonicKeyManager(test2Mnemonic) 62 | assert.NoError(t, err) 63 | 64 | test1Addr := test1KeyManager.GetAddr() 65 | test2Addr := test2KeyManager.GetAddr() 66 | testCases := []struct { 67 | msg msg.Msg 68 | keyManager KeyManager 69 | accountNUm int64 70 | sequence int64 71 | expectHexTx string 72 | errMsg string 73 | }{ 74 | {msg.CreateSendMsg(test1Addr, ctypes.Coins{ctypes.Coin{Denom: "BNB", Amount: 100000000000000}}, []msg.Transfer{{test2KeyManager.GetAddr(), ctypes.Coins{ctypes.Coin{Denom: "BNB", Amount: 100000000000000}}}}), 75 | test1KeyManager, 76 | 0, 77 | 1, 78 | "c601f0625dee0a522a2c87fa0a250a141d0e3086e8e4e0a53c38a90d55bd58b34d57d2fa120d0a03424e42108080e983b1de1612250a146b571fc0a9961a7ddf45e49a88a4d83941fcabbe120d0a03424e42108080e983b1de16126c0a26eb5ae98721027e69d96640300433654e016d218a8d7ffed751023d8efe81e55dedbd6754c97112408b23eecfa8237a27676725173e58154e6c204bb291b31c3b7b507c8f04e2773909ba70e01b54f4bd0bc76669f5712a5a66b9508acdf3aa5e4fde75fbe57622a12001", 79 | "send message sign error", 80 | }, 81 | { 82 | msg.NewTokenIssueMsg(test2Addr, "Bitcoin", "BTC", 1000000000000000, true), 83 | test2KeyManager, 84 | 1, 85 | 0, 86 | "a701f0625dee0a3317efab800a146b571fc0a9961a7ddf45e49a88a4d83941fcabbe1207426974636f696e1a034254432080809aa6eaafe3012801126c0a26eb5ae9872103d8f33449356d58b699f6b16a498bd391aa5e051085415d0fe1873939bc1d2e3a12403686586a55f8c50a11ae6f09c35734f09830a566823846f9333c3e53f6d83d4a2cd3a0542c37a8d28b474f563d44223ba6c2b7cf260539b7b85020999ebe2c001801", 87 | "issue message sign error", 88 | }, 89 | {msg.NewMsgSubmitProposal("list BTC/BNB", "{\"base_asset_symbol\":\"BTC-86A\",\"quote_asset_symbol\":\"BNB\",\"init_price\":100000000,\"description\":\"list BTC/BNB\",\"expire_time\":\"2018-12-24T00:46:05+08:00\"}", msg.ProposalTypeListTradingPair, test1Addr, ctypes.Coins{ctypes.Coin{Denom: "BNB", Amount: 200000000000}}, time.Second), 90 | test1KeyManager, 91 | 0, 92 | 2, 93 | "ce02f0625dee0ad901b42d614e0a0c6c697374204254432f424e421298017b22626173655f61737365745f73796d626f6c223a224254432d383641222c2271756f74655f61737365745f73796d626f6c223a22424e42222c22696e69745f7072696365223a3130303030303030302c226465736372697074696f6e223a226c697374204254432f424e42222c226578706972655f74696d65223a22323031382d31322d32345430303a34363a30352b30383a3030227d180422141d0e3086e8e4e0a53c38a90d55bd58b34d57d2fa2a0c0a03424e421080a0b787e905308094ebdc03126c0a26eb5ae98721027e69d96640300433654e016d218a8d7ffed751023d8efe81e55dedbd6754c9711240ebac8c34f27e9dc0719167c4ad87bc2e3e1437022c3287030425db8f4233c3b80938dfa16f555738ba97e92aa7a15ebb6ac8baa5d799118cccf503302d166df92002", 94 | "submit proposal sign error", 95 | }, 96 | { 97 | msg.NewMsgVote(test1Addr, 1, msg.OptionYes), 98 | test1KeyManager, 99 | 0, 100 | 3, 101 | "9201f0625dee0a1ea1cadd36080112141d0e3086e8e4e0a53c38a90d55bd58b34d57d2fa1801126c0a26eb5ae98721027e69d96640300433654e016d218a8d7ffed751023d8efe81e55dedbd6754c97112405a2394615da1d744e991b0cc0f188ac2d7108259e15ba0b992729a8ee54e77e5641dd2ed846d59be468be2daeb628c3a6633187225a0ce85db884c965467baf52003", 102 | "vote proposal sign error", 103 | }, 104 | { 105 | msg.NewDexListMsg(test2Addr, 1, "BTC-86A", "BNB", 100000000), 106 | test2KeyManager, 107 | 1, 108 | 2, 109 | "a501f0625dee0a2fb41de13f0a146b571fc0a9961a7ddf45e49a88a4d83941fcabbe10011a074254432d3836412203424e422880c2d72f126e0a26eb5ae9872103d8f33449356d58b699f6b16a498bd391aa5e051085415d0fe1873939bc1d2e3a1240ce897838dd4d70d3c337b62ac1f60ec022bb2bf281fb77eca95adcd64de0a6aa574b128c5f732545c8b0e62dcd1cd90f9898c5f7781ae9d64042859c4e40558b18012002", 110 | "List tradimg sign error", 111 | }, 112 | {msg.NewCreateOrderMsg(test1Addr, "1D0E3086E8E4E0A53C38A90D55BD58B34D57D2FA-5", 1, "BTC-86A_BNB", 100000000, 1000000000), 113 | test1KeyManager, 114 | 0, 115 | 4, 116 | "d801f0625dee0a64ce6dc0430a141d0e3086e8e4e0a53c38a90d55bd58b34d57d2fa122a314430453330383645384534453041353343333841393044353542443538423334443537443246412d351a0b4254432d3836415f424e42200228013080c2d72f388094ebdc034001126c0a26eb5ae98721027e69d96640300433654e016d218a8d7ffed751023d8efe81e55dedbd6754c97112409fe317e036f2bdc8c87a0138dc52367faef80ea1d6e21a35634b17a82ed7be632c9cb03f865f6f8a6872736ccab716a157f3cb99339afa55686aa455dc134f6a2004", 117 | "Create order sign error", 118 | }, 119 | { 120 | msg.NewCancelOrderMsg(test1Addr, "BTC-86A_BNB", "1D0E3086E8E4E0A53C38A90D55BD58B34D57D2FA-5"), 121 | test1KeyManager, 122 | 0, 123 | 5, 124 | "c701f0625dee0a53166e681b0a141d0e3086e8e4e0a53c38a90d55bd58b34d57d2fa120b4254432d3836415f424e421a2a314430453330383645384534453041353343333841393044353542443538423334443537443246412d35126c0a26eb5ae98721027e69d96640300433654e016d218a8d7ffed751023d8efe81e55dedbd6754c9711240fe2fd18630317849bd1d4ae064f8c4fd95f6186bdb61e2b73a5fb5e93ac7794d4a990ba943694659df9d3f49d5312fec020b80148677f3e95fd6d88486bba19d2005", 125 | "Cancel order sign error", 126 | }, 127 | { 128 | msg.NewFreezeMsg(test1Addr, "BNB", 100000000), 129 | test1KeyManager, 130 | 0, 131 | 10, 132 | "9801f0625dee0a24e774b32d0a141d0e3086e8e4e0a53c38a90d55bd58b34d57d2fa1203424e421880c2d72f126c0a26eb5ae98721027e69d96640300433654e016d218a8d7ffed751023d8efe81e55dedbd6754c971124013142dc274677af4f09d4be295f1855709b7608e1a9d4cc76aa23103c092ce1915c0ed51fc3c8a8510b57a7a8e8d532c6f5d1159cdb0e7333dda0d0a9e55cac4200a", 133 | "Freeze token sign error", 134 | }, 135 | { 136 | msg.NewUnfreezeMsg(test1Addr, "BNB", 100000000), 137 | test1KeyManager, 138 | 0, 139 | 11, 140 | "9801f0625dee0a246515ff0d0a141d0e3086e8e4e0a53c38a90d55bd58b34d57d2fa1203424e421880c2d72f126c0a26eb5ae98721027e69d96640300433654e016d218a8d7ffed751023d8efe81e55dedbd6754c9711240af320bdecb27fe5f7f89abcb9ffc11df2479859fa66586654f36425d908ff7a32921c9af658f86c63db797981a3110db33c6033db017bdca5ca87b1c440c8fc6200b", 141 | "Unfreeze token sign error", 142 | }, 143 | { 144 | msg.NewTokenBurnMsg(test1Addr, "BNB", 100000000), 145 | test1KeyManager, 146 | 0, 147 | 12, 148 | "9801f0625dee0a247ed2d2a00a141d0e3086e8e4e0a53c38a90d55bd58b34d57d2fa1203424e421880c2d72f126c0a26eb5ae98721027e69d96640300433654e016d218a8d7ffed751023d8efe81e55dedbd6754c971124066f3e784fa602d7697dd46bf89a17e82db7ab89da1e72b3c253cd14ee073628c7cfbe1b05dab541bd162687e5bd390bfed029c99792e69015c1f86deb399fde6200c", 149 | "Burn token sign error", 150 | }, 151 | { 152 | msg.NewMintMsg(test2Addr, "BTC-86A", 100000000), 153 | test2KeyManager, 154 | 1, 155 | 5, 156 | "9e01f0625dee0a28467e08290a146b571fc0a9961a7ddf45e49a88a4d83941fcabbe12074254432d3836411880c2d72f126e0a26eb5ae9872103d8f33449356d58b699f6b16a498bd391aa5e051085415d0fe1873939bc1d2e3a124073b5f00488861a7abdf2274fb719add8b8c9a0bbe16c46bc3ac844671df7c705080d8b061d37bbfcec93d9ed05b3601fde94adadc5086f828402c9f91ce55d1518012005", 157 | "Mint token sign error", 158 | }, 159 | } 160 | for _, c := range testCases { 161 | signMsg := tx.StdSignMsg{ 162 | ChainID: "bnbchain-1000", 163 | AccountNumber: c.accountNUm, 164 | Sequence: c.sequence, 165 | Memo: "", 166 | Msgs: []msg.Msg{c.msg}, 167 | Source: 0, 168 | } 169 | 170 | rawSignResult, err := c.keyManager.Sign(signMsg) 171 | signResult := []byte(hex.EncodeToString(rawSignResult)) 172 | assert.NoError(t, err) 173 | expectHexTx := c.expectHexTx 174 | assert.True(t, bytes.Equal(signResult, []byte(expectHexTx)), c.errMsg) 175 | } 176 | } 177 | 178 | func TestExportAsKeyStoreNoError(t *testing.T) { 179 | defer os.Remove("TestGenerateKeyStoreNoError.json") 180 | km, err := NewKeyManager() 181 | assert.NoError(t, err) 182 | encryPlain1, err := km.GetPrivKey().Sign([]byte("test plain")) 183 | assert.NoError(t, err) 184 | keyJSONV1, err := km.ExportAsKeyStore("testpassword") 185 | assert.NoError(t, err) 186 | bz, err := json.Marshal(keyJSONV1) 187 | assert.NoError(t, err) 188 | err = ioutil.WriteFile("TestGenerateKeyStoreNoError.json", bz, 0660) 189 | assert.NoError(t, err) 190 | newkm, err := NewKeyStoreKeyManager("TestGenerateKeyStoreNoError.json", "testpassword") 191 | assert.NoError(t, err) 192 | encryPlain2, err := newkm.GetPrivKey().Sign([]byte("test plain")) 193 | assert.NoError(t, err) 194 | assert.True(t, bytes.Equal(encryPlain1, encryPlain2)) 195 | } 196 | 197 | func TestExportAsMnemonicNoError(t *testing.T) { 198 | km, err := NewKeyManager() 199 | assert.NoError(t, err) 200 | encryPlain1, err := km.GetPrivKey().Sign([]byte("test plain")) 201 | assert.NoError(t, err) 202 | mnemonic, err := km.ExportAsMnemonic() 203 | assert.NoError(t, err) 204 | newkm, err := NewMnemonicKeyManager(mnemonic) 205 | assert.NoError(t, err) 206 | encryPlain2, err := newkm.GetPrivKey().Sign([]byte("test plain")) 207 | assert.NoError(t, err) 208 | assert.True(t, bytes.Equal(encryPlain1, encryPlain2)) 209 | _, err = newkm.ExportAsMnemonic() 210 | assert.NoError(t, err) 211 | } 212 | 213 | func TestExportAsPrivateKeyNoError(t *testing.T) { 214 | km, err := NewKeyManager() 215 | assert.NoError(t, err) 216 | encryPlain1, err := km.GetPrivKey().Sign([]byte("test plain")) 217 | assert.NoError(t, err) 218 | pk, err := km.ExportAsPrivateKey() 219 | assert.NoError(t, err) 220 | newkm, err := NewPrivateKeyManager(pk) 221 | assert.NoError(t, err) 222 | encryPlain2, err := newkm.GetPrivKey().Sign([]byte("test plain")) 223 | assert.NoError(t, err) 224 | assert.True(t, bytes.Equal(encryPlain1, encryPlain2)) 225 | } 226 | 227 | func TestExportAsMnemonicyError(t *testing.T) { 228 | km, err := NewPrivateKeyManager("9579fff0cab07a4379e845a890105004ba4c8276f8ad9d22082b2acbf02d884b") 229 | assert.NoError(t, err) 230 | _, err = km.ExportAsMnemonic() 231 | assert.Error(t, err) 232 | file := "testkeystore.json" 233 | km, err = NewKeyStoreKeyManager(file, "Zjubfd@123") 234 | assert.NoError(t, err) 235 | _, err = km.ExportAsMnemonic() 236 | assert.Error(t, err) 237 | } 238 | --------------------------------------------------------------------------------