A minimal proxy wallet deployed by exchange and custodian factories for hot wallet deposit address infrastructure.
Historical Significance
The most-deployed smart contract bytecode in Ethereum history. Over 1.5 million instances represent the backbone of exchange deposit address infrastructure during the early growth of Ethereum.
Key Facts
Description
UserWallet is a lightweight proxy contract deployed by factory contracts for exchange and custodian hot wallet systems. Each instance delegates calls to a shared implementation, making it the single most-deployed bytecode in Ethereum history with over 1.5 million instances. Factory-deployed at scale from 2017 onward, these contracts served as deposit addresses for crypto exchanges managing per-user inbound ETH. The pattern separates deposit address logic from the implementation contract, allowing upgrades without redeploying individual wallets.
Source Verified
Spurious Dragon Era
Continued DoS protection. State trie clearing.
Bytecode Overview
Verified Source Available
Source verified on Etherscan.
Show source code (Solidity)
{
"language": "Solidity",
"sources": {
"UserWallet.sol": {
"content": "pragma solidity ^0.4.10;\r\n\r\n// Copyright 2017 Bittrex\r\n\r\ncontract AbstractSweeper {\r\n function sweep(address token, uint amount) returns (bool);\r\n\r\n function () { throw; }\r\n\r\n Controller controller;\r\n\r\n function AbstractSweeper(address _controller) {\r\n controller = Controller(_controller);\r\n }\r\n\r\n modifier canSweep() {\r\n if (msg.sender != controller.authorizedCaller() && msg.sender != controller.owner()) throw;\r\n if (controller.halted()) throw;\r\n _;\r\n }\r\n}\r\n\r\ncontract Token {\r\n function balanceOf(address a) returns (uint) {\r\n (a);\r\n return 0;\r\n }\r\n\r\n function transfer(address a, uint val) returns (bool) {\r\n (a);\r\n (val);\r\n return false;\r\n }\r\n}\r\n\r\ncontract DefaultSweeper is AbstractSweeper {\r\n function DefaultSweeper(address controller)\r\n AbstractSweeper(controller) {}\r\n\r\n function sweep(address _token, uint _amount)\r\n canSweep\r\n returns (bool) {\r\n bool success = false;\r\n address destination = controller.destination();\r\n\r\n if (_token != address(0)) {\r\n Token token = Token(_token);\r\n uint amount = _amount;\r\n if (amount > token.balanceOf(this)) {\r\n return false;\r\n }\r\n\r\n success = token.transfer(destination, amount);\r\n }\r\n else {\r\n uint amountInWei = _amount;\r\n if (amountInWei > this.balance) {\r\n return false;\r\n }\r\n\r\n success = destination.send(amountInWei);\r\n }\r\n\r\n if (success) {\r\n controller.logSweep(this, destination, _token, _amount);\r\n }\r\n return success;\r\n }\r\n}\r\n\r\ncontract UserWallet {\r\n AbstractSweeperList sweeperList;\r\n function UserWallet(address _sweeperlist) {\r\n sweeperList = AbstractSweeperList(_sweeperlist);\r\n }\r\n\r\n function () public payable { }\r\n\r\n function tokenFallback(address _from, uint _value, bytes _data) {\r\n (_from);\r\n (_value);\r\n (_data);\r\n }\r\n\r\n function sweep(address _token, uint _amount)\r\n returns (bool) {\r\n (_amount);\r\n return sweeperList.sweeperOf(_token).delegatecall(msg.data);\r\n }\r\n}\r\n\r\ncontract AbstractSweeperList {\r\n function sweeperOf(address _token) returns (address);\r\n}\r\n\r\ncontract Controller is AbstractSweeperList {\r\n address public owner;\r\n address public authorizedCaller;\r\n\r\n address public destination;\r\n\r\n bool public halted;\r\n\r\n event LogNewWallet(address receiver);\r\n event LogSweep(address indexed from, address indexed to, address indexed token, uint amount);\r\n \r\n modifier onlyOwner() {\r\n if (msg.sender != owner) throw; \r\n _;\r\n }\r\n\r\n modifier onlyAuthorizedCaller() {\r\n if (msg.sender != authorizedCaller) throw; \r\n _;\r\n }\r\n\r\n modifier onlyAdmins() {\r\n if (msg.sender != authorizedCaller && msg.sender != owner) throw; \r\n _;\r\n }\r\n\r\n function Controller() \r\n {\r\n owner = msg.sender;\r\n destination = msg.sender;\r\n authorizedCaller = msg.sender;\r\n }\r\n\r\n function changeAuthorizedCaller(address _newCaller) onlyOwner {\r\n authorizedCaller = _newCaller;\r\n }\r\n\r\n function changeDestination(address _dest) onlyOwner {\r\n destination = _dest;\r\n }\r\n\r\n function changeOwner(address _owner) onlyOwner {\r\n owner = _owner;\r\n }\r\n\r\n function makeWallet() onlyAdmins returns (address wallet) {\r\n wallet = address(new UserWallet(this));\r\n LogNewWallet(wallet);\r\n }\r\n\r\n function halt() onlyAdmins {\r\n halted = true;\r\n }\r\n\r\n function start() onlyOwner {\r\n halted = false;\r\n }\r\n\r\n address public defaultSweeper = address(new DefaultSweeper(this));\r\n mapping (address => address) sweepers;\r\n\r\n function addSweeper(address _token, address _sweeper) onlyOwner {\r\n sweepers[_token] = _sweeper;\r\n }\r\n\r\n function sweeperOf(address _token) returns (address) {\r\n address sweeper = sweepers[_token];\r\n if (sweeper == 0) sweeper = defaultSweeper;\r\n return sweeper;\r\n }\r\n\r\n function logSweep(address from, address to, address token, uint amount) {\r\n LogSweep(from, to, token, amount);\r\n }\r\n}"
}
},
"settings": {
"compilationTarget": {
"UserWallet.sol": "UserWallet"
},
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
}