// (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package evm import ( "fmt" "time" "github.com/ava-labs/avalanchego/api" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/formatting" cjson "github.com/ava-labs/avalanchego/utils/json" "github.com/ava-labs/avalanchego/utils/rpc" ) // Client ... type Client struct { requester rpc.EndpointRequester } // NewClient returns a Client for interacting with EVM [chain] func NewClient(uri, chain string, requestTimeout time.Duration) *Client { return &Client{ requester: rpc.NewEndpointRequester(uri, fmt.Sprintf("/ext/bc/%s/avax", chain), "avax", requestTimeout), } } // NewCChainClient returns a Client for interacting with the C Chain func NewCChainClient(uri string, requestTimeout time.Duration) *Client { return NewClient(uri, "C", requestTimeout) } // IssueTx issues a transaction to a node and returns the TxID func (c *Client) IssueTx(txBytes []byte) (ids.ID, error) { res := &api.JSONTxID{} txStr, err := formatting.Encode(formatting.Hex, txBytes) if err != nil { return res.TxID, fmt.Errorf("problem hex encoding bytes: %w", err) } err = c.requester.SendRequest("issueTx", &api.FormattedTx{ Tx: txStr, Encoding: formatting.Hex, }, res) return res.TxID, err } // GetTxStatus returns the status of [txID] // func (c *Client) GetTxStatus(txID ids.ID) (choices.Status, error) { // res := &GetTxStatusReply{} // err := c.requester.SendRequest("getTxStatus", &api.JSONTxID{ // TxID: txID, // }, res) // return res.Status, err // } // GetTx returns the byte representation of [txID] func (c *Client) GetTx(txID ids.ID) ([]byte, error) { res := &api.FormattedTx{} err := c.requester.SendRequest("getTx", &api.GetTxArgs{ TxID: txID, Encoding: formatting.Hex, }, res) if err != nil { return nil, err } return formatting.Decode(formatting.Hex, res.Tx) } // GetUTXOs returns the byte representation of the UTXOs controlled by [addrs] func (c *Client) GetUTXOs(addrs []string, limit uint32, startAddress, startUTXOID string) ([][]byte, api.Index, error) { res := &api.GetUTXOsReply{} err := c.requester.SendRequest("getUTXOs", &api.GetUTXOsArgs{ Addresses: addrs, Limit: cjson.Uint32(limit), StartIndex: api.Index{ Address: startAddress, UTXO: startUTXOID, }, Encoding: formatting.Hex, }, res) if err != nil { return nil, api.Index{}, err } utxos := make([][]byte, len(res.UTXOs)) for i, utxo := range res.UTXOs { b, err := formatting.Decode(formatting.Hex, utxo) if err != nil { return nil, api.Index{}, err } utxos[i] = b } return utxos, res.EndIndex, nil } // CreateAddress creates a new address controlled by [user] func (c *Client) CreateAddress(user api.UserPass) (string, error) { res := &api.JSONAddress{} err := c.requester.SendRequest("createAddress", &user, res) return res.Address, err } // ListAddresses returns all addresses on this chain controlled by [user] func (c *Client) ListAddresses(user api.UserPass) ([]string, error) { res := &api.JSONAddresses{} err := c.requester.SendRequest("listAddresses", &user, res) return res.Addresses, err } // ExportKey returns the private key corresponding to [addr] controlled by [user] // in both Avalanche standard format and hex format func (c *Client) ExportKey(user api.UserPass, addr string) (string, string, error) { res := &ExportKeyReply{} err := c.requester.SendRequest("exportKey", &ExportKeyArgs{ UserPass: user, Address: addr, }, res) return res.PrivateKey, res.PrivateKeyHex, err } // ImportKey imports [privateKey] to [user] func (c *Client) ImportKey(user api.UserPass, privateKey string) (string, error) { res := &api.JSONAddress{} err := c.requester.SendRequest("importKey", &ImportKeyArgs{ UserPass: user, PrivateKey: privateKey, }, res) return res.Address, err } // Import sends an import transaction to import funds from [sourceChain] and // returns the ID of the newly created transaction func (c *Client) Import(user api.UserPass, to, sourceChain string) (ids.ID, error) { res := &api.JSONTxID{} err := c.requester.SendRequest("import", &ImportArgs{ UserPass: user, To: to, SourceChain: sourceChain, }, res) return res.TxID, err } // ExportAVAX sends AVAX from this chain to the address specified by [to]. // Returns the ID of the newly created atomic transaction func (c *Client) ExportAVAX( user api.UserPass, amount uint64, to string, ) (ids.ID, error) { return c.Export(user, amount, to, "AVAX") } // Export sends an asset from this chain to the P/C-Chain. // After this tx is accepted, the AVAX must be imported to the P/C-chain with an importTx. // Returns the ID of the newly created atomic transaction func (c *Client) Export( user api.UserPass, amount uint64, to string, assetID string, ) (ids.ID, error) { res := &api.JSONTxID{} err := c.requester.SendRequest("export", &ExportArgs{ ExportAVAXArgs: ExportAVAXArgs{ UserPass: user, Amount: cjson.Uint64(amount), To: to, }, AssetID: assetID, }, res) return res.TxID, err }