0

I am trying to compile a contract in solidity for flash loan node bot, but it does not compile, so I can deploy it on L2 networks.

Contract code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// Import OpenZeppelin's IERC20 interface
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// Import Balancer interfaces
import { IVault } from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
import { IFlashLoanRecipient } from "@balancer-labs/v2-interfaces/contracts/vault/IFlashLoanRecipient.sol";

contract FlashLoanBot is IFlashLoanRecipient {
    IVault public balancerVault;  // Balancer's vault contract
    address public owner;  // Contract owner

    constructor(address _balancerVault) {
        balancerVault = IVault(_balancerVault);  // Initialize the Balancer Vault address
        owner = msg.sender;  // Assign the contract deployer as the owner
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not authorized");
        _;
    }

    // Function to initiate the flash loan for a specific token and amount
    function executeFlashLoan(address token, uint256 amount) external onlyOwner {
        address;  // Create an array with one token
        tokens[0] = token;  // Set the token address
        uint256;  // Create an array with one amount
        amounts[0] = amount;  // Set the loan amount

        // Call Balancer's flash loan function
        balancerVault.flashLoan(
            IFlashLoanRecipient(address(this)),  // The recipient of the loan is this contract
            tokens,  // Array containing the token being borrowed
            amounts,  // Array containing the amount being borrowed
            ""  // Empty user data
        );
    }

    // This function is called by Balancer Vault during the flash loan execution
    function receiveFlashLoan(
        IERC20[] memory tokens,
        uint256[] memory amounts,
        uint256[] memory fees,
        bytes memory userData
    ) external override {
        require(msg.sender == address(balancerVault), "Caller is not the Balancer Vault");

        // Perform token swaps or arbitrage logic here (this part is left to your strategy)

        // Repay the loan along with fees
        for (uint256 i = 0; i < tokens.length; i++) {
            uint256 totalRepayment = amounts[i] + fees[i];  // Calculate total repayment: loan + fee
            tokens[i].approve(address(balancerVault), totalRepayment);  // Approve the Vault to withdraw the repayment
        }
    }
}

hardhat.config

require("dotenv").config();
require("@nomiclabs/hardhat-waffle");

module.exports = {
  solidity: {
    version: "0.8.20",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
  networks: {
    polygon: {
      url: "https://polygon-rpc.com/",
      accounts: [`0x${process.env.PRIVATE_KEY}`],
      chainId: 137,
    },
    arbitrum: {
      url: "https://arb1.arbitrum.io/rpc",
      accounts: [`0x${process.env.PRIVATE_KEY}`],
      chainId: 42161,
    },
    optimism: {
      url: "https://mainnet.optimism.io",
      accounts: [`0x${process.env.PRIVATE_KEY}`],
      chainId: 10,
    }
  }
};

When I run npx hardhat compile I get

DeclarationError: Undeclared identifier. Did you mean "token"?
  --> contracts/FlashLoanBot.sol:27:9:
   |
27 |         tokens[0] = token;  // Set the token address
   |         ^^^^^^


DeclarationError: Undeclared identifier. Did you mean "amount"?
  --> contracts/FlashLoanBot.sol:29:9:
   |
29 |         amounts[0] = amount;  // Set the loan amount
   |         ^^^^^^^


DeclarationError: Undeclared identifier. Did you mean "token"?
  --> contracts/FlashLoanBot.sol:34:13:
   |
34 |             tokens,  // Array containing the token being borrowed
   |             ^^^^^^


DeclarationError: Undeclared identifier. Did you mean "amount"?
  --> contracts/FlashLoanBot.sol:35:13:
   |
35 |             amounts,  // Array containing the amount being borrowed
   |             ^^^^^^^


Error HH600: Compilation failed

Any ideas why that may be? I can't see it.

1 Answer 1

0

There are a couple of errors:

  1. Since, you're inheriting IFlashLoanRecipient which is having the receiveFlashLoan() function, so you need to override that function, and it's having the first parameter i.e., tokens array of type IERC20, but that IERC20 is not imported from Openzeppelin Contracts, rather it's imported from the IREC20 defined within the Balancer Contracts, i.e.,:

    import "../solidity-utils/openzeppelin/IERC20.sol";
    

    So, you can import the same in your FlashLoanBot contract like:

    import {IERC20} from "@balancer-labs/v2-interfaces/contracts/solidity-utils/openzeppelin/IERC20.sol";
    
  2. tokens and amounts are not defined as single element arrays inside the memory of executeFlashLoan() function, so you need to replace:

    address;  // Create an array with one token
    tokens[0] = token;  // Set the token address
    uint256;  // Create an array with one amount
    amounts[0] = amount;  // Set the loan amount
    

    with:

    IERC20[] memory tokens = new IERC20[](1);  // Create an array with one token
    tokens[0] = IERC20(token);  // Set the token address
    uint256[] memory amounts = new uint256[](1); // Create an array with one amount
    amounts[0] = amount;  // Set the loan amount
    

So, your revised contract code would be:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// Import Balancer interfaces
import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
import {IFlashLoanRecipient} from "@balancer-labs/v2-interfaces/contracts/vault/IFlashLoanRecipient.sol";
import {IERC20} from "@balancer-labs/v2-interfaces/contracts/solidity-utils/openzeppelin/IERC20.sol";

contract FlashLoanBot is IFlashLoanRecipient {
    IVault public balancerVault; // Balancer's vault contract
    address public owner; // Contract owner

    constructor(address _balancerVault) {
        balancerVault = IVault(_balancerVault); // Initialize the Balancer Vault address
        owner = msg.sender; // Assign the contract deployer as the owner
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not authorized");
        _;
    }

    // Function to initiate the flash loan for a specific token and amount
    function executeFlashLoan(address token, uint256 amount)
        external
        onlyOwner
    {
        IERC20[] memory tokens = new IERC20[](1); // Create an array with one token
        tokens[0] = IERC20(token); // Set the token address
        uint256[] memory amounts = new uint256[](1); // Create an array with one amount
        amounts[0] = amount; // Set the loan amount

        // Call Balancer's flash loan function
        balancerVault.flashLoan(
            IFlashLoanRecipient(address(this)), // The recipient of the loan is this contract
            tokens, // Array containing the token being borrowed
            amounts, // Array containing the amount being borrowed
            "" // Empty user data
        );
    }

    // This function is called by Balancer Vault during the flash loan execution
    function receiveFlashLoan(
        IERC20[] memory tokens,
        uint256[] memory amounts,
        uint256[] memory fees,
        bytes memory /* userData */
    ) external override {
        require(
            msg.sender == address(balancerVault),
            "Caller is not the Balancer Vault"
        );

        // Perform token swaps or arbitrage logic here (this part is left to your strategy)

        // Repay the loan along with fees
        for (uint256 i = 0; i < tokens.length; i++) {
            uint256 totalRepayment = amounts[i] + fees[i]; // Calculate total repayment: loan + fee
            tokens[i].approve(address(balancerVault), totalRepayment); // Approve the Vault to withdraw the repayment
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.