> For the complete documentation index, see [llms.txt](https://docs.crystal.exchange/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.crystal.exchange/developer-resources/smart-contract-methods/crystalvaultfactory.md).

# CrystalVaultFactory

Create and interact with individual vaults built on top of the Crystal protocol.

## Conventions

**Native token.** Wherever an asset address is accepted, `eth` (`0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`) means native ETH. Vaults always hold WETH; the factory wraps on deposit and unwraps on withdrawal when you pass `eth`. Vault records in `getVault` store the WETH address, not the sentinel.

**Asset order.** `deposit` and `withdraw` require `quoteAsset` and `baseAsset` to match the vault's registered pair (after `eth` normalization) or they revert with `InvalidMarket`.

**Owner-only methods.** Every method that takes a `vault` parameter and changes its state can only be called by that vault's owner, and reverts with `Unauthorized` otherwise. Governance cannot modify individual vaults; it only sets factory-wide defaults and limits.

**Shares.** Each vault's share token symbol is `CLV-` followed by the base symbol then the quote symbol, e.g. `CLV-WETHUSDC`. The vault address is the share token address.

**Metadata.**

```solidity
struct VaultMetaData {
    string name;
    string description;
    string social1;
    string social2;
    string social3;
}
```

## Vaults

#### deploy

```solidity
function deploy(address quoteAsset, address baseAsset, uint256 amountQuote, uint256 amountBase, uint256 maxShares, uint40 lockup, bool decreaseOnWithdraw, VaultMetaData metadata) external payable returns (address vault)
```

Deploys a new vault with `msg.sender` as owner and makes the initial deposit in the same call. Both initial amounts must strictly exceed the minimum deposit for their token (`minDeposit(token)` if set, otherwise `globalMinDeposit`). If either asset is `eth`, `msg.value` must equal that asset's amount. The initial deposit is made with zero slippage minimums.

**Parameters**

| Name               | Type          | Description                                                                             |
| ------------------ | ------------- | --------------------------------------------------------------------------------------- |
| quoteAsset         | address       | Quote asset, or `eth`.                                                                  |
| baseAsset          | address       | Base asset, or `eth`.                                                                   |
| amountQuote        | uint256       | Initial quote deposit. Must exceed the token's minimum.                                 |
| amountBase         | uint256       | Initial base deposit. Must exceed the token's minimum.                                  |
| maxShares          | uint256       | Cap on total shares. 0 = uncapped.                                                      |
| lockup             | uint40        | Withdrawal lockup in seconds. 0 = use the factory's `maxLockup`.                        |
| decreaseOnWithdraw | bool          | Whether the vault scales down its resting orders when a withdrawal reduces its balance. |
| metadata           | VaultMetaData | Name, description, and social links.                                                    |

**Return Values**

| Name  | Type    | Description                                                   |
| ----- | ------- | ------------------------------------------------------------- |
| vault | address | Address of the deployed vault, which is also its share token. |

#### deposit

```solidity
function deposit(address vault, address quoteAsset, address baseAsset, uint256 amountQuoteDesired, uint256 amountBaseDesired, uint256 amountQuoteMin, uint256 amountBaseMin) public payable returns (uint256 shares, uint256 amountQuote, uint256 amountBase)
```

Deposits both assets into a vault and mints shares to the caller. The factory pulls the full desired amounts, lets the vault take what it needs to keep proportions, and refunds the remainder in the same transaction. If either asset is `eth`, `msg.value` must equal that asset's desired amount; otherwise `msg.value` must be zero. Reverts if the vault is locked or closed, or if the amounts used fall below the minimums.

**Parameters**

| Name               | Type    | Description                             |
| ------------------ | ------- | --------------------------------------- |
| vault              | address | Vault address.                          |
| quoteAsset         | address | Vault's quote asset, or `eth`.          |
| baseAsset          | address | Vault's base asset, or `eth`.           |
| amountQuoteDesired | uint256 | Maximum quote to contribute.            |
| amountBaseDesired  | uint256 | Maximum base to contribute.             |
| amountQuoteMin     | uint256 | Revert if less quote than this is used. |
| amountBaseMin      | uint256 | Revert if less base than this is used.  |

**Return Values**

| Name        | Type    | Description               |
| ----------- | ------- | ------------------------- |
| shares      | uint256 | Shares minted.            |
| amountQuote | uint256 | Quote actually deposited. |
| amountBase  | uint256 | Base actually deposited.  |

#### withdraw

```solidity
function withdraw(address vault, address quoteAsset, address baseAsset, uint256 shares, uint256 amountQuoteMin, uint256 amountBaseMin) external returns (uint256 amountQuote, uint256 amountBase)
```

Burns `shares` and sends the caller their proportional quote and base. Pass `eth` for either asset to receive native ETH. Subject to the vault's lockup: shares cannot be redeemed until the caller's `unlockTimestamp` has passed. If the withdrawal leaves the owner with zero shares, the vault is automatically locked and closed.

**Parameters**

| Name           | Type    | Description                                          |
| -------------- | ------- | ---------------------------------------------------- |
| vault          | address | Vault address.                                       |
| quoteAsset     | address | Vault's quote asset, or `eth` to receive native ETH. |
| baseAsset      | address | Vault's base asset, or `eth` to receive native ETH.  |
| shares         | uint256 | Shares to redeem.                                    |
| amountQuoteMin | uint256 | Revert if less quote than this is returned.          |
| amountBaseMin  | uint256 | Revert if less base than this is returned.           |

**Return Values**

| Name        | Type    | Description     |
| ----------- | ------- | --------------- |
| amountQuote | uint256 | Quote returned. |
| amountBase  | uint256 | Base returned.  |

#### previewDeposit

```solidity
function previewDeposit(address vault, uint256 amountQuoteDesired, uint256 amountBaseDesired) external view returns (uint256 shares, uint256 amountQuote, uint256 amountBase)
```

Returns what `deposit` would mint and consume for the given desired amounts, without changing state.

**Parameters**

| Name               | Type    | Description                  |
| ------------------ | ------- | ---------------------------- |
| vault              | address | Vault address.               |
| amountQuoteDesired | uint256 | Maximum quote to contribute. |
| amountBaseDesired  | uint256 | Maximum base to contribute.  |

**Return Values**

| Name        | Type    | Description                  |
| ----------- | ------- | ---------------------------- |
| shares      | uint256 | Shares that would be minted. |
| amountQuote | uint256 | Quote that would be used.    |
| amountBase  | uint256 | Base that would be used.     |

#### previewWithdrawal

```solidity
function previewWithdrawal(address vault, uint256 shares) external view returns (uint256 amountQuote, uint256 amountBase)
```

Returns what redeeming `shares` would pay out at the vault's current balances.

**Parameters**

| Name   | Type    | Description      |
| ------ | ------- | ---------------- |
| vault  | address | Vault address.   |
| shares | uint256 | Shares to price. |

**Return Values**

| Name        | Type    | Description                   |
| ----------- | ------- | ----------------------------- |
| amountQuote | uint256 | Quote that would be returned. |
| amountBase  | uint256 | Base that would be returned.  |

#### balanceOf

```solidity
function balanceOf(address vault, address user) external view returns (uint256 shares, uint256 amountQuote, uint256 amountBase)
```

Returns a user's share balance in a vault and the quote and base those shares currently represent.

**Parameters**

| Name  | Type    | Description    |
| ----- | ------- | -------------- |
| vault | address | Vault address. |
| user  | address | Share holder.  |

**Return Values**

| Name        | Type    | Description                 |
| ----------- | ------- | --------------------------- |
| shares      | uint256 | Share balance.              |
| amountQuote | uint256 | Quote the shares represent. |
| amountBase  | uint256 | Base the shares represent.  |

## Vault Management

All methods in this section are owner-only.

#### lock

```solidity
function lock(address vault) external
```

Pauses new deposits. Withdrawals are unaffected.

**Parameters**

| Name  | Type    | Description    |
| ----- | ------- | -------------- |
| vault | address | Vault address. |

#### unlock

```solidity
function unlock(address vault) external
```

Resumes deposits.

**Parameters**

| Name  | Type    | Description    |
| ----- | ------- | -------------- |
| vault | address | Vault address. |

#### close

```solidity
function close(address vault) external returns (uint256 amountQuote, uint256 amountBase)
```

Redeems all of the owner's shares with no slippage minimums and marks the vault locked and closed. Assets are transferred as ERC-20s; the WETH side is not unwrapped. Other depositors can still withdraw from a closed vault.

**Parameters**

| Name  | Type    | Description    |
| ----- | ------- | -------------- |
| vault | address | Vault address. |

**Return Values**

| Name        | Type    | Description                  |
| ----------- | ------- | ---------------------------- |
| amountQuote | uint256 | Quote returned to the owner. |
| amountBase  | uint256 | Base returned to the owner.  |

#### changeMaxShares

```solidity
function changeMaxShares(address vault, uint256 newMaxShares) external
```

Sets the cap on total shares.

**Parameters**

| Name         | Type    | Description            |
| ------------ | ------- | ---------------------- |
| vault        | address | Vault address.         |
| newMaxShares | uint256 | New cap. 0 = uncapped. |

#### changeLockup

```solidity
function changeLockup(address vault, uint40 newLockup) external
```

Sets the withdrawal lockup. The vault contract validates the value against the factory's `maxLockup`.

**Parameters**

| Name      | Type    | Description        |
| --------- | ------- | ------------------ |
| vault     | address | Vault address.     |
| newLockup | uint40  | Lockup in seconds. |

#### changeDecreaseOnWithdraw

```solidity
function changeDecreaseOnWithdraw(address vault, bool newDecrease) external
```

Toggles whether the vault scales down its resting orders when a withdrawal reduces its balance.

**Parameters**

| Name        | Type    | Description    |
| ----------- | ------- | -------------- |
| vault       | address | Vault address. |
| newDecrease | bool    | New setting.   |

#### changeOrderCap

```solidity
function changeOrderCap(address vault, uint16 newCap) external
```

Sets the maximum number of open orders the vault may hold. The vault contract validates the value against the factory's `maxOrderCap`.

**Parameters**

| Name   | Type    | Description    |
| ------ | ------- | -------------- |
| vault  | address | Vault address. |
| newCap | uint16  | New order cap. |

#### changeMarket

```solidity
function changeMarket(address vault) external
```

Re-reads the canonical market for the vault's pair from Crystal. Call this if the canonical market for the pair has changed since the vault was deployed.

**Parameters**

| Name  | Type    | Description    |
| ----- | ------- | -------------- |
| vault | address | Vault address. |

#### claimFees

```solidity
function claimFees(address vault, address[] tokens) external
```

Claims the vault's claimable rewards on Crystal for the listed tokens to the owner. Vaults do not create markets and are unlikely to be used as referrers, so these are typically incentives distributed by the protocol or third parties.

**Parameters**

| Name   | Type       | Description      |
| ------ | ---------- | ---------------- |
| vault  | address    | Vault address.   |
| tokens | address\[] | Tokens to claim. |

#### clearCloidSlots

```solidity
function clearCloidSlots(address vault, uint256 userId, uint256[] ids) external
```

Calls Crystal's `clearCloidSlots` on behalf of the vault.

**Parameters**

| Name   | Type       | Description                    |
| ------ | ---------- | ------------------------------ |
| vault  | address    | Vault address.                 |
| userId | uint256    | The vault's Crystal user id.   |
| ids    | uint256\[] | Cloid slots to clear (1–1023). |

## Governance

Callable only by `gov`. These set factory-wide defaults and limits; they do not change existing vaults.

#### changeGov

```solidity
function changeGov(address newGov) external
```

Transfers governance.

**Parameters**

| Name   | Type    | Description             |
| ------ | ------- | ----------------------- |
| newGov | address | New governance address. |

#### changeMaxOrderCap

```solidity
function changeMaxOrderCap(uint16 newCap) external
```

Sets the maximum order cap a vault may configure.

**Parameters**

| Name   | Type   | Description                      |
| ------ | ------ | -------------------------------- |
| newCap | uint16 | New maximum. Must be below 1024. |

#### changeMaxLockup

```solidity
function changeMaxLockup(uint40 newLockup) external
```

Sets the maximum lockup a vault may configure. Also the default lockup for vaults deployed with `lockup = 0`.

**Parameters**

| Name      | Type   | Description                                          |
| --------- | ------ | ---------------------------------------------------- |
| newLockup | uint40 | New maximum in seconds. At most 30 days (2,592,000). |

#### changeGlobalMinDeposit

```solidity
function changeGlobalMinDeposit(uint256 newGlobalMinDeposit) external
```

Sets the default minimum initial deposit for tokens with no per-token override.

**Parameters**

| Name                | Type    | Description                                            |
| ------------------- | ------- | ------------------------------------------------------ |
| newGlobalMinDeposit | uint256 | New minimum. Initial deposits must strictly exceed it. |

#### changeMinDeposit

```solidity
function changeMinDeposit(address token, uint256 newMinDeposit) external
```

Sets a per-token minimum initial deposit. Passing `eth` sets the value for WETH.

**Parameters**

| Name          | Type    | Description                                      |
| ------------- | ------- | ------------------------------------------------ |
| token         | address | Token, or `eth` for WETH.                        |
| newMinDeposit | uint256 | New minimum. 0 falls back to `globalMinDeposit`. |

## State and Registry Getters

| Name             | Signature                                                                                                                | Description                                                                                 |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- |
| weth             | `weth() → address`                                                                                                       | Wrapped native token.                                                                       |
| eth              | `eth() → address`                                                                                                        | Native-token sentinel.                                                                      |
| gov              | `gov() → address`                                                                                                        | Governance address.                                                                         |
| crystal          | `crystal() → address`                                                                                                    | Crystal core contract.                                                                      |
| allVaults        | `allVaults(uint256) → address`                                                                                           | Vault at index.                                                                             |
| allVaultsLength  | `allVaultsLength() → uint256`                                                                                            | Number of deployed vaults.                                                                  |
| getVault         | `getVault(address) → (quoteAsset, baseAsset, owner, totalShares, maxShares, lockup, decreaseOnWithdraw, locked, closed)` | Vault record. `totalShares` is updated on every deposit and withdrawal through the factory. |
| minDeposit       | `minDeposit(address token) → uint256`                                                                                    | Per-token minimum initial deposit; 0 if none.                                               |
| globalMinDeposit | `globalMinDeposit() → uint256`                                                                                           | Default minimum initial deposit.                                                            |
| maxOrderCap      | `maxOrderCap() → uint16`                                                                                                 | Maximum order cap a vault may set.                                                          |
| maxLockup        | `maxLockup() → uint40`                                                                                                   | Maximum lockup a vault may set, and the default for new vaults.                             |

***

## Events

Events and errors emitted by CrystalVaultFactory.

#### VaultDeployed

```solidity
event VaultDeployed(address indexed vault, address quoteAsset, address baseAsset, address owner, uint256 maxShares, uint256 lockup, bool decreaseOnWithdraw, VaultMetaData metadata)
```

Emitted by `deploy`, before the initial `Deposit`.

| Name               | Type          | Description                                                                  |
| ------------------ | ------------- | ---------------------------------------------------------------------------- |
| vault              | address       | New vault address.                                                           |
| quoteAsset         | address       | Quote asset (WETH, not `eth`).                                               |
| baseAsset          | address       | Base asset (WETH, not `eth`).                                                |
| owner              | address       | Vault owner.                                                                 |
| maxShares          | uint256       | Share cap. 0 = uncapped.                                                     |
| lockup             | uint256       | Effective lockup in seconds. Reports `maxLockup` when the deployer passed 0. |
| decreaseOnWithdraw | bool          | Decrease-on-withdraw setting.                                                |
| metadata           | VaultMetaData | Name, description, and social links.                                         |

#### Deposit

```solidity
event Deposit(address indexed vault, address indexed sender, uint256 shares, uint256 quoteAmount, uint256 baseAmount)
```

Emitted by `deposit`, including the initial deposit in `deploy`.

| Name        | Type    | Description      |
| ----------- | ------- | ---------------- |
| vault       | address | Vault.           |
| sender      | address | Depositor.       |
| shares      | uint256 | Shares minted.   |
| quoteAmount | uint256 | Quote deposited. |
| baseAmount  | uint256 | Base deposited.  |

#### Withdraw

```solidity
event Withdraw(address indexed vault, address indexed sender, uint256 shares, uint256 quoteAmount, uint256 baseAmount)
```

Emitted by `withdraw` and `close`.

| Name        | Type    | Description        |
| ----------- | ------- | ------------------ |
| vault       | address | Vault.             |
| sender      | address | Redeeming account. |
| shares      | uint256 | Shares burned.     |
| quoteAmount | uint256 | Quote returned.    |
| baseAmount  | uint256 | Base returned.     |

#### MaxSharesChanged

```solidity
event MaxSharesChanged(address indexed vault, uint256 maxShares)
```

Emitted by `changeMaxShares`.

| Name      | Type    | Description |
| --------- | ------- | ----------- |
| vault     | address | Vault.      |
| maxShares | uint256 | New cap.    |

#### LockupChanged

```solidity
event LockupChanged(address indexed vault, uint256 lockup)
```

Emitted by `changeLockup`.

| Name   | Type    | Description            |
| ------ | ------- | ---------------------- |
| vault  | address | Vault.                 |
| lockup | uint256 | New lockup in seconds. |

#### DecreaseOnWithdrawChanged

```solidity
event DecreaseOnWithdrawChanged(address indexed vault, bool newDecrease)
```

Emitted by `changeDecreaseOnWithdraw`.

| Name        | Type    | Description  |
| ----------- | ------- | ------------ |
| vault       | address | Vault.       |
| newDecrease | bool    | New setting. |

#### Locked

```solidity
event Locked(address indexed vault)
```

Emitted by `lock`, and automatically when a `withdraw` or `close` leaves the owner with zero shares.

| Name  | Type    | Description |
| ----- | ------- | ----------- |
| vault | address | Vault.      |

#### Unlocked

```solidity
event Unlocked(address indexed vault)
```

Emitted by `unlock`.

| Name  | Type    | Description |
| ----- | ------- | ----------- |
| vault | address | Vault.      |

#### Closed

```solidity
event Closed(address indexed vault)
```

Emitted when a vault is closed, either by `close` or automatically when a `withdraw` leaves the owner with zero shares. A vault cannot be reopened.

| Name  | Type    | Description |
| ----- | ------- | ----------- |
| vault | address | Vault.      |

## Errors

| Error                                           | Meaning                                                                               |
| ----------------------------------------------- | ------------------------------------------------------------------------------------- |
| `SizeBelowMin()`                                | An initial deposit in `deploy` did not exceed the token's minimum.                    |
| `Unauthorized(address user)`                    | Caller is not the vault owner (owner-only methods) or not `gov` (governance methods). |
| `InvalidMarket(address asset0, address asset1)` | `quoteAsset`/`baseAsset` do not match the vault's pair.                               |
| `InvalidMsgValue()`                             | `msg.value` does not match the `eth` amount, or was sent when no asset is `eth`.      |
| `InvalidParams()`                               | Governance parameter out of range.                                                    |
| `TransferFailed(address recipient)`             | Native ETH refund or payout failed.                                                   |

`changeOrderCap` and `changeMarket` do not emit factory events; the vault contract handles those changes directly.
