Deposit forwarder that asks a controller contract for its destination, forwards every incoming payment there, and logs the sender, the amount and the calldata.
Historical Significance
Exchange deposit systems of this period had to choose between burning a payout address into every deployed contract or paying for a storage write per contract. This family does neither: the destination is read from a shared controller at the moment funds arrive. The event carries the full calldata alongside the value, so an operator could attribute a deposit even when the sender attached data the forwarder itself never interpreted.
Key Facts
Description
A per-user deposit address. The payable fallback calls acceptFrom on its controller to register the incoming value, reads the current payout address from destination(), transfers the full msg.value to it, and emits Forwarded with the sender, this contract, the destination, the value and the raw calldata. Two sweep helpers cover tokens sent to the address by mistake: flushTokens pulls an ERC20 balance to the same destination, and flush moves any stranded ether. hasController reports whether a given address is the controller this forwarder trusts.
The design keeps the payout address out of the deployed bytecode. Each forwarder holds only a controller reference, so an exchange can redirect every deposit address it has ever handed out by updating one contract, without redeploying or asking users for a new 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.18;
contract Controller {
function acceptFrom(address _from, uint256 _value) public;
function destination() public returns (address);
}
contract ERC20 {
function balanceOf(address _owner) public returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
}
contract Forwarder {
Controller public controller;
event Forwarded(address from, address to, address destination, uint256 value, bytes data);
function () public payable {
controller.acceptFrom(this, msg.value);
address dest = controller.destination();
dest.transfer(msg.value);
Forwarded(msg.sender, this, dest, msg.value, msg.data);
}
function flushTokens(address _token) public {
ERC20 token = ERC20(_token);
uint256 bal = token.balanceOf(this);
address dest = controller.destination();
if (bal > 0) {
token.transfer(dest, bal);
}
}
function flush() public {
address dest = controller.destination();
dest.transfer(this.balance);
}
function hasController(address _addr) public constant returns (bool) {
return address(controller) == _addr;
}
}