Exemplo n.º 1
0
class CoinWallet(object):
    '''
    Class for a wallet
    '''
    def __init__(self, wallet_config):
        self._errors = []
        self._config = {}
        self._cache = Cacher({
            'accounts': {},
            'transactions': {},
            'transactiondetails': {},
            'balances': {},
            'info': {},
        })

        if type(wallet_config) is dict:
            self._config = wallet_config

    @property
    def provider_id(self):
        '''
        Property for the provider id
        '''
        return self.get('id', None)

    @property
    def enabled(self):
        '''
        Return the status (enabled/disabled)
        '''
        return self.get('enabled', False)

    def __getitem__(self, key):
        '''
        Getter for dictionary-line behavior
        '''
        if key == "currency_symbol":
            return self.getCurrencySymbol()
        elif key == "currency_code":
            return self.getCurrencyCode()

        config = getattr(self, '_config')
        return config[key]

    def __setitem__(self, key, value):
        '''
        Setter for dictionary-line behavior
        '''
        config = getattr(self, '_config')
        config[key] = value
        return setattr(self, '_config', config)

    def get(self, key, default=False):
        '''
        Implementing .get() method for dictionary-line behavior
        '''
        if self._config.get(key, False):
            return self._config.get(key, False)
        else:
            return default

    def haskey(self, key):
        '''
        Check the existence of key
        '''
        if key in self._config.keys():
            return True
        else:
            return False

    def getNet(self):
        '''
        Return network value, mainnet or testnet
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("provider_id=%s" % self.provider_id)
        cached_peerinfo = self._cache.fetch('info', cache_hash)
        if cached_peerinfo:
            info = cached_peerinfo
        else:
            info = connector.getInfo(self.provider_id)
            self._cache.store('info', cache_hash, info)

        is_testnet = False
        if info.has_key('testnet'):
            is_testnet = info.get('testnet')
            if is_testnet is False:
                return "mainnet"
            elif is_testnet is True:
                return "testnet"
        else:
            # default to mainnet
            return "mainnet"

    def balance(self):
        '''
        Get wallet balance
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("balance")
        cached_object = self._cache.fetch('balance', cache_hash)
        if cached_object:
            return cached_object.get(self.provider_id, "-")

        balance = connector.getBalance(self.provider_id)

        # store result in cache
        self._cache.store('balance', cache_hash, balance)

        return misc.longNumber(balance.get(self.provider_id, "-"))

    def getParamHash(self, param=""):
        '''
        This function takes a string and calculates a sha224 hash out of it. 
        It is used to hash the input parameters of functions/method in order to 
        uniquely identify a cached result based  only on the input parameters of 
        the function/method call.
        '''
        cache_hash = hashlib.sha224(param).hexdigest()
        return cache_hash

    def listAccounts(self, gethidden=False, getarchived=False):
        '''
        Get a list of accounts. This method also supports filtering, fetches address for each account etc.
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("gethidden=%s&getarchived=%s" %
                                       (gethidden, getarchived))
        cached_object = self._cache.fetch('accounts', cache_hash)
        if cached_object:
            return cached_object

        # get data from the connector (xxxcoind)
        fresh_accounts = connector.listAccounts(
            gethidden=False,
            getarchived=False,
            selected_provider_id=self.provider_id)

        # get a list of archived address
        address_ignore_list = []
        if not getarchived:
            ignore_list = accountFilter.objects.filter(status=1)
            for ignored_account in ignore_list:
                address_ignore_list.append(
                    ignored_account.address.encode('ascii'))

        # get a list of hidden accounts
        address_hidden_list = []
        if not gethidden:
            hidden_list = accountFilter.objects.filter(status=2)
            for hidden_account in hidden_list:
                address_hidden_list.append(
                    hidden_account.address.encode('ascii'))

        accountObjects = []
        for account_name, account_balance in fresh_accounts.get(
                self.provider_id, {}).items():
            '''
            # check all addresses if they are in the archive list
            for ignored_address in address_ignore_list:
                if ignored_address in account_addresses:
                    del account_addresses[account_addresses.index(ignored_address)]
            
            # check all addresses if they are in the hidden list
            hidden_flag = False
            for hidden_address in address_hidden_list:
                if hidden_address in account_addresses:
                    hidden_flag = True
            '''

            accountObjects.append(
                CoinAccount({
                    'name': account_name,
                    'balance': account_balance,
                    'currency': self['currency'],
                    'provider_id': self.provider_id,
                    'wallet': self,
                }))

        # cache the result
        self._cache.store('accounts', cache_hash, accountObjects)
        return accountObjects

    def getCurrencySymbol(self):
        '''
        Return the Unicode currency symbol
        '''
        return self.get('symbol', None)

    def getCurrencyCode(self):
        '''
        Return the currency code
        '''
        return self.get('currency', "").lower()

    def listTransactions(self, limit=10, start=0):
        '''
        Return a list of transactions wallet-wide
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("limit=%s&start=%s" % (limit, start))
        cached_object = self._cache.fetch('transactions', cache_hash)
        if cached_object:
            return cached_object

        transactions = []
        transactions_dicts = connector.listTransactionsByAccount(
            "*", self.provider_id, limit, start)
        for transaction in transactions_dicts:
            transaction['wallet'] = self
            transaction['currency'] = self.getCurrencyCode()
            transaction['currency_symbol'] = self.getCurrencySymbol()
            transaction['provider_id'] = self.provider_id
            transactions.append(CoinTransaction(transaction))

        self._cache.store('transactions', cache_hash, transactions)
        return transactions

    def getAccountByName(self, name):
        '''
        Return CoinAccount() for name
        '''
        accounts = self.listAccounts(gethidden=True, getarchived=True)
        for account in accounts:
            if account['name'] == name:
                return account

        return None

    def getTransactionById(self, txid):
        '''
        Return a transaction by txid
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("txid=%s" % (txid))
        cached_object = self._cache.fetch('transactiondetails', cache_hash)
        if cached_object:
            return cached_object

        transaction_details = connector.getTransaction(txid, self.provider_id)
        transaction_details['currency'] = self.getCurrencyCode()
        transaction_details['wallet'] = self

        self._cache.store('transactiondetails', cache_hash,
                          transaction_details)
        return CoinTransaction(transaction_details)

    def getAddressesByAccount(self, account):
        '''
        Get a list of address for account
        '''
        addresses_list = connector.getAddressesByAccount(
            account, self.provider_id)
        coinaddresses = []
        for address in addresses_list:
            coinaddresses.append(CoinAddress(address, account))

        return coinaddresses

    def getDefaultAccount(self):
        '''
        Return the CoinAccount object for the default wallet account
        '''
        accounts = self.listAccounts(gethidden=True, getarchived=True)
        for account in accounts:
            if len(account['name']) == 0:
                return account
        else:
            return None

    def getAccountByAddress(self, address):
        '''
        Return account by address
        '''
        accounts = self.listAccounts(gethidden=True, getarchived=True)

        target_account = None
        for account in accounts:
            for account_address in account['addresses']:
                if str(address) == str(account_address):
                    target_account = account
                    target_account['currency'] = self.getCurrencyCode()
                    target_account['provider_id'] = self.provider_id
                    return target_account
        else:
            return None

    def getAccountByIdentifier(self, identifier):
        '''
        Get account by identifier
        '''
        list_of_accounts = self.listAccounts(gethidden=True, getarchived=True)
        for account in list_of_accounts:
            if account.getIdentifier() == identifier:
                return account
        else:
            return None
Exemplo n.º 2
0
class CoinAccount(object):
    '''
    Class for an account
    '''
    def __init__(self, accountDetails):
        self._errors = []
        self._account = {}
        self._hidden = False
        self._cache = Cacher({
            'transactions': {},
            'balances': {},
            'addressesbyaccount': {},
        })

        if type(accountDetails) is dict:
            self._account = accountDetails
            self._provider_id = accountDetails['provider_id']

    @property
    def provider_id(self):
        '''
        Property for the provider id
        '''
        return self.get('provider_id', None)

    def __getitem__(self, key):
        '''
        Getter for dictionary-line behavior
        '''

        if key == "addresses":
            return self.getAddresses()
        elif key == "last_activity":
            return self.getLastActivity()
        elif key == "currency_symbol":
            return self.getCurrencySymbol()
        elif key == "currency_code":
            return self.getCurrencyCode()
        elif key == 'identifier':
            return self.getIdentifier()

        account = getattr(self, '_account')
        return account.get(key, None)

    def __setitem__(self, key, value):
        '''
        Setter for dictionary-line behavior
        '''
        account = getattr(self, '_account')
        account[key] = value
        return setattr(self, '_account', account)

    def get(self, key, default=False):
        '''
        Getter for dictionary-line behavior
        '''
        if self._account.get(key, False):
            return self._account.get(key, False)
        else:
            return default

    def haskey(self, key):
        '''
        Check the existence of key
        '''
        if key in self._account.keys():
            return True
        else:
            return False

    def getParamHash(self, param=""):
        '''
        This function takes a string and calculates a sha224 hash out of it. 
        It is used to hash the input parameters of functions/method in order to 
        uniquely identify a cached result based  only on the input parameters of 
        the function/method call.
        '''
        cache_hash = hashlib.sha224(param).hexdigest()
        return cache_hash

    def getIdentifier(self):
        '''
        There is no unique identifier for an account in a xxxcoind daemon
        so lets make one. Hopefully the below hashing method will uniquely 
        identify an account for us
        '''
        unique_string = "provider_id=%s&name=%s&currency=%s" % (
            self['provider_id'], self['name'], self['currency'])
        identifier = hashlib.sha1(unique_string).hexdigest()
        return identifier

    def isDefault(self):
        '''
        Return bool whether this is a default account or not
        '''
        if self._account['name'] == u"":
            self._hidden = True
            return True
        else:
            return False

    def getBalance(self):
        '''
        Return the account balance
        '''
        balance = connector.getBalance(self.provider_id, self['name'])
        return misc.longNumber(balance)

    def isHidden(self):
        '''
        Return bool if this account is hidden
        '''
        return self._hidden or self._account['hidden'] or self.isDefault()

    def getAddresses(self):
        '''
        Get the address for an account name
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("name=%s" % (self['name']))
        cached_object = self._cache.fetch('addressesbyaccount', cache_hash)
        if cached_object:
            return cached_object

        addresses = connector.getAddressesByAccount(self['name'],
                                                    self.provider_id)
        addresses_list = []
        for address in addresses:
            coinaddr = CoinAddress(address, self)
            addresses_list.append(coinaddr)

        # cache the result
        self._cache.store('addressesbyaccount', cache_hash, addresses_list)
        return addresses_list

    def getAddressesCount(self):
        '''
        Return the number of address under this account
        '''
        addresses = self.getAddresses()
        return len(addresses)

    def getLastActivity(self):
        '''
        Return the date of the last activity
        '''
        last_transaction = self.listTransactions(1, 0)
        if last_transaction:
            last_activity = misc.twitterizeDate(last_transaction[0]['time'])
        else:
            last_activity = "never"

        self['last_activity'] = last_activity
        return last_activity

    def getCurrencySymbol(self):
        '''
        Return the Unicode currency symbol
        '''
        return misc.getCurrencySymbol(connector, self.getCurrencyCode())

    def getCurrencyCode(self):
        '''
        Return the currency code
        '''
        return self.get('currency', "").lower()

    def listTransactions(self,
                         limit=100000,
                         start=0,
                         orderby='time',
                         reverse=True):
        '''
        Get a list of transactions by account name and provider_id
        '''

        cache_hash = self.getParamHash(
            "limit=%s&start=%sorderby=%s&reverse=%s" %
            (limit, start, orderby, reverse))
        cached_object = self._cache.fetch('transactions', cache_hash)
        if cached_object:
            return cached_object

        transactions = []
        transaction_list = connector.listTransactionsByAccount(
            self['name'], self['provider_id'], limit, start)

        for entry in transaction_list:
            if entry.get('address', False):
                entry['address'] = CoinAddress(entry['address'], self)

            # give out a provider id and a currency code to the transaction dict
            entry['provider_id'] = self.provider_id
            entry['currency'] = self['currency']

            if entry['category'] == 'receive':
                entry['source_address'] = CoinAddress(
                    entry.get('details', {}).get('sender_address', False),
                    "This is a sender address!")
            elif entry['category'] == 'send':
                entry['source_addresses'] = self[
                    'wallet'].getAddressesByAccount(entry['account'])

            entry['wallet'] = self['wallet']

            coin_transaction = CoinTransaction(entry)
            transactions.append(coin_transaction)

        # sort result
        transactions = sorted(transactions,
                              key=lambda transaction: transaction[orderby],
                              reverse=reverse)

        # cache the result
        self._cache.store('transactions', cache_hash, transactions)
        return transactions
