defmodule Polymarket.Schemas.NewMarketEvent do @moduledoc """ New market event. Announces a freshly created market on the websocket feed. """ use TypedEctoSchema alias Polymarket.JsonUtil alias Polymarket.Schemas.Coerce alias Polymarket.Schemas.EventMessage alias Polymarket.Schemas.FeeSchedule @primary_key false @derive Jason.Encoder typed_embedded_schema do field(:id, :string) field(:active, :boolean) field(:line, :string) field(:description, :string) field(:question, :string) field(:market, :string) field(:condition_id, :string) field(:slug, :string) # Assumed to be an array of tag strings; only seen empty so far. field(:tags, {:array, :string}) field(:clob_token_ids, {:array, :string}) field(:assets_ids, {:array, :string}) field(:outcomes, {:array, :string}) field(:taker_base_fee, :integer) field(:order_price_min_tick_size, :float) field(:fees_enabled, :boolean) field(:group_item_title, :string) # Empty string in samples; kept as a string since the populated format is # unknown (Gamma models the equivalent field as a datetime). field(:game_start_time, :string) field(:sports_market_type, :string) # Unix epoch in milliseconds, delivered as a string (e.g. "1779660930454"). field(:timestamp, :integer) field(:event_type, :string) embeds_one(:fee_schedule, FeeSchedule) embeds_one(:event_message, EventMessage) end @required [:id, :market, :condition_id, :timestamp, :event_type] @doc """ Builds a `NewMarketEvent` from a decoded (atom-keyed) websocket message, coercing each value to its field type. Returns `{:error, {:missing_fields, fields}}` when a required field is absent. """ @spec from_attrs(map()) :: {:ok, t()} | {:error, {:missing_fields, [atom()]}} def from_attrs(attrs) do attrs = JsonUtil.snake_case_keys(attrs) %__MODULE__{ id: attrs["id"], active: attrs["active"], line: attrs["line"], description: attrs["description"], question: attrs["question"], market: attrs["market"], condition_id: attrs["condition_id"], slug: attrs["slug"], tags: attrs["tags"], clob_token_ids: attrs["clob_token_ids"], assets_ids: attrs["assets_ids"], outcomes: attrs["outcomes"], taker_base_fee: Coerce.to_int(attrs["taker_base_fee"]), order_price_min_tick_size: Coerce.to_float(attrs["order_price_min_tick_size"]), fees_enabled: attrs["fees_enabled"], group_item_title: attrs["group_item_title"], game_start_time: attrs["game_start_time"], sports_market_type: attrs["sports_market_type"], timestamp: Coerce.to_int(attrs["timestamp"]), event_type: attrs["event_type"], fee_schedule: Coerce.embed(FeeSchedule, attrs["fee_schedule"]), event_message: Coerce.embed(EventMessage, attrs["event_message"]) } |> Coerce.require_fields(@required) end end