2020-02-17 12:01:57 +00:00
|
|
|
package client
|
2018-03-05 08:53:09 +00:00
|
|
|
|
2018-12-21 09:32:18 +00:00
|
|
|
import (
|
|
|
|
"encoding/hex"
|
|
|
|
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
2020-03-03 17:26:56 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-03-03 17:26:56 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
2018-12-21 09:32:18 +00:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
2018-03-25 16:21:00 +00:00
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// GetAccountState returns detailed information about a NEO account.
|
2020-02-20 18:08:22 +00:00
|
|
|
func (c *Client) GetAccountState(address string) (*result.AccountState, error) {
|
2018-03-05 08:53:09 +00:00
|
|
|
var (
|
2020-01-14 12:02:38 +00:00
|
|
|
params = request.NewRawParams(address)
|
2020-02-20 18:08:22 +00:00
|
|
|
resp = &result.AccountState{}
|
2018-03-05 08:53:09 +00:00
|
|
|
)
|
|
|
|
if err := c.performRequest("getaccountstate", params, resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2020-03-03 17:26:56 +00:00
|
|
|
// GetBlockByIndex returns a block by its height.
|
|
|
|
func (c *Client) GetBlockByIndex(index uint32) (*block.Block, error) {
|
|
|
|
return c.getBlock(request.NewRawParams(index))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockByHash returns a block by its hash.
|
|
|
|
func (c *Client) GetBlockByHash(hash util.Uint256) (*block.Block, error) {
|
|
|
|
return c.getBlock(request.NewRawParams(hash.StringLE()))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) getBlock(params request.RawParams) (*block.Block, error) {
|
|
|
|
var (
|
|
|
|
resp string
|
|
|
|
err error
|
|
|
|
b *block.Block
|
|
|
|
)
|
|
|
|
if err = c.performRequest("getblock", params, &resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
blockBytes, err := hex.DecodeString(resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
r := io.NewBinReaderFromBuf(blockBytes)
|
|
|
|
b = new(block.Block)
|
|
|
|
b.DecodeBinary(r)
|
|
|
|
if r.Err != nil {
|
|
|
|
return nil, r.Err
|
|
|
|
}
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockByIndexVerbose returns a block wrapper with additional metadata by
|
|
|
|
// its height.
|
|
|
|
func (c *Client) GetBlockByIndexVerbose(index uint32) (*result.Block, error) {
|
|
|
|
return c.getBlockVerbose(request.NewRawParams(index, 1))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockByHashVerbose returns a block wrapper with additional metadata by
|
|
|
|
// its hash.
|
|
|
|
func (c *Client) GetBlockByHashVerbose(hash util.Uint256) (*result.Block, error) {
|
|
|
|
return c.getBlockVerbose(request.NewRawParams(hash.StringLE(), 1))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) getBlockVerbose(params request.RawParams) (*result.Block, error) {
|
|
|
|
var (
|
|
|
|
resp = &result.Block{}
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
if err = c.performRequest("getblock", params, &resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2020-02-27 12:46:50 +00:00
|
|
|
// GetClaimable returns tx outputs which can be claimed.
|
|
|
|
func (c *Client) GetClaimable(address string) (*result.ClaimableInfo, error) {
|
|
|
|
params := request.NewRawParams(address)
|
|
|
|
resp := new(result.ClaimableInfo)
|
|
|
|
if err := c.performRequest("getclaimable", params, resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2020-03-05 11:50:06 +00:00
|
|
|
// GetNEP5Balances is a wrapper for getnep5balances RPC.
|
|
|
|
func (c *Client) GetNEP5Balances(address util.Uint160) (*result.NEP5Balances, error) {
|
|
|
|
params := request.NewRawParams(address.StringLE())
|
|
|
|
resp := new(result.NEP5Balances)
|
|
|
|
if err := c.performRequest("getnep5balances", params, resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2020-03-05 12:16:03 +00:00
|
|
|
// GetNEP5Transfers is a wrapper for getnep5transfers RPC.
|
|
|
|
func (c *Client) GetNEP5Transfers(address string) (*result.NEP5Transfers, error) {
|
|
|
|
params := request.NewRawParams(address)
|
|
|
|
resp := new(result.NEP5Transfers)
|
|
|
|
if err := c.performRequest("getnep5transfers", params, resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2020-03-03 17:43:57 +00:00
|
|
|
// GetRawTransaction returns a transaction by hash.
|
|
|
|
func (c *Client) GetRawTransaction(hash util.Uint256) (*transaction.Transaction, error) {
|
|
|
|
var (
|
|
|
|
params = request.NewRawParams(hash.StringLE())
|
|
|
|
resp string
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
if err = c.performRequest("getrawtransaction", params, &resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
txBytes, err := hex.DecodeString(resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
r := io.NewBinReaderFromBuf(txBytes)
|
|
|
|
tx := new(transaction.Transaction)
|
|
|
|
tx.DecodeBinary(r)
|
|
|
|
if r.Err != nil {
|
|
|
|
return nil, r.Err
|
|
|
|
}
|
|
|
|
return tx, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRawTransactionVerbose returns a transaction wrapper with additional
|
|
|
|
// metadata by transaction's hash.
|
|
|
|
func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.TransactionOutputRaw, error) {
|
|
|
|
var (
|
|
|
|
params = request.NewRawParams(hash.StringLE(), 1)
|
|
|
|
resp = &result.TransactionOutputRaw{}
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
if err = c.performRequest("getrawtransaction", params, &resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2019-11-19 17:15:32 +00:00
|
|
|
// GetUnspents returns UTXOs for the given NEO account.
|
2020-02-20 18:08:22 +00:00
|
|
|
func (c *Client) GetUnspents(address string) (*result.Unspents, error) {
|
2019-11-19 17:15:32 +00:00
|
|
|
var (
|
2020-01-14 12:02:38 +00:00
|
|
|
params = request.NewRawParams(address)
|
2020-02-20 18:08:22 +00:00
|
|
|
resp = &result.Unspents{}
|
2019-11-19 17:15:32 +00:00
|
|
|
)
|
|
|
|
if err := c.performRequest("getunspents", params, resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2019-02-13 18:01:10 +00:00
|
|
|
// InvokeScript returns the result of the given script after running it true the VM.
|
|
|
|
// NOTE: This is a test invoke and will not affect the blockchain.
|
2020-03-03 10:08:34 +00:00
|
|
|
func (c *Client) InvokeScript(script string) (*result.Invoke, error) {
|
2018-03-05 08:53:09 +00:00
|
|
|
var (
|
2020-01-14 12:02:38 +00:00
|
|
|
params = request.NewRawParams(script)
|
2020-03-03 10:08:34 +00:00
|
|
|
resp = &result.Invoke{}
|
2018-03-05 08:53:09 +00:00
|
|
|
)
|
|
|
|
if err := c.performRequest("invokescript", params, resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// InvokeFunction returns the results after calling the smart contract scripthash
|
2018-03-25 16:21:00 +00:00
|
|
|
// with the given operation and parameters.
|
|
|
|
// NOTE: this is test invoke and will not affect the blockchain.
|
2020-03-03 10:08:34 +00:00
|
|
|
func (c *Client) InvokeFunction(script, operation string, params []smartcontract.Parameter) (*result.Invoke, error) {
|
2018-03-25 16:21:00 +00:00
|
|
|
var (
|
2020-01-14 12:02:38 +00:00
|
|
|
p = request.NewRawParams(script, operation, params)
|
2020-03-03 10:08:34 +00:00
|
|
|
resp = &result.Invoke{}
|
2018-03-25 16:21:00 +00:00
|
|
|
)
|
|
|
|
if err := c.performRequest("invokefunction", p, resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// Invoke returns the results after calling the smart contract scripthash
|
2018-11-26 15:57:53 +00:00
|
|
|
// with the given parameters.
|
2020-03-03 10:08:34 +00:00
|
|
|
func (c *Client) Invoke(script string, params []smartcontract.Parameter) (*result.Invoke, error) {
|
2018-11-26 15:57:53 +00:00
|
|
|
var (
|
2020-01-14 12:02:38 +00:00
|
|
|
p = request.NewRawParams(script, params)
|
2020-03-03 10:08:34 +00:00
|
|
|
resp = &result.Invoke{}
|
2018-11-26 15:57:53 +00:00
|
|
|
)
|
|
|
|
if err := c.performRequest("invoke", p, resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2020-02-27 07:58:46 +00:00
|
|
|
// SendRawTransaction broadcasts a transaction over the NEO network.
|
2018-03-05 08:53:09 +00:00
|
|
|
// The given hex string needs to be signed with a keypair.
|
|
|
|
// When the result of the response object is true, the TX has successfully
|
|
|
|
// been broadcasted to the network.
|
2020-02-27 07:58:46 +00:00
|
|
|
func (c *Client) SendRawTransaction(rawTX *transaction.Transaction) error {
|
2018-03-05 08:53:09 +00:00
|
|
|
var (
|
2020-01-14 12:02:38 +00:00
|
|
|
params = request.NewRawParams(hex.EncodeToString(rawTX.Bytes()))
|
2020-02-20 18:08:22 +00:00
|
|
|
resp bool
|
2018-03-05 08:53:09 +00:00
|
|
|
)
|
2020-02-20 18:08:22 +00:00
|
|
|
if err := c.performRequest("sendrawtransaction", params, &resp); err != nil {
|
|
|
|
return err
|
2018-03-05 08:53:09 +00:00
|
|
|
}
|
2020-02-20 18:08:22 +00:00
|
|
|
if !resp {
|
|
|
|
return errors.New("sendrawtransaction returned false")
|
|
|
|
}
|
|
|
|
return nil
|
2018-03-05 08:53:09 +00:00
|
|
|
}
|
2018-12-21 09:32:18 +00:00
|
|
|
|
2020-02-28 11:14:35 +00:00
|
|
|
// TransferAsset sends an amount of specific asset to a given address.
|
2019-02-12 19:03:21 +00:00
|
|
|
// This call requires open wallet. (`wif` key in client struct.)
|
2018-12-21 09:32:18 +00:00
|
|
|
// If response.Result is `true` then transaction was formed correctly and was written in blockchain.
|
2020-02-28 11:14:35 +00:00
|
|
|
func (c *Client) TransferAsset(asset util.Uint256, address string, amount util.Fixed8) (util.Uint256, error) {
|
2018-12-21 09:32:18 +00:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
rawTx *transaction.Transaction
|
2020-02-17 11:54:53 +00:00
|
|
|
txParams = request.ContractTxParams{
|
|
|
|
AssetID: asset,
|
|
|
|
Address: address,
|
|
|
|
Value: amount,
|
|
|
|
WIF: c.WIF(),
|
|
|
|
Balancer: c.Balancer(),
|
2018-12-21 09:32:18 +00:00
|
|
|
}
|
2020-02-20 18:08:22 +00:00
|
|
|
resp util.Uint256
|
2018-12-21 09:32:18 +00:00
|
|
|
)
|
|
|
|
|
2020-02-17 11:54:53 +00:00
|
|
|
if rawTx, err = request.CreateRawContractTransaction(txParams); err != nil {
|
2020-02-28 11:14:35 +00:00
|
|
|
return resp, errors.Wrap(err, "failed to create raw transaction")
|
2018-12-21 09:32:18 +00:00
|
|
|
}
|
2020-02-27 07:58:46 +00:00
|
|
|
if err = c.SendRawTransaction(rawTx); err != nil {
|
2020-02-20 16:29:21 +00:00
|
|
|
return resp, errors.Wrap(err, "failed to send raw transaction")
|
2019-01-22 12:14:40 +00:00
|
|
|
}
|
2020-02-20 18:08:22 +00:00
|
|
|
return rawTx.Hash(), nil
|
2018-12-21 09:32:18 +00:00
|
|
|
}
|
2019-11-20 13:07:43 +00:00
|
|
|
|
2019-11-29 14:59:07 +00:00
|
|
|
// SignAndPushInvocationTx signs and pushes given script as an invocation
|
|
|
|
// transaction using given wif to sign it and spending the amount of gas
|
|
|
|
// specified. It returns a hash of the invocation transaction and an error.
|
|
|
|
func (c *Client) SignAndPushInvocationTx(script []byte, wif *keys.WIF, gas util.Fixed8) (util.Uint256, error) {
|
2019-11-20 13:07:43 +00:00
|
|
|
var txHash util.Uint256
|
2019-11-29 14:59:07 +00:00
|
|
|
var err error
|
2019-11-20 13:07:43 +00:00
|
|
|
|
2019-11-29 14:59:07 +00:00
|
|
|
tx := transaction.NewInvocationTX(script, gas)
|
2019-11-20 13:07:43 +00:00
|
|
|
|
|
|
|
fromAddress := wif.PrivateKey.Address()
|
|
|
|
|
2019-11-29 15:00:08 +00:00
|
|
|
if gas > 0 {
|
2020-02-17 11:54:53 +00:00
|
|
|
if err = request.AddInputsAndUnspentsToTx(tx, fromAddress, core.UtilityTokenID(), gas, c); err != nil {
|
2019-11-29 15:00:08 +00:00
|
|
|
return txHash, errors.Wrap(err, "failed to add inputs and unspents to transaction")
|
|
|
|
}
|
2019-11-20 13:07:43 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 16:01:07 +00:00
|
|
|
acc, err := wallet.NewAccountFromWIF(wif.S)
|
|
|
|
if err != nil {
|
|
|
|
return txHash, err
|
|
|
|
} else if err = acc.SignTx(tx); err != nil {
|
2019-11-20 13:07:43 +00:00
|
|
|
return txHash, errors.Wrap(err, "failed to sign tx")
|
|
|
|
}
|
|
|
|
txHash = tx.Hash()
|
2020-02-27 07:58:46 +00:00
|
|
|
err = c.SendRawTransaction(tx)
|
2019-11-20 13:07:43 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return txHash, errors.Wrap(err, "failed sendning tx")
|
|
|
|
}
|
|
|
|
return txHash, nil
|
|
|
|
}
|