From e7217edc1b5f89b06ea8dbccbf818c6df831538e Mon Sep 17 00:00:00 2001 From: James Young Date: Sat, 5 May 2018 19:47:05 -0700 Subject: [PATCH] update how donations work and eth/token offerings --- contracts/BasicToken.sol | 50 +++++++++++ contracts/EIP20.sol | 72 +++++++++++++++ contracts/EIP20Interface.sol | 50 +++++++++++ contracts/ERC20.sol | 15 ++++ contracts/ERC20Basic.sol | 14 +++ contracts/GuildBank.sol | 21 ++++- contracts/Moloch.sol | 19 ++-- contracts/SafeMath.sol | 48 ++++++++++ contracts/StandardToken.sol | 100 +++++++++++++++++++++ contracts/TestCoin.sol | 16 ++++ contracts/TownHallLib.sol | 20 +---- migrations/2_moloch_migration.js | 3 - migrations/3_testcoin_migration.js | 14 +++ package-lock.json | 136 +++++++++++++++++++++++++++-- package.json | 5 ++ test/moloch.js | 51 ++++++++--- test/test.json | 1 + test/testcoins.json | 1 + 18 files changed, 583 insertions(+), 53 deletions(-) create mode 100644 contracts/BasicToken.sol create mode 100644 contracts/EIP20.sol create mode 100644 contracts/EIP20Interface.sol create mode 100644 contracts/ERC20.sol create mode 100644 contracts/ERC20Basic.sol create mode 100644 contracts/SafeMath.sol create mode 100644 contracts/StandardToken.sol create mode 100644 contracts/TestCoin.sol create mode 100644 migrations/3_testcoin_migration.js create mode 100644 test/test.json create mode 100644 test/testcoins.json diff --git a/contracts/BasicToken.sol b/contracts/BasicToken.sol new file mode 100644 index 0000000..8ab22f5 --- /dev/null +++ b/contracts/BasicToken.sol @@ -0,0 +1,50 @@ +pragma solidity ^0.4.21; + + +import "./ERC20Basic.sol"; +import "./SafeMath.sol"; + + +/** + * @title Basic token + * @dev Basic version of StandardToken, with no allowances. + */ +contract BasicToken is ERC20Basic { + using SafeMath for uint256; + + mapping(address => uint256) balances; + + uint256 totalSupply_; + + /** + * @dev total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return totalSupply_; + } + + /** + * @dev transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balances[msg.sender]); + + balances[msg.sender] = balances[msg.sender].sub(_value); + balances[_to] = balances[_to].add(_value); + emit Transfer(msg.sender, _to, _value); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address _owner) public view returns (uint256) { + return balances[_owner]; + } + +} \ No newline at end of file diff --git a/contracts/EIP20.sol b/contracts/EIP20.sol new file mode 100644 index 0000000..c952a60 --- /dev/null +++ b/contracts/EIP20.sol @@ -0,0 +1,72 @@ +/* +Implements EIP20 token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md +.*/ + + +pragma solidity 0.4.23; + +import "./EIP20Interface.sol"; + + +contract EIP20 is EIP20Interface { + + uint256 constant private MAX_UINT256 = 2**256 - 1; + mapping (address => uint256) public balances; + mapping (address => mapping (address => uint256)) public allowed; + /* + NOTE: + The following variables are OPTIONAL vanities. One does not have to include them. + They allow one to customise the token contract & in no way influences the core functionality. + Some wallets/interfaces might not even bother to look at this information. + */ + string public name; //fancy name: eg Simon Bucks + uint8 public decimals; //How many decimals to show. + string public symbol; //An identifier: eg SBX + + function EIP20( + uint256 _initialAmount, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol + ) public { + balances[msg.sender] = _initialAmount; // Give the creator all initial tokens + totalSupply = _initialAmount; // Update total supply + name = _tokenName; // Set the name for display purposes + decimals = _decimalUnits; // Amount of decimals for display purposes + symbol = _tokenSymbol; // Set the symbol for display purposes + } + + function transfer(address _to, uint256 _value) public returns (bool success) { + require(balances[msg.sender] >= _value); + balances[msg.sender] -= _value; + balances[_to] += _value; + emit Transfer(msg.sender, _to, _value); //solhint-disable-line indent, no-unused-vars + return true; + } + + function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { + uint256 allowance = allowed[_from][msg.sender]; + require(balances[_from] >= _value && allowance >= _value); + balances[_to] += _value; + balances[_from] -= _value; + if (allowance < MAX_UINT256) { + allowed[_from][msg.sender] -= _value; + } + emit Transfer(_from, _to, _value); //solhint-disable-line indent, no-unused-vars + return true; + } + + function balanceOf(address _owner) public view returns (uint256 balance) { + return balances[_owner]; + } + + function approve(address _spender, uint256 _value) public returns (bool success) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); //solhint-disable-line indent, no-unused-vars + return true; + } + + function allowance(address _owner, address _spender) public view returns (uint256 remaining) { + return allowed[_owner][_spender]; + } +} \ No newline at end of file diff --git a/contracts/EIP20Interface.sol b/contracts/EIP20Interface.sol new file mode 100644 index 0000000..9dde6a9 --- /dev/null +++ b/contracts/EIP20Interface.sol @@ -0,0 +1,50 @@ +// Abstract contract for the full ERC 20 Token standard +// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md +pragma solidity ^0.4.23; + + +contract EIP20Interface { + /* This is a slight change to the ERC20 base standard. + function totalSupply() constant returns (uint256 supply); + is replaced with: + uint256 public totalSupply; + This automatically creates a getter function for the totalSupply. + This is moved to the base contract since public getter functions are not + currently recognised as an implementation of the matching abstract + function by the compiler. + */ + /// total amount of tokens + uint256 public totalSupply; + + /// @param _owner The address from which the balance will be retrieved + /// @return The balance + function balanceOf(address _owner) public view returns (uint256 balance); + + /// @notice send `_value` token to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint256 _value) public returns (bool success); + + /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` + /// @param _from The address of the sender + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + /// @return Whether the transfer was successful or not + function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); + + /// @notice `msg.sender` approves `_spender` to spend `_value` tokens + /// @param _spender The address of the account able to transfer the tokens + /// @param _value The amount of tokens to be approved for transfer + /// @return Whether the approval was successful or not + function approve(address _spender, uint256 _value) public returns (bool success); + + /// @param _owner The address of the account owning tokens + /// @param _spender The address of the account able to transfer the tokens + /// @return Amount of remaining tokens allowed to spent + function allowance(address _owner, address _spender) public view returns (uint256 remaining); + + // solhint-disable-next-line no-simple-event-func-name + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); +} \ No newline at end of file diff --git a/contracts/ERC20.sol b/contracts/ERC20.sol new file mode 100644 index 0000000..ad75588 --- /dev/null +++ b/contracts/ERC20.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.21; + +import "./ERC20Basic.sol"; + + +/** + * @title ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/20 + */ +contract ERC20 is ERC20Basic { + function allowance(address owner, address spender) public view returns (uint256); + function transferFrom(address from, address to, uint256 value) public returns (bool); + function approve(address spender, uint256 value) public returns (bool); + event Approval(address indexed owner, address indexed spender, uint256 value); +} \ No newline at end of file diff --git a/contracts/ERC20Basic.sol b/contracts/ERC20Basic.sol new file mode 100644 index 0000000..abd1dea --- /dev/null +++ b/contracts/ERC20Basic.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.4.21; + + +/** + * @title ERC20Basic + * @dev Simpler version of ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/179 + */ +contract ERC20Basic { + function totalSupply() public view returns (uint256); + function balanceOf(address who) public view returns (uint256); + function transfer(address to, uint256 value) public returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value); +} \ No newline at end of file diff --git a/contracts/GuildBank.sol b/contracts/GuildBank.sol index 9c9502b..ff18f76 100644 --- a/contracts/GuildBank.sol +++ b/contracts/GuildBank.sol @@ -9,13 +9,26 @@ contract GuildBank is Ownable { using SafeMath for uint256; LootToken public lootToken; + mapping (address => bool) knownTokenAddress; + address[] public tokenAddresses; constructor(address _lootokenAddress) public { lootToken = LootToken(_lootokenAddress); } - function offerTokens(ERC20 _tokenContract, uint256 _amount) public { - require(_tokenContract.transferFrom(msg.sender, this, _amount), "GuildBank::offerTokens - failed to transfer tokens to GuildBank"); + function offerTokens( + address _holder, + address _tokenContract, + uint256 _amount + ) + public returns (bool) + { + if (knownTokenAddress[_tokenContract] == false) { + knownTokenAddress[_tokenContract] = true; + tokenAddresses.push(_tokenContract); + } + ERC20 token = ERC20(_tokenContract); + return (token.transferFrom(_holder, this, _amount)); } function convertLootTokensToLoot( @@ -55,6 +68,10 @@ contract GuildBank is Ownable { require(token.transfer(_address, _tokenTributeAmounts[i]), "GuildBank::withdraw - failed to transfer to member"); } _address.transfer(_ethAmount); + } + + function getTokenAddresses() view public returns (address[]) { + return tokenAddresses; } function() public payable {} diff --git a/contracts/Moloch.sol b/contracts/Moloch.sol index 0f066b0..7693eb1 100644 --- a/contracts/Moloch.sol +++ b/contracts/Moloch.sol @@ -148,19 +148,7 @@ contract Moloch is Ownable { } function finishProposal() public { - proposalQueue.finishProposal(members, guildBank, votingShares, lootToken, GRACE_PERIOD_SECONDS); - } - - function donateWei() public payable { - address(guildBank).transfer(msg.value); - } - - function getWei() public returns(uint256) { - return address(guildBank).balance; - } - - function donateTokens(ERC20 tokenAddress, uint amount) public { - require(tokenAddress.transferFrom(msg.sender, address(guildBank), amount), "Moloch::donateTokens - failed to transfer tokens to GuildBank"); + proposalQueue.finishProposal(members, votingShares, lootToken, GRACE_PERIOD_SECONDS); } /************** @@ -182,6 +170,7 @@ contract Moloch is Ownable { } function withdraw() public { + require(members.approved[msg.sender] = false); require(members.hasWithdrawn[msg.sender] = false); members.hasWithdrawn[msg.sender] = true; guildBank.withdraw( @@ -192,6 +181,10 @@ contract Moloch is Ownable { ); } + function getGuildBank() public view returns (GuildBank) { + return guildBank; + } + function getMember(address memberAddress) public view returns (bool) { return members.getMember(memberAddress); } diff --git a/contracts/SafeMath.sol b/contracts/SafeMath.sol new file mode 100644 index 0000000..c119270 --- /dev/null +++ b/contracts/SafeMath.sol @@ -0,0 +1,48 @@ +pragma solidity ^0.4.21; + + +/** + * @title SafeMath + * @dev Math operations with safety checks that throw on error + */ +library SafeMath { + + /** + * @dev Multiplies two numbers, throws on overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { + if (a == 0) { + return 0; + } + c = a * b; + assert(c / a == b); + return c; + } + + /** + * @dev Integer division of two numbers, truncating the quotient. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + // uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return a / b; + } + + /** + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + assert(b <= a); + return a - b; + } + + /** + * @dev Adds two numbers, throws on overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256 c) { + c = a + b; + assert(c >= a); + return c; + } +} \ No newline at end of file diff --git a/contracts/StandardToken.sol b/contracts/StandardToken.sol new file mode 100644 index 0000000..724fcc8 --- /dev/null +++ b/contracts/StandardToken.sol @@ -0,0 +1,100 @@ +pragma solidity ^0.4.21; + +import "./BasicToken.sol"; +import "./ERC20.sol"; + + +/** + * @title Standard ERC20 token + * + * @dev Implementation of the basic standard token. + * @dev https://github.com/ethereum/EIPs/issues/20 + * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol + */ +contract StandardToken is ERC20, BasicToken { + + mapping (address => mapping (address => uint256)) internal allowed; + + + /** + * @dev Transfer tokens from one address to another + * @param _from address The address which you want to send tokens from + * @param _to address The address which you want to transfer to + * @param _value uint256 the amount of tokens to be transferred + */ + function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balances[_from]); + require(_value <= allowed[_from][msg.sender]); + + balances[_from] = balances[_from].sub(_value); + balances[_to] = balances[_to].add(_value); + allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); + emit Transfer(_from, _to, _value); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * + * Beware that changing an allowance with this method brings the risk that someone may use both the old + * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this + * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _spender, uint256 _value) public returns (bool) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance(address _owner, address _spender) public view returns (uint256) { + return allowed[_owner][_spender]; + } + + /** + * @dev Increase the amount of tokens that an owner allowed to a spender. + * + * approve should be called when allowed[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _addedValue The amount of tokens to increase the allowance by. + */ + function increaseApproval(address _spender, uint _addedValue) public returns (bool) { + allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue); + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + + /** + * @dev Decrease the amount of tokens that an owner allowed to a spender. + * + * approve should be called when allowed[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _subtractedValue The amount of tokens to decrease the allowance by. + */ + function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) { + uint oldValue = allowed[msg.sender][_spender]; + if (_subtractedValue > oldValue) { + allowed[msg.sender][_spender] = 0; + } else { + allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); + } + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + +} \ No newline at end of file diff --git a/contracts/TestCoin.sol b/contracts/TestCoin.sol new file mode 100644 index 0000000..2631183 --- /dev/null +++ b/contracts/TestCoin.sol @@ -0,0 +1,16 @@ + +pragma solidity 0.4.23; + +import "./StandardToken.sol"; + +contract TestCoin is ERC20, StandardToken { + string public name = "TEST COIN"; + string public symbol = "TEST"; + uint8 public decimals = 18; + uint public INITIAL_SUPPLY = 10000000000; + + constructor() public { + totalSupply_ = INITIAL_SUPPLY; + balances[msg.sender] = INITIAL_SUPPLY; + } +} \ No newline at end of file diff --git a/contracts/TownHallLib.sol b/contracts/TownHallLib.sol index 1d40e70..d5cff5e 100644 --- a/contracts/TownHallLib.sol +++ b/contracts/TownHallLib.sol @@ -148,12 +148,11 @@ library TownHallLib { // collect token tribute for(uint8 i = 0; i < membershipProposal.prospectiveMember.tokenTributeAddresses.length; i++) { + address tokenAddress = membershipProposal.prospectiveMember.tokenTributeAddresses[i]; require(membershipProposal.prospectiveMember.tokenTributeAmounts[i] > 0, "TownHallLib::createMemberProposal - minimum token tribute no met"); // need non zero amounts - ERC20 erc20 = ERC20(membershipProposal.prospectiveMember.tokenTributeAddresses[i]); - - // transfer tokens to this contract as tribute + // transfer tokens to GuildBank contract as tribute // approval must be granted prior to this step - require(erc20.transferFrom(_propospectiveMemberAddress, _guildBank, _tokenTributeAmounts[i]), "TownHallLib::createMemberProposal - token transfer failure"); + require(_guildBank.offerTokens(_propospectiveMemberAddress, tokenAddress, _tokenTributeAmounts[i])); } // push to end of proposal queue @@ -266,7 +265,6 @@ library TownHallLib { function finishProposal( ProposalQueue storage proposalQueue, Members storage members, - GuildBank guildBank, VotingShares votingShares, LootToken lootToken, uint GRACE_PERIOD_SECONDS @@ -285,7 +283,7 @@ library TownHallLib { if (winningBallotItem == WINNING_PROPOSAL_INDEX) { if (currentProposal.proposalType == ProposalTypes.Membership) { // add member here - _acceptMemberProposal(members, guildBank, votingShares, lootToken, currentProposal); + _acceptMemberProposal(members, votingShares, lootToken, currentProposal); } else if (currentProposal.proposalType == ProposalTypes.Project) { // accept proposal _acceptProjectProposal(votingShares, lootToken, currentProposal); @@ -418,7 +416,6 @@ library TownHallLib { for (uint8 i = 0; i < _tokenTributeAddresses.length; i++) { ERC20 erc20 = ERC20(_tokenTributeAddresses[i]); require(erc20.approve(address(guildBank), _tokenTributeAmounts[i]), "TownHallLib::_collectTributes - could not collect token tribute"); - guildBank.offerTokens(erc20, _tokenTributeAmounts[i]); } } @@ -441,21 +438,12 @@ library TownHallLib { // ACCEPT MEMBER function _acceptMemberProposal( Members storage members, - GuildBank guildBank, VotingShares votingShares, LootToken lootToken, Proposal memberProposal ) internal { - // collect tributes into bank - _collectTributes( - guildBank, - memberProposal.prospectiveMember.ethTributeAmount, - memberProposal.prospectiveMember.tokenTributeAddresses, - memberProposal.prospectiveMember.tokenTributeAmounts - ); - // add to moloch members address newMemberAddress = memberProposal.prospectiveMember.prospectiveMemberAddress; members.approved[newMemberAddress] = true; diff --git a/migrations/2_moloch_migration.js b/migrations/2_moloch_migration.js index 49d2ed9..fdc51f0 100644 --- a/migrations/2_moloch_migration.js +++ b/migrations/2_moloch_migration.js @@ -1,9 +1,6 @@ /* global artifacts */ const Moloch = artifacts.require('./Moloch.sol') -const VotingShares = artifacts.require('./VotingShares.sol') -const LootToken = artifacts.require('./LootToken.sol') -const GuildBank = artifacts.require('./GuildBank.sol') const TownHallLib = artifacts.require('./TownHallLib.sol') const VotingLib = artifacts.require('./VotingLib.sol') diff --git a/migrations/3_testcoin_migration.js b/migrations/3_testcoin_migration.js new file mode 100644 index 0000000..de4903a --- /dev/null +++ b/migrations/3_testcoin_migration.js @@ -0,0 +1,14 @@ +/* global artifacts */ +const fse = require('fs-extra') +const TestCoin = artifacts.require('./TestCoin.sol') + +module.exports = (deployer, network, accounts) => { + deployer.then(async () => { + let testJSON = {addresses:[]} + for (let i=0; i < 3; i++) { + await deployer.deploy(TestCoin) + testJSON.addresses.push(TestCoin.address) + } + await fse.writeJson('./test/testcoins.json', testJSON) + }) +} diff --git a/package-lock.json b/package-lock.json index bb75454..b1be5f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -144,6 +144,22 @@ } } }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "2.5.5", + "regenerator-runtime": "0.11.1" + }, + "dependencies": { + "core-js": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.5.tgz", + "integrity": "sha1-sU3ek2xkDAV5prUMq8wTLdYSfjs=" + } + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -462,7 +478,7 @@ "js-yaml": "3.10.0", "json-stable-stringify-without-jsonify": "1.0.1", "levn": "0.3.0", - "lodash": "4.17.5", + "lodash": "4.17.10", "minimatch": "3.0.4", "mkdirp": "0.5.1", "natural-compare": "1.4.0", @@ -680,6 +696,59 @@ "number-to-bn": "1.7.0" } }, + "ethjs-format": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.7.tgz", + "integrity": "sha512-uNYAi+r3/mvR3xYu2AfSXx5teP4ovy9z2FrRsblU+h2logsaIKZPi9V3bn3V7wuRcnG0HZ3QydgZuVaRo06C4Q==", + "requires": { + "bn.js": "4.11.6", + "ethjs-schema": "0.2.1", + "ethjs-util": "0.1.3", + "is-hex-prefixed": "1.0.0", + "number-to-bn": "1.7.0", + "strip-hex-prefix": "1.0.0" + } + }, + "ethjs-provider-http": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-provider-http/-/ethjs-provider-http-0.1.6.tgz", + "integrity": "sha1-HsXZtL4lfvHValALIqdBmF6IlCA=", + "requires": { + "xhr2": "0.1.3" + } + }, + "ethjs-query": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.7.tgz", + "integrity": "sha512-TZnKUwfkWjy0SowFdPLtmsytCorHi0i4vvkQn7Jg8rZt33cRzKhuzOwKr/G3vdigCc+ePXOhUGMcJSAPlOG44A==", + "requires": { + "ethjs-format": "0.2.7", + "ethjs-rpc": "0.2.0", + "promise-to-callback": "1.0.0" + } + }, + "ethjs-rpc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.2.0.tgz", + "integrity": "sha512-RINulkNZTKnj4R/cjYYtYMnFFaBcVALzbtEJEONrrka8IeoarNB9Jbzn+2rT00Cv8y/CxAI+GgY1d0/i2iQeOg==", + "requires": { + "promise-to-callback": "1.0.0" + } + }, + "ethjs-schema": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-schema/-/ethjs-schema-0.2.1.tgz", + "integrity": "sha512-DXd8lwNrhT9sjsh/Vd2Z+4pfyGxhc0POVnLBUfwk5udtdoBzADyq+sK39dcb48+ZU+2VgtwHxtGWnLnCfmfW5g==" + }, + "ethjs-util": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz", + "integrity": "sha1-39XqSkANxeQhqInK9H4IGtp4u1U=", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, "external-editor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", @@ -777,6 +846,16 @@ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", "dev": true }, + "fs-extra": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.0.tgz", + "integrity": "sha512-lk2cUCo8QzbiEWEbt7Cw3m27WMiRG321xsssbcIpfMhpRjrlC08WBOVQqj1/nQYYNnPtyIhP1oqLO3QwT2tPCw==", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -838,8 +917,7 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "has": { "version": "1.0.1", @@ -917,7 +995,7 @@ "cli-width": "2.2.0", "external-editor": "2.1.0", "figures": "2.0.0", - "lodash": "4.17.5", + "lodash": "4.17.10", "mute-stream": "0.0.7", "run-async": "2.3.0", "rx-lite": "4.0.8", @@ -954,6 +1032,11 @@ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, + "is-fn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fn/-/is-fn-1.0.0.tgz", + "integrity": "sha1-lUPV3nvPWwiiLsiiC65uKG1RDYw=" + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -1083,6 +1166,14 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "4.1.11" + } + }, "jsx-ast-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", @@ -1133,9 +1224,9 @@ } }, "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", "dev": true }, "lodash.cond": { @@ -1484,6 +1575,15 @@ "asap": "2.0.6" } }, + "promise-to-callback": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/promise-to-callback/-/promise-to-callback-1.0.0.tgz", + "integrity": "sha1-XSp0kBC/tn2WNZj805YHRqaP7vc=", + "requires": { + "is-fn": "1.0.0", + "set-immediate-shim": "1.0.1" + } + }, "prop-types": { "version": "15.6.0", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz", @@ -1548,6 +1648,11 @@ "util-deprecate": "1.0.2" } }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, "require-uncached": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", @@ -1634,6 +1739,11 @@ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -1805,7 +1915,7 @@ "ajv": "5.5.2", "ajv-keywords": "2.1.1", "chalk": "2.3.1", - "lodash": "4.17.5", + "lodash": "4.17.10", "slice-ansi": "1.0.0", "string-width": "2.1.1" } @@ -1858,6 +1968,11 @@ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", "dev": true }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1910,6 +2025,11 @@ "mkdirp": "0.5.1" } }, + "xhr2": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.3.tgz", + "integrity": "sha1-y/xHWaabSoiOeM9PILBRA4dXvRE=" + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index 3490dbd..36cf36f 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,11 @@ "test": "test" }, "dependencies": { + "babel-runtime": "^6.26.0", + "ethjs-provider-http": "^0.1.6", + "ethjs-query": "^0.3.7", + "ethjs-rpc": "^0.2.0", + "fs-extra": "^6.0.0", "zeppelin-solidity": "1.7.0" }, "devDependencies": { diff --git a/test/moloch.js b/test/moloch.js index 369b617..2762973 100644 --- a/test/moloch.js +++ b/test/moloch.js @@ -1,7 +1,26 @@ +const fse = require('fs-extra') + +const HttpProvider = require(`ethjs-provider-http`); +const EthRPC = require(`ethjs-rpc`); +const ethRPC = new EthRPC(new HttpProvider(`http://localhost:8545`)); +const EthQuery = require(`ethjs-query`) +const ethQuery = new EthQuery(new HttpProvider(`http://localhost:8545`)) + const Moloch = artifacts.require('./Moloch') const GuildBank = artifacts.require('./GuildBank') +const TestCoin = artifacts.require('./StandardToken') const foundersJSON = require('../migrations/founders.json') + +async function mineBlocks(numBlocksToMine) { + for (let i = 0; i < numBlocksToMine; i++) { + let err = await ethRPC.sendAsync({method: `evm_mine`}) + if (err.length > 0) console.log('err', err) + let thisBlockNumber = await ethQuery.blockNumber() + console.log('- mining block', thisBlockNumber.toNumber()) + } +} + contract('verify up to deployment', accounts => { before('deploy contracts', async() => { moloch = await Moloch.deployed() @@ -41,20 +60,30 @@ contract('verify up to deployment', accounts => { }) }) -contract('verify up to donation', accounts => { - before('deploy contracts', async() => { +contract('donate', accounts => { + let moloch, guildBank + + before('deploy Moloch', async() => { moloch = await Moloch.deployed() - }) - it('donate', async() => { - await moloch.donateWei.sendTransaction({from:accounts[0], value:100}) - totalWei = await moloch.getWei.call(); - console.log('totalWei', totalWei) - guildBankAddress = await moloch.guildBankAddress.call() - console.log('guildBankAddress', guildBankAddress) + guildBankAddress = await moloch.getGuildBank.call() guildBank = await GuildBank.at(guildBankAddress) - bal = await guildBank.balance - console.log('bal', bal) + }) + + it('donate ETH', async()=> { + await guildBank.sendTransaction({from:accounts[0], value:100}) + balance = await web3.eth.getBalance(guildBankAddress) + assert.equal(100, balance.toNumber(), 'transaction sent does not equal balance in Guild Bank') + }) + it('donate tokens', async() => { + tokens = await fse.readJson('./test/testcoins.json') + token = await TestCoin.at(tokens.addresses[0]) + token_balance = await token.balanceOf(accounts[0]) + approve = await token.approve.call(moloch.address, 10000000, {from: accounts[0]}) + // await mineBlocks(2) + // allowance = await token.allowance.call(accounts[0], moloch.address) + // offerTokens = await guildBank.offerTokens.call(accounts[0],tokens.addresses[0], 1, {from: accounts[0]}) + // tokenAddresses = await guildBank.getTokenAddresses.call() }) }) diff --git a/test/test.json b/test/test.json new file mode 100644 index 0000000..67d0c8f --- /dev/null +++ b/test/test.json @@ -0,0 +1 @@ +{"addresses":["0x77564e4d127c82a5a789d276060e43154895fcad","0x8bbf424757773248e990740f5c19c29bd8446b97","0x2f3e9e140d5ea1372a2e7a4097120b9beb44f513"]} diff --git a/test/testcoins.json b/test/testcoins.json new file mode 100644 index 0000000..1c8955f --- /dev/null +++ b/test/testcoins.json @@ -0,0 +1 @@ +{"addresses":["0x315cd1fcbace4f178dc9928f25870f609905e3c7","0x7e687f8227dd9322452e3c807a5f034878cbc8eb","0xe78608d8b37591cc3f0605c56721355fc1fffbd2"]}