lib/ton/wallet.ex

defmodule Ton.Wallet do
  @moduledoc """
  Defines a wallet
  """

  alias Ton.Bitstring
  alias Ton.Boc
  alias Ton.Cell

  defstruct [:initial_code, :initial_data, :workchain, :wallet_id, :public_key]

  @type t :: %__MODULE__{
          initial_code: Cell.t(),
          initial_data: Cell.t(),
          workchain: integer(),
          wallet_id: integer(),
          public_key: binary()
        }

  @wallet_v4_source Base.decode64!(
                      "te6ccgECFAEAAtQAART/APSkE/S88sgLAQIBIAIDAgFIBAUE+PKDCNcYINMf0x/THwL4I7vyZO1E0NMf0x/T//QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/8QERITAubQAdDTAyFxsJJfBOAi10nBIJJfBOAC0x8hghBwbHVnvSKCEGRzdHK9sJJfBeAD+kAwIPpEAcjKB8v/ydDtRNCBAUDXIfQEMFyBAQj0Cm+hMbOSXwfgBdM/yCWCEHBsdWe6kjgw4w0DghBkc3RyupJfBuMNBgcCASAICQB4AfoA9AQw+CdvIjBQCqEhvvLgUIIQcGx1Z4MesXCAGFAEywUmzxZY+gIZ9ADLaRfLH1Jgyz8gyYBA+wAGAIpQBIEBCPRZMO1E0IEBQNcgyAHPFvQAye1UAXKwjiOCEGRzdHKDHrFwgBhQBcsFUAPPFiP6AhPLassfyz/JgED7AJJfA+ICASAKCwBZvSQrb2omhAgKBrkPoCGEcNQICEekk30pkQzmkD6f+YN4EoAbeBAUiYcVnzGEAgFYDA0AEbjJftRNDXCx+AA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYAIBIA4PABmtznaiaEAga5Drhf/AABmvHfaiaEAQa5DrhY/AAG7SB/oA1NQi+QAFyMoHFcv/ydB3dIAYyMsFywIizxZQBfoCFMtrEszMyXP7AMhAFIEBCPRR8qcCAHCBAQjXGPoA0z/IVCBHgQEI9FHyp4IQbm90ZXB0gBjIywXLAlAGzxZQBPoCFMtqEssfyz/Jc/sAAgBsgQEI1xj6ANM/MFIkgQEI9Fnyp4IQZHN0cnB0gBjIywXLAlAFzxZQA/oCE8tqyx8Syz/Jc/sAAAr0AMntVA=="
                    )

  @spec create(binary(), integer(), integer()) :: t()
  def create(public_key, workchain \\ 0, wallet_id \\ 698_983_191) do
    source_code = @wallet_v4_source |> Boc.parse() |> Enum.at(0)
    initial_data = Cell.new()

    data =
      initial_data.data
      |> Bitstring.write_uint(0, 32)
      |> Bitstring.write_uint(wallet_id, 32)
      |> Bitstring.write_binary(public_key)
      |> Bitstring.write_bit(0)

    initial_data = %{initial_data | data: data}

    %__MODULE__{
      initial_code: source_code,
      initial_data: initial_data,
      workchain: workchain,
      wallet_id: wallet_id,
      public_key: public_key
    }
  end

  @spec state_init_cell(t(), Cell.t() | nil) :: Cell.t()
  def state_init_cell(wallet, cell \\ nil) do
    cell = cell || Cell.new()

    data =
      cell.data
      # SplitDepth
      |> Bitstring.write_bit(0)
      # TickTock
      |> Bitstring.write_bit(0)
      # Code present
      |> Bitstring.write_bit(1)
      # data presense
      |> Bitstring.write_bit(1)
      # library
      |> Bitstring.write_bit(0)

    %{cell | refs: cell.refs ++ [wallet.initial_code, wallet.initial_data], data: data}
  end

  @spec hash(t()) :: binary()
  def hash(wallet) do
    wallet
    |> state_init_cell()
    |> Cell.hash()
  end
end