Wallet Routing And Funds Recovery¶
Purpose¶
Use this guide when Polymarket funds or positions appear on the wrong wallet, a Deposit Wallet or Safe route looks inconsistent, or a deposit did not arrive where you expected. Start with the simple recovery commands, then use the advanced diagnostics only when the CLI or support asks for them.
This guide helps you collect evidence and choose the next safe command. It does not prove that an affected account has been recovered.
Plain-English Wallet Terms¶
These terms appear throughout this guide.
- Bullpen-managed 0x wallet — an Ethereum
0x...address controlled by your Bullpen account. An account can have more than one. It can authorize transfers, but it is usually not where your Polymarket funds live. - Imported external EVM wallet — an EVM account added for visibility. It
cannot be selected as a Bullpen-managed wallet and is unavailable for
managed transfer, ownership-proven Polymarket recovery, or managed trading.
Inspect its stable capability flags with
bullpen wallet list --output json. - Selected trading wallet — for each Bullpen-managed 0x wallet, Bullpen chooses which Polymarket wallet is active for trading: Deposit Wallet, Safe, or Proxy. The CLI follows that choice; you do not pick it by hand during normal trading.
- Assets outside the selected trading wallet — funds or positions sitting on a Polymarket wallet that is not the selected trading wallet. They are not lost, but the active trading flow cannot use them until they are moved to the selected wallet.
- Deposit Wallet derivation — the proof path used to compute the expected Deposit Wallet address. If output says the CLI used a fallback proof path, treat that as degraded evidence and retry diagnostics when Polygon RPC is healthy before using it for a support decision.
- Legacy pre-beacon Deposit Wallet — an address derived by Polymarket's older Deposit Wallet factory before the June 2026 beacon migration. Deployed legacy Deposit Wallets can be recovery sources when ownership and asset evidence are proven. Some legacy or routing-only cases still require support-side recovery.
Start Here: Symptom → Command¶
Match your symptom, run the first command, then follow the linked section below. Preview and support commands are read-only; live recovery commands still require explicit confirmation.
| Symptom | Run this first | Then |
|---|---|---|
| "My Polymarket balance shows $0 but I deposited" | bullpen recover funds --dry-run --output json |
Review the plan. Submit only when it says the CLI can move funds from an owned wallet. |
| "My deposit never arrived" | bullpen funds diagnose-deposit --tx <TX_HASH> --chain <CHAIN> --token <TOKEN> --address <RECIPIENT_ADDRESS> --output json |
Wrong chain / wrong token / exchange address -> include the JSON in your support ticket. |
| "Funds are on the wrong wallet" | bullpen recover funds --dry-run --output json |
Stranded assets reported → Preview Recovery Workflows. |
| "I moved funds to my Safe and can't trade them" | bullpen recover funds --dry-run --output json |
Execute only when the preview clearly says the CLI can move owned funds and the source, destination, route, and assets match your intent. |
| "I can't trade / trading-wallet rejection" | bullpen fix --refresh |
Follow the single next action it prints. Do not switch wallet kind or retry the trade unless fix or Bullpen Support gives that exact step. |
"I can't redeem / STATE_FAILED" |
bullpen recover redeem --dry-run --output json |
Capture the dry-run JSON; see Trading → Redeem. |
| "Wallet routing disagreement" | bullpen recover polymarket --refresh --output json |
Do not force a wallet kind, relogin repeatedly, or retry money movement. Follow recovery_plan.next_action; create a support bundle only when the plan says support is needed. |
| "The CLI reports legacy Deposit Wallet recovery is needed" | bullpen recover funds --dry-run --output json |
Follow the plan. It may move proven legacy Deposit Wallet assets locally or direct you to support. |
| "Wallet records disagree" | bullpen recover polymarket --refresh --output json |
Follow recovery_plan.next_action; include doctor wallet JSON only when the plan or support asks for it. |
For trading-wallet rejections, you are done when bullpen fix --refresh
reports no blocking action and your original command succeeds.
For wallet-routing disagreement, you are done when
bullpen recover polymarket --refresh --output json reports no blocking action
and your original command succeeds.
For missing deposits, you are done when you have created a
bullpen support bundle --output json artifact or attached the read-only diagnostic evidence to a Bullpen Support
ticket, unless the CLI prints a self-service recovery plan whose source,
destination, route, and asset details match the deposit you are trying to
recover.
Self-Serve Versus Escalate¶
- Self-serve: a clean "assets on an owned wallet" result is normal only
when
bullpen recover funds --dry-run --output jsonsays the CLI can move the funds locally, the account ownership evidence is strong, and the source, destination, route, and asset details match your intent. Execute only if the JSON plan is correct. See Preview Recovery Workflows. - Escalate to support: wrong-chain or wrong-token deposits, exchange/imported
wallet destinations, trading-wallet or order-route rejections after
bullpen fix --refresh, routing disagreements afterbullpen recover polymarket --refresh --output json, routing-only address paths, and wallet-record disagreements are not direct self-serve movements. If the plan says local recovery is unavailable or uncertain, stop and create a support artifact withbullpen support bundle --output json; do not force a wallet kind to "fix" them.
Before You Start¶
- Run diagnostics from the same Bullpen account, machine, and environment that saw the issue.
- Do not delete
~/.bullpen, export private keys, bridge manually, or force a wallet kind as the first recovery step. - Do not share private keys, seed phrases, JWTs, API tokens, full config files, or unredacted logs with support.
- Treat
--non-interactiveand--yesas separate controls. Non-interactive mode does not approve money-moving commands.
Safe First Commands¶
For most recovery questions, run:
For trading-wallet rejections, refresh the account-level fix plan:
No immediate state-change to orders or funds: Run the readiness refresh only when the failed command or support identifies a trading-wallet rejection and asks for the account-level fix plan.
For wallet-routing disagreement failures, refresh the Polymarket recovery plan. This is a read-only planning command; it does not move funds:
If either plan sends you to support, create one privacy-contract-bearing artifact:
Use the advanced wallet audit only when the recovery output or support asks for
wallet evidence. It is read-only by default and includes root
privacy_contract disclosure when shared as a support artifact.
The pattern to look for is an asset balance on a wallet that is not selected for trading. Addresses and amounts below are redacted and illustrative; your exact fields will differ.
Example output — stranded assets on a non-selected wallet
{
"schema_version": 1,
"owners": [
{
"owner_eoa": "0xOWNER…1234",
"server_selected": { "kind": "deposit_wallet", "address": "0xDEP…aaaa" },
"wallets": [
{
"kind": "deposit_wallet",
"address": "0xDEP…aaaa",
"status": "active",
"is_server_selected": true,
"pusd": "0.00",
"usdce": "0.00",
"positions": 0
},
{
"kind": "safe",
"address": "0xSAFE…bbbb",
"status": "inactive_legacy",
"is_server_selected": false,
"pusd": "42.10",
"usdce": "0.00",
"positions": 1,
"stranded": true
}
]
}
],
"summary": { "stranded_assets_found": true }
}
The audit enumerates Bullpen-managed 0x wallets, checks selected Polymarket routing, and
probes Safe, Proxy, current Deposit Wallet, deployed legacy Deposit Wallet, and
CLI-proven locally signable owned EOA state without submitting a
transaction. See the command reference for
bullpen polymarket wallet-audit;
it documents --owner and --include-order-credit.
If legacy Deposit Wallet evidence appears, do not assume all recovery is
impossible. Run bullpen recover funds --dry-run --output json and use the
plan outcome. The plan will either say the CLI can move proven owned assets or
direct you to support.
If the report is about a missing or wrong-chain deposit, run the deposit diagnostic next. It is read-only and does not attempt recovery.
bullpen funds diagnose-deposit --tx <TX_HASH> --chain <CHAIN> --token <TOKEN> --address <RECIPIENT_ADDRESS> --output json
Use the generated
funds diagnose-deposit reference
for accepted chain and token values. If you only know the recipient, the
reference also documents the address-only diagnostic shape.
Read The Result¶
Use the JSON output as evidence, not as permission to run a repair command.
Account-level recovery guidance appears in recovery_plan. Funds movement
guidance uses root status and legs[]. Login-attempt guidance appears in
auth_incident. Follow the fields in the object returned by the command instead
of combining steps from multiple guides.
Preview or read-only commands come first in this section: use
bullpen recover funds --dry-run --output json,
bullpen recover polymarket --refresh --output json, or the relevant
diagnostic output before any live recovery command.
| Result class | Next safe action |
|---|---|
| Wallet route is consistent and no stranded assets are reported | Continue with the original failed command's preview or diagnostic path. |
| Assets or positions appear on an owned Safe, Proxy, current Deposit Wallet, deployed legacy Deposit Wallet, or CLI-proven locally signable owned EOA | Preview bullpen recover funds --dry-run --output json before execution. |
| The recovery preview says local recovery is available | Live: Execute bullpen recover funds --yes only after reviewing the dry-run JSON and confirming root status is ready, every executable leg has outcome: "supported" and effective_evidence.submit_authorized: true, and the source, destination, route, and assets match your intent. |
| The recovery preview says nothing needs to move | Do not submit another command for that item. |
| The recovery preview says local recovery is unavailable or uncertain | Do not force wallet selection or retry live money movement. Run the printed support command or bullpen support bundle --output json. |
| Deposit was sent to a chain or token the CLI cannot recover, an exchange address, imported external EVM wallet, routing-only address, or bot Safe | Do not try to select that wallet for trading or managed recovery. Include diagnose-deposit JSON and wallet-audit JSON in your support ticket; that support handoff is the completion condition for CLI-side work. |
| Wallet records or on-chain state disagree, or the error reports a wallet-routing disagreement | Run bullpen recover polymarket --refresh --output json and follow recovery_plan.next_action. Include doctor wallet JSON only when the plan or support asks for passive evidence. |
Run the broader wallet diagnostic when the issue is account inventory or cache disagreement rather than stranded Polymarket assets.
A healthy result says no disagreements were found. If the diagnostic reports a
disagreement, residual funds, or an inconclusive wallet state, the local cache,
Bullpen records, and on-chain bytecode do not agree for at least one
Bullpen-managed 0x wallet. Run
bullpen recover polymarket --refresh --output json for the recovery verdict;
attach doctor wallet JSON only when the verdict or support asks for it. The
safety section confirms the command performed no writes.
doctor wallet is passive: it does not sign, submit, or run the extra
order credit check. If support needs order-route rejection evidence, use the
explicit wallet-audit --include-order-credit command or attach the original
failed money command output. The command never treats a successful balance read
as proof that a wallet is accepted for trading.
Example output — wallet disagreement (illustrative, redacted)
{
"schema_version": 2,
"status": "disagreements_found",
"total_owners": 1,
"entries": [
{
"owner": "0xOWNER…1234",
"local_cache_kind": "legacy_safe",
"server_selected_kind": "safe",
"onchain_deposit_wallet_deployed": true,
"disagreement": "server_safe_but_dw_funded",
"hint": "Deposit Wallet is funded on-chain but server selects the Safe. Include this JSON in your support ticket; do not force a wallet kind."
}
],
"safety": {
"signer_creation": false,
"token_refresh": false,
"wallet_cache_mutation": false
}
}
See the generated doctor wallet reference.
Check Order Credit¶
Default wallet-audit and recovery dry-runs skip authenticated order credit
checks for each wallet row. If funds still look missing after the read-only
audit, or if the recovery dry-run says order credit checking was skipped or
incomplete, run the explicit order credit probe before choosing an
asset-movement command.
Read-only, support-gated: The JSON summary tells you whether order credit
was checked for each wallet. Order credit cannot be moved on-chain; when it
exists on a wallet that is not selected for trading, support may
route the case through a web-app withdrawal or support review instead of
consolidate.
Preview Recovery Workflows¶
Preview recovery when assets or positions appear on an owned Polymarket wallet that the active trade path cannot use.
Preview: The dry-run prints a plan without executing it. The
next_action value in the JSON may name a live command, but that field is
guidance for after review, not a preview action.
Live: Run bullpen recover funds --yes only when the root status is
ready, every executable leg has outcome: "supported",
effective_evidence.submit_authorized: true, and the source, destination,
route, and assets match your intent.
Example output — funds recovery dry-run plan (illustrative, redacted)
{
"schema_version": 1,
"dry_run": true,
"status": "ready",
"operation": "recover_funds",
"legs": [
{
"source_identity": {
"owner_eoa": "0x1111111111111111111111111111111111111111",
"source_address": "0x2222222222222222222222222222222222222222",
"source_class": "non_selected_safe",
"wallet_kind": "Safe",
"server_wallet_type": "Safe",
"server_wallet_type_raw": null,
"deposit_wallet_derivation": null,
"is_server_selected": false,
"operation": "migrate_pusd",
"asset_class": "pusd",
"identity_fingerprint": "recovery-leg:v1:0000000000000000000000000000000000000000000000000000000000000000"
},
"destination_identity": {
"destination_address": "0x3333333333333333333333333333333333333333",
"destination_policy": "selected_or_explicit_owned_wallet",
"wallet_kind": "DepositWallet",
"is_explicit": false
},
"observed_source_rows": [
{
"source": "wallet_audit",
"state": "verified_onchain",
"reason": "pUSD balance found on a non-selected Safe"
}
],
"asset_evidence": {
"state": "verified_onchain",
"reason": "pUSD balance found on-chain",
"proof_scope": "polygon_rpc",
"amount": "42.100000",
"amount_policy": "exact_amount"
},
"effective_evidence": {
"state": "verified_onchain",
"reason": "pUSD balance found on-chain",
"submit_authorized": true,
"proof_scope": "polygon_rpc"
},
"route": {
"operation": "migrate_pusd",
"asset_class": "pusd",
"asset_identifier": "pUSD",
"source_address": "0x2222222222222222222222222222222222222222",
"destination_address": "0x3333333333333333333333333333333333333333",
"destination_kind": "DepositWallet"
},
"outcome": "supported",
"submit": {
"state": "not_submitted",
"tx_hash": null,
"receipt_state": null,
"verification_state": null,
"source_delta": null,
"destination_delta": null,
"token_delta": null,
"operation_proof": null,
"safe_to_retry": false
},
"next_action": "Run `bullpen recover funds --yes` after reviewing this plan.",
"safe_to_retry": false,
"support_artifact": null
}
],
"whole_plan_preflight": {
"state": "not_checked",
"checked_leg_count": 0,
"failure_reason": null
},
"partial_execution": {
"completed": 0,
"failed": 0,
"skipped": 0,
"not_started": 1
}
}
Eligible recovery sources include selected and non-selected owned Safe, Proxy, current Deposit Wallet, deployed legacy Deposit Wallet, and CLI-proven locally signable owned EOA sources. Direct-address submit requires CLI-proven signing authority and sufficient POL/MATIC gas. Other address-source routing requires Bullpen support.
Recovery never changes the selected trading wallet. It moves eligible assets toward the current destination in the plan. On live submit, the CLI refreshes the source identity, destination identity, and exact transfer details. If they changed since preview, the command stops before any transfer. It also validates the full plan before the first transfer, so one leg the CLI cannot execute blocks partial execution.
Understand Recovery JSON¶
JSON and human output distinguish these fields:
| Field | Values | Meaning |
|---|---|---|
status |
Dry-run: ready, no_op, backend_only, blocked; live: complete, preflight_failed, partial_execution, failed, executed, blocked |
Root plan or submit status. Live execution requires dry-run root status: "ready" plus executable-leg evidence below. |
legs[] |
Array of recovery actions | The per-asset or per-route work units. |
legs[].source_identity / legs[].destination_identity |
Address, wallet kind, selected state, and authority fields | Confirm the source and destination match your intent before submitting. |
legs[].route |
operation, asset_class, asset_identifier, source/destination addresses, and optional destination kind |
The exact operation the leg plans to run. |
legs[].outcome |
supported, no_op, unsupported, backend_only, unknown |
Whether a plan leg can run locally, needs no action, needs support, or lacks enough evidence. Treat only supported as locally executable. |
legs[].effective_evidence.submit_authorized |
true / false |
Whether ownership and asset evidence are strong enough for local submit. A ready preview should have this set to true for executable supported legs. |
legs[].submit |
state, optional transaction fields, and live retry evidence |
Submit and post-submit state for each action. In dry-runs, legs[].submit.state is usually not_submitted for executable actions or skipped_no_op for no-op actions. Do not use retry fields to decide whether an ordinary preview is authorized. |
legs[].submit.state |
not_submitted, submitted, confirmed, failed, outcome_unknown, skipped_no_op, skipped_preflight_failed, not_started |
Submit status for each leg. |
partial_execution |
completed, failed, skipped, not_started |
Counts after a live run. |
legs[].submit.safe_to_retry |
true / false |
Post-live-submit retry evidence. Retry only the submitted failed/unknown leg when that leg reports true; do not resubmit a leg with outcome_unknown or safe_to_retry: false until status or support review resolves it. Ignore this field for ordinary dry-run preview authorization because no submit has occurred. |
Diagnostic and support metadata may include resolution_owner on objects such
as recovery_plan, wallet readiness, order-route readiness, auth incidents, signing
capability, or support bundles. Ordinary ready recovery previews do not use a
top-level resolution_owner to decide whether to submit; interpret them from
legs[].source_identity, legs[].destination_identity,
legs[].effective_evidence.submit_authorized, legs[].outcome,
legs[].submit.state, and legs[].next_action. Use
legs[].submit.safe_to_retry only after a live submit, and only for the leg
whose submit status failed or became unknown.
If support asks you to inspect only one Bullpen-managed 0x wallet, use the generated
consolidate reference for
the exact --owner form. Do not force --wallet-kind unless support
explicitly directs it.
Mutating Commands¶
The commands in this section can submit transactions, change account metadata, or move funds. Run them only after diagnostics and plan review.
Execute recovery only after the dry-run routes eligible assets to the intended
destination. Run bullpen recover funds --dry-run --output json first and
review the source, destination, route, assets, and executable-leg evidence.
Live: This command can move funds, cancel orders, transfer positions, merge complete sets, and sweep balances according to the reviewed recovery plan.
Run this only after the dry-run root status is ready, every executable leg has
outcome: "supported" and effective_evidence.submit_authorized: true, and
the source, destination, route, and asset details match your intent. If the
dry-run says local recovery is unavailable or uncertain, stop and run
bullpen support bundle --output json. The command can cancel
orders, transfer positions, merge complete sets, and sweep balances according
to the reviewed recovery plan. A successful command on one account does not
prove another affected account is recovered.
Sweep stranded ERC-20 funds only when diagnostics and support identify a supported Polygon ERC-20 balance held by a Bullpen-owned Safe, Proxy, or Deposit Wallet.
If support confirms sweep-stranded is the right command and gives you the
exact token, source, amount, and destination, submit the reviewed transfer:
Destructive, support-directed immediate state-change: sweep-stranded has
no separate dry-run flag; execute it only when the recovery preview or Bullpen
support confirms the source asset, amount, and destination.
bullpen polymarket sweep-stranded \
--token <TOKEN> \
--from <SOURCE_WALLET> \
--to <DESTINATION_WALLET> \
--amount <AMOUNT>
The form above performs preflight checks, prints the transfer summary, and asks
for confirmation. Run it only after the recovery preview or Bullpen support
confirms the source asset, amount, and destination. This is a one-way transfer.
Review the generated
sweep-stranded reference
before confirming, especially recipient rules and the --unsafe-recipient
boundary.
Deploy or re-register a Deposit Wallet only when diagnostics show that the selected trading route is Deposit Wallet and the generated command output says that action is appropriate.
After reviewing the diagnostic output or support instruction, run only one specific confirmed command. To deploy a selected Deposit Wallet:
Write, support-gated immediate state-change: There is no separate preview flag; deploy only when diagnostics or support identify this exact repair and the command's confirmation flow shows the selected Deposit Wallet route.
To refresh registration only when diagnostics or support identify that exact repair:
Write, support-gated immediate state-change: There is no separate preview flag; re-register only when diagnostics or support identify this exact repair and the command's confirmation flow shows the selected Deposit Wallet route.
These commands do not override normal wallet selection. They have no separate
--preview flag; without --yes, they open an interactive confirmation flow
after checking current state. --force-relayer-refresh is a support-directed
compatibility override; do not use it after an external registration rejection
unless Bullpen support gives that exact instruction.
Current builds treat that rejection as terminal for local repair and generate a
support bundle instead. Do not use this command when the CLI says funds are at
a legacy pre-beacon address pending recovery; that state is different from a
current Deposit Wallet registration refresh.
Bullpen support must confirm external repair before approval, activation, or
trading resumes. See the generated
deploy-deposit-wallet reference
and
reregister-deposit-wallet reference.
Select a Bullpen-managed 0x wallet only when you intend to change the primary wallet for a chain.
Write, immediate state-change: Execute wallet selection only when you
intend to change the primary EVM wallet to the exact Bullpen-managed address
shown by bullpen wallet list or bullpen wallet addresses.
This selects a Bullpen-managed 0x wallet; it does not directly choose the
selected Polymarket trading wallet. The address must be a Bullpen-managed EVM
wallet; imported external EVM wallets remain visible but cannot be selected.
See the generated
wallet select reference.
Support Capture¶
Create one privacy-contract-bearing support artifact:
The command collects the CLI version, session health, and selected trading
wallet evidence without exposing credentials. Its root privacy_contract
discloses whether operational wallet/account/resource, condition, transaction,
order, or trade IDs, exact balances, and local paths are included. Include the
failed command's short error message in the ticket. Run individual JSON
diagnostics only when support asks for a specific follow-up.
Do not attach secrets or full unredacted logs. Raw logs are exceptional evidence; attach them only when support asks after JSON artifacts are insufficient, and manually scrub credentials, tokens, private keys, auth headers, raw provider bodies, raw credential error chains, and unrelated local paths first.