Deposit Wallet Lifecycle
The deposit wallet has a defined lifecycle. Polygolem handles every phase, and go-bot’s live loop automates the full startup sequence so a restart always recovers to a ready state.
Lifecycle Phases
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ DERIVE │ ──→ │ DEPLOY │ ──→ │ APPROVE │ ──→ │ FUND │ │ (offline)│ │ (relayer)│ │ (relayer)│ │ (onchain)│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ └───────────────────────────────────────────────────▼ ┌──────────┐ ┌──────────┐ │ TRADE │ ──→ │ REDEEM │ │ (CLOB) │ │ (relayer)│ └──────────┘ └──────────┘Phase 1: Derive (offline, always succeeds)
The deposit wallet address is computed from the EOA address using CREATE2. No network calls. The same EOA always produces the same address.
wallet = CreateAddress2( factory = 0x00000000000Fb5C9ADea0298D729A0CB3823Cc07, salt = keccak256(abi.encode(factory, LeftPad32(EOA))), hash = keccak256(proxyInitCode))Phase 2: Deploy (relayer, idempotent)
The relayer deploys a clone proxy via the deposit wallet factory and funds the deployment gas. The go-bot checks deployment status before submitting.
WALLET-CREATE { from: <EOA>, to: <factory> }On-chain code is the source of truth. The relayer’s
/deployedendpoint can returnfalseeven when the deposit wallet is fully deployed on Polygon (for example, after a staleWALLET-CREATErow markedSTATE_FAILEDdespite the underlying transaction landing). Polygolem and the go-bot SDK both fall back toeth_getCodeat the derived address; if bytecode exists, the wallet is treated as deployed andWALLET-CREATEis skipped.polygolem deposit-wallet status --jsonexposes which path answered viarelayerDeployed,onchainCodeDeployed, anddeploymentStatusSource.
Phase 3: Fund (onchain)
pUSD must be transferred from the EOA to the deposit wallet. The EOA’s pUSD balance does not count for deposit wallet trading. Only pUSD held by the deposit wallet contract is available for CLOB orders.
Two-step funding:
- EOA acquires pUSD (bridge POL or swap)
- EOA transfers pUSD to deposit wallet (ERC-20 transfer)
Phase 4: Approve (relayer WALLET batches)
The deposit wallet must approve trading contracts before CLOB orders can settle. That trading readiness batch is six calls:
- pUSD
approveforCTFExchangeV2 - CTF
setApprovalForAllforCTFExchangeV2 - pUSD
approveforNegRiskExchangeV2 - CTF
setApprovalForAllforNegRiskExchangeV2 - pUSD
approveforNegRiskAdapterV2 - CTF
setApprovalForAllforNegRiskAdapterV2
V2 split, merge, and redeem readiness is separate. The collateral adapters also need a one-time WALLET batch:
- pUSD
approveforCtfCollateralAdapter - CTF
setApprovalForAllforCtfCollateralAdapter - pUSD
approveforNegRiskCtfCollateralAdapter - CTF
setApprovalForAllforNegRiskCtfCollateralAdapter
Redeem itself requires the CTF approval leg; pUSD approval is included so the same adapter-readiness batch also covers future split flows.
Phase 5: Trade (CLOB)
With the wallet deployed, funded, and approved, orders are placed with
deposit-wallet signing automatically. The EOA signs the order, but the CLOB
sees the deposit wallet as both maker and signer in the V2 order payload.
Phase 6: Redeem Winners (relayer WALLET batch)
After a market resolves, query Data API positions for the deposit wallet and
look for redeemable=true. That is the readiness signal; there is no separate
resolved boolean in the current Data API position schema.
V2 redeem routes through collateral adapters, not ConditionalTokens
directly. The owner signs an EIP-712 WALLET batch, and the relayer submits
that batch through the deposit-wallet factory:
| Market Type | Adapter |
|---|---|
| Standard binary | CtfCollateralAdapter |
| Negative-risk | NegRiskCtfCollateralAdapter |
The adapter uses conditionId, detects the wallet’s CTF balances, redeems the
winning side, wraps proceeds back into pUSD, and returns pUSD to the deposit
wallet.
Do not use direct EOA calls, raw CTF calls, or SAFE/PROXY relayer examples as fallbacks for deposit-wallet positions. If the relayer rejects the adapter-targeted WALLET batch, first verify the adapter addresses against Polymarket’s current contracts reference. If the addresses are current, surface the upstream blocker and stop.
The operator surface is polygolem deposit-wallet approve-adapters,
redeemable, and redeem. Every signing path is dry-run by default;
submission requires both --submit and a typed --confirm token
(APPROVE_ADAPTERS for adapter approvals, REDEEM_WINNERS for redeem).
See Redeeming Winning Positions for the
full runbook.
Recovery Modes
On every startup, go-bot walks the lifecycle and fills any gaps. Every step is idempotent — running it twice on an already-ready wallet is a no-op.
| State on Restart | What Happens |
|---|---|
| No deployment | IsDeployed() → false and eth_getCode empty → WALLET-CREATE → poll until mined |
| Deployed (relayer says so) | IsDeployed() → true → skip deploy |
| Deployed (relayer false-negative) | IsDeployed() → false but eth_getCode non-empty → treat as deployed, skip WALLET-CREATE |
| Deployed, no pUSD | Wallet has code, balance zero → fund EOA pUSD → transfer to wallet |
| Deployed, pUSD present, no approvals | Balance OK, allowances empty → SubmitWalletBatchSafe with fresh nonce |
| Deployed, trade approvals present, adapter approvals missing | Trading can work, but split/merge/redeem must fail closed until adapter approvals are submitted |
| Fully operational | All checks pass → skip to live trading loop |
| Nonce conflict (lost response after a previous batch) | SubmitWalletBatchSafe re-fetches nonce from relayer, signs with new nonce, retries |
| Wallet lost (never happens — it’s a contract on Polygon) | Re-derive address (same result) → on-chain code still present → skip deploy |
Nonce Safety
Every WALLET batch consumes one nonce tracked by the relayer per EOA. The nonce is never cached or reused:
- Fetch fresh nonce from
GET /nonce?address=<EOA>&type=WALLET - Sign the batch EIP-712 with that nonce
- Submit to
POST /submit(type=WALLET) - If submission succeeds → poll for confirmation
- If submission fails with nonce conflict (a previous lost response consumed it) → re-fetch (step 1) and retry
- If submission fails with any other error → report and stop
This guarantees:
- No duplicate nonce submission
- Recovery from lost responses without operator intervention
- Max 3 retries before failing with a clear error
First-Time Onboard
First-time setup can start directly with polygolem deposit-wallet onboard.
Polymarket login signs with the EOA shown in the website’s SIWE prompt; the
deposit wallet remains the trading wallet for pUSD, POLY_1271 orders, CTF
positions, approvals, and redemption.
# Full wallet onboarding:# derive + auto SIWE/profile/relayer auth + deploy + approvals# + UI Enable Trading signs + fund.POLYMARKET_PRIVATE_KEY="0x..." \ polygolem deposit-wallet onboard --fund-amount 50 --jsonIf V2 relayer credentials are missing, wallet commands sign the Polymarket
SIWE message locally, register the profile, mint the relayer key, persist it
to the Polygolem env file, and continue. polygolem auth login is still
available when you want to refresh or inspect that step explicitly.
This single command runs: derive → deploy → trading and adapter approvals → UI Enable Trading signs → fund. The UI Enable Trading leg signs ClobAuth, creates or derives CLOB API keys, and submits the 2-call token approval batch.
For pre-provisioned CLOB credentials, run polygolem builder auto. Otherwise
Polygolem derives or creates the EOA-bound CLOB key on demand for order auth.
Non-zero order attribution is configured separately with
POLYMARKET_BUILDER_CODE or CLI --builder-code.
Then sync the CLOB balance:
POLYMARKET_PRIVATE_KEY="0x..." \ polygolem clob update-balance --asset-type collateralAutomated Startup (go-bot live)
go-bot’s live command automates the full lifecycle at startup:
go-bot live startup: 1. derive deposit wallet address (offline) 2. check IsDeployed(); if false, fall back to eth_getCode → deploy only when both say not deployed 3. check deposit wallet pUSD balance → fund if needed 4. check collateral allowances → approve if needed 5. update CLOB balance cache 6. enter live trading loop with deposit-wallet signingWith persistence, a restart after a crash recovers cleanly:
crash → restart → derive (same address) → IsDeployed or eth_getCode=true→ skip deploy → balance OK → skip fund → allowances OK → skip approve→ start tradingChecking Status
# Is the wallet deployed? (relayer + on-chain dual-source check)polygolem deposit-wallet status --json# {# "deployed": true,# "deploymentStatusSource": "polygon_code",# "relayerDeployed": false,# "onchainCodeDeployed": true,# "depositWallet": "0x21999a..."# }
# What's the deposit wallet balance?polygolem clob balance --asset-type collateral
# Are the UI Enable Trading signs and allowances ready?polygolem deposit-wallet status --check-enable-trading
# Check EOA onchain funds with wallet/RPC tooling; CLOB balance reads use# the deposit wallet cache.deploymentStatusSource is one of:
relayer— relayer/deployedreturned true (normal happy path).polygon_code— relayer said false, buteth_getCodereturned non-empty bytecode. The wallet is deployed; the relayer row is stale.relayer_and_polygon_code— both reported not deployed. Real first-deploy state;polygolem deposit-wallet deploy --waitwill submitWALLET-CREATE(and itself skips the call ifeth_getCodebecomes non-empty before the request is made, e.g. mid-retry).
pUSD held by the EOA and pUSD held by the deposit wallet are separate balances. Only the deposit wallet balance counts for POLY_1271 trading.
Redeem Readiness Checklist
Before submitting a V2 redeem batch:
- The wallet is deployed according to Polygon
eth_getCode. - Data API
/positions?user=<depositWallet>returns at least oneredeemable=truerow. - The position includes
conditionId,asset,outcome,outcomeIndex, andnegativeRisk. - CTF
isApprovedForAll(wallet, adapter)is true for the required adapter. - The WALLET batch is dry-run and inspected before any live submission.
go-bot must call the Polygolem SDK package directly for this flow. The Polygolem CLI is for humans and operator runbooks, not the production bot integration boundary.