通过solidity向Aave提供ETH

Posted

技术标签:

【中文标题】通过solidity向Aave提供ETH【英文标题】:Supply ETH to Aave through solidity 【发布时间】:2021-10-03 18:04:50 【问题描述】:

我正在尝试存入 Aave V2 合约 Aave's Code Examples

// SPDX-License-Identifier: MIT
pragma solidity >= 0.4.22 < 0.8.7;

import  IERC20, ILendingPool, IProtocolDataProvider, IStableDebtToken  from './Interfaces.sol';
import  SafeERC20  from './Libraries.sol';

/**
* This is a proof of concept starter contract, showing how uncollaterised loans are possible
* using Aave v2 credit delegation.
* This example supports stable interest rate borrows.
* It is not production ready (!). User permissions and user accounting of loans should be implemented.
* See @dev comments
*/

contract MyV2CreditDelegation 
    using SafeERC20 for IERC20;
    
    ILendingPool constant lendingPool = ILendingPool(address(0x9FE532197ad76c5a68961439604C037EB79681F0)); // Kovan
    IProtocolDataProvider constant dataProvider = IProtocolDataProvider(address(0x744C1aaA95232EeF8A9994C4E0b3a89659D9AB79)); // Kovan
    
    address owner;

    constructor () public 
        owner = msg.sender;
    

    /**
    * Deposits collateral into the Aave, to enable credit delegation
    * This would be called by the delegator.
    * @param asset The asset to be deposited as collateral
    * @param amount The amount to be deposited as collateral
    * @param isPull Whether to pull the funds from the caller, or use funds sent to this contract
    *  User must have approved this contract to pull funds if `isPull` = true
    * 
    */
    function depositCollateral(address asset, uint256 amount, bool isPull) public 
        if (isPull) 
            IERC20(asset).safeTransferFrom(msg.sender, address(this), amount);
        
        IERC20(asset).safeApprove(address(lendingPool), amount);
        lendingPool.deposit(asset, amount, address(this), 0);
    

    /**
    * Approves the borrower to take an uncollaterised loan
    * @param borrower The borrower of the funds (i.e. delgatee)
    * @param amount The amount the borrower is allowed to borrow (i.e. their line of credit)
    * @param asset The asset they are allowed to borrow
    * 
    * Add permissions to this call, e.g. only the owner should be able to approve borrowers!
    */
    function approveBorrower(address borrower, uint256 amount, address asset) public 
        (, address stableDebtTokenAddress,) = dataProvider.getReserveTokensAddresses(asset);
        IStableDebtToken(stableDebtTokenAddress).approveDelegation(borrower, amount);
    
    
    /**
    * Repay an uncollaterised loan
    * @param amount The amount to repay
    * @param asset The asset to be repaid
    * 
    * User calling this function must have approved this contract with an allowance to transfer the tokens
    * 
    * You should keep internal accounting of borrowers, if your contract will have multiple borrowers
    */
    function repayBorrower(uint256 amount, address asset) public 
        IERC20(asset).safeTransferFrom(msg.sender, address(this), amount);
        IERC20(asset).safeApprove(address(lendingPool), amount);
        lendingPool.repay(asset, amount, 1, address(this));
    
    
    /**
    * Withdraw all of a collateral as the underlying asset, if no outstanding loans delegated
    * @param asset The underlying asset to withdraw
    * 
    * Add permissions to this call, e.g. only the owner should be able to withdraw the collateral!
    */
    function withdrawCollateral(address asset) public 
        (address aTokenAddress,,) = dataProvider.getReserveTokensAddresses(asset);
        uint256 assetBalance = IERC20(aTokenAddress).balanceOf(address(this));
        lendingPool.withdraw(asset, assetBalance, owner);
    

我有这样的代码:

