├── aave-flash-loan-v2 ├── .env.example ├── .gitignore ├── hardhat.config.js ├── README.md ├── scripts │ └── deployFlashLoan.js ├── package.json └── contracts │ └── FlashLoan.sol ├── aave-flash-loan-v3 ├── .env.example ├── .gitignore ├── hardhat.config.js ├── README.md ├── scripts │ ├── deployDex.js │ ├── deployFlashLoan.js │ └── deployFlashLoanArbitrage.js ├── package.json └── contracts │ ├── FlashLoan.sol │ ├── Dex.sol │ └── FlashLoanArbitrage.sol └── README.md /aave-flash-loan-v2/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | INFURA_GOERLI_ENDPOINT= -------------------------------------------------------------------------------- /aave-flash-loan-v3/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | INFURA_GOERLI_ENDPOINT= -------------------------------------------------------------------------------- /aave-flash-loan-v2/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | typechain-types 7 | 8 | #Hardhat files 9 | cache 10 | artifacts 11 | 12 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | typechain-types 7 | 8 | #Hardhat files 9 | cache 10 | artifacts 11 | 12 | -------------------------------------------------------------------------------- /aave-flash-loan-v2/hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomicfoundation/hardhat-toolbox"); 2 | require("dotenv").config(); 3 | 4 | /** @type import('hardhat/config').HardhatUserConfig */ 5 | module.exports = { 6 | solidity: "0.6.12", 7 | networks: { 8 | goerli: { 9 | url: process.env.INFURA_GOERLI_ENDPOINT, 10 | accounts: [process.env.PRIVATE_KEY], 11 | }, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomicfoundation/hardhat-toolbox"); 2 | require("dotenv").config(); 3 | 4 | /** @type import('hardhat/config').HardhatUserConfig */ 5 | module.exports = { 6 | solidity: "0.8.10", 7 | networks: { 8 | goerli: { 9 | url: process.env.INFURA_GOERLI_ENDPOINT, 10 | accounts: [process.env.PRIVATE_KEY], 11 | }, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /aave-flash-loan-v2/README.md: -------------------------------------------------------------------------------- 1 | # Sample Hardhat Project 2 | 3 | This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract. 4 | 5 | Try running some of the following tasks: 6 | 7 | ```shell 8 | npx hardhat help 9 | npx hardhat test 10 | REPORT_GAS=true npx hardhat test 11 | npx hardhat node 12 | npx hardhat run scripts/deploy.js 13 | ``` 14 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/README.md: -------------------------------------------------------------------------------- 1 | # Sample Hardhat Project 2 | 3 | This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract. 4 | 5 | Try running some of the following tasks: 6 | 7 | ```shell 8 | npx hardhat help 9 | npx hardhat test 10 | REPORT_GAS=true npx hardhat test 11 | npx hardhat node 12 | npx hardhat run scripts/deploy.js 13 | ``` 14 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/scripts/deployDex.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | console.log("deploying..."); 5 | const Dex = await hre.ethers.getContractFactory("Dex"); 6 | const dex = await Dex.deploy(); 7 | 8 | await dex.deployed(); 9 | 10 | console.log("Dex contract deployed: ", dex.address); 11 | } 12 | 13 | main().catch((error) => { 14 | console.error(error); 15 | process.exitCode = 1; 16 | }); 17 | -------------------------------------------------------------------------------- /aave-flash-loan-v2/scripts/deployFlashLoan.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | console.log("deploying..."); 5 | const FlashLoan = await hre.ethers.getContractFactory("FlashLoan"); 6 | const flashLoan = await FlashLoan.deploy( 7 | "0x5E52dEc931FFb32f609681B8438A51c675cc232d" 8 | ); 9 | 10 | await flashLoan.deployed(); 11 | 12 | console.log("Flash loan contract deployed: ", flashLoan.address); 13 | } 14 | 15 | main().catch((error) => { 16 | console.error(error); 17 | process.exitCode = 1; 18 | }); 19 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/scripts/deployFlashLoan.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | console.log("deploying..."); 5 | const FlashLoan = await hre.ethers.getContractFactory("FlashLoan"); 6 | const flashLoan = await FlashLoan.deploy( 7 | "0xc4dCB5126a3AfEd129BC3668Ea19285A9f56D15D" 8 | ); 9 | 10 | await flashLoan.deployed(); 11 | 12 | console.log("Flash loan contract deployed: ", flashLoan.address); 13 | } 14 | 15 | main().catch((error) => { 16 | console.error(error); 17 | process.exitCode = 1; 18 | }); 19 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/scripts/deployFlashLoanArbitrage.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | console.log("deploying..."); 5 | const FlashLoanArbitrage = await hre.ethers.getContractFactory( 6 | "FlashLoanArbitrage" 7 | ); 8 | const flashLoanArbitrage = await FlashLoanArbitrage.deploy( 9 | "0xc4dCB5126a3AfEd129BC3668Ea19285A9f56D15D" 10 | ); 11 | 12 | await flashLoanArbitrage.deployed(); 13 | 14 | console.log("Flash loan contract deployed: ", flashLoanArbitrage.address); 15 | } 16 | 17 | main().catch((error) => { 18 | console.error(error); 19 | process.exitCode = 1; 20 | }); 21 | -------------------------------------------------------------------------------- /aave-flash-loan-v2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@ethersproject/abi": "^5.7.0", 5 | "@ethersproject/providers": "^5.7.1", 6 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.3", 7 | "@nomicfoundation/hardhat-network-helpers": "^1.0.6", 8 | "@nomicfoundation/hardhat-toolbox": "^2.0.0", 9 | "@nomiclabs/hardhat-ethers": "^2.1.1", 10 | "@nomiclabs/hardhat-etherscan": "^3.1.0", 11 | "@typechain/ethers-v5": "^10.1.0", 12 | "@typechain/hardhat": "^6.1.3", 13 | "chai": "^4.3.6", 14 | "ethers": "^5.7.1", 15 | "hardhat": "^2.11.2", 16 | "hardhat-gas-reporter": "^1.0.9", 17 | "solidity-coverage": "^0.8.2", 18 | "typechain": "^8.1.0" 19 | }, 20 | "dependencies": { 21 | "@aave/protocol-v2": "^1.0.1", 22 | "dotenv": "^16.0.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@ethersproject/abi": "^5.7.0", 5 | "@ethersproject/providers": "^5.7.1", 6 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.3", 7 | "@nomicfoundation/hardhat-network-helpers": "^1.0.6", 8 | "@nomicfoundation/hardhat-toolbox": "^2.0.0", 9 | "@nomiclabs/hardhat-ethers": "^2.1.1", 10 | "@nomiclabs/hardhat-etherscan": "^3.1.0", 11 | "@typechain/ethers-v5": "^10.1.0", 12 | "@typechain/hardhat": "^6.1.3", 13 | "chai": "^4.3.6", 14 | "ethers": "^5.7.1", 15 | "hardhat": "^2.11.2", 16 | "hardhat-gas-reporter": "^1.0.9", 17 | "solidity-coverage": "^0.8.2", 18 | "typechain": "^8.1.0" 19 | }, 20 | "dependencies": { 21 | "@aave/core-v3": "^1.16.2", 22 | "@openzeppelin/contracts": "^4.7.3", 23 | "dotenv": "^16.0.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aave Flash Loan Tutorial 2 | Create an Aave Flash Loan arbitrage smart contract from scratch in this comprehensive flash loan tutorial by Block Explorer. 3 | 4 | ## Project repo: 5 | https://github.com/jspruance/aave-flash-loan-tutorial 6 | 7 | ## Aave v3 Flash Loan documentation: 8 | https://docs.aave.com/developers/guides/flash-loans 9 | https://docs.aave.com/developers/deployed-contracts/v3-testnet-addresses 10 | 11 | ## DAI-TestnetMintableERC20-Aave token (Goerli): 12 | 0xDF1742fE5b0bFc12331D8EAec6b478DfDbD31464 13 | 14 | ## USDC-TestnetMintableERC20-Aave token(Goerli): 15 | 0xA2025B15a1757311bfD68cb14eaeFCc237AF5b43 16 | 17 | ## AAVE PoolAddressProvider (Goerli): 18 | 0x5E52dEc931FFb32f609681B8438A51c675cc232d 19 | 20 | ## Remix imports: 21 | import {FlashLoanReceiverBase} from "https://github.com/aave/protocol-v2/blob/master/contracts/flashloan/base/FlashLoanReceiverBase.sol"; 22 | import {ILendingPool} from "https://github.com/aave/protocol-v2/blob/master/contracts/interfaces/ILendingPool.sol"; 23 | import {ILendingPoolAddressesProvider} from "https://github.com/aave/protocol-v2/blob/master/contracts/interfaces/ILendingPoolAddressesProvider.sol"; 24 | import {IERC20} from "https://github.com/aave/protocol-v2/blob/master/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 25 | 26 | ## Dex.sol deployed (Goerli): 27 | 0xD6e8c479B6B62d8Ce985C0f686D39e96af9424df 28 | 29 | ## Add liquidity to Dex.sol: 30 | USDC 1500 31 | DAI 1500 32 | 33 | ## Approve: 34 | USDC 1000000000 35 | DAI 1200000000000000000000 36 | 37 | ## Request Loan - USDC (6 decimal): 38 | 0xA2025B15a1757311bfD68cb14eaeFCc237AF5b43,1000000000 // 1,000 USDC 39 | 0xA2025B15a1757311bfD68cb14eaeFCc237AF5b43,1000000 // 1 USDC 40 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/contracts/FlashLoan.sol: -------------------------------------------------------------------------------- 1 | // contracts/FlashLoan.sol 2 | // SPDX-License-Identifier: MIT 3 | pragma solidity 0.8.10; 4 | 5 | import {FlashLoanSimpleReceiverBase} from "@aave/core-v3/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol"; 6 | import {IPoolAddressesProvider} from "@aave/core-v3/contracts/interfaces/IPoolAddressesProvider.sol"; 7 | import {IERC20} from "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 8 | 9 | contract FlashLoan is FlashLoanSimpleReceiverBase { 10 | address payable owner; 11 | 12 | constructor(address _addressProvider) 13 | FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_addressProvider)) 14 | { 15 | owner = payable(msg.sender); 16 | } 17 | 18 | /** 19 | This function is called after your contract has received the flash loaned amount 20 | */ 21 | function executeOperation( 22 | address asset, 23 | uint256 amount, 24 | uint256 premium, 25 | address initiator, 26 | bytes calldata params 27 | ) external override returns (bool) { 28 | // 29 | // This contract now has the funds requested. 30 | // Your logic goes here. 31 | // 32 | 33 | // At the end of your logic above, this contract owes 34 | // the flashloaned amount + premiums. 35 | // Therefore ensure your contract has enough to repay 36 | // these amounts. 37 | 38 | // Approve the Pool contract allowance to *pull* the owed amount 39 | uint256 amountOwed = amount + premium; 40 | IERC20(asset).approve(address(POOL), amountOwed); 41 | 42 | return true; 43 | } 44 | 45 | function requestFlashLoan(address _token, uint256 _amount) public { 46 | address receiverAddress = address(this); 47 | address asset = _token; 48 | uint256 amount = _amount; 49 | bytes memory params = ""; 50 | uint16 referralCode = 0; 51 | 52 | POOL.flashLoanSimple( 53 | receiverAddress, 54 | asset, 55 | amount, 56 | params, 57 | referralCode 58 | ); 59 | } 60 | 61 | function getBalance(address _tokenAddress) external view returns (uint256) { 62 | return IERC20(_tokenAddress).balanceOf(address(this)); 63 | } 64 | 65 | function withdraw(address _tokenAddress) external onlyOwner { 66 | IERC20 token = IERC20(_tokenAddress); 67 | token.transfer(msg.sender, token.balanceOf(address(this))); 68 | } 69 | 70 | modifier onlyOwner() { 71 | require( 72 | msg.sender == owner, 73 | "Only the contract owner can call this function" 74 | ); 75 | _; 76 | } 77 | 78 | receive() external payable {} 79 | } 80 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/contracts/Dex.sol: -------------------------------------------------------------------------------- 1 | // contracts/FlashLoan.sol 2 | // SPDX-License-Identifier: MIT 3 | pragma solidity 0.8.10; 4 | 5 | import {IERC20} from "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 6 | 7 | contract Dex { 8 | address payable public owner; 9 | 10 | // Aave ERC20 Token addresses on Goerli network 11 | address private immutable daiAddress = 12 | 0xDF1742fE5b0bFc12331D8EAec6b478DfDbD31464; 13 | address private immutable usdcAddress = 14 | 0xA2025B15a1757311bfD68cb14eaeFCc237AF5b43; 15 | 16 | IERC20 private dai; 17 | IERC20 private usdc; 18 | 19 | // exchange rate indexes 20 | uint256 dexARate = 90; 21 | uint256 dexBRate = 100; 22 | 23 | // keeps track of individuals' dai balances 24 | mapping(address => uint256) public daiBalances; 25 | 26 | // keeps track of individuals' USDC balances 27 | mapping(address => uint256) public usdcBalances; 28 | 29 | constructor() { 30 | owner = payable(msg.sender); 31 | dai = IERC20(daiAddress); 32 | usdc = IERC20(usdcAddress); 33 | } 34 | 35 | function depositUSDC(uint256 _amount) external { 36 | usdcBalances[msg.sender] += _amount; 37 | uint256 allowance = usdc.allowance(msg.sender, address(this)); 38 | require(allowance >= _amount, "Check the token allowance"); 39 | usdc.transferFrom(msg.sender, address(this), _amount); 40 | } 41 | 42 | function depositDAI(uint256 _amount) external { 43 | daiBalances[msg.sender] += _amount; 44 | uint256 allowance = dai.allowance(msg.sender, address(this)); 45 | require(allowance >= _amount, "Check the token allowance"); 46 | dai.transferFrom(msg.sender, address(this), _amount); 47 | } 48 | 49 | function buyDAI() external { 50 | uint256 daiToReceive = ((usdcBalances[msg.sender] / dexARate) * 100) * 51 | (10**12); 52 | dai.transfer(msg.sender, daiToReceive); 53 | } 54 | 55 | function sellDAI() external { 56 | uint256 usdcToReceive = ((daiBalances[msg.sender] * dexBRate) / 100) / 57 | (10**12); 58 | usdc.transfer(msg.sender, usdcToReceive); 59 | } 60 | 61 | function getBalance(address _tokenAddress) external view returns (uint256) { 62 | return IERC20(_tokenAddress).balanceOf(address(this)); 63 | } 64 | 65 | function withdraw(address _tokenAddress) external onlyOwner { 66 | IERC20 token = IERC20(_tokenAddress); 67 | token.transfer(msg.sender, token.balanceOf(address(this))); 68 | } 69 | 70 | modifier onlyOwner() { 71 | require( 72 | msg.sender == owner, 73 | "Only the contract owner can call this function" 74 | ); 75 | _; 76 | } 77 | 78 | receive() external payable {} 79 | } 80 | -------------------------------------------------------------------------------- /aave-flash-loan-v2/contracts/FlashLoan.sol: -------------------------------------------------------------------------------- 1 | // contracts/FlashLoanV2.sol 2 | // SPDX-License-Identifier: MIT 3 | pragma solidity 0.6.12; 4 | 5 | import {FlashLoanReceiverBase} from "@aave/protocol-v2/contracts/flashloan/base/FlashLoanReceiverBase.sol"; 6 | import {ILendingPool} from "@aave/protocol-v2/contracts/interfaces/ILendingPool.sol"; 7 | import {ILendingPoolAddressesProvider} from "@aave/protocol-v2/contracts/interfaces/ILendingPoolAddressesProvider.sol"; 8 | import {IERC20} from "@aave/protocol-v2/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 9 | 10 | contract FlashLoan is FlashLoanReceiverBase { 11 | constructor(address _addressProvider) 12 | public 13 | FlashLoanReceiverBase(ILendingPoolAddressesProvider(_addressProvider)) 14 | {} 15 | 16 | /** 17 | This function is called after your contract has received the flash loaned amount 18 | */ 19 | function executeOperation( 20 | address[] calldata assets, 21 | uint256[] calldata amounts, 22 | uint256[] calldata premiums, 23 | address initiator, 24 | bytes calldata params 25 | ) external override returns (bool) { 26 | // 27 | // This contract now has the funds requested. 28 | // Your logic goes here. 29 | // 30 | 31 | // At the end of your logic above, this contract owes 32 | // the flashloaned amounts + premiums. 33 | // Therefore ensure your contract has enough to repay 34 | // these amounts. 35 | 36 | // Approve the LendingPool contract allowance to *pull* the owed amount 37 | for (uint256 i = 0; i < assets.length; i++) { 38 | uint256 amountOwing = amounts[i].add(premiums[i]); 39 | IERC20(assets[i]).approve(address(LENDING_POOL), amountOwing); 40 | } 41 | 42 | return true; 43 | } 44 | 45 | function requestFlashLoan(address _token, uint256 _amount) public { 46 | address receiverAddress = address(this); 47 | 48 | address[] memory assets = new address[](1); 49 | assets[0] = _token; 50 | 51 | uint256[] memory amounts = new uint256[](1); 52 | amounts[0] = _amount; 53 | 54 | // 0 = no debt, 1 = stable, 2 = variable 55 | uint256[] memory modes = new uint256[](1); 56 | modes[0] = 0; 57 | 58 | address onBehalfOf = address(this); 59 | bytes memory params = ""; 60 | uint16 referralCode = 0; 61 | 62 | LENDING_POOL.flashLoan( 63 | receiverAddress, 64 | assets, 65 | amounts, 66 | modes, 67 | onBehalfOf, 68 | params, 69 | referralCode 70 | ); 71 | } 72 | 73 | function getBalance(address _tokenAddress) external view returns (uint256) { 74 | return IERC20(_tokenAddress).balanceOf(address(this)); 75 | } 76 | 77 | function withdraw(address _tokenAddress) external onlyOwner { 78 | IERC20(_tokenAddress).transfer( 79 | msg.sender, 80 | token.balanceOf(address(this)) 81 | ); 82 | } 83 | 84 | modifier onlyOwner() { 85 | require( 86 | msg.sender == owner, 87 | "Only the contract owner can call this function" 88 | ); 89 | _; 90 | } 91 | 92 | receive() external payable {} 93 | } 94 | -------------------------------------------------------------------------------- /aave-flash-loan-v3/contracts/FlashLoanArbitrage.sol: -------------------------------------------------------------------------------- 1 | // contracts/FlashLoan.sol 2 | // SPDX-License-Identifier: MIT 3 | pragma solidity 0.8.10; 4 | 5 | import {FlashLoanSimpleReceiverBase} from "@aave/core-v3/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol"; 6 | import {IPoolAddressesProvider} from "@aave/core-v3/contracts/interfaces/IPoolAddressesProvider.sol"; 7 | import {IERC20} from "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 8 | 9 | interface IDex { 10 | function depositUSDC(uint256 _amount) external; 11 | 12 | function depositDAI(uint256 _amount) external; 13 | 14 | function buyDAI() external; 15 | 16 | function sellDAI() external; 17 | } 18 | 19 | contract FlashLoanArbitrage is FlashLoanSimpleReceiverBase { 20 | address payable owner; 21 | 22 | // Aave ERC20 Token addresses on Goerli network 23 | address private immutable daiAddress = 24 | 0xDF1742fE5b0bFc12331D8EAec6b478DfDbD31464; 25 | address private immutable usdcAddress = 26 | 0xA2025B15a1757311bfD68cb14eaeFCc237AF5b43; 27 | address private dexContractAddress = 28 | 0xD6e8c479B6B62d8Ce985C0f686D39e96af9424df; 29 | 30 | IERC20 private dai; 31 | IERC20 private usdc; 32 | IDex private dexContract; 33 | 34 | constructor(address _addressProvider) 35 | FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_addressProvider)) 36 | { 37 | owner = payable(msg.sender); 38 | 39 | dai = IERC20(daiAddress); 40 | usdc = IERC20(usdcAddress); 41 | dexContract = IDex(dexContractAddress); 42 | } 43 | 44 | /** 45 | This function is called after your contract has received the flash loaned amount 46 | */ 47 | function executeOperation( 48 | address asset, 49 | uint256 amount, 50 | uint256 premium, 51 | address initiator, 52 | bytes calldata params 53 | ) external override returns (bool) { 54 | // 55 | // This contract now has the funds requested. 56 | // Your logic goes here. 57 | // 58 | 59 | // Arbirtage operation 60 | dexContract.depositUSDC(1000000000); // 1000 USDC 61 | dexContract.buyDAI(); 62 | dexContract.depositDAI(dai.balanceOf(address(this))); 63 | dexContract.sellDAI(); 64 | 65 | // At the end of your logic above, this contract owes 66 | // the flashloaned amount + premiums. 67 | // Therefore ensure your contract has enough to repay 68 | // these amounts. 69 | 70 | // Approve the Pool contract allowance to *pull* the owed amount 71 | uint256 amountOwed = amount + premium; 72 | IERC20(asset).approve(address(POOL), amountOwed); 73 | 74 | return true; 75 | } 76 | 77 | function requestFlashLoan(address _token, uint256 _amount) public { 78 | address receiverAddress = address(this); 79 | address asset = _token; 80 | uint256 amount = _amount; 81 | bytes memory params = ""; 82 | uint16 referralCode = 0; 83 | 84 | POOL.flashLoanSimple( 85 | receiverAddress, 86 | asset, 87 | amount, 88 | params, 89 | referralCode 90 | ); 91 | } 92 | 93 | function approveUSDC(uint256 _amount) external returns (bool) { 94 | return usdc.approve(dexContractAddress, _amount); 95 | } 96 | 97 | function allowanceUSDC() external view returns (uint256) { 98 | return usdc.allowance(address(this), dexContractAddress); 99 | } 100 | 101 | function approveDAI(uint256 _amount) external returns (bool) { 102 | return dai.approve(dexContractAddress, _amount); 103 | } 104 | 105 | function allowanceDAI() external view returns (uint256) { 106 | return dai.allowance(address(this), dexContractAddress); 107 | } 108 | 109 | function getBalance(address _tokenAddress) external view returns (uint256) { 110 | return IERC20(_tokenAddress).balanceOf(address(this)); 111 | } 112 | 113 | function withdraw(address _tokenAddress) external onlyOwner { 114 | IERC20 token = IERC20(_tokenAddress); 115 | token.transfer(msg.sender, token.balanceOf(address(this))); 116 | } 117 | 118 | modifier onlyOwner() { 119 | require( 120 | msg.sender == owner, 121 | "Only the contract owner can call this function" 122 | ); 123 | _; 124 | } 125 | 126 | receive() external payable {} 127 | } 128 | --------------------------------------------------------------------------------