Exemple #1
0
    def __init__(self, _conf=None):
        """
        Initialize CtbCoin with given parameters. _conf is a coin config dictionary defined in conf/coins.yml
        """

        # verify _conf is a config dictionary
        if (not _conf or not hasattr(_conf, "name")
                or not hasattr(_conf, "config_file")
                or not hasattr(_conf, "txfee")):
            raise Exception("CtbCoin::__init__(): _conf is empty or invalid")

        self.conf = _conf

        # connect to coin daemon
        try:
            lg.debug("CtbCoin::__init__(): connecting to %s...",
                     self.conf.name)
            self.conn = Bitcoind(self.conf.config_file,
                                 rpcserver=self.conf.config_rpcserver)
        except BitcoindException as e:
            lg.error(
                "CtbCoin::__init__(): error connecting to %s using %s: %s",
                self.conf.name,
                self.conf.config_file,
                e,
            )
            raise

        lg.info("CtbCoin::__init__():: connected to %s", self.conf.name)
        time.sleep(0.5)

        # set transaction fee
        lg.info("Setting tx fee of %f", self.conf.txfee)
        self.conn.settxfee(self.conf.txfee)
Exemple #2
0
def tip(ctx, to_user, amount):
    '''Send a tip to another user'''

    # Author is a Member
    from_id = ctx.message.author.id

    if not is_registered(from_id):
        yield from bot.say(
            'You are not registered. Use ?register to create an account.')
        return

    dconn = Bitcoind('~/.dashcore/dash.conf',
                     rpcport=19998)  # testnet, 9998 is realnet
    balance = dconn.getbalance(from_id)
    if float(amount) > balance:
        yield from bot.say('You can only send up to %f.' % balance)
        return

    if to_user.startswith('<@') and to_user.endswith('>'):
        to_id = to_user[2:-1]
    else:
        yield from bot.say(
            'Bad user id "%s", please use @ symbol so Discord sends me a user id.'
            % to_user)
        return

    new_tx(from_id, to_id, float(amount))
    yield from bot.say('A tip of %s dash will be offered to %s.' %
                       (amount, to_user))
Exemple #3
0
def send(ctx, addr, amount):
    '''Send from my account to abitrary dash address'''

    # Author is a Member
    id = ctx.message.author.id

    if not is_registered(id):
        yield from bot.say(
            'You are not registered. Use ?register to create an account.')
        return

    dconn = Bitcoind('~/.dashcore/dash.conf',
                     rpcport=19998)  # testnet, 9998 is realnet
    balance = dconn.getbalance(id)
    if float(amount) > balance:
        yield from bot.say('You can only send up to %f.' % balance)
        return

    txid = dconn.sendfrom(id, addr, amount)

    # Generate and save a QR code with the address
    im = qrcode.make(txid)
    filename = '/tmp/' + txid + '.png'
    im.save(filename, 'png')

    yield from bot.say('Your transaction id is %s.' % (txid))
    yield from bot.send_file(ctx.message.channel, filename)

    # Clean up the image file
    os.remove(filename)
Exemple #4
0
def register(ctx):
    '''Adds a user to the database, generates a wallet for them, gives them its address to send funds to.'''

    # Author is a Member
    id = ctx.message.author.id
    name = ctx.message.author.name

    if is_registered(id):
        yield from bot.say(
            'You are already registered. Use ?getaddress to get your tip wallet address'
        )
        return

    new_user(id, name)

    # Generate a new address
    dconn = Bitcoind('~/.dashcore/dash.conf',
                     rpcport=19998)  # testnet, 9998 is realnet
    addr = dconn.getnewaddress()
    dconn.setaccount(addr, id)

    # Generate and save a QR code with the address
    im = qrcode.make(addr)
    filename = '/tmp/' + addr + '.png'
    im.save(filename, 'png')

    yield from bot.say(
        'Welcome %s, your tip wallet address is %s.\nPlease send some dash here to be able to tip.'
        % (name, addr))
    yield from bot.send_file(ctx.message.channel, filename)

    # Clean up the image file
    os.remove(filename)
Exemple #5
0
def getaddress(ctx):
    '''Resends the user's current account address'''

    # Author is a Member
    id = ctx.message.author.id

    if not is_registered(id):
        yield from bot.say(
            'You are not registered. Use ?register to create an account.')
        return

    dconn = Bitcoind('~/.dashcore/dash.conf',
                     rpcport=19998)  # testnet, 9998 is realnet
    addr = dconn.getaccountaddress(id)
    dconn.setaccount(addr, id)

    # Generate and save a QR code with the address
    im = qrcode.make(addr)
    filename = '/tmp/' + addr + '.png'
    im.save(filename, 'png')

    yield from bot.say('Your tip wallet address is %s.' % (addr))
    yield from bot.send_file(ctx.message.channel, filename)

    # Clean up the image file
    os.remove(filename)
