Skip to content

Commit

Permalink
Adding command_payload_json type (#121)
Browse files Browse the repository at this point in the history
* Adding command_payload_json

* Fix requested changes

* Fix more requested changes

Co-authored-by: Jhonatan Hidalgo <jhonatan-kmt@users.noreply.github.com>
Co-authored-by: Santiago Botero <98826652+santiagoboterokommit@users.noreply.github.com>
  • Loading branch information
3 people committed Nov 3, 2022
1 parent 2080ee6 commit 01a0696
Show file tree
Hide file tree
Showing 6 changed files with 826 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ kadena-*.tar
/priv/plts

/.elixir_ls

/.vscode
208 changes: 208 additions & 0 deletions lib/types/command_payload_json.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
defmodule Kadena.Types.CommandPayloadJSON do
@moduledoc """
`CommandPayloadJSON` struct definition.
"""
alias Kadena.Utils.MapCase

alias Kadena.Types.{
Base16String,
Cap,
CapsList,
ChainID,
CommandPayload,
ContPayload,
EnvData,
ExecPayload,
MetaData,
NetworkID,
OptionalCapsList,
PactCode,
PactDecimal,
PactInt,
PactPayload,
PactTransactionHash,
PactValue,
PactValuesList,
Proof,
Rollback,
Signer,
SignersList,
Step
}

@behaviour Kadena.Types.Spec

@type json :: String.t()
@type signers_list :: SignersList.t()
@type signers :: list(map())
@type network_id :: NetworkID.t()
@type string_value :: String.t() | nil
@type pact_payload :: PactPayload.t()
@type proof :: Proof.t() | nil
@type data :: EnvData.t() | nil
@type meta :: MetaData.t()
@type signer :: Signer.t()
@type addr :: Base16String.t() | nil
@type scheme :: :ed25519 | nil
@type valid_scheme :: :ED25519 | nil
@type clist :: CapsList.t() | nil
@type valid_clist :: list(map())
@type cap :: Cap.t()
@type pact_values_list :: PactValuesList.t()
@type literal ::
integer()
| boolean()
| String.t()
| PactInt.t()
| PactDecimal.t()
| PactValuesList.t()
@type value :: integer() | string_value() | boolean() | Decimal.t()
@type valid_pact_value :: list(value)
@type pact_value :: list(valid_pact_value())
@type map_return :: map() | nil
@type valid_extract :: {:ok, string_value()} | {:ok, map_return()} | {:ok, signers()}

@type t :: %__MODULE__{json: json()}

defstruct [:json]

@impl true
def new(%CommandPayload{
network_id: network_id,
payload: payload,
signers: signers,
meta: meta,
nonce: nonce
}) do
with {:ok, payload} <- extract_payload(payload),
{:ok, meta} <- extract_meta(meta),
{:ok, network_id} <- extract_network_id(network_id),
{:ok, signers} <- extract_signers_list(signers) do
request_body =
%{
payload: payload,
meta: meta,
network_id: network_id,
nonce: nonce,
signers: signers
}
|> MapCase.to_camel!()
|> Jason.encode!()

%__MODULE__{json: request_body}
end
end

@spec extract_network_id(network_id()) :: valid_extract()
defp extract_network_id(%NetworkID{id: id}), do: {:ok, id}

@spec extract_payload(pact_payload()) :: valid_extract()
defp extract_payload(%PactPayload{payload: %ExecPayload{} = exec_payload}) do
%ExecPayload{code: %PactCode{code: code}, data: data} = exec_payload
payload = %{exec: %{code: code, data: extract_data(data)}}
{:ok, payload}
end

defp extract_payload(%PactPayload{
payload: %ContPayload{
data: data,
pact_id: %PactTransactionHash{hash: hash},
proof: proof,
rollback: %Rollback{value: rollback},
step: %Step{number: number}
}
}) do
payload = %{
cont: %{
data: extract_data(data),
pact_id: hash,
proof: extract_proof(proof),
roollback: rollback,
step: number
}
}

{:ok, payload}
end

@spec extract_proof(proof()) :: string_value()
defp extract_proof(nil), do: nil
defp extract_proof(%Proof{value: proof}), do: proof

@spec extract_data(data()) :: map_return()
defp extract_data(nil), do: nil
defp extract_data(%EnvData{data: data}), do: data

@spec extract_meta(meta()) :: valid_extract()
defp extract_meta(%MetaData{
creation_time: creation_time,
ttl: ttl,
gas_limit: gas_limit,
gas_price: gas_price,
sender: sender,
chain_id: %ChainID{id: id}
}) do
meta = %{
chain_id: id,
creation_time: creation_time,
gas_limit: gas_limit,
gas_price: gas_price,
sender: sender,
ttl: ttl
}

{:ok, meta}
end

@spec extract_signers_list(signers :: signers_list()) :: valid_extract()
defp extract_signers_list(%SignersList{signers: list}) do
signers = Enum.map(list, fn sig -> extract_signer_info(sig) end)
{:ok, signers}
end

@spec extract_signer_info(signer()) :: map_return()
defp extract_signer_info(%Signer{
addr: addr,
scheme: scheme,
pub_key: %Base16String{value: pub_key},
clist: %OptionalCapsList{clist: clist}
}) do
%{
addr: extract_addr(addr),
scheme: extract_scheme(scheme),
pub_key: pub_key,
clist: extract_clist(clist)
}
end

@spec extract_addr(addr()) :: string_value()
defp extract_addr(nil), do: nil
defp extract_addr(%Base16String{value: value}), do: value

@spec extract_scheme(scheme()) :: valid_scheme()
defp extract_scheme(nil), do: nil
defp extract_scheme(:ed25519), do: :ED25519

@spec extract_clist(clist()) :: valid_clist()
defp extract_clist(nil), do: []

defp extract_clist(%CapsList{caps: caps}) do
Enum.map(caps, fn cap -> extract_cap_info(cap) end)
end

@spec extract_cap_info(cap()) :: map_return()
defp extract_cap_info(%Cap{name: name, args: args}) do
%{name: name, args: extract_values(args)}
end

@spec extract_values(pact_values_list()) :: pact_value()
defp extract_values(%PactValuesList{pact_values: pact_values}) do
Enum.map(pact_values, fn %PactValue{literal: pact_value} -> extract_value(pact_value) end)
end

@spec extract_value(literal()) :: valid_pact_value()
defp extract_value(%PactValuesList{} = pact_value), do: extract_values(pact_value)
defp extract_value(%PactInt{raw_value: value}), do: value
defp extract_value(%PactDecimal{raw_value: value}), do: value
defp extract_value(value), do: value
end
63 changes: 63 additions & 0 deletions lib/utils/map_case.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
defmodule Kadena.Utils.MapCase do
@moduledoc """
`Utils.MapCase` functions to convert the keys of a map to camel or snake case
"""

@type key :: atom() | String.t()
@type opt :: :to_camel | :to_snake
@type string_value :: String.t()
@type value :: any()
@type words :: list(string_value())
@type valid_map :: {:ok, map()}
@type valid_format :: string_value() | map()

@spec to_camel(map :: map()) :: valid_map()
def to_camel(map) when is_map(map), do: {:ok, format(map, :to_camel)}

@spec to_camel!(map :: map()) :: map()
def to_camel!(map) when is_map(map), do: format(map, :to_camel)

@spec to_snake(map :: map()) :: valid_map()
def to_snake(map) when is_map(map), do: {:ok, format(map, :to_snake)}

@spec to_snake!(map :: map()) :: map()
def to_snake!(map) when is_map(map), do: format(map, :to_snake)

@spec format(map :: map(), type :: opt()) :: map()
defp format(%Decimal{} = decimal, _type), do: decimal

defp format(%{} = map, type) do
map
|> Enum.map(fn {k, v} -> {format_key(k, type), format_value(v, type)} end)
|> Enum.into(%{})
end

defp format(value, _type), do: value

@spec format_key(key :: key(), type :: opt()) :: string_value()
defp format_key(key, type) when is_atom(key),
do: key |> Atom.to_string() |> format_key(type)

defp format_key(key, :to_camel) when is_binary(key) do
if String.contains?(key, "_") do
[first_word | rest] = String.split(key, "_")
first_word <> camelize(rest)
else
key
end
end

defp format_key(key, :to_snake) when is_binary(key), do: Macro.underscore(key)

@spec format_value(value :: value(), type :: opt()) :: valid_format()
defp format_value(value, type) when is_map(value), do: format(value, type)

defp format_value(value, type) when is_list(value),
do: Enum.map(value, fn map -> format(map, type) end)

defp format_value(value, _type), do: value

@spec camelize(words :: words()) :: string_value()
defp camelize([]), do: ""
defp camelize([word | rest]), do: Macro.camelize(word) <> camelize(rest)
end
6 changes: 3 additions & 3 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
"credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"},
"earmark_parser": {:hex, :earmark_parser, "1.4.26", "f4291134583f373c7d8755566122908eb9662df4c4b63caa66a0eabe06569b0a", [:mix], [], "hexpm", "48d460899f8a0c52c5470676611c01f64f3337bad0b26ddab43648428d94aabc"},
"earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_doc": {:hex, :ex_doc, "0.28.5", "3e52a6d2130ce74d096859e477b97080c156d0926701c13870a4e1f752363279", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d2c4b07133113e9aa3e9ba27efb9088ba900e9e51caa383919676afdf09ab181"},
"ex_doc": {:hex, :ex_doc, "0.29.0", "4a1cb903ce746aceef9c1f9ae8a6c12b742a5461e6959b9d3b24d813ffbea146", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "f096adb8bbca677d35d278223361c7792d496b3fc0d0224c9d4bc2f651af5db1"},
"excoveralls": {:hex, :excoveralls, "0.15.0", "ac941bf85f9f201a9626cc42b2232b251ad8738da993cf406a4290cacf562ea4", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9631912006b27eca30a2f3c93562bc7ae15980afb014ceb8147dc5cdd8f376f1"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.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.3.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", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"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.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
Expand Down
Loading

0 comments on commit 01a0696

Please sign in to comment.