> ## Documentation Index
> Fetch the complete documentation index at: https://docs.testnet.dev.adipredictstreet.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Vaults overview

> Why every PredictStreet trader has their own on-chain vault, and what it does for you.

A **vault** is a per-user on-chain custody contract — an EIP-1167
minimal proxy of `VaultImplementation`, deployed by `VaultFactory`.
Every trader who places signed orders on PredictStreet has exactly one
vault, and that vault is the address that actually holds your USDC and
outcome ERC-1155 tokens on chain.

## Why vaults

The exchange does not custody funds for you. Three things only the
vault model gives you:

* **You own the keys.** `VaultImplementation` exposes
  `initiateEmergencyWithdraw` + `emergencyWithdrawERC20/ERC1155` after
  a 7-day timelock — even if PredictStreet goes dark, you pull your
  funds out yourself.
* **Per-user isolation.** A bug or compromise affecting one vault
  cannot drain another. There is no pooled treasury.
* **Dual-signature withdrawals.** External transfers (`withdrawERC20`,
  `withdrawERC1155`) require **both** your EIP-712 signature **and** a
  backend co-signature, so a stolen API key alone cannot move
  funds out — neither replaces the vault owner's private key that
  signs the EIP-712 authorisation.

## How vaults connect to trading

When you sign a vault-backed order (`signatureType = 1`):

```
Order.maker  = your vault address    (VaultFactory.vaultOf(eoa))
Order.signer = your EOA              (the key that produced the EIP-712 signature)
```

On-chain, `CTFExchange._verifyVault` enforces
`vaultFactory.vaultOf(signer) == maker`, so the only way the maker
field matches is if you actually deployed and own that vault.

This is also why **SELL needs the outcome ERC-1155 to live in the
vault** (not the EOA): the platform looks up positions keyed by
`maker = vault`. Splitting USDC into a YES + NO outcome set therefore
goes through `vault.splitPosition(...)` rather than the EOA calling
`ConditionalTokens` directly. See
[Vault contract reference](/concepts/contracts/vaults) for the on-chain
function shapes.

## Lifecycle, in five lines

```
vaultOf(eoa) == 0x0000000000000000000000000000000000000000   ── (1)
                                                                │ deployVault
                                                                ▼
vaultOf(eoa) == 0xYourVault   (clone exists, ready for funds)  ── (2)
                                                                │ approve  +  depositERC20  (deposit limits auto-init by backend)
                                                                ▼
vault.balanceOf(usdc) > 0     (USDC custodied — can BUY)       ── (3)
                                                                │ vault.splitPosition (USDC → YES + NO)
                                                                ▼
vault.balanceOf(yesToken) > 0  (outcome tokens — can SELL)     ── (4)
                                                                │ withdrawERC20 / withdrawERC1155 (dual-sig)
                                                                ▼
funds back to your EOA or external address                     ── (5)
```

## Two ways to get a vault

The platform deploys every partner-managed vault automatically.
The trigger differs by partner kind:

* **single\_wallet** and **multi\_wallet with `requirePerWalletKyc=true`** —
  the back-office wallet calls `VaultFactory.deployVault(eoa)` the
  moment the EOA's `kyc_status` flips to `APPROVED` (tier ≥ 1) and
  initialises deposit-limit caps in the same flow.
* **multi\_wallet with `requirePerWalletKyc=false`** (KYB-onboarded
  prime brokerage) — the deploy job is enqueued on the first
  authenticated request that names a previously-unseen sub-account
  in `X-User-Wallet`, with no retail KYC required for the
  sub-account.

Partners do not call `VaultFactory.deployVault` themselves and do
not pay deploy gas. See
[Backend auto-deploy](/concepts/vaults/auto-deploy) for the
trigger detail, polling pattern, and the seven `deployStatus`
values.

`VaultFactory.deployVault(eoa)` is a public function callable by
any address — operations can call it from a treasury wallet in a
true emergency, the on-chain result is identical to auto-deploy.
But this is exclusively a recovery path; partner integration code
should never include it.
