Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/polymarket/_internal/actions/orders/limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def validate_limit_order_params(
if expiration < 0:
raise UserInputError("expiration must be a non-negative integer.")
minimum = int(time.time()) + _MIN_EXPIRATION_BUFFER_S
if expiration <= minimum:
if expiration < minimum:
raise UserInputError(
f"expiration must be at least {_MIN_EXPIRATION_BUFFER_S} seconds in the future."
)
Expand Down
11 changes: 10 additions & 1 deletion src/polymarket/clients/async_secure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,10 @@ async def create_limit_order(

Use :meth:`post_order` to submit the returned signed order, or
:meth:`place_limit_order` to create and post in one call.

When ``expiration`` is provided, it must be a Unix timestamp at least
60 seconds in the future. Use extra buffer for immediate submissions to
account for latency and clock skew.
"""
params = validate_limit_order_params(
token_id=token_id,
Expand Down Expand Up @@ -1690,7 +1694,12 @@ async def place_limit_order(
expiration: int | None = None,
builder_code: str | None = None,
) -> OrderResponse:
"""Create, sign, and post a limit order."""
"""Create, sign, and post a limit order.

When ``expiration`` is provided, it must be a Unix timestamp at least
60 seconds in the future. Use extra buffer for immediate submissions to
account for latency and clock skew.
"""
signed = await self.create_limit_order(
token_id=token_id,
price=price,
Expand Down
8 changes: 8 additions & 0 deletions src/polymarket/clients/secure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,10 @@ def create_limit_order(
Use :meth:`post_order` to submit the returned signed order, or
:meth:`place_limit_order` to create and post in one call.

When ``expiration`` is provided, it must be a Unix timestamp at least
60 seconds in the future. Use extra buffer for immediate submissions to
account for latency and clock skew.

Raises:
UserInputError: If order parameters are invalid.
SigningError: If the order cannot be signed.
Expand Down Expand Up @@ -1540,6 +1544,10 @@ def place_limit_order(
) -> OrderResponse:
"""Create, sign, and post a limit order.

When ``expiration`` is provided, it must be a Unix timestamp at least
60 seconds in the future. Use extra buffer for immediate submissions to
account for latency and clock skew.

Raises:
UserInputError: If order parameters are invalid.
InsufficientAllowanceError: If required allowance cannot be recovered.
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/test_order_limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,36 @@ def test_validate_limit_order_params_rejects_near_expiration() -> None:
)


def test_validate_limit_order_params_rejects_expiration_below_minimum(
monkeypatch: pytest.MonkeyPatch,
) -> None:
now = 1_700_000_000
monkeypatch.setattr("polymarket._internal.actions.orders.limit.time.time", lambda: now)
with pytest.raises(UserInputError, match="60 seconds"):
validate_limit_order_params(
token_id="8501497",
price="0.5",
size="10",
side="BUY",
expiration=now + 59,
)


def test_validate_limit_order_params_accepts_minimum_expiration_boundary(
monkeypatch: pytest.MonkeyPatch,
) -> None:
now = 1_700_000_000
monkeypatch.setattr("polymarket._internal.actions.orders.limit.time.time", lambda: now)
params = validate_limit_order_params(
token_id="8501497",
price="0.5",
size="10",
side="BUY",
expiration=now + 60,
)
assert params.expiration == now + 60


def test_validate_limit_order_params_accepts_far_expiration() -> None:
params = validate_limit_order_params(
token_id="8501497",
Expand Down
Loading