App = 
  web3Provider: null,
  contracts: ,

  init: async function() 
    return await App.initWeb3();
  ,

  initWeb3: async function() 
    // Modern dapp browsers...
    if (window.ethereum) 
      App.web3Provider = window.ethereum;
      try 
        // Request account access
        await window.ethereum.enable();
       catch (error) 
        // User denied account access...
        console.error("User denied account access")
      
    
    // Legacy dapp browsers...
    else if (window.web3) 
      App.web3Provider = window.web3.currentProvider;
    
    // If no injected web3 instance is detected, fall back to Ganache
    else 
      App.web3Provider = new Web3.providers.HttpProvider('http://localhost:8545');
    
    web3 = new Web3(App.web3Provider);

    return App.initContract();
  ,

  initContract: function() 
    $.getJSON('MyV2CreditDelegation.json', function(data) 
      // Get the necessary contract artifact file and instantiate it with @truffle/contract
      var safeYieldArtifact = data;
      App.contracts.MyV2CreditDelegation = TruffleContract(safeYieldArtifact);
    
      // Set the provider for our contract
      App.contracts.MyV2CreditDelegation.setProvider(App.web3Provider);
    );
    

    

    return App.bindEvents();
  ,

  bindEvents: function() 
    $(document).on('click', '.btn-deposit', App.handleDeposit);
    $(document).on('click', '.btn-withdrawl', App.handleWithdrawl);
  ,

  handleDeposit: function(event) 
    event.preventDefault();
    web3.eth.getAccounts(function(error, accounts) 
      if (error) 
        console.log(error);
      
    
      var account = accounts[0];

      App.contracts.MyV2CreditDelegation.deployed().then(function(instance) 
        creditDelegatorInstance = instance;
        const mockETHAddress = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
        // Execute adopt as a transaction by sending account
        return creditDelegatorInstance.depositCollateral(mockETHAddress, 1, true);
      ).then(function(result) 
        //return App.markAdopted();
      ).catch(function(err) 
        console.log(err.message);
      );
    );
  ,

  handleWithdrawl: function(event) 
    event.preventDefault();
  ,
;

$(function() 
  $(window).load(function() 
    App.init();
  );
);

尝试提供时,Metamask 显示错误:

警告:交易错误。合约代码中抛出异常。

只需一个简单的按钮即可在 html 中调用它:

<button class="btn btn-default btn-withdrawl" 
  type="button"> Withdrawl
</button>

我正在运行甘纳许

ganache-cli --fork https://mainnet.infura.io/v3/MyProjectId

我在控制台中看到的唯一错误是:

事务:0x9961f8a187c09fd7c9ebf803771fa161c9939268bb01552a1598807bcfdc13ff 用气量:24813 区块编号:12905002 出块时间:2021 年 7 月 26 日星期一 20:38:30 GMT-0400(东部夏令时间) 运行时错误:还原

我的猜测是我没有适当地从 Web3 调用合同

如何以编程方式向 aave 提供 Eth(或任何其他令牌)?

【问题讨论】:

您确定是从正确的帐户发送的吗?毕竟,我看到你定义了account,但从不使用它。 好点,我一直在玩一堆不同的合同,试图让这个发送,所以这显然是一个错误。我会调查的 我还注意到 MyV2CreditDelegation 指的是 Kovan 上的 ILendingPoolIProtocolDataProvider,但这些地址并没有在主网上使用。由于您通过分叉主网来启动 ganache,因此这些都行不通。你的depositCollateral 肯定会失败。 【参考方案1】:

我在浏览器中使用Hardhat而不是Web3来发送事务,但我成功了:

我使用了 Kovan 测试网络。 我使用MyCrypto faucet 为我的测试地址提供了一些 ETH。 我使用 Aave faucet 给自己一些 AAVE。 我从 Aave 的代码示例中导入了合同。 我运行了以下脚本:

创建一个新的 HardHat 项目

npm init --yes
npm install --save-dev hardhat 
npm install @nomiclabs/hardhat-waffle 
npm install --save-dev "@nomiclabs/hardhat-ethers@^2.0.0" "ethers@^5.0.0" "ethereum-waffle@^3.2.0"
npx hardhat 
(follow the prompt)
import '@nomiclabs/hardhat-ethers';
import * as dotenv from 'dotenv';
import  LogDescription  from 'ethers/lib/utils';
import hre from 'hardhat';
import  IERC20__factory, MyV2CreditDelegation__factory  from '../typechain';

dotenv.config();

// Infura, Alchemy, ... however you can get access to the Kovan test network
// E.g. https://kovan.infura.io/v3/<project-id>
const KOVAN_JSON_RPC = process.env.KOVAN_JSON_RPC || '';
if (!KOVAN_JSON_RPC) 
    console.error('Forgot to set KOVAN_JSON_RPC in aave.ts or .env');
    process.exit(1);


// Test account that has Kovan ETH and an AAVE token balance
const AAVE_HOLDER = '';

