Copied token from future recopistory

This commit is contained in:
Jordi Baylina
2016-11-08 14:12:24 +01:00
commit ddd1df5f9e
6 changed files with 971 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules/

276
MiniMeToken.sol Normal file
View File

@@ -0,0 +1,276 @@
pragma solidity ^0.4.4;
contract Owned {
/// Allows only the owner to call a function
modifier onlyOwner { if (msg.sender != owner) throw; _; }
address public owner;
function Owned() { owner = msg.sender;}
function changeOwner(address _newOwner) onlyOwner {
owner = _newOwner;
}
}
contract MiniMeToken is Owned {
string public name; //fancy name: eg Simon Bucks
uint8 public decimals; //How many decimals to show. ie. There could 1000 base units with 3 decimals. Meaning 0.980 SBX = 980 base units. It's like comparing 1 wei to 1 ether.
string public symbol; //An identifier: eg SBX
string public version = 'H0.1'; //human 0.1 standard. Just an arbitrary versioning scheme.
struct Checkpoint {
// snapshot when starts to take effect this assignation
uint fromBlock;
// balance assigned to token holder from this snapshot
uint value;
}
MiniMeToken public parentToken;
uint public parentSnapShotBlock;
uint public creationBlock;
mapping (address => Checkpoint[]) balances;
mapping (address => mapping (address => uint256)) allowed;
Checkpoint[] totalSupplyHistory;
bool public isConstant;
MiniMeTokenFactory public tokenFactory;
////////////////
// Constructor
////////////////
function MiniMeToken(
address _tokenFactory,
address _parentToken,
uint _parentSnapShotBlock,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
bool _isConstant
) {
tokenFactory = MiniMeTokenFactory(_tokenFactory);
name = _tokenName; // Set the name for display purposes
decimals = _decimalUnits; // Amount of decimals for display purposes
symbol = _tokenSymbol; // Set the symbol for display purposes
parentToken = MiniMeToken(_parentToken);
parentSnapShotBlock = _parentSnapShotBlock;
isConstant = _isConstant;
creationBlock = block.number;
}
////////////////
// ERC20 Interface
////////////////
function transfer(address _to, uint256 _value) returns (bool success) {
return doTransfer(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
//same as above. Replace this line with the following if you want to protect against wrapping uints.
//if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
if (isConstant) throw;
if (msg.sender != owner) {
if (allowed[_from][msg.sender] < _value) return false;
allowed[_from][msg.sender] -= _value;
}
return doTransfer(_from, _to, _value);
}
function doTransfer(address _from, address _to, uint _value) internal returns(bool) {
if (_value == 0) {
return true;
}
// Do not allow transfer to this
if ((_to == 0) || (_to == address(this))) throw;
// Remove _from votes
var previousBalanceFrom = balanceOfAt(_from, block.number);
if (previousBalanceFrom < _value) {
return false;
}
updateValueAtNow(balances[_from], previousBalanceFrom - _value);
var previousBalanceTo = balanceOfAt(_to, block.number);
updateValueAtNow(balances[_to], previousBalanceTo + _value);
Transfer(_from, _to, _value);
return true;
}
function balanceOf(address _owner) constant returns (uint256 balance) {
return balanceOfAt(_owner, block.number);
}
function approve(address _spender, uint256 _value) returns (bool success) {
if (isConstant) throw;
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
/* Approves and then calls the receiving contract */
function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
if (isConstant) throw;
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
//call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn't have to include a contract in here just for this.
//receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
//it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.
if(!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { throw; }
return true;
}
function totalSupply() constant returns (uint) {
return totalSupplyAt(block.number);
}
////////////////
// Query balance and totalSupply in History
////////////////
function balanceOfAt(address _holder, uint _blockNumber) constant returns (uint) {
if (_blockNumber < creationBlock) {
return 0;
} else if ((balances[_holder].length == 0) || (balances[_holder][0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.balanceOfAt(_holder, parentSnapShotBlock);
} else {
return 0;
}
} else {
return getValueAt( balances[_holder], _blockNumber);
}
}
function totalSupplyAt(uint _blockNumber) constant returns(uint) {
if (_blockNumber < creationBlock) {
return 0;
} else if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.totalSupplyAt(parentSnapShotBlock);
} else {
return 0;
}
} else {
return getValueAt( totalSupplyHistory, _blockNumber);
}
}
////////////////
// Create a child token from an snapshot of this token at a given block
////////////////
function createChildToken(string _childTokenName, uint8 _childDecimalUnits, string _childTokenSymbol, uint _snapshotBlock, bool _isConstant) returns(address) {
if (_snapshotBlock > block.number) _snapshotBlock = block.number;
MiniMeToken childToken = tokenFactory.createChildToken(this, _snapshotBlock, _childTokenName, _childDecimalUnits, _childTokenSymbol, _isConstant);
NewChildToken(address(childToken), _snapshotBlock);
return address(childToken);
}
////////////////
// Generate and destroy tokens
////////////////
function generateTokens(address _holder, uint _value) onlyOwner {
if (isConstant) throw;
uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
updateValueAtNow(totalSupplyHistory, curTotalSupply + _value);
var previousBalanceTo = balanceOf(_holder);
updateValueAtNow(balances[_holder], previousBalanceTo + _value);
Transfer(0, _holder, _value);
}
function destroyTokens(address _holder, uint _value) onlyOwner {
if (isConstant) throw;
uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
if (curTotalSupply < _value) throw;
updateValueAtNow(totalSupplyHistory, curTotalSupply - _value);
var previousBalanceFrom = balanceOf(_holder);
if (previousBalanceFrom < _value) throw;
updateValueAtNow(balances[_holder], previousBalanceFrom - _value);
Transfer(_holder, 0, _value);
}
////////////////
// Constant tokens
////////////////
function setConstant(bool _isConstant) onlyOwner {
isConstant = _isConstant;
}
////////////////
// Internal helper functions to query and set a value in a snapshot array
////////////////
function getValueAt(Checkpoint[] storage checkpoints, uint _block) constant internal returns (uint) {
if (checkpoints.length == 0) return 0;
//Shorcut for the actual value
if (_block >= checkpoints[checkpoints.length-1].fromBlock) return checkpoints[checkpoints.length-1].value;
if (_block < checkpoints[0].fromBlock) return 0;
uint min = 0;
uint max = checkpoints.length-1;
while (max > min) {
uint mid = (max + min + 1)/ 2;
if (checkpoints[mid].fromBlock<=_block) {
min = mid;
} else {
max = mid-1;
}
}
return checkpoints[min].value;
}
function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value) internal {
if ((checkpoints.length == 0) || (checkpoints[checkpoints.length -1].fromBlock < block.number)) {
Checkpoint newCheckPoint = checkpoints[ checkpoints.length++ ];
newCheckPoint.fromBlock = block.number;
newCheckPoint.value = _value;
} else {
Checkpoint oldCheckPoint = checkpoints[checkpoints.length-1];
oldCheckPoint.value = _value;
}
}
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
event NewChildToken(address indexed _childToken, uint _snapshotBlock);
}
contract MiniMeTokenFactory {
function createChildToken(
address _parentToken,
uint _snapshotBlock,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
bool _isConstant
) returns (MiniMeToken) {
MiniMeToken newToken = new MiniMeToken(this, _parentToken, _snapshotBlock, _tokenName, _decimalUnits, _tokenSymbol, _isConstant);
return newToken;
}
}