Exemple #6
0
    def __init__(self, _conf = None):
        """
        Initialize CtbCoin with given parameters
            _conf is a coin config dictionary defined in sample-config.yml under 'cc'
        """

        # verify _conf is a config dictionary
        if not _conf or not _conf.has_key('name') or not _conf.has_key('conf-file'):
            raise Exception("CtbCoin::__init__(): _conf is empty or invalid")

        self.conf = _conf

        # connect to coin daemon
        try:
            lg.debug("CtbCoin::__init__(): connecting to %s...", self.conf['name'])
            self.conn = Bitcoind(self.conf['conf-file'])
        except BitcoindException as e:
            lg.error("CtbCoin::__init__(): error connecting to %s: %s", self.conf['name'], str(e))
            raise

        lg.info("CtbCoin::__init__():: connected to %s", self.conf['name'])

        # set transaction fee
        lg.info("Setting tx fee of %f", self.conf['txfee'])
        self.conn.settxfee(self.conf['txfee'])
Exemple #7
0
    def __init__(self, _conf = None):
        """
        Initialize CtbCoin with given parameters. _conf is a coin config dictionary defined in conf/coins.yml
        """

        # verify _conf is a config dictionary
        if not _conf or not hasattr(_conf, 'name') or not hasattr(_conf, 'config_file') or not hasattr(_conf, 'txfee'):
            raise Exception("CtbCoin::__init__(): _conf is empty or invalid")

        self.conf = _conf

        # connect to coin daemon
        try:
            lg.debug("CtbCoin::__init__(): connecting to %s...", self.conf.name)
            self.conn = Bitcoind(self.conf.config_file, rpcserver=self.conf.config_rpcserver)
        except BitcoindException as e:
            lg.error("CtbCoin::__init__(): error connecting to %s using %s: %s", self.conf.name, self.conf.config_file, e)
            raise

        lg.info("CtbCoin::__init__():: connected to %s", self.conf.name)
        time.sleep(0.5)

        # set transaction fee
        lg.info("Setting tx fee of %f", self.conf.txfee)
        self.conn.settxfee(self.conf.txfee)
Exemple #8
0
    def _connect_coin(self, c):
        """
        Returns a coin daemon connection object
        """
        lg.debug("Connecting to %s...", c['name'])

        try:
            conn = Bitcoind(c['conf-file'])
        except BitcoindException as e:
            lg.error("Error connecting to %s: %s", c['name'], str(e))
            sys.exit(1)
        lg.info("Connected to %s", c['name'])

        # Set tx fee
        lg.info("Setting tx fee of %f", c['txfee'])
        conn.settxfee(c['txfee'])

        # Done
        return conn