async function main() 
    // Fork Kovan
    await hre.network.provider.request(
        method: 'hardhat_reset',
        params: [ forking:  jsonRpcUrl: KOVAN_JSON_RPC  ],
    );

    // Act like AAVE_HOLDER
    await hre.network.provider.request(
        method: 'hardhat_impersonateAccount',
        params: [AAVE_HOLDER],
    );
    const signer = await hre.ethers.getSigner(AAVE_HOLDER);
    console.log('signer:', signer.address);

    // AAVE token on Kovan network
    const token = IERC20__factory.connect('0xb597cd8d3217ea6477232f9217fa70837ff667af', signer);
    console.log('token balance:', (await token.balanceOf(signer.address)).toString());

    const MyV2CreditDelegation = new MyV2CreditDelegation__factory(signer);
    const delegation = await MyV2CreditDelegation.deploy( gasLimit: 1e7 );
    console.log('delegation:', delegation.address);

    await token.approve(delegation.address, 1000000000000);
    console.log('allowance:', (await token.allowance(signer.address, delegation.address,  gasLimit: 1e6 )).toString());

    const depositTrans = await delegation.depositCollateral(token.address, 1000000000000, true,  gasLimit: 1e6 );
    console.log('depositTrans:', depositTrans.hash);
    const receipt = await depositTrans.wait();
    for (const log of receipt.logs) 
        const [name, desc] = parseLog(log) || [];
        if (desc) 
            const args = desc.eventFragment.inputs.map(( name, type, indexed , index) =>
                `\n    $type$indexed ? ' indexed' : '' $name: $desc.args[name]`);
            args.unshift(`\n    contract $name $log.address`);
            console.log('Event', log.logIndex, `$desc.name($args ? args.join(',') : '')`);
         else 
            console.log('Log', log.logIndex, JSON.stringify(log.topics, null, 4), JSON.stringify(log.data));
        
    

    function parseLog(log:  address: string, topics: Array<string>, data: string ): [string, LogDescription] | undefined 
        try  return ['', delegation.interface.parseLog(log)];  catch (e)  
        try 
            const desc = token.interface.parseLog(log);
            return [log.address.toLowerCase() === token.address.toLowerCase() ? 'AAVE' : 'IERC20', desc];
         catch (e)  
    


main().then(() => process.exit(0), error => 
    console.error(JSON.stringify(error));
    console.error(error);
);

结果:

$ hardhat run --no-compile --network kovan .\scripts\Aave.ts
token balance: 999999000000000000
delegation: 0x2863E2a95Dc84C227B11CF1997e295E59ab15670
allowance: 1000000000000
depositTrans: 0x0a3d1a8bfbdfc0f403371f9936122d19bdc9f3539c34e3fb1b0a7896a398f923
Done in 57.11s.

您可以在 Etherscan for Kovan 上进行验证(块 26666177、26666180 和 26666183):

部署MyV2CreditDelegation(transaction,contract) 批准 AAVE 合同 (transaction) 记录的Approval 事件和token.allowance 返回了正确的值 存入抵押品 (transaction) 将0.000001AAVE 从我的地址转移到部署的合约 将0.000001aAAVE 从我的地址转移到部署的合约 将 0.000001 AAVE 从已部署的合约转移到 aAAVE 合约 Transfer/Approval/Mint/DelegatedPowerChanged/...的大量记录事件

最初,我的脚本会首先部署一个测试代币(并在上面铸造一些余额),我会尝试将其作为抵押品存入,但提供者以某种方式将其还原,甚至没有交易出现在 Kovan Etherscan 上。因此,您的代码中的问题可能是mockETHAddress,而且您似乎实际上并未批准您的委托合同以提取指定的金额。

this repository 中提供了更复杂但可立即运行的设置。它模拟了一个在 Kovan 上拥有 ETH 和 AAVE 余额的账户。

【讨论】:

这个答案还是有点欠缺。我已尝试更新您的答案,以使其更具菜鸟证明。但是,当我尝试run hardhat run --no-compile --network kovan .\scripts\Aave.ts 时,我收到一个错误`Cannot use import statement outside a module` 请更新答案以包括如何正确设置项目 老实说这个答案可能需要一些改进,但我不会浪费赏金,请更新这个答案 你能提供一个git repo吗? 工作一旁,我花了一点时间来提取脚本和依赖项,但我添加了一个demo repository,这应该只需要你做yarn; yarn build; yarn start; 来查看脚本的工作。 假设您安装了 Yarn v1.22.0+。 希望这对您有用? 谢谢,太棒了

以上是关于通过solidity向Aave提供ETH的主要内容,如果未能解决你的问题,请参考以下文章

第153篇 Solidity 中支付通道的实现

获取 Chainlink ETH/USD 价格反馈答案为 uint256 而不是 int solidity

Aave推特都想做的去中心化社交媒体会是怎样的? |链捕手

区块链 aave源代码分析之二 闪电贷flashloan

区块链Defi特性引用

如何在Objective C中遵循SOLID原则向现有方法添加另一个参数