> ## Documentation Index
> Fetch the complete documentation index at: https://developers.paxoslabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct Deposits

> Deposit tokens into an Amplify vault by calling the DistributorCodeDepositor contract directly

This guide walks you through depositing tokens into an Amplify vault by calling the **DistributorCodeDepositor** smart contract directly. It covers every contract method you need to call, in order, for both the standard approval flow and the single-transaction permit flow.

## How Deposits Work

When you deposit tokens (e.g., USDC) into a vault, you receive **vault shares** in return. These shares represent your proportional ownership of the vault's assets and appreciate in value as the vault earns yield.

There are two ways to deposit:

| Flow                             | Transactions   | Best For                                         |
| -------------------------------- | -------------- | ------------------------------------------------ |
| **Standard (Approve + Deposit)** | 2 transactions | All tokens, all wallets                          |
| **Permit (Sign + Deposit)**      | 1 transaction  | Supported tokens only (USDC, USDG, pyUSD, USD₮0) |

***

## What You'll Need

| Requirement           | Description                                                                                                                                                                    |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Contract addresses    | `distributorCodeDepositorAddress` and `accountantAddress` — see [Vault Discovery](/v0.5.1/intro/products/earn/developers/guides/direct-contract/vault-queries/vault-discovery) |
| ABI                   | Provided below — just copy into your project                                                                                                                                   |
| RPC endpoint          | An Ethereum node URL (Alchemy, Infura, QuickNode, etc.)                                                                                                                        |
| Private key or wallet | To sign and send transactions                                                                                                                                                  |
| Deposit tokens        | The token you're depositing (e.g., USDC) + ETH for gas                                                                                                                         |

***

## ABI Reference

You need three ABI snippets. Copy these into your project as a JSON file or inline constant.

### DistributorCodeDepositor ABI

```json theme={null}
[
  {
    "inputs": [
      { "name": "depositAsset", "type": "address" },
      { "name": "depositAmount", "type": "uint256" },
      { "name": "minimumMint", "type": "uint256" },
      { "name": "to", "type": "address" },
      { "name": "distributorCode", "type": "bytes" }
    ],
    "name": "deposit",
    "outputs": [{ "name": "shares", "type": "uint256" }],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      { "name": "depositAsset", "type": "address" },
      { "name": "depositAmount", "type": "uint256" },
      { "name": "minimumMint", "type": "uint256" },
      { "name": "to", "type": "address" },
      { "name": "distributorCode", "type": "bytes" },
      { "name": "deadline", "type": "uint256" },
      { "name": "v", "type": "uint8" },
      { "name": "r", "type": "bytes32" },
      { "name": "s", "type": "bytes32" }
    ],
    "name": "depositWithPermit",
    "outputs": [{ "name": "shares", "type": "uint256" }],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]
```

### ERC-20 ABI (for approvals and allowance checks)

```json theme={null}
[
  {
    "inputs": [
      { "name": "spender", "type": "address" },
      { "name": "amount", "type": "uint256" }
    ],
    "name": "approve",
    "outputs": [{ "name": "", "type": "bool" }],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      { "name": "owner", "type": "address" },
      { "name": "spender", "type": "address" }
    ],
    "name": "allowance",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [{ "name": "owner", "type": "address" }],
    "name": "nonces",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  }
]
```

### Accountant ABI (for slippage calculation)

```json theme={null}
[
  {
    "inputs": [],
    "name": "getRateInQuoteSafe",
    "outputs": [{ "name": "rate", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  }
]
```

***

## Contract Method Reference

### `deposit(depositAsset, depositAmount, minimumMint, to, distributorCode)`

