> ## 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.

# Backend auto-deploy

> The platform deploys every partner vault automatically — partners do not call deployVault, do not pay deploy gas, and do not coordinate the on-chain bootstrap.

<Note>
  **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` until the
  vault address resolves.
</Note>

## 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](/auth/api-keys#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

```mermaid theme={null}
sequenceDiagram
    participant U as Associated wallet
    participant CORE as core-api
    participant CHAIN as ADI chain

    Note over U,CORE: trigger — KYC approved or first<br/>multi_wallet request through the key
    Note over CORE: backend enqueues<br/>auto-deploy job
    CORE->>CHAIN: VaultFactory.deployVault(eoa)
    CHAIN-->>CORE: VaultCreated(seq, owner, vault)
    Note over CORE: deposit-limit caps<br/>auto-initialised
    CORE-->>U: GET /api/me/vault → { vault, deployed: true, ... }
    U->>CHAIN: USDC.approve(vault, MaxUint256)
    U->>CHAIN: vault.depositERC20(USDC, amount)
```

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](https://status.predictstreet.com).

## Reading deployment status

```http theme={null}
GET /api/me/vault
X-Api-Key: ps_live_<keyId>_<secret>   # needs `portfolio:read`
```

```json theme={null}
{
  "walletAddress":     "0x...",
  "vaultAddress":      "0x...",
  "deployed":          true,
  "deployStatus":      "confirmed",
  "deployTxHash":      "0x...",
  "deployRequestedAt": "2026-04-25T12:34:06.247Z",
  "deployConfirmedAt": "2026-04-25T12:34:15.256Z"
}
```

| Field          | Meaning                                                                                                                                          |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `vaultAddress` | The deterministic vault contract address — populated as soon as the deploy job is enqueued, even if not yet mined.                               |
| `deployed`     | `true` once `VaultFactory.vaultOf(eoa)` returns a non-zero address on chain. The off-chain mirror is consistent with the chain within \~1 block. |
| `deployStatus` | See [`deployStatus` values](#deploystatus-values) below — seven states tracking the auto-deploy job from enqueue to terminal.                    |
| `deployTxHash` | Set once the back-office wallet broadcasts the tx. Useful for blockscout cross-reference.                                                        |

### `deployStatus` values

| Value              | Meaning                                                                                                                                                                                                            | Action                                                                                                                                           |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `not_started`      | No 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](#what-if-auto-deploy-doesnt-fire) below. |
| `pending`          | Job enqueued; awaiting wallet-pool slot.                                                                                                                                                                           | Poll again in a few seconds.                                                                                                                     |
| `building`         | Match-submitter is constructing the on-chain tx.                                                                                                                                                                   | Poll again in a few seconds.                                                                                                                     |
| `submitted`        | Tx broadcast; awaiting on-chain finality. `deployTxHash` is now set.                                                                                                                                               | Poll until `confirmed`, or subscribe to `vault.deploy_confirmed` on `/ws/user`.                                                                  |
| `confirmed`        | Tx mined; `vaultOf(eoa)` returns the vault address.                                                                                                                                                                | Proceed to deposit + trade. `deployed: true`.                                                                                                    |
| `skipped_existing` | Wallet already had an on-chain vault before the auto-deploy system existed (legacy users).                                                                                                                         | Treat as `confirmed` — `deployed: true`.                                                                                                         |
| `failed_permanent` | Tx reverted; the job will not retry.                                                                                                                                                                               | Contact support. The most common cause is a misconfigured back-office wallet pool.                                                               |

Vault deploy is not currently surfaced on the typed WebSocket
channels — poll `GET /api/me/vault` until `deployed: true`.

## 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 a separate platform job that runs *after* vault deploy.

<Warning>
  The two lifecycles are independent. `/api/me/vault` flipping to
  `deployed: true` does **not** imply the registry has been
  initialised — the init job typically lags by 30 seconds, but in
  observed runs has lagged by up to \~4 minutes. Calling
  `vault.depositERC20(...)` against an uninitialised registry reverts
  with `NotInitialized()` (selector `0x87138d5c`).

  Bootstrap clients should poll **`/api/me/deposit-limits`** until
  `initialized: true` (not just `/api/me/vault.deployed`) before
  attempting the on-chain deposit. See [Deposit
  limits](/concepts/deposits/limits) for the cap shape and how usage
  windows roll.
</Warning>

## Verifying

```typescript theme={null}
// 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);
}

// Vault deploy is not surfaced on the typed WS channels — poll
// `GET /api/me/vault` until `deployed: true`. Auto-deploy normally
// completes within a few seconds.
```

## 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](/concepts/contracts/vaults#vaultfactory)
documents the function signature.
