Skip to content

PrepareLimitOrderParamsSchema: off-by-one between GTD expiration check and error message #66

@Nexory

Description

@Nexory

In packages/client/src/actions/orders/limit.ts:37-46, the GTD expiration check uses <=:

const minimumExpiration = Math.floor(Date.now() / 1000) + 60;

if (params.expiration <= minimumExpiration) {
  context.addIssue({
    code: 'custom',
    message: 'Expiration must be at least 60 seconds in the future.',
    path: ['expiration'],
  });
}

The condition rejects expiration == now + 60, so the actual required value is expiration > now + 60 (strictly more than 60 seconds). The error message says "at least 60 seconds in the future", which suggests expiration >= now + 60 is acceptable.

A user passing expiration = Math.floor(Date.now() / 1000) + 60 (literally matching the documented contract) hits a Zod validation error.

This is the same off-by-one that was fixed in py-sdk via Polymarket/py-sdk#46 (closing py-sdk#44).

Suggested fix

Tighten the comparison to < to align with the documented contract and the CLOB server-side rule (which the py-sdk fix confirmed is inclusive at the 60-second boundary):

if (params.expiration < minimumExpiration) {

Worth also mirroring the docstring note added in py-sdk 20c9600 on the public createLimitOrder / placeLimitOrder surface so users know to add their own buffer for network latency and clock skew on top of the 60s minimum.

Happy to send a small PR once external PRs are accepted.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions