Skip to content

Commit

Permalink
feat: send operations to RPC node
Browse files Browse the repository at this point in the history
  • Loading branch information
vhf committed May 2, 2024
1 parent 7d8f1c3 commit b3699a3
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 1 deletion.
17 changes: 17 additions & 0 deletions lib/application.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule Tezex.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false

use Application

@impl true
def start(_type, _args) do
children = [{Finch, name: Tezex.Finch}]

# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Tezex.Supervisor]
Supervisor.start_link(children, opts)
end
end
89 changes: 89 additions & 0 deletions lib/rpc.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
defmodule Tezex.Rpc do
alias Tezex.ForgeOperation
alias Tezex.Rpc
alias Tezex.Transaction

@type t() :: %__MODULE__{
endpoint: binary(),
chain_id: binary(),
headers: Finch.Request.headers(),
opts: Finch.request_opts()
}

defstruct [:endpoint, chain_id: "main", headers: [], opts: []]

def send_contract_operation(
%Rpc{} = rpc,
public_key_hash,
counter,
contract,
amount,
fee,
storage_limit,
gas_limit,
entrypoint,
parameters
) do
parameters =
cond do
not is_nil(parameters) -> %{entrypoint: entrypoint || "default", value: parameters}
not is_nil(entrypoint) -> %{entrypoint: entrypoint, value: []}
true -> nil
end

tx = %Transaction{
source: public_key_hash,
destination: contract,
amount: Integer.to_string(amount),
storage_limit: Integer.to_string(storage_limit),
gas_limit: Integer.to_string(gas_limit),
counter: Integer.to_string(counter),
fee: Integer.to_string(fee),
kind: "transaction",
parameters: parameters
}
end

def send_operation(%Rpc{} = rpc, operations, signer, offset) do
{:ok, block_head} = get_block_at_offset(rpc, offset)
block_hash = binary_part(block_head["hash"], 0, 51)

forged_operation_group =
ForgeOperation.forge_operation_group(%{"branch" => block_hash, "contents" => operations})
end

def get_counter_for_account(%Rpc{} = rpc, address) do
with {:ok, n} <- get(rpc, "/blocks/head/context/contracts/#{address}/counter"),
{n, ""} <- Integer.parse(n) do
n
end
end

def get_block(%Rpc{} = rpc, hash \\ "head") do
get(rpc, "/blocks/#{hash}")
end

def get_block_at_offset(%Rpc{} = rpc, offset) do
if offset <= 0 do
get_block(rpc)
end

{:ok, head} = get_block(rpc)
get(rpc, "/blocks/#{head["header"]["level"] - offset}")
end

def get(%Rpc{} = rpc, path) do
url =
URI.parse(rpc.endpoint)
|> URI.append_path("/chains/#{rpc.chain_id}")
|> URI.append_path(path)
|> URI.to_string()

Finch.build(:get, url, rpc.headers)
|> Finch.request(Tezex.Finch, rpc.opts)
|> case do
{:ok, %Finch.Response{status: 200, body: body}} -> Jason.decode(body)
{:error, _} = err -> err
end
end
end
53 changes: 53 additions & 0 deletions lib/transaction.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
defmodule Tezex.Transaction do
alias Tezex.Transaction

@type t() :: %__MODULE__{
source: binary() | nil,
destination: binary(),
fee: pos_integer() | nil,
counter: integer() | nil,
gas_limit: pos_integer() | nil,
amount: pos_integer() | nil,
destination: binary(),
storage_limit: pos_integer() | nil,
parameters: map() | nil
}

defstruct [
:kind,
:destination,
:source,
fee: 0,
counter: 0,
gas_limit: 0,
amount: 0,
storage_limit: 0,
parameters: nil
]

defimpl Jason.Encoder do
def encode(%Transaction{parameters: nil} = transaction, opts) do
transaction
|> Map.from_struct()
|> Map.drop([:parameters])
|> encode(opts)
end

def encode(%Transaction{} = transaction, opts) do
transaction
|> Map.from_struct()
|> encode(opts)
end

