Late 2018 deposit address that does not know where it is sending: on every payment it asks a shared registry for the current target, forwards the whole amount there, and logs it.
Historical Significance
Exchange deposit addresses are one of the most numerous kinds of contract ever deployed, and almost all of them answer the same question differently: where does the money go, and who can change that. The common answer in this era was to hard code a destination or store one per contract. This one refuses to hold the answer at all.
What that buys is a single point of redirection for a whole fleet, which is convenient and also the entire risk. Whoever controls the registry controls the destination of every deposit made through every one of these addresses, retroactively, with one transaction and no trace in the deposit contracts themselves. The contracts are honest about it: their own storage names nothing but the registry.
Key Facts
Description
The fallback is the contract. Ether arrives, the contract calls getTargetAddress on a registry whose address was fixed at construction, sends the full amount on with transfer, and emits EthForwarded with the sender, the destination and the value. Nothing is kept, and nothing about the destination is stored here.
That indirection is the design. A deposit address that stores its own destination has to be redeployed or individually updated to point somewhere else. These ask at the moment of payment, so the operator changes one value in one registry and every address in the fleet follows on its next payment. The registry itself is a small owned contract with exactly two functions, getTargetAddress and setTargetAddress.
The rest is a manual override. The contract inherits the standard Ownable of the period, including renounceOwnership and the OwnershipRenounced event, and the owner can call transferETH to push ether to a chosen address or transferTokens to move an ERC20 balance, since tokens sent to a deposit address trigger no fallback and would otherwise sit here. Both return true and transferTokens requires the token's own transfer to report success, which is the 2018 habit of trusting the return value rather than checking the balance.
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 Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
contract ERC20Basic {
function transfer(address to, uint256 value) public returns (bool);
}
contract TargetRegistry {
function getTargetAddress() public view returns (address);
}
contract TargetedForwarder is Ownable {
TargetRegistry internal registry;
event EthForwarded(address indexed from, address indexed to, uint256 value);
constructor(address _registry) public {
registry = TargetRegistry(_registry);
}
function () public payable {
address target = registry.getTargetAddress();
target.transfer(msg.value);
emit EthForwarded(msg.sender, target, msg.value);
}
function transferETH(address _to, uint256 _amount) public onlyOwner returns (bool) {
_to.transfer(_amount);
return true;
}
function transferTokens(address _token, address _to, uint256 _amount) public onlyOwner returns (bool) {
ERC20Basic token = ERC20Basic(_token);
require(token.transfer(_to, _amount));
return true;
}
}External Links
Related contracts
TargetedForwarder
Same deployerLate 2018 deposit address that does not know where it is sending: on every payment it asks a shared registry for the current target, forwards the whole amount there, and logs it.
0xbc634c...c14c75September 20, 2018TargetedForwarder
Same deployerLate 2018 deposit address that does not know where it is sending: on every payment it asks a shared registry for the current target, forwards the whole amount there, and logs it.
0xe13c49...c3d27fSeptember 20, 2018TargetedForwarder
Same deployerLate 2018 deposit address that does not know where it is sending: on every payment it asks a shared registry for the current target, forwards the whole amount there, and logs it.
0xae34a2...1d62b7September 20, 2018TargetedForwarder
Same deployerLate 2018 deposit address that does not know where it is sending: on every payment it asks a shared registry for the current target, forwards the whole amount there, and logs it.
0x2f3580...1a9071September 20, 2018TargetedForwarder
Same deployerLate 2018 deposit address that does not know where it is sending: on every payment it asks a shared registry for the current target, forwards the whole amount there, and logs it.
0x7658e8...d9b075September 20, 2018TargetedForwarder
Same deployerLate 2018 deposit address that does not know where it is sending: on every payment it asks a shared registry for the current target, forwards the whole amount there, and logs it.
0x32ccd3...f19e14September 20, 2018