Ethernaut 题库闯关 #22 — Dex 2

Ethernaut题库闯关连载的第22篇

今天这篇是Ethernaut 题库闯关连载的第22篇,难度等级: 一般。

欢迎大家订阅专栏:Ethernaut 题库闯关,坚持挑战下去,你的 Solidity代码能力肯定大有提高。

挑战# 22:Dex 2

本关将要求你以不同的方式打破DexTwo,这是上一关经过微妙修改的Dex合约。

这一关要求我们从 DexTwo合约中抽空Dex 中所有的token1和token2。

在开始时,我们持有10个 token1和10个 token2的代币,而DEX合约初始流动性为每个代币100个。

本关合约源码如下:

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import '@openzeppelin/contracts/math/SafeMath.sol';
import '@openzeppelin/contracts/access/Ownable.sol';

contract DexTwo is Ownable {
  using SafeMath for uint;
  address public token1;
  address public token2;
  constructor() public {}

  function setTokens(address _token1, address _token2) public onlyOwner {
    token1 = _token1;
    token2 = _token2;
  }

  function add_liquidity(address token_address, uint amount) public onlyOwner {
    IERC20(token_address).transferFrom(msg.sender, address(this), amount);
  }

  function swap(address from, address to, uint amount) public {
    require(IERC20(from).balanceOf(msg.sender) >= amount, "Not enough to swap");
    uint swapAmount = getSwapAmount(from, to, amount);
    IERC20(from).transferFrom(msg.sender, address(this), amount);
    IERC20(to).approve(address(this), swapAmount);
    IERC20(to).transferFrom(address(this), msg.sender, swapAmount);
  } 

  function getSwapAmount(address from, address to, uint amount) public view returns(uint){
    return((amount * IERC20(to).balanceOf(address(this)))/IERC20(from).balanceOf(address(this)));
  }

  function approve(address spender, uint amount) public {
    SwappableTokenTwo(token1).approve(msg.sender, spender, amount);
    SwappableTokenTwo(token2).approve(msg.sender, spender, amount);
  }

  function balanceOf(address token, address account) public view returns (uint){
    return IERC20(token).balanceOf(account);
  }
}

contract SwappableTokenTwo is ERC20 {
  address private _dex;
  constructor(address dexInstance, string memory name, string memory symbol, uint initialSupply) public ERC20(name, symbol) {
        _mint(msg.sender, initialSupply);
        _dex = dexInstance;
  }

  function approve(address owner, address spender, uint256 amount) public returns(bool){
    require(owner != _dex, "InvalidApprover");
    super._approve(owner, spender, amount);
  }
}

想想自己如何闯关?

要完成这一关,我们需要了解 swap方法是如何被修改的?以及如何攻击中使用一个自定义的代币合约。

研究合约

DexTwo合约与之前Dex挑战中的合约基本相同,唯一改变的是一些函数名称和swap函数的内容。

除了像Dex一样的DexTwo合约,我们还有SwappableTokenTwo,一个ERC20代币的实现。

让我们看看swap函数的内容:


function swap(
    address from,
    address to,
    uint256 amount
) public {
    require(IERC20(from).balanceOf(msg.sender) >= amount, "Not enough to swap");
    uint256 swapAmount = getSwapAmount(from, to, amount);...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Ethernaut CTF
Ethernaut CTF
信奉 CODE IS LAW.