# Supply Assets on Aave V3

Supply assets to Aave V3 markets to earn interest, and enable or disable them as collateral.

## Permit Overview

Some Aave operations support _permit functionality_ using [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) signatures to authorize ERC-20 token transfers within the same transaction.

### Benefits of Permit

- **Single Transaction**: Execute operations without separate approval transactions
- **Exact Amounts**: Sign permissions for specific amounts instead of infinite approvals
- **Time Limited**: Permits have deadlines for enhanced security

> [!NOTE]
> Permit is available for ERC-20 tokens that implement
> [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612).

## Supply Assets

By supplying assets to an Aave market, users earn interest on their deposits according to the reserve’s supply APY rate.

When supplying assets to an Aave market, you can use the following methods:

| Method                                    | Description                                                                                                   | Typical Scenario                                                                     |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| **Direct Supply**                         | Supply ERC-20 or native tokens directly from the sender’s wallet. aTokens are sent to the sender’s address. | User supplies assets from their own wallet.                                          |
| **On Behalf of Another**                  | Supply from the sender’s wallet, but send aTokens to another address.                                       | User supplies from one wallet and the supply position (aTokens) belongs to another. |
| **With Permit**                           | Use a permit signature to skip ERC-20 approval and supply in a single transaction.                            | User signs a permit and sends a single transaction. No ERC-20 allowance left behind. |
| **With Permit, On Behalf of Another**     | Same as permit supply, but aTokens are sent to another address.                                             | No ERC-20 allowance needed and the supply position belongs to another wallet.       |

To supply assets to an Aave market, follow these steps.

### 1. Identify the Supply Reserve

First, determine which reserve you want to supply assets to.

Given this `Reserve` object for WETH on an Ethereum market:

```ts title="Reserve"
const reserve: Reserve = {
  __typename: "Reserve",
  market: {
    __typename: "MarketInfo",
    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
    chain: { chainId: 1 },
    // …
  },
  underlyingToken: {
    __typename: "Currency",
    symbol: "WETH",
    name: "Wrapped Ether",
    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    // …
  },
  acceptsNative: {
    __typename: "NativeCurrency",
    symbol: "ETH",
    name: "Ethereum",
    // …
  },
  isFrozen: false,
  isPaused: false,
  permitSupported: true,
  userState: {
    __typename: "ReserveUserState",
    suppliable: {
      __typename: "TokenAmount",
      amount: {
        __typename: "DecimalValue",
        value: "1245.67",
        raw: "1245670000000000000000",
        decimals: 18,
        // …
      },
      // …
    },
  },
  // …
};
```

To supply to the reserve, you need to verify these conditions:

- `Reserve.isFrozen` is `false` - the reserve is not frozen
- `Reserve.isPaused` is `false` - the reserve is not paused
- `Reserve.userState.suppliable.amount.value` is **greater than 0** - the amount the user can supply to the reserve given their unique circumstances

> [!NOTE]
> Include a user address when fetching market and reserve data, or
> `Reserve.userState` will be empty.

The `Reserve.permitSupported` flag indicates whether the underlying token supports EIP-2612 permits.

Additionally, if `Reserve.acceptsNative` is not `null`, users can choose to supply the asset as the chain’s native token and it will be automatically wrapped before being sent to the reserve. This is typical for reserves of the wrapped version of the chain’s native token (e.g., WETH on Ethereum).

### 2. Prepare the Supply Execution Plan

Next, if all of these conditions are met, we can proceed with creating the execution plan for the supply operation.

Use the `useSupply` hook in React, the `supply` action in TypeScript, or the `supply` query in GraphQL to create the execution plan for supplying assets to a market reserve. In React and TypeScript, you can optionally supply on behalf of another address.

<tabgroup>
<tab label="React">

```tsx title="Direct ERC-20 Supply"
import { useWalletClient } from "wagmi";
import { useSupply, bigDecimal, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [supply, supplying] = useSupply();

const execute = async () => {
  const result = await supply({
    market: reserve.market.address,
    amount: {
      erc20: {
        currency: reserve.underlyingToken.address,
        value: bigDecimal(42), // 42 WETH
      },
    },
    sender: evmAddress(walletClient!.account.address),
    chainId: reserve.market.chain.chainId,
  });

  // …
};
```

