Token sweeper with an owner, a second authorised caller, a halt switch and a separate flag controlling whether it accepts ether at all.
Historical Significance
The split between an owner and a single authorised caller is the interesting design choice. Routine collection runs under a hot key that can be rotated without touching ownership, while the owner key stays cold and is only needed to change configuration. The halt flag gives an operator one switch that stops collection everywhere without revoking the hot key or redeploying.
Key Facts
Description
Four storage values drive everything: an owner, an authorised caller, a halted flag and an accept-ether flag, with the two booleans packed into the same slot as the authorised caller. The payable fallback rejects payments outright unless the accept-ether flag is set.
sweep and sweepFrom move a fixed amount of a token to the caller, using transfer and transferFrom respectively, and both return false rather than reverting when the balance is short. sweepAll moves the whole balance. sendEther forwards ether and is gated on the accept-ether flag. Every sweep path requires the caller to be the owner or the authorised caller, requires a non-zero token address, and requires that the halted flag is clear. The owner alone can flip either flag, rotate the authorised caller, or transfer ownership, and both address setters refuse the zero address.
Source Verified
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Byzantium Era
First Metropolis hard fork. Added zk-SNARK precompiles, REVERT opcode, and staticcall.
Bytecode Overview
Verified Source Available
This contract has verified source code.
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
pragma solidity ^0.4.24;
contract ERC20 {
function balanceOf(address _owner) public returns (uint256);
function transfer(address _to, uint256 _value) public;
function transferFrom(address _from, address _to, uint256 _value) public;
}
contract Sweeper {
address public owner;
address public authorizedCaller;
bool public halted;
bool public isPayable;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
modifier onlyAuthorized() {
require(msg.sender == owner || msg.sender == authorizedCaller);
_;
}
function () public payable {
if (isPayable == false) {
revert();
}
}
function sweep(address _token, uint256 _amount) public onlyAuthorized returns (bool) {
bool ok = false;
require(_token != address(0) && halted == false);
ERC20 token = ERC20(_token);
if (token.balanceOf(this) < _amount) {
return false;
}
token.transfer(msg.sender, _amount);
return true;
}
function sweepFrom(address _token, uint256 _amount) public onlyAuthorized returns (bool) {
bool ok = false;
require(_token != address(0) && halted == false);
ERC20 token = ERC20(_token);
if (token.balanceOf(this) < _amount) {
return false;
}
token.transferFrom(this, msg.sender, _amount);
return true;
}
function sendEther(address _to, uint256 _amount) public payable onlyAuthorized returns (bool) {
if (isPayable == false) {
revert();
}
return _to.send(_amount);
}
function sweepAll(address _token) public onlyAuthorized returns (bool) {
bool ok = false;
require(_token != address(0) && halted == false);
ERC20 token = ERC20(_token);
token.transfer(msg.sender, token.balanceOf(this));
return true;
}
function setAcceptEth(bool _value) public onlyOwner {
isPayable = _value;
}
function setHalted(bool _value) public onlyOwner {
halted = _value;
}
function transferAuthorizedCaller(address _newCaller) public onlyOwner {
require(_newCaller != address(0));
authorizedCaller = _newCaller;
}
function transferOwnership(address _newOwner) public onlyOwner {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}External Links
Related contracts
Msg
Same eraMinimal contract that stores a single public string in state, exposed via the auto-generated m() getter. First of 281 identical siblings. Source verified by EthereumHistory.
0x2c8f58...37b173January 13, 2018Wallet
Same eraToken collection wallet that moves an entire token balance to a chosen address, without the ERC223 callback handler.
0x002204...531195January 19, 2018Wallet
Same eraOwner wallet that forwards ether to its owner, logs any call from a stranger with the full calldata, and lets the owner execute arbitrary calls.
0x001feb...9e7a4fJanuary 20, 2018Sweeper
Same eraMinimal ETH sweeper, first of 1,900 identical deployments in a 2-day burst in January 2018. All sweep to a single hardcoded destination. Source verified by EthereumHistory.
0xeb15f6...6cb3e1January 23, 2018Sweep
Same eraETH sweep-to-fixed-recipient — fallback forwards the contract's entire balance to `0xd293a88c…8d4` via `.send()` and reverts on failure. Massive cluster of 1899 identical deployments — likely deposit-address contracts for a single custodian.
0x00188b...b260a7January 23, 2018Forwarder
Same eraDeposit forwarder in the BitGo style, sending ether to a parent address and able to flush stranded tokens to the same place.
0x00d083...4d5405February 2, 2018