# Contract Interfaces

## Collateral

The Collateral contract stores collateral balances for { user, product } pairs. There is a single Collateral contract in the protocol.

### Deposit

Deposit pulls collateral (DSU) from the `msg.sender` and credits the product's collateral balance for the specified account.

```solidity
function depositTo(address account, address product, uint256 amount) external
```

* `account` - The address of the user account
* `product` - The address of the Perennial product
* `amount` - Amount of DSU to deposit

### Withdraw

Withdraw decrements the balance of `msg.sender` product collateral balance and pushes the DSU to the specified receiver.

```solidity
function withdrawTo(address receiver, address product, uint256 amount) external
```

* `account` - The address of the user account
* `product` - The address of the Perennial product
* `amount` - Amount of DSU to deposit

### Liquidate

Liquidate closes `account` 's position for the specified product. Liquidate will revert if the user is not eligible for liquidation.&#x20;

```solidity
function liquidate(address account, address product) external
```

To check if a user is liquidateable, call

```solidity
function liquidatable(address account, address product) external
```

* `account` - The address of the user account
* `product` - The address of the Perennial product

## Product

The Product contract is a market in the Perennial protocol. A new product contract is deployed for each launched market via the Controller's `createProduct` method.

### Open/Close Make

[Maker positions](/lps-makers/vaults.md) provide liquidity for a given product. The maximum size of a maker position is determined by the account's collateral and the product's maintenance requirement.

```solidity
function openMake(uint256 amount) external
function closeMake(uint256 amount) external
```

* `amount` - Size of the maker position to open or close

### Open/Close Take

[Taker positions](broken://pages/OLHBn8ZCHJpuPIyRIDtL) are traders in the system. The maximum size of a taker position is determined by the account's collateral, the product's maintenance requirement, and the product's liquidity (open maker positons)&#x20;

```solidity
function openTake(uint256 amount) external
function closeTake(uint256 amount) external
```

* `amount` - Size of the taker position to open or close

## Lens

The Lens contract provides convenience functions for reading Protocol, Product, and Accounts state. The functions on the Lens contracts are designed to be called via Ether's [`callStatic`](https://docs.ethers.io/v5/api/contract/contract/#contract-callStatic) method (or similar, depending on your Web3 library of choice). You can find the lens address for each deployed chain in [Deployed Contracts](/developers/deployed-contracts.md)

### Snapshots

Snapshot functions return batched data for the Protocol, and one or more Products or Accounts. For struct fields, refer to the [Lens interface](https://github.com/equilibria-xyz/perennial-mono/blob/master/packages/perennial/contracts/interfaces/IPerennialLens.sol#L13).

```solidity
function snapshot() external returns (ProtocolSnapshot memory)
 
function snapshot(address product) external returns (ProductSnapshot memory)
function snapshot(address account, address product) external returns (UserProductSnapshot memory)
 
function snapshots(address[] calldata productAddresses) external returns (ProductSnapshot[] memory)
function snapshots(address account, address[] calldata productAddresses) external returns (UserProductSnapshot[] memory)
```

* `account` - The address of the user account
* `product` - The address of the Perennial product

## MultiInvoker

The MultiInvoker allows for multiple interactions with the Perennial protocol in a single transaction.

The entrypoint to MultiInvoker is `invoke`. Each invocation can take one or multiple Actions, and will perform each action in order. For common chains, see our [integration tests](https://github.com/equilibria-xyz/perennial-mono/blob/master/packages/perennial/test/integration/multiinvoker/multiinvoker.test.ts#L46).

```solidity
function invoke(Invocation[] calldata invocations) external;
```

Where each `Invocation` has an `action` and `args` field. The `args` are ABI encoded arguments, you can use the following typescript snippet to generate payloads for each action.

```typescript
enum InvokerAction {
  NOOP,
  DEPOSIT,
  WITHDRAW,
  OPEN_TAKE,
  CLOSE_TAKE,
  OPEN_MAKE,
  CLOSE_MAKE,
  CLAIM,
  WRAP,
  UNWRAP,
  WRAP_AND_DEPOSIT,
  WITHDRAW_AND_UNWRAP,
}

const buildInvokerAction = (
  action: InvokerAction,
  {
    userAddress,
    productAddress,
    position,
    amount,
    programs,
  }: {
    userAddress?: string
    productAddress?: string
    position?: BigNumberish
    amount?: BigNumberish
    programs?: number[]
  }
): IMultiInvoker.InvocationStruct => {
  switch (action) {
    case InvokerAction.DEPOSIT:
      return {
        action: 1,
        args: utils.defaultAbiCoder.encode(['address', 'address', 'uint'], [userAddress, productAddress, amount]),
      }
    case InvokerAction.WITHDRAW:
      return {
        action: 2,
        args: utils.defaultAbiCoder.encode(['address', 'address', 'uint'], [userAddress, productAddress, amount]),
      }
    case InvokerAction.OPEN_TAKE:
      return {
        action: 3,
        args: utils.defaultAbiCoder.encode(['address', 'uint'], [productAddress, position]),
      }
    case InvokerAction.CLOSE_TAKE:
      return {
        action: 4,
        args: utils.defaultAbiCoder.encode(['address', 'uint'], [productAddress, position]),
      }
    case InvokerAction.OPEN_MAKE:
      return {
        action: 5,
        args: utils.defaultAbiCoder.encode(['address', 'uint'], [productAddress, position]),
      }
    case InvokerAction.CLOSE_MAKE:
      return {
        action: 6,
        args: utils.defaultAbiCoder.encode(['address', 'uint'], [productAddress, position]),
      }
    case InvokerAction.CLAIM:
      return {
        action: 7,
        args: utils.defaultAbiCoder.encode(['address', 'uint[]'], [productAddress, programs]),
      }
    case InvokerAction.WRAP:
      return {
        action: 8,
        args: utils.defaultAbiCoder.encode(['address', 'uint'], [userAddress, amount]),
      }
    case InvokerAction.UNWRAP:
      return {
        action: 9,
        args: utils.defaultAbiCoder.encode(['address', 'uint'], [userAddress, amount]),
      }
    case InvokerAction.WRAP_AND_DEPOSIT:
      return {
        action: 10,
        args: utils.defaultAbiCoder.encode(['address', 'address', 'uint'], [userAddress, productAddress, amount]),
      }
    case InvokerAction.WITHDRAW_AND_UNWRAP:
      return {
        action: 11,
        args: utils.defaultAbiCoder.encode(['address', 'address', 'uint'], [userAddress, productAddress, amount]),
      }
    default:
      return { action: 0, args: '0x' }
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs-v1.perennial.finance/developers/contract-interfaces.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
