amount
参数一致。token
是具有通缩机制或转账时收取手续费的代币,实际存入的代币数量可能会少于 amount
,导致 balances[msg.sender]
记录的数量与实际存入的数量不一致。代码:DeFiVulnLabs/src/test/fee-on-transfer.sol
contract STA is ERC20Detailed {
using SafeMath for uint256;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowed;
string constant tokenName = "Statera";
string constant tokenSymbol = "STA";
uint8 constant tokenDecimals = 18;
uint256 _totalSupply = 100000000000000000000000000;
uint256 public basePercent = 100;
constructor()
public
payable
ERC20Detailed(tokenName, tokenSymbol, tokenDecimals)
{
_issue(msg.sender, _totalSupply);
}
function transfer(address to, uint256 value) public returns (bool) {
require(value <= _balances[msg.sender]);
require(to != address(0));
uint256 tokensToBurn = cut(value);
uint256 tokensToTransfer = value.sub(tokensToBurn);
_balances[msg.sender] = _balances[msg.sender].sub(value);
_balances[to] = _balances[to].add(tokensToTransfer);
_totalSupply = _totalSupply.sub(tokensToBurn);
emit Transfer(msg.sender, to, tokensToTransfer);
emit Transfer(msg.sender, address(0), tokensToBurn);
return true;
}
function cut(uint256 value) public view returns (uint256) {
uint256 roundValue = value.ceil(basePercent);
uint256 cutValue = roundValue.mul(basePercent).div(10000);
return cutValue;
}
}
uint256 cutValue = roundValue.mul(basePercent).div(10000);
emit Transfer(msg.sender, address(0), tokensToBurn);
deposit
函数存入代币,并通过 withdraw
函数提取代币。contract VulnVault {
mapping(address => uint256) private balances;
IERC20 private token;
constructor(address _tokenAddress) {
token = IERC20(_tokenAddress);
}
//存入代币
function deposit(uint256 amount) external {
require(amount > 0, "Deposit amount must be greater than zero");
token.transferFrom(msg.sender, address(this), amount);
balances[msg.sender] += amount;
emit Deposit(msg.sender, amount);
}
//提取代币
function withdraw(uint256 amount) external {
require(amount > 0, "Withdrawal amount must be greater than zero");
require(amount <= balances[msg.sender], "Insufficient balance");
balances[msg.sender] -= amount;
token.transfer(msg.sender, amount);
emit Withdrawal(msg.sender, amount);
}
function getBalance(address account) external view returns (uint256) {
return balances[account];
}
}
function deposit(uint256 amount) external {
require(amount > 0, "Deposit amount must be greater than zero");
token.transferFrom(msg.sender, address(this), amount);
balances[msg.sender] += amount;
emit Deposit(msg.sender, amount);
}
而可以看到现在使用的是现在的用户余额的增加是依赖于
uint256 actualDepositAmount = balanceAfter - balanceBefore了。
function deposit(uint256 amount) external {
require(amount > 0, "Deposit amount must be greater than zero");
//将amount
uint256 balanceBefore = token.balanceOf(address(this));
token.transferFrom(msg.sender, address(this), amount);
uint256 balanceAfter = token.balanceOf(address(this));
uint256 actualDepositAmount = balanceAfter - balanceBefore;
balances[msg.sender] += actualDepositAmount;
emit Deposit(msg.sender, actualDepositAmount);
}
也即效果应该如下,用户存入10000个代币进行质押,100的代币作为手续费burn掉,实际上存入的值应该是9900,而不是10000个
原文始发于微信公众号(Ice ThirdSpace):DeFiVulnLabs靶场全系列详解(二十七)转账收费代币不兼容——fee-on-transfer
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论