Deposit forwarder that pushes incoming ether straight to a bank address, with a separate operator key for sweeping leftover ether and ERC-20 balances.
Historical Significance
Splitting the receiving address from the operating key is the pattern an exchange or payment processor reaches for once it is running deposit addresses at scale: the hot operator key can sweep but cannot change where funds land, and the owner key that can is used rarely. The addmod guard on the setters is a home-made confirmation step, standing in for the multisig or timelock a later contract would use.
Key Facts
Description
Three addresses live in storage: the owner, the bank that receives everything, and a transfer address that acts as a day-to-day operator. The payable fallback rejects zero-value payments and immediately forwards the amount received to the bank with a raw call, so a plain send to this address lands in the bank in the same transaction.
transferEther and transferToken exist for what the fallback misses. Both are open to the operator or the owner. transferEther checks the contract's own balance covers the request before forwarding; transferToken reads balanceOf on the token, checks the same three conditions, and calls transfer with the bank as the recipient. Failures are caught with assert rather than require, which in this compiler burns the remaining gas.
The two setters are the unusual part. Each takes the new address plus four numbers, and refuses unless addmod of the first three equals the fourth. The check is arithmetic, not cryptographic, so it works as a typo guard on the address rather than as a second authorisation factor.
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.11;
contract ERC20 {
function balanceOf(address _owner) constant returns (uint256 balance);
function transfer(address _to, uint256 _value) returns (bool success);
}
contract Forwarder {
address public owner;
address public bankAddress;
address public transferAddress;
function Forwarder() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
modifier onlyTransferOrOwner() {
require(msg.sender == transferAddress || msg.sender == owner);
_;
}
function () payable {
require(msg.value > 0);
assert(bankAddress.call.value(msg.value)());
}
function setBankAddress(address _addr, uint256 _a, uint256 _b, uint256 _k, uint256 _c) onlyOwner {
require(_addr != address(0));
require(addmod(_a, _b, _k) == _c);
bankAddress = _addr;
}
function setTransferAddress(address _addr, uint256 _a, uint256 _b, uint256 _k, uint256 _c) onlyOwner {
require(_addr != address(0));
require(addmod(_a, _b, _k) == _c);
transferAddress = _addr;
}
function transferToken(address _token, uint256 _amount) onlyTransferOrOwner {
uint256 balance;
assert(_token != address(0));
balance = ERC20(_token).balanceOf(this);
require(balance > 0 && _amount > 0 && balance >= _amount);
assert(ERC20(_token).transfer(bankAddress, _amount));
}
function transferEther(uint256 _amount) onlyTransferOrOwner {
require(this.balance > 0 && _amount > 0 && this.balance >= _amount);
assert(bankAddress.call.value(_amount)());
}
}