Updated 00:57 Aug 20 2016 UTC - using BigNumber
to accurately compute the totalSupply
figures.
Checking Your The DAO Token Balance
From ETC withdraw contract to be reviewed you can check your The DAO token balance at pre-hard-fork block 1,919,999 using geth
synced to the Ethereum Classic chain using the following commands:
geth --fast --oppose-dao-fork console
// Allow the chain to sync
> var daobalancesnapshot_abi = [{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"seal","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"totalAccounts","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"data","type":"uint256[]"}],"name":"fill","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"sealed","outputs":[{"name":"","type":"bool"}],"type":"function"},{"inputs":[],"type":"constructor"}];
undefined
> var daobalancesnapshot = web3.eth.contract(daobalancesnapshot_abi).at("0x180826b05452ce96e157f0708c43381fee64a6b8");
undefined
> daobalancesnapshot.balanceOf(YOURACCOUNTHERE);
123456
Alternatively, you can verify your The DAO token balances at block 1,919,999 in theDAOTokenBalance_20160819_155742UTC_balance.xlsx. You may have to right mouse click -> Save Link As to download the spreadsheet to your computer.
Checking All DAO Token Balances
The script getTheDAOTokenBalance finds all addresses involved in the CreatedToken
and Transfer
The DAO events and queries each of these addresses against The DAO's balanceOf(...)
function, AT block 1,919,999.
The script additionally reconciles this results against the DAOBalanceSnapShot
contract at 0x180826b05452ce96e157f0708c43381fee64a6b8 (with ABI here) that the Goodies intend to use to determine the number of The DAO tokens each address owns at block 1,919,999.
The results are that my script calculate the same number of The DAO tokens for each address compared to the Goodies' DAOBalanceSnapShot
contract and the totals are the same.
There is a summary at github.com/bokkypoobah/TheDAOETCTokenBalance. You can find all the CreatedToken
events in theDAOTokenBalance_20160819_155742UTC_creation.txt, all the Transfer
events in theDAOTokenBalance_20160819_155742UTC_transfer.txt and all balances at block 1,919,999 in theDAOTokenBalance_20160819_155742UTC_balance.txt and theDAOTokenBalance_20160819_155742UTC_balance.xlsx.
My script finds a total of 22,092 non-zero accounts with a total of 1,153,816,598.7024671407837618 DAOs. My script queries the Goodies' DAOBalanceSnapShot
contract and finds the same DAO total. The DAOBalanceSnapShot
contract has a totalSupply
attribute that returns the value 11538165987024671407837618 or 1,153,816,598.7024671407837618 DAOs.The Goodies' DAOBalanceSnapShot
contract accurately represent the balances of DTH's accounts at the pre-hard-fork block 1,919,999.
And checking theDAO's totalSupply()
at pre-hard-fork block 1,919,999 using geth
confirms the total supply figure.
> var theDAOABIFragment = [{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"type":"function"}];
undefined
> var theDAOAddress = "0xbb9bc244d798123fde783fcc1c72d3bb8c189413"
undefined
> var theDAO = web3.eth.contract(theDAOABIFragment).at(theDAOAddress);
undefined
> theDAO.totalSupply(1919999).toString(10);
"11538165987024671407837618"
The Script
To use the following script, you will have to download the Classic blockchain using geth --oppose-dao-fork console
. Note that you cannot use the --fast
parameter as this will exclude the intermediate results required for the debug.traceTransaction(...)
API query required to determine the correct addresses involved in the token creation. The script will take over half a day to execute, depending on the speed of your processor and disk.
The script getTheDAOTokenBalance follows:
#!/bin/sh
# ------------------------------------------------------------------------------
# Retrieve The DAO Creation and Transfer events, collecting addresses. Then
# retrieve the pre-hard-fork balances and the current balances for these
# addresses.
#
# v2 improvements
# * Summing totals as BigNumbers instead of floats
# * Only including non-zero balances at block 1919999 in counter
#
# Usage:
# 1. Download this script to getTheDAOTokenBalance .
# 2. `chmod 700 getTheDAOTokenBalance`
# 3. Run `geth console` in a window.
# 4. Then run this script `./getTheDAOTokenBalance` in a separate window.
#
# Enjoy. (c) BokkyPooBah 2016. The MIT licence.
# ------------------------------------------------------------------------------
DATE=`date -u +%Y%m%d_%H%M%S`
OUTPUT=theDAOTokenBalance_${DATE}UTC_all.txt
CREATION=theDAOTokenBalance_${DATE}UTC_creation.txt
TRANSFER=theDAOTokenBalance_${DATE}UTC_transfer.txt
BALANCE=theDAOTokenBalance_${DATE}UTC_balance.txt
geth attach << EOF | egrep "^Header|^Data|^Stats|^Footer" > $OUTPUT
var theDAOABIFragment = [{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"type":"function"}, {"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"CreatedToken","type":"event"}, {"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Transfer","type":"event"}];
var theDAOAddress = "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413";
var theDAO = web3.eth.contract(theDAOABIFragment).at(theDAOAddress);
var theDAOTokenBalancePreHardForkABI = [{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"seal","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"totalAccounts","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"data","type":"uint256[]"}],"name":"fill","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"sealed","outputs":[{"name":"","type":"bool"}],"type":"function"},{"inputs":[],"type":"constructor"}];
var theDAOTokenBalancePreHardForkAddress = "0x180826b05452ce96e157f0708c43381fee64a6b8";
var theDAOTokenBalancePreHardForkContract = web3.eth.contract(theDAOTokenBalancePreHardForkABI).at(theDAOTokenBalancePreHardForkAddress);
// The DAO created in block 1428757 Apr-30-2016 01:42:58 AM +UTC
var creationStartBlock = 1428757;
// First The DAO creation event with non-zero extraBalance in block 1520861 May-15-2016 09:00:16 AM +UTC
var creationWithExtraBalanceStartBlock = 1520861;
// Last The DAO creation event in block 1599205 May-28-2016 08:59:47 AM +UTC
var creationEndBlock = 1599205;
// First The DAO transfer event in block 1599207 May-28-2016 09:00:07 AM +UTC, but use block above
var transferStartBlock = creationEndBlock + 1;
// Last The DAO transfer
var transferEndBlock = eth.blockNumber;
// Pre hard-fork block
var preHardForkBlock = 1919999;
// Hard-fork block
var hardForkBlock = 1920000;
// Collect addresses
var addresses = {};
// --- Get creation events ---
var startBlock = creationStartBlock;
var endBlock = creationEndBlock;
// Testing
// startBlock = creationWithExtraBalanceStartBlock - 5;
// endBlock = creationWithExtraBalanceStartBlock + 5;
var theDAOCreatedTokenEvent = theDAO.CreatedToken({}, {fromBlock: startBlock, toBlock: endBlock});
console.log("HeaderCreation\tTokenOwner");
var i = 0;
theDAOCreatedTokenEvent.watch(function(error, result) {
addresses[result.args.to] = 1;
i = i + 1;
console.log("DataCreation\t" + i + "\t" + result.args.to);
});
// --- Get transfer events ---
var startBlock = transferStartBlock;
var endBlock = transferEndBlock;
// Testing
// startBlock = transferStartBlock;
// endBlock = transferStartBlock + 10;
var theDAOTransferEvent = theDAO.Transfer({}, {fromBlock: startBlock, toBlock: endBlock});
console.log("HeaderTransfer\tFrom\tTo");
i = 0;
theDAOTransferEvent.watch(function(error, result) {
addresses[result.args._from] = 1;
addresses[result.args._to] = 1;
i = i + 1;
console.log("DataTransfer\t" + i + "\t" + result.args._from + "\t" + result.args._to);
});
// --- Get balances ---
var currentBlock = transferEndBlock;
console.log("HeaderBalance\tNumber\tAddress\tPreHardForkDAO\tPreHardForkDAOContract\tPreHardForkDAODiff\tCurrentDAO\tChangeDAO\tPreHardForkETH\tCurrentETH\tChangeETH");
var daosPreHardForkTotal = new BigNumber(0);
var daosPreHardForkContractTotal = new BigNumber(0);
var daosCurrentTotal = new BigNumber(0);
var nonZeroAccounts = new BigNumber(0);
i = 0;
for (var address in addresses) {
i = i + 1;
var checkAddress = "0xda0031fab25270778386a2dcac0bb934a288c464";
var daosPreHardFork = theDAO.balanceOf(address, preHardForkBlock);
var daosPreHardForkContract = theDAOTokenBalancePreHardForkContract.balanceOf(address);
var daosPreHardForkDiff = daosPreHardFork - daosPreHardForkContract;
var daosCurrent = theDAO.balanceOf(address, currentBlock);
if (daosPreHardFork != 0 || daosPreHardForkContract != 0) {
nonZeroAccounts++;
}
var daosChange = daosCurrent - daosPreHardFork;
var ethsPreHardFork = eth.getBalance(address, preHardForkBlock);
var ethsCurrent = eth.getBalance(address, currentBlock);
var ethsChange = ethsCurrent - ethsPreHardFork;
daosPreHardForkTotal = daosPreHardForkTotal.plus(daosPreHardFork);
daosPreHardForkContractTotal = daosPreHardForkContractTotal.plus(daosPreHardForkContract);
daosCurrentTotal = daosCurrentTotal.plus(daosCurrent);
console.log("DataBalance\t" + i + "\t" + address + "\t" +
(daosPreHardFork/1e16).toFixed(16) + "\t" + (daosPreHardForkContract/1e16).toFixed(16) + "\t" + (daosPreHardForkDiff/1e16).toFixed(16) + "\t" +
(daosCurrent/1e16).toFixed(16) + "\t" + (daosChange/1e16).toFixed(16) + "\t" +
(ethsPreHardFork/1e18).toFixed(18) + "\t" + (ethsCurrent/1e18).toFixed(18) + "\t" + (ethsChange/1e18).toFixed(18));
}
console.log("Stats\tnonZeroAccounts\t" + nonZeroAccounts);
console.log("Stats\tdaosPreHardForkTotal\t" + daosPreHardForkTotal.toPrecision(30) + "\t" + (daosPreHardForkTotal/1e16).toFixed(16));
console.log("Stats\tdaosPreHardForkContractTotal\t" + daosPreHardForkContractTotal.toPrecision(30) + "\t" + (daosPreHardForkContractTotal/1e16).toFixed(16));
console.log("Stats\tdaosCurrentTotal\t" + daosCurrentTotal.toPrecision(30) + "\t" + (daosCurrentTotal/1e16).toFixed(16));
console.log("Footer\tReport generated at " + (new Date()).toGMTString() + " with latest block number " + transferEndBlock);
EOF
egrep "HeaderCreation|DataCreation|Footer" $OUTPUT > $CREATION
egrep "HeaderTransfer|DataTransfer|Footer" $OUTPUT > $TRANSFER
egrep "HeaderBalance|DataBalance|Footer|Stats" $OUTPUT > $BALANCE