address(reciver).transfer(amount);
token.transfer(reciver, amount);
token.transferFrom(sender, reciver, amount);
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract StokenERC20 is IERC20 {
mapping(address => uint256) public override balanceOf;
mapping(address => mapping(address => uint256)) public override allowance;
uint256 public immutable override totalSupply;
string public constant name = "STOKEN";
string public constant symbol = "SETH";
uint8 public constant decimals = 18;
constructor(uint256 _totalSupply) {
_totalSupply *= 10**18;
totalSupply = _totalSupply;
balanceOf[msg.sender] = _totalSupply;
emit Transfer(address(0), msg.sender, _totalSupply);
}
function transfer(address _to, uint256 _value) public override returns (bool) {
unchecked {
if (balanceOf[msg.sender] >= _value && balanceOf[_to] + _value >= balanceOf[_to]) {
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
} else {
return false;
}
}
}
function transferFrom(
address _from,
address _to,
uint256 _value
) public override returns (bool) {
unchecked {
if (
balanceOf[_from] >= _value &&
allowance[_from][msg.sender] >= _value &&
balanceOf[_to] + _value >= balanceOf[_to]
) {
balanceOf[_to] += _value;
balanceOf[_from] -= _value;
emit Transfer(_from, _to, _value);
allowance[_from][msg.sender] -= _value;
emit Approval(_from, msg.sender, allowance[_from][msg.sender]);
return true;
} else {
return false;
}
}
}
function approve(address _spender, uint256 _value) public override returns (bool) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
}
/*
Contract takes ERC20 Stokens as input
and returns the native ETH (1:1 ratio).
*/
contract Exchange {
IERC20 public token;
address public owner;
mapping(address => uint256) private balances;
event Transfer(address indexed from, address indexed to, uint256 amount);
event NativeTransfer(address indexed to, uint256 amount);
constructor(address _token) payable {
require(msg.value >= 10, "10 ETH required");
owner = msg.sender;
token = IERC20(_token);
}
modifier onlyOwner() {
require(msg.sender == owner, "not owner");
_;
}
function changeOwner(address _newOwner) public onlyOwner {
owner = _newOwner;
}
function changeToken(address _newToken) public onlyOwner {
token = IERC20(_newToken);
}
function balanceOf(address user) public view returns (uint256) {
return balances[user];
}
function enter(uint256 amount) public {
require(amount >= 10 ether, "minimum is 10");
token.transferFrom(msg.sender, address(this), amount);
balances[msg.sender] += amount;
emit Transfer(msg.sender, address(this), amount);
}
function exit(uint256 amount) public {
uint256 getAmount = balances[msg.sender];
require(getAmount >= amount, "user doesn't have enough funds deposited");
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
emit NativeTransfer(msg.sender, amount);
}
}
function transferFrom(
address _from,
address _to,
uint256 _value
) public override returns (bool) {
unchecked {
if (
balanceOf[_from] >= _value &&
allowance[_from][msg.sender] >= _value &&
balanceOf[_to] + _value >= balanceOf[_to]
) {
balanceOf[_to] += _value;
balanceOf[_from] -= _value;
emit Transfer(_from, _to, _value);
allowance[_from][msg.sender] -= _value;
emit Approval(_from, msg.sender, allowance[_from][msg.sender]);
return true;
} else {
return false;
}
}
}
function enter(uint256 amount) public {
require(amount >= 10 ether, "minimum is 10");
token.transferFrom(msg.sender, address(this), amount);
balances[msg.sender] += amount;
emit Transfer(msg.sender, address(this), amount);
}
(bool success, bytes memory returnData) = targetContract.call(abi.encodeWithSignature("myFunction(uint256)", 123));
if (success) {
// 调用成功,处理返回值
} else {
// 调用失败,处理错误
}
require(success, "failed!");
原文始发于微信公众号(山石网科安全技术研究院):CTF专栏 | 以太坊应用中基于回退与返回错误的假充值攻击原理分析