Skip to content

gasless: submit_deposit_wallet_create / _sync have no retry loop despite GASLESS_SUBMIT_RETRY_ATTEMPTS being imported #61

@Nexory

Description

@Nexory

Current code

src/polymarket/_internal/actions/relayer/gasless.py, lines 351–357 (async) and 562–568 (sync):

payload = {
    "type": RelayerTransactionType.WALLET_CREATE.value,
    "from": ctx.signer.address,
    "to": ctx.environment.wallet_derivation.deposit_wallet_factory,
    "metadata": metadata,
}
response = await submit_gasless(ctx.relayer, payload=payload)   # line 357 — no retry loop

Compare with prepare_gasless_transaction (lines 75–91), which wraps the same submit_gasless endpoint in a full retry loop:

for attempt in range(GASLESS_SUBMIT_RETRY_ATTEMPTS + 1):
    try:
        response = await _submit_for_wallet_type(ctx, payload, wallet_type)
        break
    except RateLimitError:
        if attempt < GASLESS_SUBMIT_RETRY_ATTEMPTS:
            await asyncio.sleep(GASLESS_SUBMIT_RETRY_DELAY)
            continue
        raise
    except Exception as e:
        if is_retryable_submit_error(e) and attempt < GASLESS_SUBMIT_RETRY_ATTEMPTS:
            await asyncio.sleep(GASLESS_SUBMIT_RETRY_DELAY)
            continue
        raise

GASLESS_SUBMIT_RETRY_ATTEMPTS and is_retryable_submit_error are imported at lines 27–28 of the same file but are never referenced in either submit_deposit_wallet_create or submit_deposit_wallet_create_sync.

Reproduction

Call setup_gasless_wallet (secure.py:2027) when the relayer is under load or briefly rate-limiting:

  1. Relayer returns a RateLimitError (HTTP 429) or a wallet-busy/nonce-mismatch 400 during the single submit_gasless call inside submit_deposit_wallet_create.
  2. The exception propagates immediately — no retry is attempted.
  3. The entire wallet-deployment flow fails, requiring the caller to restart from scratch.

With prepare_gasless_transaction the same error class is transparently retried up to GASLESS_SUBMIT_RETRY_ATTEMPTS times with the configured back-off, so the inconsistency is directly observable if you trigger both paths under the same transient relayer condition.

Impact

  • Wallet deployment is disproportionately fragile compared to trade submission. A single transient 429 or wallet-busy response kills setup_gasless_wallet entirely, while the same error during a regular gasless trade is silently retried.
  • The WALLET_CREATE payload has no nonce field (lines 351–356 / 562–567), making it fully idempotent — there is no correctness reason to avoid retrying it unchanged.
  • All commits since the functions were introduced add only docs/credential/dependency changes; no commit has ever added retry logic to the WALLET_CREATE path. The imported symbols going unused is a clear oversight.

Suggested fix

Wrap the submit_gasless call in both submit_deposit_wallet_create and submit_deposit_wallet_create_sync in the same retry pattern already used by prepare_gasless_transaction / prepare_gasless_transaction_sync (lines 392–408 for the sync counterpart). Since the payload is nonce-free it can be resubmitted unchanged on every attempt:

for attempt in range(GASLESS_SUBMIT_RETRY_ATTEMPTS + 1):
    try:
        response = await submit_gasless(ctx.relayer, payload=payload)
        break
    except RateLimitError:
        if attempt < GASLESS_SUBMIT_RETRY_ATTEMPTS:
            await asyncio.sleep(GASLESS_SUBMIT_RETRY_DELAY)
            continue
        raise
    except Exception as e:
        if is_retryable_submit_error(e) and attempt < GASLESS_SUBMIT_RETRY_ATTEMPTS:
            await asyncio.sleep(GASLESS_SUBMIT_RETRY_DELAY)
            continue
        raise

Apply the equivalent synchronous pattern to submit_deposit_wallet_create_sync at line 568.

Related

  • prepare_gasless_transaction (async, lines 75–91) and prepare_gasless_transaction_sync (sync, lines 392–408) — the retry pattern to replicate
  • Verified against HEAD commit 588d664; no open or closed issue/PR covers this path

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