Easy extra income from Aave in Solidity 💸
Published: 2023-08-29 16:20:57

---
title: Easy extra income from Aave in Solidity 💸
published: true
description: 
tags: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xz6hizcjnp3f8nz83p2g.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-08-07 00:00 +0000
---

¿What if you could earn passive income on your DAO treasury? ¿Or during your your token presale, auction or in any project where you have idle ERC20 tokens sitting on a contract? On this guide we'll launch a staking contract that lends on AAVE on the background.

We'll launch this contract on Scroll Sepolia but I'll show what needs to be done in order to deploy it on any other chain where AAVE is deployed.

**Note:** We'll use Remix and Blockscout for deploying and interacting with the contracts. Alternatively you can use [this repo](https://github.com/Turupawn/AaveLenderDemo) that includes [commented code](https://github.com/Turupawn/AaveLenderDemo/blob/master/src/AaveLender.sol), [foundry unit tests](https://github.com/Turupawn/AaveLenderDemo/blob/master/test/AaveLender.t.sol), and a [github action](https://github.com/Turupawn/AaveLenderDemo/blob/master/.github/workflows/test.yml).

## Step1: Launch the contract

Make sure to have a wallet such as [Metamask](https://metamask.io/), [connect it to Scroll Sepolia](https://chainlist.org/chain/534351), and get funds from a [faucet](https://docs.scroll.io/en/user-guide/faucet/).

Launch the following contract on Remix by passing the `aavePoolAddress` and `stakedTokenAddress` addresses as constructor params. Use the following addresses deployed on Scroll Sepolia:
* `aavePoolAddress`: `0x48914C788295b5db23aF2b5F0B3BE775C4eA9440`
* `stakedTokenAddress`: `0x7984E363c38b590bB4CA35aEd5133Ef2c6619C40` which is the AAVE testnet DAI on Scroll Sepolia

```javascript
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

library DataTypes {
  struct ReserveConfigurationMap {
    uint256 data;
  }

  struct ReserveData {
    ReserveConfigurationMap configuration;
    uint128 liquidityIndex;
    uint128 currentLiquidityRate;
    uint128 variableBorrowIndex;
    uint128 currentVariableBorrowRate;
    uint128 currentStableBorrowRate;
    uint40 lastUpdateTimestamp;
    uint16 id;
    address aTokenAddress;
    address stableDebtTokenAddress;
    address variableDebtTokenAddress;
    address interestRateStrategyAddress;
    uint128 accruedToTreasury;
    uint128 unbacked;
    uint128 isolationModeTotalDebt;
  }
}

interface IPool {
    function borrow(
        address asset,
        uint256 amount,
        uint256 interestRateMode, // 1 for Stable, 2 for Variable
        uint16 referralCode,
        address onBehalfOf) external;

    function supply(
        address asset,
        uint256 amount,
        address onBehalfOf,
        uint16 referralCode) external;

    function withdraw(
        address asset,
        uint256 amount,
        address to) external returns (uint256);

    function getReserveData(
        address asset) external view returns (DataTypes.ReserveData memory);
}

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 value) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

contract AaveLender {
    address public immutable AAVE_POOL_ADDRESS;
    address public immutable STAKED_TOKEN_ADDRESS;
    address public immutable ATOKEN_ADDRESS;
    address public immutable OWNER;
    mapping(address account => uint amount) public stakeByAccount;
    uint public totalStake;

    constructor(address aavePoolAddress, address stakedTokenAddress) {
        AAVE_POOL_ADDRESS = aavePoolAddress;
        STAKED_TOKEN_ADDRESS = stakedTokenAddress;
        OWNER = msg.sender;
        ATOKEN_ADDRESS = IPool(aavePoolAddress).getReserveData(stakedTokenAddress).aTokenAddress;
    }

    function stake(uint amount) public {
        totalStake += amount;
        stakeByAccount[msg.sender] += amount;
        IERC20(STAKED_TOKEN_ADDRESS).transferFrom(msg.sender, address(this), amount);
        IERC20(STAKED_TOKEN_ADDRESS).approve(AAVE_POOL_ADDRESS, amount);
        IPool(AAVE_POOL_ADDRESS).supply(
            STAKED_TOKEN_ADDRESS,
            amount,
            address(this),
            0);
    }

    function unstake(uint amount) public {
        require(amount <= stakeByAccount[msg.sender], "Not enough stake");
        totalStake -= amount;
        stakeByAccount[msg.sender] -= amount;
        IPool(AAVE_POOL_ADDRESS).withdraw(
          STAKED_TOKEN_ADDRESS,
          amount,
          msg.sender
        );
    }

    function yieldEarned() public view returns(uint){
        return IERC20(ATOKEN_ADDRESS).balanceOf(address(this)) - totalStake;
    }

    function withdraw(uint amount) public {
        require(msg.sender == OWNER, "Sender is not owner");
        require(amount <= yieldEarned(), "Maximum withdraw exceeded");
        IPool(AAVE_POOL_ADDRESS).withdraw(
          STAKED_TOKEN_ADDRESS,
          amount,
          msg.sender
        );
    }
}
```

## Step 2: Mint testnet DAI

Now go to the [Aave Faucet](https://app.aave.com/faucet/), connect your wallet on Scroll Sepolia, click the Faucet button and confirm the transaction.

![Faucet de Aave](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfu89tcoqm7o1m4qo31a.png)

Once the transaction is confirmed you will be able to see your Testnet DAIs by adding the token by using the following address `0x7984E363c38b590bB4CA35aEd5133Ef2c6619C40`.

Remember that you're only able to borrow and lend tokens previously added to the Aave protocol. Also notice that this DAI version is not the same as other protocols on Sepolia and Scroll Sepolia such as [Uniswap v3](https://uniswap-showcase.sepolia.scroll.xyz/#/swap). This is a special version deployed by Aave and it's the only one compatible with Aave on Scroll Testnet. If you're on any mainnet chain you will be able to use the token official version.

## Step3: Approve the Staking contract

We need to approve the Staking contract so it can access our funds.

We'll also do this on [Scroll-Etherscan](https://sepolia.scrollscan.dev/address/0x7984E363c38b590bB4CA35aEd5133Ef2c6619C40#writeContract).

On the DAI contract at `0x7984E363c38b590bB4CA35aEd5133Ef2c6619C40`, pass the following params to the approve token function.

* `spender`: The staking contract you just launched
* `amount`: `100000000000000000000` which is 100 in wei format.

![Approve AaveLender contract](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwv04xqaxwii7jwi60ks.png)


## Step 4: Earn yield

Now you can stake by calling the `stake` function and passing as parameter the amount of DAI you approved.

![stake and lend on AAVE](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j5ln5h7vyf9z1m61on6o.png)

On every block, the yield will be increasing bit by bit and can be displaying by calling `yieldEarned`. The yield can be sent to the owner by calling the `withdraw` method.

![withdraw yield earned on aave](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3l1kdu476870kl3cu19x.png)

## Next steps

This demo shows how to lend on AAVE from a smart contract with minimal code. Now is up to you to use it to improve an existing project or to create something new. Personally, I would like to add this a lottery contract I'm working on so all the accumulated ticket sales generate yield while we wait for the lottery winner.. Let me know in the comments if you have ideas or questions about this tutorial.

Learn more about Aave on the [official documentation](https://docs.aave.com/developers/getting-started/readme).

**Thanks for watching this guide!**

Follow Filosofía Código on dev.to and in [Youtube]( https://www.youtube.com/channel/UCbF5CFuXv2vTkcGfepWV2nA) for everything related to Blockchain development.