58
README.md Normal file
View File

@@ -0,0 +1,58 @@
# MiniMeToken
A MiniMeToken is a standard ERC20 token with some extra functionality:
### The token is clonable
Any body can create a new token with an initial distribution of cloned tokens identical to the original token. At some specific block.
To create a child token, the next function is defined:
function createChildToken(
string _childTokenName,
uint8 _childDecimalUnits,
string _childTokenSymbol
uint _snapshotBlock, // if block is not already mined, it will teke the current block
bool _isConstant
) returns(address)
Once the child token is created, it acts as a completely independent token.
### Balances history is registered and available
The contract maintains a history of all the distribution changes of the token. Two calls are introduced to know the totalSupply and the balance of any address at any block in the past.
function totalSupplyAt(uint _blockNumber) constant returns(uint)
function balanceOfAt(address _holder, uint _blockNumber) constant returns (uint)
### Optional token owner
The owner of the contract can generate/destroy/transfer tokens at its own discretion. Of course, the owner can be a regular account, another contract that rules the contract or just the address 0x0 if this functionality is not wanted.
As an example, a Token Creation contract can be the owner of the Token Contract and at the end of the token creation period, the ownership can be transfered to the 0x0 address.
To create and destroy tokens, this two functions are introduced:
function generateTokens(address _holder, uint _value) onlyOwner
function destroyTokens(address _holder, uint _value) onlyOwner
### Owner of the token can freeze the transfers.
Tokens can be created with the constant flag set on, and the owner can also toggle this flag. When a token is flagged with this flag, no transfers, generations and destroys are allowed.
function setConstant(bool _isConstant) onlyOwner
## Applications
Some of the applications that child tokens can be used for are:
1. a ballot that is burned when you vote.
2. a discount ticked that is redeemed when you use it.
3. a token of a "spinoff" DAO.
4. a token that can be used to give explicit support to an action or a campaign.
5. lots of other applications.
And all that maintaining always the original token.