Exemple #9
0
class CtbCoin(object):
    """
    Coin class for cointip bot
    """

    conn = None
    conf = None

    def __init__(self, _conf = None):
        """
        Initialize CtbCoin with given parameters
            _conf is a coin config dictionary defined in sample-config.yml under 'cc'
        """

        # verify _conf is a config dictionary
        if not _conf or not _conf.has_key('name') or not _conf.has_key('conf-file'):
            raise Exception("CtbCoin::__init__(): _conf is empty or invalid")

        self.conf = _conf

        # connect to coin daemon
        try:
            lg.debug("CtbCoin::__init__(): connecting to %s...", self.conf['name'])
            self.conn = Bitcoind(self.conf['conf-file'])
        except BitcoindException as e:
            lg.error("CtbCoin::__init__(): error connecting to %s: %s", self.conf['name'], str(e))
            raise

        lg.info("CtbCoin::__init__():: connected to %s", self.conf['name'])

        # set transaction fee
        lg.info("Setting tx fee of %f", self.conf['txfee'])
        self.conn.settxfee(self.conf['txfee'])

    def getbalance(self, _user = None, _minconf = None):
        """
        Get user's tip or withdraw balance
            _minconf is number of confirmations to consider
        Returns (float) balance
        """
        lg.debug("CtbCoin::getbalance(%s, %s)", _user, _minconf)

        user = self._verify_user(_user=_user)
        minconf = self._verify_minconf(_minconf=_minconf)
        balance = float(0)

        try:
            balance = self.conn.getbalance(user, minconf)
        except BitcoindException as e:
            lg.error("CtbCoin.getbalance(): error getting %s (minconf=%s) balance for %s: %s", self.conf['name'], minconf, user, str(e))
            raise

        return float(balance)

    def sendtouser(self, _userfrom = None, _userto = None, _amount = None, _minconf = 1):
        """
        Transfer (move) coins to user
        Returns (bool)
        """
        lg.debug("CtbCoin::sendtouser(%s, %s, %s)", _userfrom, _userto, _amount)

        userfrom = self._verify_user(_user=_userfrom)
        userto = self._verify_user(_user=_userto)
        amount = self._verify_amount(_amount=_amount)

        # send request to coin daemon
        try:
            lg.info("CtbCoin::sendtouser(): moving %s %s from %s to %s", amount, self.conf['name'], userfrom, userto)
            result = self.conn.move(userfrom, userto, amount)
            time.sleep(1)
        except Exception as e:
            lg.error("CtbCoin::sendtouser(): error sending %s %s from %s to %s: %s", amount, self.conf['name'], userfrom, userto, str(e))
            return False

        return True

    def sendtoaddr(self, _userfrom = None, _addrto = None, _amount = None):
        """
        Send coins to address
        Returns (string) txid
        """
        lg.debug("CtbCoin::sendtoaddr(%s, %s, %s)", _userfrom, _addrto, _amount)

        userfrom = self._verify_user(_user=_userfrom)
        addrto = self._verify_addr(_addr=_addrto)
        amount = self._verify_amount(_amount=_amount)
        minconf = self._verify_minconf(_minconf=self.conf['minconf']['withdraw'])
        txid = ""

        # send request to coin daemon
        try:
            lg.info("CtbCoin::sendtoaddr(): sending %s %s from %s to %s", amount, self.conf['name'], userfrom, addrto)

            # Unlock wallet, if applicable
            if self.conf.has_key('walletpassphrase'):
                lg.debug("CtbCoin::sendtoaddr(): unlocking wallet...")
                self.conn.walletpassphrase(self.conf['walletpassphrase'], 1)

            # Perform transaction
            lg.debug("CtbCoin::sendtoaddr(): calling sendfrom()...")
            txid = self.conn.sendfrom(userfrom, addrto, amount, minconf)

            # Lock wallet, if applicable
            if self.conf.has_key('walletpassphrase'):
                lg.debug("CtbCoin::sendtoaddr(): locking wallet...")
                self.conn.walletlock()

            time.sleep(1)

        except Exception as e:
            lg.error("CtbCoin::sendtoaddr(): error sending %s %s from %s to %s: %s", amount, self.conf['name'], userfrom, addrto, str(e))
            raise

        return str(txid)

    def validateaddr(self, _addr = None):
        """
        Verify that _addr is a valid coin address
        Returns (bool)
        """
        lg.debug("CtbCoin::validateaddr(%s)", _addr)

        addr = self._verify_addr(_addr=_addr)
        addr_valid = self.conn.validateaddress(addr)

        if not addr_valid.has_key('isvalid') or not addr_valid['isvalid']:
            lg.debug("CtbCoin::validateaddr(%s): not valid", addr)
            return False
        else:
            lg.debug("CtbCoin::validateaddr(%s): valid", addr)
            return True

    def getnewaddr(self, _user = None):
        """
        Generate a new address for _user
        Returns (string) address
        """

        user = self._verify_user(_user=_user)
        addr = ""

        try:
            # Unlock wallet for keypoolrefill
            if self.conf.has_key('walletpassphrase'):
                self.conn.walletpassphrase(self.conf['walletpassphrase'], 1)
            # Generate address foruser
            addr = self.conn.getnewaddress(user)
            # Lock wallet
            if self.conf.has_key('walletpassphrase'):
                self.conn.walletlock()
        except BitcoindException as e:
            lg.error("CtbCoin::getnewaddr(%s): error: %s", user, str(e))
            raise

        if not addr:
            raise Exception("CtbCoin::getnewaddr(%s): empty addr", user)

        return str(addr)

    def _verify_user(self, _user = None):
        """
        Verify and return a username
        """

        if not _user or not type(_user) in [str, unicode]:
            raise Exception("CtbCoin::_verify_user(): _user wrong type (%s) or empty (%s)", type(_user), _user)

        return str(_user.lower())

    def _verify_addr(self, _addr = None):
        """
        Verify and return coin address
        """

        if not _addr or not type(_addr) in [str, unicode]:
            raise Exception("CtbCoin::_verify_addr(): _addr wrong type (%s) or empty (%s)", type(_addr),_addr)

        return re.escape(str(_addr))

    def _verify_amount(self, _amount = None):
        """
        Verify and return amount
        """

        if not _amount or not type(_amount) in [int, float] or not _amount > 0:
            raise Exception("CtbCoin::_verify_amount(): _amount wrong type (%s), empty, or negative (%s)", type(_amount), _amount)

        return _amount

    def _verify_minconf(self, _minconf = None):
        """
        Verify and return minimum number of confirmations
        """

        if not _minconf or not type(_minconf) == int or not _minconf >= 0:
            raise Exception("CtbCoin::_verify_minconf(): _minconf wrong type (%s), empty, or negative (%s)", type(_minconf), _minconf)

        return _minconf
