def balances(self, account=0):
     rsp = self.raw_request('getbalance', {'account_index': account})
     retdata = {
         'account_index' : 0,
         'unlocked_balance':  RoundDown(  from_atomic( rsp['unlocked_balance'] ) ) ,
         'balance':  RoundDown( from_atomic( rsp['balance'] ) ) ,
         'blocks_to_unlock' :  rsp['blocks_to_unlock']
     }
     return  retdata
    def import_key_images(self, key_images : list):
        rsp = self.raw_request('import_key_images', {'signed_key_images': key_images})
        # rpc.import_key_images()
        unspent = RoundDown(Decimal(rsp['unspent']) * PICONERO)
        spent = RoundDown(Decimal(rsp['spent']) * PICONERO)

        #这里转为浮点数返回
        retdata = {
            'height': rsp['height'],
            'unspent': unspent,
            'spent': spent
        }
        return retdata
Exemple #3
0
    def GetBalanceInEther(self, addr):
        nBalance = self.eth_getBalance(addr, "latest")

        #向下取整, 而不是四舍五入, 四舍五入会导致金额偏大
        dBalance = RoundDown(Decimal(str(nBalance)) / Decimal(str(10**18)))
        strBalance = '%.8f' % dBalance
        return strBalance
Exemple #4
0
    def get_single_token_balance(cls, rpcconn: USDPProxy, addr: str,
                                 token_name: str) -> dict:
        """
        获取 HTDF和token余额,  而不是获取所有 token余额
        :param rpcconn:
        :param addr:
        :return:
        """
        strhtdfbalance = USDP_GetBalance.get_balance(rpcconn, addr)
        strhtdfbalance = str(RoundDown(Decimal(strhtdfbalance))) if Decimal(
            strhtdfbalance) > Decimal('0.00000001') else '0.00000000'
        retdata = {'HTDF': strhtdfbalance}

        for contract_addr in HRC20_CONTRACT_MAP.keys():
            token_info = HRC20_CONTRACT_MAP[contract_addr]
            if token_info['symbol'] != token_name.upper():
                continue

            strbalance = rpcconn.getHRC20TokenBalance(
                contract_addr=contract_addr, address=addr)
            strsymbol = rpcconn.getHRC20_symbol(contract_addr=contract_addr)

            if strsymbol.upper() in g_special_token_list:
                strsymbol = 'HRC20-' + strsymbol
            retdata[strsymbol] = str(strbalance)
            break
        return retdata
Exemple #5
0
    def proccess(self, rpcconn):

        #1.从t_usdp_active_addr获取所有的地址
        strSql = """SELECT address FROM t_het_active_addrs WHERE `balance` > 0.001 ORDER BY `balance` DESC LIMIT 100;"""
        sqlRet = sql.run(strSql)
        addrs = []
        for item in sqlRet:
            if "address" in item:
                addrs.append(item["address"])

        #2.实时获取所有地址的账户信息( addr, balance, account_no, sequence )
        retData = []
        for strAddr in addrs:
            retInfo = USDP_GetAccountInfo.account_info(rpcconn, strAddr)
            if not retInfo:  #如果账户一毛钱不剩, 返回None
                strSql = """DELETE FROM t_het_active_addrs WHERE address='{0}';""".format(
                    strAddr)
                logging.info("sql: {}".format(strSql))
                sqlRet = sql.run(strSql)
                continue

            #防止HET 归集数量太大, 导致归集失败
            if Decimal(retInfo['balance']) > Decimal('100000000.0'):
                retInfo['balance'] = '%.8f' % RoundDown(
                    Decimal(retInfo['balance']) - Decimal('0.5432'))
            retData.append(retInfo)

        #对返回数据进行排序

        sortedRet = sorted(retData,
                           key=lambda keys: Decimal(keys['balance']),
                           reverse=True)

        #3.返回数据
        return sortedRet