```tsx title="Direct Native Supply"
import { useWalletClient } from "wagmi";
import { useSupply, bigDecimal, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [supply, supplying] = useSupply();

const execute = async () => {
  const result = await supply({
    market: reserve.market.address,
    amount: {
      native: bigDecimal(42), // 42 ETH
    },
    sender: evmAddress(walletClient!.account.address),
    chainId: reserve.market.chain.chainId,
  });

  // …
};
```

```tsx title="Supply On Behalf of Another"
import { useWalletClient } from "wagmi";
import { useSupply, bigDecimal, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [supply, supplying] = useSupply();

const execute = async () => {
  const result = await supply({
    market: reserve.market.address,
    amount: {
      erc20: {
        currency: reserve.underlyingToken.address,
        value: bigDecimal(42), // 42 WETH
      },
      // OR
      // native: bigDecimal(42), // 42 ETH
    },
    sender: evmAddress(walletClient!.account.address),
    chainId: reserve.market.chain.chainId,
    onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
  });

  // …
};
```

</tab>
<tab label="TypeScript">

```ts title="Direct ERC-20 Supply"
import { supply } from "@aave/client/actions";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await supply(client, {
  market: reserve.market.address,
  amount: {
    erc20: {
      currency: reserve.underlyingToken.address,
      value: bigDecimal(42), // 42 WETH
    },
  },
  sender: evmAddress(wallet.account.address),
  chainId: reserve.market.chain.chainId,
});

// …
```

```ts title="Direct Native Supply"
import { supply } from "@aave/client/actions";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await supply(client, {
  market: reserve.market.address,
  amount: {
    native: bigDecimal(42), // 42 ETH
  },
  sender: evmAddress(wallet.account.address),
  chainId: reserve.market.chain.chainId,
});

// …
```

```ts title="Supply On Behalf of Another"
import { supply } from "@aave/client/actions";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await supply(client, {
  market: reserve.market.address,
  amount: {
    erc20: {
      currency: reserve.underlyingToken.address,
      value: bigDecimal(42), // 42 WETH
    },
    // OR
    // native: bigDecimal(42), // 42 ETH
  },
  sender: evmAddress(wallet.account.address),
  chainId: reserve.market.chain.chainId,
  onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
});

// …
```

```ts title="client.ts"
import { AaveClient } from "@aave/client";

export const client = AaveClient.create();
```

```ts title="wallet.ts"
import { createWalletClient, http, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";

export const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY as Hex),
  chain: mainnet,
  transport: http(),
});
```

</tab>
<tab label="GraphQL">

```graphql title="Query"
query {
  supply(
    request: {
      market: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2"
      amount: {
        erc20: {
          currency: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          value: "42"
        }
        # OR
        # native: "42" # if the reserve accepts native currency
      }
      sender: "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"
      chainId: 1
    }
  ) {
    __typename
    ... on TransactionRequest {
      to
      from
      data
      value
      chainId
      operation
    }
    ... on ApprovalRequired {
      reason
      requiredAmount {
        value
        decimals
      }
      currentAllowance {
        value
        decimals
      }
      approval {
        to
        from
        data
        value
        chainId
        operation
      }
      originalTransaction {
        to
        from
        data
        value
        chainId
        operation
      }
    }
    ... on InsufficientBalanceError {
      required {
        value
        decimals
      }
      available {
        value
        decimals
      }
    }
  }
}
```

</tab>
</tabgroup>
If `Reserve.permitSupported` is `true` and you supply ERC-20 tokens, you can sign permits and prepare supply transactions.

