livebook / public-apps /helius_transaction_render.livemd
hugobarauna's picture
Create helius_transaction_render.livemd
15781db verified
raw
history blame
5.16 kB
<!-- livebook:{"app_settings":{"access_type":"public","output_type":"rich","slug":"helius-transaction-render"}} -->
# Helius Transaction Render
```elixir
Mix.install([
{:req, "~> 0.3.4"},
{:jason, "~> 1.4.0"},
{:kino, "~> 0.12.3"}
])
```
## Code Setup
This section includes all the Elixir code to fetch and render the given transaction
You don't need to edit any of it
```elixir
# Define transaction fetching logic
defmodule HeliusFetch do
def fetch_transaction(signature, api_key) do
transactions_url = "https://api.helius.xyz/v0/transactions"
Req.post!(
transactions_url,
params: ["api-key": api_key],
json: %{transactions: [signature]}
).body
|> List.first()
end
end
Kino.nothing()
```
````elixir
# Define transaction rendering logic
defmodule TransactionRender do
defp truncate(string, length) do
start = String.slice(string, 0, length)
last = String.slice(string, 0 - length, length)
start <> "..." <> last
end
defp render_summary(transaction) do
source = transaction["source"]
type = transaction["type"]
description = transaction["description"]
fee_payer = transaction["feePayer"]
Kino.Markdown.new("""
**Source**: #{source}
**Type**: #{type}
**Description**: #{description}
**Fee Payer**: [#{truncate(fee_payer, 8)}](https://explorer.solana.com/address/#{fee_payer})
""")
end
defp render_event(name, event) do
Kino.Markdown.new("""
### #{name}
```json
#{Jason.encode!(event, pretty: true)}
```
""")
end
defp render_events(transaction) do
events = transaction["events"]
case events do
%{} ->
Kino.Text.new("No events")
_ ->
events
|> Enum.map(fn {name, event} -> render_event(name, event) end)
|> Kino.Layout.grid()
end
end
defp native_transfer_diagram_line(transfer) do
from =
case transfer["fromUserAccount"] do
"" -> "none"
address -> truncate(address, 4)
end
to =
case transfer["toUserAccount"] do
"" -> "none"
address -> truncate(address, 4)
end
amount = (transfer["amount"] / 1_000_000_000) |> Float.round(4)
label = "#{amount} SOL"
# Mermaid diagram line starting with 2 spaces
" #{from}-...->|#{label}|#{to}"
end
defp render_native_transfers(transaction) do
native_transfers = transaction["nativeTransfers"]
case native_transfers do
[] ->
Kino.Text.new("No native transfers")
_ ->
diagram_lines =
native_transfers
|> Enum.filter(fn transfer -> transfer["amount"] > 0 end)
|> Enum.map(fn transfer -> native_transfer_diagram_line(transfer) end)
|> Enum.join("\n")
diagram = """
flowchart LR
#{diagram_lines}
"""
Kino.Mermaid.new(diagram)
end
end
defp token_transfer_diagram_line(transfer) do
from =
case transfer["fromUserAccount"] do
"" -> "none"
address -> truncate(address, 4)
end
to =
case transfer["toUserAccount"] do
"" -> "none"
address -> truncate(address, 4)
end
token_amount = transfer["tokenAmount"]
mint = truncate(transfer["mint"], 4)
label = "#{token_amount} #{mint}"
" #{from}-...->|#{label}|#{to}"
end
defp render_token_transfers(transaction) do
token_transfers = transaction["tokenTransfers"]
case token_transfers do
[] ->
Kino.Text.new("No token transfers")
_ ->
diagram_lines =
token_transfers
|> Enum.map(fn transfer -> token_transfer_diagram_line(transfer) end)
|> Enum.join("\n")
diagram = """
flowchart LR
#{diagram_lines}
"""
Kino.Mermaid.new(diagram)
end
end
def render(transaction) do
Kino.Layout.tabs(
Summary: render_summary(transaction),
Tree: Kino.Tree.new(transaction),
Events: render_events(transaction),
"Native Transfers": render_native_transfers(transaction),
"Token Transfers": render_token_transfers(transaction)
)
end
end
````
<!-- livebook:{"branch_parent_index":0} -->
## Fetch a transaction
```elixir
form =
Kino.Control.form(
[
signature: Kino.Input.text("Transaction Signature"),
api_key: Kino.Input.password("Helius API Key")
],
submit: "Fetch"
)
form |> Kino.render()
frame = Kino.Frame.new()
```
This next code block does all the magic
You just need to evaluate it :)
```elixir
Kino.listen(form, fn event ->
signature_length = byte_size(event.data.signature)
api_key_length = byte_size(event.data.api_key)
case {signature_length, api_key_length} do
{0, _} ->
Kino.Frame.render(
frame,
Kino.Markdown.new("**No transaction signature given**")
)
{_, 0} ->
Kino.Frame.render(
frame,
Kino.Markdown.new("**No Helius API key given**")
)
_ ->
transaction = HeliusFetch.fetch_transaction(event.data.signature, event.data.api_key)
Kino.Frame.render(frame, TransactionRender.render(transaction))
end
end)
```