defmodule Stellar.Horizon.Operation do
@moduledoc """
Represents a `Operation` resource from Horizon API.
"""
@behaviour Stellar.Horizon.Resource
alias Stellar.Horizon.{Mapping, Transaction}
alias Stellar.Horizon.Operation.{
AccountMerge,
AllowTrust,
BeginSponsoringFutureReserves,
BumpSequence,
ChangeTrust,
CreateAccount,
CreateClaimableBalance,
ClaimClaimableBalance,
CreatePassiveSellOffer,
EndSponsoringFutureReserves,
LiquidityPoolDeposit,
LiquidityPoolWithdraw,
ManageBuyOffer,
ManageSellOffer,
ManageData,
PathPaymentStrictReceive,
PathPaymentStrictSend,
Payment,
RevokeSponsorship,
SetOptions
}
@type body ::
AccountMerge.t()
| AllowTrust.t()
| BeginSponsoringFutureReserves.t()
| BumpSequence.t()
| ChangeTrust.t()
| CreateAccount.t()
| CreateClaimableBalance.t()
| ClaimClaimableBalance.t()
| CreatePassiveSellOffer.t()
| EndSponsoringFutureReserves.t()
| LiquidityPoolDeposit.t()
| LiquidityPoolWithdraw.t()
| ManageBuyOffer.t()
| ManageSellOffer.t()
| ManageData.t()
| PathPaymentStrictReceive.t()
| PathPaymentStrictSend.t()
| Payment.t()
| RevokeSponsorship.t()
| SetOptions.t()
@type t :: %__MODULE__{
id: String.t(),
paging_token: String.t(),
source_account: String.t(),
type_i: non_neg_integer(),
type: String.t(),
transaction_hash: String.t(),
transaction_successful: boolean(),
body: body(),
transaction: Transaction.t() | nil,
created_at: DateTime.t()
}
defstruct [
:id,
:paging_token,
:source_account,
:type,
:type_i,
:transaction_hash,
:transaction_successful,
:body,
:transaction,
:created_at
]
@mapping [
id: :integer,
type_i: :integer,
transaction: {:struct, Transaction},
created_at: :date_time
]
@impl true
def new(attrs, opts \\ [])
def new(attrs, _opts) do
mapping =
attrs
|> Map.get(:type)
|> operation_type_mapping()
attrs
|> operation_attrs()
|> (&Mapping.build(%__MODULE__{}, &1)).()
|> Mapping.parse(mapping)
end
@spec operation_attrs(attrs :: map()) :: map()
defp operation_attrs(attrs) do
body_attrs =
%__MODULE__{}
|> Map.from_struct()
|> Map.keys()
|> (&Map.drop(attrs, &1 ++ [:_links])).()
Map.put(attrs, :body, body_attrs)
end
@spec operation_type_mapping(type :: any()) :: Keyword.t()
defp operation_type_mapping(nil), do: @mapping
defp operation_type_mapping(type),
do: Keyword.merge(@mapping, body: {:struct, operation_type(type)})
@spec operation_type(type :: String.t()) :: module()
defp operation_type("create_account"), do: CreateAccount
defp operation_type("payment"), do: Payment
defp operation_type("path_payment_strict_receive"), do: PathPaymentStrictReceive
defp operation_type("path_payment_strict_send"), do: PathPaymentStrictSend
defp operation_type("manage_sell_offer"), do: ManageSellOffer
defp operation_type("manage_buy_offer"), do: ManageBuyOffer
defp operation_type("create_passive_sell_offer"), do: CreatePassiveSellOffer
defp operation_type("set_options"), do: SetOptions
defp operation_type("change_trust"), do: ChangeTrust
defp operation_type("allow_trust"), do: AllowTrust
defp operation_type("account_merge"), do: AccountMerge
defp operation_type("manage_data"), do: ManageData
defp operation_type("bump_sequence"), do: BumpSequence
defp operation_type("create_claimable_balance"), do: CreateClaimableBalance
defp operation_type("claim_claimable_balance"), do: ClaimClaimableBalance
defp operation_type("begin_sponsoring_future_reserves"), do: BeginSponsoringFutureReserves
defp operation_type("end_sponsoring_future_reserves"), do: EndSponsoringFutureReserves
defp operation_type("revoke_sponsorship"), do: RevokeSponsorship
defp operation_type("liquidity_pool_deposit"), do: LiquidityPoolDeposit
defp operation_type("liquidity_pool_withdraw"), do: LiquidityPoolWithdraw
end