Skip to content

A Monero RPC Wallet client implementation written in Go (Golang)

License

Notifications You must be signed in to change notification settings

LuaxY/go-monero

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

63 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-monero

This package is a hub of monero related tools for Go. At this time, only the Wallet RPC Client is available.

Go Report Card Build Status

Wallet RPC Client

GoDoc

The go-monero/walletrpc package is a RPC client with all the methods of the v0.15.0.0 release. It does support digest authentication, however I don't recommend using it alone (without https). If there is a need to split the RPC client and server into separate instances, you could put a proxy on the instance that contains the RPC server and check the authenticity of the requests using https + X-API-KEY headers between the proxy and this RPC client (there is an example about this implementation below)

Installation

go get -u github.com/LuaxY/go-monero/walletrpc

Usage

The simplest way to use walletrpc is if you have both the server (monero-wallet-rpc) and the client on the same machine.

Running monero-wallet-rpc:

monero-wallet-rpc --testnet --wallet-file ~/testnet/mywallet.bin --rpc-bind-port 18082 --disable-rpc-login

Go:

package main

import (
	"fmt"
	"os"

	"github.com/LuaxY/go-monero/walletrpc"
	"github.com/LuaxY/go-monero/walletrpc/unit"
)

func main() {
	// Start a wallet client instance
	client := walletrpc.New(walletrpc.Config{
		Address: "http://127.0.0.1:18082/json_rpc",
	})

	// check wallet balance
	balance, err := client.GetBalance(&walletrpc.GetBalanceRequest{
		AccountIndex: 0,
	})

	// there are two types of error that can happen:
	//   connection errors
	//   monero wallet errors
	// connection errors are pretty much unicorns if everything is on the
	// same instance (unless your OS hit an open files limit or something)
	if err != nil {
		if iswerr, werr := walletrpc.GetWalletError(err); iswerr {
			// it is a monero wallet error
			fmt.Printf("Wallet error (id:%v) %v\n", werr.Code, werr.Message)
			os.Exit(1)
		}
		fmt.Println("Error:", err.Error())
		os.Exit(1)
	}

	fmt.Println("Balance:", walletrpc.XMRToDecimal(balance.Balance))
	fmt.Println("Unlocked balance:", walletrpc.XMRToDecimal(balance.UnlockedBalance))

	// Make a transfer
	res, err := client.Transfer(&walletrpc.TransferRequest{
		Destinations: []walletrpc.Destination{
			{
				Address: "45eoXYNHC4LcL2Hh42T9FMPTmZHyDEwDbgfBEuNj3RZUek8A4og4KiCfVL6ZmvHBfCALnggWtHH7QHF8426yRayLQq7MLf5",
				Amount:  10 * unit.Millinero, // 0.01 XMR
			},
		},
		Priority: walletrpc.PriorityUnimportant,
		Mixin:    1,
	})
	if err != nil {
		if iswerr, werr := walletrpc.GetWalletError(err); iswerr {
			// insufficient funds return a monero wallet error
			// walletrpc.ErrGenericTransferError
			fmt.Printf("Wallet error (id:%v) %v\n", werr.Code, werr.Message)
			os.Exit(1)
		}
		fmt.Println("Error:", err.Error())
		os.Exit(1)
	}
	fmt.Println("Transfer success! Fee:", walletrpc.XMRToDecimal(uint64(res.Fee)), "Hash:", res.TxHash)
}

Using Digest Authentication

monero-wallet-rpc --testnet --rpc-bind-ip 127.0.0.1 --rpc-bind-port 29567 --rpc-login john:doe --wallet-file ~/testnet/wallet_03.bin
package main

import (
	"fmt"

	"github.com/gabstv/httpdigest"

	"github.com/LuaxY/go-monero/walletrpc"
)

func main() {
	// username: john
	// password: doe
	t := httpdigest.New("john", "doe")

	client := walletrpc.New(walletrpc.Config{
		Address:   "http://127.0.0.1:29567/json_rpc",
		Transport: t,
	})

	balance, err := client.GetBalance(&walletrpc.GetBalanceRequest{
		AccountIndex: 0,
	})

	if err != nil {
		panic(err)
	}
	fmt.Println("balance", walletrpc.XMRToDecimal(balance.Balance))
	fmt.Println("unlocked balance", walletrpc.XMRToDecimal(balance.UnlockedBalance))
}

Using a proxy

You can use a proxy to be in between this client and the monero RPC server. This way you can use a safe encryption tunnel around the network.

Starting the RPC server

monero-wallet-rpc --testnet --wallet-file ~/testnet/mywallet.bin --rpc-bind-port 18082 --disable-rpc-login

Starting a proxy server

This example uses sandpiper (github.com/gabstv/sandpiper/sandpiper) but you could also use nginx or apache

sandpiper config.yml:

debug: true
#listen_addr:     :8084
listen_addr_tls: :23456
fallback_domain: moneroproxy
routes:
  - 
    domain:        moneroproxy
    out_conn_type: HTTP
    out_addr:      localhost:18082
    auth_mode:  apikey
    auth_key:   X-API-KEY
    auth_value: 55c12fca1b994455d3ec1795bdc82cca
    tls_cert_file: moneroproxy.cert.pem
    tls_key_file:  moneroproxy.key.pem

The Go program is similar, but it uses an API-KEY:

package main

import (
    "crypto/tls"
    "fmt"
    "net/http"
    "os"
    
    "github.com/LuaxY/go-monero/walletrpc"
)

func main() {
	// Start a wallet client instance
	client := walletrpc.New(walletrpc.Config{
        Address: "http://127.0.0.1:23456/json_rpc",
        CustomHeaders: map[string]string{
			"X-API-KEY": "55c12fca1b994455d3ec1795bdc82cca", // we use the same key defined above
        },
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true, // WARNING: instead of this, you can
				// provide (or install) a certificate to make it
				// really secure with Certificates: []tls.Certificate{},
			},
		},
	})

	// check wallet balance
	balance, err := client.GetBalance(&walletrpc.GetBalanceRequest{
        AccountIndex: 0,
    })

	// there are two types of error that can happen:
	//   connection errors
	//   monero wallet errors
	// connection errors are pretty much unicorns if everything is on the
	// same instance (unless your OS hit an open files limit or something)
	if err != nil {
		if iswerr, werr := walletrpc.GetWalletError(err); iswerr {
			// it is a monero wallet error
			fmt.Printf("Wallet error (id:%v) %v\n", werr.Code, werr.Message)
			os.Exit(1)
		}
		fmt.Println("Error:", err.Error())
		os.Exit(1)
	}

	fmt.Println("Balance:", walletrpc.XMRToDecimal(balance.Balance))
    fmt.Println("Unlocked balance:", walletrpc.XMRToDecimal(balance.UnlockedBalance))
}

Special Thanks

This version of go-monero is based on the works of: