defmodule BitcoinLib.Key.HD.DerivationPath.Parser.Change do
@moduledoc """
Determines which change chain is being used, either receiving or change.
This is a hardened value.
See: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#change
"""
@receiving_chain "0"
@receiving_chain_value 0
@receiving_chain_atom :receiving_chain
@change_chain "1"
@change_chain_value 1
@change_chain_atom :change_chain
@doc """
Converts a list of path levels managed up until the change chain, extracts
the change chain and returns the remaining levels
## Examples
iex> ["1", "2", "3"]
...> |> BitcoinLib.Key.HD.DerivationPath.Parser.Change.extract()
{:ok, :change_chain, ["2", "3"]}
"""
@spec extract(list()) :: {:ok, nil, []} | {:ok, atom(), list()} | {:error, binary()}
def extract([]), do: {:ok, nil, []}
def extract([change_chain | rest]) do
change_chain
|> String.trim()
|> convert(rest)
end
def get_atom(@receiving_chain_value), do: @receiving_chain_atom
def get_atom(@change_chain_value), do: @change_chain_atom
defp convert(@receiving_chain, rest), do: {:ok, @receiving_chain_atom, rest}
defp convert(@change_chain, rest), do: {:ok, @change_chain_atom, rest}
defp convert(change, _rest) do
message =
case String.ends_with?(change, "'") do
true -> "change chain must NOT be a hardened value"
false -> "#{change} is not a valid change chain"
end
{:error, message}
end
end