def post(self): try: address = self.get_argument("address") if len(address) != 34 or (not str(address).startswith('T')): raise Exception("invalid address") trx = Trx( Tron(full_node=TRON_RPC_URL, solidity_node=TRON_RPC_URL, event_server=TRON_RPC_URL)) account_info = trx.get_account(address=address) if 'balance' in account_info: decBalance = Decimal( account_info['balance']) / Decimal('1000000') fmtBalance = str( decBalance.quantize(Decimal("0.000000"), getattr(decimal, 'ROUND_DOWN'))) else: fmtBalance = '0.000000' self.write( json.dumps(BaseHandler.success_ret_with_data(fmtBalance), default=decimal_default)) pass except Exception as e: self.write( json.dumps(BaseHandler.error_ret_with_data("error: %s" % e))) logging.error("error:{0} in {1}".format(e, get_linenumber()))
async def send_trx(self, from_address, private_key, to_address, amount): account = Tron(private_key=private_key, default_address=from_address) account_api = Trx(account) amount_sun = amount * 1e6 tx = await self._request('POST', '/wallet/createtransaction', owner_address=self.to_hex( from_address.encode()), to_address=self.to_hex(to_address.encode()), amount=int(amount_sun)) signed_tx = account_api.sign(tx) return await self._request('POST', '/wallet/broadcasttransaction', **signed_tx)
async def send_token(self, from_address, private_key, to_address, token_id, amount): account = Tron(private_key=private_key, default_address=from_address) account_api = Trx(account) amount_sun = amount * 1e6 tx = await self._request( 'POST', '/wallet/transferasset', owner_address=self.to_hex(from_address.encode()), to_address=self.to_hex(to_address.encode()), amount=int(amount_sun), asset_name=codecs.encode(str(token_id).encode(), 'hex').decode()) signed_tx = account_api.sign(tx) return await self._request('POST', '/wallet/broadcasttransaction', **signed_tx)
def post(self): try: address = self.get_argument("address") if len(address) != 34 or (not str(address).startswith('T')): raise Exception("invalid address") trx = Trx( Tron(full_node=TRON_RPC_URL, solidity_node=TRON_RPC_URL, event_server=TRON_RPC_URL)) account_info = trx.get_account(address=address) if 'balance' in account_info: decBalance = Decimal( account_info['balance']) / Decimal('1000000') fmtBalance = decBalance.quantize( Decimal("0.000000"), getattr(decimal, 'ROUND_DOWN')) else: fmtBalance = '0.000000' is_active = 'create_time' in account_info #账户是否已经激活 rsp_data = { 'address': address, 'balance': str(fmtBalance), 'active': is_active #其他代币资产信息可以根据资产id进行获取, 如TRC20-USDT , 此是后话 } logging.info(f'{rsp_data}') self.write( json.dumps(BaseHandler.success_ret_with_data(rsp_data), default=decimal_default)) pass except Exception as e: self.write( json.dumps(BaseHandler.error_ret_with_data("error: %s" % e))) logging.error("error:{0} in {1}".format(e, get_linenumber()))
def post(self): trx = Trx( Tron(full_node=TRON_RPC_URL, solidity_node=TRON_RPC_URL, event_server=TRON_RPC_URL)) try: signed_trx = self.get_argument_from_json("data") order_id = self.get_argument_from_json("orderId") is_exist, txid, tx_json = self.get_order_from_db(order_id) if is_exist: self.write( json.dumps(BaseHandler.success_ret_with_data(tx_json), default=decimal_default)) return signed_trx_jsonobj = json.loads(signed_trx) ret = trx.broadcast(signed_trx_jsonobj) if 'result' in ret and ret['result'] == True: self.write( json.dumps(BaseHandler.success_ret_with_data(ret), default=decimal_default)) #如果广播成功, 则插入数据库 if ret['result'] == True: self.insert_txid_into_db(order_id=order_id, txid=ret['transaction']['txID'], tx_json_str=json.dumps(ret)) else: errmsg = json.dumps(ret) self.write(json.dumps(BaseHandler.error_ret_with_data(errmsg))) except Exception as e: logging.error("TRX_SendRawTransaction: {}".format(e)) self.write( json.dumps(BaseHandler.error_ret_with_data("error: %s" % e))) pass
def process(self, symbol: str = 'TRX') -> list: #每次只查部分地址, 以防http超时 strSql = f"""SELECT address FROM tb_trx_active_addrs WHERE `symbol`='{symbol}' AND `balance` >= 1 ORDER BY `balance` DESC LIMIT 25;""" sqlRet = sql.run(strSql) addrs = [] for item in sqlRet: if "address" in item: if item['address'] not in addrs: addrs.append(item["address"]) trx = Trx( Tron(full_node=TRON_RPC_URL, solidity_node=TRON_RPC_URL, event_server=TRON_RPC_URL)) retList = [] for addr in addrs: account_info = trx.get_account(address=addr) if 'balance' in account_info: decBalance = Decimal( account_info['balance']) / Decimal('1000000') fmtBalance = decBalance.quantize( Decimal("0.000000"), getattr(decimal, 'ROUND_DOWN')) else: fmtBalance = '0.000000' if Decimal(fmtBalance) < Decimal('1.0'): logging.info( f"{addr}'s balance({fmtBalance}) is less than 1.0TRX, skip it." ) continue retList.append({ 'address': addr, 'balance': str(fmtBalance), 'symbol': symbol }) return retList
def post(self): try: trx = Trx( Tron(full_node=TRON_RPC_URL, solidity_node=TRON_RPC_URL, event_server=TRON_RPC_URL)) src_acct = self.get_argument("src_acct") dst_acct = self.get_argument("dst_acct") stramount = self.get_argument("amount") src_acct = src_acct.strip() dst_acct = dst_acct.strip() stramount = stramount.strip() if len(src_acct) != 34 or (not str(src_acct).startswith('T')): raise Exception("invalid src address") if len(dst_acct) != 34 or (not str(dst_acct).startswith('T')): raise Exception("invalid dst address") amount = float(stramount) tx = trx.tron.transaction_builder.send_transaction( to=dst_acct, amount=amount, account=src_acct) self.modify_expiration(tx) tx['signature'] = ['this_is_placeholder_for_signature'] rsp_data = { 'raw_trx_json_str': json.dumps(tx), 'digest': tx['txID'] } logging.info(f'{rsp_data}') self.write( json.dumps(BaseHandler.success_ret_with_data(rsp_data), default=decimal_default)) pass except Exception as e: logging.error("TRX_CreateRawTransaction: {}".format(e)) self.write( json.dumps(BaseHandler.error_ret_with_data("error: %s" % e))) pass
def __init__(self): self.N_BLOCK_COUNT_EACH_TIME = 5 self.tron = Tron(full_node=full_node, solidity_node=solidity_node, event_server=event_server) self.api = Trx(tron=self.tron) # self.connected = self.tron.is_connected() self.addrs = self._GetExDepositAddrsFromDB() logging.info("len(addrs) : {}".format(len(self.addrs))) #使用 dict提高查询速度 self.hex_addrs = set() for addr in self.addrs: self.hex_addrs.add( str(self.tron.address.to_hex(address=addr)).lower()) logging.info("hex_addr: {}".format(self.hex_addrs)) pass
def main(): logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() full_node = 'https://api.trongrid.io' solidity_node = 'https://api.trongrid.io' event_server = 'https://api.trongrid.io' privkey = "你的私钥" tron = Tron(full_node=full_node, solidity_node=solidity_node, event_server=event_server, private_key=privkey) trx = Trx(tron) from_addr = 'TPcUx2iwjomVzmX3CHDDYmnEPJFTVeyqqS' to_addr = 'TDUjsjJzQABwVv8DnLVDZ778uKQ7X5Fs7E' options = { 'from' : from_addr } amount = float(0.123) # receipt = trx.send_transaction( to=to_addr, amount=amount, options=options ) #构造交易 tx = trx.tron.transaction_builder.send_transaction( to_addr, amount, options['from'] ) if False: sign = trx.sign(tx) sleep(61) # 休眠 61秒 广播时报错: {'code': 'TRANSACTION_EXPIRATION_ERROR', 'message': 'transaction expired'} result = trx.broadcast(sign) pprint(result) return old_expiration_hex = my_encode_int64(tx['raw_data']['expiration']) #改变 raw_data.expiration, 增加一个小时 tx['raw_data']['expiration'] += 3600 * 1000 new_expiration_hex = my_encode_int64(tx['raw_data']['expiration']) #也要改变 raw_data_hex 中相应的字段 # tmp_hex = tx['raw_data_hex'][30:] # tx['raw_data_hex'] = tx['raw_data_hex'][0:30] raw_data_hex = str(tx['raw_data_hex']) index = raw_data_hex.find(old_expiration_hex) logger.info( "index : {}".format( index) ) new_raw_data_hex = raw_data_hex.replace(old_expiration_hex, new_expiration_hex) old_txid = hashlib.sha256( unhexlify( tx['raw_data_hex'] )).hexdigest() new_txid = hashlib.sha256( unhexlify( new_raw_data_hex) ).hexdigest() if old_txid == tx['txID'] : logger.info('txid 比对成功!') else: logger.info('txid比对失败!') tx['txID'] = new_txid sign = trx.sign(tx) my_sig = new_ecsign( unhexlify( new_txid), unhexlify( privkey) ) logger.info( type(hexlify(my_sig)) ) logger.info( type(sign['signature'][0] )) logger.info( "我的签名: {}".format( str(hexlify(my_sig), encoding='latin') )) logger.info("原始签名: {}".format( sign['signature'][0] )) if sign['signature'][0] == str(hexlify(my_sig), encoding='latin'): logger.info('签名对比成功!') else: logger.info('签名对比失败') sleep(61) #休眠 61秒, 来测试修改 expiration的效果 result = trx.broadcast(sign) pprint(result) #测试成功 txid为: 8c2b0a40812be8bcee3f92587e6824dc5a6035572cffe13707211821085ea7d3 pass
class TrxScanner(object): def __init__(self): self.N_BLOCK_COUNT_EACH_TIME = 5 self.tron = Tron(full_node=full_node, solidity_node=solidity_node, event_server=event_server) self.api = Trx(tron=self.tron) # self.connected = self.tron.is_connected() self.addrs = self._GetExDepositAddrsFromDB() logging.info("len(addrs) : {}".format(len(self.addrs))) #使用 dict提高查询速度 self.hex_addrs = set() for addr in self.addrs: self.hex_addrs.add( str(self.tron.address.to_hex(address=addr)).lower()) logging.info("hex_addr: {}".format(self.hex_addrs)) pass def _GetExDepositAddrsFromDB(self): try: sqlstr = """SELECT DISTINCT `address` from `tb_trx_deposit_addrs`;""" sql_result = sql.run(sqlstr) addrs = [] for item in sql_result: if 'address' not in item: continue addrs.append(item['address'].strip()) return addrs except Exception as e: logging.error(" _GetAddresses() error: {}".format(e)) return [] def _PushTxIntoDB(self, tx: dict): strSql = """INSERT INTO tb_trx_deposit(`txid`,`timestamp`,`from`,`to`,`amount`,`symbol`,`confirmations`, `block_number`) """ strSql += f"""VALUES('{tx['txid']}',{tx['timestamp']},'{tx['from']}', '{tx['to']}','{tx['amount']}','{tx['symbol']}',{tx['confirmations']}, {tx['blocknumber']}) """ strSql += """ ON DUPLICATE KEY UPDATE `confirmations`={}; """.format( tx['confirmations']) logging.info("sql: {} ".format(strSql)) sqlRet = sql.run(strSql) def _UpdateActiveBalance(self, addr: str): account_info = self.api.get_account(address=addr) if 'balance' in account_info: decBalance = Decimal(account_info['balance']) / Decimal('1000000') fmtBalance = decBalance.quantize(Decimal("0.000000"), getattr(decimal, 'ROUND_DOWN')) else: fmtBalance = '0.000000' strSql = """INSERT INTO `tb_trx_active_addrs`(`symbol`, `address`, `balance`)""" strSql += f"""VALUES('TRX', '{addr}', {fmtBalance})""" strSql += """ON DUPLICATE KEY UPDATE `balance`=VALUES(`balance`);""" logging.info("sql: {} ".format(strSql)) sqlRet = sql.run(strSql) pass def _GetDepositTrxsFromBlockRange(self, nStart: int, nEnd: int): logging.info("starting get block {} to {}".format(nStart, nEnd)) #TODO: 可以增加 visible字段, 地址会以 Base58格式返回; 如果是代币, assetname会是代币名称 blocks_info = self.api.get_block_range(start=nStart, end=nEnd) if not blocks_info: raise Exception("blocks_info is none") rettrxs = [] for oneblock in blocks_info: try: if 'transactions' not in oneblock: continue transactions = oneblock['transactions'] for tx in transactions: valueinfo = tx['raw_data']['contract'][0]['parameter'][ 'value'] # 只包含 amount, owner_address, to_address if len(valueinfo) != 3: logging.info("valueinfo's length is not 3, pass it! ") continue if 'amount' not in valueinfo: logging.info( "amount not in valueinfo, it's not normal TRX transaction" ) continue dst_hex_addr = valueinfo['to_address'] src_hex_addr = valueinfo['owner_address'] # 如果from地址是交易所的地址(一般是归集操作) if src_hex_addr in self.hex_addrs: src_b58_addr = str(self.tron.address.from_hex( valueinfo['owner_address']), encoding='utf8') self._UpdateActiveBalance(addr=src_b58_addr) if dst_hex_addr not in self.hex_addrs: logging.info("addr {} is not exchange addr".format( dst_hex_addr)) continue else: #如果目的地址是交易所的地址, 则跟新活跃地址表的余额, 方便后期归集 dst_b58_addr = str( self.tron.address.from_hex(dst_hex_addr), encoding='utf8') self._UpdateActiveBalance(addr=dst_b58_addr) src_b58_addr = str( self.tron.address.from_hex(src_hex_addr), encoding='utf8') dst_b58_addr = str( self.tron.address.from_hex(dst_hex_addr), encoding='utf8') txid = tx['txID'] blocknumber = oneblock['block_header']['raw_data'][ 'number'] timestamp = int(tx['raw_data']['timestamp'] / 1000) damount = Decimal(str( valueinfo['amount'])) / Decimal('1000000') stramount = damount.quantize( Decimal("0.000000"), getattr(decimal, 'ROUND_DOWN')) successed = ("SUCCESS" == tx['ret'][0]['contractRet']) if not successed: logging.info("tx {} is not successed tx".format(txid)) continue txinfo = { 'txid': txid, 'to': dst_b58_addr, 'from': src_b58_addr, 'amount': stramount, 'timestamp': timestamp, 'blocknumber': blocknumber, 'confirmations': 100, 'symbol': 'TRX' } logging.info('found a deposit tx: {}'.format(txinfo)) rettrxs.append(txinfo) except Exception as e: logging.error(e) continue return rettrxs def __GetScanStartBlock(self, strCoinType): """ 从数据库中获取币种的 扫描的起始区块 """ #类型判断 assert (isinstance(strCoinType, str)) #对参数进行检查 #注意sql注入 strType = strCoinType.lower() sqlRet = sql.run( """SELECT start_block FROM t_scan_start WHERE coin_type='{0}';""". format(strType)) if len(sqlRet) > 0: item = sqlRet[0] if 'start_block' in item: nRet = int(str(item['start_block']), 10) return nRet return 0 def __GetLatestBlockNumber(self): while True: try: block = self.api.get_current_block() number = block['block_header']['raw_data']['number'] return number except Exception as e: logging.error("{}, will try again".format(e)) def StartScan(self): nLatestestBlock = self.__GetLatestBlockNumber() nStartBlock = self.__GetScanStartBlock('trx') # for n in range(nStartBlock, nLatestestBlock + 1): n = nStartBlock while n < nLatestestBlock + 1: nTmpEnd = n + self.N_BLOCK_COUNT_EACH_TIME if n + self.N_BLOCK_COUNT_EACH_TIME <= nLatestestBlock + 1 else nLatestestBlock + 1 txs = self._GetDepositTrxsFromBlockRange(n, nTmpEnd) for tx in txs: self._PushTxIntoDB(tx) # 保存本次扫描的结束区块高度 strSql = """update t_scan_start set start_block={0} where coin_type='{1}';""".format( nTmpEnd - 1, 'trx') logging.info("sql : {}".format(strSql)) sql.run(strSql) n = nTmpEnd pass