Exemple #6
0
    def getHRC20TokenBalance(self, contract_addr: str, address: str) -> str:
        # 123.56.71.141:1317/hs/contract/htdf1nkkc48lfchy92ahg50akj2384v4yfqpm4hsq6y/70a0823100000000000000000000000067ee5cbe5cb9ae6794ca1437186f12066b0196af

        rlp_data = '70a08231'
        from htdf.my_bech32 import Bech32AddrToHex
        hex_addr = Bech32AddrToHex(addr=address)
        hex_addr_fmt = '0' * (32 * 2 - len(hex_addr)) + hex_addr

        rlp_data += hex_addr_fmt

        assert len(rlp_data) == (4 * 2 + 32 * 2), 'rlp data is illgal'

        urlpath = f'/hs/contract/{contract_addr}/{rlp_data}'
        rsp = self._get_url_call(urlpath)
        data = rsp.replace('"', '')

        assert len(
            data
        ) == 32 * 2, f'{contract_addr} data {data} is illegal, urlpath: {urlpath}'

        if int(data, 16) == 0: return '0.00000000'

        ndecimals = self.getHRC20_decimals(contract_addr=contract_addr)
        assert 1 < ndecimals <= 18

        # balance =   int(data, 16) * 1.0 / 10**(ndecimals)  #会四舍五入!!  有问题
        balance = Decimal(int(data, 16)) / Decimal(10**(ndecimals))
        if balance < 0.00010000: return '0.00000000'
        # balance.quantize(Decimal("0.00000000"), getattr(decimal, 'ROUND_DOWN'))
        strfmt_balance = str(RoundDown(Decimal(str(balance))))
        # strfmt_balance = '%.8f' % balance
        return strfmt_balance
Exemple #7
0
    def get_all_balance(cls, rpcconn, addr, symbol='', block='latest'):

        str_eth_balance = rpcconn.eth_getBalance(addr, block)
        dbalance = Decimal(str_eth_balance) / Decimal(10**18)
        dbalance = RoundDown(dbalance)
        retData = {}
        retData['ETC'] = "%.8f" % dbalance

        # if symbol.upper() == 'ETH':
        #     pass
        # elif len(symbol) == 0:
        #     # 检查代币余额
        #     for contract_addr in ERC20_CONTRACTS_MAP.values():
        #         strSymbol = rpcconn.eth_erc20_symbol(contract_addr)
        #         strBalance = rpcconn.eth_erc20_balanceOf(contract_addr, addr, True)
        #         retData[strSymbol] = strBalance
        # else:
        #     contract_addr = ERC20_CONTRACTS_MAP[symbol] if symbol != 'ERC20-USDT' else ERC20_CONTRACTS_MAP['USDT']
        #     strSymbol = rpcconn.eth_erc20_symbol(contract_addr)
        #     strBalance = rpcconn.eth_erc20_balanceOf(contract_addr, addr, True)
        #     retData[strSymbol] = strBalance
        #
        # if 'USDT' in retData:
        #     retData['ERC20-USDT'] = retData['USDT']
        #     del (retData['USDT'])

        return retData
Exemple #8
0
def EncodeDecimal(o):
    if isinstance(o, decimal.Decimal):
        # return float(decimal.Decimal( round(o, 8)))
        d =  RoundDown(o)
        f = float(d)
        return f
        # return float(o)
    raise TypeError(repr(o) + " is not JSON serializable")
 def process(address: str):
     api = RippleProxy(host=XRP_RIPPLED_PUBLIC_API_URL,
                       port=XRP_RIPPLED_PUBLIC_API_PORT)
     rsp = api.get_account_info(address=address)
     retinfo = {}
     retinfo['account'] = rsp['account_data']['Account']
     retinfo['sequence'] = rsp['account_data']['Sequence']
     balance = '%.8f' % RoundDown(
         Decimal(rsp['account_data']['Balance']) / Decimal(10**6))  # 防止假充值
     retinfo['balance'] = balance
     return retinfo
Exemple #10
0
    def eth_erc20_balanceOf(self, contract_addr, user_addr, format=False):

        tmp_contract_addr = '0x' + contract_addr.replace('0x', '')
        data = '0x70a08231000000000000000000000000' + user_addr.replace(
            '0x', '')

        str_balance = self.eth_call(to_address=tmp_contract_addr, data=data)
        if not format:
            return hex(int(str_balance, 16))[2:].replace('L', '')
        else:
            nDecimals = self.eth_erc20_decimals(tmp_contract_addr)
            dBalance = Decimal(int(str_balance, 16)) / (10**nDecimals)
            d = RoundDown(dBalance)
            return '%.8f' % d
