avsa's personal test of the ERC777 standard he co-authored — stripped-down ReferenceToken deployed from his wallet on Apr 5, 2018.
Historical Significance
avsa (Alex Van de Sande) was a co-author of EIP-777, the ERC777 token standard, alongside Jordi Baylina and Jacques Dafflon. This contract is his personal sandbox deployment of the standard he helped write — pushed from his own wallet (0xd1220a0c…b9adb / alex.vandesande.eth) less than two weeks after EIP-777's first draft. The choice of placeholder constructor args (name="My Token", symbol="TOK") and the absence of mint/burn/ownership functions confirms this was a test/demo rather than a production token. It captures what the bare minimum ERC777 surface looked like in the hands of one of its authors right at the moment the standard was crystallizing.
Context
Deployed on April 5, 2018 (block 5,385,661), seven months before EIP-777 was finalized. Based on the ReferenceToken contract from Jacques Dafflon's jacquesd/eip777 repository — the canonical reference implementation that avsa was actively reviewing at the time — but stripped of everything not strictly required by the standard: Owned, mint(), burn(), and the disable/enableERC20() toggle were all removed, leaving only the 16-selector ERC20+ERC777 dispatch surface. The ERC820 introspection registry used is Jordi Baylina's deployment at 0x991a1bcb077599290d7305493c9A630c20f8b798. Constructor args at deploy: name="My Token", symbol="TOK", initialSupply=0, granularity=0 (defaulting to 1).
Token Information
Key Facts
Source Verified
Source reconstructed from on-chain bytecode and matched against the jacquesd/eip777 ReferenceToken with avsa's strip-downs applied. Compiled with solc 0.4.21+commit.dfe3193c, optimizer enabled, runs=200. Result: 4029-byte runtime vs 4028 on-chain — a 1-byte difference attributable to a stack-allocation / argument-reuse choice the optimizer makes based on a tiny source-structure detail in doSend that we can't pin down without avsa's original .sol file. All 16 dispatch selectors, the storage layout, and every event signature align exactly. Reproducible build: github.com/cartoonitunes/avsa-erc777-verification.
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Byzantium Era
First Metropolis hard fork. Added zk-SNARK precompiles, REVERT opcode, and staticcall.
Bytecode Overview
Verified Source Available
Source verified through compiler archaeology (near-exact bytecode match).
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
// Reconstructed source for 0x04f3e35cba2bd70d2c37455c410e39826e7c8039
// Deployed by avsa.eth (0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb) on 2018-04-05
// Compiler: solc 0.4.21 + optimizer (runs=200)
// Result: NEAR-EXACT bytecode match (4029 vs 4028 on-chain, 1 byte difference)
pragma solidity ^0.4.21;
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a / b;
return c;
}
function sub(uint256 a, uint256 b) internal constant returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
interface ERC777TokensSender {
function tokensToSend(
address operator,
address from,
address to,
uint amount,
bytes userData,
bytes operatorData
) public;
}
interface ERC777TokensRecipient {
function tokensReceived(
address operator,
address from,
address to,
uint amount,
bytes userData,
bytes operatorData
) public;
}
contract ERC820Registry {
function getInterfaceImplementer(address addr, bytes32 iHash) public constant returns (address);
function setInterfaceImplementer(address addr, bytes32 iHash, address implementer) public;
}
contract ReferenceToken {
using SafeMath for uint256;
string public name;
string public symbol;
uint8 public decimals = 18;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
ERC820Registry private erc820Registry = ERC820Registry(0x991a1bcb077599290d7305493c9A630c20f8b798);
uint256 public granularity = 1;
mapping(address => mapping(address => bool)) public isOperatorFor;
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
event Sent(
address indexed operator,
address indexed from,
address indexed to,
uint256 amount,
bytes userData,
bytes operatorData
);
event Minted(address indexed operator, address indexed to, uint256 amount, bytes operatorData);
event Burned(address indexed operator, address indexed from, uint256 amount, bytes userData, bytes operatorData);
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
event RevokedOperator(address indexed operator, address indexed tokenHolder);
function ReferenceToken(
string _name,
string _symbol,
uint256 _initialSupply,
uint256 _granularity
) public {
name = _name;
symbol = _symbol;
totalSupply = _initialSupply * (10 ** 18);
granularity = _granularity == 0 ? 1 : _granularity;
setInterfaceImplementation("ERC20", this);
setInterfaceImplementation("ERC777", this);
}
function send(address _to, uint256 _amount) public {
doSend(msg.sender, _to, _amount, "", msg.sender, "", true);
}
function send(address _to, uint256 _amount, bytes _userData) public {
doSend(msg.sender, _to, _amount, _userData, msg.sender, "", true);
}
function authorizeOperator(address _operator) public {
isOperatorFor[_operator][msg.sender] = true;
AuthorizedOperator(_operator, msg.sender);
}
function revokeOperator(address _operator) public {
isOperatorFor[_operator][msg.sender] = false;
RevokedOperator(_operator, msg.sender);
}
function operatorSend(address _from, address _to, uint256 _amount, bytes _userData, bytes _operatorData) public {
require(isOperatorFor[msg.sender][_from]);
doSend(_from, _to, _amount, _userData, msg.sender, _operatorData, true);
}
function transfer(address _to, uint256 _amount) public returns (bool success) {
doSend(msg.sender, _to, _amount, "", msg.sender, "", false);
return true;
}
function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success) {
require(_amount <= allowance[_from][msg.sender]);
allowance[_from][msg.sender] -= _amount;
doSend(_from, _to, _amount, "", msg.sender, "", false);
return true;
}
function approve(address _spender, uint256 _amount) public returns (bool success) {
allowance[msg.sender][_spender] = _amount;
return true;
}
function isRegularAddress(address _addr) internal constant returns(bool) {
if (_addr == 0) { return false; }
uint size;
assembly { size := extcodesize(_addr) }
return size == 0;
}
function doSend(
address _from,
address _to,
uint256 _amount,
bytes _userData,
address _operator,
bytes _operatorData,
bool _preventLocking
) private {
require(_amount % granularity == 0);
require(_to != address(0));
uint256 _fromBal = balanceOf[_from];
require(_fromBal >= _amount);
uint256 _toBal = balanceOf[_to];
require(_toBal + _amount > _toBal);
if (_preventLocking) {
address impl = interfaceAddr(_from, "ERC777TokensSender");
if (impl != 0) {
ERC777TokensSender(impl).tokensToSend(
_operator, _from, _to, _amount, _userData, _operatorData);
}
impl = interfaceAddr(_to, "ERC777TokensRecipient");
if (impl != 0) {
ERC777TokensRecipient(impl).tokensReceived(
_operator, _from, _to, _amount, _userData, _operatorData);
} else {
require(isRegularAddress(_to));
}
}
balanceOf[_from] = _fromBal - _amount;
balanceOf[_to] = balanceOf[_to] + _amount;
Transfer(_from, _to, _amount);
Sent(_operator, _from, _to, _amount, _userData, _operatorData);
assert(balanceOf[_from] + balanceOf[_to] == _fromBal + _toBal);
}
function setInterfaceImplementation(string ifaceLabel, address impl) internal {
bytes32 ifaceHash = keccak256(ifaceLabel);
erc820Registry.setInterfaceImplementer(this, ifaceHash, impl);
}
function interfaceAddr(address addr, string ifaceLabel) internal constant returns(address) {
bytes32 ifaceHash = keccak256(ifaceLabel);
return erc820Registry.getInterfaceImplementer(addr, ifaceHash);
}
}