Files
atomic-swap/monero/rpc.go

362 lines
7.3 KiB
Go

package monero
import (
"encoding/json"
"fmt"
"strings"
"github.com/noot/atomic-swap/common/rpctypes"
mcrypto "github.com/noot/atomic-swap/crypto/monero"
)
type generateFromKeysRequest struct {
Filename string `json:"filename"`
Address string `json:"address"`
SpendKey string `json:"spendkey"`
ViewKey string `json:"viewkey"`
Password string `json:"password"`
}
type generateFromKeysResponse struct {
Address string `json:"address"`
Info string `json:"info"`
}
func (c *client) callGenerateFromKeys(sk *mcrypto.PrivateSpendKey, vk *mcrypto.PrivateViewKey, address mcrypto.Address,
filename, password string) error {
const (
method = "generate_from_keys"
successMessage = "Wallet has been generated successfully."
viewOnlySuccessMessage = "Watch-only wallet has been generated successfully."
)
req := &generateFromKeysRequest{
Filename: filename,
Address: string(address),
ViewKey: vk.Hex(),
Password: password,
}
if sk != nil {
req.SpendKey = sk.Hex()
}
params, err := json.Marshal(req)
if err != nil {
return err
}
resp, err := rpctypes.PostRPC(c.endpoint, method, string(params))
if err != nil {
return err
}
if resp.Error != nil {
return resp.Error
}
var res *generateFromKeysResponse
if err = json.Unmarshal(resp.Result, &res); err != nil {
return err
}
// TODO: check for if we passed spend key or not
if strings.Compare(successMessage, res.Info) == 0 || strings.Compare(viewOnlySuccessMessage, res.Info) == 0 {
return nil
}
return fmt.Errorf("got unexpected Info string: %s", res.Info)
}
// Destination represents a transfer destination
type Destination struct {
Amount uint `json:"amount"`
Address string `json:"address"`
}
type sweepAllRequest struct {
Address string `json:"address"`
AccountIndex uint `json:"account_index"`
}
// SweepAllResponse ...
type SweepAllResponse struct {
AmountList []uint `json:"amount_list"`
FeeList []uint `json:"fee_list"`
TxHashList []string `json:"tx_hash_list"`
}
func (c *client) callSweepAll(to string, accountIdx uint) (*SweepAllResponse, error) {
const (
method = "sweep_all"
)
req := &sweepAllRequest{
AccountIndex: accountIdx,
Address: to,
}
params, err := json.Marshal(req)
if err != nil {
return nil, err
}
resp, err := rpctypes.PostRPC(c.endpoint, method, string(params))
if err != nil {
return nil, err
}
if resp.Error != nil {
return nil, resp.Error
}
var res *SweepAllResponse
if err = json.Unmarshal(resp.Result, &res); err != nil {
return nil, err
}
return res, nil
}
type transferRequest struct {
Destinations []Destination `json:"destinations"`
AccountIndex uint // optional
Priority uint `json:"priority"`
}
// TransferResponse ...
type TransferResponse struct {
Amount uint `json:"amount"`
Fee uint `json:"fee"`
MultisigTxset interface{} `json:"multisig_txset"`
TxBlob string `json:"tx_blob"`
TxHash string `json:"tx_hash"`
TxKey string `json:"tx_key"`
TxMetadata string `json:"tx_metadata"`
UnsignedTxset string `json:"unsigned_txset"`
}
func (c *client) callTransfer(destinations []Destination, accountIdx uint) (*TransferResponse, error) {
const (
method = "transfer"
)
req := &transferRequest{
Destinations: destinations,
AccountIndex: accountIdx,
Priority: 0,
}
params, err := json.Marshal(req)
if err != nil {
return nil, err
}
resp, err := rpctypes.PostRPC(c.endpoint, method, string(params))
if err != nil {
return nil, err
}
if resp.Error != nil {
return nil, resp.Error
}
var res *TransferResponse
if err = json.Unmarshal(resp.Result, &res); err != nil {
return nil, err
}
return res, nil
}
type getBalanceRequest struct {
AccountIndex uint `json:"account_index"`
}
// GetBalanceResponse ...
type GetBalanceResponse struct {
Balance float64 `json:"balance"`
BlocksToUnlock uint `json:"blocks_to_unlock"`
UnlockedBalance float64 `json:"unlocked_balance"`
PerSubaddress []map[string]interface{} `json:"per_subaddress"`
}
func (c *client) callGetBalance(idx uint) (*GetBalanceResponse, error) {
const method = "get_balance"
req := &getBalanceRequest{
AccountIndex: idx,
}
params, err := json.Marshal(req)
if err != nil {
return nil, err
}
resp, err := rpctypes.PostRPC(c.endpoint, method, string(params))
if err != nil {
return nil, err
}
if resp.Error != nil {
return nil, resp.Error
}
var res *GetBalanceResponse
if err = json.Unmarshal(resp.Result, &res); err != nil {
return nil, err
}
return res, nil
}
// GetAddressRequest ...
type GetAddressRequest struct {
AccountIndex uint `json:"account_index"`
}
// GetAddressResponse ...
type GetAddressResponse struct {
Address string `json:"address"`
}
func (c *client) callGetAddress(idx uint) (*GetAddressResponse, error) {
const method = "get_address"
req := &GetAddressRequest{
AccountIndex: idx,
}
params, err := json.Marshal(req)
if err != nil {
return nil, err
}
resp, err := rpctypes.PostRPC(c.endpoint, method, string(params))
if err != nil {
return nil, err
}
if resp.Error != nil {
return nil, resp.Error
}
var res *GetAddressResponse
if err = json.Unmarshal(resp.Result, &res); err != nil {
return nil, err
}
return res, nil
}
// GetAccountsResponse ...
type GetAccountsResponse struct {
SubaddressAccounts []map[string]interface{} `json:"subaddress_accounts"`
}
func (c *client) callGetAccounts() (*GetAccountsResponse, error) {
const method = "get_accounts"
resp, err := rpctypes.PostRPC(c.endpoint, method, "{}")
if err != nil {
return nil, err
}
if resp.Error != nil {
return nil, resp.Error
}
var res *GetAccountsResponse
if err = json.Unmarshal(resp.Result, &res); err != nil {
return nil, err
}
return res, nil
}
type openWalletRequest struct {
Filename string `json:"filename"`
Password string `json:"password"`
}
func (c *client) callOpenWallet(filename, password string) error {
const method = "open_wallet"
req := &openWalletRequest{
Filename: filename,
Password: password,
}
params, err := json.Marshal(req)
if err != nil {
return err
}
resp, err := rpctypes.PostRPC(c.endpoint, method, string(params))
if err != nil {
return err
}
if resp.Error != nil {
return resp.Error
}
return nil
}
type createWalletRequest struct {
Filename string `json:"filename"`
Password string `json:"password"`
Language string `json:"language"`
}
func (c *client) callCreateWallet(filename, password string) error {
const method = "create_wallet"
req := &createWalletRequest{
Filename: filename,
Password: password,
Language: "English",
}
params, err := json.Marshal(req)
if err != nil {
return err
}
resp, err := rpctypes.PostRPC(c.endpoint, method, string(params))
if err != nil {
return err
}
if resp.Error != nil {
return resp.Error
}
return nil
}
type getHeightResponse struct {
Height uint `json:"height"`
}
func (c *client) callGetHeight() (uint, error) {
const method = "get_height"
resp, err := rpctypes.PostRPC(c.endpoint, method, "{}")
if err != nil {
return 0, err
}
if resp.Error != nil {
return 0, resp.Error
}
var res *getHeightResponse
if err = json.Unmarshal(resp.Result, &res); err != nil {
return 0, err
}
return res.Height, nil
}