def get_assets_supply(assets=[]): supplies = {} if 'XCP' in assets: supplies['XCP'] = (util.call_jsonrpc_api("get_supply", {'asset': 'XCP'})['result'], True) assets.remove('XCP') if 'BTC' in assets: supplies['BTC'] = (0, True) assets.remove('BTC') if len(assets) > 0: sql = '''SELECT asset, SUM(quantity) AS supply, divisible FROM issuances WHERE asset IN ({}) AND status = ? GROUP BY asset ORDER BY asset'''.format(','.join(['?' for e in range(0,len(assets))])) bindings = assets + ['valid'] issuances = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result'] for issuance in issuances: supplies[issuance['asset']] = (issuance['supply'], issuance['divisible']) return supplies
def get_assets_supply(assets=[]): supplies = {} if 'XCP' in assets: supplies['XCP'] = (util.call_jsonrpc_api("get_supply", {'asset': 'XCP'})['result'], True) assets.remove('XCP') if 'BTC' in assets: supplies['BTC'] = (0, True) assets.remove('BTC') if len(assets) > 0: sql = '''SELECT asset, SUM(quantity) AS supply, divisible FROM issuances WHERE asset IN ({}) AND status = ? GROUP BY asset ORDER BY asset'''.format(','.join(['?' for e in range(0, len(assets))])) bindings = assets + ['valid'] issuances = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result'] for issuance in issuances: supplies[issuance['asset']] = (issuance['supply'], issuance['divisible']) return supplies
def get_optimal_fee_per_kb(): fees = cache.get_value("FEE_PER_KB") if not fees: if config.BLOCKTRAIL_API_KEY: # query blocktrail API fees = util.get_url( "https://api.blocktrail.com/v1/BTC/fee-per-kb?api_key={}".format(config.BLOCKTRAIL_API_KEY), abort_on_error=True, is_json=True) else: # query bitcoind fees = {} fees['optimal'] = util.call_jsonrpc_api("fee_per_kb", {'conf_target': 3}, abort_on_error=True, use_cache=False)['result'] fees['low_priority'] = util.call_jsonrpc_api("fee_per_kb", {'conf_target': 8}, abort_on_error=True, use_cache=False)['result'] cache.set_value("FEE_PER_KB", fees, cache_period=60 * 5) # cache for 5 minutes return fees
def parse_base64_feed(base64_feed): decoded_feed = base64.b64decode(base64_feed) feed = json.loads(decoded_feed) if not isinstance(feed, dict) or "feed" not in feed: return False errors = util.is_valid_json(feed["feed"], config.FEED_SCHEMA) if len(errors) > 0: raise Exception("Invalid json: {}".format(", ".join(errors))) # get broadcast infos params = { "filters": {"field": "source", "op": "=", "value": feed["feed"]["address"]}, "order_by": "tx_index", "order_dir": "DESC", "limit": 1, } broadcasts = util.call_jsonrpc_api("get_broadcasts", params)["result"] if len(broadcasts) == 0: raise Exception("invalid feed address") complete_feed = {} complete_feed["fee_fraction_int"] = broadcasts[0]["fee_fraction_int"] complete_feed["source"] = broadcasts[0]["source"] complete_feed["locked"] = broadcasts[0]["locked"] complete_feed["counters"] = get_feed_counters(broadcasts[0]["source"]) complete_feed["info_data"] = sanitize_json_data(feed["feed"]) feed["feed"] = complete_feed return feed
def bitcoind_rpc(command, params): return util.call_jsonrpc_api( command, params=params, endpoint=config.BACKEND_URL_NOAUTH, auth=config.BACKEND_AUTH, abort_on_error=True)['result']
def get_asset_info(asset, at_dt=None): asset_info = config.mongo_db.tracked_assets.find_one({'asset': asset}) if asset not in (config.XCP, config.BTC) and at_dt and asset_info['_at_block_time'] > at_dt: #get the asset info at or before the given at_dt datetime for e in reversed(asset_info['_history']): #newest to oldest if e['_at_block_time'] <= at_dt: asset_info = e break else: #asset was created AFTER at_dt asset_info = None if asset_info is None: return None assert asset_info['_at_block_time'] <= at_dt #modify some of the properties of the returned asset_info for BTC and XCP if asset == config.BTC: if at_dt: start_block_index, end_block_index = database.get_block_indexes_for_dates(end_dt=at_dt) asset_info['total_issued'] = blockchain.get_btc_supply(normalize=False, at_block_index=end_block_index) asset_info['total_issued_normalized'] = blockchain.normalize_quantity(asset_info['total_issued']) else: asset_info['total_issued'] = blockchain.get_btc_supply(normalize=False) asset_info['total_issued_normalized'] = blockchain.normalize_quantity(asset_info['total_issued']) elif asset == config.XCP: #BUG: this does not take end_dt (if specified) into account. however, the deviation won't be too big # as XCP doesn't deflate quickly at all, and shouldn't matter that much since there weren't any/much trades # before the end of the burn period (which is what is involved with how we use at_dt with currently) asset_info['total_issued'] = util.call_jsonrpc_api("get_supply", {'asset': 'XCP'}, abort_on_error=True)['result'] asset_info['total_issued_normalized'] = blockchain.normalize_quantity(asset_info['total_issued']) if not asset_info: raise Exception("Invalid asset: %s" % asset) return asset_info
def parse_base64_feed(base64_feed): decoded_feed = base64.b64decode(base64_feed) feed = json.loads(decoded_feed) if not isinstance(feed, dict) or 'feed' not in feed: return False errors = util.is_valid_json(feed['feed'], config.FEED_SCHEMA) if len(errors) > 0: raise Exception("Invalid json: {}".format(", ".join(errors))) # get broadcast infos params = { 'filters': { 'field': 'source', 'op': '=', 'value': feed['feed']['address'] }, 'order_by': 'tx_index', 'order_dir': 'DESC', 'limit': 1 } broadcasts = util.call_jsonrpc_api('get_broadcasts', params)['result'] if len(broadcasts) == 0: raise Exception("invalid feed address") complete_feed = {} complete_feed['fee_fraction_int'] = broadcasts[0]['fee_fraction_int'] complete_feed['source'] = broadcasts[0]['source'] complete_feed['locked'] = broadcasts[0]['locked'] complete_feed['counters'] = get_feed_counters(broadcasts[0]['source']) complete_feed['info_data'] = sanitize_json_data(feed['feed']) feed['feed'] = complete_feed return feed
def get_pairs_with_orders(addresses=[], max_pairs=12): pairs_with_orders = [] sources = '''AND source IN ({})'''.format(','.join(['?' for e in range(0,len(addresses))])) sql = '''SELECT (MIN(give_asset, get_asset) || '/' || MAX(give_asset, get_asset)) AS pair, COUNT(*) AS order_count FROM orders WHERE give_asset != get_asset AND status = ? {} GROUP BY pair ORDER BY order_count DESC LIMIT ?'''.format(sources) bindings = ['open'] + addresses + [max_pairs] my_pairs = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result'] for my_pair in my_pairs: base_asset, quote_asset = util.assets_to_asset_pair(*tuple(my_pair['pair'].split("/"))) top_pair = { 'base_asset': base_asset, 'quote_asset': quote_asset, 'my_order_count': my_pair['order_count'] } if my_pair['pair'] == 'BTC/XCP': # XCP/BTC always in first pairs_with_orders.insert(0, top_pair) else: pairs_with_orders.append(top_pair) return pairs_with_orders
def get_pairs_with_orders(addresses=[], max_pairs=12): pairs_with_orders = [] sources = '''AND source IN ({})'''.format(','.join(['?' for e in range(0, len(addresses))])) sql = '''SELECT (MIN(give_asset, get_asset) || '/' || MAX(give_asset, get_asset)) AS pair, COUNT(*) AS order_count FROM orders WHERE give_asset != get_asset AND status = ? {} GROUP BY pair ORDER BY order_count DESC LIMIT ?'''.format(sources) bindings = ['open'] + addresses + [max_pairs] my_pairs = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result'] for my_pair in my_pairs: base_asset, quote_asset = util.assets_to_asset_pair(*tuple(my_pair['pair'].split("/"))) top_pair = { 'base_asset': base_asset, 'quote_asset': quote_asset, 'my_order_count': my_pair['order_count'] } if my_pair['pair'] == 'BTC/XCP': # XCP/BTC always in first pairs_with_orders.insert(0, top_pair) else: pairs_with_orders.append(top_pair) return pairs_with_orders
def get_feed(address_or_url = ''): conditions = { '$or': [{'source': address_or_url}, {'info_url': address_or_url}], 'info_status': 'valid' } result = {} feeds = config.mongo_db.feeds.find(spec=conditions, projection={'_id': False}, limit=1) for feed in feeds: if 'targets' not in feed['info_data'] or ('type' in feed['info_data'] and feed['info_data']['type'] in ['all', 'cfd']): feed['info_data']['next_broadcast'] = util.next_interval_date(feed['info_data']['broadcast_date']) feed['info_data']['next_deadline'] = util.next_interval_date(feed['info_data']['deadline']) result = feed result['counters'] = get_feed_counters(feed['source']) if 'counters' not in result: params = { 'filters': { 'field': 'source', 'op': '=', 'value': address_or_url }, 'order_by': 'tx_index', 'order_dir': 'DESC', 'limit': 10 } broadcasts = util.call_jsonrpc_api('get_broadcasts', params)['result'] if broadcasts: return { 'broadcasts': broadcasts, 'counters': get_feed_counters(address_or_url) } return result
def proxy_to_counterpartyd(method='', params=[]): if method == 'sql': raise Exception("Invalid method") result = None cache_key = None if config.REDIS_ENABLE_APICACHE: # check for a precached result and send that back instead assert config.REDIS_CLIENT cache_key = method + '||' + base64.b64encode(json.dumps(params).encode()).decode() #^ must use encoding (e.g. base64) since redis doesn't allow spaces in its key names # (also shortens the hashing key for better performance) result = config.REDIS_CLIENT.get(cache_key) if result: try: result = json.loads(result) except Exception as e: logging.warn("Error loading JSON from cache: %s, cached data: '%s'" % (e, result)) result = None # skip from reading from cache and just make the API call if result is None: # cache miss or cache disabled result = util.call_jsonrpc_api(method, params) if config.REDIS_ENABLE_APICACHE: # cache miss assert config.REDIS_CLIENT config.REDIS_CLIENT.setex(cache_key, DEFAULT_COUNTERPARTYD_API_CACHE_PERIOD, json.dumps(result)) #^TODO: we may want to have different cache periods for different types of data if 'error' in result: if result['error'].get('data', None): errorMsg = result['error']['data'].get('message', result['error']['message']) if isinstance(errorMsg, bytes): errorMsg = str(errorMsg, 'utf-8') else: errorMsg = json.dumps(result['error']) raise Exception(errorMsg if errorMsg is not None else "UNKNOWN") return result['result']
def gettransaction_batch(txhash_list): raw_txes = util.call_jsonrpc_api("getrawtransaction_batch", { 'txhash_list': txhash_list, 'verbose': True, 'skip_missing': True}, abort_on_error=True)['result'] txes = {} for tx_hash, tx in raw_txes.iteritems(): if tx is None: txes[tx_hash] = None continue valueOut = 0 for vout in tx['vout']: valueOut += vout['value'] txes[tx_hash] = { 'txid': tx_hash, 'version': tx['version'], 'locktime': tx['locktime'], 'confirmations': tx['confirmations'] if 'confirmations' in tx else 0, 'blocktime': tx['blocktime'] if 'blocktime' in tx else 0, 'blockhash': tx['blockhash'] if 'blockhash' in tx else 0, 'time': tx['time'] if 'time' in tx else 0, 'valueOut': valueOut, 'vin': tx['vin'], 'vout': tx['vout'] } return txes
def cached_function(*args, **kwargs): function_signature = hashlib.sha256(func.__name__ + str(args) + str(kwargs)).hexdigest() sql = "SELECT block_index FROM blocks ORDER BY block_index DESC LIMIT 1" block_index = util.call_jsonrpc_api('sql', { 'query': sql, 'bindings': [] })['result'][0]['block_index'] cached_result = config.mongo_db.counterblockd_cache.find_one({ 'block_index': block_index, 'function': function_signature }) if not cached_result or config.TESTNET: #logger.info("generate cache ({}, {}, {})".format(func.__name__, block_index, function_signature)) try: result = func(*args, **kwargs) config.mongo_db.counterblockd_cache.insert({ 'block_index': block_index, 'function': function_signature, 'result': json.dumps(result) }) return result except Exception, e: logger.exception(e)
def gettransaction_batch(txhash_list): raw_txes = util.call_jsonrpc_api("getrawtransaction_batch", { 'txhash_list': txhash_list, 'verbose': True, 'skip_missing': True }, abort_on_error=True)['result'] txes = {} for tx_hash, tx in raw_txes.iteritems(): if tx is None: txes[tx_hash] = None continue valueOut = 0 for vout in tx['vout']: valueOut += vout['value'] txes[tx_hash] = { 'txid': tx_hash, 'version': tx['version'], 'locktime': tx['locktime'], 'confirmations': tx['confirmations'] if 'confirmations' in tx else 0, 'blocktime': tx['blocktime'] if 'blocktime' in tx else 0, 'blockhash': tx['blockhash'] if 'blockhash' in tx else 0, 'time': tx['time'] if 'time' in tx else 0, 'valueOut': valueOut, 'vin': tx['vin'], 'vout': tx['vout'] } return txes
def get_feed_counters(feed_address): counters = {} sql = 'SELECT COUNT(*) AS bet_count, SUM(wager_quantity) AS wager_quantity, SUM(wager_remaining) AS wager_remaining, status FROM bets ' sql += 'WHERE feed_address=? GROUP BY status ORDER BY status DESC' bindings = [feed_address] params = {'query': sql, 'bindings': bindings} counters['bets'] = util.call_jsonrpc_api('sql', params)['result'] return counters
def get_messagefeed_messages_by_index(message_indexes): msgs = util.call_jsonrpc_api("get_messages_by_index", {'message_indexes': message_indexes}, abort_on_error=True)['result'] events = [] for m in msgs: events.append(messages.decorate_message_for_feed(m)) return events
def get_feed_counters(feed_address): counters = {} sql = "SELECT COUNT(*) AS bet_count, SUM(wager_quantity) AS wager_quantity, SUM(wager_remaining) AS wager_remaining, status FROM bets " sql += "WHERE feed_address=? GROUP BY status ORDER BY status DESC" bindings = [feed_address] params = {"query": sql, "bindings": bindings} counters["bets"] = util.call_jsonrpc_api("sql", params)["result"] return counters
def get_normalized_balances(addresses): """ This call augments counterparty's get_balances with a normalized_quantity field. It also will include any owned assets for an address, even if their balance is zero. NOTE: Does not retrieve BTC balance. Use get_address_info for that. """ if not isinstance(addresses, list): raise Exception("addresses must be a list of addresses, even if it just contains one address") if not len(addresses): raise Exception("Invalid address list supplied") filters = [] for address in addresses: filters.append({'field': 'address', 'op': '==', 'value': address}) mappings = {} result = util.call_jsonrpc_api( "get_balances", {'filters': filters, 'filterop': 'or'}, abort_on_error=True)['result'] isowner = {} owned_assets = config.mongo_db.tracked_assets.find( {'$or': [{'owner': a} for a in addresses]}, {'_history': 0, '_id': 0}) for o in owned_assets: isowner[o['owner'] + o['asset']] = o data = [] for d in result: if not d['quantity'] and ((d['address'] + d['asset']) not in isowner): continue # don't include balances with a zero asset value asset_info = config.mongo_db.tracked_assets.find_one({'asset': d['asset']}) divisible = True # XCP and BTC if asset_info and 'divisible' in asset_info: divisible = asset_info['divisible'] d['normalized_quantity'] = blockchain.normalize_quantity(d['quantity'], divisible) d['owner'] = (d['address'] + d['asset']) in isowner try: d['asset_longname'] = asset_info['asset_longname'] except TypeError as e: d['asset_longname'] = d['asset'] mappings[d['address'] + d['asset']] = d data.append(d) # include any owned assets for each address, even if their balance is zero for key in isowner: if key not in mappings: o = isowner[key] data.append({ 'address': o['owner'], 'asset': o['asset'], 'quantity': 0, 'normalized_quantity': 0, 'owner': True, }) return data
def get_unspent_txouts(source, return_confirmed=False): """returns a list of unspent outputs for a specific address @return: A list of dicts, with each entry in the dict having the following keys: """ txouts = util.call_jsonrpc_api("get_unspent_txouts", {'address': source, 'unconfirmed': True}, abort_on_error=True)['result'] if return_confirmed: return txouts, [output for output in txouts if output['confirmations'] > 0] else: return txouts
def get_last_n_messages(count=100): if count > 1000: raise Exception("The count is too damn high") message_indexes = list(range(max(config.state['last_message_index'] - count, 0) + 1, config.state['last_message_index'] + 1)) msgs = util.call_jsonrpc_api( "get_messages_by_index", {'message_indexes': message_indexes}, abort_on_error=True)['result'] for i in range(len(msgs)): msgs[i] = messages.decorate_message_for_feed(msgs[i]) return msgs
def get_last_n_messages(count=100): if count > 1000: raise Exception("The count is too damn high") message_indexes = range(max(config.state['last_message_index'] - count, 0) + 1, config.state['last_message_index'] + 1) msgs = util.call_jsonrpc_api("get_messages_by_index", { 'message_indexes': message_indexes }, abort_on_error=True)['result'] for i in xrange(len(msgs)): msgs[i] = messages.decorate_message_for_feed(msgs[i]) return msgs
def convert_armory_signedtx_to_raw_hex(signed_tx_ascii): endpoint = "http://127.0.0.1:%s/" % (ARMORY_UTXSVR_PORT_MAINNET if not config.TESTNET else ARMORY_UTXSVR_PORT_TESTNET) params = {'signed_tx_ascii': signed_tx_ascii} raw_tx_hex = util.call_jsonrpc_api("convert_signed_tx_to_raw_hex", params=params, endpoint=endpoint, abort_on_error=True)['result'] return raw_tx_hex
def create_armory_utx(unsigned_tx_hex, public_key_hex): endpoint = "http://%s:%s/" % ( module_config["ARMORY_UTXSVR_HOST"], ARMORY_UTXSVR_PORT_MAINNET if not config.TESTNET else ARMORY_UTXSVR_PORT_TESTNET, ) params = {"unsigned_tx_hex": unsigned_tx_hex, "public_key_hex": public_key_hex} utx_ascii = util.call_jsonrpc_api("serialize_unsigned_tx", params=params, endpoint=endpoint, abort_on_error=True)[ "result" ] return utx_ascii
def create_armory_utx(unsigned_tx_hex, public_key_hex): port = ARMORY_UTXSVR_PORT_MAINNET if config.TESTNET: port = ARMORY_UTXSVR_PORT_TESTNET elif config.REGTEST: port = ARMORY_UTXSVR_PORT_REGTEST endpoint = "http://%s:%s/" % (module_config['ARMORY_UTXSVR_HOST'], port) params = {'unsigned_tx_hex': unsigned_tx_hex, 'public_key_hex': public_key_hex} utx_ascii = util.call_jsonrpc_api("serialize_unsigned_tx", params=params, endpoint=endpoint, abort_on_error=True)['result'] return utx_ascii
def convert_armory_signedtx_to_raw_hex(signed_tx_ascii): endpoint = "http://%s:%s/" % ( module_config["ARMORY_UTXSVR_HOST"], ARMORY_UTXSVR_PORT_MAINNET if not config.TESTNET else ARMORY_UTXSVR_PORT_TESTNET, ) params = {"signed_tx_ascii": signed_tx_ascii} raw_tx_hex = util.call_jsonrpc_api( "convert_signed_tx_to_raw_hex", params=params, endpoint=endpoint, abort_on_error=True )["result"] return raw_tx_hex
def convert_armory_signedtx_to_raw_hex(signed_tx_ascii): port = ARMORY_UTXSVR_PORT_MAINNET if config.TESTNET: port = ARMORY_UTXSVR_PORT_TESTNET elif config.REGTEST: port = ARMORY_UTXSVR_PORT_REGTEST endpoint = "http://%s:%s/" % (module_config['ARMORY_UTXSVR_HOST'], port) params = {'signed_tx_ascii': signed_tx_ascii} raw_tx_hex = util.call_jsonrpc_api("convert_signed_tx_to_raw_hex", params=params, endpoint=endpoint, abort_on_error=True)['result'] return raw_tx_hex
def get_feed_counters(feed_address): counters = {} sql = 'SELECT COUNT(*) AS bet_count, SUM(wager_quantity) AS wager_quantity, SUM(wager_remaining) AS wager_remaining, status FROM bets ' sql += 'WHERE feed_address=? GROUP BY status ORDER BY status DESC' bindings = [feed_address] params = { 'query': sql, 'bindings': bindings } counters['bets'] = util.call_jsonrpc_api('sql', params)['result'] return counters;
def get_block_info(block_index, prefetch=0): global blockinfo_cache if block_index in blockinfo_cache: return blockinfo_cache[block_index] blockinfo_cache.clear() blocks = util.call_jsonrpc_api( "get_blocks", {"block_indexes": range(block_index, block_index + prefetch)}, abort_on_error=True )["result"] for block in blocks: blockinfo_cache[block["block_index"]] = block return blockinfo_cache[block_index]
def get_block_info(block_index, prefetch=0): global blockinfo_cache if block_index in blockinfo_cache: return blockinfo_cache[block_index] blockinfo_cache.clear() blocks = util.call_jsonrpc_api( 'get_blocks', {'block_indexes': range(block_index, block_index + prefetch)}, abort_on_error=True)['result'] for block in blocks: blockinfo_cache[block['block_index']] = block return blockinfo_cache[block_index]
def get_normalized_balances(addresses): """ This call augments counterparty's get_balances with a normalized_quantity field. It also will include any owned assets for an address, even if their balance is zero. NOTE: Does not retrieve BTC balance. Use get_address_info for that. """ if not isinstance(addresses, list): raise Exception("addresses must be a list of addresses, even if it just contains one address") if not len(addresses): raise Exception("Invalid address list supplied") filters = [] for address in addresses: filters.append({'field': 'address', 'op': '==', 'value': address}) mappings = {} result = util.call_jsonrpc_api( "get_balances", {'filters': filters, 'filterop': 'or'}, abort_on_error=True)['result'] isowner = {} owned_assets = config.mongo_db.tracked_assets.find( {'$or': [{'owner': a} for a in addresses]}, {'_history': 0, '_id': 0}) for o in owned_assets: isowner[o['owner'] + o['asset']] = o data = [] for d in result: if not d['quantity'] and ((d['address'] + d['asset']) not in isowner): continue # don't include balances with a zero asset value asset_info = config.mongo_db.tracked_assets.find_one({'asset': d['asset']}) divisible = True # XCP and BTC if asset_info and 'divisible' in asset_info: divisible = asset_info['divisible'] d['normalized_quantity'] = blockchain.normalize_quantity(d['quantity'], divisible) d['owner'] = (d['address'] + d['asset']) in isowner mappings[d['address'] + d['asset']] = d data.append(d) # include any owned assets for each address, even if their balance is zero for key in isowner: if key not in mappings: o = isowner[key] data.append({ 'address': o['owner'], 'asset': o['asset'], 'quantity': 0, 'normalized_quantity': 0, 'owner': True, }) return data
def get_bets(bet_type, feed_address, deadline, target_value=None, leverage=5040): limit = 50 bindings = [] sql = "SELECT * FROM bets WHERE counterwager_remaining>0 AND " sql += "bet_type=? AND feed_address=? AND leverage=? AND deadline=? " bindings += [bet_type, feed_address, leverage, deadline] if target_value != None: sql += "AND target_value=? " bindings.append(target_value) sql += "ORDER BY ((counterwager_quantity+0.0)/(wager_quantity+0.0)) ASC LIMIT ?" bindings.append(limit) params = {"query": sql, "bindings": bindings} return util.call_jsonrpc_api("sql", params)["result"]
def create_armory_utx(unsigned_tx_hex, public_key_hex): endpoint = "http://127.0.0.1:%s/" % (ARMORY_UTXSVR_PORT_MAINNET if not config.TESTNET else ARMORY_UTXSVR_PORT_TESTNET) params = { 'unsigned_tx_hex': unsigned_tx_hex, 'public_key_hex': public_key_hex } utx_ascii = util.call_jsonrpc_api("serialize_unsigned_tx", params=params, endpoint=endpoint, abort_on_error=True)['result'] return utx_ascii
def get_block_info(block_index, prefetch=0, min_message_index=None): global blockinfo_cache if block_index in blockinfo_cache: return blockinfo_cache[block_index] blockinfo_cache.clear() blocks = util.call_jsonrpc_api('get_blocks', {'block_indexes': range(block_index, block_index + prefetch), 'min_message_index': min_message_index}, abort_on_error=True)['result'] for block in blocks: blockinfo_cache[block['block_index']] = block return blockinfo_cache[block_index]
def get_unspent_txouts(source, return_confirmed=False): """returns a list of unspent outputs for a specific address @return: A list of dicts, with each entry in the dict having the following keys: """ txouts = util.call_jsonrpc_api("get_unspent_txouts", { 'address': source, 'unconfirmed': True }, abort_on_error=True)['result'] if return_confirmed: return txouts, [ output for output in txouts if output['confirmations'] > 0 ] else: return txouts
def get_user_bets(addresses=[], status="open"): params = { "filters": {"field": "source", "op": "IN", "value": addresses}, "status": status, "order_by": "tx_index", "order_dir": "DESC", "limit": 100, } bets = util.call_jsonrpc_api("get_bets", params)["result"] sources = {} for bet in bets: sources[bet["feed_address"]] = True return {"bets": bets, "feeds": get_feeds_by_source_addresses(list(sources.keys()))}
def get_bets(bet_type, feed_address, deadline, target_value=None, leverage=5040): limit = 50 bindings = [] sql = 'SELECT * FROM bets WHERE counterwager_remaining>0 AND ' sql += 'bet_type=? AND feed_address=? AND leverage=? AND deadline=? ' bindings += [bet_type, feed_address, leverage, deadline] if target_value != None: sql += 'AND target_value=? ' bindings.append(target_value) sql += 'ORDER BY ((counterwager_quantity+0.0)/(wager_quantity+0.0)) ASC LIMIT ?'; bindings.append(limit) params = { 'query': sql, 'bindings': bindings } return util.call_jsonrpc_api('sql', params)['result']
def get_block_info(block_index, prefetch=0, min_message_index=None): global block_info_cache if block_index in block_info_cache: return block_info_cache[block_index] block_info_cache.clear() blocks = util.call_jsonrpc_api( 'get_blocks', { 'block_indexes': list(range(block_index, block_index + prefetch)), 'min_message_index': min_message_index }, abort_on_error=True, use_cache=False)['result'] for block in blocks: block_info_cache[block['block_index']] = block return block_info_cache[block_index]
def get_escrowed_balances(addresses): addresses_holder = ','.join(['?' for e in range(0, len(addresses))]) sql = '''SELECT (source || '_' || give_asset) AS source_asset, source AS address, give_asset AS asset, SUM(give_remaining) AS quantity FROM orders WHERE source IN ({}) AND status = ? AND give_asset != ? GROUP BY source_asset'''.format(addresses_holder) bindings = addresses + ['open', config.BTC] results = util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT (tx0_address || '_' || forward_asset) AS source_asset, tx0_address AS address, forward_asset AS asset, SUM(forward_quantity) AS quantity FROM order_matches WHERE tx0_address IN ({}) AND forward_asset != ? AND status = ? GROUP BY source_asset'''.format(addresses_holder) bindings = addresses + [config.BTC, 'pending'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT (tx1_address || '_' || backward_asset) AS source_asset, tx1_address AS address, backward_asset AS asset, SUM(backward_quantity) AS quantity FROM order_matches WHERE tx1_address IN ({}) AND backward_asset != ? AND status = ? GROUP BY source_asset'''.format(addresses_holder) bindings = addresses + [config.BTC, 'pending'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT source AS address, '{}' AS asset, SUM(wager_remaining) AS quantity FROM bets WHERE source IN ({}) AND status = ? GROUP BY address'''.format(config.XCP, addresses_holder) bindings = addresses + ['open'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT tx0_address AS address, '{}' AS asset, SUM(forward_quantity) AS quantity FROM bet_matches WHERE tx0_address IN ({}) AND status = ? GROUP BY address'''.format(config.XCP, addresses_holder) bindings = addresses + ['pending'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT tx1_address AS address, '{}' AS asset, SUM(backward_quantity) AS quantity FROM bet_matches WHERE tx1_address IN ({}) AND status = ? GROUP BY address'''.format(config.XCP, addresses_holder) bindings = addresses + ['pending'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] escrowed_balances = {} for order in results: if order['address'] not in escrowed_balances: escrowed_balances[order['address']] = {} if order['asset'] not in escrowed_balances[order['address']]: escrowed_balances[order['address']][order['asset']] = 0 escrowed_balances[order['address']][order['asset']] += order['quantity'] return escrowed_balances
def get_escrowed_balances(addresses): addresses_holder = ','.join(['?' for e in range(0,len(addresses))]) sql ='''SELECT (source || '_' || give_asset) AS source_asset, source AS address, give_asset AS asset, SUM(give_remaining) AS quantity FROM orders WHERE source IN ({}) AND status = ? AND give_asset != ? GROUP BY source_asset'''.format(addresses_holder) bindings = addresses + ['open', 'BTC'] results = util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT (tx0_address || '_' || forward_asset) AS source_asset, tx0_address AS address, forward_asset AS asset, SUM(forward_quantity) AS quantity FROM order_matches WHERE tx0_address IN ({}) AND forward_asset != ? AND status = ? GROUP BY source_asset'''.format(addresses_holder) bindings = addresses + ['BTC', 'pending'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT (tx1_address || '_' || backward_asset) AS source_asset, tx1_address AS address, backward_asset AS asset, SUM(backward_quantity) AS quantity FROM order_matches WHERE tx1_address IN ({}) AND backward_asset != ? AND status = ? GROUP BY source_asset'''.format(addresses_holder) bindings = addresses + ['BTC', 'pending'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT source AS address, '{}' AS asset, SUM(wager_remaining) AS quantity FROM bets WHERE source IN ({}) AND status = ? GROUP BY address'''.format(config.XCP, addresses_holder) bindings = addresses + ['open'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT tx0_address AS address, '{}' AS asset, SUM(forward_quantity) AS quantity FROM bet_matches WHERE tx0_address IN ({}) AND status = ? GROUP BY address'''.format(config.XCP, addresses_holder) bindings = addresses + ['pending'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] sql = '''SELECT tx1_address AS address, '{}' AS asset, SUM(backward_quantity) AS quantity FROM bet_matches WHERE tx1_address IN ({}) AND status = ? GROUP BY address'''.format(config.XCP, addresses_holder) bindings = addresses + ['pending'] results += util.call_jsonrpc_api("sql", {'query': sql, 'bindings': bindings}, abort_on_error=True)['result'] escrowed_balances = {} for order in results: if order['address'] not in escrowed_balances: escrowed_balances[order['address']] = {} if order['asset'] not in escrowed_balances[order['address']]: escrowed_balances[order['address']][order['asset']] = 0 escrowed_balances[order['address']][order['asset']] += order['quantity'] return escrowed_balances
def proxy_to_counterpartyd(method='', params=[]): if method == 'sql': raise Exception("Invalid method") result = None cache_key = None result = util.call_jsonrpc_api(method, params) if 'error' in result: if result['error'].get('data', None): errorMsg = result['error']['data'].get('message', result['error']['message']) if isinstance(errorMsg, bytes): errorMsg = str(errorMsg, 'utf-8') else: errorMsg = json.dumps(result['error']) raise Exception(errorMsg if errorMsg is not None else "UNKNOWN") return result['result']
def get_assets_info(assetsList): assets = assetsList # TODO: change the parameter name at some point in the future...shouldn't be using camel case here if not isinstance(assets, list): raise Exception( "assets must be a list of asset names, even if it just contains one entry" ) assets_info = [] for asset in assets: # BTC and XCP. if asset in [config.BTC, config.XCP]: if asset == config.BTC: supply = blockchain.get_btc_supply(self.proxy, normalize=False) else: supply = util.call_jsonrpc_api("get_supply", {'asset': config.XCP}, abort_on_error=True)['result'] assets_info.append({ 'asset': asset, 'owner': None, 'divisible': True, 'locked': False, 'supply': supply, 'description': '', 'issuer': None }) continue # User-created asset. tracked_asset = config.mongo_db.tracked_assets.find_one( {'asset': asset}, { '_id': 0, '_history': 0 }) if not tracked_asset: continue # asset not found, most likely assets_info.append({ 'asset': asset, 'owner': tracked_asset['owner'], 'divisible': tracked_asset['divisible'], 'locked': tracked_asset['locked'], 'supply': tracked_asset['total_issued'], 'description': tracked_asset['description'], 'issuer': tracked_asset['owner'] }) return assets_info
def get_market_orders(asset1, asset2, addresses=[], supplies=None, min_fee_provided=0.95, max_fee_required=0.95): base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2) if not supplies: supplies = get_assets_supply([asset1, asset2]) market_orders = [] buy_orders = [] sell_orders = [] sql = '''SELECT orders.*, blocks.block_time FROM orders INNER JOIN blocks ON orders.block_index=blocks.block_index WHERE status = ? ''' bindings = ['open'] if len(addresses) > 0: sql += '''AND source IN ({}) '''.format(','.join(['?' for e in range(0,len(addresses))])) bindings += addresses sql += '''AND give_remaining > 0 AND give_asset IN (?, ?) AND get_asset IN (?, ?) ORDER BY tx_index DESC''' bindings += [asset1, asset2, asset1, asset2] orders = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result'] for order in orders: market_order = {} exclude = False if order['give_asset'] == 'BTC': try: fee_provided = order['fee_provided'] / (order['give_quantity'] / 100) market_order['fee_provided'] = format(D(order['fee_provided']) / (D(order['give_quantity']) / D(100)), '.2f') except Exception, e: fee_provided = min_fee_provided - 1 # exclude exclude = fee_provided < min_fee_provided elif order['get_asset'] == 'BTC': try: fee_required = order['fee_required'] / (order['get_quantity'] / 100) market_order['fee_required'] = format(D(order['fee_required']) / (D(order['get_quantity']) / D(100)), '.2f') except Exception, e: fee_required = max_fee_required + 1 # exclude
def find_user_bets(db, addresses, status='open'): params = { 'filters': { 'field': 'source', 'op': 'IN', 'value': addresses }, 'status': status, 'order_by': 'tx_index', 'order_dir': 'DESC', 'limit': 100 } bets = util.call_jsonrpc_api('get_bets', params)['result'] sources = {} for bet in bets: sources[bet['feed_address']] = True return {'bets': bets, 'feeds': get_feeds_by_source(db, sources.keys())}
def cached_function(*args, **kwargs): sql = "SELECT block_index FROM blocks ORDER BY block_index DESC LIMIT 1" block_index = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': []})['result'][0]['block_index'] function_signature = hashlib.sha256(func.__name__ + str(args) + str(kwargs)).hexdigest() cached_result = config.mongo_db.counterblockd_cache.find_one({'block_index': block_index, 'function': function_signature}) if not cached_result or config.TESTNET: #logger.info("generate cache ({}, {}, {})".format(func.__name__, block_index, function_signature)) try: result = func(*args, **kwargs) config.mongo_db.counterblockd_cache.insert({ 'block_index': block_index, 'function': function_signature, 'result': json.dumps(result) }) return result except Exception, e: logger.exception(e)
def cached_function(*args, **kwargs): function_signature = hashlib.sha256(func.__name__ + str(args) + str(kwargs)).hexdigest() sql = "SELECT block_index FROM blocks ORDER BY block_index DESC LIMIT 1" block_index = util.call_jsonrpc_api("sql", {"query": sql, "bindings": []})["result"][0]["block_index"] cached_result = config.mongo_db.counterblockd_cache.find_one( {"block_index": block_index, "function": function_signature} ) if not cached_result or config.TESTNET: # logger.info("generate cache ({}, {}, {})".format(func.__name__, block_index, function_signature)) try: result = func(*args, **kwargs) config.mongo_db.counterblockd_cache.insert( {"block_index": block_index, "function": function_signature, "result": json.dumps(result)} ) return result except Exception, e: logger.exception(e)
def get_pair_price(base_asset, quote_asset, max_block_time=None, supplies=None): if not supplies: supplies = get_assets_supply([base_asset, quote_asset]) sql = '''SELECT *, MAX(tx0_index, tx1_index) AS tx_index, blocks.block_time FROM order_matches INNER JOIN blocks ON order_matches.block_index = blocks.block_index WHERE forward_asset IN (?, ?) AND backward_asset IN (?, ?) ''' bindings = [base_asset, quote_asset, base_asset, quote_asset] if max_block_time: sql += '''AND block_time <= ? ''' bindings += [max_block_time] sql += '''ORDER BY tx_index DESC LIMIT 2''' order_matches = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result'] if len(order_matches) == 0: last_price = D(0.0) elif order_matches[0]['forward_asset'] == base_asset: last_price = calculate_price(order_matches[0]['forward_quantity'], order_matches[0]['backward_quantity'], supplies[order_matches[0]['forward_asset']][1], supplies[order_matches[0]['backward_asset']][1]) else: last_price = calculate_price(order_matches[0]['backward_quantity'], order_matches[0]['forward_quantity'], supplies[order_matches[0]['backward_asset']][1], supplies[order_matches[0]['forward_asset']][1]) trend = 0 if len(order_matches) == 2: if order_matches[1]['forward_asset'] == base_asset: before_last_price = calculate_price(order_matches[0]['forward_quantity'], order_matches[0]['backward_quantity'], supplies[order_matches[0]['forward_asset']][1], supplies[order_matches[0]['backward_asset']][1]) else: before_last_price = calculate_price(order_matches[0]['backward_quantity'], order_matches[0]['forward_quantity'], supplies[order_matches[0]['backward_asset']][1], supplies[order_matches[0]['forward_asset']][1]) if last_price < before_last_price: trend = -1 elif last_price > before_last_price: trend = 1 return D(last_price), trend
def get_user_bets(addresses = [], status="open"): params = { 'filters': { 'field': 'source', 'op': 'IN', 'value': addresses }, 'status': status, 'order_by': 'tx_index', 'order_dir': 'DESC', 'limit': 100 } bets = util.call_jsonrpc_api('get_bets', params)['result'] sources = {} for bet in bets: sources[bet['feed_address']] = True return { 'bets': bets, 'feeds': get_feeds_by_source_addresses(sources.keys()) }
def get_assets_info(assetsList): assets = assetsList #TODO: change the parameter name at some point in the future...shouldn't be using camel case here if not isinstance(assets, list): raise Exception("assets must be a list of asset names, even if it just contains one entry") assets_info = [] for asset in assets: # BTC and XCP. if asset in [config.BTC, config.XCP]: if asset == config.BTC: supply = blockchain.get_btc_supply(self.proxy, normalize=False) else: supply = util.call_jsonrpc_api("get_supply", {'asset': 'XCP'}, abort_on_error=True)['result'] assets_info.append({ 'asset': asset, 'owner': None, 'divisible': True, 'locked': False, 'supply': supply, 'description': '', 'issuer': None }) continue # User-created asset. tracked_asset = config.mongo_db.tracked_assets.find_one({'asset': asset}, {'_id': 0, '_history': 0}) if not tracked_asset: continue #asset not found, most likely assets_info.append({ 'asset': asset, 'owner': tracked_asset['owner'], 'divisible': tracked_asset['divisible'], 'locked': tracked_asset['locked'], 'supply': tracked_asset['total_issued'], 'description': tracked_asset['description'], 'issuer': tracked_asset['owner']}) return assets_info
def get_feed(address_or_url=""): conditions = {"$or": [{"source": address_or_url}, {"info_url": address_or_url}], "info_status": "valid"} result = {} feeds = config.mongo_db.feeds.find(conditions, projection={"_id": False}, limit=1) for feed in feeds: if "targets" not in feed["info_data"] or ( "type" in feed["info_data"] and feed["info_data"]["type"] in ["all", "cfd"] ): feed["info_data"]["next_broadcast"] = util.next_interval_date(feed["info_data"]["broadcast_date"]) feed["info_data"]["next_deadline"] = util.next_interval_date(feed["info_data"]["deadline"]) result = feed result["counters"] = get_feed_counters(feed["source"]) if "counters" not in result: params = { "filters": {"field": "source", "op": "=", "value": address_or_url}, "order_by": "tx_index", "order_dir": "DESC", "limit": 10, } broadcasts = util.call_jsonrpc_api("get_broadcasts", params)["result"] if broadcasts: return {"broadcasts": broadcasts, "counters": get_feed_counters(address_or_url)} return result
def search_raw_transactions(address, unconfirmed=True): return util.call_jsonrpc_api("search_raw_transactions", {'address': address, 'unconfirmed': unconfirmed}, abort_on_error=True)['result']
def get_market_orders(asset1, asset2, addresses=[], supplies=None, min_fee_provided=0.95, max_fee_required=0.95): base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2) if not supplies: supplies = get_assets_supply([asset1, asset2]) market_orders = [] buy_orders = [] sell_orders = [] sql = '''SELECT orders.*, blocks.block_time FROM orders INNER JOIN blocks ON orders.block_index=blocks.block_index WHERE status = ? ''' bindings = ['open'] if len(addresses) > 0: sql += '''AND source IN ({}) '''.format(','.join(['?' for e in range(0, len(addresses))])) bindings += addresses sql += '''AND give_remaining > 0 AND give_asset IN (?, ?) AND get_asset IN (?, ?) ORDER BY tx_index DESC''' bindings += [asset1, asset2, asset1, asset2] orders = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result'] for order in orders: market_order = {} exclude = False if order['give_asset'] == config.BTC: try: fee_provided = order['fee_provided'] / (order['give_quantity'] / 100) market_order['fee_provided'] = format(D(order['fee_provided']) / (D(order['give_quantity']) / D(100)), '.2f') except Exception as e: fee_provided = min_fee_provided - 1 # exclude exclude = fee_provided < min_fee_provided elif order['get_asset'] == config.BTC: try: fee_required = order['fee_required'] / (order['get_quantity'] / 100) market_order['fee_required'] = format(D(order['fee_required']) / (D(order['get_quantity']) / D(100)), '.2f') except Exception as e: fee_required = max_fee_required + 1 # exclude exclude = fee_required > max_fee_required if not exclude: if order['give_asset'] == base_asset: try: price = calculate_price(order['give_quantity'], order['get_quantity'], supplies[order['give_asset']][1], supplies[order['get_asset']][1], 'SELL') except: continue market_order['type'] = 'SELL' market_order['amount'] = order['give_remaining'] market_order['total'] = D(order['give_remaining']) * D(price) if not supplies[order['give_asset']][1] and supplies[order['get_asset']][1]: market_order['total'] = int(market_order['total'] * config.UNIT) elif supplies[order['give_asset']][1] and not supplies[order['get_asset']][1]: market_order['total'] = int(market_order['total'] / config.UNIT) else: market_order['total'] = int(market_order['total']) else: try: price = calculate_price(order['get_quantity'], order['give_quantity'], supplies[order['get_asset']][1], supplies[order['give_asset']][1], 'BUY') except: continue market_order['type'] = 'BUY' market_order['total'] = order['give_remaining'] market_order['amount'] = D(order['give_remaining']) / D(price) if supplies[order['give_asset']][1] and not supplies[order['get_asset']][1]: market_order['amount'] = int(market_order['amount'] / config.UNIT) elif not supplies[order['give_asset']][1] and supplies[order['get_asset']][1]: market_order['amount'] = int(market_order['amount'] * config.UNIT) else: market_order['amount'] = int(market_order['amount']) market_order['price'] = price if len(addresses) > 0: completed = format(((D(order['give_quantity']) - D(order['give_remaining'])) / D(order['give_quantity'])) * D(100), '.2f') market_order['completion'] = "{}%".format(completed) market_order['tx_index'] = order['tx_index'] market_order['tx_hash'] = order['tx_hash'] market_order['source'] = order['source'] market_order['block_index'] = order['block_index'] market_order['block_time'] = order['block_time'] market_orders.append(market_order) else: if market_order['type'] == 'SELL': sell_orders.append(market_order) else: buy_orders.append(market_order) if len(addresses) == 0: market_orders = merge_same_price_orders(sell_orders) + merge_same_price_orders(buy_orders) return market_orders
def get_pairs(quote_asset='BITCRYSTALS', exclude_pairs=[], max_pairs=12, from_time=None): bindings = [] sql = '''SELECT (CASE WHEN forward_asset = ? THEN backward_asset ELSE forward_asset END) AS base_asset, (CASE WHEN backward_asset = ? THEN backward_asset ELSE forward_asset END) AS quote_asset, (CASE WHEN backward_asset = ? THEN (forward_asset || '/' || backward_asset) ELSE (backward_asset || '/' || forward_asset) END) AS pair, (CASE WHEN forward_asset = ? THEN backward_quantity ELSE forward_quantity END) AS bq, (CASE WHEN backward_asset = ? THEN backward_quantity ELSE forward_quantity END) AS qq ''' if from_time: sql += ''', block_time ''' sql += '''FROM order_matches ''' bindings += [quote_asset, quote_asset, quote_asset, quote_asset, quote_asset] if from_time: sql += '''INNER JOIN blocks ON order_matches.block_index = blocks.block_index ''' priority_quote_assets = [] for priority_quote_asset in config.QUOTE_ASSETS: if priority_quote_asset != quote_asset: priority_quote_assets.append(priority_quote_asset) else: break if len(priority_quote_assets) > 0: asset_bindings = ','.join(['?' for e in range(0,len(priority_quote_assets))]) sql += '''WHERE ((forward_asset = ? AND backward_asset NOT IN ({})) OR (forward_asset NOT IN ({}) AND backward_asset = ?)) '''.format(asset_bindings, asset_bindings) bindings += [quote_asset] + priority_quote_assets + priority_quote_assets + [quote_asset] else: sql += '''WHERE ((forward_asset = ?) OR (backward_asset = ?)) ''' bindings += [quote_asset, quote_asset] if len(exclude_pairs) > 0: sql += '''AND pair NOT IN ({}) '''.format(','.join(['?' for e in range(0,len(exclude_pairs))])) bindings += exclude_pairs if from_time: sql += '''AND block_time > ? ''' bindings += [from_time] sql += '''AND forward_asset != backward_asset AND status = ?''' bindings += ['completed', max_pairs] sql = '''SELECT base_asset, quote_asset, pair, SUM(bq) AS base_quantity, SUM(qq) AS quote_quantity FROM ({}) GROUP BY pair ORDER BY quote_quantity DESC LIMIT ?'''.format(sql) return util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result']
def get_market_trades(asset1, asset2, addresses=[], limit=50, supplies=None): limit = min(limit, 100) base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2) if not supplies: supplies = get_assets_supply([asset1, asset2]) market_trades = [] sources = '' bindings = ['expired'] if len(addresses) > 0: placeholder = ','.join(['?' for e in range(0,len(addresses))]) sources = '''AND (tx0_address IN ({}) OR tx1_address IN ({}))'''.format(placeholder, placeholder) bindings += addresses + addresses sql = '''SELECT order_matches.*, blocks.block_time FROM order_matches INNER JOIN blocks ON order_matches.block_index=blocks.block_index WHERE status != ? {} AND forward_asset IN (?, ?) AND backward_asset IN (?, ?) ORDER BY block_index DESC LIMIT ?'''.format(sources) bindings += [asset1, asset2, asset1, asset2, limit] order_matches = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result'] for order_match in order_matches: if order_match['tx0_address'] in addresses: trade = {} trade['match_id'] = order_match['id'] trade['source'] = order_match['tx0_address'] trade['countersource'] = order_match['tx1_address'] trade['block_index'] = order_match['block_index'] trade['block_time'] = order_match['block_time'] trade['status'] = order_match['status'] if order_match['forward_asset'] == base_asset: trade['type'] = 'SELL' trade['price'] = calculate_price(order_match['forward_quantity'], order_match['backward_quantity'], supplies[order_match['forward_asset']][1], supplies[order_match['backward_asset']][1], 'SELL') trade['amount'] = order_match['forward_quantity'] trade['total'] = order_match['backward_quantity'] else: trade['type'] = 'BUY' trade['price'] = calculate_price(order_match['backward_quantity'], order_match['forward_quantity'], supplies[order_match['backward_asset']][1], supplies[order_match['forward_asset']][1], 'BUY') trade['amount'] = order_match['backward_quantity'] trade['total'] = order_match['forward_quantity'] market_trades.append(trade) if len(addresses)==0 or order_match['tx1_address'] in addresses: trade = {} trade['match_id'] = order_match['id'] trade['source'] = order_match['tx1_address'] trade['countersource'] = order_match['tx0_address'] trade['block_index'] = order_match['block_index'] trade['block_time'] = order_match['block_time'] trade['status'] = order_match['status'] if order_match['backward_asset'] == base_asset: trade['type'] = 'SELL' trade['price'] = calculate_price(order_match['backward_quantity'], order_match['forward_quantity'], supplies[order_match['backward_asset']][1], supplies[order_match['forward_asset']][1], 'SELL') trade['amount'] = order_match['backward_quantity'] trade['total'] = order_match['forward_quantity'] else: trade['type'] = 'BUY' trade['price'] = calculate_price(order_match['forward_quantity'], order_match['backward_quantity'], supplies[order_match['forward_asset']][1], supplies[order_match['backward_asset']][1], 'BUY') trade['amount'] = order_match['forward_quantity'] trade['total'] = order_match['backward_quantity'] market_trades.append(trade) return market_trades