defmodule Stellar.TxBuild.Ledger.ContractData do @moduledoc """ `ContractData` struct definition. """ import Stellar.TxBuild.Validations, only: [validate_address: 1] alias Stellar.TxBuild.{SCAddress, SCVal} alias StellarBase.XDR.{ContractEntryBodyType, ContractDataDurability, LedgerKeyContractData} @behaviour Stellar.TxBuild.XDR @type error :: {:error, atom()} @type validation :: {:ok, any()} | error() @type contract :: SCAddress.t() @type key :: SCVal.t() @type durability :: :temporary | :persistent @type body_type :: :data_entry | :expiration_ext @type t :: %__MODULE__{ contract: contract(), key: key(), durability: durability(), body_type: body_type() } defstruct [:contract, :key, :durability, :body_type] @allowed_durabilities ~w(temporary persistent)a @allowed_body_types ~w(data_entry expiration_ext)a @impl true def new(args, opts \\ []) def new( [ {:contract, contract}, {:key, key}, {:durability, durability}, {:body_type, body_type} ], _opts ) when durability in @allowed_durabilities and body_type in @allowed_body_types do with {:ok, contract} <- validate_address(contract), {:ok, key} <- validate_sc_val_ledger_instance(key) do %__MODULE__{ contract: contract, key: key, durability: durability, body_type: body_type } end end def new(_value, _opts), do: {:error, :invalid_ledger_key_args} @impl true def to_xdr(%__MODULE__{ contract: contract, key: key, durability: durability, body_type: body_type }) do key = SCVal.to_xdr(key) durability = durability_to_xdr(durability) body_type = body_type_to_xdr(body_type) contract |> SCAddress.to_xdr() |> LedgerKeyContractData.new(key, durability, body_type) end def to_xdr(_struct), do: {:error, :invalid_struct} @spec validate_sc_val_ledger_instance(key :: key()) :: validation() defp validate_sc_val_ledger_instance(%SCVal{} = key), do: {:ok, key} defp validate_sc_val_ledger_instance(_key), do: {:error, :invalid_key} @spec durability_to_xdr(atom()) :: ContractDataDurability.t() defp durability_to_xdr(:temporary), do: ContractDataDurability.new(:TEMPORARY) defp durability_to_xdr(:persistent), do: ContractDataDurability.new(:PERSISTENT) @spec body_type_to_xdr(atom()) :: ContractEntryBodyType.t() defp body_type_to_xdr(:data_entry), do: ContractEntryBodyType.new(:DATA_ENTRY) defp body_type_to_xdr(:expiration_ext), do: ContractEntryBodyType.new(:EXPIRATION_EXTENSION) end