defmodule Stellar.TxBuild.SCAddress do @moduledoc """ `SCAddress` struct definition. """ import Stellar.TxBuild.Validations, only: [validate_account_id: 1] @behaviour Stellar.TxBuild.XDR alias StellarBase.XDR.{ SCAddressType, Hash, SCAddress } alias Stellar.TxBuild.AccountID @type validation :: {:ok, any()} | {:error, atom()} @type value :: binary() @type t :: %__MODULE__{ type: atom(), value: value() } @allowed_types ~w(account contract)a defstruct [:type, :value] @impl true def new(args, opts \\ nil) def new([{type, value}], _opts) when type in @allowed_types do with {:ok, _value} <- validate_sc_address({type, value}) do %__MODULE__{ type: type, value: value } end end def new(_args, _opts), do: {:error, :invalid_sc_address} @impl true def to_xdr(%__MODULE__{type: :account, value: value}) do type = SCAddressType.new(:SC_ADDRESS_TYPE_ACCOUNT) value |> AccountID.new() |> AccountID.to_xdr() |> SCAddress.new(type) end def to_xdr(%__MODULE__{type: :contract, value: value}) do type = SCAddressType.new(:SC_ADDRESS_contract) value |> Hash.new() |> SCAddress.new(type) end @spec validate_sc_address(tuple :: tuple()) :: validation() defp validate_sc_address({:account, value}) do case validate_account_id({:account, value}) do {:ok, account_id} -> {:ok, account_id} {:error, _reason} -> {:error, :invalid_account_id} end end defp validate_sc_address({:contract, value}) when is_binary(value), do: {:ok, value} defp validate_sc_address({:contract, _value}), do: {:error, :invalid_contract_hash} end