Skip to content

Commit

Permalink
Fix investorCount calculation. Fix maximum sellable tokens naming. Fi…
Browse files Browse the repository at this point in the history
…x missing asserts in some tests.
  • Loading branch information
miohtama committed Apr 12, 2017
1 parent 769eb5e commit 02af3a0
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 46 deletions.
4 changes: 2 additions & 2 deletions contracts/Crowdsale.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ contract Crowdsale is Haltable {
/** State machine
*
* - Preparing: All contract initialization calls and variables have not been set yet
* - Prefunding: We have not started yet
* - Prefunding: We have not passed start time yet
* - Funding: Active crowdsale
* - Success: Minimum funding goal reached
* - Failure: Minimum funding goal not reached before ending time
Expand Down Expand Up @@ -144,7 +144,7 @@ contract Crowdsale is Haltable {
throw;
}

if(investedAmountOf[receiver] != 0) {
if(investedAmountOf[receiver] == 0) {
// A new investor
investorCount++;
}
Expand Down
10 changes: 5 additions & 5 deletions contracts/MintedTokenCappedCrowdsale.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ import "./MintableToken.sol";
contract MintedTokenCappedCrowdsale is Crowdsale {

/* Maximum amount of tokens this crowdsale can sell. */
uint public maximumTokensSold;
uint public maximumSellableTokens;

function MintedTokenCappedCrowdsale(address _token, address _pricingStrategy, address _multisigWallet, uint _start, uint _end, uint _minimumFundingGoal, uint _maximumTokensSold) Crowdsale(_token, _pricingStrategy, _multisigWallet, _start, _end, _minimumFundingGoal) {
maximumTokensSold = _maximumTokensSold;
function MintedTokenCappedCrowdsale(address _token, address _pricingStrategy, address _multisigWallet, uint _start, uint _end, uint _minimumFundingGoal, uint _maximumSellableTokens) Crowdsale(_token, _pricingStrategy, _multisigWallet, _start, _end, _minimumFundingGoal) {
maximumSellableTokens = _maximumSellableTokens;
}

/**
* Called from invest() to confirm if the curret investment does not break our cap rule.
*/
function isBreakingCap(uint weiAmount, uint tokenAmount, uint weiRaisedTotal, uint tokensSoldTotal) constant returns (bool limitBroken) {
return tokensSoldTotal > maximumTokensSold;
return tokensSoldTotal > maximumSellableTokens;
}

function isCrowdsaleFull() public constant returns (bool) {
return tokensSold >= maximumTokensSold;
return tokensSold >= maximumSellableTokens;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion crowdsales/example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ testnet:
_start: "{{ timestamp(datetime(2017, 4, 15, 16, 0)) }}"
_end: "{{ timestamp(datetime(2017, 4, 15, 16, 0)) + 30*24*3600 }}"
_minimumFundingGoal: 7500
_maximumTokensSold: 4000000
_maximumSellableTokens: 4000000
#
# Finalize contract
#
Expand Down
16 changes: 11 additions & 5 deletions ico/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
import textwrap
from collections import Counter
from typing import Tuple
import os

import jinja2
import ruamel.yaml
from eth_utils import from_wei

from eth_utils import from_wei
from populus import Project
from web3.contract import Contract

from populus.utils.cli import request_account_unlock
from populus.utils.accounts import is_account_locked
from web3.contract import Contract

from ico.definition import load_crowdsale_definitions
from ico.definition import get_jinja_context
Expand Down Expand Up @@ -115,17 +115,23 @@ def deploy_crowdsale(project: Project, chain, source_definitions: dict, deploy_a

# Perform manual verification of the deployed contract
if verify_on_etherscan:
verify_contract(
fname = runtime_data["contracts"][name]["contract_file"]
src = verify_contract(
project=project,
chain_name=chain_name,
address=runtime_data["contracts"][name]["address"],
contract_name=contract_name,
contract_filename=runtime_data["contracts"][name]["contract_file"],
contract_filename=fname,
constructor_args=runtime_data["contracts"][name]["constructor_args"],
libraries=runtime_data["contracts"][name]["libraries"],
browser_driver=browser_driver)
runtime_data["contracts"][name]["etherscan_link"] = get_etherscan_link(chain_name, runtime_data["contracts"][name]["address"])

# Write out our expanded contract
expanded_path = os.path.join(os.getcwd(), "build", "expanded", fname)
with open(expanded_path, "wt") as out:
out.write(src)

return runtime_data, statistics, contracts


Expand Down
10 changes: 7 additions & 3 deletions ico/etherscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ def _fill_in_textarea_value(browser, splinter_elem, value):



def verify_contract(project: Project, chain_name: str, address: str, contract_name, contract_filename: str, constructor_args: str, libraries: dict, optimization=True, compiler: str="v0.4.8+commit.60cc1668", browser_driver="chrome"):
def verify_contract(project: Project, chain_name: str, address: str, contract_name, contract_filename: str, constructor_args: str, libraries: dict, optimization=True, compiler: str="v0.4.8+commit.60cc1668", browser_driver="chrome") -> str:
"""Semi-automated contract verified on Etherscan.
Uses a web browser + Selenium auto fill to verify contracts.
See the page in action: https://etherscan.io/verifyContract?a=0xcd111aa492a9c77a367c36e6d6af8e6f212e0c8e
:return: Contract expanded source code
"""

try:
Expand Down Expand Up @@ -75,17 +77,19 @@ def verify_contract(project: Project, chain_name: str, address: str, contract_na
print("Waiting EtherScan to process the contract verification")
while time.time() < deadline:
if browser.is_text_present("Successfully generated ByteCode and ABI for Contract Address", wait_time=1):
return
return src

if browser.is_text_present("already been verified"):
print("The contract has already been verified")
return
return src

time.sleep(1.0)

print("Contract verification failed. Check the browser for details.")
input("Press enter to continue")

return src


def get_etherscan_link(network, address):
"""Construct etherscan link"""
Expand Down
9 changes: 5 additions & 4 deletions ico/tests/contracts/test_minted_capped.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def crowdsale(chain, team_multisig, start_time, end_time, milestone_pricing, pre

assert contract.call().owner() == team_multisig
assert not token.call().released()
assert contract.call().maximumSellableTokens() == cap

# Allow crowdsale contract to do mint()
token.transact({"from": team_multisig}).setMintAgent(contract.address, True)
Expand Down Expand Up @@ -153,10 +154,10 @@ def test_buy_some(chain, crowdsale, token, finalizer, start_time, end_time, team
assert token.call().totalSupply() == customer_tokens * (1+founder_allocation)

# See that customers get their tokens
token.call().balanceOf(customer) == crowdsale.call().tokensSold()
assert token.call().balanceOf(customer) == crowdsale.call().tokensSold()

# See that team multisig got our bonus tokens
token.call().balanceOf(team_multisig) == crowdsale.call().tokensSold() * founder_allocation
assert token.call().balanceOf(team_multisig) == crowdsale.call().tokensSold() * founder_allocation

# Token is transferable
assert token.call().released()
Expand Down Expand Up @@ -190,10 +191,10 @@ def test_buy_all(chain, crowdsale, token, finalizer, start_time, end_time, team_
assert token.call().totalSupply() == customer_tokens * (1 + founder_allocation)

# See that customers get their tokens
token.call().balanceOf(customer) == crowdsale.call().tokensSold()
assert token.call().balanceOf(customer) == crowdsale.call().tokensSold()

# See that team multisig got our bonus tokens
token.call().balanceOf(team_multisig) == crowdsale.call().tokensSold() * founder_allocation
assert token.call().balanceOf(team_multisig) == crowdsale.call().tokensSold() * founder_allocation

# Token is transferable
assert token.call().released()
12 changes: 6 additions & 6 deletions ico/tests/contracts/test_presale.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ def test_invest_presale_move_to_crowdsale(chain, presale_fund_collector, presale
presale_fund_collector.transact().parcipateCrowdsaleAll()

# Presale balances zerod
presale_fund_collector.call().balances(customer) == 0
presale_fund_collector.call().balances(customer_2) == 0
assert presale_fund_collector.call().balances(customer) == 0
assert presale_fund_collector.call().balances(customer_2) == 0

# Tokens received
presale_crowdsale.call().investedAmountOf(customer) == to_wei(1, "ether")
presale_crowdsale.call().investedAmountOf(customer_2) == to_wei(1.5, "ether")
assert presale_crowdsale.call().investedAmountOf(customer) == to_wei(1, "ether")
assert presale_crowdsale.call().investedAmountOf(customer_2) == to_wei(1.5, "ether")


def test_invest_presale_move_to_crowdsale_twice(chain, presale_fund_collector, presale_crowdsale, finalizer, preico_starts_at, customer, customer_2):
Expand All @@ -116,8 +116,8 @@ def test_invest_presale_move_to_crowdsale_twice(chain, presale_fund_collector, p
presale_fund_collector.transact().parcipateCrowdsaleAll()

# Tokens received
presale_crowdsale.call().investedAmountOf(customer) == to_wei(1, "ether")
presale_crowdsale.call().investedAmountOf(customer_2) == to_wei(1.5, "ether")
assert presale_crowdsale.call().investedAmountOf(customer) == to_wei(1, "ether")
assert presale_crowdsale.call().investedAmountOf(customer_2) == to_wei(1.5, "ether")


def test_invest_presale_move_to_crowdsale_too_early(chain, presale_fund_collector, presale_crowdsale, customer, customer_2, preico_starts_at):
Expand Down
42 changes: 22 additions & 20 deletions ico/tests/contracts/test_uncapped_flatprice.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_buy_early(chain: TestRPCChain, ico: Contract, customer: str, preico_sta
ico.transact({"from": customer, "value": to_wei(1, "ether")}).buy()


def test_buy(chain: TestRPCChain, web3: Web3, ico: Contract, uncapped_token: Contract, customer: str, preico_token_price, preico_starts_at, team_multisig):
def test_buy_one_investor(chain: TestRPCChain, web3: Web3, ico: Contract, uncapped_token: Contract, customer: str, preico_token_price, preico_starts_at, team_multisig):
"""Can buy when crowdsale is running."""

original_balance = web3.eth.getBalance(team_multisig)
Expand All @@ -53,26 +53,28 @@ def test_buy(chain: TestRPCChain, web3: Web3, ico: Contract, uncapped_token: Con

time_travel(chain, preico_starts_at + 1)
assert ico.call().getState() == CrowdsaleState.Funding

assert ico.call().investorCount() == 0
assert ico.call().investedAmountOf(customer) == 0
ico.transact({"from": customer, "value": wei_value}).buy()

#
# See everything was correctly credited
#

# Tokens on every account
uncapped_token.call().balanceOf(customer) == buys_tokens
uncapped_token.call().totalSupply() == buys_tokens
ico.call().tokensSold() == buys_tokens
assert uncapped_token.call().balanceOf(customer) == buys_tokens
assert uncapped_token.call().totalSupply() == buys_tokens
assert ico.call().tokensSold() == buys_tokens
assert ico.call().investorCount() == 1

# Ether on every account
ico.call().weiRaised() == wei_value
ico.call().investedAmountOf(customer) == wei_value
assert ico.call().weiRaised() == wei_value
assert ico.call().investedAmountOf(customer) == wei_value
balance_diff = web3.eth.getBalance(team_multisig) - original_balance
assert balance_diff == wei_value

# Investors
ico.call().investorCount() == 1
assert ico.call().investorCount() == 1

#
# Events
Expand Down Expand Up @@ -114,18 +116,18 @@ def test_buy_again(chain: TestRPCChain, web3: Web3, ico: Contract, uncapped_toke
#

# Tokens on every account
uncapped_token.call().balanceOf(customer) == buys_tokens * 2
uncapped_token.call().totalSupply() == buys_tokens * 2
ico.call().tokensSold() == buys_tokens * 2
assert uncapped_token.call().balanceOf(customer) == buys_tokens * 2
assert uncapped_token.call().totalSupply() == buys_tokens * 2
assert ico.call().tokensSold() == buys_tokens * 2

# Ether on every account
ico.call().weiRaised() == wei_value * 2
ico.call().investedAmountOf(customer) == wei_value * 2
assert ico.call().weiRaised() == wei_value * 2
assert ico.call().investedAmountOf(customer) == wei_value * 2
balance_diff = web3.eth.getBalance(team_multisig) - original_balance
assert balance_diff == wei_value * 2

# Investors
ico.call().investorCount() == 1
assert ico.call().investorCount() == 1

#
# Events
Expand Down Expand Up @@ -159,18 +161,18 @@ def test_buy_two_investors(chain: TestRPCChain, web3: Web3, ico: Contract, uncap
#

# Tokens on every account
uncapped_token.call().balanceOf(customer) == buys_tokens
uncapped_token.call().totalSupply() == buys_tokens * 2
ico.call().tokensSold() == buys_tokens * 2
assert uncapped_token.call().balanceOf(customer) == buys_tokens
assert uncapped_token.call().totalSupply() == buys_tokens * 2
assert ico.call().tokensSold() == buys_tokens * 2

# Ether on every account
ico.call().weiRaised() == wei_value * 2
ico.call().investedAmountOf(customer) == wei_value
assert ico.call().weiRaised() == wei_value * 2
assert ico.call().investedAmountOf(customer) == wei_value
balance_diff = web3.eth.getBalance(team_multisig) - original_balance
assert balance_diff == wei_value * 2

# Investors
ico.call().investorCount() == 2
assert ico.call().investorCount() == 2

#
# Events
Expand Down

0 comments on commit 02af3a0

Please sign in to comment.