diff --git a/modules/brc20_api/api.js b/modules/brc20_api/api.js index ca07c372..8b83dc45 100644 --- a/modules/brc20_api/api.js +++ b/modules/brc20_api/api.js @@ -530,4 +530,61 @@ app.get('/v1/brc20/event', async (request, response) => { } }); +app.get('/v1/brc20/ticker_info', async (request, response) => { + try { + console.log(`${request.protocol}://${request.get('host')}${request.originalUrl}`) + let tick = request.query.ticker.toLowerCase() || '' + + let query = `select original_tick, tick, max_supply, decimals, limit_per_mint, + remaining_supply, remaining_supply, burned_supply, is_self_mint, deploy_inscription_id, block_height + from brc20_tickers + where tick = $1` + + let res = await query_db(query, [tick]) + if (res.rows.length == 0) { + response.status(400).send({ error: 'no tick found', result: null }) + return + } + + let ticker_nfo = res.rows[0] + response.send({ error: null, result: ticker_info }) + } catch (err) { + console.log(err) + response.status(500).send({ error: 'internal error', result: null }) + } +}); + +app.get('/v1/brc20/balance_summary_of_wallet', async (request, response) => { + try { + console.log(`${request.protocol}://${request.get('host')}${request.originalUrl}`) + let address = request.query.address || '' + let pkscript = request.query.pkscript || '' + + let current_block_height = await get_block_height_of_db() + let balance_list = [] + + let query = ` select tick, overall_balance, available_balance + from brc20_current_balances + where pkscript = $1;` + let params = [pkscript] + if (address != '') { + query = query.replace('pkscript', 'wallet') + params = [address] + } + + let res = await query_db(query, params) + if (res.rows.length == 0) { + response.status(400).send({ error: 'no balance found', result: null }) + return + } + balance_list = res.rows + + summary = { block_height: current_block_height, detail: balance_list } + response.send({ error: null, result: summary }) + } catch (err) { + console.log(err) + response.status(500).send({ error: 'internal error', result: null }) + } +}); + app.listen(api_port, api_host); diff --git a/modules/runes_api/api.js b/modules/runes_api/api.js index a12f59aa..d137d802 100644 --- a/modules/runes_api/api.js +++ b/modules/runes_api/api.js @@ -112,10 +112,11 @@ app.get('/v1/runes/activity_on_block', async (request, response) => { event_type_id_to_name[row.event_type_id] = row.event_type_name }) - let query = `select event_type, outpoint, pkscript, rune_id, amount + let query = `select event_type, outpoint, pkscript, re.rune_id, rite.rune_name, amount from runes_events re + left join runes_id_to_entry rite on rite.rune_id = re.rune_id where block_height = $1 - order by id asc;` + order by re.id asc;` let res = await query_db(query, [block_height]) let result = [] for (const row of res.rows) { @@ -124,6 +125,7 @@ app.get('/v1/runes/activity_on_block', async (request, response) => { outpoint: row.outpoint, pkscript: row.pkscript, rune_id: row.rune_id, + rune_name: row.rune_name, amount: row.amount }) } @@ -186,7 +188,41 @@ app.get('/v1/runes/get_unspent_rune_outpoints_of_wallet', async (request, respon let params = [pkscript_selector_value] let res = await query_db(query, params) - response.send({ error: null, result: res.rows, db_block_height: current_block_height }) + + let rune_ids = [] + let rune_id_map = {} + for (const row of res.rows) { + for (const rune_id of row.rune_ids) { + if (rune_id_map[rune_id] == undefined) { + rune_id_map[rune_id] = rune_id + rune_ids.push(rune_id) + } + } + } + + let rune_id_to_name = {} + if (rune_ids.length > 0) { + let query = ` select rune_id, rune_name from runes_id_to_entry where rune_id = ANY ($1);` + let params = [rune_ids] + let res1 = await query_db(query, params) + res1.rows.forEach((row) => { + rune_id_to_name[row.rune_id] = row.rune_name + }) + } + + let result = [] + for (const row of res.rows) { + let outpoint = row + let rune_infos = [] + for (const rune_id of row.rune_ids) { + let rune = {rune_id: rune_id, rune_name: rune_id_to_name[rune_id]} + rune_infos.push(rune) + } + outpoint.rune_infos = rune_infos + result.push(outpoint) + } + + response.send({ error: null, result: result, db_block_height: current_block_height }) } catch (err) { console.log(err) response.status(500).send({ error: 'internal error', result: null }) @@ -280,6 +316,51 @@ app.get('/v1/runes/get_hash_of_all_activity', async (request, response) => { } }); +// get runes info of a given rune name +app.get('/v1/runes/rune_info', async (request, response) => { + try { + console.log(`${request.protocol}://${request.get('host')}${request.originalUrl}`) + let rune_name = request.query.rune_name + + let query = `select + rune_name, + rune_id, + rune_block, + burned, + divisibility, + etching, + terms_amount, + terms_cap, + terms_height_l, + terms_height_h, + terms_offset_l, + terms_offset_h, + mints, + number, + premine, + spacers, + symbol, + timestamp, + turbo, + genesis_height, + last_updated_block_height + from runes_id_to_entry + where rune_name = $1` + + let res = await query_db(query, [rune_name]) + if (res.rows.length == 0) { + response.status(400).send({ error: 'no tick found', result: null }) + return + } + + let rune_info = res.rows[0] + response.send({ error: null, result: rune_info }) + } catch (err) { + console.log(err) + response.status(500).send({ error: 'internal error', result: null }) + } +}); + // get all events with a specific transaction ID app.get('/v1/runes/event', async (request, response) => { try { diff --git a/modules/runes_index/index_runes.js b/modules/runes_index/index_runes.js index a0d88a8c..feb97a16 100644 --- a/modules/runes_index/index_runes.js +++ b/modules/runes_index/index_runes.js @@ -197,8 +197,8 @@ async function main_index() { if (block_height > current_height) continue console.warn("Block repeating, possible reorg!!") let blockhash = parts[3].trim() - let blockhash_db_q = await db_pool.query("select block_hash from runes_block_hashes where block_height = $1;", [block_height]) - if (blockhash_db_q.rows[0].block_hash != blockhash) { + let blockhash_db_q = await db_pool.query("select block_hash from runes_block_hashes where block_height = $1;", [block_height]) + if (blockhash_db_q.rows.length == 0 || blockhash_db_q.rows[0].block_hash != blockhash) { let reorg_st_tm = +(new Date()) console.error("Reorg detected at block_height " + block_height) await handle_reorg(block_height) @@ -296,9 +296,10 @@ async function main_index() { , terms_offset_l, terms_offset_h , mints, "number", premine, rune_name, spacers, symbol , "timestamp", turbo, genesis_height, last_updated_block_height) values ($1, $2, $3, $4, $5 - , $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21);` + , $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) + ON conflict(rune_id) DO NOTHING;` let sql_query_outpoint_to_balances_insert = `INSERT into runes_outpoint_to_balances (outpoint, pkscript, wallet_addr, rune_ids, balances, block_height) values ($1, $2, $3, $4, $5, $6);` - let sql_query_id_to_entry_changes_insert = `INSERT into runes_id_to_entry_changes (rune_id, burned, mints, block_height) values ($1, $2, $3, $4);` + let sql_query_id_to_entry_changes_insert = `INSERT into runes_id_to_entry_changes (rune_id, burned, mints, block_height) values ($1, $2, $3, $4) ON conflict(rune_id, block_height) DO NOTHING;;` let sql_query_id_to_entry_update = `UPDATE runes_id_to_entry SET burned = $1, mints = $2, last_updated_block_height = $3 WHERE rune_id = $4 AND last_updated_block_height < $5;` @@ -639,7 +640,7 @@ async function update_cumulative_block_hashes(until_height, to_be_inserted_hashe } else { cumulative_event_hash = block_event_hash } - await db_pool.query(`INSERT into runes_cumulative_event_hashes (block_height, block_event_hash, cumulative_event_hash) values ($1, $2, $3);`, [height, block_event_hash, cumulative_event_hash]) + await db_pool.query(`INSERT into runes_cumulative_event_hashes (block_height, block_event_hash, cumulative_event_hash) values ($1, $2, $3) ON conflict(block_height) DO NOTHING;`, [height, block_event_hash, cumulative_event_hash]) } if (report_to_indexer) {