77
js/minimetoken_helper.js Normal file
View File

@@ -0,0 +1,77 @@
/*jslint node: true */
"use strict";
var async = require('async');
var ethConnector = require('ethconnector');
var path = require('path');
var _ = require('lodash');
var miniMeTokenAbi;
var minimeToken;
var miniMeTokenFactoryAbi;
var miniMeTokenFactory;
var src;
exports.deploy = function(opts, cb) {
var compilationResult;
return async.series([
function(cb) {
ethConnector.loadSol(path.join(__dirname, "../MiniMeToken.sol"), function(err, _src) {
if (err) return cb(err);
src = _src;
cb();
});
},
function(cb) {
ethConnector.applyConstants(src, opts, function(err, _src) {
if (err) return cb(err);
src = _src;
cb();
});
},
function(cb) {
ethConnector.compile(src, function(err, result) {
if (err) return cb(err);
compilationResult = result;
cb();
});
},
function(cb) {
miniMeTokenFactoryAbi = JSON.parse(compilationResult.MiniMeTokenFactory.interface);
ethConnector.deploy(compilationResult.MiniMeTokenFactory.interface,
compilationResult.MiniMeTokenFactory.bytecode,
0,
0,
function(err, _miniMeTokenFactory) {
if (err) return cb(err);
miniMeTokenFactory = _miniMeTokenFactory;
cb();
});
},
function(cb) {
miniMeTokenAbi = JSON.parse(compilationResult.MiniMeToken.interface);
exports.miniMeTokenAbi = miniMeTokenAbi;
ethConnector.deploy(compilationResult.MiniMeToken.interface,
compilationResult.MiniMeToken.bytecode,
0,
0,
miniMeTokenFactory.address,
0,
0,
opts.tokenName,
opts.decimalUnits,
opts.tokenSymbol,
opts.isConstant || false,
function(err, _minimeToken) {
if (err) return cb(err);
minimeToken = _minimeToken;
cb();
});
}
], function(err) {
if (err) return cb(err);
cb(null,minimeToken, compilationResult);
});
};

34
package.json Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "minimi",
"version": "0.0.1",
"description": "Minimi contract",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "mocha"
},
"repository": {
"type": "git",
"url": "https://github.com/CharityDAO/minimi.git"
},
"keywords": [
"dao",
"solidity",
"token",
"charity",
"smart",
"contract",
"minime"
],
"author": "Jordi Baylina",
"license": "GPL-3.0",
"bugs": {
"url": "https://github.com/CharityDAO/minimi/issues"
},
"homepage": "https://github.com/CharityDAO/future",
"dependencies": {
"ethconnector": "0.0.13"
}
}

525
test/minimetoken_normal.js Normal file
View File