Exemple #10
0
class CtbCoin(object):
    """
    Coin class for cointip bot
    """

    conn = None
    conf = None

    def __init__(self, _conf = None):
        """
        Initialize CtbCoin with given parameters. _conf is a coin config dictionary defined in conf/coins.yml
        """

        # verify _conf is a config dictionary
        if not _conf or not hasattr(_conf, 'name') or not hasattr(_conf, 'config_file') or not hasattr(_conf, 'txfee'):
            raise Exception("CtbCoin::__init__(): _conf is empty or invalid")

        self.conf = _conf

        # connect to coin daemon
        try:
            lg.debug("CtbCoin::__init__(): connecting to %s...", self.conf.name)
            self.conn = Bitcoind(self.conf.config_file, rpcserver=self.conf.config_rpcserver)
        except BitcoindException as e:
            lg.error("CtbCoin::__init__(): error connecting to %s using %s: %s", self.conf.name, self.conf.config_file, e)
            raise

        lg.info("CtbCoin::__init__():: connected to %s", self.conf.name)
        time.sleep(0.5)

        # set transaction fee
        lg.info("Setting tx fee of %f", self.conf.txfee)
        self.conn.settxfee(self.conf.txfee)

    def getbalance(self, _user = None, _minconf = None):
        """
        Get user's tip or withdraw balance. _minconf is number of confirmations to use.
        Returns (float) balance
        """
        lg.debug("CtbCoin::getbalance(%s, %s)", _user, _minconf)

        user = self.verify_user(_user=_user)
        minconf = self.verify_minconf(_minconf=_minconf)
        balance = float(0)

        try:
            balance = self.conn.getbalance(user, minconf)
        except BitcoindException as e:
            lg.error("CtbCoin.getbalance(): error getting %s (minconf=%s) balance for %s: %s", self.conf.name, minconf, user, e)
            raise

        time.sleep(0.5)
        return float(balance)

    def sendtouser(self, _userfrom = None, _userto = None, _amount = None, _minconf = 1):
        """
        Transfer (move) coins to user
        Returns (bool)
        """
        lg.debug("CtbCoin::sendtouser(%s, %s, %s)", _userfrom, _userto, _amount)

        userfrom = self.verify_user(_user=_userfrom)
        userto = self.verify_user(_user=_userto)
        amount = self.verify_amount(_amount=_amount)

        # send request to coin daemon
        try:
            lg.info("CtbCoin::sendtouser(): moving %s %s from %s to %s", amount, self.conf.name, userfrom, userto)
            result = self.conn.move(userfrom, userto, amount)
            time.sleep(0.5)
        except Exception as e:
            lg.error("CtbCoin::sendtouser(): error sending %s %s from %s to %s: %s", amount, self.conf.name, userfrom, userto, e)
            return False

        time.sleep(0.5)
        return True

    def sendtoaddr(self, _userfrom = None, _addrto = None, _amount = None):
        """
        Send coins to address
        Returns (string) txid
        """
        lg.debug("CtbCoin::sendtoaddr(%s, %s, %s)", _userfrom, _addrto, _amount)

        userfrom = self.verify_user(_user=_userfrom)
        addrto = self.verify_addr(_addr=_addrto)
        amount = self.verify_amount(_amount=_amount)
        minconf = self.verify_minconf(_minconf=self.conf.minconf.withdraw)
        txid = ""

        # send request to coin daemon
        try:
            lg.info("CtbCoin::sendtoaddr(): sending %s %s from %s to %s", amount, self.conf.name, userfrom, addrto)

            # Unlock wallet, if applicable
            if hasattr(self.conf, 'walletpassphrase'):
                lg.debug("CtbCoin::sendtoaddr(): unlocking wallet...")
                self.conn.walletpassphrase(self.conf.walletpassphrase, 1)

            # Perform transaction
            lg.debug("CtbCoin::sendtoaddr(): calling sendfrom()...")
            txid = self.conn.sendfrom(userfrom, addrto, amount, minconf)

            # Lock wallet, if applicable
            if hasattr(self.conf, 'walletpassphrase'):
                lg.debug("CtbCoin::sendtoaddr(): locking wallet...")
                self.conn.walletlock()

        except Exception as e:
            lg.error("CtbCoin::sendtoaddr(): error sending %s %s from %s to %s: %s", amount, self.conf.name, userfrom, addrto, e)
            raise

        time.sleep(0.5)
        return str(txid)

    def validateaddr(self, _addr = None):
        """
        Verify that _addr is a valid coin address
        Returns (bool)
        """
        lg.debug("CtbCoin::validateaddr(%s)", _addr)

        addr = self.verify_addr(_addr=_addr)
        addr_valid = self.conn.validateaddress(addr)
        time.sleep(0.5)

        if not addr_valid.has_key('isvalid') or not addr_valid['isvalid']:
            lg.debug("CtbCoin::validateaddr(%s): not valid", addr)
            return False
        else:
            lg.debug("CtbCoin::validateaddr(%s): valid", addr)
            return True

    def getnewaddr(self, _user = None):
        """
        Generate a new address for _user
        Returns (string) address
        """

        user = self.verify_user(_user=_user)
        addr = ""
        counter = 0

        while True:
            try:
                # Unlock wallet for keypoolrefill
                if hasattr(self.conf, 'walletpassphrase'):
                    self.conn.walletpassphrase(self.conf.walletpassphrase, 1)

                # Generate new address
                addr = self.conn.getnewaddress(user)

                # Lock wallet
                if hasattr(self.conf, 'walletpassphrase'):
                    self.conn.walletlock()

                if not addr:
                    raise Exception("CtbCoin::getnewaddr(%s): empty addr", user)

                time.sleep(0.1)
                return str(addr)

            except BitcoindException as e:
                lg.error("CtbCoin::getnewaddr(%s): BitcoindException: %s", user, e)
                raise
            except CannotSendRequest as e:
                if counter < 3:
                    lg.warning("CtbCoin::getnewaddr(%s): CannotSendRequest, retrying")
                    counter += 1
                    time.sleep(10)
                    continue
                else:
                    raise
            except Exception as e:
                if str(e) == "timed out" and counter < 3:
                    lg.warning("CtbCoin::getnewaddr(%s): timed out, retrying")
                    counter += 1
                    time.sleep(10)
                    continue
                else:
                    lg.error("CtbCoin::getnewaddr(%s): Exception: %s", user, e)
                    raise


    def verify_user(self, _user = None):
        """
        Verify and return a username
        """

        if not _user or not type(_user) in [str, unicode]:
            raise Exception("CtbCoin::verify_user(): _user wrong type (%s) or empty (%s)", type(_user), _user)

        return str(_user.lower())

    def verify_addr(self, _addr = None):
        """
        Verify and return coin address
        """

        if not _addr or not type(_addr) in [str, unicode]:
            raise Exception("CtbCoin::verify_addr(): _addr wrong type (%s) or empty (%s)", type(_addr),_addr)

        return re.escape(str(_addr))

    def verify_amount(self, _amount = None):
        """
        Verify and return amount
        """

        if not _amount or not type(_amount) in [int, float] or not _amount > 0:
            raise Exception("CtbCoin::verify_amount(): _amount wrong type (%s), empty, or negative (%s)", type(_amount), _amount)

        return _amount

    def verify_minconf(self, _minconf = None):
        """
        Verify and return minimum number of confirmations
        """

        if not _minconf or not type(_minconf) == int or not _minconf >= 0:
            raise Exception("CtbCoin::verify_minconf(): _minconf wrong type (%s), empty, or negative (%s)", type(_minconf), _minconf)

        return _minconf