Exemple #11
0
    def get_all_balance(cls, rpcconn: USDPProxy, addr: str) -> dict:
        strhtdfbalance = USDP_GetBalance.get_balance(rpcconn, addr)
        strhtdfbalance = str(RoundDown(Decimal(strhtdfbalance))) if Decimal(
            strhtdfbalance) > Decimal('0.00000001') else '0.00000000'
        retdata = {'HTDF': strhtdfbalance}

        for contract_addr in HRC20_CONTRACT_MAP.keys():
            strbalance = rpcconn.getHRC20TokenBalance(
                contract_addr=contract_addr, address=addr)
            strsymbol = rpcconn.getHRC20_symbol(contract_addr=contract_addr)

            if strsymbol.upper() in g_special_token_list:
                strsymbol = 'HRC20-' + strsymbol
            retdata[strsymbol] = str(strbalance)
        return retdata
Exemple #12
0
    def process(rpc_connection, blknumber, txindex):
        txdata = rpc_connection.eth_getTransactionByBlockNumberAndIndex(
            blknumber, txindex)
        blockData = rpc_connection.eth_getBlockByNumber(blknumber)
        txdata["blocktime"] = blockData[
            "timestamp"] if blockData and "timestamp" in blockData else 0
        txdata["confirmations"] = ETH_BlockNumber.latest(
            rpc_connection) - blknumber
        txdata["blockNumber"] = blknumber
        from utils import filtered, alterkeyname
        retData = filtered(alterkeyname(txdata, 'hash', 'txid'), [
            "confirmations", "blocktime", "blockNumber", "nonce", "txid",
            "from", "to", "value", "gas", "gasPrice"
        ]) if txdata else False

        for key in ["nonce", "gas", "value", "gasPrice", "blocktime"]:
            if "0x" in retData[key]: retData[key] = str(int(retData[key], 16))
            getcontext().prec = 30
            dValue = RoundDown(Decimal(retData[key]) / Decimal(10**18))
            if key in ["value"]: retData[key] = "%.8f" % dValue

        return retData
