export token transfers to csv file

pull/2242/head
Ayrat Badykov 5 years ago
parent 00131ecb9b
commit 1b009499ed
No known key found for this signature in database
GPG Key ID: B44668E265E9396F
  1. 119
      apps/explorer/lib/explorer/chain/address_token_transfer_csv_exporter.ex
  2. 1
      apps/explorer/mix.exs
  3. 72
      apps/explorer/test/explorer/chain/address_token_transfer_csv_exporter_test.exs
  4. 1
      mix.lock

@ -0,0 +1,119 @@
defmodule Explorer.Chain.AddressTokenTransferCsvExporter do
@moduledoc """
Exports token transfers to a csv file.
"""
alias Explorer.{Chain, PagingOptions}
alias Explorer.Chain.{Address, Transaction, TokenTransfer}
alias NimbleCSV.RFC4180
@necessity_by_association [
necessity_by_association: %{
[created_contract_address: :names] => :optional,
[from_address: :names] => :optional,
[to_address: :names] => :optional,
[token_transfers: :token] => :optional,
[token_transfers: :to_address] => :optional,
[token_transfers: :from_address] => :optional,
[token_transfers: :token_contract_address] => :optional,
:block => :required
}
]
@page_size 150
@paging_options %PagingOptions{page_size: @page_size + 1}
def export(address) do
address
|> fetch_all_transactions(@paging_options)
|> to_token_transfers()
|> to_csv_format(address)
|> dump_to_stream()
end
defp fetch_all_transactions(address, paging_options, acc \\ []) do
options = Keyword.merge(@necessity_by_association, paging_options: paging_options)
transactions =
address
|> Chain.address_to_transactions_with_rewards(options)
|> Enum.filter(fn transaction -> Enum.count(transaction.token_transfers) > 0 end)
new_acc = transactions ++ acc
case Enum.split(transactions, @page_size) do
{_transactions, [%Transaction{block_number: block_number, index: index}]} ->
new_paging_options = %{@paging_options | key: {block_number, index}}
fetch_all_transactions(address, new_paging_options, new_acc)
{_, []} ->
new_acc
end
end
defp to_token_transfers(transactions) do
transactions
|> Enum.flat_map(fn transaction ->
transaction.token_transfers
|> Enum.map(fn transfer -> %{transfer | transaction: transaction} end)
end)
end
defp dump_to_stream(transactions) do
transactions
|> RFC4180.dump_to_stream()
end
defp to_csv_format(token_transfers, address) do
row_names = [
"TxHash",
"BlockNumber",
"UnixTimestamp",
"FromAddress",
"ToAddress",
"TokenContractAddress",
"Type",
"TokenSymbol",
"TokensTransferred",
"TransactionFee",
"Status",
"ErrCode"
]
token_transfer_lists =
token_transfers
|> Stream.map(fn token_transfer ->
[
to_string(token_transfer.transaction_hash),
token_transfer.transaction.block_number,
token_transfer.transaction.block.timestamp,
to_string(token_transfer.from_address),
to_string(token_transfer.to_address),
to_string(token_transfer.token_contract_address),
type(token_transfer, address),
token_transfer.token.symbol,
token_transfer.amount,
fee(token_transfer.transaction),
token_transfer.transaction.status,
token_transfer.transaction.error
]
end)
Stream.concat([row_names], token_transfer_lists)
end
defp type(%TokenTransfer{from_address_hash: from_address}, %Address{hash: from_address}), do: "OUT"
defp type(%TokenTransfer{to_address_hash: to_address}, %Address{hash: to_address}), do: "IN"
defp type(_, _), do: ""
defp fee(transaction) do
transaction
|> Chain.fee(:wei)
|> case do
{:actual, value} -> value
{:maximum, value} -> "Max of #{value}"
end
end
end

@ -92,6 +92,7 @@ defmodule Explorer.Mixfile do
{:mock, "~> 0.3.0", only: [:test], runtime: false},
{:mox, "~> 0.4", only: [:test]},
{:poison, "~> 3.1"},
{:nimble_csv, "~> 0.6.0"},
{:postgrex, ">= 0.0.0"},
# For compatibility with `prometheus_process_collector`, which hasn't been updated yet
{:prometheus, "~> 4.0", override: true},

@ -0,0 +1,72 @@
defmodule Explorer.Chain.AddressTokenTransferCsvExporterTest do
use Explorer.DataCase
alias Explorer.Chain.AddressTokenTransferCsvExporter
describe "export/1" do
test "exports token transfers to csv" do
address = insert(:address)
transaction =
:transaction
|> insert(from_address: address)
|> with_block()
token_transfer = insert(:token_transfer, transaction: transaction, from_address: address)
[result] =
address
|> AddressTokenTransferCsvExporter.export()
|> Enum.to_list()
|> Enum.drop(1)
|> Enum.map(fn [
tx_hash,
_,
block_number,
_,
timestamp,
_,
from_address,
_,
to_address,
_,
token_contract_address,
_,
type,
_,
token_symbol,
_,
tokens_transferred,
_,
transaction_fee,
_,
status,
_,
err_code,
_
] ->
%{
tx_hash: tx_hash,
block_number: block_number,
timestamp: timestamp,
from_address: from_address,
to_address: to_address,
token_contract_address: token_contract_address,
type: type,
token_symbol: token_symbol,
tokens_transferred: tokens_transferred,
transaction_fee: transaction_fee,
status: status,
err_code: err_code
}
end)
assert result.block_number == to_string(transaction.block_number)
assert result.tx_hash == to_string(transaction.hash)
assert result.from_address == to_string(token_transfer.from_address_hash)
assert result.to_address == to_string(token_transfer.to_address_hash)
assert result.timestamp == to_string(transaction.block.timestamp)
assert result.type == "OUT"
end
end
end

@ -73,6 +73,7 @@
"mock": {:hex, :mock, "0.3.2", "e98e998fd76c191c7e1a9557c8617912c53df3d4a6132f561eb762b699ef59fa", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"mox": {:hex, :mox, "0.4.0", "7f120840f7d626184a3d65de36189ca6f37d432e5d63acd80045198e4c5f7e6e", [:mix], [], "hexpm"},
"msgpax": {:hex, :msgpax, "2.2.2", "559a07806bbe5fdd31e4597455be030bd96356f7a621ca9eed832747c83bfb67", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"},
"nimble_csv": {:hex, :nimble_csv, "0.6.0", "a3673f26d41f986774fe6060e309615343d3cb83a6d435754d8b1fdbd5764879", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
"optimal": {:hex, :optimal, "0.3.6", "46bbf52fbbbd238cda81e02560caa84f93a53c75620f1fe19e81e4ae7b07d1dd", [:mix], [], "hexpm"},
"parallel_stream": {:hex, :parallel_stream, "1.0.6", "b967be2b23f0f6787fab7ed681b4c45a215a81481fb62b01a5b750fa8f30f76c", [:mix], []},

Loading…
Cancel
Save