DexTwo 컨트랙트가 가지고 있는 token1과 token2의 잔고를 모두 탈취(drain) 해라
나는 token1과 token2를 각각 10개씩 소유하고 있으며,
DEX 컨트랙트는 각각 100개씩 가진 상태로 시작한다.
// 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, uint256 amount) public onlyOwner {
IERC20(token_address).transferFrom(msg.sender, address(this), amount);
}
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);
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, uint256 amount) public view returns (uint256) {
return ((amount * IERC20(to).balanceOf(address(this))) / IERC20(from).balanceOf(address(this)));
}
function approve(address spender, uint256 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 (uint256) {
return IERC20(token).balanceOf(account);
}
}
contract SwappableTokenTwo is ERC20 {
address private _dex;
constructor(address dexInstance, string memory name, string memory symbol, uint256 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);
}
}
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);
IERC20(from).transferFrom(msg.sender, address(this), amount);
IERC20(to).approve(address(this), swapAmount);
IERC20(to).transferFrom(address(this), msg.sender, swapAmount);
}
require((from == token1 && to == token2) || (from == token2 && to == token1), "Invalid tokens");
Dex 문제와 다르게 DexTwo 문제에서는 swap() 함수는 위 require 코드가 빠져있다.
따라서 DexTwo 문제에서는 token1, token2 를 따로 체크하는 코드가 없기 때문에 임의의 Token을 만들어 swap() 함수를 동작시켜도 정상적으로 동작한다.
이를 이용해 새로운 ERC20 Token을 만들어 swap() 함수를 동작시키면 된다.
나의 AttackToken 100개를 DEX에게 주고, DEX의 token1 100개를 나에게 전송한다. (AttackToken은 내가 만든 커스텀 토큰이고, 공급량은 충분함, 처음은 1000개라고 가정)