ERC20FlashMint——实现漏洞案例1

  • SmileBits
  • 更新于 2024-04-21 11:44
  • 阅读 1004

参考:openzepplin的ERC20FlashMintERC3156是整个FlashLoan的标准,FlashMint只是其中一个特例。FlashLoan主要的可能漏洞是:1、通过在flashloan借贷内部质押(deposit)之类的,来替代repay,达到攻击目的2、通过

参考:openzepplin 的ERC20FlashMint

ERC3156 是整个FlashLoan的标准,FlashMint只是其中一个特例。 FlashLoan主要的可能漏洞是:

默认fee是为0 ,feeReceiver是address(0)

**我们来看看最近审计一个项目的代码----大家仔细看看代码,能看出问题在哪吗?

/// @notice Performs a flash mint (called flash loan to confirm with ERC3156 standard).

///

/// @param receiver The address which will receive the flash minted tokens.

/// @param token The address of the token to flash mint.

/// @param amount How much to flash mint.

/// @param data ABI encoded data to pass to the receiver.

///

/// @return If the flash loan was successful.

function flashLoan(

IERC3156FlashBorrower receiver,

address token,

uint256 amount,

bytes calldata data

) external override nonReentrant returns (bool) {

if (token != address(this)) {

revert IllegalArgument();

}

if (amount > maxFlashLoan(token)) {

revert IllegalArgument();

}

uint256 fee = flashFee(token, amount);
_mint(address(receiver), amount);

if (receiver.onFlashLoan(msg.sender, token, amount, fee, data) != CALLBACK_SUCCESS) {
revert IllegalState();
}

_burn(address(receiver), amount + fee); // Will throw error if not enough to burn

return true;

}

我们可以对比openzepplin的实现

function flashLoan(

IERC3156FlashBorrower receiver,

address token,

uint256 amount,

bytes calldata data

) public virtual override returns (bool) {

require(amount <= maxFlashLoan(token), "ERC20FlashMint: amount exceeds maxFlashLoan");

uint256 fee = flashFee(token, amount);

_mint(address(receiver), amount);

require(

receiver.onFlashLoan(msg.sender, token, amount, fee, data) == _RETURN_VALUE,

"ERC20FlashMint: invalid return value"

);

address flashFeeReceiver = _flashFeeReceiver();

_spendAllowance(address(receiver), address(this), amount + fee);

if (fee == 0 || flashFeeReceiver == address(0)) {

_burn(address(receiver), amount + fee);

} else {

_burn(address(receiver), amount);

_transfer(address(receiver), flashFeeReceiver, fee);

}

return true;

}

发现问题代码的实现少了关键的一行: _spendAllowance(address(receiver), address(this), amount + fee); 缺少这一行会导致什么问题呢 如果一个合约是IERC3156FlashBorrower receiver,而且合约上面有资金,那么任意的地址都可以通过flashMint来消耗上面的资金即消耗fee——损人不利己的事情。 有这一行代码,保证了其他的任意调用不会成功。你在真正需要flashmint的时候,在回调里面会添加approve()授权函数来保证,销毁成功。 注意点: 1、FlashLoan在借贷的回调里面是,将token转会Loaner合约,而在FlashMint的回调里面是,将token授权给Token合约,让它可以销毁 2、token授权给Token合约这个事情有点点感觉没那么自然,但是是必须的。需要注意。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

3 条评论

请先 登录 后评论
SmileBits
SmileBits
智能合约安全审计