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.
VaultImplementationexposesinitiateEmergencyWithdraw+emergencyWithdrawERC20/ERC1155after 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):
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 for the on-chain
function shapes.
Lifecycle, in five lines
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 callsVaultFactory.deployVault(eoa)the moment the EOA’skyc_statusflips toAPPROVED(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 inX-User-Wallet, with no retail KYC required for the sub-account.
VaultFactory.deployVault themselves and do
not pay deploy gas. See
Backend 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.