Skip to content

Commit

Permalink
Reorg test. Add import statement expander. Make owner parameter of pr…
Browse files Browse the repository at this point in the history
…esale contract explicit.
  • Loading branch information
miohtama committed Apr 4, 2017
1 parent e747101 commit de8593e
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 15 deletions.
5 changes: 3 additions & 2 deletions contracts/PresaleFundCollector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ contract PresaleFundCollector is Ownable {
/**
* Create presale contract where lock up period is given days
*/
function PresaleFundCollector(uint _freezeEndsAt, uint _weiMinimumLimit) {
owner = msg.sender;
function PresaleFundCollector(address _owner, uint _freezeEndsAt, uint _weiMinimumLimit) {

owner = _owner;

// Give argument
if(_freezeEndsAt == 0) {
Expand Down
6 changes: 4 additions & 2 deletions ico/deploypresale.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ def utc_time():

@click.command()
@click.option('--chain', nargs=1, default="mainnet", help='On which chain to deploy - see populus.json')
@click.option('--address', nargs=1, help='Account to deploy from (must exist on geth)', default=None)
@click.option('--address', nargs=1, help='Account to deploy from (must exist on geth)', required=True)
@click.option('--owner', nargs=1, help='Address that is set as owner of the presale contract', required=True)
@click.option('--days', nargs=1, default=30, help='How many days presale is frozen for', type=int)
@click.option('--minimum', nargs=1, default=1, help='What is the minimum pre-ico buy in (ether)', type=float)
def main(chain, address, days, minimum):
@click.option('--verify/--no-verify', default=True, help='Verify contract source code one EtherScan.io')
def main(chain, address, days, minimum, verify):
"""Deploy a PresaleFundCollector contract."""
project = Project()

Expand Down
41 changes: 41 additions & 0 deletions ico/etherscan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""etherscan.io utilities."""

import requests

from populus import Project

from ico.importexpand import expand_contract_imports


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-nightly.2017.1.13+commit.bde0b406"):
"""Make a contract verified on Etherscan.
See the page in action: https://etherscan.io/verifyContract?a=0xcd111aa492a9c77a367c36e6d6af8e6f212e0c8e
"""

src = expand_contract_imports(project, contract_filename)

if chain_name == "mainnet":
url = "https://etherscan.io/verifyContract"
elif chain_name == "ropsten":
url = "https://ropsten.etherscan.io/verifyContract"
else:
raise RuntimeError("Unknown chain")

data = {
"ctl00$ContentPlaceHolder1$txtContractAddress": address,
"ctl00$ContentPlaceHolder1$txtContractName": contract_name,
"ctl00$ContentPlaceHolder1$ddlCompilerVersions": compiler,
"ctl00$ContentPlaceHolder1$ddlOptimization": "1" if optimization else "0",
"ctl00$ContentPlaceHolder1$txtSourceCode": src,
"ctl00$ContentPlaceHolder1$txtConstructorArguements": constructor_args,
}

idx = 1
for library_name, library_address in libraries.items():
data["ctl00$ContentPlaceHolder1$txtLibraryAddress{}".format(idx)] = library_address
data["ctl00$ContentPlaceHolder1$txtLibraryName{}".format(idx)] = library_name

resp = requests.post(url, data)
resp.raise_for_status()

69 changes: 69 additions & 0 deletions ico/importexpand.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Expand Solidity import statements for Etherscan verification service.
Mainly need for EtherScan verification service.
"""
import os
from typing import Tuple

from populus import Project


class Expander:
"""Solidity import expanded."""

def __init__(self, project: Project):
self.project = project
self.processed_imports = set()

def expand_file(self, import_path: str):
"""Read Solidity source code and expart any import paths inside.
Supports Populus remapping settings:
http://populus.readthedocs.io/en/latest/config.html#compiler-settings
:param import_path:
"""

# Already handled
if import_path in self.processed_imports:
return ""

# TODO: properly handle import remapping here, read them from project config
if import_path.startswith("zeppelin/"):
abs_import_path = os.path.join(os.getcwd(), import_path)
else:
abs_import_path = os.path.join(os.getcwd(), "contracts", import_path)

abs_import_path = os.path.abspath(abs_import_path)

with open(abs_import_path, "rt") as inp:
source = inp.read()
self.processed_imports.add(import_path)
return self.process_source(source)


def process_source(self, src: str):
"""Process Solidity source code and expand any import statement."""

out = []

for line in src.split("\n"):
# Detect import statements, ghetto way
if line.startswith('import "'):
prefix, import_path, suffix = line.split('"')
source = self.expand_file(import_path)
out += source.split("\n")
else:
out.append(line)

return "\n".join(out)


def expand_contract_imports(project: Project, contract_filename: str) -> Tuple[str, str]:
"""Expand Solidity import statements.
:return: Tuple[final expanded source, set of processed filenames]
"""
exp = Expander(project)
return exp.expand_file(contract_filename), exp.processed_imports
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def presale_freeze_ends_at() -> int:
def presale_fund_collector(chain, presale_freeze_ends_at, team_multisig) -> Contract:
"""In actual ICO, the price is doubled (for testing purposes)."""
args = [
team_multisig,
presale_freeze_ends_at,
to_wei(1, "ether")
]
Expand Down Expand Up @@ -222,17 +223,6 @@ def test_invest_signature(chain, web3, presale_fund_collector, presale_crowdsale
"""Check we get invest() signature for data payload."""

value = to_wei(1, "ether")
transaction = {"from": customer, "value": value}
sig = presale_fund_collector._prepare_transaction("invest")
assert sig["data"] == "0xe8b5e51f"


def test_encode_constructor(chain, web3, presale_fund_collector, presale_freeze_ends_at):
"""Needed for getting Etherscan.io signature in presale.py."""

args = [
int(1),
to_wei(1, "ether")
]
data = get_constructor_arguments(presale_fund_collector, args)
assert data == "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a7640000"
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
17 changes: 17 additions & 0 deletions ico/tests/tools/test_expand.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Test import expansion tool."""

from populus import Project

from ico.importexpand import expand_contract_imports


def test_expand_token(project: Project):
"""Expand import statement in a Solidity source file."""

expanded, imported_files = expand_contract_imports(project, "Crowdsale.sol")

assert imported_files == {'zeppelin/contracts/token/ERC20.sol', './PricingStrategy.sol', './Haltable.sol', './SafeMathLib.sol', 'zeppelin/contracts/ownership/Ownable.sol', 'Crowdsale.sol', './FinalizeAgent.sol'}

assert "contract Crowdsale" in expanded
assert 'import "' not in expanded

0 comments on commit de8593e

Please sign in to comment.