Current section
Files
Jump to
Current section
Files
lib/sutra/cardano/transaction/output.ex
defmodule Sutra.Cardano.Transaction.Output do
@moduledoc """
Cardano Transaction Output
"""
alias Sutra.Cardano.Address
alias Sutra.Cardano.Asset
alias Sutra.Cardano.Script
alias Sutra.Cardano.Transaction.Datum
alias Sutra.Data.Cbor
alias Sutra.Utils
import Sutra.Utils, only: [maybe: 3]
use Sutra.Data
@type t() :: %__MODULE__{
address: Address.t(),
value: Asset.t(),
datum: Datum.t(),
reference_script: String.t() | nil
}
defdata do
data(:address, Address)
data(:value, Asset)
data(:datum, Datum)
data(:reference_script, ~OPTION(:string))
data(:datum_raw, :string, virtual: true)
end
def new(%Address{} = addr, %{} = value, opts \\ []) when is_list(opts) do
datum = opts[:datum] || Datum.no_datum()
%__MODULE__{
address: addr,
value: value,
datum: datum,
reference_script: opts[:reference_script],
datum_raw: opts[:datum_raw]
}
end
@doc """
decode CBOR data to Output
## CDDL
"""
def from_cbor([%CBOR.Tag{value: raw_addr} | [assets | dtm_hash]])
when is_binary(raw_addr) do
from_cbor([raw_addr | [assets | dtm_hash]])
end
def from_cbor([raw_addr | [assets | dtm_hash]]) when is_binary(raw_addr) do
%__MODULE__{
address: Address.Parser.decode(raw_addr),
value: Asset.from_cbor(assets),
datum: dtm_hash |> Utils.safe_head() |> Cbor.extract_value!() |> Datum.from_cbor(),
datum_raw: nil
}
end
def from_cbor(%{0 => %CBOR.Tag{tag: :bytes, value: addr_value}} = ops) do
ref_script = if is_nil(ops[3]), do: nil, else: Script.from_script_ref(ops[3])
%__MODULE__{
address: Address.Parser.decode(addr_value),
value: Asset.from_cbor(ops[1]),
datum: Datum.from_cbor(ops[2]),
reference_script: ref_script,
datum_raw: nil
}
end
@doc """
encode Output to CBOR data
## CDDL
"""
# Pre babbage Era Output
def to_cbor(%__MODULE__{datum: nil, reference_script: nil} = output) do
[
Address.to_cbor(output.address),
Asset.to_cbor(output.value)
]
end
def to_cbor(%__MODULE__{datum: %Datum{} = dtm, reference_script: nil} = output)
when dtm.kind != :inline_datum do
datum_cbor = if dtm.kind == :datum_hash, do: [Datum.to_cbor(dtm)], else: []
[
Address.to_cbor(output.address),
Asset.to_cbor(output.value)
] ++ datum_cbor
end
def to_cbor(%__MODULE__{} = output) do
Enum.reduce(Map.to_list(output), %{}, fn current_val, acc ->
case current_val do
{_, nil} ->
acc
{:address, addr_info} ->
Map.put(acc, 0, Address.to_cbor(addr_info))
{:value, asset_info} ->
Map.put(acc, 1, Asset.to_cbor(asset_info))
{:datum, datum_info} ->
datum_info
|> Datum.to_cbor(encoding: :datum_option)
|> maybe(acc, &Map.put(acc, 2, &1))
{:reference_script, script} ->
Map.put(acc, 3, Script.to_script_ref(script))
_ ->
acc
end
end)
end
def to_hex(%__MODULE__{} = output) do
output
|> __MODULE__.to_cbor()
|> CBOR.encode()
|> Base.encode16()
end
end