From 0919c224956b065a3417f7c7352082ac0b06632a Mon Sep 17 00:00:00 2001 From: Miles Zhang Date: Wed, 17 Jan 2024 10:36:41 +0800 Subject: [PATCH] feat: download csv of omiga_inscription transactions (#1571) Signed-off-by: Miles Zhang --- .../api/v1/omiga_inscriptions_controller.rb | 11 +++ ...port_omiga_inscription_transactions_job.rb | 78 +++++++++++++++++++ config/routes.rb | 6 +- .../v1/omiga_inscriptions_controller_test.rb | 66 ++++++++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 app/jobs/csv_exportable/export_omiga_inscription_transactions_job.rb diff --git a/app/controllers/api/v1/omiga_inscriptions_controller.rb b/app/controllers/api/v1/omiga_inscriptions_controller.rb index ee81800d9..806222116 100644 --- a/app/controllers/api/v1/omiga_inscriptions_controller.rb +++ b/app/controllers/api/v1/omiga_inscriptions_controller.rb @@ -28,6 +28,17 @@ def show raise Api::V1::Exceptions::UdtNotFoundError end + def download_csv + args = params.permit(:id, :start_date, :end_date, :start_number, + :end_number, udt: {}) + file = CsvExportable::ExportOmigaInscriptionTransactionsJob.perform_now(args.to_h) + + send_data file, type: "text/csv; charset=utf-8; header=present", + disposition: "attachment;filename=inscription_transactions.csv" + rescue ActiveRecord::RecordNotFound + raise Api::V1::Exceptions::UdtNotFoundError + end + private def validate_query_params diff --git a/app/jobs/csv_exportable/export_omiga_inscription_transactions_job.rb b/app/jobs/csv_exportable/export_omiga_inscription_transactions_job.rb new file mode 100644 index 000000000..84924ed73 --- /dev/null +++ b/app/jobs/csv_exportable/export_omiga_inscription_transactions_job.rb @@ -0,0 +1,78 @@ +module CsvExportable + class ExportOmigaInscriptionTransactionsJob < BaseExporter + def perform(args) + udt = Udt.find_by!(type_hash: args[:id], published: true) + ckb_transactions = udt.ckb_transactions + + if args[:start_date].present? + start_date = BigDecimal(args[:start_date]) + ckb_transactions = ckb_transactions.where("block_timestamp >= ?", + start_date) + end + + if args[:end_date].present? + end_date = BigDecimal(args[:end_date]) + ckb_transactions = ckb_transactions.where("block_timestamp <= ?", + end_date) + end + + if args[:start_number].present? + ckb_transactions = ckb_transactions.where("block_number >= ?", + args[:start_number]) + end + + if args[:end_number].present? + ckb_transactions = ckb_transactions.where("block_number <= ?", + args[:end_number]) + end + + ckb_transactions = ckb_transactions.includes(:inputs, :outputs). + order(block_timestamp: :desc).limit(5000) + + rows = [] + ckb_transactions.find_in_batches(batch_size: 1000, + order: :desc) do |transactions| + transactions.each do |transaction| + row = generate_row(transaction, udt) + next if row.blank? + + rows << row + end + end + + header = [ + "Txn hash", "Blockno", "UnixTimestamp", "Method", "Token", + "Amount", "date(UTC)" + ] + + generate_csv(header, rows) + end + + def generate_row(transaction, udt) + inputs = transaction.inputs.omiga_inscription + outputs = transaction.outputs.omiga_inscription + + datetime = datetime_utc(transaction.block_timestamp) + unit = udt.symbol.presence || udt.name + method = + if inputs.blank? && outputs.present? + "mint" + elsif inputs.present? && outputs.present? + "rebase_mint" + else + "unknown" + end + data = CkbUtils.parse_omiga_inscription_data(outputs.first.data) + + [ + transaction.tx_hash, + transaction.block_number, + transaction.block_timestamp, + method, + unit, + data[:mint_limit], + datetime, + ] + end + end +end diff --git a/config/routes.rb b/config/routes.rb index b02ea620d..6dfbc23fa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -59,7 +59,11 @@ get :download_csv end end - resources :omiga_inscriptions, only: %i(index show) + resources :omiga_inscriptions, only: %i(index show) do + collection do + get :download_csv + end + end resources :udt_transactions, only: :show resources :address_udt_transactions, only: :show resources :distribution_data, only: :show diff --git a/test/controllers/api/v1/omiga_inscriptions_controller_test.rb b/test/controllers/api/v1/omiga_inscriptions_controller_test.rb index b0e20a6a0..07bd27b88 100644 --- a/test/controllers/api/v1/omiga_inscriptions_controller_test.rb +++ b/test/controllers/api/v1/omiga_inscriptions_controller_test.rb @@ -91,6 +91,72 @@ class OmigaInscriptionsControllerTest < ActionDispatch::IntegrationTest assert_equal response_udts, response.body end + + test "should get download_csv" do + block1 = create(:block, :with_block_hash, number: 0, + timestamp: Time.now.to_i * 1000) + tx1 = create(:ckb_transaction, block: block1, + tx_hash: "0x3e89753ebca825e1504498eb18b56576d5b7eff59fe033346a10ab9e8ca359a4", block_timestamp: block1.timestamp) + input_address1 = create(:address) + address1_lock = create(:lock_script, address_id: input_address1.id) + info_ts = create(:type_script, + args: "0xcd89d8f36593a9a82501c024c5cdc4877ca11c5b3d5831b3e78334aecb978f0d", + code_hash: "0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6", + hash_type: "type") + info_output = create(:cell_output, ckb_transaction: tx1, + block: block1, capacity: 50000000 * 10**8, + tx_hash: tx1.tx_hash, + cell_index: 1, + address: input_address1, + cell_type: "omiga_inscription_info", + lock_script_id: address1_lock.id, + type_script_id: info_ts.id) + info_output.data = "0x0814434b42204669737420496e736372697074696f6e04434b42495fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b50679080040075af0750700000000000000000000e8764817000000000000000000000000" + info = create(:omiga_inscription_info, + code_hash: "0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6", + hash_type: "type", + args: "0xcd89d8f36593a9a82501c024c5cdc4877ca11c5b3d5831b3e78334aecb978f0d", + decimal: 0.8e1, + name: "CKB Fist Inscription", + symbol: "CKBI", + udt_hash: "0x5fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b5067908", + expected_supply: 0.21e16, + mint_limit: 0.1e12, + mint_status: "minting", + udt_id: nil) + input_address2 = create(:address) + address2_lock = create(:lock_script, address_id: input_address2.id) + + xudt_ts = create(:type_script, + args: "0x9709d30fc21348ae1d28a197310a80aec3b8cdb5c93814d5e240f9fba85b76af", + code_hash: "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + hash_type: "type", + script_hash: "0x5fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b5067908") + block2 = create(:block, :with_block_hash, number: 1, + timestamp: Time.now.to_i * 1000) + tx2 = create(:ckb_transaction, block: block2, + tx_hash: "0xd5d38a2096c10e5d0d55def7f2b3fe58779aad831fbc9dcd594446b1f0837430") + xudt_output = create(:cell_output, ckb_transaction: tx2, + block: block2, capacity: 50000000 * 10**8, + tx_hash: tx2.tx_hash, + type_hash: xudt_ts.script_hash, + cell_index: 1, + address: input_address2, + cell_type: "omiga_inscription", + lock_script_id: address2_lock.id, + type_script_id: xudt_ts.id) + + xudt_output.data = "0x00e87648170000000000000000000000" + udt = create(:udt, :omiga_inscription) + create(:udt_transaction, udt_id: udt.id, ckb_transaction_id: tx2.id) + valid_get download_csv_api_v1_omiga_inscriptions_url(id: udt.type_hash, start_date: (Time.now - 1.minute).to_i * 1000, + end_date: Time.now.to_i * 1000) + + assert_response :success + content = CSV.parse(response.body) + assert_equal "0xd5d38a2096c10e5d0d55def7f2b3fe58779aad831fbc9dcd594446b1f0837430", + content[1][0] + end end end end