For the complete documentation index, see [llms.txt](https://docs.tesseract.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tesseract.fi/dedicated-client-vaults/integration-guide/scenario-a/deploying-a-vault.md).

# Deploying a Vault

A vault is created in a single transaction against the Vault Deployer for the asset you want to hold. The deployer pulls your initial deposit and mints shares to your wallet in the same call.

### Pick the right deployer

One deployer per asset:

| Asset | Deployer                                                                                                                     |
| ----- | ---------------------------------------------------------------------------------------------------------------------------- |
| USDC  | [`0xe4D85722dB649d3890f9DBA4510F1A16AD942FD9`](https://etherscan.io/address/0xe4D85722dB649d3890f9DBA4510F1A16AD942FD9#code) |
| WBTC  | [`0x55073cdF0b0E42C8B807A265EADff69973274a8d`](https://etherscan.io/address/0x55073cdF0b0E42C8B807A265EADff69973274a8d#code) |
| WETH  | [`0x6701241e65d4baFC399Ca4358E95960aF3C041C4`](https://etherscan.io/address/0x6701241e65d4baFC399Ca4358E95960aF3C041C4#code) |

### Read the current minimum initial deposit

Before deploying, read the minimum initial deposit from the deployer — it's configured per asset and can change, so read it on-chain rather than hard-coding.

```ts
const deployerAbi = [
  {type: 'function', stateMutability: 'view', name: 'minInitialDeposit',
   inputs: [], outputs: [{type: 'uint256'}]},
] as const

const minDeposit = await client.readContract({
  address: deployer, abi: deployerAbi, functionName: 'minInitialDeposit',
})
```

### Approve the initial deposit

The deployer needs to be able to pull `initialDeposit` of the underlying asset from your wallet:

```ts
const assetAbi = [{
  type: 'function', stateMutability: 'nonpayable', name: 'approve',
  inputs: [{type: 'address'}, {type: 'uint256'}],
  outputs: [{type: 'bool'}],
}] as const

await walletClient.writeContract({
  address: underlyingToken,
  abi: assetAbi, functionName: 'approve',
  args: [deployer, initialDeposit],
})
```

If the underlying token supports [EIP‑2612 permit](https://eips.ethereum.org/EIPS/eip-2612) (USDC does), you can skip the separate approval transaction by using `deployVaultWithPermit` instead — see below.

### Call `deployVault`

```ts
const deployAbi = [{
  type: 'function', stateMutability: 'nonpayable', name: 'deployVault',
  inputs: [
    {name: 'initialDeposit',    type: 'uint256'},
    {name: 'maxManagementFee',  type: 'uint256'},
    {name: 'maxPerformanceFee', type: 'uint256'},
  ],
  outputs: [/* FusionInstance struct — read from the event instead */],
}] as const

// Fees are in basis points (100 bps = 1%). Default DCV terms are
// 0.25% management (25 bps) and 30% performance (3000 bps) — pass those
// as the slippage caps, unless you've agreed different terms with Tesseract.
const MAX_MGMT_FEE = 25n      // 0.25%
const MAX_PERF_FEE = 3000n    // 30%

const hash = await walletClient.writeContract({
  address: deployer,
  abi: deployAbi,
  functionName: 'deployVault',
  args: [initialDeposit, MAX_MGMT_FEE, MAX_PERF_FEE],
})

const receipt = await client.waitForTransactionReceipt({hash})
```

`maxManagementFee` and `maxPerformanceFee` are slippage guards — the transaction reverts if the deployer's currently configured fees exceed them. Use the agreed contractual values so an accidental on-chain fee bump can't deploy a vault with fees higher than what you signed up for.

### Extract the vault address

The deployer emits a `VaultDeployed` event. Parse it from the receipt:

```ts
import {parseAbiItem, decodeEventLog} from 'viem'

const vaultDeployedEvent = parseAbiItem(
  'event VaultDeployed(address indexed plasmaVault, address indexed owner, address accessManager, address feeManager, address rewardsManager, address withdrawManager, address contextManager, address priceManager)'
)

const log = receipt.logs.find(l => l.address.toLowerCase() === deployer.toLowerCase())
const decoded = decodeEventLog({abi: [vaultDeployedEvent], data: log.data, topics: log.topics})

const vault = decoded.args.plasmaVault
const withdrawManager = decoded.args.withdrawManager
```

Save `plasmaVault` (the vault address you'll interact with for deposits / withdrawals) and `withdrawManager` (per-vault manager for scheduled withdrawals). Both are also discoverable later via the [Public API](/dedicated-client-vaults/reference/public-api.md).

### Using permit (one transaction)

For underlying tokens that support EIP‑2612, you can skip the separate approval and deploy in a single transaction:

```ts
// 1. Generate a permit signature for `initialDeposit` to `deployer`
const {v, r, s, deadline} = await signPermit({...})

// 2. Call the permit variant
await walletClient.writeContract({
  address: deployer,
  abi: /* deployVaultWithPermit ABI */, 
  functionName: 'deployVaultWithPermit',
  args: [initialDeposit, mgmtFee, perfFee, deadline, v, r, s],
})
```

Once your vault exists, continue to [**Strategy Assignment**](/dedicated-client-vaults/integration-guide/scenario-a/strategy-assignment.md) to start managing it, or [**Deposits**](/dedicated-client-vaults/integration-guide/scenario-a/deposits.md) if you want to add more capital first.