Exemplo n.º 3
0
class CoinTransaction(object):
    '''
    Class for a transaction
    '''
    
    # source: https://github.com/zamgo/PHPCoinAddress/blob/master/README.md
    prefixes = {
                'btc': {'mainnet': '\x00', 'testnet': '\x6f'},
                'ltc': {'mainnet': '\x30', 'testnet': '\x6f'},
                'ftc': {'mainnet': '\x0E', 'testnet': '\x6f'},
                'ppc': {'mainnet': '\x37', 'testnet': '\x6f'},
                'nmc': {'mainnet': '\x34', 'testnet': '\x6f'},
                'nvc': {'mainnet': '\x08', 'testnet': '\x6f'},
                'doge': {'mainnet': '\x30', 'testnet': '\x6f'},
               }
    
    def __init__(self, transactionDetails):
        self._transaction = {}
        self. _cache = Cacher({
                     'details': {},
                     })
        
        if type(transactionDetails) is dict:
            self._transaction = transactionDetails
            
            self['timereceived_pretty'] = misc.twitterizeDate(self.get('timereceived', 'never'))
            self['time_pretty'] = misc.twitterizeDate(self.get('time', 'never'))
            self['timereceived_human'] = datetime.datetime.fromtimestamp(self.get('timereceived', 0))
            self['time_human'] = datetime.datetime.fromtimestamp(self.get('time', 0))
            self['blocktime_human'] = datetime.datetime.fromtimestamp(self.get('blocktime', 0))
            self['blocktime_pretty'] = misc.twitterizeDate(self.get('blocktime', 'never'))
            self['currency_symbol'] = misc.getCurrencySymbol(connector, self['currency'])
            
            if self.get('category', False) in ['receive', 'send']:
                if self['confirmations'] <= MainConfig['globals']['confirmation_limit']:
                    self['status_icon'] = 'glyphicon-time'
                    self['status_color'] = '#AAA';
                    self['tooltip'] = self['confirmations']
                else:
                    self['status_icon'] = 'glyphicon-ok-circle'
                    self['status_color'] = '#1C9E3F';
                    self['tooltip'] = self['confirmations']
            
            accountObject = self['wallet'].getAccountByName(self['account'])
            self['account'] = accountObject
            
            if self['category'] == 'receive':
                self['icon'] = 'glyphicon-circle-arrow-down'
            elif self['category'] == 'send':
                self['icon'] = 'glyphicon-circle-arrow-up'
            elif self['category'] == 'move':
                self['icon'] = 'glyphicon-circle-arrow-right'
                self['otheraccount'] = self['wallet'].getAccountByName(self['otheraccount'])
            
    def __getitem__(self, key):
        '''
        Getter for dictionary-line behavior
        '''
        if key == "account":
            if self.haskey("account"):
                return self._transaction['account']
            else:
                return self._transaction['details'][0]['account']
        elif key == "category":
            if self.haskey("category"):
                return self._transaction['category']
            else:
                return self._transaction['details'][0]['category']
        elif key == "currency_symbol":
            return self.getCurrencySymbol()
        elif key == "currency_code":
            return self.getCurrencyCode()
        elif key == "raw_transaction":
            return self.getRawTransaction()
        elif key == "source_address":
            return self.getSenderAddress()
        elif key == "address":
            return CoinAddress(self._transaction['address'], self._transaction['account'])
        
        transaction = getattr(self, '_transaction')
        return transaction.get(key, None)
     
    def __setitem__(self, key, value):
        '''
        Setter for dictionary-line behavior
        '''
        transaction = getattr(self, '_transaction')
        transaction[key] = value
        return setattr(self, '_transaction', transaction)
    
    def get(self, key, default=False):
        '''
        get() method for dictionary-line behavior
        '''
        if self._transaction.get(key, False):
            return self._transaction.get(key, False)
        else:
            return default
        
    def haskey(self, key):
        '''
        Check the existence of key
        '''
        if key in self._transaction.keys():
            return True
        else:
            return False
        
    @property
    def provider_id(self):
        '''
        Property for the provider id
        '''
        return self.get('provider_id', None)
    
    @property
    def transaction_id(self):
        '''
        Property for the txid
        '''
        return self.get('txid', None)
    
    @property
    def txid(self):
        '''
        Property for the txid
        '''
        return self.get('txid', None)
    
    def getParamHash(self, param=""):
        '''
        This function takes a string and calculates a sha224 hash out of it. 
        It is used to hash the input parameters of functions/method in order to 
        uniquely identify a cached result based  only on the input parameters of 
        the function/method call.
        '''
        cache_hash = hashlib.sha224(param).hexdigest()
        return cache_hash
    
    def metaProperties(self):
        '''
        Return transaction details, like sender address
        '''
        raw_transaction = self.getRawTransaction()
        
        if self['category'] == 'receive':
            sender_address = self.decodeScriptSig(raw_transaction, self['currency'], self['wallet'].getNet())
        else:
            sender_address = None
            
        return {'sender_address': sender_address}
    
    def getRawTransaction(self):
        '''
        Get the raw transaction dict
        '''
        cache_hash = self.getParamHash("details")
        cached_object = self._cache.fetch('details', cache_hash)
        if cached_object:
            raw_transaction = cached_object
        else:
            raw_transaction = connector.getRawTransaction(self['txid'], self['wallet']['provider_id'])
            self._cache.store('details', cache_hash, raw_transaction)
        return raw_transaction

    def getSenderAddress(self):
        '''
        Getter function for the sender address
        '''
        if self['category'] == 'receive':
            meta_properties = self.metaProperties()
            if meta_properties.get('sender_address', False):
                return CoinAddress(meta_properties['sender_address'], 'This is a sender address!')
            
        return None

    def decodeScriptSig(self, rawtransaction, currency, net='testnet'):
        '''
        Decode input script signature, courtesy of:
        http://bitcoin.stackexchange.com/questions/7838/why-does-gettransaction-report-me-only-the-receiving-address/8864#8864
        '''
        try:
            script_sig = rawtransaction['vin'][0]['scriptSig']['asm']
        except:
            return "not enough info"
        
        script = script_sig.split()
        
        h = hashlib.sha256(script[1].decode("hex")).digest()
        ripe160 = hashlib.new('ripemd160')
        ripe160.update(h)
        d = ripe160.digest()
        
        prefix = self.prefixes[currency.lower()][net]
        address = (prefix + d)
        
        # calculate checksum
        checksum = hashlib.sha256(hashlib.sha256(address).digest()).digest()[:4]
        
        # build the raw address
        address += checksum
        
        # encode the address in base58
        encoded_address = misc.b58encode(address)
        
        return encoded_address

    def getCurrencySymbol(self):
        '''
        Return the Unicode currency symbol
        '''
        return misc.getCurrencySymbol(connector, self.getCurrencyCode())
    
    def getCurrencyCode(self):
        '''
        Return the currency code
        '''
        return self.get('currency', "").lower()
