Skip to main content
Status: live. Every partner-managed vault is deployed by the platform’s back-office wallet. Partners do not call deployVault themselves — the on-chain bootstrap is handled end-to-end by the backend in response to KYC approval (single_wallet, or multi_wallet with requirePerWalletKyc=true) or first-request auto-onboarding (multi_wallet with requirePerWalletKyc=false). Poll GET /api/me/vault or subscribe to the user_activity WebSocket channel until the vault address resolves.

What triggers it

There are two trigger paths, picked automatically based on the partner record:
  1. KYC approval — single_wallet partners, and multi_wallet partners with requirePerWalletKyc=true. The auto-deploy job is enqueued the moment the EOA’s kyc_status flips to APPROVED (tier ≥ 1). See Partner kinds for the per-flag enforcement matrix.
  2. First request auto-onboarding — multi_wallet partners with requirePerWalletKyc=false (KYB-onboarded prime brokerage model). The first authenticated request from the partner key that names a previously-unseen sub-account in X-User-Wallet creates the core.users row and enqueues an auto-deploy job right then — without retail KYC for the sub-account.
Either way, the on-chain VaultFactory.deployVault call comes from the back-office submitter, gas is paid by the platform, and the result is identical: a fully-initialised VaultImplementation clone with deposit-limit caps registered against your EOA.

Sequence

Typical end-to-end timing on testnet: under 15 seconds from trigger to deployed=true. Mainnet target is similar; spikes during high block latency are visible on the status page.

Reading deployment status

GET /api/me/vault
X-Api-Key: ps_live_<keyId>_<secret>   # needs `portfolio:read`
{
  "walletAddress":     "0x...",
  "vaultAddress":      "0x...",
  "deployed":          true,
  "deployStatus":      "confirmed",
  "deployTxHash":      "0x...",
  "deployRequestedAt": "2026-04-25T12:34:06.247Z",
  "deployConfirmedAt": "2026-04-25T12:34:15.256Z"
}
FieldMeaning
vaultAddressThe deterministic vault contract address — populated as soon as the deploy job is enqueued, even if not yet mined.
deployedtrue once VaultFactory.vaultOf(eoa) returns a non-zero address on chain. The off-chain mirror is consistent with the chain within ~1 block.
deployStatusSee deployStatus values below — seven states tracking the auto-deploy job from enqueue to terminal.
deployTxHashSet once the back-office wallet broadcasts the tx. Useful for blockscout cross-reference.

deployStatus values

ValueMeaningAction
not_startedNo deploy job enqueued yet for this wallet — typically a brand-new EOA before KYC tier 1 clears (single_wallet) or before the first authenticated request lands (multi_wallet with requirePerWalletKyc=false).Wait for the trigger to fire; if it’s been more than 15 seconds, see What if auto-deploy doesn’t fire below.
pendingJob enqueued; awaiting wallet-pool slot.Poll again in a few seconds.
buildingMatch-submitter is constructing the on-chain tx.Poll again in a few seconds.
submittedTx broadcast; awaiting on-chain finality. deployTxHash is now set.Poll until confirmed, or subscribe to vault.deploy_confirmed on /ws/user.
confirmedTx mined; vaultOf(eoa) returns the vault address.Proceed to deposit + trade. deployed: true.
skipped_existingWallet already had an on-chain vault before the auto-deploy system existed (legacy users).Treat as confirmeddeployed: true.
failed_permanentTx reverted; the job will not retry.Contact support. The most common cause is a misconfigured back-office wallet pool.
The same status flips on the user_activity WebSocket channel as vault.deploy_confirmed for partners that prefer push semantics — see WebSocket subscriptions.

What stays the same

  • The on-chain artefact is identical to a manually-deployed vault — same VaultImplementation clone at the same deterministic address, same ABI, same vaultOf(eoa) lookup.
  • Vault ownership stays with your associated EOA. The back-office wallet pays gas to deploy but never holds keys to the vault.
  • Emergency withdraw, dual-signature withdrawal, splits, merges, and redeems — all unchanged. Auto-deploy only saves the on-chain bootstrap, not custody.
  • Order.maker is your vault address; Order.signer is your EOA — the EIP-712 domain and signature flow are identical to manual deploy.

What stays your responsibility

  • approve of USDC to the vault. ERC-20 transferability is owner-only by design — only the EOA that holds USDC can authorise the vault to pull it. The platform cannot bypass that.
  • depositERC20 from your EOA. Auto-deploy stops at the vault contract; the actual USDC transfer is a separate user-side tx (or via your wallet provider’s permit flow if it supports EIP-2612).
  • Custody of the EOA private key — never reaches our infrastructure.
  • Gas for trading-side txes (split / merge / convert / withdraw / cancel on-chain) is paid by your EOA. Auto-deploy only covers the deploy bootstrap.

Limits initialisation

Per-EOA deposit caps in DepositLimitRegistry (daily / weekly / monthly) are initialised by the platform alongside the deploy. By the time /api/me/vault reports deployed=true, the user is also cleared to deposit up to their tier-1 caps. See Deposit limits for the cap shape and how usage windows roll.

Verifying

// Off-chain: poll until the vault deploys
const r = await fetch(`${BASE}/api/me/vault`, {
  headers: { 'X-Api-Key': process.env.PS_API_KEY! },
});
const v = await r.json();
if (v.deployed) {
  console.log('vault ready:', v.vaultAddress, 'tx:', v.deployTxHash);
}

// Or push: subscribe via WS
ws.send(JSON.stringify({
  type:    'subscribe',
  channel: 'user_activity',
}));
// → { type: 'event', topic: 'vault.deploy_confirmed', vaultAddress: '0x...', txHash: '0x...' }

What if auto-deploy doesn’t fire

For a partner-issued API key, auto-deploy is the only path — operations issues orders:write / vault:write keys only after the prerequisite KYC (or partner-level KYB) lands, so by the time your code runs the trigger is already in flight. If GET /api/me/vault keeps returning deployStatus:'not_started' past the typical 15-second window, the most common causes are:
  • KYC not actually approved for the EOA (single_wallet path) — call your integration manager.
  • multi_wallet requirePerWalletKyc=true and the sub-account hasn’t been KYC’d. Either complete KYC for that sub-account or ask operations to flip the partner to requirePerWalletKyc=false if the prime-brokerage compliance model fits.
  • failed_permanent on deployStatus — the on-chain tx reverted and the job will not retry. Contact support; usually means the back-office wallet pool is degraded.
VaultFactory.deployVault(eoa) is callable on-chain by any address (the function only stores vaultOwner = eoa and is idempotent), so in a true emergency a partner can deploy themselves and pay gas — but operations should be the first call. The contract reference at Vault contracts → VaultFactory documents the function signature.