Exemple #11
0
class CtbCoin(object):
    """
    Coin class for cointip bot
    """

    conn = None
    conf = None

    def __init__(self, _conf=None):
        """
        Initialize CtbCoin with given parameters. _conf is a coin config dictionary defined in conf/coins.yml
        """

        # verify _conf is a config dictionary
        if (not _conf or not hasattr(_conf, "name")
                or not hasattr(_conf, "config_file")
                or not hasattr(_conf, "txfee")):
            raise Exception("CtbCoin::__init__(): _conf is empty or invalid")

        self.conf = _conf

        # connect to coin daemon
        try:
            lg.debug("CtbCoin::__init__(): connecting to %s...",
                     self.conf.name)
            self.conn = Bitcoind(self.conf.config_file,
                                 rpcserver=self.conf.config_rpcserver)
        except BitcoindException as e:
            lg.error(
                "CtbCoin::__init__(): error connecting to %s using %s: %s",
                self.conf.name,
                self.conf.config_file,
                e,
            )
            raise

        lg.info("CtbCoin::__init__():: connected to %s", self.conf.name)
        time.sleep(0.5)

        # set transaction fee
        lg.info("Setting tx fee of %f", self.conf.txfee)
        self.conn.settxfee(self.conf.txfee)

    def getbalance(self, _user=None, _minconf=None):
        """
        Get user's tip or withdraw balance. _minconf is number of confirmations to use.
        Returns (float) balance
        """
        lg.debug("CtbCoin::getbalance(%s, %s)", _user, _minconf)

        user = self.verify_user(_user=_user)
        minconf = self.verify_minconf(_minconf=_minconf)
        balance = float(0)

        try:
            balance = self.conn.getbalance(user, minconf)
        except BitcoindException as e:
            lg.error(
                "CtbCoin.getbalance(): error getting %s (minconf=%s) balance for %s: %s",
                self.conf.name,
                minconf,
                user,
                e,
            )
            raise

        time.sleep(0.5)
        return float(balance)

    def sendtouser(self,
                   _userfrom=None,
                   _userto=None,
                   _amount=None,
                   _minconf=1):
        """
        Transfer (move) coins to user
        Returns (bool)
        """
        lg.debug("CtbCoin::sendtouser(%s, %s, %s)", _userfrom, _userto,
                 _amount)

        userfrom = self.verify_user(_user=_userfrom)
        userto = self.verify_user(_user=_userto)
        amount = self.verify_amount(_amount=_amount)

        # send request to coin daemon
        try:
            lg.info(
                "CtbCoin::sendtouser(): moving %s %s from %s to %s",
                amount,
                self.conf.name,
                userfrom,
                userto,
            )
            self.conn.move(userfrom, userto, amount)
            time.sleep(0.5)
        except Exception as e:
            lg.error(
                "CtbCoin::sendtouser(): error sending %s %s from %s to %s: %s",
                amount,
                self.conf.name,
                userfrom,
                userto,
                e,
            )
            return False

        time.sleep(0.5)
        return True

    def sendtoaddr(self, _userfrom=None, _addrto=None, _amount=None):
        """
        Send coins to address
        Returns (string) txid
        """
        lg.debug("CtbCoin::sendtoaddr(%s, %s, %s)", _userfrom, _addrto,
                 _amount)

        userfrom = self.verify_user(_user=_userfrom)
        addrto = self.verify_addr(_addr=_addrto)
        amount = self.verify_amount(_amount=_amount)
        minconf = self.verify_minconf(_minconf=self.conf.minconf.withdraw)
        txid = ""

        # send request to coin daemon
        try:
            lg.info(
                "CtbCoin::sendtoaddr(): sending %s %s from %s to %s",
                amount,
                self.conf.name,
                userfrom,
                addrto,
            )

            # Unlock wallet, if applicable
            if hasattr(self.conf, "walletpassphrase"):
                lg.debug("CtbCoin::sendtoaddr(): unlocking wallet...")
                self.conn.walletpassphrase(self.conf.walletpassphrase, 1)

            # Perform transaction
            lg.debug("CtbCoin::sendtoaddr(): calling sendfrom()...")
            txid = self.conn.sendfrom(userfrom, addrto, amount, minconf)

            # Lock wallet, if applicable
            if hasattr(self.conf, "walletpassphrase"):
                lg.debug("CtbCoin::sendtoaddr(): locking wallet...")
                self.conn.walletlock()

        except Exception as e:
            lg.error(
                "CtbCoin::sendtoaddr(): error sending %s %s from %s to %s: %s",
                amount,
                self.conf.name,
                userfrom,
                addrto,
                e,
            )
            raise

        time.sleep(0.5)
        return str(txid)

    def validateaddr(self, _addr=None):
        """
        Verify that _addr is a valid coin address
        Returns (bool)
        """
        lg.debug("CtbCoin::validateaddr(%s)", _addr)

        addr = self.verify_addr(_addr=_addr)
        addr_valid = self.conn.validateaddress(addr)
        time.sleep(0.5)

        if "isvalid" not in addr_valid or not addr_valid["isvalid"]:
            lg.debug("CtbCoin::validateaddr(%s): not valid", addr)
            return False
        else:
            lg.debug("CtbCoin::validateaddr(%s): valid", addr)
            return True

    def getnewaddr(self, _user=None):
        """
        Generate a new address for _user
        Returns (string) address
        """

        user = self.verify_user(_user=_user)
        addr = ""
        counter = 0

        while True:
            try:
                # Unlock wallet for keypoolrefill
                if hasattr(self.conf, "walletpassphrase"):
                    self.conn.walletpassphrase(self.conf.walletpassphrase, 1)

                # Generate new address
                addr = self.conn.getnewaddress(user)

                # Lock wallet
                if hasattr(self.conf, "walletpassphrase"):
                    self.conn.walletlock()

                if not addr:
                    raise Exception("CtbCoin::getnewaddr(%s): empty addr",
                                    user)

                time.sleep(0.1)
                return str(addr)

            except BitcoindException as e:
                lg.error("CtbCoin::getnewaddr(%s): BitcoindException: %s",
                         user, e)
                raise
            except CannotSendRequest:
                if counter < 3:
                    lg.warning(
                        "CtbCoin::getnewaddr(%s): CannotSendRequest, retrying")
                    counter += 1
                    time.sleep(10)
                    continue
                else:
                    raise
            except Exception as e:
                if str(e) == "timed out" and counter < 3:
                    lg.warning("CtbCoin::getnewaddr(%s): timed out, retrying")
                    counter += 1
                    time.sleep(10)
                    continue
                else:
                    lg.error("CtbCoin::getnewaddr(%s): Exception: %s", user, e)
                    raise

    def verify_user(self, _user=None):
        """
        Verify and return a username
        """

        if not _user or not type(_user) in [str, unicode]:
            raise Exception(
                "CtbCoin::verify_user(): _user wrong type (%s) or empty (%s)",
                type(_user),
                _user,
            )

        return str(_user.lower())

    def verify_addr(self, _addr=None):
        """
        Verify and return coin address
        """

        if not _addr or not type(_addr) in [str, unicode]:
            raise Exception(
                "CtbCoin::verify_addr(): _addr wrong type (%s) or empty (%s)",
                type(_addr),
                _addr,
            )

        return re.escape(str(_addr))

    def verify_amount(self, _amount=None):
        """
        Verify and return amount
        """

        if not _amount or not type(_amount) in [int, float] or not _amount > 0:
            raise Exception(
                "CtbCoin::verify_amount(): _amount wrong type (%s), empty, or negative (%s)",
                type(_amount),
                _amount,
            )

        return _amount

    def verify_minconf(self, _minconf=None):
        """
        Verify and return minimum number of confirmations
        """

        if not _minconf or not type(_minconf) == int or not _minconf >= 0:
            raise Exception(
                "CtbCoin::verify_minconf(): _minconf wrong type (%s), empty, or negative (%s)",
                type(_minconf),
                _minconf,
            )

        return _minconf
