Awesome IRC bot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
5.6 KiB

#!/usr/bin/env python
.. module:: CryptoWalletRPC
:synopsis: Module capable of operating bitcoind-style RPC. Provided as a service.
.. moduleauthor:: Dave Pedu <>
from pyircbot.modulebase import ModuleBase
from bitcoinrpc.authproxy import AuthServiceProxy
import re
from threading import Thread
from decimal import Decimal
class CryptoWalletRPC(ModuleBase):
def __init__(self, bot, moduleName):
ModuleBase.__init__(self, bot, moduleName) = ["bitcoinrpc"]
self.rpcservices = {}
def loadrpcservices(self):
# Create a dict of abbreviation=>BitcoinRPC objcet relation"CryptoWalletRPC: loadrpcservices: connecting to RPCs")
for abbr, coin in self.config["types"].items():
self.rpcservices[abbr.lower()] = BitcoinRPC(self.log,
def getRpc(self, currencyAbbr):
# Return the rpc for the currency requested
# self.getRpc("LTC") -> returns a litecoin rpc instance
currencyAbbr = currencyAbbr.lower()
if currencyAbbr in self.rpcservices:
return self.rpcservices[currencyAbbr]
return None
def getSupported(self):
# return a list of (appreviatons of) supported currencies
return list(self.rpcservices.keys())
def isSupported(self, abbr):
# true/false if currency is supported
supported = self.getSupported()
return abbr.lower() in supported
# def validate_addr(self, coin_abbr, address):
# client = self.getRpc(coin_abbr.lower())
# if not client or not client.validate_addr(:
# return False
def getInfo(self, abbr):
# return the coin's info from config
if self.isSupported(abbr):
return self.config["types"][abbr.upper()]
class BitcoinRPC(object):
def __init__(self, logger, name, fullname, host, port, username, password, precision, reserve, addr_re):
# Store info and connect = name = host
self.port = port
self.username = username
self.password = password
self.precision = precision
self.reserve = reserve
self.addr_re = addr_re
self.log = logger
self.con = None # AuthServiceProxy (bitcoin json rpc client) stored here
Thread( # Initiate rpc connection
def validate_addr(self, addr):
Validate an address string. Returns true if the `addr` provided is a valid address string
:param addr: address to validate
:type addr: str
:return: bool
return True if type(addr) is str and self.addr_re.match(addr) else False
def getBal(self, acct):
Return the balance of the passed account
:param acct: account name
:type acct: str
:return: decimal.Decimal
return self.getAcctBal(acct)
def getAcctAddr(self, acct):
Return the deposit address associated with the passed account
:param acct: account name
:type acct: str
addrs = self.con.getaddressesbyaccount(acct)
if len(addrs) == 0:
return self.con.getnewaddress(acct)
return addrs[0]
def getAcctBal(self, acct):
# returns an account's balance
return Decimal(self.con.getbalance(acct))
def canMove(self, fromAcct, toAcct, amount):
# true or false if fromAcct can afford to give toAcct an amount of coins
balfrom = self.getAcctBal(fromAcct)
return (balfrom - self.reserve) >= amount
def move(self, fromAcct, toAcct, amount):
# move coins from one account to another
if self.canMove(fromAcct, toAcct, amount):
return self.con.move(fromAcct, toAcct, amount)
return False
def send(self, fromAcct, toAddr, amount):
# send coins to an external addr
if self.canMove(fromAcct, toAddr, amount):
return self.con.sendfrom(fromAcct, toAddr, amount)
return False
def checkPrecision(self, amount):
return amount == round(amount, self.precision)
def ping(self):
# internal. test connection and connect if necessary
def connect(self):
# internal. connect to the service"CryptoWalletRPC: %s: Connecting to %s:%s" % (,, self.port))
self.con = AuthServiceProxy("http://%s:%s@%s:%s" % (self.username, self.password,, self.port))
except Exception as e:
self.log.error("CryptoWalletRPC: %s: Could not connect to %s:%s: %s" %
(,, self.port, str(e)))
return"CryptoWalletRPC: %s: Connected to %s:%s" % (,, self.port))