Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
yediwu committed Mar 12, 2020
0 parents commit 347b61f
Show file tree
Hide file tree
Showing 55 changed files with 5,371 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.envrc
.idea
86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# gxclient-go
A client to interact with gxchain implemented in GO

<p>
<a href='javascript:;'>
<img width="300px" src='https://raw.githubusercontent.com/gxchain/gxips/master/assets/images/task-gxclient.png'/>
</a>
<a href='javascript:;'>
<img width="300px" src='https://raw.githubusercontent.com/gxchain/gxips/master/assets/images/task-gxclient-en.png'/>
</a>
</p>

## Usage
```
import "github.com/gxchain/gxclient-go"
```

# APIs
- [ ] [Keypair API](#keypair-api)
- [x] [Chain API](#chain-api)
- [ ] [Faucet API](#faucet-api)
- [x] [Account API](#account-api)
- [x] [Asset API](#asset-api)
- [ ] [Contract API](#contract-api)
- [x] [Staking API](#staking-api)

## Constructors
```
//init client
func NewClient(actPriKeyWif, memoPriKeyWif, accountName, url string) (*Client, error) {
```


## Chain API
```
//broadcast transaction
func (client *Client) broadcast(stx *types.SignedTransaction) error
//broadcast transaction
func (client *Client) broadcastSync(stx *types.SignedTransaction) (*types.BroadcastResponse, error)
// GET ChainId of entry point
func (api *API) GetChainId() (string, error)
// Gets dynamic global properties of current blockchain
func (api *API) GetDynamicGlobalProperties() (*DynamicGlobalProperties, error)
// Get block by block height
func (api *API) GetBlock(blockNum uint32) (*Block, error)
//get block objects
func (api *API) GetObjects(objectIds ...string) ([]json.RawMessage, error)
//get block object
func (api *API) GetObject(objectId string) (json.RawMessage, error)
//send transfer request to entryPoint node
func (client *Client) Transfer(to, memo, amountAsset, feeSymbol string, broadcast bool) (*types.TransactionResult, error)
```

## Account API
```
// get account info by account name
func (api *API) GetAccount(account string) (*types.Account, error)
// get accounts info by account names
func (api *API) GetAccounts(accounts ...string) ([]*types.Account, error)
//get account balances by account name
func (api *API) GetAccountBalances(accountID string, assets ...string) ([]*types.AssetAmount, error)
//get account_ids by public key
func (api *API) GetAccountsByPublicKey(publicKeys string) ([]string, error)
```

## Asset API
```
// get assets corresponding to the provided symbols or IDs
func (api *API) GetAssets(symbols ...string) ([]*Asset, error)
// get assets corresponding to the provided symbol or ID
func (api *API) GetAsset(symbol string) (*Asset, error)
```

## Staking API

```
//Get staking programs
func (api *API) GetStakingPrograms() ([]*types.StakingProgram, error)
//create staking
func (client *Client) CreateStaking(to string, amount float64, programId, feeSymbol string, broadcast bool) (*types.TransactionResult, error)
//update staking by stakingId
func (client *Client) UpdateStaking(to, stakingId, feeSymbol string, broadcast bool) (*types.TransactionResult, error)
//claim staking by stakingId
func (client *Client) ClaimStaking(stakingId, feeSymbol string, broadcast bool) (*types.TransactionResult, error)
```

56 changes: 56 additions & 0 deletions api/broadcast/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package broadcast

import (
"gxclient-go/rpc"
"gxclient-go/types"
"reflect"
)

type API struct {
caller rpc.Caller
id rpc.APIID
}

func NewAPI(id rpc.APIID, caller rpc.Caller) *API {
return &API{id: id, caller: caller}
}

func typeof(v interface{}) string {
return reflect.TypeOf(v).String()
}

func (api *API) call(method string, args []interface{}, reply interface{}) error {
err := api.caller.Connect()
if err != nil {
return err
}
return api.caller.Call(api.id, method, args, reply)
}

// BroadcastTransaction broadcast a transaction to the network.
func (api *API) BroadcastTransaction(tx *types.Transaction) error {
if typeof(api.caller) == "*http.HttpTransport" {
txs := make([]*types.Transaction, 1)
txs[0] = tx
return api.call("call", []interface{}{2, "broadcast_transaction", txs}, nil)
}

var reply interface{}
return api.call("broadcast_transaction", []interface{}{tx}, &reply)
}

func (api *API) BroadcastTransactionSynchronous(tx *types.Transaction) (*types.BroadcastResponse, error) {
response := types.BroadcastResponse{}
var err error
if typeof(api.caller) == "*http.HttpTransport" {
txs := make([]*types.Transaction, 1)
txs[0] = tx
err = api.call("call", []interface{}{2, "broadcast_transaction_synchronous", txs}, &response)
} else {
err = api.call("broadcast_transaction_synchronous", []interface{}{tx}, &response)
}
if err != nil {
return nil, err
}
return &response, err
}
9 changes: 9 additions & 0 deletions api/broadcast/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package broadcast

//type BroadcastResponse struct {
// ID string `json:"id"`
// BlockNum uint32 `json:"block_num"`
// TrxNum uint32 `json:"trx_num"`
// Expired bool `json:"expired"`
// Trx map[string]interface{} `json:"trx"`
//}
223 changes: 223 additions & 0 deletions api/database/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package database

import (
"encoding/json"
"github.com/pkg/errors"
"github.com/tidwall/gjson"
"gxclient-go/rpc"
"gxclient-go/types"
)

type API struct {
caller rpc.Caller
id rpc.APIID
}

func NewAPI(id rpc.APIID, caller rpc.Caller) *API {
return &API{id: id, caller: caller}
}

func (api *API) call(method string, args []interface{}, reply interface{}) error {
err := api.caller.Connect()
if err != nil {
return err
}
return api.caller.Call(api.id, method, args, reply)
}

func (api *API) setCallback(method string, callback func(raw json.RawMessage)) error {
return api.caller.SetCallback(api.id, method, callback)
}

// GET ChainId of entry point
func (api *API) GetChainId() (string, error) {
var resp string
err := api.call("get_chain_id", rpc.EmptyParams, &resp)
return resp, err
}

// Gets dynamic global properties of current blockchain
func (api *API) GetDynamicGlobalProperties() (*DynamicGlobalProperties, error) {
var resp DynamicGlobalProperties
err := api.call("get_dynamic_global_properties", rpc.EmptyParams, &resp)
return &resp, err
}

// Get block by block height
func (api *API) GetBlock(blockNum uint32) (*Block, error) {
var resp Block
err := api.call("get_block", []interface{}{blockNum}, &resp)
return &resp, err
}

func (api *API) GetObjects(objectIds ...string) ([]json.RawMessage, error) {
var resp []json.RawMessage
err := api.call("get_objects", []interface{}{objectIds}, &resp)
return resp, err
}

func (api *API) GetObject(objectId string) (json.RawMessage, error) {
var resp []json.RawMessage
err := api.call("get_objects", []interface{}{[]string{objectId}}, &resp)
return resp[0], err
}

//get_account_by_name
func (api *API) GetAccount(account string) (*types.Account, error) {
var resp *types.Account
if err := api.call("get_account_by_name", []interface{}{account}, &resp); err != nil {
return nil, err
}
if resp == nil {
return nil, errors.Errorf("account %s not exist", account)
}
return resp, nil
}

func (api *API) GetAccounts(accounts ...string) ([]*types.Account, error) {
ret := make([]*types.Account, len(accounts))
for i, account := range accounts {
a, err := api.GetAccount(account)
if err != nil {
return nil, err
}
ret[i] = a
}
return ret, nil
}

// GetAccountBalances
// Get an account’s balances in various assets.
func (api *API) GetAccountBalances(accountID string, assets ...string) ([]*types.AssetAmount, error) {
var resp []*types.AssetAmount
err := api.call("get_account_balances", []interface{}{accountID, assets}, &resp)
return resp, err
}

//get_key_references
func (api *API) GetAccountsByPublicKeys(publicKeys ...string) (*[][]string, error) {
var resp *[][]string
err := api.call("get_key_references", []interface{}{publicKeys}, &resp)
return resp, err
}

//get_key_references
func (api *API) GetAccountsByPublicKey(publicKeys string) ([]string, error) {
var resp [][]string
err := api.call("get_key_references", []interface{}{[]string{publicKeys}}, &resp)
if resp == nil {
return nil, err
}
return resp[0], err
}

//lookup_asset_symbols
func (api *API) GetAssets(symbols ...string) ([]*Asset, error) {
var resp []*Asset
err := api.call("lookup_asset_symbols", []interface{}{symbols}, &resp)
return resp, err
}

// LookupAssetSymbols get assets corresponding to the provided symbol or IDs
func (api *API) GetAsset(symbol string) (*Asset, error) {
var resp []*Asset
if err := api.call("lookup_asset_symbols", []interface{}{[]string{symbol}}, &resp); err != nil {
return nil, err
}
if resp[0] == nil {
return nil, errors.Errorf("assets %s not exist", symbol)
}
return resp[0], nil
}

//get_contract_account_by_name
func (api *API) GetWitnessByAccount(accountId string) (*Witness, error) {
var resp *Witness
if err := api.call("get_witness_by_account", []interface{}{accountId}, &resp); err != nil {
return nil, err
}
if resp == nil {
return nil, errors.Errorf("%s is not witness", accountId)
}
return resp, nil
}

// Semantically equivalent to get_account_balances, but takes a name instead of an ID.
func (api *API) GetNamedAccountBalances(account string, assets ...string) ([]*types.AssetAmount, error) {
var resp []*types.AssetAmount
err := api.call("get_named_account_balances", []interface{}{account, assets}, &resp)
return resp, err
}

// LookupAccounts gets names and IDs for registered accounts
// lower_bound_name: Lower bound of the first name to return
// limit: Maximum number of results to return must not exceed 1000
func (api *API) LookupAccounts(lowerBoundName string, limit uint16) (AccountsMap, error) {
var resp AccountsMap
err := api.call("lookup_accounts", []interface{}{lowerBoundName, limit}, &resp)
return resp, err
}

// GetRequiredFee fetchs fee for operations
func (api *API) GetRequiredFee(ops []types.Operation, assetID string) ([]types.AssetAmount, error) {
var resp []types.AssetAmount

opsJSON := []interface{}{}
for _, o := range ops {
_, err := json.Marshal(o)
if err != nil {
return []types.AssetAmount{}, err
}

opArr := []interface{}{o.Type(), o}

opsJSON = append(opsJSON, opArr)
}
if err := api.call("get_required_fees", []interface{}{opsJSON, assetID}, &resp); err != nil {
return nil, err
}
return resp, nil
}

// get_staking_objects
func (api *API) GetStakingObjects(accountID string) ([]*types.StakingObject, error) {
var resp []*types.StakingObject
err := api.call("get_staking_objects", []interface{}{accountID}, &resp)
return resp, err
}

func (api *API) GetStakingPrograms() ([]*types.StakingProgram, error) {
var programs []*types.StakingProgram
globalProperties, err := api.getGlobalProperties()
if err != nil {
return nil, err
}
properties := gjson.Parse(globalProperties.Properties)
extensions := properties.Get("parameters").Get("extensions").Array()
for _, ex := range extensions {
if ex.Array()[0].String() == "11" {
for _, param := range ex.Array()[1].Get("params").Array() {
program := types.StakingProgram{
ProgramId: param.Array()[0].String(),
Weight: uint32(param.Array()[1].Get("weight").Uint()),
StakingDays: uint32(param.Array()[1].Get("staking_days").Uint()),
}
programs = append(programs, &program)
}
}
}
return programs, err
}

func (api *API) getGlobalProperties() (*GlobalProperties, error) {
var resp *GlobalProperties
err := api.call("get_global_properties", rpc.EmptyParams, &resp)
return resp, err
}

// GetBlockHeader returns block header by the given block number
func (api *API) GetBlockHeader(blockNum uint32) (*BlockHeader, error) {
var resp BlockHeader
err := api.call("get_block_header", []interface{}{blockNum}, &resp)
return &resp, err
}
Loading

0 comments on commit 347b61f

Please sign in to comment.