Secrets Management
Polygolem and go-bot operate on a least-persistence model for secrets. Nothing is written to disk unless it’s statically provisioned by the operator. The private key is the only mandatory secret and it lives exclusively in the environment.
The Four Secrets Tiers
| Tier | Secret | Source | Persisted? | Why |
|---|---|---|---|---|
| 1 | Private key | POLYMARKET_PRIVATE_KEY env | Never to any file | Signs everything. Only in env, never argv, never stdout, never disk. |
| 2 | Builder credentials | polymarket.com/settings?tab=builder | Yes — .live-secrets.json | Long-lived, static. Avoids operator re-typing on restart. |
| 3 | CLOB API key | Derived from private key | No — regenerate | Deterministic from the key. Regeneration costs nothing. |
| 4 | Deposit wallet address | Derived via CREATE2 from EOA | Cache — .live-secrets.json | Deterministic. Cached for audit trail and display. |
Tier 1 — Private Key
# The ONLY place the key livesexport POLYMARKET_PRIVATE_KEY="0x..."Rules:
- Never written to any file by polygolem or go-bot.
- Never appears in command arguments (
/proc/*/cmdline). - Passed to polygolem subprocess via env only.
- Redacted in all logs:
0xa1b2...c3d4. - If missing from env at startup → hard error, no fallback.
Tier 2 — Builder Credentials
Builder credentials are obtained from
polymarket.com/settings?tab=builder.
They are an API key, secret, and passphrase tied to your Polymarket account.
The relayer uses them to authorize WALLET-CREATE and WALLET batch
submissions.
Startup Resolution Order
1. POLYMARKET_BUILDER_API_KEY env var → use it └─ if not set: .live-secrets.json → read from file └─ if not found: error → "builder creds required"The same priority applies to POLYMARKET_BUILDER_SECRET and
POLYMARKET_BUILDER_PASSPHRASE.
Persistence Format
go-bot/.live-secrets.json (.gitignored, chmod 600):
{ "eoa_address": "0xAb12...", "deposit_wallet_address": "0xCd34...", "builder_api_key": "550e8400-e29b-41d4-a716-446655440000", "builder_secret": "REDACTED_IN_LOGS_ONLY", "builder_passphrase": "REDACTED_IN_LOGS_ONLY", "created_at": "2026-05-07T12:00:00Z"}The
builder_secretandbuilder_passphrasevalues are stored in plaintext on disk but are never logged. All log output showsREDACTED_IN_LOGS_ONLYfor these fields.
Writing Secrets on First Run
# Option A: Provide via env on first run, go-bot persists automaticallyPOLYMARKET_PRIVATE_KEY="0x..." \POLYMARKET_BUILDER_API_KEY="550e8400-e29b-41d4-a716-446655440000" \POLYMARKET_BUILDER_SECRET="..." \POLYMARKET_BUILDER_PASSPHRASE="..." \ go-bot live
# On restart, only the private key is needed:POLYMARKET_PRIVATE_KEY="0x..." go-bot liveTier 3 — CLOB API Key
Generated by polygolem clob create-api-key. The command signs the CLOB L1
EIP-712 auth payload with the EOA private key, calls POST /auth/api-key, and
falls back to GET /auth/derive-api-key when credentials already exist.
This means:
- No need to persist in normal bot operation — create or derive on startup.
- The private key stays local; only the L1 auth signature is sent upstream.
- The resulting key is used for L2-authenticated CLOB API calls.
// In go-bot: regenerated at startup, never written to diskapiKey, err := cli.EnsureAPIKey(ctx)Tier 4 — Deposit Wallet Address
Derived via CREATE2 from the EOA address. Completely deterministic — the same EOA always produces the same deposit wallet address.
Cached in .live-secrets.json for:
- Faster startup (skip recomputation — small win)
- Audit trail (which address did this bot trade with?)
- Cross-check on restart (derived must equal persisted — mismatch = wrong key)