Exemplo n.º 4
0
class CoinAccount(object):
    '''
    Class for an account
    '''
    
    def __init__(self, accountDetails):
        self._errors = []
        self._account = {}
        self._hidden = False
        self._cache = Cacher({
         'transactions': {},
         'balances': {},
         'addressesbyaccount': {},
         })
        
        if type(accountDetails) is dict:
            self._account = accountDetails
            self._provider_id = accountDetails['provider_id']
            
    @property
    def provider_id(self):
        '''
        Property for the provider id
        '''
        return self.get('provider_id', None)
           
    def __getitem__(self, key):
        '''
        Getter for dictionary-line behavior
        '''

        if key == "addresses":
            return self.getAddresses()
        elif key == "last_activity":
            return self.getLastActivity()
        elif key == "currency_symbol":
            return self.getCurrencySymbol()
        elif key == "currency_code":
            return self.getCurrencyCode()
        elif key == 'identifier':
            return self.getIdentifier()

        account = getattr(self, '_account')
        return account.get(key, None)
     
    def __setitem__(self, key, value):
        '''
        Setter for dictionary-line behavior
        '''
        account = getattr(self, '_account')
        account[key] = value
        return setattr(self, '_account', account)
    
    def get(self, key, default=False):
        '''
        Getter for dictionary-line behavior
        '''
        if self._account.get(key, False):
            return self._account.get(key, False)
        else:
            return default
        
    def haskey(self, key):
        '''
        Check the existence of key
        '''
        if key in self._account.keys():
            return True
        else:
            return False
    
    def getParamHash(self, param=""):
        '''
        This function takes a string and calculates a sha224 hash out of it. 
        It is used to hash the input parameters of functions/method in order to 
        uniquely identify a cached result based  only on the input parameters of 
        the function/method call.
        '''
        cache_hash = hashlib.sha224(param).hexdigest()
        return cache_hash
    
    def getIdentifier(self):
        '''
        There is no unique identifier for an account in a xxxcoind daemon
        so lets make one. Hopefully the below hashing method will uniquely 
        identify an account for us
        '''
        unique_string = "provider_id=%s&name=%s&currency=%s" % (self['provider_id'], self['name'], self['currency'])
        identifier = hashlib.sha1(unique_string).hexdigest()
        return identifier
        
    def isDefault(self):
        '''
        Return bool whether this is a default account or not
        '''
        if self._account['name'] == u"":
            self._hidden = True
            return True
        else:
            return False
    
    def getBalance(self):
        '''
        Return the account balance
        '''
        balance = connector.getBalance(self.provider_id, self['name'])
        return misc.longNumber(balance)
    
    def isHidden(self):
        '''
        Return bool if this account is hidden
        '''
        return self._hidden or self._account['hidden'] or self.isDefault()
    
    def getAddresses(self):
        '''
        Get the address for an account name
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("name=%s" % (self['name']))
        cached_object = self._cache.fetch('addressesbyaccount', cache_hash)
        if cached_object:
            return cached_object
        
        addresses = connector.getAddressesByAccount(self['name'], self.provider_id)
        addresses_list = []
        for address in addresses:
            coinaddr = CoinAddress(address, self)
            addresses_list.append(coinaddr)
            
        # cache the result
        self._cache.store('addressesbyaccount', cache_hash, addresses_list)
        return addresses_list
    
    def getAddressesCount(self):
        '''
        Return the number of address under this account
        '''
        addresses = self.getAddresses()
        return len(addresses)
    
    def getLastActivity(self):
        '''
        Return the date of the last activity
        '''
        last_transaction = self.listTransactions(1, 0)
        if last_transaction:
            last_activity = misc.twitterizeDate(last_transaction[0]['time'])
        else:
            last_activity = "never"
            
        self['last_activity'] = last_activity
        return last_activity
    
    def getCurrencySymbol(self):
        '''
        Return the Unicode currency symbol
        '''
        return misc.getCurrencySymbol(connector, self.getCurrencyCode())
    
    def getCurrencyCode(self):
        '''
        Return the currency code
        '''
        return self.get('currency', "").lower()
    
    def listTransactions(self, limit=100000, start=0, orderby='time', reverse=True):    
        '''
        Get a list of transactions by account name and provider_id
        '''

        cache_hash = self.getParamHash("limit=%s&start=%sorderby=%s&reverse=%s" % (limit, start, orderby, reverse))
        cached_object = self._cache.fetch('transactions', cache_hash)
        if cached_object:
            return cached_object
        
        transactions = []
        transaction_list = connector.listTransactionsByAccount(self['name'], self['provider_id'], limit, start)
        
        for entry in transaction_list:
            if entry.get('address', False):
                entry['address'] = CoinAddress(entry['address'], self)
            
            # give out a provider id and a currency code to the transaction dict
            entry['provider_id'] = self.provider_id
            entry['currency'] = self['currency']
            
            if entry['category'] == 'receive':
                entry['source_address'] = CoinAddress(entry.get('details', {}).get('sender_address', False), "This is a sender address!")
            elif entry['category'] == 'send':
                entry['source_addresses'] = self['wallet'].getAddressesByAccount(entry['account'])
            
            entry['wallet'] = self['wallet']
            
            coin_transaction = CoinTransaction(entry)
            transactions.append(coin_transaction)
            
        # sort result
        transactions = sorted(transactions, key=lambda transaction: transaction[orderby], reverse=reverse) 
            
        # cache the result
        self._cache.store('transactions', cache_hash, transactions)
        return transactions
Exemplo n.º 5
0
class CoinTransaction(object):
    '''
    Class for a transaction
    '''

    # source: https://github.com/zamgo/PHPCoinAddress/blob/master/README.md
    prefixes = {
        'btc': {
            'mainnet': '\x00',
            'testnet': '\x6f'
        },
        'ltc': {
            'mainnet': '\x30',
            'testnet': '\x6f'
        },
        'ftc': {
            'mainnet': '\x0E',
            'testnet': '\x6f'
        },
        'ppc': {
            'mainnet': '\x37',
            'testnet': '\x6f'
        },
        'nmc': {
            'mainnet': '\x34',
            'testnet': '\x6f'
        },
        'nvc': {
            'mainnet': '\x08',
            'testnet': '\x6f'
        },
        'doge': {
            'mainnet': '\x30',
            'testnet': '\x6f'
        },
    }

    def __init__(self, transactionDetails):
        self._transaction = {}
        self._cache = Cacher({
            'details': {},
        })

        if type(transactionDetails) is dict:
            self._transaction = transactionDetails

            self['timereceived_pretty'] = misc.twitterizeDate(
                self.get('timereceived', 'never'))
            self['time_pretty'] = misc.twitterizeDate(self.get(
                'time', 'never'))
            self['timereceived_human'] = datetime.datetime.fromtimestamp(
                self.get('timereceived', 0))
            self['time_human'] = datetime.datetime.fromtimestamp(
                self.get('time', 0))
            self['blocktime_human'] = datetime.datetime.fromtimestamp(
                self.get('blocktime', 0))
            self['blocktime_pretty'] = misc.twitterizeDate(
                self.get('blocktime', 'never'))
            self['currency_symbol'] = misc.getCurrencySymbol(
                connector, self['currency'])

            if self.get('category', False) in ['receive', 'send']:
                if self['confirmations'] <= MainConfig['globals'][
                        'confirmation_limit']:
                    self['status_icon'] = 'glyphicon-time'
                    self['status_color'] = '#AAA'
                    self['tooltip'] = self['confirmations']
                else:
                    self['status_icon'] = 'glyphicon-ok-circle'
                    self['status_color'] = '#1C9E3F'
                    self['tooltip'] = self['confirmations']

            accountObject = self['wallet'].getAccountByName(self['account'])
            self['account'] = accountObject

            if self['category'] == 'receive':
                self['icon'] = 'glyphicon-circle-arrow-down'
            elif self['category'] == 'send':
                self['icon'] = 'glyphicon-circle-arrow-up'
            elif self['category'] == 'move':
                self['icon'] = 'glyphicon-circle-arrow-right'
                self['otheraccount'] = self['wallet'].getAccountByName(
                    self['otheraccount'])

    def __getitem__(self, key):
        '''
        Getter for dictionary-line behavior
        '''
        if key == "account":
            if self.haskey("account"):
                return self._transaction['account']
            else:
                return self._transaction['details'][0]['account']
        elif key == "category":
            if self.haskey("category"):
                return self._transaction['category']
            else:
                return self._transaction['details'][0]['category']
        elif key == "currency_symbol":
            return self.getCurrencySymbol()
        elif key == "currency_code":
            return self.getCurrencyCode()
        elif key == "raw_transaction":
            return self.getRawTransaction()
        elif key == "source_address":
            return self.getSenderAddress()
        elif key == "address":
            return CoinAddress(self._transaction['address'],
                               self._transaction['account'])

        transaction = getattr(self, '_transaction')
        return transaction.get(key, None)

    def __setitem__(self, key, value):
        '''
        Setter for dictionary-line behavior
        '''
        transaction = getattr(self, '_transaction')
        transaction[key] = value
        return setattr(self, '_transaction', transaction)

    def get(self, key, default=False):
        '''
        get() method for dictionary-line behavior
        '''
        if self._transaction.get(key, False):
            return self._transaction.get(key, False)
        else:
            return default

    def haskey(self, key):
        '''
        Check the existence of key
        '''
        if key in self._transaction.keys():
            return True
        else:
            return False

    @property
    def provider_id(self):
        '''
        Property for the provider id
        '''
        return self.get('provider_id', None)

    @property
    def transaction_id(self):
        '''
        Property for the txid
        '''
        return self.get('txid', None)

    @property
    def txid(self):
        '''
        Property for the txid
        '''
        return self.get('txid', None)

    def getParamHash(self, param=""):
        '''
        This function takes a string and calculates a sha224 hash out of it. 
        It is used to hash the input parameters of functions/method in order to 
        uniquely identify a cached result based  only on the input parameters of 
        the function/method call.
        '''
        cache_hash = hashlib.sha224(param).hexdigest()
        return cache_hash

    def metaProperties(self):
        '''
        Return transaction details, like sender address
        '''
        raw_transaction = self.getRawTransaction()

        if self['category'] == 'receive':
            sender_address = self.decodeScriptSig(raw_transaction,
                                                  self['currency'],
                                                  self['wallet'].getNet())
        else:
            sender_address = None

        return {'sender_address': sender_address}

    def getRawTransaction(self):
        '''
        Get the raw transaction dict
        '''
        cache_hash = self.getParamHash("details")
        cached_object = self._cache.fetch('details', cache_hash)
        if cached_object:
            raw_transaction = cached_object
        else:
            raw_transaction = connector.getRawTransaction(
                self['txid'], self['wallet']['provider_id'])
            self._cache.store('details', cache_hash, raw_transaction)
        return raw_transaction

    def getSenderAddress(self):
        '''
        Getter function for the sender address
        '''
        if self['category'] == 'receive':
            meta_properties = self.metaProperties()
            if meta_properties.get('sender_address', False):
                return CoinAddress(meta_properties['sender_address'],
                                   'This is a sender address!')

        return None

    def decodeScriptSig(self, rawtransaction, currency, net='testnet'):
        '''
        Decode input script signature, courtesy of:
        http://bitcoin.stackexchange.com/questions/7838/why-does-gettransaction-report-me-only-the-receiving-address/8864#8864
        '''
        try:
            script_sig = rawtransaction['vin'][0]['scriptSig']['asm']
        except:
            return "not enough info"

        script = script_sig.split()

        h = hashlib.sha256(script[1].decode("hex")).digest()
        ripe160 = hashlib.new('ripemd160')
        ripe160.update(h)
        d = ripe160.digest()

        prefix = self.prefixes[currency.lower()][net]
        address = (prefix + d)

        # calculate checksum
        checksum = hashlib.sha256(
            hashlib.sha256(address).digest()).digest()[:4]

        # build the raw address
        address += checksum

        # encode the address in base58
        encoded_address = misc.b58encode(address)

        return encoded_address

    def getCurrencySymbol(self):
        '''
        Return the Unicode currency symbol
        '''
        return misc.getCurrencySymbol(connector, self.getCurrencyCode())

    def getCurrencyCode(self):
        '''
        Return the currency code
        '''
        return self.get('currency', "").lower()
Exemplo n.º 6
0
class CoinWallet(object):
    '''
    Class for a wallet
    '''
    def __init__(self, wallet_config):
        self._errors = []
        self._config = {}
        self._cache = Cacher({
             'accounts': {},
             'transactions': {},
             'transactiondetails': {},
             'balances': {},
             'info': {},
             })
        
        if type(wallet_config) is dict:
            self._config = wallet_config
        
    @property
    def provider_id(self):
        '''
        Property for the provider id
        '''
        return self.get('id', None)
    
    @property
    def enabled(self):
        '''
        Return the status (enabled/disabled)
        '''
        return self.get('enabled', False)
    
    def __getitem__(self, key):
        '''
        Getter for dictionary-line behavior
        '''
        if key == "currency_symbol":
            return self.getCurrencySymbol()
        elif key == "currency_code":
            return self.getCurrencyCode()
        
        config = getattr(self, '_config')
        return config[key]
     
    def __setitem__(self, key, value):
        '''
        Setter for dictionary-line behavior
        '''
        config = getattr(self, '_config')
        config[key] = value
        return setattr(self, '_config', config)
    
    def get(self, key, default=False):
        '''
        Implementing .get() method for dictionary-line behavior
        '''
        if self._config.get(key, False):
            return self._config.get(key, False)
        else:
            return default
    
    def haskey(self, key):
        '''
        Check the existence of key
        '''
        if key in self._config.keys():
            return True
        else:
            return False
    
    def getNet(self):
        '''
        Return network value, mainnet or testnet
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("provider_id=%s" % self.provider_id)
        cached_peerinfo = self._cache.fetch('info', cache_hash)
        if cached_peerinfo:
            info = cached_peerinfo
        else:
            info = connector.getInfo(self.provider_id)
            self._cache.store('info', cache_hash, info)
        
        is_testnet = False
        if info.has_key('testnet'):
            is_testnet = info.get('testnet')
            if is_testnet is False:
                return "mainnet"
            elif is_testnet is True:
                return "testnet"
        else:
            # default to mainnet
            return "mainnet"
    
    def balance(self):
        '''
        Get wallet balance
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("balance")
        cached_object = self._cache.fetch('balance', cache_hash)
        if cached_object:
            return cached_object.get(self.provider_id, "-")
        
        balance = connector.getBalance(self.provider_id)

        # store result in cache
        self._cache.store('balance', cache_hash, balance)
        
        return misc.longNumber(balance.get(self.provider_id, "-"))
    
    def getParamHash(self, param=""):
        '''
        This function takes a string and calculates a sha224 hash out of it. 
        It is used to hash the input parameters of functions/method in order to 
        uniquely identify a cached result based  only on the input parameters of 
        the function/method call.
        '''
        cache_hash = hashlib.sha224(param).hexdigest()
        return cache_hash
    
    def listAccounts(self, gethidden=False, getarchived=False):
        '''
        Get a list of accounts. This method also supports filtering, fetches address for each account etc.
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("gethidden=%s&getarchived=%s" % (gethidden, getarchived))
        cached_object = self._cache.fetch('accounts', cache_hash)
        if cached_object:
            return cached_object
        
        # get data from the connector (xxxcoind)
        fresh_accounts = connector.listAccounts(gethidden=False, getarchived=False, selected_provider_id=self.provider_id)

        # get a list of archived address
        address_ignore_list = []
        if not getarchived:
            ignore_list = accountFilter.objects.filter(status=1)
            for ignored_account in ignore_list:
                address_ignore_list.append(ignored_account.address.encode('ascii'))
        
        # get a list of hidden accounts
        address_hidden_list = []
        if not gethidden:
            hidden_list = accountFilter.objects.filter(status=2)
            for hidden_account in hidden_list:
                address_hidden_list.append(hidden_account.address.encode('ascii'))
        
        accountObjects = []
        for account_name, account_balance in fresh_accounts.get(self.provider_id, {}).items():

            '''
            # check all addresses if they are in the archive list
            for ignored_address in address_ignore_list:
                if ignored_address in account_addresses:
                    del account_addresses[account_addresses.index(ignored_address)]
            
            # check all addresses if they are in the hidden list
            hidden_flag = False
            for hidden_address in address_hidden_list:
                if hidden_address in account_addresses:
                    hidden_flag = True
            '''
            
            accountObjects.append(CoinAccount({
                                       'name': account_name,
                                       'balance': account_balance,
                                       'currency': self['currency'],
                                       'provider_id': self.provider_id,
                                       'wallet': self,
                                       }))
        
        # cache the result
        self._cache.store('accounts', cache_hash, accountObjects)
        return accountObjects
    
    def getCurrencySymbol(self):
        '''
        Return the Unicode currency symbol
        '''
        return self.get('symbol', None)
    
    def getCurrencyCode(self):
        '''
        Return the currency code
        '''
        return self.get('currency', "").lower()
    
    def listTransactions(self, limit=10, start=0):
        '''
        Return a list of transactions wallet-wide
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("limit=%s&start=%s" % (limit, start))
        cached_object = self._cache.fetch('transactions', cache_hash)
        if cached_object:
            return cached_object
        
        transactions = []
        transactions_dicts = connector.listTransactionsByAccount("*", self.provider_id, limit, start)
        for transaction in transactions_dicts:
            transaction['wallet'] = self
            transaction['currency'] = self.getCurrencyCode()
            transaction['currency_symbol'] = self.getCurrencySymbol()
            transaction['provider_id'] = self.provider_id
            transactions.append(CoinTransaction(transaction))
        
        self._cache.store('transactions', cache_hash, transactions)
        return transactions
    
    def getAccountByName(self, name):
        '''
        Return CoinAccount() for name
        '''
        accounts = self.listAccounts(gethidden=True, getarchived=True)
        for account in accounts:
            if account['name'] == name:
                return account
        
        return None
    
    def getTransactionById(self, txid):
        '''
        Return a transaction by txid
        '''
        # check for cached data, use that or get it again
        cache_hash = self.getParamHash("txid=%s" % (txid))
        cached_object = self._cache.fetch('transactiondetails', cache_hash)
        if cached_object:
            return cached_object
        
        transaction_details = connector.getTransaction(txid, self.provider_id)
        transaction_details['currency'] = self.getCurrencyCode()
        transaction_details['wallet'] = self
        
        self._cache.store('transactiondetails', cache_hash, transaction_details)
        return CoinTransaction(transaction_details)
    
    def getAddressesByAccount(self, account):
        '''
        Get a list of address for account
        '''
        addresses_list = connector.getAddressesByAccount(account, self.provider_id)
        coinaddresses = []
        for address in addresses_list:
            coinaddresses.append(CoinAddress(address, account))
            
        return coinaddresses
    
    def getDefaultAccount(self):
        '''
        Return the CoinAccount object for the default wallet account
        '''
        accounts = self.listAccounts(gethidden=True, getarchived=True)
        for account in accounts:
            if len(account['name']) == 0:
                return account
        else:
            return None
        
    def getAccountByAddress(self, address):
        '''
        Return account by address
        '''
        accounts = self.listAccounts(gethidden=True, getarchived=True)
        
        target_account = None
        for account in accounts:
            for account_address in account['addresses']:
                if str(address) == str(account_address):
                    target_account = account
                    target_account['currency'] = self.getCurrencyCode()
                    target_account['provider_id'] = self.provider_id
                    return target_account
        else:
            return None
        
    def getAccountByIdentifier(self, identifier):
        '''
        Get account by identifier
        '''
        list_of_accounts = self.listAccounts(gethidden=True, getarchived=True)
        for account in list_of_accounts:
            if account.getIdentifier() == identifier:
                return account
        else:
            return None