PM’s signer pre-arm gauntlet must confirm PM_SIGNER_KEY controls the configured maker_proxy. The original CREATE2-derivation check only knew two Polymarket factory schemes and silently failed for Deposit Wallet proxies, leaving live execution inert. Fix: verify the proxy’s on-chain owner() instead of deriving it.

For Agents

Code: crates/position_manager/src/signer_arm.rs (arm_signer). New helpers: clob::proxy_owner_lower + a pure decode helper, mirroring the reqwest eth_call pattern in crates/position_manager/src/onchain.rs. The check now reads maker_proxy.owner() (selector 0x8da5cb5b) over POLYGON_RPC_URL and compares to the signer EOA; CREATE2 email-derivation kept as fallback. SigningClient::connect carries no RPC URL (CLOB HTTP auth only) — the RPC call goes through the dedicated reqwest path.

Symptoms

  • Log line: signer pre-arm FAILED (proxy) — LIVE disabled, running unsigned.
  • Live execution silently inert: PM reserves, then fails no signer, never POSTs an order, no money moves.
  • Reproduced on the “Bandi” account: proxy 0xdb0d23c2c3468da13c6e8abfe96edfecc72d9efe, owned on-chain by EOA 0xfa7772b9aA1230a53D3BEA9a11f5c52f110684f7.

Root Cause — Polymarket has THREE wallet types, not two

The pre-arm proxy check CREATE2-derived the proxy from the signer EOA using only two factories vendored from rs-clob-client-v2 / polymarket-clob:

Wallet typeFactorySaltInit-code hash
Email / Magic0xaB45c5A4B0c941a2F231C04C3f49182e1A254052keccak256(eoa)PROXY_INIT_CODE_HASH
Gnosis Safe0xaacFeEa03eb1561C4e67d661e40682Bd20E3541bkeccak256(padded eoa)SAFE_INIT_CODE_HASH

The third type was unaccounted for:

The Deposit Wallet

Factory 0x00000000000Fb5C9ADea0298D729A0CB3823Cc07 (“Polymarket: Deposit Wallet Factory Proxy”) deploys an EIP-1167 minimal proxy pointing at impl 0x58ca52ebe0dadfdf531cde7062e76746de4db1eb (“Polymarket: Deposit Wallet Impl”). Its CREATE2 salt / init-code do not follow the standard EIP-1167 + keccak256(eoa) scheme — an off-chain reconstruction did not reproduce the address. So neither hardcoded factory can derive a Deposit Wallet proxy, and the pre-arm proxy check always failed for these accounts.

How it was root-caused

  1. Read the proxy’s creation tx (0xe0965457…) on Polygonscan.
  2. The From / factory address + WalletDeployed + OwnershipTransferred events gave the deploying factory and the owner EOA.
  3. Computed all four candidates off-chain (proxy ⨉ safe schemes ⨉ candidate EOAs) — none matched the real proxy address, confirming a non-standard derivation.

The Fix — verify ownership, don’t derive the address

Instead of replicating each factory’s CREATE2 (brittle, breaks on any new factory), the pre-arm now asks the chain who owns the proxy:

  • eth_call maker_proxy.owner() (selector 0x8da5cb5b) via POLYGON_RPC_URL.
  • Assert the returned address (lowercased) == signer EOA.
  • CREATE2 email-derivation retained as a fallback.
  • Added a diagnostic warn! on failure logging onchain_owner / derived_email_proxy / expected_proxypublic addresses only, never the key.

This is correct for all Polymarket wallet types (email/Magic, Gnosis Safe, Deposit Wallet, and any future type) and is not coupled to factory addresses or init-code hashes.

Operator Lesson

PM_SIGNER_KEY must be the EOA private key that on-chain owns the configured maker_proxy. The signer EOA is NOT the proxy address — the proxy is a contract. Verify ownership via the proxy’s owner() / the WalletDeployed event, never by assuming a CREATE2 scheme.

Side Note — DRPC WSS flapping (env-only fix, same session)

The DRPC ogws WSS endpoint flapped ~1 reconnect/min (Connection reset without closing handshake). Fixed by swapping POLYGON_WSS_URL to Alchemy (wss://polygon-mainnet.g.alchemy.com/v2/...) for both PM self-watch and cohort firstmover — env-only, no code change. The self-watch logs subscription is narrow (filtered to the CTF Exchange + OrderFilled + watched-wallet topics), so Alchemy bandwidth is minimal.