Deposit forwarder on OpenZeppelin Ownable v2 that reads its payout address from a registry and carries a revert reason for failed token moves.
Historical Significance
Indexing both parties in the deposit event, rather than only the sender, means an operator can query by payout target across every forwarder they run. The unguarded token sweep is the same reasoning as its cousins: the funds can only ever move to one place, so there is nothing to protect and a stranger paying the gas is a gift.
Key Facts
Description
The payable fallback asks a registry contract for getTargetAddress, transfers the incoming value there, and emits EthForwarded with the sender and the target both indexed so either side can be filtered in a log query.
transferETH is owner gated and moves a chosen amount to a chosen address. transferTokens is deliberately not owner gated, so anyone may push a stranded token balance to the registry target, and it reverts with Token transfer has failed when the ERC20 refuses. Ownership uses the later OpenZeppelin shape with a private owner field, an isOwner helper and a renounceOwnership path.
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 private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(isOwner());
_;
}
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_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 Registry {
function getTargetAddress() public returns (address);
}
contract ERC20 {
function transfer(address to, uint256 value) public returns (bool);
}
contract Forwarder is Ownable {
Registry private registry;
event EthForwarded(address indexed from, address indexed to, uint256 value);
function () external 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, uint256 amount) public {
address target = registry.getTargetAddress();
ERC20 t = ERC20(token);
require(t.transfer(target, amount), "Token transfer has failed");
}
}