defmodule Polymarket.Submit do @moduledoc false # Internal helper — composes calldata + tx + RPC into a single # submission step. Used by the six public submit wrappers in # `Polymarket.ERC20`, `Polymarket.CTF`, and `Polymarket.Collateral`. # # This module is intentionally `@moduledoc false`. Callers who want # general contract-call submission — outside the six fixed surfaces # this SDK owns — should reach for `Polymarket.Tx` and # `Polymarket.RPC` directly. Locking the public submission surface to # the named wrappers gives the SDK room to add per-call validations # (e.g. `partition` shape checks for CTF) without breaking a generic # interface. alias Polymarket.{RPC, Tx} @signing_opts [:nonce, :gas_price, :gas_limit, :chain_id, :private_key] @doc false # Validates that every key in `required` is present in `opts`. # Returns `:ok` or `{:error, {:missing_option, key}}` for the first # missing key. Used by the submit wrappers to honor their advertised # `{:ok, _} | {:error, _}` contract instead of raising `KeyError`. @spec require_opts(keyword(), [atom()]) :: :ok | {:error, {:missing_option, atom()}} def require_opts(opts, required) when is_list(opts) and is_list(required) do case Enum.find(required, &(not Keyword.has_key?(opts, &1))) do nil -> :ok missing -> {:error, {:missing_option, missing}} end end @doc false @spec send_call(RPC.t(), String.t(), binary(), keyword()) :: {:ok, String.t()} | {:error, term()} def send_call(%RPC{} = rpc, contract, calldata, opts) when is_binary(contract) and is_binary(calldata) and is_list(opts) do with :ok <- require_opts(opts, @signing_opts) do tx = Tx.new( nonce: Keyword.fetch!(opts, :nonce), gas_price: Keyword.fetch!(opts, :gas_price), gas_limit: Keyword.fetch!(opts, :gas_limit), to: contract, value: Keyword.get(opts, :value, 0), data: calldata, chain_id: Keyword.fetch!(opts, :chain_id) ) signed = Tx.sign(tx, Keyword.fetch!(opts, :private_key)) RPC.send_raw_transaction(rpc, signed) end end end