- **React**: Use the `useSupply` and `useERC20Permit` hooks, with the `useERC20Permit` implementation for the [wallet library of choice](../getting-started/react#sign-erc-20-permits).
- **TypeScript**: Use the `supply` and `permitTypedData` actions together with the `signERC20PermitWith` helper, with the `signERC20PermitWith` implementation for the [wallet library of choice](../getting-started/typescript#sign-erc-20-permits).

<tabgroup>
<tab label="React">

```tsx title="Supply ERC-20 with Permit"
import { useSupply, bigDecimal, evmAddress } from "@aave/react";
import { useERC20Permit } from "@aave/react/viem";
import { useWalletClient } from "wagmi";

// …

const { data: walletClient } = useWalletClient();

const [signPermit, signing] = useERC20Permit(walletClient);
const [supply, supplying] = useSupply();

const execute = async () => {
  const amount = bigDecimal(42); // 42 WETH

  const permit = await signPermit({
    amount,
    chainId: reserve.market.chain.chainId,
    currency: reserve.underlyingToken.address,
    owner: evmAddress(walletClient!.account.address),
    spender: reserve.market.address,
  }).andThen((signature) =>
    supply({
      market: reserve.market.address,
      amount: {
        erc20: {
          currency: reserve.underlyingToken.address,
          value: amount, // 42 WETH
          permitSig: signature,
        },
      },
      sender: evmAddress(walletClient!.account.address),
      chainId: reserve.market.chain.chainId,
    })
  );

  // …
};
```

```tsx title="Supply ERC-20 with Permit On Behalf of Another"
import { useSupply, bigDecimal, evmAddress } from "@aave/react";
import { useERC20Permit } from "@aave/react/viem";
import { useWalletClient } from "wagmi";

// …

const { data: walletClient } = useWalletClient();

const [signPermit, signing] = useERC20Permit(walletClient);
const [supply, supplying] = useSupply();

const execute = async () => {
  const amount = bigDecimal(42); // 42 WETH

  const permit = await signPermit({
    amount,
    chainId: reserve.market.chain.chainId,
    currency: reserve.underlyingToken.address,
    owner: evmAddress(walletClient!.account.address),
    spender: reserve.market.address,
  }).andThen((signature) =>
    supply({
      market: reserve.market.address,
      amount: {
        erc20: {
          currency: reserve.underlyingToken.address,
          value: amount, // 42 WETH
          permitSig: signature,
        },
      },
      sender: evmAddress(walletClient!.account.address),
      chainId: reserve.market.chain.chainId,
      onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
    })
  );

  // …
};
```

</tab>
<tab label="TypeScript">

```tsx title="Supply ERC-20 with Permit"
import { supply, permitTypedData } from "@aave/client/actions";
import { signERC20PermitWith } from "@aave/client/viem";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const amount = bigDecimal(42); // 42 WETH

const result = await permitTypedData(client, {
  amount,
  chainId: reserve.market.chain.chainId,
  currency: reserve.underlyingToken.address,
  owner: evmAddress(wallet.account.address),
  spender: reserve.market.address,
})
  .andThen(signERC20PermitWith(wallet))
  .andThen((signature) =>
    supply(client, {
      market: reserve.market.address,
      amount: {
        erc20: {
          currency: reserve.underlyingToken.address,
          value: amount,
          permitSig: signature,
        },
      },
      sender: evmAddress(wallet.account.address),
      chainId: reserve.market.chain.chainId,
    })
  );

// …
```

```tsx title="Supply ERC-20 with Permit On Behalf of Another"
import { supply, permitTypedData } from "@aave/client/actions";
import { signERC20PermitWith } from "@aave/client/viem";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const amount = bigDecimal(42); // 42 WETH

const result = await permitTypedData(client, {
  amount,
  chainId: reserve.market.chain.chainId,
  currency: reserve.underlyingToken.address,
  owner: evmAddress(wallet.account.address),
  spender: reserve.market.address,
})
  .andThen(signERC20PermitWith(wallet))
  .andThen((signature) =>
    supply(client, {
      market: reserve.market.address,
      amount: {
        erc20: {
          currency: reserve.underlyingToken.address,
          value: amount,
          permitSig: signature,
        },
      },
      sender: evmAddress(wallet.account.address),
      chainId: reserve.market.chain.chainId,
      onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
    })
  );

// …
```

</tab>
</tabgroup>
### 3. Process the Supply Execution Plan

Finally, you need to handle the execution plan, and the process is the same whether or not you used a permit in the previous step.

> [!NOTE]
> With a permit signature, the execution plan runs as a single transaction.

- **React**: Use the `useSendTransaction` hook for the [wallet library of your choice](../getting-started/react#send-aave-transactions) to send the transactions in the execution plan.
- **TypeScript**: Use `sendWith` for your [chosen wallet library](../getting-started/typescript#send-aave-transactions) to send the transactions in the execution plan, and await indexing with `client.waitForTransaction`.
- **GraphQL**: If the response is a `TransactionRequest`, you can send it directly using the wallet associated with the from address.

<tabgroup>
<tab label="React">

```tsx title="Viem"
import { useWalletClient } from "wagmi";
import { errAsync, useSupply } from "@aave/react";
import { useSendTransaction } from "@aave/react/viem";

// …

const { data: walletClient } = useWalletClient();

const [supply, supplying] = useSupply();
const [sendTransaction, sending] = useSendTransaction(walletClient);

// …

// Optional: combine loading states
const loading = supplying.loading || sending.loading;
const error = supplying.error || sending.error;

// …

const execute = async () => {
  const result = await supply({
    // …
  }).andThen((plan) => {
    switch (plan.__typename) {
      case "TransactionRequest":
        // Single transaction execution
        return sendTransaction(plan);

      case "ApprovalRequired":
        // Approval + transaction sequence
        return sendTransaction(plan.approval).andThen(() =>
          sendTransaction(plan.originalTransaction)
        );

      case "InsufficientBalanceError":
        return errAsync(
          new Error(`Insufficient balance: ${plan.required.value} required.`)
        );
    }
  });

  if (result.isErr()) {
    console.error("Supply failed:", result.error);
  } else {
    console.log("Supply successful with hash:", result.value);
  }
};
```

</tab>
<tab label="TypeScript">

```ts title="Viem"
import { supply } from "@aave/client/actions";
import { sendWith } from "@aave/client/viem";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await supply(client, {
  // …
})
  .andThen(sendWith(wallet))
  .andThen(client.waitForTransaction);

if (result.isErr()) {
  console.error("Supply failed:", result.error);
} else {
  console.log("Supply successful:", result.value);
}
```

</tab>
<tab label="GraphQL">

```json title="TransactionRequest"
{
  "data": {
    "supply": {
      "__typename": "TransactionRequest",
      "to": "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
      "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
      "data": "0x617ba037000000000000000000000000c0…",
      "value": "0",
      "chainId": 1,
      "operation": "SUPPLY"
    }
  }
}
```

</tab>
</tabgroup>
In GraphQL, if the response is an `ApprovalRequired`, you must first send the `approval` transaction. Once it succeeds, you can then send the `originalTransaction`.

```json title="ApprovalRequired"
{
  "data": {
    "supply": {
      "__typename": "ApprovalRequired",
      "reason": "Insufficient allowance for ERC-20 token transfer",
      "requiredAmount": {
        "value": "42.0",
        "decimals": 18
      },
      "currentAllowance": {
        "value": "0.0",
        "decimals": 18
      },
      "approval": {
        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0x095ea7b3000000000000000000000000878…",
        "value": "0",
        "chainId": 1,
        "operation": null
      },
      "originalTransaction": {
        "to": "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0x617ba037000000000000000000000000c0…",
        "value": "0",
        "chainId": 1,
        "operation": "SUPPLY"
      }
    }
  }
}
```

In GraphQL, if the response is an `InsufficientBalanceError`, inform the user that they don’t have enough balance to supply the requested amount.

```json title="InsufficientBalanceError"
{
  "data": {
    "supply": {
      "__typename": "InsufficientBalanceError",
      "required": {
        "value": "42.0",
        "decimals": 18
      },
      "available": {
        "value": "15.5",
        "decimals": 18
      }
    }
  }
}
```

## Collateral Management

To manage which supplied assets are used as collateral for borrowing, follow these steps.

### 1. Identify the Collateral Position

First, determine which user supply position you want to enable or disable as collateral.

Given this `MarketUserReserveSupplyPosition` object:

```ts title="MarketUserReserveSupplyPosition"
const position: MarketUserReserveSupplyPosition = {
  __typename: "MarketUserReserveSupplyPosition",
  market: {
    __typename: "MarketInfo",
    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
    chain: { chainId: 1 },
    // …
  },
  currency: {
    __typename: "Currency",
    symbol: "WETH",
    name: "Wrapped Ether",
    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    // …
  },
  balance: {
    __typename: "TokenAmount",
    amount: {
      __typename: "DecimalValue",
      value: "5.0",
      raw: "5000000000000000000",
      decimals: 18,
      // …
    },
    // …
  },
  isCollateral: false, // Currently not used as collateral
  canBeCollateral: true, // Can be enabled as collateral
  // …
};
```

To enable a position as collateral, you need to verify these conditions:

- `position.canBeCollateral` is `true` - the asset can be used as collateral
- `position.isCollateral` is `false` - the asset is not currently used as collateral

To disable a position as collateral, you only need to check if `position.isCollateral` is `true`.

> [!NOTE]
> An Aave DAO vote can disable a reserve as collateral. This blocks new
> collateral use but doesn’t affect existing positions.

### 2. Prepare the Collateral Transaction Request

Next, we can proceed with creating the transaction request for the collateral toggle operation.

Use the `useCollateralToggle` hook in React, the `collateralToggle` action in TypeScript, or the `collateralToggle` query in GraphQL to create the transaction request for enabling or disabling collateral.

<tabgroup>
<tab label="React">

```tsx title="Toggle Collateral"
import { useWalletClient } from "wagmi";
import { useCollateralToggle, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [toggleCollateral, toggling] = useCollateralToggle();

const execute = async () => {
  const result = await toggleCollateral({
    market: position.market.address,
    underlyingToken: position.currency.address,
    user: evmAddress(walletClient!.account.address),
    chainId: position.market.chain.chainId,
  });

  // …
};
```

</tab>
<tab label="TypeScript">

```ts title="Toggle Collateral"
import { collateralToggle } from "@aave/client/actions";
import { evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await collateralToggle(client, {
  market: position.market.address,
  underlyingToken: position.currency.address,
  user: evmAddress(wallet.account.address),
  chainId: position.market.chain.chainId,
});

// …
```

```ts title="client.ts"
import { AaveClient } from "@aave/client";

export const client = AaveClient.create();
```

```ts title="wallet.ts"
import { createWalletClient, http, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";

export const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY as Hex),
  chain: mainnet,
  transport: http(),
});
```

</tab>
<tab label="GraphQL">

```graphql title="Query"
query {
  collateralToggle(
    request: {
      market: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2"
      underlyingToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
      user: "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"
      chainId: 1
    }
  ) {
    to
    from
    data
    value
    chainId
  }
}
```

</tab>
</tabgroup>
### 3. Send the Collateral Transaction

Finally, send the transaction.

- **React**: Use the `useSendTransaction` hook for the [wallet library of your choice](../getting-started/react#send-aave-transactions) to send the transaction.
- **TypeScript**: Use `sendWith` for your [chosen wallet library](../getting-started/typescript#send-aave-transactions) to initiate the transaction, and await indexing with `client.waitForTransaction`.
- **GraphQL**: The response is a `TransactionRequest` that can be sent directly using the wallet associated with the `from` address.

<tabgroup>
<tab label="React">

```tsx title="Viem"
import { useWalletClient } from "wagmi";
import { useCollateralToggle } from "@aave/react";
import { useSendTransaction } from "@aave/react/viem";

// …

const { data: walletClient } = useWalletClient();

const [toggleCollateral, toggling] = useCollateralToggle();
const [sendTransaction, sending] = useSendTransaction(walletClient);

// …

// Optional: combine loading states
const loading = toggling.loading || sending.loading;
const error = toggling.error || sending.error;

// …

const execute = async () => {
  const result = await toggleCollateral({
    // …
  }).andThen(sendTransaction);

  if (result.isErr()) {
    console.error("Collateral toggle failed:", result.error);
  } else {
    console.log("Collateral toggle successful with hash:", result.value);
  }
};
```

</tab>
<tab label="TypeScript">

```ts title="Viem"
import { collateralToggle } from "@aave/client/actions";
import { sendWith } from "@aave/client/viem";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await collateralToggle(client, {
  // …
})
  .andThen(sendWith(wallet))
  .andThen(client.waitForTransaction);

if (result.isErr()) {
  console.error("Collateral toggle failed:", result.error);
} else {
  console.log("Collateral toggle successful:", result.value);
}
```

</tab>
<tab label="GraphQL">

```json title="TransactionRequest"
{
  "data": {
    "collateralToggle": {
      "__typename": "TransactionRequest",
      "to": "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
      "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
      "data": "0x5a3b74b9000000000000000000000000c02…",
      "value": "0",
      "chainId": 1,
      "operation": "RESERVE_USED_AS_COLLATERAL_ENABLED"
    }
  }
}
```

</tab>
</tabgroup>
