The earliest fully compliant ERC-20 token contract on Ethereum mainnet, wrapping Ether 1:1 into a transferable token.
Historical Significance
Deployed in April 2016, Ether Token Proxy predates decentralized exchanges, automated market makers, and the canonical Wrapped Ether implementations that later became foundational to DeFi.
At a time when ERC-20 was still an emerging community standard and many tokens were only partially compliant, this contract adhered strictly to the full interface and event structure.
By wrapping native ETH into a standards-compliant ERC-20 token, it anticipated one of the most important primitives in decentralized finance: composable Ether.
Context
In early 2016, Ethereum was less than a year old. ERC-20 existed primarily as a social standard rather than a formally enforced specification, and many deployed tokens implemented only subsets of the interface.
Native ETH itself was not ERC-20 compatible and could not interact uniformly with token contracts. Ether Token Proxy demonstrates early recognition of this limitation and presents a clean, fully compliant solution that abstracted ETH into a transferable token form.
The contract was deployed more than two years before Uniswap and modern DeFi infrastructure emerged.
Token Information
Key Facts
Description
Ether Token Proxy is a fully ERC-20 compliant smart contract that tokenizes Ether into a standard ERC-20 representation. Users deposit ETH to receive ERC-20 tokens and can redeem those tokens at any time to withdraw the underlying ETH.
The contract implements the complete ERC-20 interface:
totalSupply()balanceOf(address)transfer(address,uint256)transferFrom(address,address,uint256)approve(address,uint256)allowance(address,address)
It emits properly structured Transfer and Approval events in accordance with the ERC-20 specification.
Supply is dynamic and equals the contract’s ETH balance. Deposits mint tokens, withdrawals burn them, maintaining full collateralization at all times.
Source Verified
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Homestead Era
The first planned hard fork. Removed the canary contract, adjusted gas costs.
Bytecode Overview
Verified Source Available
Source verified on Etherscan.
Show source code (Solidity)
/*
live: 0x89d64bc7e46bdc49a89652ae9bb167418cbad62e
morden: 0xe379e36671acbcc87ec7b760c07e6e45a1294944
solc: v0.3.1-2016-04-12-3ad5e82 (optimization)
*/
contract tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token);
}
contract Token {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function totalSupply() constant returns (uint256 supply);
function balanceOf(address _owner) constant returns (uint256 balance);
function transfer(address _to, uint256 _value) returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
function approve(address _spender, uint256 _value) returns (bool success);
function approveAndCall(address _spender, uint256 _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
}
contract SafeAddSub {
function safeToAdd(uint a, uint b) internal returns (bool) {
return (a + b > a);
}
function safeToSubtract(uint a, uint b) internal returns (bool) {
return (a >= b);
}
function safeAdd(uint a, uint b) internal returns (uint256) {
if (!safeToAdd(a, b)) throw;
return a + b;
}
function safeSubtract(uint a, uint b) internal returns (uint256) {
if (!safeToSubtract(a, b)) throw;
return a - b;
}
}
contract EthToken is Token, SafeAddSub {
string public constant name = "Ether Token Proxy";
string public constant symbol = "ETH";
uint8 public constant decimals = 18;
uint256 public constant baseUnit = 10**18;
mapping (address => uint256) _balanceOf;
mapping (address => mapping (address => uint256)) _allowance;
event Deposit(address indexed owner, uint256 amount);
event Withdrawal(address indexed owner, uint256 amount);
function totalSupply() constant returns (uint256 supply) {
return this.balance;
}
function () {
deposit();
}
function deposit() {
_balanceOf[msg.sender] = safeAdd(_balanceOf[msg.sender], msg.value);
Deposit(msg.sender, msg.value);
}
function redeem() {
withdraw(_balanceOf[msg.sender]);
}
function withdraw(uint256 _value) returns (bool success) {
_balanceOf[msg.sender] = safeSubtract(_balanceOf[msg.sender], _value);
if (!msg.sender.send(_value)) {
if (!msg.sender.call.gas(msg.gas).value(_value)()) throw;
}
Withdrawal(msg.sender, _value);
return true;
}
function balanceOf(address _owner) constant returns (uint256 balance) {
return _balanceOf[_owner];
}
function transfer(address _to, uint256 _value) returns (bool success) {
if (_to == address(this) || _to == 0) {
return withdraw(_value);
} else {
_balanceOf[msg.sender] = safeSubtract(_balanceOf[msg.sender], _value);
_balanceOf[_to] = safeAdd(_balanceOf[_to], _value);
Transfer(msg.sender, _to, _value);
}
return true;
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
if (!safeToSubtract(_allowance[_from][msg.sender], _value)) throw;
if (_to == address(this) || _to == 0) {
if (!transferFrom(_from, msg.sender, _value)) throw;
withdraw(_value);
} else {
_balanceOf[_from] = safeSubtract(_balanceOf[_from], _value);
_balanceOf[_to] = safeAdd(_balanceOf[_to], _value);
_allowance[_from][msg.sender] = safeSubtract(_allowance[_from][msg.sender], _value);
Transfer(_from, _to, _value);
}
return true;
}
function approve(address _spender, uint256 _value) returns (bool success) {
_allowance[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function approveAndCall(address _spender, uint256 _value) returns (bool success) {
if (approve(_spender, _value)) {
tokenRecipient(_spender).receiveApproval(msg.sender, _value, this);
return true;
}
throw;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return _allowance[_owner][_spender];
}
}