> ## 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 account by calling the DistributorCodeDepositor contract directly

This guide walks you through depositing tokens into an Amplify account 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 an account, you receive **account shares** in return. These shares represent your proportional ownership of the account's assets and appreciate in value as the account 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) |

### KYT Accounts

<Warning>
  As of v0.5.2, Amplify accounts use the **KYT** (Know Your Transaction) depositor contract (`DistributorCodeDepositorV1`). Both `deposit()` and `depositWithPermit()` require an `Attestation` parameter for compliance policy integration.

  For now, pass **empty/zero values** for the attestation fields as shown in the examples below. Contact the [Paxos Labs team](mailto:support@paxoslabs.com) to implement the compliance policy of your choice — at which point you will receive real attestation values to pass here.
</Warning>

The `Attestation` struct is passed as the last parameter before any permit fields:

```json theme={null}
{
  "uuid": "",
  "expiration": 0,
  "attester": "0x0000000000000000000000000000000000000000",
  "signature": "0x"
}
```

***

## What You'll Need

| Requirement           | Description                                                                                                                                                                      |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Contract addresses    | `distributorCodeDepositorAddress` and `accountantAddress` — see [Account Discovery](/v0.5.2/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 the DistributorCodeDepositor ABI, the ERC-20 ABI, and the Accountant ABI. Copy these into your project as a JSON file or inline constant.

### DistributorCodeDepositor ABI

Both `deposit()` and `depositWithPermit()` include the `_attestation` tuple parameter for KYT compliance.

```json theme={null}
[
  {
    "inputs": [
      { "name": "depositAsset", "type": "address" },
      { "name": "depositAmount", "type": "uint256" },
      { "name": "minimumMint", "type": "uint256" },
      { "name": "to", "type": "address" },
      { "name": "distributorCode", "type": "bytes" },
      {
        "components": [
          { "name": "uuid", "type": "string" },
          { "name": "expiration", "type": "uint256" },
          { "name": "attester", "type": "address" },
          { "name": "signature", "type": "bytes" }
        ],
        "name": "_attestation",
        "type": "tuple"
      }
    ],
    "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" },
      {
        "components": [
          { "name": "uuid", "type": "string" },
          { "name": "expiration", "type": "uint256" },
          { "name": "attester", "type": "address" },
          { "name": "signature", "type": "bytes" }
        ],
        "name": "_attestation",
        "type": "tuple"
      },
      { "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": "quote", "type": "address" }
    ],
    "name": "getRateInQuoteSafe",
    "outputs": [{ "name": "rateInQuote", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  }
]
```

***

## Contract Method Reference

### `deposit`

**`deposit(depositAsset, depositAmount, minimumMint, to, distributorCode, _attestation)`**

| 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 account shares (usually the depositor)                          |
| `distributorCode` | `bytes`   | Tracking code for referrals/attribution. Pass `0x` (empty bytes) if not applicable.              |
| `_attestation`    | `tuple`   | Compliance attestation struct. Pass empty/zero values for now — see [note above](#kyt-accounts). |

**Attestation fields**:

| Field        | Type      | Description                                 | Default Value                                |
| ------------ | --------- | ------------------------------------------- | -------------------------------------------- |
| `uuid`       | `string`  | Unique attestation identifier               | `""` (empty string)                          |
| `expiration` | `uint256` | Unix timestamp when the attestation expires | `0`                                          |
| `attester`   | `address` | Address of the attestation provider         | `0x0000000000000000000000000000000000000000` |
| `signature`  | `bytes`   | Cryptographic signature from the attester   | `0x` (empty bytes)                           |

<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`

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

Same parameters as `deposit()` (including the `_attestation` tuple), plus the permit fields appended **after** the attestation:

| 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 account's **Accountant** contract publishes the exchange rate between the deposit token and account shares. Use it to calculate a safe `minimumMint`.

### Contract call

```
Accountant.getRateInQuoteSafe(depositAssetAddress) → uint256 rateInQuote
```

`rateInQuote` represents the amount of the deposit asset per 1e18 account shares (i.e., per one full share). Pass the deposit token address as the `quote` parameter.

### 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(depositAssetAddress) → uint256 rateInQuote
    ```

    Then calculate: `minimumMint = ((depositAmount × 1e18) / rateInQuote) × (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
      {                  // _attestation — use empty values for now
        uuid: "",
        expiration: 0,
        attester: "0x0000000000000000000000000000000000000000",
        signature: "0x"
      }
    ) → uint256 shares
    ```

    The return value is the number of account 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)                                                                                           |
| `_attestation`    | `{ uuid: "", expiration: 0, attester: "0x0000000000000000000000000000000000000000", signature: "0x" }` |

***

## 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(depositAssetAddress) → uint256 rateInQuote
    ```
  </Step>

  <Step title="Execute depositWithPermit (transaction)">
    Call `depositWithPermit()` on the DistributorCodeDepositor with the permit signature. Note the `_attestation` tuple is placed **before** the permit parameters.

    ```
    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
      {                  // _attestation — use empty values for now
        uuid: "",
        expiration: 0,
        attester: "0x0000000000000000000000000000000000000000",
        signature: "0x"
      },
      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 account 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>

  <Accordion title="Transaction reverts without attestation parameter">
    The `DistributorCodeDepositorV1` contract requires the `_attestation` tuple
    parameter. If you omit it or use an older ABI without the attestation field,
    the transaction will revert. Ensure you're using the ABI from this guide and
    passing the attestation struct (empty values are fine for now). Contact the
    [Paxos Labs team](mailto:support@paxoslabs.com) to implement your compliance
    policy.
  </Accordion>
</AccordionGroup>

***

## Next Steps

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