def encode(value, opts) do
value
|> Map.put(:kind, "transaction")
|> Map.update!(:fee, &to_string/1)
|> Map.update!(:gas_limit, &to_string/1)
|> Map.update!(:amount, &to_string/1)
|> Map.update!(:storage_limit, &to_string/1)
|> Map.update!(:counter, &to_string/1)
|> Jason.Encode.map(opts)
end
end
end
5 changes: 4 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ defmodule Tezex.MixProject do
description: description(),
package: package(),
deps: deps(),
start_permanent: Mix.env() == :prod,
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
coveralls: :test,
Expand Down Expand Up @@ -55,6 +56,7 @@ defmodule Tezex.MixProject do
# Run "mix help compile.app" to learn about applications.
def application do
[
mod: {Tezex.Application, []},
extra_applications: [:logger, :crypto]
]
end
Expand All @@ -68,7 +70,8 @@ defmodule Tezex.MixProject do
{:ex_doc, "~> 0.27", only: :dev, runtime: false},
{:ex_unit_notifier, "~> 1.2", only: :test},
{:excoveralls, "~> 0.15.1", only: :test},
{:jason, "~> 1.4", only: :test},
{:finch, "~> 0.10"},
{:jason, "~> 1.4"},
{:mix_test_watch, "~> 1.0", only: [:dev, :test], runtime: false},
{:ssl_verify_fun, "~> 1.1", manager: :rebar3, override: true}
]
Expand Down
8 changes: 8 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
%{
"base_58_check": {:hex, :base_58_check, "1.0.0", "bbe527bb00ffd9c5b03abdf970aefd9ca36bd3967dcd75efa8a3c2ed1dcec154", [:mix], [], "hexpm", "06b538938722a04680210e889edaf96f4c967251218fbfbafa19ec2702ba489c"},
"blake2": {:hex, :blake2, "1.0.4", "8263c69a191142922bc2510f1ffc0de0ae96e8c3bd5e2ad3fac7e87aed94c8b1", [:mix], [], "hexpm", "e9f4120d163ba14d86304195e50745fa18483e6ad2be94c864ae449bbdd6a189"},
"castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"},
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
Expand All @@ -9,17 +10,24 @@
"ex_unit_notifier": {:hex, :ex_unit_notifier, "1.3.0", "1d82aa6d2fb44e6f0f219142661a46e13dcba833e150e1395190d2e0fb721990", [:mix], [], "hexpm", "55fffd6062e8d962fc44e8b06fa30a87dc7251ee2a69f520781a3bb29858c365"},
"excoveralls": {:hex, :excoveralls, "0.15.3", "54bb54043e1cf5fe431eb3db36b25e8fd62cf3976666bafe491e3fa5e29eba47", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8eb5d8134d84c327685f7bb8f1db4147f1363c3c9533928234e496e3070114e"},
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
"hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
"mint": {:hex, :mint, "1.6.0", "88a4f91cd690508a04ff1c3e28952f322528934be541844d54e0ceb765f01d5e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "3c5ae85d90a5aca0a49c0d8b67360bbe407f3b54f1030a111047ff988e8fefaa"},
"mix_test_watch": {:hex, :mix_test_watch, "1.2.0", "1f9acd9e1104f62f280e30fc2243ae5e6d8ddc2f7f4dc9bceb454b9a41c82b42", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "278dc955c20b3fb9a3168b5c2493c2e5cffad133548d307e0a50c7f2cfbf34f6"},
"nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
}
17 changes: 17 additions & 0 deletions test/rpc_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule Tezex.RpcTest do
use ExUnit.Case, async: true

alias Tezex.Rpc
doctest Rpc

test "get_counter_for_account" do
# mock
# counter =
# Rpc.get_counter_for_account(
# %Rpc{endpoint: "https://rpc.tzkt.io/mainnet/"},
# "tz1LKpeN8ZSSFNyTWiBNaE4u4sjaq7J1Vz2z"
# )

# assert is_integer(counter)
end
end

0 comments on commit b3699a3

Please sign in to comment.