Exemple #12
0
class CtbCoin(object):
    """
    Coin class for cointip bot
    """

    conn = None
    conf = None

    def __init__(self, _conf = None):
        """
        Initialize CtbCoin with given parameters. _conf is a coin config dictionary defined in conf/coins.yml
        """

        # verify _conf is a config dictionary
        if not _conf or not hasattr(_conf, 'name') or not hasattr(_conf, 'config_file') or not hasattr(_conf, 'txfee'):
            raise Exception("CtbCoin::__init__(): _conf is empty or invalid")

        self.conf = _conf

        # connect to coin daemon
        try:
            lg.debug("CtbCoin::__init__(): connecting to %s...", self.conf.name)
            self.conn = Bitcoind(self.conf.config_file, rpcserver=self.conf.config_rpcserver)
        except BitcoindException as e:
            lg.error("CtbCoin::__init__(): error connecting to %s using %s: %s", self.conf.name, self.conf.config_file, e)
            raise

        lg.info("CtbCoin::__init__():: connected to %s", self.conf.name)
        time.sleep(0.5)

        # set transaction fee
        lg.info("Setting tx fee of %f", self.conf.txfee)
        self.conn.settxfee(self.conf.txfee)

    def getbalance(self, _user = None, _minconf = None, _db = None):
        """
        Get user's tip or withdraw balance. _minconf is number of confirmations to use.
        Returns (float) balance
        """
        lg.debug("CtbCoin::getbalance(%s, %s)", _user, _minconf)

        user = self.verify_user(_user=_user)
        minconf = self.verify_minconf(_minconf=_minconf)
        balance = float(0)
        
        if _db == None:
            return balance

        #try:
        #    balance = self.conn.getbalance(user, minconf)
        #except BitcoindException as e:
        #    lg.error("CtbCoin.getbalance(): error getting %s (minconf=%s) balance for %s: %s", self.conf.name, minconf, user, e)
        #    raise
        
        #first get the received by account
        received = self.getreceivedbyaccount(_user=user, _minconf=minconf)
        #look up received in database
        sql = "SELECT * from t_addrs WHERE username = %s AND coin = %s"
        mysqlrow = _db.execute(sql, (user, self.conf.unit)).fetchone()
        if not mysqlrow:
            lg.debug("< CtbCoin::getbalance(%s, %s) DONE (no)", user, coin)
            return balance
        else:
            #get the balance from the database
            balance = ( received + mysqlrow['tips_received'] ) - ( mysqlrow['addr_sent'] + mysqlrow['tips_sent'])
            #update received and balance
            sql = "UPDATE t_addrs SET addr_received = %s, balance = %s WHERE username = %s AND coin = %s"
            _db.execute(sql, (received, balance, user, self.conf.unit))
            lg.debug("< CtbCoin::getbalance(%s) DONE", user)
            return float(balance)
        
        

        #time.sleep(0.5)
        #return float(balance)
        
    def getreceivedbyaccount(self, _user = None, _minconf = None):
        """
        Get user's tip or withdraw balance. _minconf is number of confirmations to use.
        Returns (float) balance
        """
        lg.debug("CtbCoin::getreceivedbyaccount(%s, %s)", _user, _minconf)

        user = self.verify_user(_user=_user)
        minconf = self.verify_minconf(_minconf=_minconf)
        received = float(0)

        try:
            received = self.conn.getreceivedbyaccount(user, minconf)
        except BitcoindException as e:
            lg.error("CtbCoin.getreceivedbyaccount(): error getting %s (minconf=%s) received for %s: %s", self.conf.name, minconf, user, e)
            raise

        time.sleep(0.5)
        return float(received)

    def sendtouser(self, _userfrom = None, _userto = None, _amount = None, _minconf = 1, _db = None):
        """
        Transfer (move) coins to user
        Returns (bool)
        """
        lg.debug("CtbCoin::sendtouser(%s, %s, %.9f)", _userfrom, _userto, _amount)

        userfrom = self.verify_user(_user=_userfrom)
        userto = self.verify_user(_user=_userto)
        amount = self.verify_amount(_amount=_amount)
        
        if _db == None:
            return False

        # dont bother with the coin daemon, we're doing the move in the db
        
        # send request to coin daemon
        #try:
        #    lg.info("CtbCoin::sendtouser(): moving %.9f %s from %s to %s", amount, self.conf.name, userfrom, userto)
        #    result = self.conn.move(userfrom, userto, amount)
        #    time.sleep(0.5)
        #except Exception as e:
        #    lg.error("CtbCoin::sendtouser(): error moving %.9f %s from %s to %s: %s", amount, self.conf.name, userfrom, userto, e)
        #    return False

        #subtract the amount from _userfrom in db
        sql = "SELECT * from t_addrs WHERE username = %s AND coin = %s"
        mysqlrow = _db.execute(sql, (userfrom, self.conf.unit)).fetchone()
        if not mysqlrow:
            lg.debug("< CtbCoin::sendtouser from(%s, %s) DONE (no)", userfrom, self.conf.unit)
            return None
        else:
            tipssent = mysqlrow['tips_sent']
            tipssent += amount
            balance = ( mysqlrow['addr_received'] + mysqlrow['tips_received'] ) - ( mysqlrow['addr_sent'] + tipssent )
            sql = "UPDATE t_addrs SET tips_sent = %s, balance = %s WHERE username = %s AND coin = %s"
            _db.execute(sql, (tipssent, balance, userfrom, self.conf.unit))           
            
        #add the ammount to _userto in db
        sql = "SELECT * from t_addrs WHERE username = %s AND coin = %s"
        mysqlrow = _db.execute(sql, (userto, self.conf.unit)).fetchone()
        if not mysqlrow:
            lg.debug("< CtbCoin::sendtouser to(%s, %s) DONE (no)", userto, self.conf.unit)
            return None
        else:
            tipsrec = mysqlrow['tips_received']
            tipsrec += amount
            balance = ( mysqlrow['addr_received'] + tipsrec ) - ( mysqlrow['addr_sent'] + mysqlrow['tips_sent'])
            sql = "UPDATE t_addrs SET tips_received = %s, balance = %s WHERE username = %s AND coin = %s"
            _db.execute(sql, (tipsrec, balance, userto, self.conf.unit))       

        return True

    def sendtoaddr(self, _userfrom = None, _addrto = None, _amount = None, _db = None):
        """
        Send coins to address
        Returns (string) txid
        """
        lg.debug("CtbCoin::sendtoaddr(%s, %s, %.9f)", _userfrom, _addrto, _amount)

        if _db == None:
            return False
        
        userfrom = self.verify_user(_user=_userfrom)
        addrto = self.verify_addr(_addr=_addrto)
        amount = self.verify_amount(_amount=_amount)
        minconf = self.verify_minconf(_minconf=self.conf.minconf.withdraw)
        txid = ""
        
        #TODO - add the withdrawn ammount to the addr_sent
        

        # send request to coin daemon
        try:
            lg.info("CtbCoin::sendtoaddr(): sending %.9f %s from %s to %s", amount, self.conf.name, userfrom, addrto)

            # Unlock wallet, if applicable
            if hasattr(self.conf, 'walletpassphrase'):
                lg.debug("CtbCoin::sendtoaddr(): unlocking wallet...")
                self.conn.walletpassphrase(self.conf.walletpassphrase, 10)
            
            # Perform transaction
            lg.debug("CtbCoin::sendtoaddr(): calling sendtoaddress()...")
            #txid = self.conn.sendfrom(userfrom, addrto, amount, minconf)
            txid = self.conn.sendtoaddress(addrto, amount)
            time.sleep(0.5)
            
            # Lock wallet, if applicable
            if hasattr(self.conf, 'walletpassphrase'):
                lg.debug("CtbCoin::sendtoaddr(): locking wallet...")
                self.conn.walletlock()
                time.sleep(0.5)
                
            #subtract the amount from _userfrom in db
            sql = "SELECT * from t_addrs WHERE username = %s AND coin = %s"
            mysqlrow = _db.execute(sql, (userfrom, self.conf.unit)).fetchone()
            if not mysqlrow:
                lg.debug("< CtbCoin::sendtoaddr from(%s, %s) DONE (no)", userfrom, self.conf.unit)
                return None
            else:
                addrsent = mysqlrow['addr_sent']
                addrsent += (amount + self.conf.txfee)
                balance = ( mysqlrow['addr_received'] + mysqlrow['tips_received'] ) - ( addrsent + mysqlrow['tips_sent'])
                sql = "UPDATE t_addrs SET addr_sent = %s, balance = %s WHERE username = %s AND coin = %s"
                _db.execute(sql, (addrsent, balance, userfrom, self.conf.unit))      
                
                
        except Exception as e:
            lg.error("CtbCoin::sendtoaddr(): error sending %.9f %s from %s to %s: %s", amount, self.conf.name, userfrom, addrto, e)
            raise

        time.sleep(0.5)
        return str(txid)

    def validateaddr(self, _addr = None):
        """
        Verify that _addr is a valid coin address
        Returns (bool)
        """
        lg.debug("CtbCoin::validateaddr(%s)", _addr)

        addr = self.verify_addr(_addr=_addr)
        addr_valid = self.conn.validateaddress(addr)
        time.sleep(0.5)

        if not addr_valid.has_key('isvalid') or not addr_valid['isvalid']:
            lg.debug("CtbCoin::validateaddr(%s): not valid", addr)
            return False
        else:
            lg.debug("CtbCoin::validateaddr(%s): valid", addr)
            return True

    def getnewaddr(self, _user = None):
        """
        Generate a new address for _user
        Returns (string) address
        """

        user = self.verify_user(_user=_user)
        addr = ""
        counter = 0

        while True:
            try:
                # Unlock wallet for keypoolrefill
                if hasattr(self.conf, 'walletpassphrase'):
                    self.conn.walletpassphrase(self.conf.walletpassphrase, 1)

                # Generate new address
                addr = self.conn.getnewaddress(user)

                # Lock wallet
                if hasattr(self.conf, 'walletpassphrase'):
                    self.conn.walletlock()

                if not addr:
                    raise Exception("CtbCoin::getnewaddr(%s): empty addr", user)

                time.sleep(0.1)
                return str(addr)

            except BitcoindException as e:
                lg.error("CtbCoin::getnewaddr(%s): BitcoindException: %s", user, e)
                raise
            except CannotSendRequest as e:
                if counter < 3:
                    lg.warning("CtbCoin::getnewaddr(%s): CannotSendRequest, retrying")
                    counter += 1
                    time.sleep(10)
                    continue
                else:
                    raise
            except Exception as e:
                if str(e) == "timed out" and counter < 3:
                    lg.warning("CtbCoin::getnewaddr(%s): timed out, retrying")
                    counter += 1
                    time.sleep(10)
                    continue
                else:
                    lg.error("CtbCoin::getnewaddr(%s): Exception: %s", user, e)
                    raise


    def verify_user(self, _user = None):
        """
        Verify and return a username
        """

        if not _user or not type(_user) in [str, unicode]:
            raise Exception("CtbCoin::verify_user(): _user wrong type (%s) or empty (%s)", type(_user), _user)

        return str(_user.lower())

    def verify_addr(self, _addr = None):
        """
        Verify and return coin address
        """

        if not _addr or not type(_addr) in [str, unicode]:
            raise Exception("CtbCoin::verify_addr(): _addr wrong type (%s) or empty (%s)", type(_addr),_addr)

        return re.escape(str(_addr))

    def verify_amount(self, _amount = None):
        """
        Verify and return amount
        """

        if not _amount or not type(_amount) in [int, float] or not _amount > 0:
            raise Exception("CtbCoin::verify_amount(): _amount wrong type (%s), empty, or negative (%s)", type(_amount), _amount)

        return _amount

    def verify_minconf(self, _minconf = None):
        """
        Verify and return minimum number of confirmations
        """

        if not _minconf or not type(_minconf) == int or not _minconf >= 0:
            raise Exception("CtbCoin::verify_minconf(): _minconf wrong type (%s), empty, or negative (%s)", type(_minconf), _minconf)

        return _minconf