One-off payment address that logs every incoming transaction and forwards the balance to a fixed payout address.
Historical Significance
This is accounting infrastructure rather than a protocol. The events are the product, and the contract exists to make a payment addressable and attributable without a database entry per customer. Its weak points are the same ones every payment forwarder of the period had: an unchecked send, and an event that records intent rather than outcome.
Key Facts
Description
The contract is an invoice in the literal sense: a merchant hands out a fresh address per bill, and anything sent to it is recorded and swept onward. The fallback emits IncomingTx with the block number indexed, plus the sender, the value and the timestamp, then forwards the contract's whole balance to the payout address stored at construction.
Indexing the block number rather than the sender is a deliberate choice. A back end reconciling payments scans by block range, not by payer, and the payer of an invoice is rarely known in advance.
The forward uses send and ignores the result, so a payout address that rejects the transfer leaves the funds sitting in the invoice while the event still claims the payment arrived. refund is owner-only and emits RefundInvoice, but moves nothing: the refund itself happens off chain, and the event is the receipt.
Source Verified
Homestead Era
The first planned hard fork. Removed the canary contract, adjusted gas costs.
Bytecode Overview
Verified Source Available
This contract has verified source code.
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
contract Invoice {
address public owner;
address payout;
event IncomingTx(uint256 indexed blockNumber, address from, uint256 value, uint256 timestamp);
event RefundInvoice(address invoice, uint256 timestamp);
function () {
IncomingTx(block.number, msg.sender, msg.value, now);
forward();
}
function forward() internal {
payout.send(this.balance);
}
function transferOwnership(address _newOwner) {
if (msg.sender != owner) throw;
owner = _newOwner;
}
function refund(address _to) {
if (msg.sender != owner) throw;
RefundInvoice(this, now);
}
}