Exemple #13
0
    def GetTransactionsInfoFromBlock(self, nHeight):
        try:

            txRet = []

            nChainLastest = self.GetLastestBlockNumberFromBlockChain()
            if not nChainLastest: return txRet

            blockInfo = self.eth_getBlockByNumber(nHeight)
            if not blockInfo: return txRet

            #使用Bloom Filter 判断是否包含ERC20交易
            # bf =  hex2Dec( blockInfo['logsBloom'] )

            # included_contracts = []
            #测试合约地址是否存在
            # if bloom_query(bf, hexstr_to_bytes(ERC20_TRANSFER_EVENT_HASH)): #检查 transfer事件是否存在
            #     for contract_addr in ERC20_CONTRACTS_LIST:
            #         con_addr = contract_addr.replace('0x', '').lower()  #如果包含'0x'则去掉 '0x'
            #         if bloom_query(bf,   hexstr_to_bytes(con_addr) ):
            #             included_contracts.append(con_addr)

            nTimestamp = hex2Dec(blockInfo["timestamp"])
            nNumber = hex2Dec(blockInfo["number"])
            nGasLimit = hex2Dec(blockInfo["gasLimit"])

            nConfirmations = nChainLastest - nNumber

            for tx in blockInfo["transactions"]:
                txTmp = {}

                #如果是创建合约, to是 null
                if tx['to'] is None: continue

                if tx['to'] in self.exUserAddrs:  #普通的ETC充币
                    # 普通的ETC转账
                    txTmp["txid"] = tx["hash"]
                    txTmp["from"] = tx["from"]
                    txTmp["to"] = tx["to"]
                    txTmp["nonce"] = hex2Dec(tx["nonce"])
                    txTmp["blocktime"] = nTimestamp
                    txTmp["confirmations"] = nConfirmations
                    txTmp["blockNumber"] = nNumber
                    txTmp['symbol'] = 'ETC'
                    getcontext().prec = 30
                    txTmp["value"] = "%.8f" % RoundDown(
                        Decimal(hex2Dec(tx["value"])) /
                        Decimal(10**18))  # ether
                    print("found tx:{}".format(txTmp))
                    txRet.append(txTmp)

                else:  #有可能是ERC20代币充值
                    # if 0 == len(included_contracts):
                    #     continue
                    #
                    # #如果是合约调用合约进行的ERC20代币转账, to地址可能并不是代币合约的地址,
                    # #因此必须通过bloomFilter进行过滤, 防止漏掉充值
                    #
                    # receipt = self.eth_getTransactionReceipt(tx['hash'])
                    # if int(receipt['status'], 16) != 1: continue
                    # if len(receipt['logs']) < 1: continue
                    #
                    # bf = hex2Dec(receipt['logsBloom'])
                    # if not bloom_query(bf, unhexlify(ERC20_TRANSFER_EVENT_HASH)):  # 检查 transfer事件是否存在
                    #     # print("transfer event is not in logsBloom.")
                    #     continue
                    #
                    # tmp_con_addrs = []
                    # for contract_addr in ERC20_CONTRACTS_LIST:
                    #     con_addr = contract_addr.replace('0x', '').lower()  # 如果包含'0x'则去掉 '0x'
                    #     if bloom_query(bf, hexstr_to_bytes( con_addr)):
                    #         tmp_con_addrs.append('0x' + con_addr)
                    #         break
                    #
                    # if len(tmp_con_addrs) == 0:
                    #     continue
                    # print("tmp include contract addr : {}".format(tmp_con_addrs))
                    #
                    # # 支持合约的批量转账
                    # for log in receipt['logs']:
                    #     if log['removed']: continue
                    #     topics = log['topics']
                    #
                    #     # transfer事件的topics的数量必须是3
                    #     if len(topics) != 3:
                    #         continue
                    #
                    #     # 如果合约地址不是交易所要监控的合约,则跳过
                    #     if log['address'] not in tmp_con_addrs:
                    #         continue
                    #
                    #     # 如果事件的哈希不是transfer的, 则跳过
                    #     event_hash = topics[0]
                    #     if ERC20_TRANSFER_EVENT_HASH.replace('0x', '').lower() != event_hash.replace('0x', '').lower():
                    #         continue
                    #
                    #     # addr_from 并不完全等于 tx['from'], 即合约的调用者并一定是token的发送方,
                    #     #  可以参考ERC20标准的 transferFrom 方法
                    #     addr_from = '0x' + topics[1][-40:]  # ERC20代币的发送方
                    #     addr_to = '0x' + topics[2][-40:]  # ERC20代币的接收方
                    #
                    #     #如果from地址是交易所的地址(一般是归集操作), 则也需要更新活跃地址表
                    #     if addr_from in self.exUserAddrs:
                    #         strSql = """INSERT INTO t_eth_patch_addrs(`address`) VALUES('{}')""".format(addr_from)
                    #         sqlRet = sql.run(strSql)
                    #
                    #     if addr_to not in self.exUserAddrs:
                    #         print('{} is not exchange address'.format(addr_to))
                    #         continue
                    #
                    #
                    #     # 获取代币简称 , 必须用 log['address'], 不能用tx['to'],
                    #     # 因为合约调用合约, tx['to']是调用者, log['address']才是真正执行的合约
                    #     strSymbol = self.eth_erc20_symbol(log['address'])
                    #     nDecimal = self.eth_erc20_decimals(log['address'])  # 获取小数位数
                    #     strValue = log['data']
                    #
                    #     txTmp["txid"] = tx["hash"]
                    #     txTmp["from"] = addr_from
                    #     txTmp["to"] = addr_to.strip()
                    #     txTmp["nonce"] = hex2Dec(tx["nonce"])
                    #     txTmp["blocktime"] = nTimestamp
                    #     txTmp["confirmations"] = nConfirmations
                    #     txTmp["blockNumber"] = nNumber
                    #     txTmp['symbol'] = strSymbol
                    #
                    #     getcontext().prec = 30
                    #     txTmp["value"] = "%.8f" % RoundDown(Decimal(hex2Dec(strValue)) / Decimal(10 ** nDecimal))  # 单位转换
                    #     print("found tx: {}".format(txTmp))
                    #
                    #     txRet.append(txTmp)
                    pass

            return txRet
        except Exception as e:
            print("GetTransactionsInfoFromBlock(nHeight) error:", e)
            return None
        pass
    def get_deposit_txs(self):

        ret_txs = []

        params = {
            'in': True,
            'pending': False,
            'failed': False,
            'pool': False,
            'filter_by_height': False,  #通过高度过滤, 暂时不通过高度过滤, 后期充币比较多的时候,再根据高度过滤
            # 'min_height' : 0,
            # 'max_height': 0,
            'account_index': 0,
            # 'subaddr_indices' : []   # 如果为空, 则查询所有
        }

        logging.info(f'starting get_transfers')
        res = self.raw_request(method='get_transfers', params=params)
        logging.info(f'get_transfers finished. result: {res}')

        res_in_txs = res['in'] if 'in' in res else []

        for in_tx in res_in_txs:

            tmp_tx = {}

            tmp_tx['dst_addr'] = in_tx['address']
            tmp_tx['amount'] = RoundDown(
                Decimal(in_tx['amount']) / Decimal(10**12))
            tmp_tx['confirmations'] = in_tx['confirmations']

            if in_tx['confirmations'] < 10:
                logging.info(
                    f'txid:{in_tx["txid"]} confirmations : {in_tx["confirmations"]}/10 .'
                )
                continue

            tmp_tx['blocknumber'] = in_tx['height']

            #subaddr_index  {major, minor}  可以推出 和  in_tx['address']相同
            tmp_tx['timestamp'] = in_tx['timestamp']
            tmp_tx['txid'] = in_tx['txid']
            tmp_tx['type'] = in_tx['type']  #充币交易必须是  'in'

            #double_spend_seen 一般是用于  pool 交易的判断, 这里只是
            if in_tx['double_spend_seen']:
                logging.warning(f'txid:{tmp_tx["txid"]} is double spend tx ')
                continue

            tmp_tx['unlock_time'] = in_tx[
                'unlock_time']  # 必须是 0,  如果不是0, 说明还没解锁
            tmp_tx['locked'] = in_tx['locked']  # 如果是锁定的不要,充币不能锁定
            if tmp_tx['locked']:
                logging.warning(
                    f'txid:{tmp_tx["txid"]} is locked tx, unlock_time: { tmp_tx["unlock_time"]  }'
                )
                continue

            major = in_tx['subaddr_index']['major']
            minor = in_tx['subaddr_index']['minor']
            if major == 0 and minor == 0:
                logging.warning(
                    f'txid:{tmp_tx["txid"]} is master addr(0, 0) tx , do not regard as deposit tx  '
                )
                continue

            subaddr = get_address_ex(private_view_key=XMR_PRIV_VIEW_KEY,
                                     master_addr=XMR_MASTER_ADDR,
                                     major=major,
                                     minor=minor)

            if subaddr != tmp_tx['dst_addr']:
                logging.info(
                    f'tx dst_addr is {tmp_tx["dst_addr"]}, but ({major}, {minor}) sub addr is {subaddr}'
                )
                continue

            ret_txs.append(tmp_tx)

        return ret_txs
    def __GetTransactionFromBlock(self, nBlockNum: int):
        data = self.getBlockByBlockNum(nBlockNum)
        timeStr = data["block_meta"]["header"]["time"]
        timeStr = timeStr[:timeStr.rfind('.')]
        ta = time.strptime(timeStr, "%Y-%m-%dT%H:%M:%S")
        timestamp = int(time.mktime(ta))
        #print("timestamp", timestamp)

        retData = []
        txs = data["block"]["txs"]
        if not isinstance(txs, list): return []
        for tx in txs:
            txData = {}

            #2019-06-13 yqq 因失败的交易也会被打包进区块, 所以,加上交易有效性判断
            strTxid = str(tx["Hash"]).strip()
            if len(strTxid) != 64:
                print("strTxid is invalid txid")
                continue

            #2020-04-14 增加HRC20交易有效性判断
            if not self.isValidTx(strTxid):
                print("%s is invalid tx" % strTxid)
                continue

            txData["txid"] = tx["Hash"]
            txData["from"] = tx["From"]
            txData["to"] = tx["To"]
            txData["amount"] = tx["Amount"][0]["amount"]  #单位是 usdp, 不用再除10**8
            txData["timestamp"] = timestamp

            strTxid = txData["txid"].strip()
            strFrom = txData["from"].strip()
            strTo = txData["to"].strip()

            #print("self.__exUserAddrs size:{}".format(len(self.__exUserAddrs)))
            strLog = "{} is valid tx, from: {} to:{}".format(
                strTxid, strFrom, strTo)
            if strFrom in self.__exUserAddrs:  #这种情况是地址被归集了,需要更新余额
                self.__RefreshBalanceIntoDB(strFrom)
            if strTo not in self.__exUserAddrs:  #仅监测交易所用户的地址,

                #2020-04-13 增加HRC20判断
                if self.__strCoinType.lower() != 'htdf':
                    strLog = strLog + ", but not for exchange."
                    print(strLog)
                    continue

                if strTo not in HRC20_CONTRACT_MAP:
                    strLog = strLog + ", but not for exchange."
                    print(strLog)
                    continue

                #如果是关心的 HRC20 合约交易
                data = tx['Data']

                # 函数签名(4字节)  + 代币接收地址(32字节) + 代币金额(32字节)
                if len(data) != (4 + 32 + 32) * 2:
                    print('data length ')
                    continue

                method_sig = data[:4 * 2]
                if method_sig.lower() != 'a9059cbb':
                    print(
                        f'method sig is not  `transfer` sig . data:{method_sig}'
                    )
                    continue

                token_recipient = data[4 * 2 + 12 * 2:4 * 2 +
                                       32 * 2]  #只去最后 20 字节, 去掉全面填补的 0
                recipient_bech32_addr = HexAddrToBech32(
                    hrp='htdf', hexstraddr=token_recipient)

                token_amount = data[4 * 2 + 32 * 2:]
                token_decimal = HRC20_CONTRACT_MAP[strTo]['decimal']
                token_symbol = HRC20_CONTRACT_MAP[strTo]['symbol']

                if recipient_bech32_addr not in self.__exUserAddrs:
                    print(
                        f'token_recipient bech32_addr {recipient_bech32_addr} is not belong to exchange'
                    )

                    #如果源地址是交易所的, 更新 HRC20 代币代币余额
                    if strFrom in self.__exUserAddrs:
                        self.__RefreshHRC20TokenBalance(
                            contract_addr=strFrom,
                            address=recipient_bech32_addr,
                            symbol=token_symbol)

                    continue

                #以防万一
                if not (1 < token_decimal <= 18):
                    print(
                        f' token_decimal is invalid !  {strTo} : {token_decimal} '
                    )
                    continue

                amount = Decimal(int(token_amount, 16)) / Decimal(
                    10**token_decimal)

                if amount < 0.000000001:
                    print(
                        f' token_amount {token_amount} is too small! skip it!  '
                    )
                    continue

                strfmt_amount = str(RoundDown(amount))

                strsql = """INSERT INTO tb_hrc20_deposit(`txid`,`symbol`,`from`,`to`,`value`,`block_number`,`block_time`,`confirmations`) """
                strsql += f"""VALUES('{tx["Hash"]}', '{token_symbol}', '{strFrom}', '{recipient_bech32_addr}', '{strfmt_amount}', {nBlockNum}, {timestamp}, 10) """
                strsql += """ ON DUPLICATE KEY UPDATE `confirmations`={}; """.format(
                    10)

                print(strsql)

                sqlret = sql.run(strsql)

                self.__RefreshHRC20TokenBalance(contract_addr=strTo,
                                                address=recipient_bech32_addr,
                                                symbol=token_symbol)

                continue
            else:  # 正常充币的情况
                strLog = strLog + ", it's for exchange."
                self.__RefreshBalanceIntoDB(strTo)
            print(strLog)

            retData.append(txData)
        return retData