| Parameter         | Type      | Description                                                                                    |
| ----------------- | --------- | ---------------------------------------------------------------------------------------------- |
| `depositAsset`    | `address` | The ERC-20 token address to deposit (e.g., USDC: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`) |
| `depositAmount`   | `uint256` | Amount in the token's smallest unit. USDC has 6 decimals, so `1000000` = 1 USDC.               |
| `minimumMint`     | `uint256` | Minimum shares to receive — protects against slippage. Set to `0` to accept any amount.        |
| `to`              | `address` | Address that receives the minted vault shares (usually the depositor)                          |
| `distributorCode` | `bytes`   | Tracking code for referrals/attribution. Pass `0x` (empty bytes) if not applicable.            |

<Warning>
  **Important**: `depositAmount` is in the token's smallest unit. USDC has 6
  decimals, so 1,000 USDC = `1000000000` (1000 × 10^6). Getting this wrong is
  the most common integration mistake.
</Warning>

### `depositWithPermit(depositAsset, depositAmount, minimumMint, to, distributorCode, deadline, v, r, s)`

Same parameters as `deposit()`, plus:

| Parameter  | Type      | Description                                    |
| ---------- | --------- | ---------------------------------------------- |
| `deadline` | `uint256` | Unix timestamp after which the permit expires  |
| `v`        | `uint8`   | Recovery byte of the EIP-2612 permit signature |
| `r`        | `bytes32` | First 32 bytes of the permit signature         |
| `s`        | `bytes32` | Second 32 bytes of the permit signature        |

### Distributor Codes

The `distributorCode` parameter is used for referral attribution. If Paxos Labs has provided you with a distributor code, encode it as bytes (e.g., `toHex('your_code')` in JavaScript, `b'your_code'` in Python, `[]byte("your_code")` in Go).

If you don't have one, pass empty bytes (`0x`, `b""`, `[]byte{}`).

***

## Calculating `minimumMint` (Slippage Protection)

The vault's **Accountant** contract publishes the exchange rate between the deposit token and vault shares. Use it to calculate a safe `minimumMint`.

### Contract call

```
Accountant.getRateInQuoteSafe() → uint256 rate
```

`rate` represents the amount of the deposit asset per 1e18 vault shares (i.e., per one full share).

### Calculation

```
expectedShares = (depositAmount × 1e18) / rate
minimumMint    = expectedShares − (expectedShares × SLIPPAGE_BPS) / 10000
```

Where `SLIPPAGE_BPS` is your slippage tolerance in basis points (e.g., `50` = 0.5%).

<Info>
  Setting `minimumMint` to `0` disables slippage protection entirely. This is
  fine for testing but not recommended for production — a front-running bot
  could manipulate the rate between your transaction submission and execution.
</Info>

***

## Standard Deposit Walkthrough

The standard flow requires two transactions: an ERC-20 approval followed by the deposit.

<Steps>
  <Step title="Check existing allowance (read)">
    Call the deposit token's `allowance()` to see if the DistributorCodeDepositor already has sufficient spending permission.

    ```
    DepositToken.allowance(yourAddress, distributorCodeDepositorAddress) → uint256
    ```

    If the returned value is ≥ your `depositAmount`, skip to Step 3.
  </Step>

  <Step title="Approve the DistributorCodeDepositor (transaction)">
    Call `approve()` on the deposit token, granting the DistributorCodeDepositor permission to transfer your tokens.

    ```
    DepositToken.approve(distributorCodeDepositorAddress, depositAmount) → bool
    ```

    Wait for the transaction to be mined before proceeding.

    <Warning>
      **USDT special case**: USDT requires resetting the allowance to `0` before
      setting a new value if there's an existing non-zero allowance. Call
      `approve(spender, 0)` first, then `approve(spender, amount)`.
    </Warning>
  </Step>

  <Step title="Calculate minimumMint (read)">
    Query the exchange rate and compute slippage protection.

    ```
    Accountant.getRateInQuoteSafe() → uint256 rate
    ```

    Then calculate: `minimumMint = ((depositAmount × 1e18) / rate) × (10000 − SLIPPAGE_BPS) / 10000`
  </Step>

  <Step title="Execute the deposit (transaction)">
    Call `deposit()` on the DistributorCodeDepositor.

    ```
    DistributorCodeDepositor.deposit(
      depositAsset,      // e.g., USDC address
      depositAmount,     // e.g., 1000000000 (1,000 USDC)
      minimumMint,       // from Step 3
      to,                // recipient of vault shares (usually your address)
      distributorCode    // 0x if none
    ) → uint256 shares
    ```

    The return value is the number of vault shares minted.
  </Step>

  <Step title="Confirm the transaction">
    Wait for the transaction receipt. The deposit is complete once the transaction is included in a block. You can verify by calling `BoringVault.balanceOf(yourAddress)` to see your new share balance.
  </Step>
</Steps>

### Example values (1,000 USDC deposit on Ethereum mainnet)

| Parameter         | Value                                        |
| ----------------- | -------------------------------------------- |
| `depositAsset`    | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` |
| `depositAmount`   | `1000000000` (1,000 × 10^6)                  |
| `minimumMint`     | Calculated from Accountant rate              |
| `to`              | Your wallet address                          |
| `distributorCode` | `0x` (empty)                                 |

***

## Permit Deposit Walkthrough

For tokens that support [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) permits, you can combine approval and deposit into a single transaction.

| Token | Permit Support                          |
| ----- | --------------------------------------- |
| USDC  | Yes                                     |
| USDG  | Yes                                     |
| pyUSD | Yes                                     |
| USD₮0 | Yes                                     |
| USDT  | **No** — use standard approve + deposit |

<Steps>
  <Step title="Get the permit nonce (read)">
    Query the token's current nonce for your address.

    ```
    DepositToken.nonces(yourAddress) → uint256 nonce
    ```
  </Step>

  <Step title="Sign the EIP-712 permit message (off-chain)">
    Construct and sign an EIP-712 typed data message. This is an off-chain signature — no gas required.

    **EIP-712 Domain** (varies by token — this example is for USDC on Ethereum):

    | Field               | Value              |
    | ------------------- | ------------------ |
    | `name`              | `"USD Coin"`       |
    | `version`           | `"2"`              |
    | `chainId`           | `1`                |
    | `verifyingContract` | USDC token address |

    **Permit message**:

    | Field      | Value                               |
    | ---------- | ----------------------------------- |
    | `owner`    | Your wallet address                 |
    | `spender`  | `distributorCodeDepositorAddress`   |
    | `value`    | `depositAmount`                     |
    | `nonce`    | From Step 1                         |
    | `deadline` | Unix timestamp (e.g., now + 1 hour) |

    The EIP-712 type structure:

    ```
    Permit(address owner, address spender, uint256 value, uint256 nonce, uint256 deadline)
    ```

    Sign using your wallet's `signTypedData` (or equivalent EIP-712 signing method). Parse the resulting signature into `v`, `r`, `s` components.
  </Step>

  <Step title="Calculate minimumMint (read)">
    Same as the standard flow:

    ```
    Accountant.getRateInQuoteSafe() → uint256 rate
    ```
  </Step>

  <Step title="Execute depositWithPermit (transaction)">
    Call `depositWithPermit()` on the DistributorCodeDepositor with the permit signature.

    ```
    DistributorCodeDepositor.depositWithPermit(
      depositAsset,      // e.g., USDC address
      depositAmount,     // e.g., 1000000000 (1,000 USDC)
      minimumMint,       // from Step 3
      to,                // recipient of vault shares
      distributorCode,   // 0x if none
      deadline,          // from Step 2
      v,                 // signature recovery byte
      r,                 // signature first 32 bytes
      s                  // signature second 32 bytes
    ) → uint256 shares
    ```

    The contract verifies the permit signature on-chain, transfers your tokens, and mints vault shares — all in a single transaction.
  </Step>
</Steps>

<Warning>
  Smart contract wallets (like Privy Smart Wallets or Safe) **cannot sign
  permits** because they don't have a private key. Use the standard approval
  flow instead.
</Warning>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Transaction reverts with no error message">
    The most common cause is that `minimumMint` is set too high relative to the
    current exchange rate. Set it to `0` for testing or recalculate from the
    Accountant's `getRateInQuoteSafe()`.
  </Accordion>

  <Accordion title="PermitFailedAndAllowanceTooLow">
    The permit signature is invalid and there's no existing ERC-20 approval.
    Double-check the permit domain parameters (`name`, `version`,
    `verifyingContract`) match the token's EIP-712 domain. Or switch to the
    standard approve + deposit flow.
  </Accordion>

  <Accordion title="ERC20: insufficient allowance">
    You haven't approved the DistributorCodeDepositor to spend your tokens. Call
    `approve()` on the token contract before calling `deposit()`.
  </Accordion>

  <Accordion title="ERC20: transfer amount exceeds balance">
    Your wallet doesn't hold enough of the deposit token. Check your balance
    before depositing.
  </Accordion>

  <Accordion title="USDT approval fails">
    USDT requires resetting the allowance to `0` before setting a new value if
    there's an existing non-zero allowance. Call `approve(spender, 0)` first,
    then `approve(spender, amount)`. Other tokens (USDC, USDG, pyUSD) allow
    overwriting an existing approval directly.
  </Accordion>
</AccordionGroup>

***

## Next Steps

* [Direct Withdrawals](/v0.5.1/intro/products/earn/developers/guides/direct-contract/withdrawals) — Submit a withdrawal order
* [Direct Cancellations](/v0.5.1/intro/products/earn/developers/guides/direct-contract/cancellations) — Cancel a pending withdrawal
* [Vault Queries & Monitoring](/v0.5.1/intro/products/earn/developers/guides/direct-contract/vault-queries/index) — Read APY, TVL, check balances, and monitor withdrawal status
* [SDK Deposits Guide](/v0.5.1/intro/products/earn/developers/guides/deposits) — Use the Amplify SDK instead
