OverviewRecipes

Smart Wallets with Aave

Learn how to build DeFi applications that interact with Aave using Alchemy Smart Wallets. This recipe covers supplying and withdrawing assets with both our Core library and our Wallet APIs for seamless user experiences.

Prerequisites

  1. Have DAI available on your chosen chain (default: Arbitrum).
  2. Alchemy API key, Account config and Gas Manager policy ID for sponsored transactions (you can follow the setup here)

Walkthrough

Check out this video walkthrough, and follow along with the quick start below:

Quick Start

  1. Clone and setup:

    $git clone https://github.com/alchemyplatform/smart-wallets-aave.git
    >cd smart-wallets-aave
    >npm install
  2. Configure environment:

    $cp .env.example .env
    ># Fill in your ALCHEMY_API_KEY, PRIVATE_KEY, and PAYMASTER_POLICY_ID
  3. Initialize smart wallet and get address:

    $npm run account
  4. Fund your smart wallet: Send 0.01+ DAI to the smart wallet address from step 3

  5. Interact with Aave:

    $npm run supply # Supply assets to Aave
    >npm run withdraw # Withdraw assets from Aave
1

Configure the integration

The configuration is centralized in src/config.ts for easy customization:

1import { arbitrum, sepolia } from "@account-kit/infra";
2
3export const config = {
4 // Network configuration - change this to switch chains
5 chain: arbitrum, // Can be changed to sepolia, polygon, etc.
6
7 // Token and protocol addresses
8 addresses: {
9 dai: {
10 [arbitrum.id]: "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1",
11 [sepolia.id]: "0x68194a729C2450ad26072b3D33ADaCbcef39D574",
12 },
13 aaveV3Pool: {
14 [arbitrum.id]: "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
15 [sepolia.id]: "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951",
16 },
17 },
18
19 // Transaction amounts
20 amounts: {
21 deposit: "0.01", // Amount to deposit
22 withdraw: "0.01", // Amount to withdraw
23 },
24};
2

Interact with Aave Protocol

This approach uses the direct @aa-sdk/core implementation for simpler, more streamlined Aave interactions.

1import { LocalAccountSigner } from "@aa-sdk/core";
2import { createModularAccountAlchemyClient } from "@account-kit/smart-contracts";
3import { alchemy } from "@account-kit/infra";
4import { reserve, supply, withdraw } from "@aave/client/actions";
5import {
6 currentChain,
7 getCurrentTokenAddress,
8 getCurrentAavePoolAddress,
9 config,
10} from "./config";
11
12// Supply assets to Aave
13async function executeSupply() {
14 const alchemyApiKey = process.env.ALCHEMY_API_KEY!;
15 const privateKey = process.env.PRIVATE_KEY! as `0x${string}`;
16 const policyId = process.env.PAYMASTER_POLICY_ID! as `0x${string}`;
17
18 // Setup signer
19 const signer = LocalAccountSigner.privateKeyToAccountSigner(privateKey);
20
21 // Create smart account client with gas sponsorship
22 const smartAccountClient = await createModularAccountAlchemyClient({
23 transport: alchemy({ apiKey: alchemyApiKey }),
24 policyId, // Enables gas sponsorship
25 chain: currentChain,
26 signer,
27 });
28
29 const accountAddress = smartAccountClient.account.address;
30
31 // Get reserve data from Aave
32 const reserveDataResult = await reserve(client, {
33 market: evmAddress(getCurrentAavePoolAddress()),
34 underlyingToken: evmAddress(getCurrentTokenAddress()),
35 chainId: chainId(currentChain.id),
36 user: accountAddress,
37 });
38
39 const reserveData = reserveDataResult.value;
40
41 // Get supply transaction data
42 const supplyResult = await supply(client, {
43 market: reserveData.market.address,
44 amount: {
45 erc20: {
46 currency: reserveData.underlyingToken.address,
47 value: config.amounts.deposit,
48 },
49 },
50 sender: evmAddress(accountAddress),
51 chainId: reserveData.market.chain.chainId,
52 });
53
54 let supplyData = supplyResult.value;
55
56 // Handle transactions (approval + supply or just supply)
57 if (supplyData.__typename === "ApprovalRequired") {
58 // Send approval transaction
59 const approvalTx = await smartAccountClient.sendUserOperation({
60 account: smartAccountClient.account,
61 uo: {
62 target: supplyData.approval.to,
63 data: supplyData.approval.data,
64 },
65 });
66
67 await smartAccountClient.getUserOperationReceipt(approvalTx.hash);
68
69 // Send supply transaction
70 const supplyTx = await smartAccountClient.sendUserOperation({
71 account: smartAccountClient.account,
72 uo: {
73 target: supplyData.originalTransaction.to,
74 data: supplyData.originalTransaction.data,
75 value: BigInt(supplyData.originalTransaction.value),
76 },
77 });
78
79 console.log("Supply completed! Hash:", supplyTx.hash);
80 }
81}
82
83// Withdraw assets from Aave
84async function executeWithdraw() {
85 // Setup same as supply...
86 const smartAccountClient = await createModularAccountAlchemyClient({
87 transport: alchemy({ apiKey: alchemyApiKey }),
88 policyId,
89 chain: currentChain,
90 signer,
91 });
92
93 // Get withdraw transaction data
94 const withdrawResult = await withdraw(client, {
95 market: reserveData.market.address,
96 amount: {
97 erc20: {
98 currency: reserveData.underlyingToken.address,
99 value: { exact: config.amounts.withdraw }, // or { max: true } for all
100 },
101 },
102 sender: evmAddress(accountAddress),
103 chainId: reserveData.market.chain.chainId,
104 });
105
106 let withdrawData = withdrawResult.value;
107
108 if (withdrawData.__typename === "TransactionRequest") {
109 const withdrawTx = await smartAccountClient.sendUserOperation({
110 account: smartAccountClient.account,
111 uo: {
112 target: withdrawData.to,
113 data: withdrawData.data,
114 value: BigInt(withdrawData.value),
115 },
116 });
117
118 console.log("Withdrawal completed! Hash:", withdrawTx.hash);
119 }
120}
3

Available Scripts

The repository includes convenient scripts for different approaches:

$# Core implementation (recommended)
>npm run core:account # Initialize account
>npm run core:supply # Supply to Aave
>npm run core:withdraw # Withdraw from Aave
>
># Wallet APIs implementation
>npm run wallet:account # Initialize account
>npm run wallet:supply # Supply to Aave
>npm run wallet:withdraw # Withdraw from Aave
>
># Default scripts (use Core)
>npm run account # Defaults to core:account
>npm run supply # Defaults to core:supply
>npm run withdraw # Defaults to core:withdraw

Success!

You can now interact with Aave protocol through smart wallets with sponsored gas fees, enabling seamless DeFi experiences for supplying, withdrawing, and managing liquidity without gas complexity.

Resources