合约代码:
WUSDMaster:https://bscscan.com/address/0xa79fe386b88fbee6e492eeb76ec48517d1ec759a#code
攻击交易:
https://bscscan.com/tx/0x31262f15a5b82999bf8d9d0f7e58dcb1656108e6031a2797b612216a95e1670e
合约WUSDMaster中函数 stake
将质押的usdt的10%用来购买wex代币,同时1:1生成wusd。
function stake(uint256 amount) external nonReentrant {
require(amount <= maxStakeAmount, 'amount too high');
usdt.safeTransferFrom(msg.sender, address(this), amount);
if(feePermille > 0) {
uint256 feeAmount = amount * feePermille / 1000;
usdt.safeTransfer(treasury, feeAmount);
amount = amount - feeAmount;
}
uint256 wexAmount = amount * wexPermille / 1000;
usdt.approve(address(wswapRouter), wexAmount);
wswapRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
wexAmount,
0,
swapPath,
address(this),
block.timestamp
);
wusd.mint(msg.sender, amount);
emit Stake(msg.sender, amount);
}
在函数redeem
中,返回质押的89.3%的usdt。以及WUSDMaster合约内百分比的wex代币.
function redeem(uint256 amount) external nonReentrant {
uint256 usdtTransferAmount = amount * (1000 - wexPermille - treasuryPermille) / 1000;
uint256 usdtTreasuryAmount = amount * treasuryPermille / 1000;
uint256 wexTransferAmount = wex.balanceOf(address(this)) * amount / wusd.totalSupply();
wusd.burn(msg.sender, amount);
usdt.safeTransfer(treasury, usdtTreasuryAmount);
usdt.safeTransfer(msg.sender, usdtTransferAmount);
wex.safeTransfer(msg.sender, wexTransferAmount);
emit Redeem(msg.sender, amount);
}
(理想情况下)如果wex价值在历史中一直上升同时有人在不断的stake
,同时没有人redeem
,攻击者通过质押后提取,用10.7%usdt购买wex,(wex的价格为历史的平均价格,)再卖出wex,攻击者就能盈利。但是质押后赎回会因为wusd.totalSupply()的增加分到wex数量变少,如果能借取wusd。先赎回再质押,就能花费相同的usdt获得更多的wex,同时因为质押会提高wex的价格.所以提前购买大量的wex,再质押提升价格后再卖出wex,就能再获得更多的usdt。
攻击者攻击流程:
- 借取wusd 赎回usdt ,
- 获得usdt 及wex
- 使用usdt购买wex
- 质押usdt 获得wusd
- 卖出wex返还wusd