@@ -0,0 +1,525 @@
/*jslint node: true */
/*global describe, it, before, beforeEach, after, afterEach */
"use strict";
var miniMeTokenHelper = require('../js/minimetoken_helper.js');
var ethConnector = require('ethconnector');
var BigNumber = require('bignumber.js');
var assert = require("assert"); // node.js core module
var async = require('async');
var _ = require('lodash');
var verbose = false;
// b[0] -> 0, 0, 0, 0
// b[1] -> 0,10, 0, 0
// b[2] -> 0, 8, 2, 0
// b[3] -> 0, 9, 1, 0
// b[4] -> 0, 6, 1, 0
// Child token
// b[5] -> 0, 6, 1, 0
// b[6] -> 0, 2, 5. 0
describe('MiniMeToken test', function(){
var miniMeToken;
var miniMeTokenChild;
var b = [];
before(function(done) {
ethConnector.init('testrpc' ,done);
// ethConnector.init('rpc', done);
});
it('should deploy all the contracts ', function(done){
this.timeout(200000000);
var now = Math.floor(new Date().getTime() /1000);
miniMeTokenHelper.deploy({
tokenName: "MiniMe Test Token",
decimalUnits: 18,
tokenSymbol: "MMT",
}, function(err, _miniMeToken) {
assert.ifError(err);
assert.ok(_miniMeToken.address);
miniMeToken = _miniMeToken;
done();
});
});
it('Should generate tokens for address 1', function(done) {
this.timeout(2000);
async.series([
function(cb) {
ethConnector.web3.eth.getBlockNumber(function (err, _blockNumber) {
assert.ifError(err);
b[0] = _blockNumber;
log("b[0]->"+b[0]);
cb();
});
},
function(cb) {
miniMeToken.generateTokens(ethConnector.accounts[1], ethConnector.web3.toWei(10), {
from: ethConnector.accounts[0],
gas: 200000},
function(err) {
assert.ifError(err);
cb();
}
);
},
function(cb) {
miniMeToken.totalSupply(function(err, _totalSupply) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_totalSupply), 10);
cb();
});
},
function(cb) {
miniMeToken.balanceOf(ethConnector.accounts[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 10);
cb();
});
},
function(cb) {
ethConnector.web3.eth.getBlockNumber(function (err, _blockNumber) {
assert.ifError(err);
b[1] = _blockNumber;
log("b[1]->"+b[1]);
cb();
});
}
],function(err) {
done();
});
});
it('Should transfer tokens from address 1 to address 2', function(done) {
this.timeout(2000);
async.series([
function(cb) {
miniMeToken.transfer(ethConnector.accounts[2], ethConnector.web3.toWei(2), {
from: ethConnector.accounts[1],
gas: 200000},
function(err) {
assert.ifError(err);
cb();
}
);
},
function(cb) {
ethConnector.web3.eth.getBlockNumber(function (err, _blockNumber) {
assert.ifError(err);
b[2] = _blockNumber;
log("b[2]->"+b[2]);
cb();
});
},
function(cb) {
miniMeToken.totalSupply(function(err, _totalSupply) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_totalSupply), 10);
cb();
});
},
function(cb) {
miniMeToken.balanceOf(ethConnector.accounts[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 8);
cb();
});
},
function(cb) {
miniMeToken.balanceOf(ethConnector.accounts[2], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 2);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[1], b[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance).toNumber(), 10);
cb();
});
},
],function(err) {
done();
});
});
it('Should allow and transfer tokens from address 2 to address 1 allowed to 3', function(done) {
async.series([
function(cb) {
miniMeToken.approve(ethConnector.accounts[3], ethConnector.web3.toWei(2), {
from: ethConnector.accounts[2],
gas: 200000},
function(err) {
assert.ifError(err);
cb();
}
);
},
function(cb) {
miniMeToken.allowance(ethConnector.accounts[2], ethConnector.accounts[3], function(err, _allowed) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_allowed), 2);
cb();
});
},
function(cb) {
miniMeToken.transferFrom(ethConnector.accounts[2], ethConnector.accounts[1], ethConnector.web3.toWei(1), {
from: ethConnector.accounts[3],
gas: 200000},
function(err) {
assert.ifError(err);
cb();
}
);
},
function(cb) {
miniMeToken.allowance(ethConnector.accounts[2], ethConnector.accounts[3], function(err, _allowed) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_allowed), 1);
cb();
});
},
function(cb) {
ethConnector.web3.eth.getBlockNumber(function (err, _blockNumber) {
assert.ifError(err);
b[3] = _blockNumber;
log("b[3]->"+b[3]);
cb();
});
},
function(cb) {
miniMeToken.balanceOf(ethConnector.accounts[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 9);
cb();
});
},
function(cb) {
miniMeToken.balanceOf(ethConnector.accounts[2], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 1);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[1], b[2], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 8);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[2], b[2], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 2);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[1], b[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 10);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[2], b[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[1], b[0], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[2], b[0], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[1], 0, function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[2], 0, function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
],function(err) {
done();
});
});
it('Should Destroy 3 tokens from 1 and 1 from 2', function(done) {
async.series([
function(cb) {
miniMeToken.destroyTokens(ethConnector.accounts[1], ethConnector.web3.toWei(3), {
from: ethConnector.accounts[0],
gas: 200000},
function(err) {
assert.ifError(err);
cb();
}
);
},
function(cb) {
ethConnector.web3.eth.getBlockNumber(function (err, _blockNumber) {
assert.ifError(err);
b[4] = _blockNumber;
log("b[4]->"+b[4]);
cb();
});
},
function(cb) {
miniMeToken.totalSupply(function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 7);
cb();
});
},
function(cb) {
miniMeToken.balanceOf(ethConnector.accounts[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 6);
cb();
});
},
],function(err) {
done();
});
});
it('Should Create the child token', function(done) {
this.timeout(200000000);
async.series([
function(cb) {
miniMeToken.createChildToken(
"Child Token 1",
18,
"MMTc",
Number.MAX_SAFE_INTEGER,
false,
{
from: ethConnector.accounts[3],
gas: 4700000
},
function(err, txHash) {
assert.ifError(err);
ethConnector.web3.eth.getTransactionReceipt(txHash, function(err, res) {
var childTokenAddr = ethConnector.web3.toBigNumber(res.logs[0].topics[1]).toString(16);
while (childTokenAddr.length < 40) childTokenAddr = '0' + childTokenAddr;
childTokenAddr = '0x' + childTokenAddr;
miniMeTokenChild = ethConnector.web3.eth.contract( miniMeTokenHelper.miniMeTokenAbi).at(childTokenAddr);
cb();
});
});
},
function(cb) {
ethConnector.web3.eth.getBlockNumber(function (err, _blockNumber) {
assert.ifError(err);
b[5] = _blockNumber;
log("b[5]->"+b[5]);
cb();
});
},
function(cb) {
miniMeTokenChild.parentToken(function(err, _parentAddress) {
assert.ifError(err);
assert.equal(_parentAddress, miniMeToken.address);
cb();
});
},
function(cb) {
miniMeTokenChild.parentSnapShotBlock(function(err, _parentSnapshotBlock) {
assert.ifError(err);
assert.equal(_parentSnapshotBlock, b[5]);
cb();
});
},
function(cb) {
miniMeTokenChild.totalSupply(function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 7);
cb();
});
},
function(cb) {
miniMeTokenChild.balanceOf(ethConnector.accounts[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 6);
cb();
});
},
function(cb) {
miniMeTokenChild.totalSupplyAt(b[4], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
function(cb) {
miniMeTokenChild.balanceOfAt(ethConnector.accounts[2], b[4], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
],function(err) {
done();
});
});
it('Should move tokens in the child token from 2 to 3', function(done) {
async.series([
function(cb) {
miniMeTokenChild.transfer(ethConnector.accounts[2], ethConnector.web3.toWei(4), {
from: ethConnector.accounts[1],
gas: 200000},
function(err) {
assert.ifError(err);
cb();
}
);
},
function(cb) {
ethConnector.web3.eth.getBlockNumber(function (err, _blockNumber) {
assert.ifError(err);
b[6] = _blockNumber;
log("b[6]->"+b[6]);
cb();
});
},
function(cb) {
miniMeTokenChild.balanceOf(ethConnector.accounts[1], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 2);
cb();
});
},
function(cb) {
miniMeTokenChild.balanceOf(ethConnector.accounts[2], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 5);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[1], b[5], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 6);
cb();
});
},
function(cb) {
miniMeToken.balanceOfAt(ethConnector.accounts[2], b[5], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 1);
cb();
});
},
function(cb) {
miniMeTokenChild.balanceOfAt(ethConnector.accounts[1], b[5], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 6);
cb();
});
},
function(cb) {
miniMeTokenChild.balanceOfAt(ethConnector.accounts[2], b[5], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 1);
cb();
});
},
function(cb) {
miniMeTokenChild.balanceOfAt(ethConnector.accounts[1], b[4], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
function(cb) {
miniMeTokenChild.balanceOfAt(ethConnector.accounts[2], b[4], function(err, _balance) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_balance), 0);
cb();
});
},
function(cb) {
miniMeTokenChild.totalSupply(function(err, _totalSupply) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_totalSupply), 7);
cb();
});
},
function(cb) {
miniMeTokenChild.totalSupplyAt(b[5], function(err, _totalSupply) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_totalSupply), 7);
cb();
});
},
function(cb) {
miniMeTokenChild.totalSupplyAt(b[4], function(err, _totalSupply) {
assert.ifError(err);
assert.equal(ethConnector.web3.fromWei(_totalSupply), 0);
cb();
});
}
],function(err) {
done();
});
});
function bcDelay(secs, cb) {
send("evm_increaseTime", [secs], function(err, result) {
if (err) return cb(err);
// Mine a block so new time is recorded.
send("evm_mine", function(err, result) {
if (err) return cb(err);
cb();
});
});
}
function log(S) {
if (verbose) {
console.log(S);
}
}
// CALL a low level rpc
function send(method, params, callback) {
if (typeof params == "function") {
callback = params;
params = [];
}
ethConnector.web3.currentProvider.sendAsync({
jsonrpc: "2.0",
method: method,
params: params || [],
id: new Date().getTime()
}, callback);
}
});