Deposit wallet with a halt switch that forwards ether when active and, when called with no value, reads its own calldata to route a sweep through the controller.
Historical Significance
Reading arguments out of msg.data by index, rather than declaring them, let one fallback stand in for a family of sweep functions whose signatures were not fixed when the wallets were deployed. The halt switch sits on the controller rather than on each wallet, so an operator could freeze collection across every deposit address at once while still accepting customer payments.
Token Information
Key Facts
Description
A later revision of the exchange deposit wallet. On a payment it checks halted() on its sweeper list, and while the system is running it reads destination(), forwards the ether and calls logSweep. When halted it accepts the payment and does nothing further, so deposits are never rejected outright.
A call with no value takes the other branch, which is gated on the caller being either sweeper() or owner() of the sweeper list. It then pulls arguments straight out of its own calldata through a helper that returns the nth ABI word, requires that the second argument matches its configured sweeper list, looks up sweeperOf the first argument and delegatecalls that sweeper. changeController and transferOwnership are owner gated and both refuse the zero address.
Source Verified
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 AbstractSweeperList {
function sweeperOf(address _token) public returns (address);
function halted() public returns (bool);
function destination() public returns (address);
function sweeper() public returns (address);
function owner() public returns (address);
function logSweep(address from, address to, address token, uint amount) public;
}
contract UserWallet {
address public owner;
AbstractSweeperList public sweeperList;
function _arg(bytes _data, uint _n) internal pure returns (address a) {
assembly {
a := mload(add(add(_data, mul(_n, 0x20)), 4))
}
}
function () public payable {
if (msg.value > 0) {
if (!sweeperList.halted()) {
address dest = sweeperList.destination();
dest.transfer(msg.value);
sweeperList.logSweep(this, dest, 0, msg.value);
return;
}
return;
} else if (msg.sender == sweeperList.sweeper() || msg.sender == sweeperList.owner()) {
address a = _arg(msg.data, 2);
require(address(sweeperList) == a);
address b = _arg(msg.data, 1);
sweeperList.sweeperOf(b).delegatecall(msg.data);
}
}
function changeController(address _controller) public {
require(msg.sender == owner);
sweeperList = AbstractSweeperList(_controller);
}
function tokenFallback(address _from, uint _value, bytes _data) public {
}
function transferOwnership(address _owner) public {
require(msg.sender == owner);
require(_owner != address(0));
owner = _owner;
}
}